Subject: bug#69237: closed (Re: bug#69237: 30.0.50; Toggle password visibility)

From: [email-masked] (GNU bug Tracking System)
Date: Sun, 25 Feb 2024 09:26:02 +0000

Your bug report

#69237: 30.0.50; Toggle password visibility

which was filed against the emacs package, has been closed.

The explanation is attached below, along with your original report.
If you require more details, please reply to [email-masked].

-- 
69237: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=69237
GNU Bug Tracking System
Contact [email-masked] with problems

Subject: Re: bug#69237: 30.0.50; Toggle password visibility
From: Michael Albinus <[email-masked]>
To: Kévin Le Gouguec <[email-masked]>
Cc: [email-masked]
Date: Sun, 25 Feb 2024 10:11:03 +0100
List-Id: <debbugs-submit.debbugs.gnu.org>

Version: 30.1

Kévin Le Gouguec <[email-masked]> writes:

Hi,

>> There are not so many comments on the keybindings. I guess this is
>> because only few people read the bug-gnu-emacs ML. Let's install this on
>> master, and see who hollers :-)
>
> Works for me 😊  Thanks for adding icons.el support!

No further comments, so I have pushed this to master. Closing th bug.

Best regards, Michael.

Subject: 30.0.50; Toggle password visibility
From: Michael Albinus <[email-masked]>
To: [email-masked]
Date: Fri, 16 Feb 2024 14:33:02 +0100
List-Id: <debbugs-submit.debbugs.gnu.org>

We have `read-passwd', which reads a password in the minibuffer, hiding
the input. However, modern password input boxes outside Emacs allow to
show/hide the input while typing.

The appended patch tries to implement this feature. The minibuffer in
`read-passwd' has bound TAB to a function, which toggles visibility of
the typed input.

On graphic displays, the mode-line has an additional indicator for
whowing/hiding the typed password. Clicking on this indicator with
mouse-1 toggles the password visibility.

Comments?

Best regards, Michael.

In GNU Emacs 30.0.50 (build 1, x86_64-pc-linux-gnu, GTK+ Version
 3.24.39, cairo version 1.18.0) of 2024-01-07 built on gandalf
Repository revision: 166b10e9f80dc78147601a87b6425f59860bcfe4
Repository branch: master
Windowing system distributor 'The X.Org Foundation', version 11.0.12302004
System Description: Fedora Linux 39 (Workstation Edition)

Configured features:
ACL CAIRO DBUS FREETYPE GIF GLIB GMP GNUTLS GPM GSETTINGS HARFBUZZ JPEG
LIBOTF LIBSELINUX LIBXML2 M17N_FLT MODULES NATIVE_COMP NOTIFY INOTIFY
PDUMPER PNG RSVG SECCOMP SOUND SQLITE3 THREADS TIFF TOOLKIT_SCROLL_BARS
TREE_SITTER X11 XDBE XIM XINPUT2 XPM GTK3 ZLIB

Important settings:
  value of $LANG: en_US.UTF-8
  value of $XMODIFIERS: @im=ibus
  locale-coding-system: utf-8

Major mode: Group

Minor modes in effect:
  gnus-undo-mode: t
  display-time-mode: t
  delete-selection-mode: t
  icomplete-mode: t
  global-goto-address-mode: t
  goto-address-mode: t
  tooltip-mode: t
  global-eldoc-mode: t
  show-paren-mode: t
  electric-indent-mode: t
  mouse-wheel-mode: t
  menu-bar-mode: t
  file-name-shadow-mode: t
  global-font-lock-mode: t
  font-lock-mode: t
  blink-cursor-mode: t
  minibuffer-regexp-mode: t
  buffer-read-only: t
  column-number-mode: t
  line-number-mode: t
  indent-tabs-mode: t
  transient-mark-mode: t
  auto-composition-mode: t
  auto-encryption-mode: t
  auto-compression-mode: t

