Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ivy-read: prompt interpreted as format-string #1350

Closed
vidagabor opened this issue Dec 6, 2017 · 4 comments
Closed

ivy-read: prompt interpreted as format-string #1350

vidagabor opened this issue Dec 6, 2017 · 4 comments

Comments

@vidagabor
Copy link

Hi!

That's the ivy-counterpart of issue bbatsov/projectile#1200. Projectile calls ivy-read by specifying the project name as prompt that (might) contain % signs. ivy-read expects prompt as format string (only at most one occurrence of %d), and format then end up in the below backtrace:

Debugger entered--Lisp error: (error "Not enough arguments for format string")
  format("[cee%dev%evidgbo_update] Find file" 18654)
  ivy--insert-prompt()
  ivy--insert-minibuffer(#("\n#shell%20%40%20~%2Fusr%2Fsrc%2Fcee%2Frepo%2Fcee%25dev%25evidgbo_update%2F#130793Kf#\nassign_roles\n.gitcommittemplate\n.gitignore\n.gitmodules\n.gitreview\n3pp/atlas/current_version.txt\n3pp/cis-cat/extract_result.pl\n3pp/cis-cat/master_status.sh" 0 1 (read-only nil) 1 84 (face ((:foreground "yellow") ivy-current-match) read-only nil) 84 239 (read-only nil)))
  ivy--exhibit()
  ivy--minibuffer-setup()
  #[0 "\302\303\301\242\"\210\300 \207" [ivy--minibuffer-setup (#0) remove-hook minibuffer-setup-hook] 3]()
  read-from-minibuffer("[cee%dev%evidgbo_update] Find file: " nil (keymap keymap (3 keymap (19 . ivy-rotate-sort) (1 . ivy-toggle-ignore) (15 . ivy-occur)) (67108903 . ivy-avy) (33554464 . ivy-restrict-to-matches) (15 . hydra-ivy/body) (22 . ivy-scroll-up-command) (7 . minibuffer-keyboard-quit) (32 . self-insert-command) (18 . ivy-reverse-i-search) (19 . ivy-next-line-or-history) (remap keymap (describe-mode . ivy-help) (kill-ring-save . ivy-kill-ring-save) (kill-line . ivy-kill-line) (scroll-down-command . ivy-scroll-down-command) (scroll-up-command . ivy-scroll-up-command) (end-of-buffer . ivy-end-of-buffer) (beginning-of-buffer . ivy-beginning-of-buffer) (kill-word . ivy-kill-word) (forward-char . ivy-forward-char) (delete-char . ivy-delete-char) (backward-kill-word . ivy-backward-kill-word) (backward-delete-char-untabify . ivy-backward-delete-char) (delete-backward-char . ivy-backward-delete-char) (previous-line . ivy-previous-line) (next-line . ivy-next-line)) (9 . ivy-partial-or-done) (10 . ivy-alt-done) (27 keymap (1 . ivy-read-action) (15 . ivy-dispatching-call) (111 . ivy-dispatching-done) (105 . ivy-insert-current) (106 . ivy-yank-word) (114 . ivy-toggle-regexp-quote) (16 . ivy-previous-line-and-call) (14 . ivy-next-line-and-call) (118 . ivy-scroll-down-command) (112 . ivy-previous-history-element) (110 . ivy-next-history-element) (10 . ivy-immediate-done) (13 . ivy-call)) (13 . ivy-done)) nil ivy-history)
  ivy-read("[cee%dev%evidgbo_update] Find file: " ("#shell%20%40%20~%2Fusr%2Fsrc%2Fcee%2Frepo%2Fcee%25dev%25evidgbo_update%2F#130793Kf#" "assign_roles" ".gitcommittemplate" ".gitignore" ".gitmodules" ".gitreview" "3pp/atlas/current_version.txt" "3pp/cis-cat/extract_result.pl" "3pp/cis-cat/master_status.sh" "3pp/cis-cat/run_ciscat.sh" "3pp/cis-cat/settings.txt" "3pp/css/current_version.txt" "3pp/hds-agent/current_version.txt" "3pp/sdn/current_version.txt" "3pp/sdn/get_versions" "Makefile" "backports/robot/paramiko/LICENSE" "backports/robot/paramiko/MANIFEST.in" "backports/robot/paramiko/PKG-INFO" "backports/robot/paramiko/README" "backports/robot/paramiko/debian/changelog" "backports/robot/paramiko/debian/clean" "backports/robot/paramiko/debian/compat" "backports/robot/paramiko/debian/control" "backports/robot/paramiko/debian/copyright" "backports/robot/paramiko/debian/gbp.conf" "backports/robot/paramiko/debian/paramiko-doc.doc-base" "backports/robot/paramiko/debian/paramiko-doc.docs" "backports/robot/paramiko/debian/paramiko-doc.examples" "backports/robot/paramiko/debian/paramiko-doc.links" "backports/robot/paramiko/debian/patches/0001-Localize-generated-documentation.patch" "backports/robot/paramiko/debian/patches/series" "backports/robot/paramiko/debian/rules" "backports/robot/paramiko/debian/source/format" "backports/robot/paramiko/debian/source/options" "backports/robot/paramiko/debian/tests/control" "backports/robot/paramiko/debian/tests/upstream" "backports/robot/paramiko/debian/watch" "backports/robot/paramiko/demos/demo.py" "backports/robot/paramiko/demos/demo_keygen.py" "backports/robot/paramiko/demos/demo_server.py" "backports/robot/paramiko/demos/demo_sftp.py" "backports/robot/paramiko/demos/demo_simple.py" "backports/robot/paramiko/demos/forward.py" "backports/robot/paramiko/demos/interactive.py" "backports/robot/paramiko/demos/rforward.py" "backports/robot/paramiko/demos/test_rsa.key" "backports/robot/paramiko/demos/user_rsa_key" "backports/robot/paramiko/demos/user_rsa_key.pub" "backports/robot/paramiko/docs/.buildinfo" ...) :initial-input nil :caller projectile-completing-read)
  projectile-completing-read("Find file: " ("#shell%20%40%20~%2Fusr%2Fsrc%2Fcee%2Frepo%2Fcee%25dev%25evidgbo_update%2F#130793Kf#" "assign_roles" ".gitcommittemplate" ".gitignore" ".gitmodules" ".gitreview" "3pp/atlas/current_version.txt" "3pp/cis-cat/extract_result.pl" "3pp/cis-cat/master_status.sh" "3pp/cis-cat/run_ciscat.sh" "3pp/cis-cat/settings.txt" "3pp/css/current_version.txt" "3pp/hds-agent/current_version.txt" "3pp/sdn/current_version.txt" "3pp/sdn/get_versions" "Makefile" "backports/robot/paramiko/LICENSE" "backports/robot/paramiko/MANIFEST.in" "backports/robot/paramiko/PKG-INFO" "backports/robot/paramiko/README" "backports/robot/paramiko/debian/changelog" "backports/robot/paramiko/debian/clean" "backports/robot/paramiko/debian/compat" "backports/robot/paramiko/debian/control" "backports/robot/paramiko/debian/copyright" "backports/robot/paramiko/debian/gbp.conf" "backports/robot/paramiko/debian/paramiko-doc.doc-base" "backports/robot/paramiko/debian/paramiko-doc.docs" "backports/robot/paramiko/debian/paramiko-doc.examples" "backports/robot/paramiko/debian/paramiko-doc.links" "backports/robot/paramiko/debian/patches/0001-Localize-generated-documentation.patch" "backports/robot/paramiko/debian/patches/series" "backports/robot/paramiko/debian/rules" "backports/robot/paramiko/debian/source/format" "backports/robot/paramiko/debian/source/options" "backports/robot/paramiko/debian/tests/control" "backports/robot/paramiko/debian/tests/upstream" "backports/robot/paramiko/debian/watch" "backports/robot/paramiko/demos/demo.py" "backports/robot/paramiko/demos/demo_keygen.py" "backports/robot/paramiko/demos/demo_server.py" "backports/robot/paramiko/demos/demo_sftp.py" "backports/robot/paramiko/demos/demo_simple.py" "backports/robot/paramiko/demos/forward.py" "backports/robot/paramiko/demos/interactive.py" "backports/robot/paramiko/demos/rforward.py" "backports/robot/paramiko/demos/test_rsa.key" "backports/robot/paramiko/demos/user_rsa_key" "backports/robot/paramiko/demos/user_rsa_key.pub" "backports/robot/paramiko/docs/.buildinfo" ...))
  projectile-find-file(nil)
  funcall-interactively(projectile-find-file nil)
  call-interactively(projectile-find-file nil nil)
  command-execute(projectile-find-file)

@abo-abo suggested to open an issue on ivy, he has ideas how to handle this within ivy.

@basil-conto
Copy link
Collaborator

basil-conto commented Nov 15, 2018

only at most one occurrence of %d

In theory, the second %d could be replaced with the total number of candidates, as is already done elsewhere in Ivy.

Projectile calls ivy-read by specifying the project name as prompt that (might) contain % signs.

Here's a simple repro:

  1. make plain
  2. (ivy-read "foo %s: " '("a" "b" "c"))
  3. C-j

Here's the resulting backtrace:

Debugger entered--Lisp error: (error "Not enough arguments for format string")
  format("%-4d foo %s" 3)
  (if (string-match "%d.*%d" ivy-count-format) (format head (1+ ivy--index) (or (and (progn (or (and (memq ... cl-struct-ivy-state-tags) t) (signal 'wrong-type-argument (list ... ivy-last))) (aref ivy-last 19)) ivy--full-length) ivy--length)) (format head (or (and (progn (or (and (memq ... cl-struct-ivy-state-tags) t) (signal 'wrong-type-argument (list ... ivy-last))) (aref ivy-last 19)) ivy--full-length) ivy--length)))
  (concat (if (string-match "%d.*%d" ivy-count-format) (format head (1+ ivy--index) (or (and (progn (or (and ... t) (signal ... ...)) (aref ivy-last 19)) ivy--full-length) ivy--length)) (format head (or (and (progn (or (and ... t) (signal ... ...)) (aref ivy-last 19)) ivy--full-length) ivy--length))) ivy--prompt-extra tail)
  (concat (if (and (and (boundp 'minibuffer-depth-indicate-mode) minibuffer-depth-indicate-mode) (> (minibuffer-depth) 1)) (format "[%d] " (minibuffer-depth)) "") (concat (if (string-match "%d.*%d" ivy-count-format) (format head (1+ ivy--index) (or (and (progn (or ... ...) (aref ivy-last 19)) ivy--full-length) ivy--length)) (format head (or (and (progn (or ... ...) (aref ivy-last 19)) ivy--full-length) ivy--length))) ivy--prompt-extra tail))
  (let ((inhibit-read-only t) (std-props '(front-sticky t rear-nonsticky t field t read-only t)) (n-str (concat (if (and (and (boundp ...) minibuffer-depth-indicate-mode) (> (minibuffer-depth) 1)) (format "[%d] " (minibuffer-depth)) "") (concat (if (string-match "%d.*%d" ivy-count-format) (format head (1+ ivy--index) (or ... ivy--length)) (format head (or ... ivy--length))) ivy--prompt-extra tail))) (d-str (if ivy--directory (abbreviate-file-name ivy--directory) ""))) (save-excursion (goto-char (point-min)) (delete-region (point-min) (minibuffer-prompt-end)) (let ((len-n (length n-str)) (len-d (length d-str)) (ww (window-width))) (setq n-str (cond ((> (+ len-n len-d) ww) (concat n-str "\n" d-str "\n")) ((> (+ len-n len-d ...) ww) (concat n-str d-str "\n")) (t (concat n-str d-str))))) (if ivy-add-newline-after-prompt (progn (setq n-str (concat n-str "\n")))) (let ((regex (format "\\([^\n]\\{%d\\}\\)[^\n]" (window-width)))) (while (string-match regex n-str) (setq n-str (replace-match (concat (match-string 1 n-str) "\n") nil t n-str 1)))) (set-text-properties 0 (length n-str) (cons 'face (cons 'minibuffer-prompt std-props)) n-str) (setq n-str (funcall ivy-set-prompt-text-properties-function n-str std-props)) (insert n-str)) (if (ivy--prompt-selectable-p) (progn (if (or (= ivy--index -1) (= ivy--length 0)) (ivy-add-face-text-property (minibuffer-prompt-end) (line-end-position) 'ivy-prompt-match) (remove-list-of-text-properties (minibuffer-prompt-end) (line-end-position) '(face))))) (constrain-to-field nil (point-max)))
  (let (head tail) (if (string-match "\\(.*?\\)\\(:? ?\\)\\'" ivy--prompt) (progn (setq head (match-string 1 ivy--prompt)) (setq tail (match-string 2 ivy--prompt))) (setq head ivy--prompt) (setq tail "")) (let ((inhibit-read-only t) (std-props '(front-sticky t rear-nonsticky t field t read-only t)) (n-str (concat (if (and (and ... minibuffer-depth-indicate-mode) (> ... 1)) (format "[%d] " (minibuffer-depth)) "") (concat (if (string-match "%d.*%d" ivy-count-format) (format head ... ...) (format head ...)) ivy--prompt-extra tail))) (d-str (if ivy--directory (abbreviate-file-name ivy--directory) ""))) (save-excursion (goto-char (point-min)) (delete-region (point-min) (minibuffer-prompt-end)) (let ((len-n (length n-str)) (len-d (length d-str)) (ww (window-width))) (setq n-str (cond ((> ... ww) (concat n-str "\n" d-str "\n")) ((> ... ww) (concat n-str d-str "\n")) (t (concat n-str d-str))))) (if ivy-add-newline-after-prompt (progn (setq n-str (concat n-str "\n")))) (let ((regex (format "\\([^\n]\\{%d\\}\\)[^\n]" (window-width)))) (while (string-match regex n-str) (setq n-str (replace-match (concat ... "\n") nil t n-str 1)))) (set-text-properties 0 (length n-str) (cons 'face (cons 'minibuffer-prompt std-props)) n-str) (setq n-str (funcall ivy-set-prompt-text-properties-function n-str std-props)) (insert n-str)) (if (ivy--prompt-selectable-p) (progn (if (or (= ivy--index -1) (= ivy--length 0)) (ivy-add-face-text-property (minibuffer-prompt-end) (line-end-position) 'ivy-prompt-match) (remove-list-of-text-properties (minibuffer-prompt-end) (line-end-position) '(face))))) (constrain-to-field nil (point-max))))
  (progn (if (memq this-command '(ivy-done ivy-alt-done ivy-partial-or-done counsel-find-symbol)) nil (setq ivy--prompt-extra "")) (let (head tail) (if (string-match "\\(.*?\\)\\(:? ?\\)\\'" ivy--prompt) (progn (setq head (match-string 1 ivy--prompt)) (setq tail (match-string 2 ivy--prompt))) (setq head ivy--prompt) (setq tail "")) (let ((inhibit-read-only t) (std-props '(front-sticky t rear-nonsticky t field t read-only t)) (n-str (concat (if (and ... ...) (format "[%d] " ...) "") (concat (if ... ... ...) ivy--prompt-extra tail))) (d-str (if ivy--directory (abbreviate-file-name ivy--directory) ""))) (save-excursion (goto-char (point-min)) (delete-region (point-min) (minibuffer-prompt-end)) (let ((len-n (length n-str)) (len-d (length d-str)) (ww (window-width))) (setq n-str (cond (... ...) (... ...) (t ...)))) (if ivy-add-newline-after-prompt (progn (setq n-str (concat n-str "\n")))) (let ((regex (format "\\([^\n]\\{%d\\}\\)[^\n]" ...))) (while (string-match regex n-str) (setq n-str (replace-match ... nil t n-str 1)))) (set-text-properties 0 (length n-str) (cons 'face (cons 'minibuffer-prompt std-props)) n-str) (setq n-str (funcall ivy-set-prompt-text-properties-function n-str std-props)) (insert n-str)) (if (ivy--prompt-selectable-p) (progn (if (or (= ivy--index -1) (= ivy--length 0)) (ivy-add-face-text-property (minibuffer-prompt-end) (line-end-position) 'ivy-prompt-match) (remove-list-of-text-properties (minibuffer-prompt-end) (line-end-position) '...)))) (constrain-to-field nil (point-max)))))
  (if (setq ivy--prompt (ivy-prompt)) (progn (if (memq this-command '(ivy-done ivy-alt-done ivy-partial-or-done counsel-find-symbol)) nil (setq ivy--prompt-extra "")) (let (head tail) (if (string-match "\\(.*?\\)\\(:? ?\\)\\'" ivy--prompt) (progn (setq head (match-string 1 ivy--prompt)) (setq tail (match-string 2 ivy--prompt))) (setq head ivy--prompt) (setq tail "")) (let ((inhibit-read-only t) (std-props '(front-sticky t rear-nonsticky t field t read-only t)) (n-str (concat (if ... ... "") (concat ... ivy--prompt-extra tail))) (d-str (if ivy--directory (abbreviate-file-name ivy--directory) ""))) (save-excursion (goto-char (point-min)) (delete-region (point-min) (minibuffer-prompt-end)) (let ((len-n ...) (len-d ...) (ww ...)) (setq n-str (cond ... ... ...))) (if ivy-add-newline-after-prompt (progn (setq n-str ...))) (let ((regex ...)) (while (string-match regex n-str) (setq n-str ...))) (set-text-properties 0 (length n-str) (cons 'face (cons ... std-props)) n-str) (setq n-str (funcall ivy-set-prompt-text-properties-function n-str std-props)) (insert n-str)) (if (ivy--prompt-selectable-p) (progn (if (or ... ...) (ivy-add-face-text-property ... ... ...) (remove-list-of-text-properties ... ... ...)))) (constrain-to-field nil (point-max))))))
  ivy--insert-prompt()
  (let ((resize-mini-windows nil) (update-fn (progn (or (and (memq (type-of ivy-last) cl-struct-ivy-state-tags) t) (signal 'wrong-type-argument (list 'ivy-state ivy-last))) (aref ivy-last 9))) (old-mark (marker-position (mark-marker))) deactivate-mark) (ivy--cleanup) (if update-fn (progn (funcall update-fn))) (ivy--insert-prompt) (if (stringp text) (progn (if ivy-display-function (funcall ivy-display-function text) (ivy-display-function-fallback text)))) (ivy--resize-minibuffer-to-fit) (if (region-active-p) (progn (set-mark old-mark))))
  ivy--insert-minibuffer(#("\na\nb\nc" 0 1 (read-only nil) 1 2 (read-only nil face ((:foreground "white") ivy-current-match) help-echo (format (if tooltip-mode "mouse-1: %s\nmouse-3: %s" "mouse-1: %s   mouse-3: %s") ivy-mouse-1-tooltip ivy-mouse-3-tooltip) mouse-face ivy-minibuffer-match-highlight) 2 3 (read-only nil) 3 4 (read-only nil help-echo (format (if tooltip-mode "mouse-1: %s\nmouse-3: %s" "mouse-1: %s   mouse-3: %s") ivy-mouse-1-tooltip ivy-mouse-3-tooltip) mouse-face ivy-minibuffer-match-highlight) 4 5 (read-only nil) 5 6 (read-only nil help-echo (format (if tooltip-mode "mouse-1: %s\nmouse-3: %s" "mouse-1: %s   mouse-3: %s") ivy-mouse-1-tooltip ivy-mouse-3-tooltip) mouse-face ivy-minibuffer-match-highlight)))
  (if (progn (or (and (memq (type-of ivy-last) cl-struct-ivy-state-tags) t) (signal 'wrong-type-argument (list 'ivy-state ivy-last))) (aref ivy-last 19)) (let ((inhibit-message t)) (if (equal ivy--old-text ivy-text) nil (condition-case nil (let ((inhibit-quit nil)) (catch 'input (let (... val) (setq val ...) (cond ... ... ...)))) (quit (setq quit-flag t) (eval '(ignore nil))))) (if (or ivy--all-candidates (not (get-process " *counsel*"))) (progn (ivy--insert-minibuffer (ivy--format ivy--all-candidates))))) (cond (ivy--directory (cond ((or (string= "~/" ivy-text) (and (string= "~" ivy-text) ivy-magic-tilde)) (ivy--cd (expand-file-name "~/"))) ((string-match "/\\'" ivy-text) (ivy--magic-file-slash)))) ((eq (progn (or (and (memq ... cl-struct-ivy-state-tags) t) (signal 'wrong-type-argument (list ... ivy-last))) (aref ivy-last 2)) #'internal-complete-buffer) (if (or (and (string-match "\\` " ivy-text) (not (string-match "\\` " ivy--old-text))) (and (string-match "\\` " ivy--old-text) (not (string-match "\\` " ivy-text)))) (progn (setq ivy--all-candidates (if (and ... ...) (ivy--buffer-list " ") (ivy--buffer-list "" ivy-use-virtual-buffers))) (setq ivy--old-re nil))))) (ivy--insert-minibuffer (save-current-buffer (set-buffer (progn (or (and (memq ... cl-struct-ivy-state-tags) t) (signal 'wrong-type-argument (list ... ivy-last))) (aref ivy-last 13))) (ivy--format (ivy--filter ivy-text ivy--all-candidates)))) (setq ivy--old-text ivy-text))
  (progn (let ((inhibit-field-text-motion nil)) (constrain-to-field nil (point-max))) (setq ivy-text (ivy--input)) (if (progn (or (and (memq (type-of ivy-last) cl-struct-ivy-state-tags) t) (signal 'wrong-type-argument (list 'ivy-state ivy-last))) (aref ivy-last 19)) (let ((inhibit-message t)) (if (equal ivy--old-text ivy-text) nil (condition-case nil (let ((inhibit-quit nil)) (catch 'input (let ... ... ...))) (quit (setq quit-flag t) (eval '...)))) (if (or ivy--all-candidates (not (get-process " *counsel*"))) (progn (ivy--insert-minibuffer (ivy--format ivy--all-candidates))))) (cond (ivy--directory (cond ((or (string= "~/" ivy-text) (and ... ivy-magic-tilde)) (ivy--cd (expand-file-name "~/"))) ((string-match "/\\'" ivy-text) (ivy--magic-file-slash)))) ((eq (progn (or (and ... t) (signal ... ...)) (aref ivy-last 2)) #'internal-complete-buffer) (if (or (and (string-match "\\` " ivy-text) (not ...)) (and (string-match "\\` " ivy--old-text) (not ...))) (progn (setq ivy--all-candidates (if ... ... ...)) (setq ivy--old-re nil))))) (ivy--insert-minibuffer (save-current-buffer (set-buffer (progn (or (and ... t) (signal ... ...)) (aref ivy-last 13))) (ivy--format (ivy--filter ivy-text ivy--all-candidates)))) (setq ivy--old-text ivy-text)))
  (if (memq 'ivy--queue-exhibit post-command-hook) (progn (let ((inhibit-field-text-motion nil)) (constrain-to-field nil (point-max))) (setq ivy-text (ivy--input)) (if (progn (or (and (memq (type-of ivy-last) cl-struct-ivy-state-tags) t) (signal 'wrong-type-argument (list 'ivy-state ivy-last))) (aref ivy-last 19)) (let ((inhibit-message t)) (if (equal ivy--old-text ivy-text) nil (condition-case nil (let (...) (catch ... ...)) (quit (setq quit-flag t) (eval ...)))) (if (or ivy--all-candidates (not (get-process " *counsel*"))) (progn (ivy--insert-minibuffer (ivy--format ivy--all-candidates))))) (cond (ivy--directory (cond ((or ... ...) (ivy--cd ...)) ((string-match "/\\'" ivy-text) (ivy--magic-file-slash)))) ((eq (progn (or ... ...) (aref ivy-last 2)) #'internal-complete-buffer) (if (or (and ... ...) (and ... ...)) (progn (setq ivy--all-candidates ...) (setq ivy--old-re nil))))) (ivy--insert-minibuffer (save-current-buffer (set-buffer (progn (or ... ...) (aref ivy-last 13))) (ivy--format (ivy--filter ivy-text ivy--all-candidates)))) (setq ivy--old-text ivy-text))))
  ivy--exhibit()
  ivy--minibuffer-setup()
  funcall(ivy--minibuffer-setup)
  (closure ((setup-hook . #0) (fun . ivy--minibuffer-setup) (height . 10) (transformer-fn) (caller . eval-print-last-sexp) (dynamic-collection) (matcher) (re-builder) (unwind) (action 1 ("o" identity "default") ("i" (closure (bookmark-alist recentf-list avy-styles-alist avy-style avy-keys-alist avy-keys avy-action avy-all-windows cl-struct-ivy-state-tags t) (x) (insert (if (stringp x) x (car x)))) "insert") ("w" (closure (bookmark-alist recentf-list avy-styles-alist avy-style avy-keys-alist avy-keys avy-action avy-all-windows cl-struct-ivy-state-tags t) (x) (kill-new (if (stringp x) x (car x)))) "copy")) (sort) (update-fn) (keymap) (def) (preselect) (history) (initial-input) (require-match) (predicate) (--cl-rest--) (collection "a" "b" "c") (prompt . "foo %s: ") avy-styles-alist avy-style avy-keys-alist avy-keys avy-action avy-all-windows cl-struct-ivy-state-tags t) nil (remove-hook 'minibuffer-setup-hook setup-hook) (funcall fun))()
  read-from-minibuffer("foo %s: " nil (keymap keymap (3 keymap (19 . ivy-rotate-sort) (1 . ivy-toggle-ignore) (15 . ivy-occur)) (67108903 . ivy-avy) (33554464 . ivy-restrict-to-matches) (15 . hydra-ivy/body) (22 . ivy-scroll-up-command) (prior . ivy-scroll-down-command) (next . ivy-scroll-up-command) (7 . minibuffer-keyboard-quit) (right . ivy-forward-char) (32 . self-insert-command) (18 . ivy-reverse-i-search) (19 . ivy-next-line-or-history) (remap keymap (describe-mode . ivy-help) (kill-ring-save . ivy-kill-ring-save) (kill-whole-line . ivy-kill-whole-line) (kill-line . ivy-kill-line) (scroll-down-command . ivy-scroll-down-command) (scroll-up-command . ivy-scroll-up-command) (end-of-buffer . ivy-end-of-buffer) (beginning-of-buffer . ivy-beginning-of-buffer) (kill-word . ivy-kill-word) (forward-char . ivy-forward-char) (delete-char . ivy-delete-char) (backward-kill-word . ivy-backward-kill-word) (backward-delete-char-untabify . ivy-backward-delete-char) (delete-backward-char . ivy-backward-delete-char) (previous-line . ivy-previous-line) (next-line . ivy-next-line)) (9 . ivy-partial-or-done) (10 . ivy-alt-done) (27 keymap (1 . ivy-read-action) (15 . ivy-dispatching-call) (111 . ivy-dispatching-done) (105 . ivy-insert-current) (106 . ivy-yank-word) (114 . ivy-toggle-regexp-quote) (16 . ivy-previous-line-and-call) (14 . ivy-next-line-and-call) (118 . ivy-scroll-down-command) (112 . ivy-previous-history-element) (110 . ivy-next-history-element) (10 . ivy-immediate-done) (13 . ivy-call)) (mouse-3 . ivy-mouse-dispatching-done) (mouse-1 . ivy-mouse-done) (down-mouse-1 . ignore) (13 . ivy-done)) nil ivy-history)
  (if (and ivy-auto-select-single-candidate (= (length ivy--all-candidates) 1)) (progn (progn (or (and (memq (type-of ivy-last) cl-struct-ivy-state-tags) t) (signal 'wrong-type-argument (list 'ivy-state ivy-last))) (let* ((v ivy-last)) (aset v 23 (car ivy--all-candidates)))) (setq ivy-exit 'done)) (read-from-minibuffer prompt (progn (or (and (memq (type-of ivy-last) cl-struct-ivy-state-tags) t) (signal 'wrong-type-argument (list 'ivy-state ivy-last))) (aref ivy-last 5)) (make-composed-keymap keymap ivy-minibuffer-map) nil hist))
  (let* ((hist (or history 'ivy-history)) (minibuffer-completion-table collection) (minibuffer-completion-predicate predicate) (ivy-height height) (resize-mini-windows (cond ((display-graphic-p) nil) ((null resize-mini-windows) 'grow-only) (t resize-mini-windows)))) (if (and ivy-auto-select-single-candidate (= (length ivy--all-candidates) 1)) (progn (progn (or (and (memq (type-of ivy-last) cl-struct-ivy-state-tags) t) (signal 'wrong-type-argument (list 'ivy-state ivy-last))) (let* ((v ivy-last)) (aset v 23 (car ivy--all-candidates)))) (setq ivy-exit 'done)) (read-from-minibuffer prompt (progn (or (and (memq (type-of ivy-last) cl-struct-ivy-state-tags) t) (signal 'wrong-type-argument (list 'ivy-state ivy-last))) (aref ivy-last 5)) (make-composed-keymap keymap ivy-minibuffer-map) nil hist)) (if (eq ivy-exit 'done) (progn (let ((item (if ivy--directory (progn ... ...) ivy-text))) (if (equal item "") nil (set hist (cons (propertize item ... ivy--index) (delete item ...))))))) (progn (or (and (memq (type-of ivy-last) cl-struct-ivy-state-tags) t) (signal 'wrong-type-argument (list 'ivy-state ivy-last))) (aref ivy-last 23)))
  (progn (add-hook 'minibuffer-setup-hook setup-hook) (let* ((hist (or history 'ivy-history)) (minibuffer-completion-table collection) (minibuffer-completion-predicate predicate) (ivy-height height) (resize-mini-windows (cond ((display-graphic-p) nil) ((null resize-mini-windows) 'grow-only) (t resize-mini-windows)))) (if (and ivy-auto-select-single-candidate (= (length ivy--all-candidates) 1)) (progn (progn (or (and (memq ... cl-struct-ivy-state-tags) t) (signal 'wrong-type-argument (list ... ivy-last))) (let* ((v ivy-last)) (aset v 23 (car ivy--all-candidates)))) (setq ivy-exit 'done)) (read-from-minibuffer prompt (progn (or (and (memq ... cl-struct-ivy-state-tags) t) (signal 'wrong-type-argument (list ... ivy-last))) (aref ivy-last 5)) (make-composed-keymap keymap ivy-minibuffer-map) nil hist)) (if (eq ivy-exit 'done) (progn (let ((item (if ivy--directory ... ivy-text))) (if (equal item "") nil (set hist (cons ... ...)))))) (progn (or (and (memq (type-of ivy-last) cl-struct-ivy-state-tags) t) (signal 'wrong-type-argument (list 'ivy-state ivy-last))) (aref ivy-last 23))))
  (unwind-protect (progn (add-hook 'minibuffer-setup-hook setup-hook) (let* ((hist (or history 'ivy-history)) (minibuffer-completion-table collection) (minibuffer-completion-predicate predicate) (ivy-height height) (resize-mini-windows (cond ((display-graphic-p) nil) ((null resize-mini-windows) 'grow-only) (t resize-mini-windows)))) (if (and ivy-auto-select-single-candidate (= (length ivy--all-candidates) 1)) (progn (progn (or (and ... t) (signal ... ...)) (let* (...) (aset v 23 ...))) (setq ivy-exit 'done)) (read-from-minibuffer prompt (progn (or (and ... t) (signal ... ...)) (aref ivy-last 5)) (make-composed-keymap keymap ivy-minibuffer-map) nil hist)) (if (eq ivy-exit 'done) (progn (let ((item ...)) (if (equal item "") nil (set hist ...))))) (progn (or (and (memq (type-of ivy-last) cl-struct-ivy-state-tags) t) (signal 'wrong-type-argument (list 'ivy-state ivy-last))) (aref ivy-last 23)))) (remove-hook 'minibuffer-setup-hook setup-hook))
  (let ((fun #'ivy--minibuffer-setup) setup-hook) (setq setup-hook #'(lambda nil (remove-hook 'minibuffer-setup-hook setup-hook) (funcall fun))) (unwind-protect (progn (add-hook 'minibuffer-setup-hook setup-hook) (let* ((hist (or history 'ivy-history)) (minibuffer-completion-table collection) (minibuffer-completion-predicate predicate) (ivy-height height) (resize-mini-windows (cond (... nil) (... ...) (t resize-mini-windows)))) (if (and ivy-auto-select-single-candidate (= (length ivy--all-candidates) 1)) (progn (progn (or ... ...) (let* ... ...)) (setq ivy-exit 'done)) (read-from-minibuffer prompt (progn (or ... ...) (aref ivy-last 5)) (make-composed-keymap keymap ivy-minibuffer-map) nil hist)) (if (eq ivy-exit 'done) (progn (let (...) (if ... nil ...)))) (progn (or (and (memq ... cl-struct-ivy-state-tags) t) (signal 'wrong-type-argument (list ... ivy-last))) (aref ivy-last 23)))) (remove-hook 'minibuffer-setup-hook setup-hook)))
  (unwind-protect (let ((fun #'ivy--minibuffer-setup) setup-hook) (setq setup-hook #'(lambda nil (remove-hook 'minibuffer-setup-hook setup-hook) (funcall fun))) (unwind-protect (progn (add-hook 'minibuffer-setup-hook setup-hook) (let* ((hist (or history ...)) (minibuffer-completion-table collection) (minibuffer-completion-predicate predicate) (ivy-height height) (resize-mini-windows (cond ... ... ...))) (if (and ivy-auto-select-single-candidate (= ... 1)) (progn (progn ... ...) (setq ivy-exit ...)) (read-from-minibuffer prompt (progn ... ...) (make-composed-keymap keymap ivy-minibuffer-map) nil hist)) (if (eq ivy-exit 'done) (progn (let ... ...))) (progn (or (and ... t) (signal ... ...)) (aref ivy-last 23)))) (remove-hook 'minibuffer-setup-hook setup-hook))) (put 'post-command-hook 'permanent-local nil) (remove-hook 'post-command-hook #'ivy--queue-exhibit) (let ((cleanup (ivy--display-function-prop :cleanup))) (if (functionp cleanup) (progn (funcall cleanup)))) (if (setq unwind (progn (or (and (memq (type-of ivy-last) cl-struct-ivy-state-tags) t) (signal 'wrong-type-argument (list 'ivy-state ivy-last))) (aref ivy-last 16))) (progn (funcall unwind))) (if (eq ivy-exit 'done) nil (ivy-recursive-restore)))
  (prog1 (unwind-protect (let ((fun #'ivy--minibuffer-setup) setup-hook) (setq setup-hook #'(lambda nil (remove-hook 'minibuffer-setup-hook setup-hook) (funcall fun))) (unwind-protect (progn (add-hook 'minibuffer-setup-hook setup-hook) (let* ((hist ...) (minibuffer-completion-table collection) (minibuffer-completion-predicate predicate) (ivy-height height) (resize-mini-windows ...)) (if (and ivy-auto-select-single-candidate ...) (progn ... ...) (read-from-minibuffer prompt ... ... nil hist)) (if (eq ivy-exit ...) (progn ...)) (progn (or ... ...) (aref ivy-last 23)))) (remove-hook 'minibuffer-setup-hook setup-hook))) (put 'post-command-hook 'permanent-local nil) (remove-hook 'post-command-hook #'ivy--queue-exhibit) (let ((cleanup (ivy--display-function-prop :cleanup))) (if (functionp cleanup) (progn (funcall cleanup)))) (if (setq unwind (progn (or (and (memq ... cl-struct-ivy-state-tags) t) (signal 'wrong-type-argument (list ... ivy-last))) (aref ivy-last 16))) (progn (funcall unwind))) (if (eq ivy-exit 'done) nil (ivy-recursive-restore))) (ivy-call) (let ((cur (progn (or (and (memq ... cl-struct-ivy-state-tags) t) (signal 'wrong-type-argument (list ... ivy-last))) (aref ivy-last 23)))) (remove-list-of-text-properties 0 (length cur) '(idx) cur)))
  (let ((ivy-recursive-last (and (active-minibuffer-window) ivy-last)) (transformer-fn (plist-get ivy--display-transformers-list (cond (caller) ((functionp collection) collection)))) (ivy-display-function (if (window-minibuffer-p) nil (or ivy-display-function (ivy-alist-setting ivy-display-functions-alist caller)))) (height (ivy--height caller))) (setq ivy-last (record 'ivy-state prompt collection predicate require-match initial-input history preselect keymap update-fn sort (selected-frame) (selected-window) (current-buffer) nil action unwind re-builder matcher dynamic-collection transformer-fn default-directory caller nil def)) (ivy--reset-state ivy-last) (prog1 (unwind-protect (let ((fun #'ivy--minibuffer-setup) setup-hook) (setq setup-hook #'(lambda nil (remove-hook ... setup-hook) (funcall fun))) (unwind-protect (progn (add-hook 'minibuffer-setup-hook setup-hook) (let* (... ... ... ... ...) (if ... ... ...) (if ... ...) (progn ... ...))) (remove-hook 'minibuffer-setup-hook setup-hook))) (put 'post-command-hook 'permanent-local nil) (remove-hook 'post-command-hook #'ivy--queue-exhibit) (let ((cleanup (ivy--display-function-prop :cleanup))) (if (functionp cleanup) (progn (funcall cleanup)))) (if (setq unwind (progn (or (and ... t) (signal ... ...)) (aref ivy-last 16))) (progn (funcall unwind))) (if (eq ivy-exit 'done) nil (ivy-recursive-restore))) (ivy-call) (let ((cur (progn (or (and ... t) (signal ... ...)) (aref ivy-last 23)))) (remove-list-of-text-properties 0 (length cur) '(idx) cur))))
  (progn (let ((extra-actions (delete-dups (append (plist-get ivy--actions-list t) (plist-get ivy--actions-list this-command) (plist-get ivy--actions-list caller))))) (if extra-actions (progn (setq action (cond ((functionp action) (cons 1 ...)) ((null action) (cons 1 ...)) (t (delete-dups ...))))))) (if caller nil (setq caller this-command)) (let ((extra-sources (plist-get ivy--sources-list caller))) (if extra-sources (progn (setq ivy--extra-candidates nil) (let ((--dolist-tail-- extra-sources)) (while --dolist-tail-- (let (...) (cond ... ...) (setq --dolist-tail-- ...))))) (setq ivy--extra-candidates '((original-source))))) (let ((ivy-recursive-last (and (active-minibuffer-window) ivy-last)) (transformer-fn (plist-get ivy--display-transformers-list (cond (caller) ((functionp collection) collection)))) (ivy-display-function (if (window-minibuffer-p) nil (or ivy-display-function (ivy-alist-setting ivy-display-functions-alist caller)))) (height (ivy--height caller))) (setq ivy-last (record 'ivy-state prompt collection predicate require-match initial-input history preselect keymap update-fn sort (selected-frame) (selected-window) (current-buffer) nil action unwind re-builder matcher dynamic-collection transformer-fn default-directory caller nil def)) (ivy--reset-state ivy-last) (prog1 (unwind-protect (let ((fun #'ivy--minibuffer-setup) setup-hook) (setq setup-hook #'(lambda nil ... ...)) (unwind-protect (progn (add-hook ... setup-hook) (let* ... ... ... ...)) (remove-hook 'minibuffer-setup-hook setup-hook))) (put 'post-command-hook 'permanent-local nil) (remove-hook 'post-command-hook #'ivy--queue-exhibit) (let ((cleanup (ivy--display-function-prop :cleanup))) (if (functionp cleanup) (progn (funcall cleanup)))) (if (setq unwind (progn (or ... ...) (aref ivy-last 16))) (progn (funcall unwind))) (if (eq ivy-exit 'done) nil (ivy-recursive-restore))) (ivy-call) (let ((cur (progn (or ... ...) (aref ivy-last 23)))) (remove-list-of-text-properties 0 (length cur) '(idx) cur)))))
  (progn (let ((--cl-keys-- --cl-rest--)) (while --cl-keys-- (cond ((memq (car --cl-keys--) '(:predicate :require-match :initial-input :history :preselect :def :keymap :update-fn :sort :action :unwind :re-builder :matcher :dynamic-collection :caller :allow-other-keys)) (setq --cl-keys-- (cdr (cdr --cl-keys--)))) ((car (cdr (memq ... --cl-rest--))) (setq --cl-keys-- nil)) (t (error "Keyword argument %s not one of (:predicate :requir..." (car --cl-keys--)))))) (progn (let ((extra-actions (delete-dups (append (plist-get ivy--actions-list t) (plist-get ivy--actions-list this-command) (plist-get ivy--actions-list caller))))) (if extra-actions (progn (setq action (cond (... ...) (... ...) (t ...)))))) (if caller nil (setq caller this-command)) (let ((extra-sources (plist-get ivy--sources-list caller))) (if extra-sources (progn (setq ivy--extra-candidates nil) (let ((--dolist-tail-- extra-sources)) (while --dolist-tail-- (let ... ... ...)))) (setq ivy--extra-candidates '((original-source))))) (let ((ivy-recursive-last (and (active-minibuffer-window) ivy-last)) (transformer-fn (plist-get ivy--display-transformers-list (cond (caller) (... collection)))) (ivy-display-function (if (window-minibuffer-p) nil (or ivy-display-function (ivy-alist-setting ivy-display-functions-alist caller)))) (height (ivy--height caller))) (setq ivy-last (record 'ivy-state prompt collection predicate require-match initial-input history preselect keymap update-fn sort (selected-frame) (selected-window) (current-buffer) nil action unwind re-builder matcher dynamic-collection transformer-fn default-directory caller nil def)) (ivy--reset-state ivy-last) (prog1 (unwind-protect (let ((fun ...) setup-hook) (setq setup-hook #'...) (unwind-protect (progn ... ...) (remove-hook ... setup-hook))) (put 'post-command-hook 'permanent-local nil) (remove-hook 'post-command-hook #'ivy--queue-exhibit) (let ((cleanup ...)) (if (functionp cleanup) (progn ...))) (if (setq unwind (progn ... ...)) (progn (funcall unwind))) (if (eq ivy-exit 'done) nil (ivy-recursive-restore))) (ivy-call) (let ((cur (progn ... ...))) (remove-list-of-text-properties 0 (length cur) '(idx) cur))))))
  (let* ((predicate (car (cdr (plist-member --cl-rest-- ':predicate)))) (require-match (car (cdr (plist-member --cl-rest-- ':require-match)))) (initial-input (car (cdr (plist-member --cl-rest-- ':initial-input)))) (history (car (cdr (plist-member --cl-rest-- ':history)))) (preselect (car (cdr (plist-member --cl-rest-- ':preselect)))) (def (car (cdr (plist-member --cl-rest-- ':def)))) (keymap (car (cdr (plist-member --cl-rest-- ':keymap)))) (update-fn (car (cdr (plist-member --cl-rest-- ':update-fn)))) (sort (car (cdr (plist-member --cl-rest-- ':sort)))) (action (car (cdr (plist-member --cl-rest-- ':action)))) (unwind (car (cdr (plist-member --cl-rest-- ':unwind)))) (re-builder (car (cdr (plist-member --cl-rest-- ':re-builder)))) (matcher (car (cdr (plist-member --cl-rest-- ':matcher)))) (dynamic-collection (car (cdr (plist-member --cl-rest-- ':dynamic-collection)))) (caller (car (cdr (plist-member --cl-rest-- ':caller))))) (progn (let ((--cl-keys-- --cl-rest--)) (while --cl-keys-- (cond ((memq (car --cl-keys--) '...) (setq --cl-keys-- (cdr ...))) ((car (cdr ...)) (setq --cl-keys-- nil)) (t (error "Keyword argument %s not one of (:predicate :requir..." (car --cl-keys--)))))) (progn (let ((extra-actions (delete-dups (append ... ... ...)))) (if extra-actions (progn (setq action (cond ... ... ...))))) (if caller nil (setq caller this-command)) (let ((extra-sources (plist-get ivy--sources-list caller))) (if extra-sources (progn (setq ivy--extra-candidates nil) (let (...) (while --dolist-tail-- ...))) (setq ivy--extra-candidates '(...)))) (let ((ivy-recursive-last (and (active-minibuffer-window) ivy-last)) (transformer-fn (plist-get ivy--display-transformers-list (cond ... ...))) (ivy-display-function (if (window-minibuffer-p) nil (or ivy-display-function ...))) (height (ivy--height caller))) (setq ivy-last (record 'ivy-state prompt collection predicate require-match initial-input history preselect keymap update-fn sort (selected-frame) (selected-window) (current-buffer) nil action unwind re-builder matcher dynamic-collection transformer-fn default-directory caller nil def)) (ivy--reset-state ivy-last) (prog1 (unwind-protect (let (... setup-hook) (setq setup-hook ...) (unwind-protect ... ...)) (put 'post-command-hook 'permanent-local nil) (remove-hook 'post-command-hook #'ivy--queue-exhibit) (let (...) (if ... ...)) (if (setq unwind ...) (progn ...)) (if (eq ivy-exit ...) nil (ivy-recursive-restore))) (ivy-call) (let ((cur ...)) (remove-list-of-text-properties 0 (length cur) '... cur)))))))
  ivy-read("foo %s: " ("a" "b" "c"))
  eval((ivy-read "foo %s: " '("a" "b" "c")) nil)
  elisp--eval-last-sexp(t)
  eval-last-sexp(t)
  eval-print-last-sexp(nil)
  funcall-interactively(eval-print-last-sexp nil)
  call-interactively(eval-print-last-sexp nil nil)
  command-execute(eval-print-last-sexp)

Here's a breakdown of the current formatting behaviour:

Expression Result
(ivy-read "foo %s: " ...) Error
(ivy-read "foo %s %s: " ...) Error
(ivy-read "foo %%s: " ...) Works
(ivy-read "foo %%d: " ...) ivy-count-format disappears
(ivy-read "foo %d: " ...) Works
(ivy-read "foo %d %d: " ...) Error
(completing-read "foo %s: " ...) Works
(completing-read "foo %s %s: " ...) Works
(completing-read "foo %%s: " ...) Works
(completing-read "foo %%d: " ...) ivy-count-format disappears
(completing-read "foo %d: " ...) ivy-count-format disappears
(completing-read "foo %d %d: " ...) ivy-count-format disappears

The disappearing ivy-count-format is caused by the following condition in ivy-add-prompt-count:

swiper/ivy.el

Lines 2029 to 2030 in d76968a

(cond ((string-match-p "%.*d" prompt)
prompt)

This breaks because e.g. %%d, which should not be counted as a format spec, is matched by %.*d.

@basil-conto
Copy link
Collaborator

Quoting @abo-abo from bbatsov/projectile#1200 (comment)

This should not be a too big issue, I don't think a lot of people use % in the prompt.

IME, a reasonably frequent source of format specs in completion prompts is when being prompted to open a URL, which may contain such escape codes.

@abo-abo
Copy link
Owner

abo-abo commented Nov 22, 2018

Thanks, please test.

basil-conto added a commit to basil-conto/swiper that referenced this issue Nov 22, 2018
doc/ivy.org:
Update ivy-read prompt description after recent change[1] re: abo-abo#1350.
doc/ivy.texi: Regenerate.

[1]: ivy.el (ivy-read): prompt argument is no longer a format string
  2018-11-22 09:39:35 +0100 6fe1a93
basil-conto added a commit to basil-conto/swiper that referenced this issue Nov 22, 2018
Don't ivy--quote-format-string prompt now that it is no longer
interpreted as a format string[1].

[1]: ivy.el (ivy-read): prompt argument is no longer a format string
  2018-11-22 09:39:35 +0100 6fe1a93

Re: abo-abo#1350
@basil-conto
Copy link
Collaborator

Thanks, please test.

Thanks, please see #1816 for some follow-ups.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants