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>
This commit is contained in:
copilot-swe-agent[bot]
2026-04-01 02:43:55 +00:00
committed by GitHub
parent 897a2f4126
commit 8aa83221e8
2 changed files with 11 additions and 8 deletions

View File

@@ -215,6 +215,8 @@ Detailed list of changes
- Fix dragging of splits layout borders sometimes moving in the wrong direction (:pull:`9447`) - 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] 0.46.2 [2026-03-21]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@@ -20,6 +20,8 @@ func (self *KilledBySignal) Error() string { return self.Msg }
var Canceled = errors.New("Canceled by user") var Canceled = errors.New("Canceled by user")
const password_symbol = "🔒"
func ReadPassword(prompt string, kill_if_signaled bool) (password string, err error) { func ReadPassword(prompt string, kill_if_signaled bool) (password string, err error) {
lp, err := loop.New(loop.NoAlternateScreen, loop.NoRestoreColors, loop.FullKeyboardProtocol) lp, err := loop.New(loop.NoAlternateScreen, loop.NoRestoreColors, loop.FullKeyboardProtocol)
shadow := "" shadow := ""
@@ -30,22 +32,22 @@ func ReadPassword(prompt string, kill_if_signaled bool) (password string, err er
has_caps_lock := false has_caps_lock := false
redraw_prompt := func() { redraw_prompt := func() {
text := prompt + shadow
lp.QueueWriteString("\r") lp.QueueWriteString("\r")
lp.ClearToEndOfLine() lp.ClearToEndOfLine()
if has_caps_lock { if has_caps_lock {
lp.QueueWriteString("\x1b[31m[CapsLock on!]\x1b[39m ") lp.QueueWriteString("\x1b[31m[CapsLock on!]\x1b[39m ")
} }
lp.QueueWriteString(text) lp.QueueWriteString(prompt + shadow + password_symbol)
} }
lp.OnInitialize = func() (string, error) { lp.OnInitialize = func() (string, error) {
lp.QueueWriteString(prompt) lp.SetCursorVisible(false)
lp.SetCursorShape(loop.BAR_CURSOR, true) lp.QueueWriteString(prompt + password_symbol)
return "", nil return "", nil
} }
lp.OnFinalize = func() string { lp.OnFinalize = func() string {
lp.SetCursorVisible(true)
lp.SetCursorShape(loop.BLOCK_CURSOR, true) lp.SetCursorShape(loop.BLOCK_CURSOR, true)
return "\r\n" return "\r\n"
} }
@@ -55,10 +57,9 @@ func ReadPassword(prompt string, kill_if_signaled bool) (password string, err er
password += text password += text
new_width := wcswidth.Stringwidth(password) new_width := wcswidth.Stringwidth(password)
if new_width > old_width { if new_width > old_width {
extra := strings.Repeat("*", new_width-old_width) shadow += strings.Repeat("*", new_width-old_width)
lp.QueueWriteString(extra)
shadow += extra
} }
redraw_prompt()
return nil return nil
} }
@@ -91,8 +92,8 @@ func ReadPassword(prompt string, kill_if_signaled bool) (password string, err er
delta = len(shadow) delta = len(shadow)
} }
shadow = shadow[:len(shadow)-delta] shadow = shadow[:len(shadow)-delta]
lp.QueueWriteString(strings.Repeat("\x08\x1b[P", delta))
} }
redraw_prompt()
} else { } else {
lp.Beep() lp.Beep()
} }