From 8aa83221e8c8a3bcfd94e7974f1dfd3cb1552faf Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 1 Apr 2026 02:43:55 +0000 Subject: [PATCH] Improve password input: hide cursor and show lock emoji (U+1F512) Agent-Logs-Url: https://github.com/kovidgoyal/kitty/sessions/cf06c199-5837-41da-bebf-eb3c220684db Co-authored-by: kovidgoyal <1308621+kovidgoyal@users.noreply.github.com> --- docs/changelog.rst | 2 ++ tools/tui/password.go | 17 +++++++++-------- 2 files changed, 11 insertions(+), 8 deletions(-) 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() }