abo-abo / swiper

Ivy - a generic completion frontend for Emacs, Swiper - isearch with an overview, and more. Oh, man!
https://oremacs.com/swiper/
2.31k stars 338 forks source link

counsel-M-x renders `bbdb-create` unusable #2683

Closed Apteryks closed 4 years ago

Apteryks commented 4 years ago

I use enable counsel-mode, which defines counsel-M-x as my primary M-x keybinding.

Upon attempting to use bbdb-create, I can proceed with the name, organization, and email address, but it then blocks on the snail mail (address) because the completion won't let me enter an empty string, which bbdb uses to interrupt prompting for a new address line entry.

I've edebug'd it, and it seems the problem has to do with the completion handler not being set to ivy-completing-read-with-empty-string-def, as it was apparently intended here https://github.com/abo-abo/swiper/blob/master/ivy.el#L161.

  (ivy-read prompt collection :predicate predicate :require-match (and collection require-match) :initial-input (cond ((consp initial-input) (car initial-input)) ((and (stringp initial-input) (not (eq collection #'read-file-name-internal)) (string-match-p "\\+" initial-input)) (replace-regexp-in-string "\\+" "\\\\+" initial-input)) (t initial-input)) :preselect def :def def :history history :keymap nil :dynamic-collection ivy-completing-read-dynamic-collection :caller (if (and collection (symbolp collection)) collection this-command))
  (let ((str (ivy-read prompt collection :predicate predicate :require-match (and collection require-match) :initial-input (cond ((consp initial-input) (car initial-input)) ((and (stringp initial-input) (not ...) (string-match-p "\\+" initial-input)) (replace-regexp-in-string "\\+" "\\\\+" initial-input)) (t initial-input)) :preselect def :def def :history history :keymap nil :dynamic-collection ivy-completing-read-dynamic-collection :caller (if (and collection (symbolp collection)) collection this-command)))) (if (string= str "") (or def "") str))
  (if handler (let ((completion-in-region-function #'completion--in-region) (ivy-completing-read-ignore-handlers-depth (1+ (minibuffer-depth)))) (funcall (cdr handler) prompt collection predicate require-match initial-input history def inherit-input-method)) (when (consp history) (when (numberp (cdr history)) (setq initial-input (nth (1- (cdr history)) (symbol-value (car history))))) (setq history (car history))) (when (consp def) (setq def (car def))) (let ((str (ivy-read prompt collection :predicate predicate :require-match (and collection require-match) :initial-input (cond ((consp initial-input) (car initial-input)) ((and ... ... ...) (replace-regexp-in-string "\\+" "\\\\+" initial-input)) (t initial-input)) :preselect def :def def :history history :keymap nil :dynamic-collection ivy-completing-read-dynamic-collection :caller (if (and collection (symbolp collection)) collection this-command)))) (if (string= str "") (or def "") str)))
  (let ((handler (and (< ivy-completing-read-ignore-handlers-depth (minibuffer-depth)) (assq this-command ivy-completing-read-handlers-alist)))) (if handler (let ((completion-in-region-function #'completion--in-region) (ivy-completing-read-ignore-handlers-depth (1+ (minibuffer-depth)))) (funcall (cdr handler) prompt collection predicate require-match initial-input history def inherit-input-method)) (when (consp history) (when (numberp (cdr history)) (setq initial-input (nth (1- (cdr history)) (symbol-value (car history))))) (setq history (car history))) (when (consp def) (setq def (car def))) (let ((str (ivy-read prompt collection :predicate predicate :require-match (and collection require-match) :initial-input (cond (... ...) (... ...) (t initial-input)) :preselect def :def def :history history :keymap nil :dynamic-collection ivy-completing-read-dynamic-collection :caller (if (and collection ...) collection this-command)))) (if (string= str "") (or def "") str))))
  ivy-completing-read("Snail Mail Address Label [RET when done]: " ("home (parents)" "home (mère)" "home" "work" "other") nil nil nil nil nil nil)
  completing-read("Snail Mail Address Label [RET when done]: " ("home (parents)" "home (mère)" "home" "work" "other") nil nil nil)
  (progn (add-hook 'minibuffer-setup-hook setup-hook) (completing-read prompt collection nil require-match init))
  (unwind-protect (progn (add-hook 'minibuffer-setup-hook setup-hook) (completing-read prompt collection nil require-match init)) (remove-hook 'minibuffer-setup-hook setup-hook))
  (let ((fun (lambda nil (use-local-map (let ((map ...)) (set-keymap-parent map (current-local-map)) (define-key map " " nil) (define-key map "?" nil) map)))) 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) (completing-read prompt collection nil require-match init)) (remove-hook 'minibuffer-setup-hook setup-hook)))
  (minibuffer-with-setup-hook (lambda nil (use-local-map (let ((map (make-sparse-keymap))) (set-keymap-parent map (current-local-map)) (define-key map " " nil) (define-key map "?" nil) map))) (completing-read prompt collection nil require-match init))
  (if collection (minibuffer-with-setup-hook (lambda nil (use-local-map (let ((map (make-sparse-keymap))) (set-keymap-parent map (current-local-map)) (define-key map " " nil) (define-key map "?" nil) map))) (completing-read prompt collection nil require-match init)) (read-string prompt init))
  (bbdb-string-trim (if collection (minibuffer-with-setup-hook (lambda nil (use-local-map (let ((map ...)) (set-keymap-parent map (current-local-map)) (define-key map " " nil) (define-key map "?" nil) map))) (completing-read prompt collection nil require-match init)) (read-string prompt init)))
  bbdb-read-string("Snail Mail Address Label [RET when done]: " nil ("home (parents)" "home (mère)" "home" "work" "other"))
  (setq label (bbdb-read-string "Snail Mail Address Label [RET when done]: " nil bbdb-address-label-list))
  (string= "" (setq label (bbdb-read-string "Snail Mail Address Label [RET when done]: " nil bbdb-address-label-list)))
  (not (string= "" (setq label (bbdb-read-string "Snail Mail Address Label [RET when done]: " nil bbdb-address-label-list))))
  (while (not (string= "" (setq label (bbdb-read-string "Snail Mail Address Label [RET when done]: " nil bbdb-address-label-list)))) (setq address (make-vector bbdb-address-length nil)) (bbdb-record-edit-address address label t) (push address addresses))
  (let (addresses label address) (while (not (string= "" (setq label (bbdb-read-string "Snail Mail Address Label [RET when done]: " nil bbdb-address-label-list)))) (setq address (make-vector bbdb-address-length nil)) (bbdb-record-edit-address address label t) (push address addresses)) (bbdb-record-set-address record (nreverse addresses)))
  (let ((record (bbdb-empty-record))) (let (name) (bbdb-error-retry (setq name (bbdb-read-name first-and-last)) (bbdb-check-name (car name) (cdr name))) (bbdb-record-set-firstname record (car name)) (bbdb-record-set-lastname record (cdr name))) (bbdb-record-set-organization record (bbdb-read-organization)) (bbdb-record-set-mail record (bbdb-split 'mail (bbdb-read-string "E-Mail Addresses: "))) (let (addresses label address) (while (not (string= "" (setq label (bbdb-read-string "Snail Mail Address Label [RET when done]: " nil bbdb-address-label-list)))) (setq address (make-vector bbdb-address-length nil)) (bbdb-record-edit-address address label t) (push address addresses)) (bbdb-record-set-address record (nreverse addresses))) (let (phones phone-list label) (while (not (string= "" (setq label (bbdb-read-string "Phone Label [RET when done]: " nil bbdb-phone-label-list)))) (setq phone-list (bbdb-error-retry (bbdb-parse-phone (read-string "Phone: " (and ... ...))))) (push (apply 'vector label phone-list) phones)) (bbdb-record-set-phone record (nreverse phones))) (let ((xfield (bbdb-read-xfield bbdb-default-xfield))) (unless (string= "" xfield) (bbdb-record-set-xfields record (list (cons bbdb-default-xfield xfield))))) record)
  bbdb-read-record(nil)
  (list (bbdb-read-record current-prefix-arg))
  call-interactively(bbdb-create record nil)
  command-execute(bbdb-create record)
  counsel-M-x-action("bbdb-create")
  ivy-call()
  ivy-read("M-x " [eww-buffer-select LaTeX-length-list gnus-agent-summary-mode-map epg-context-signers -flatten-n tex-chktex-program Undo ⇓\ \\Downarrow TeX-command-Biber edebug-trace js-jsx--text-properties magit-reflog-commit Span\ 720\.0\ days cache-buf vc-git-make-version-backups-p LaTeX-item-tabular* tramp-gvfs-handle-copy-file cl-hash-table-p none-but-delete nnmail-fix-eudora-headers brackets-after-symbol semantic-ctxt-current-assignment-python-mode gnus-summary-recenter makefile-browser-format-macro-line contained matched-string calcFunc-sec edebug-clear-frequency-count geiser-company--setup Printing\ Services calc-arccosh TeX-auto-local firstname guix-devel-indent-modify-phases-keyword Load\ snippets\.\.\. ↮\ \\nleftrightarrow Edebug\ All\ Defs time-format makefile-insert-gmake-function \' sub-element gnus-summary-catchup-from-here for\ environment geiser-smart-tab-mode-string guix-cvs-reference sgml-tag-name--cmacro calc-embedded-mode-hook desktop-buffer-name ident message-send-mail-function ...] :predicate #f(compiled-function (sym) #<bytecode 0xa839ad>) :require-match t :history counsel-M-x-history :action counsel-M-x-action :keymap (keymap (67108908 . counsel--info-lookup-symbol) (67108910 . counsel-find-symbol)) :initial-input nil :caller counsel-M-x)
  counsel-M-x()
  funcall-interactively(counsel-M-x)
  call-interactively(counsel-M-x nil nil)
  command-execute(counsel-M-x)

In ivy-completing-read, at the time it does (assq this-command ivy-completing-read-handlers-alist), the value of this-command is exit-minibuffer instead of bbdb-create. This occurs on GNU Guix with Emacs 27.1 and ivy 0.13.1.

basil-conto commented 4 years ago

Can you not enter an empty string via C-M-j (ivy-immediate-done)?

This occurs on GNU Guix with Emacs 27.1 and ivy 0.13.1.

That's funny, GNU ELPA says Ivy 0.13.1, but the Ivy sources only go as far as 0.13.0. :)

Apteryks commented 4 years ago

@basil-conto C-M-j indeed works around the problem, thank you! But it is not intuitive for a newcomer, and the fact that https://github.com/abo-abo/swiper/blob/master/ivy.el#L161 exists points to a problem that Ivy meant to handle but failed.

basil-conto commented 4 years ago

C-M-j indeed works around the problem, thank you!

You're welcome. Does that mean this issue can be closed?

But it is not intuitive for a newcomer

It is documented in the Ivy user manual under (info "(ivy) Key bindings for single selection action then exit minibuffer").

and the fact that https://github.com/abo-abo/swiper/blob/master/ivy.el#L161 exists points to a problem that Ivy meant to handle but failed.

It's more an artefact of Ivy's design, which unfortunately did not prioritise seamless interoperability with built-in completion.

Apteryks commented 4 years ago

OK, thanks for explaining. Since it's documented and a product of Ivy's design, I'm closing this issue. Thank you!