diff --git a/docs/changelog.rst b/docs/changelog.rst index e91772087..b13d86b28 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -215,6 +215,8 @@ Detailed list of changes - Fix dragging of splits layout borders sometimes moving in the wrong direction (:pull:`9447`) +- Password input in kittens: hide the cursor and display 🔒 (U+1F512) at the end of typed characters to make it visually clear the user is entering a password + 0.46.2 [2026-03-21] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/tools/tui/password.go b/tools/tui/password.go index 902c36ae9..ca13924cb 100644 --- a/tools/tui/password.go +++ b/tools/tui/password.go @@ -20,6 +20,8 @@ func (self *KilledBySignal) Error() string { return self.Msg } var Canceled = errors.New("Canceled by user") +const password_symbol = "🔒" + func ReadPassword(prompt string, kill_if_signaled bool) (password string, err error) { lp, err := loop.New(loop.NoAlternateScreen, loop.NoRestoreColors, loop.FullKeyboardProtocol) shadow := "" @@ -30,22 +32,22 @@ func ReadPassword(prompt string, kill_if_signaled bool) (password string, err er has_caps_lock := false redraw_prompt := func() { - text := prompt + shadow lp.QueueWriteString("\r") lp.ClearToEndOfLine() if has_caps_lock { lp.QueueWriteString("\x1b[31m[CapsLock on!]\x1b[39m ") } - lp.QueueWriteString(text) + lp.QueueWriteString(prompt + shadow + password_symbol) } lp.OnInitialize = func() (string, error) { - lp.QueueWriteString(prompt) - lp.SetCursorShape(loop.BAR_CURSOR, true) + lp.SetCursorVisible(false) + lp.QueueWriteString(prompt + password_symbol) return "", nil } lp.OnFinalize = func() string { + lp.SetCursorVisible(true) lp.SetCursorShape(loop.BLOCK_CURSOR, true) return "\r\n" } @@ -55,10 +57,9 @@ func ReadPassword(prompt string, kill_if_signaled bool) (password string, err er password += text new_width := wcswidth.Stringwidth(password) if new_width > old_width { - extra := strings.Repeat("*", new_width-old_width) - lp.QueueWriteString(extra) - shadow += extra + shadow += strings.Repeat("*", new_width-old_width) } + redraw_prompt() return nil } @@ -91,8 +92,8 @@ func ReadPassword(prompt string, kill_if_signaled bool) (password string, err er delta = len(shadow) } shadow = shadow[:len(shadow)-delta] - lp.QueueWriteString(strings.Repeat("\x08\x1b[P", delta)) } + redraw_prompt() } else { lp.Beep() }