Load-path shadows:
/home/albinus/src/elpa/packages/debbugs/debbugs hides /home/albinus/.emacs.d/elpa/debbugs-0.39/debbugs
/home/albinus/src/elpa/packages/debbugs/debbugs-org hides /home/albinus/.emacs.d/elpa/debbugs-0.39/debbugs-org
/home/albinus/src/elpa/packages/debbugs/debbugs-gnu hides /home/albinus/.emacs.d/elpa/debbugs-0.39/debbugs-gnu
/home/albinus/src/elpa/packages/debbugs/debbugs-guix hides /home/albinus/.emacs.d/elpa/debbugs-0.39/debbugs-guix
/home/albinus/src/elpa/packages/debbugs/debbugs-browse hides /home/albinus/.emacs.d/elpa/debbugs-0.39/debbugs-browse
/home/albinus/src/elpa/packages/debbugs/debbugs-pkg hides /home/albinus/.emacs.d/elpa/debbugs-0.39/debbugs-pkg
/home/albinus/src/elpa/packages/debbugs/debbugs-autoloads hides /home/albinus/.emacs.d/elpa/debbugs-0.39/debbugs-autoloads
/home/albinus/src/elpa/packages/debbugs/debbugs-compat hides /home/albinus/.emacs.d/elpa/debbugs-0.39/debbugs-compat
/home/albinus/.emacs.d/elpa/helm-3.9.7/helm-packages hides /home/albinus/.emacs.d/elpa/helm-core-3.9.7/helm-packages
~/lisp/telepathy hides /home/albinus/.emacs.d/elpa/telepathy-20131209.1258/telepathy
/home/albinus/src/elpa/packages/tramp-theme/tramp-theme-autoloads hides /home/albinus/.emacs.d/elpa/tramp-theme-0.2/tramp-theme-autoloads
/home/albinus/src/elpa/packages/tramp-theme/tramp-theme hides /home/albinus/.emacs.d/elpa/tramp-theme-0.2/tramp-theme
/home/albinus/src/elpa/packages/tramp-theme/tramp-theme-pkg hides /home/albinus/.emacs.d/elpa/tramp-theme-0.2/tramp-theme-pkg
/home/albinus/.emacs.d/elpa/hydra-0.15.0/lv hides /home/albinus/.emacs.d/elpa/lv-0.15.0/lv
/home/albinus/.emacs.d/elpa/transient-20240201.1100/transient hides /usr/local/share/emacs/30.0.50/lisp/transient
~/lisp/dbus hides /usr/local/share/emacs/30.0.50/lisp/net/dbus
/home/albinus/src/tramp/lisp/tramp-sh hides /usr/local/share/emacs/30.0.50/lisp/net/tramp-sh
/home/albinus/src/tramp/lisp/tramp-fuse hides /usr/local/share/emacs/30.0.50/lisp/net/tramp-fuse
/home/albinus/src/tramp/lisp/tramp-loaddefs hides /usr/local/share/emacs/30.0.50/lisp/net/tramp-loaddefs
/home/albinus/src/tramp/lisp/tramp-ftp hides /usr/local/share/emacs/30.0.50/lisp/net/tramp-ftp
/home/albinus/src/tramp/lisp/tramp hides /usr/local/share/emacs/30.0.50/lisp/net/tramp
/home/albinus/src/tramp/lisp/tramp-cache hides /usr/local/share/emacs/30.0.50/lisp/net/tramp-cache
/home/albinus/src/tramp/lisp/tramp-uu hides /usr/local/share/emacs/30.0.50/lisp/net/tramp-uu
/home/albinus/src/tramp/lisp/tramp-rclone hides /usr/local/share/emacs/30.0.50/lisp/net/tramp-rclone
/home/albinus/src/tramp/lisp/tramp-integration hides /usr/local/share/emacs/30.0.50/lisp/net/tramp-integration
/home/albinus/src/tramp/lisp/tramp-archive hides /usr/local/share/emacs/30.0.50/lisp/net/tramp-archive
/home/albinus/src/tramp/lisp/tramp-adb hides /usr/local/share/emacs/30.0.50/lisp/net/tramp-adb
/home/albinus/src/tramp/lisp/tramp-cmds hides /usr/local/share/emacs/30.0.50/lisp/net/tramp-cmds
/home/albinus/src/tramp/lisp/tramp-compat hides /usr/local/share/emacs/30.0.50/lisp/net/tramp-compat
/home/albinus/src/tramp/lisp/tramp-sudoedit hides /usr/local/share/emacs/30.0.50/lisp/net/tramp-sudoedit
/home/albinus/src/tramp/lisp/tramp-container hides /usr/local/share/emacs/30.0.50/lisp/net/tramp-container
/home/albinus/src/tramp/lisp/tramp-gvfs hides /usr/local/share/emacs/30.0.50/lisp/net/tramp-gvfs
/home/albinus/src/tramp/lisp/tramp-crypt hides /usr/local/share/emacs/30.0.50/lisp/net/tramp-crypt
/home/albinus/src/tramp/lisp/tramp-message hides /usr/local/share/emacs/30.0.50/lisp/net/tramp-message
/home/albinus/src/tramp/lisp/tramp-smb hides /usr/local/share/emacs/30.0.50/lisp/net/tramp-smb
/home/albinus/src/tramp/lisp/trampver hides /usr/local/share/emacs/30.0.50/lisp/net/trampver
/home/albinus/src/tramp/lisp/tramp-sshfs hides /usr/local/share/emacs/30.0.50/lisp/net/tramp-sshfs

