]> git.eshelyaron.com Git - emacs.git/commitdiff
'read-passwd' can toggle the visibility of passwords
authorMichael Albinus <michael.albinus@gmx.de>
Sun, 25 Feb 2024 09:06:09 +0000 (10:06 +0100)
committerEshel Yaron <me@eshelyaron.com>
Wed, 28 Feb 2024 17:52:49 +0000 (18:52 +0100)
* doc/lispref/minibuf.texi (Reading a Password):
* etc/NEWS: 'read-passwd' can toggle the visibility of passwords.

* etc/images/README: Mention the new images below.
* etc/images/conceal.pbm:
* etc/images/conceal.svg:
* etc/images/reveal.pbm:
* etc/images/reveal.svg: New images.

* lisp/simple.el (read-passwd--mode-line-buffer)
(read-passwd--mode-line-icon): New defvars.
(read-passwd--toggle-visibility, read-passwd-mode): New defuns.

* lisp/subr.el (read-passwd-map): Add 'TAB' binding.
(read-passwd--hide-password): New defvar.
(read-passwd--hide-password): Rename function from
`read-password--hide-password'.  Adapt callees.  Implement both
hiding and showing the password.  (Bug#69237)
(read-passwd): Call `read-passwd-mode'.

(cherry picked from commit 39e3fce0d5e0f5db00e44905bcd2590170098d63)

doc/lispref/minibuf.texi
etc/NEWS
etc/images/README
etc/images/conceal.pbm [new file with mode: 0644]
etc/images/conceal.svg [new file with mode: 0644]
etc/images/reveal.pbm [new file with mode: 0644]
etc/images/reveal.svg [new file with mode: 0644]
lisp/simple.el
lisp/subr.el

index 3ae13f0b05a92878163e6d4e1a352eb0aa6f64d1..7d5e6678cbb970f05c074379dcad4a5a9ffd9ece 100644 (file)
@@ -2646,6 +2646,14 @@ times match.
 The optional argument @var{default} specifies the default password to
 return if the user enters empty input.  If @var{default} is @code{nil},
 then @code{read-passwd} returns the null string in that case.
+
+This function uses @code{read-passwd-mode}, a minor mode.  It binds two
+keys in the minbuffer: @kbd{C-u} (@code{delete-minibuffer-contents})
+deletes the password, and @kbd{TAB}
+(@code{read-passwd--toggle-visibility}) toggles the visibility of the
+password.  There is also an additional icon in the mode-line.  Clicking
+on this icon with @key{mouse-1} toggles the visibility of the password
+as well.
 @end defun
 
 @node Minibuffer Commands
index dcf58159f4231be72a6d6dc65bc911a02c16026f..beaef825350c2533065286db113e3d12d5f89b32 100644 (file)
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -320,6 +320,12 @@ Previously, it was set to t but this broke remote file name detection.
 ** Multi-character key echo now ends with a suggestion to use Help.
 Customize 'echo-keystrokes-help' to nil to prevent that.
 
++++
+** 'read-passwd' can toggle the visibility of passwords.
+Use 'TAB' in the minibuffer to show or hide the password.  Likewise,
+there is an icon on the mode-line, which toggles the visibility of the
+password when clicking with 'mouse-1'.
+
 \f
 * Editing Changes in Emacs 30.1
 
@@ -2088,7 +2094,8 @@ Example:
       "Uses c:\remote\dir\files and the key \C-x."
       ...)
 
-where the doc string contains four control characters CR, DEL, FF and ^X.
+where the docstring contains four control characters 'CR', 'DEL', 'FF'
+and 'C-x'.
 
 The warning name is 'docstrings-control-chars'.
 
@@ -2181,7 +2188,7 @@ automatically, which means that the size parameter to 'obarray-make' can
 safely be omitted.  That is, they do not become slower as they fill up.
 
 The old vector representation is still accepted by functions operating
-on obarrays, but 'obarrayp' only returns 't' for obarray objects.
+on obarrays, but 'obarrayp' only returns t for obarray objects.
 'type-of' now returns 'obarray' for obarray objects.
 
 Old code which (incorrectly) created "obarrays" as Lisp vectors filled
index a778d9ce6c331c3a116a1c854ed92953caed5cba..8e1124483734f5b896091da85562e642659b4c9f 100644 (file)
@@ -125,7 +125,7 @@ For more information see the adwaita-icon-theme repository at:
 
     https://gitlab.gnome.org/GNOME/adwaita-icon-theme
 
-Emacs images and their source in the Adwaita/scalable directory:
+Emacs images and their source in the Adwaita/symbolic directory:
 
   checked.svg               ui/checkbox-checked-symbolic.svg
   unchecked.svg             ui/checkbox-symbolic.svg
@@ -137,3 +137,8 @@ Emacs images and their source in the Adwaita/scalable directory:
   left.svg                  ui/pan-start-symbolic.svg
   right.svg                 ui/pan-end-symbolic.svg
   up.svg                    ui/pan-up-symbolic.svg
+  conceal.svg               actions/view-conceal-symbolic.svg
+  reveal.svg                actions/view-reveal-symbolic.svg
+
+conceal.pbm and reveal.pbm are generated from the respective *.svg
+files, using the ImageMagick converter tool.
diff --git a/etc/images/conceal.pbm b/etc/images/conceal.pbm
new file mode 100644 (file)
index 0000000..3df787d
Binary files /dev/null and b/etc/images/conceal.pbm differ
diff --git a/etc/images/conceal.svg b/etc/images/conceal.svg
new file mode 100644 (file)
index 0000000..172b73e
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg">
+    <path d="m 1.53125 0.46875 l -1.0625 1.0625 l 14 14 l 1.0625 -1.0625 l -2.382812 -2.382812 c 1.265624 -1.0625 2.171874 -2.496094 2.589843 -4.097657 c -0.914062 -3.523437 -4.097656 -5.984375 -7.738281 -5.988281 c -1.367188 0.011719 -2.707031 0.371094 -3.894531 1.042969 z m 6.46875 3.53125 c 2.210938 0 4 1.789062 4 4 c -0.003906 0.800781 -0.246094 1.578125 -0.699219 2.238281 l -1.46875 -1.46875 c 0.105469 -0.242187 0.164063 -0.503906 0.167969 -0.769531 c 0 -1.105469 -0.894531 -2 -2 -2 c -0.265625 0.003906 -0.527344 0.0625 -0.769531 0.167969 l -1.46875 -1.46875 c 0.660156 -0.453125 1.4375 -0.695313 2.238281 -0.699219 z m -6.144531 0.917969 c -0.753907 0.898437 -1.296875 1.957031 -1.59375 3.09375 c 0.914062 3.523437 4.097656 5.984375 7.738281 5.988281 c 0.855469 -0.007812 1.703125 -0.152344 2.511719 -0.425781 l -1.667969 -1.667969 c -0.277344 0.058594 -0.5625 0.089844 -0.84375 0.09375 c -2.210938 0 -4 -1.789062 -4 -4 c 0.003906 -0.28125 0.035156 -0.566406 0.09375 -0.84375 z m 0 0" fill="#2e3436"/>
+</svg>
diff --git a/etc/images/reveal.pbm b/etc/images/reveal.pbm
new file mode 100644 (file)
index 0000000..79d2f1f
Binary files /dev/null and b/etc/images/reveal.pbm differ
diff --git a/etc/images/reveal.svg b/etc/images/reveal.svg
new file mode 100644 (file)
index 0000000..41ae373
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg">
+    <path d="m 8 2 c -3.648438 0.003906 -6.832031 2.476562 -7.738281 6.007812 c 0.914062 3.527344 4.097656 5.988282 7.738281 5.992188 c 3.648438 -0.003906 6.832031 -2.476562 7.738281 -6.011719 c -0.914062 -3.523437 -4.097656 -5.984375 -7.738281 -5.988281 z m 0 2 c 2.210938 0 4 1.789062 4 4 s -1.789062 4 -4 4 s -4 -1.789062 -4 -4 s 1.789062 -4 4 -4 z m 0 2 c -1.105469 0 -2 0.894531 -2 2 s 0.894531 2 2 2 s 2 -0.894531 2 -2 s -0.894531 -2 -2 -2 z m 0 0" fill="#2e3436"/>
+</svg>
index afa6538641ec1b29a1171cb4ee26c48b9d0eb24b..965a1f3e82ef90826ade60abc3c0698849eb07ed 100644 (file)
@@ -10838,6 +10838,87 @@ and setting it to nil."
     (setq-local vis-mode-saved-buffer-invisibility-spec
                 buffer-invisibility-spec)
     (setq buffer-invisibility-spec nil)))