Features:
(shadow emacsbug whitespace vc-dir ewoc conf-mode smerge-mode diff
org-element org-persist org-id org-refile avl-tree generator oc-basic
ol-eww ol-rmail ol-mhe ol-irc ol-info ol-gnus nnselect ol-docview
doc-view filenotify ol-bibtex bibtex ol-bbdb ol-w3m ol-doi org-link-doi
org org-macro org-pcomplete org-list org-footnote org-faces org-entities
noutline outline ob-emacs-lisp org-table org-loaddefs cal-menu calendar
cal-loaddefs ediff-vers ediff ediff-merg ediff-mult ediff-wind
ediff-diff ediff-help ediff-init ediff-util hyperspec nndoc gnus-dup
debbugs-gnu debbugs-compat debbugs soap-client warnings mailalias debug
backtrace cl-print timezone find-func shortdoc help-fns radix-tree eww
mm-url macrostep-c cmacexp macrostep cc-mode cc-fonts cc-guess cc-menus
cc-cmds cc-styles cc-align cc-engine cc-vars cc-defs add-log vc-hg
vc-bzr vc-src vc-sccs vc-svn vc-cvs vc-rcs log-view pcvs-util pulse xref
project grep display-line-numbers url-queue gnus-fun shr-color color
flow-fill mm-archive url-http url-gw url-auth gnus-gravatar gravatar dns
url-cache smiley gnus-cite mail-extr gnus-bcklg textsec uni-scripts
idna-mapping ucs-normalize uni-confusable textsec-check gnus-async
cl-extra gnus-ml debbugs-browse bug-reference disp-table qp pop3 utf-7
nndraft nnmh nnml network-stream nsm gnus-agent gnus-srvr gnus-score
score-mode nnvirtual gnus-msg gnus-art mm-uu mml2015 mm-view mml-smime
smime gnutls dig gnus-cache gnus-sum shr pixel-fill kinsoku url-file svg
time-stamp nnnil smtpmail gnus-demon nntp gnus-group gnus-undo
gnus-start gnus-dbus dbus xml gnus-cloud nnimap nnmail mail-source utf7
nnoo gnus-spec gnus-int gnus-range message sendmail yank-media puny
rfc822 mml mml-sec epa derived epg rfc6068 epg-config mm-decode
mm-bodies mm-encode mail-parse rfc2231 rfc2047 rfc2045 ietf-drums
mailabbrev gmm-utils mailheader gnus-win gnus nnheader gnus-util
mail-utils range mm-util mail-prsvr magit-base magit-section
cursor-sensor crm dash compat mule-util sort find-dired vc-git diff-mode
easy-mmode misearch multi-isearch rng-xsd xsd-regexp rng-cmpct rng-nxml
rng-valid rng-loc rng-uri rng-parse nxml-parse rng-match rng-dt rng-util
rng-pttrn nxml-ns nxml-mode nxml-outln nxml-rap sgml-mode facemenu dom
nxml-util nxml-enc xmltok image-mode exif dired-aux compile
text-property-search comp-run comp-common face-remap ob-shell ob
ob-tangle ol org-src ob-ref ob-lob ob-table ob-exp ob-comint ob-core
org-cycle org-fold org-fold-core ob-eval org-keys oc org-compat
org-version org-macs vc vc-dispatcher time tramp-sh lxc-tramp lxd-tramp
tramp trampver tramp-integration files-x tramp-message help-mode
tramp-compat xdg shell pcomplete comint ansi-osc ring parse-time iso8601
time-date format-spec ansi-color tramp-loaddefs rx delsel ido jka-compr
icomplete cus-edit pp cus-load icons wid-edit dired dired-loaddefs
goto-addr thingatpt alert-autoloads android-mode-autoloads
auth-source-gopass-autoloads auth-source-keytar-autoloads
auth-source-kwallet-autoloads auth-source-xoauth2-autoloads
auto-sudoedit-autoloads auto-virtualenv-autoloads
auto-virtualenvwrapper-autoloads boxquote-autoloads
clang-format-autoloads company-shell-autoloads company-autoloads
counsel-toki-autoloads counsel-tramp-autoloads counsel-autoloads
dbus-codegen-autoloads debbugs-autoloads dired-du-autoloads
dired-rsync-autoloads dired-toggle-sudo-autoloads direnv-autoloads
disk-usage-autoloads dockerfile-mode-autoloads
editorconfig-charset-extras-autoloads
editorconfig-custom-majormode-autoloads
editorconfig-domain-specific-autoloads editorconfig-autoloads
editorconfig-generate-autoloads ednc-autoloads el-get-autoloads
envrc-autoloads etc-sudoers-mode-autoloads
exec-path-from-shell-autoloads fontaine-autoloads forge-autoloads
closql-autoloads emacsql-autoloads friendly-tramp-path-autoloads
fzf-autoloads ggtags-autoloads ghub-autoloads gited-autoloads
gitlab-ci-mode-flycheck-autoloads gitlab-ci-mode-autoloads
flycheck-autoloads gntp-autoloads gnus-desktop-notify-autoloads
helm-gitlab-autoloads helm-projectile-autoloads helm-autoloads
helm-core-autoloads async-autoloads ibuffer-tramp-autoloads
inheritenv-autoloads ivy-gitlab-autoloads gitlab-autoloads
journalctl-mode-autoloads keepass-mode-autoloads keytar-autoloads
kubernetes-autoloads log4e-autoloads lsp-java-autoloads
dap-mode-autoloads lsp-docker-autoloads bui-autoloads
lsp-latex-autoloads consult-autoloads lsp-treemacs-autoloads
lsp-mode-autoloads f-autoloads lxc-tramp-autoloads lxd-tramp-autoloads
magit-filenotify-autoloads magit-autoloads pcase git-commit-autoloads
magit-popup-autoloads magit-section-autoloads marcopolo-autoloads
mastodon-autoloads nexus-autoloads nnir-est-autoloads oauth2-autoloads
ob-restclient-autoloads orderless-autoloads persist-autoloads
pkg-info-autoloads epl-autoloads popup-autoloads projectile-autoloads
promise-autoloads pylint-autoloads python-environment-autoloads
deferred-autoloads pyvenv-autoloads
recentf-remove-sudo-tramp-prefix-autoloads request-autoloads
restclient-test-autoloads restclient-autoloads s3ed-autoloads finder-inf
slime-autoloads macrostep-autoloads spinner-autoloads
ssh-deploy-autoloads su-autoloads sudo-edit-autoloads sudo-ext-autoloads
sudo-utils-autoloads swiper-autoloads ivy-autoloads sx-autoloads
markdown-mode-autoloads telepathy-autoloads totp-autoloads
totp-auth-autoloads base32-autoloads tramp-theme-autoloads
transient-dwim-autoloads transient-autoloads treemacs-autoloads
cfrs-autoloads posframe-autoloads ht-autoloads pfuture-autoloads
ace-window-autoloads avy-autoloads treepy-autoloads uuid-autoloads
vdiff-autoloads hydra-autoloads lv-autoloads vertico-autoloads
virtualenv-autoloads virtualenvwrapper-autoloads s-autoloads
dash-autoloads web-server-autoloads wfnames-autoloads
with-editor-autoloads info compat-autoloads yaml-autoloads
yaml-mode-autoloads package browse-url url url-proxy url-privacy
url-expand url-methods url-history url-cookie generate-lisp-file
url-domsuf url-util mailcap url-handlers url-parse auth-source cl-seq
eieio eieio-core cl-macs password-cache json subr-x map byte-opt gv
bytecomp byte-compile url-vars cl-loaddefs cl-lib rmc iso-transl tooltip
cconv eldoc paren electric uniquify ediff-hook vc-hooks lisp-float-type
elisp-mode mwheel term/x-win x-win term/common-win x-dnd touch-screen
tool-bar dnd fontset image regexp-opt fringe tabulated-list replace
newcomment text-mode lisp-mode prog-mode register page tab-bar menu-bar
rfn-eshadow isearch easymenu timer select scroll-bar mouse jit-lock
font-lock syntax font-core term/tty-colors frame minibuffer nadvice seq
simple cl-generic indonesian philippine cham georgian utf-8-lang
misc-lang vietnamese tibetan thai tai-viet lao korean japanese eucjp-ms
cp51932 hebrew greek romanian slovak czech european ethiopic indian
cyrillic chinese composite emoji-zwj charscript charprop case-table
epa-hook jka-cmpr-hook help abbrev obarray oclosure cl-preloaded button
loaddefs theme-loaddefs faces cus-face macroexp files window
text-properties overlay sha1 md5 base64 format env code-pages mule
custom widget keymap hashtable-print-readable backquote threads dbusbind
inotify dynamic-setting system-font-setting font-render-setting cairo
gtk x-toolkit xinput2 x multi-tty move-toolbar make-network-process
native-compile emacs)

Memory information:
((conses 16 886899 163552) (symbols 48 39461 3)
 (strings 32 179866 14690) (string-bytes 1 5887530) (vectors 16 96047)
 (vector-slots 8 2459540 118160) (floats 8 849 18205)
 (intervals 56 34351 1182) (buffers 984 108))

diff --git a/etc/images/README b/etc/images/README
index a778d9ce6c3..77377d36b5a 100644
--- a/etc/images/README
+++ b/etc/images/README
@@ -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,5 @@ 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
diff --git a/etc/images/conceal.svg b/etc/images/conceal.svg
new file mode 100644
index 00000000000..172b73ed3d3
--- /dev/null
+++ b/etc/images/conceal.svg
@@ -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.svg b/etc/images/reveal.svg
new file mode 100644
index 00000000000..41ae3733a53
--- /dev/null
+++ b/etc/images/reveal.svg
@@ -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>
diff --git a/lisp/simple.el b/lisp/simple.el
index 9a33049f4ca..667b6c84a66 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -10858,6 +10858,80 @@ visible-mode
     (setq-local vis-mode-saved-buffer-invisibility-spec
                 buffer-invisibility-spec)
     (setq buffer-invisibility-spec nil)))
+
+
+;; It would be preferable to use "👁" ("\N{EYE}").  However, there is
+;; no corresponding Unicode char with a slash.  Therefore, we use images.
+(defvar read-passwd-show-password-image "reveal.svg"
+  "Mode-line image to show a hidden password")
+
+(defvar read-passwd-hide-password-image "conceal.svg"
+  "Mode-line image to hide a visible password")
+
+(defvar read-passwd-mode-line-buffer nil
+  "Buffer to modify `mode-line-format' for showing/hiding passwords.")
+
+(defvar read-passwd-mode-line-string nil
+  "Propertized mode line indicator for showing/hiding passwords.")
+
+(defvar read-passwd-mode-line-display nil
+  "Display properties for `read-passwd-mode-line-string'.")
+
+(defun read-passwd--toggle-visibility ()
+  "Toggle minibuffer contents visibility.
+Adapt also mode line."
+  (interactive)
+  (with-current-buffer read-passwd-mode-line-buffer
+    (setq read-passwd--hide-password (not read-passwd--hide-password))
+    (when (display-graphic-p)
+      (setq read-passwd-mode-line-display
+	    (find-image
+             `((:type svg
+                :file ,(if read-passwd--hide-password
+                           read-passwd-hide-password-image
+                         read-passwd-show-password-image))
+               :ascent center))
+            read-passwd-mode-line-string
+            `(:propertize " "
+              display ,read-passwd-mode-line-display
+              help-echo "mouse-1: Toggle password visibility"
+              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"
+  (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))))
+
+  (when (display-graphic-p)
+    (if read-passwd-mode
+        (with-current-buffer read-passwd-mode-line-buffer
+          ;; Add `read-passwd-mode-line-string'.
+          (when (listp mode-line-format)
+            (setq mode-line-format
+                  (cons '(:eval read-passwd-mode-line-string)
+	                mode-line-format))))
+      (with-current-buffer read-passwd-mode-line-buffer
+        ;; Remove `read-passwd-mode-line-string'.
+        (when (listp mode-line-format)
+          (setq mode-line-format (cdr mode-line-format))))))
+
+  (when read-passwd-mode
+    (read-passwd--toggle-visibility)))
+
 
 (defvar messages-buffer-mode-map
   (let ((map (make-sparse-keymap)))
diff --git a/lisp/subr.el b/lisp/subr.el
index c317d558e24..2f475891df9 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -3375,14 +3375,23 @@ read-passwd-map
   (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 minibuffer contents 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.
@@ -3420,18 +3429,20 @@ read-passwd
             (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"
+          (read-passwd-mode -1)
           (when (buffer-live-p minibuf)
             (with-current-buffer minibuf
               ;; 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))))))))