+
+\f
+(defvar read-passwd--mode-line-buffer nil
+  "Buffer to modify `mode-line-format' for showing/hiding passwords.")
+
+(defvar read-passwd--mode-line-icon nil
+  "Propertized mode line icon for showing/hiding passwords.")
+
+(defun read-passwd--toggle-visibility ()
+  "Toggle minibuffer contents visibility.
+Adapt also mode line."
+  (interactive)
+  (setq read-passwd--hide-password (not read-passwd--hide-password))
+  (with-current-buffer read-passwd--mode-line-buffer
+    (setq read-passwd--mode-line-icon
+          `(:propertize
+            ,(if icon-preference
+                 (icon-string
+                  (if read-passwd--hide-password
+                      'read-passwd--show-password-icon
+                    'read-passwd--hide-password-icon))
+               "")
+            mouse-face mode-line-highlight
+            local-map
+            (keymap
+             (mode-line keymap (mouse-1 . read-passwd--toggle-visibility)))))
+    (force-mode-line-update))
+  (read-passwd--hide-password))
+
+(define-minor-mode read-passwd-mode
+  "Toggle visibility of password in minibuffer."
+  :group 'mode-line
+  :group 'minibuffer
+  :keymap read-passwd-map
+  :version "30.1"
+
+  (require 'icons)
+  ;; It would be preferable to use "👁" ("\N{EYE}").  However, there is
+  ;; no corresponding Unicode char with a slash.  So we use symbols as
+  ;; fallback only, with "⦵" ("\N{CIRCLE WITH HORIZONTAL BAR}") for
+  ;; hiding the password.
+  (define-icon read-passwd--show-password-icon nil
+    '((image "reveal.svg" "reveal.pbm" :height (0.8 . em))
+      (symbol "👁")
+      (text "o"))
+    "Mode line icon to show a hidden password."
+    :group mode-line-faces
+    :version "30.1"
+    :help-echo "mouse-1: Toggle password visibility")
+  (define-icon read-passwd--hide-password-icon nil
+    '((image "conceal.svg" "conceal.pbm" :height (0.8 . em))
+      (symbol "⦵")
+      (text "x"))
+    "Mode line icon to hide a visible password."
+    :group mode-line-faces
+    :version "30.1"
+    :help-echo "mouse-1: Toggle password visibility")
+
+  (setq read-passwd--hide-password nil
+        ;; Stolen from `eldoc-minibuffer-message'.
+        read-passwd--mode-line-buffer
+        (window-buffer
+         (or (window-in-direction 'above (minibuffer-window))
+            (minibuffer-selected-window)
+            (get-largest-window))))
+
+  (if read-passwd-mode
+      (with-current-buffer read-passwd--mode-line-buffer
+        ;; Add `read-passwd--mode-line-icon'.
+        (when (listp mode-line-format)
+          (setq mode-line-format
+                (cons '(:eval read-passwd--mode-line-icon)
+                     mode-line-format))))
+    (with-current-buffer read-passwd--mode-line-buffer
+      ;; Remove `read-passwd--mode-line-icon'.
+      (when (listp mode-line-format)
+        (setq mode-line-format (cdr mode-line-format)))))
+
+  (when read-passwd-mode
+    (read-passwd--toggle-visibility)))
+
 \f
 (defvar messages-buffer-mode-map
   (let ((map (make-sparse-keymap)))
index 90981caebdeedebc8c71db769d0876c8c39310fb..37d6d6540714de586c85a95b69e744d3ff660f6f 100644 (file)
@@ -3382,14 +3382,23 @@ with Emacs.  Do not call it directly in your own packages."
   (let ((map (make-sparse-keymap)))
     (set-keymap-parent map minibuffer-local-map)
     (define-key map "\C-u" #'delete-minibuffer-contents) ;bug#12570
+    (define-key map "\t" #'read-passwd--toggle-visibility)
     map)
   "Keymap used while reading passwords.")
 
-(defun read-password--hide-password ()
+(defvar read-passwd--hide-password t)
+
+(defun read-passwd--hide-password ()
+  "Make password in minibuffer hidden or visible."
   (let ((beg (minibuffer-prompt-end)))
     (dotimes (i (1+ (- (buffer-size) beg)))
-      (put-text-property (+ i beg) (+ 1 i beg)
-                         'display (string (or read-hide-char ?*))))))
+      (if read-passwd--hide-password
+          (put-text-property
+           (+ i beg) (+ 1 i beg) 'display (string (or read-hide-char ?*)))
+        (remove-list-of-text-properties (+ i beg) (+ 1 i beg) '(display)))
+      (put-text-property
+       (+ i beg) (+ 1 i beg)
+       'help-echo "C-u: Clear password\nTAB: Toggle password visibility"))))
 
 (defun read-passwd (prompt &optional confirm default)
   "Read a password, prompting with PROMPT, and return it.
@@ -3427,18 +3436,20 @@ by doing (clear-string STRING)."
             (setq-local inhibit-modification-hooks nil) ;bug#15501.
            (setq-local show-paren-mode nil)            ;bug#16091.
             (setq-local inhibit--record-char t)
-            (add-hook 'post-command-hook #'read-password--hide-password nil t))
+            (read-passwd-mode 1)
+            (add-hook 'post-command-hook #'read-passwd--hide-password nil t))
         (unwind-protect
             (let ((enable-recursive-minibuffers t)
                  (read-hide-char (or read-hide-char ?*)))
               (read-string prompt nil t default)) ; t = "no history"
           (when (buffer-live-p minibuf)
             (with-current-buffer minibuf
+              (read-passwd-mode -1)
               ;; Not sure why but it seems that there might be cases where the
               ;; minibuffer is not always properly reset later on, so undo
               ;; whatever we've done here (bug#11392).
               (remove-hook 'after-change-functions
-                           #'read-password--hide-password 'local)
+                           #'read-passwd--hide-password 'local)
               (kill-local-variable 'post-self-insert-hook)
               ;; And of course, don't keep the sensitive data around.
               (erase-buffer))))))))