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

Pressing RET with `tab-always-indent` set to `'complete` triggers completion-at-point when `ivy-mode` is enabled #2815

Open apc opened 3 years ago

apc commented 3 years ago

(Caveat: I fear I may not have adequately identified the source of the problem. But I could use any help I can get at this point.)

I do not think this is the intended behavior, but correct me if I'm wrong: when in org-mode, specifying sh as the language for a code block followed by RET triggers a list of completions for the empty string.

image

The following steps should reproduce the behavior in question:

Move to a scratch buffer, enter org-mode, and then:

A few observations:

Indentation setup for shell type zsh
Making completion list... [2 times]

(I don't see the Making completion list message if I do all of the above without ever calling ivy-mode.)

What seems to happen after specifying sh as the language for a code block and hitting RET is precisely what happens when you call completion-at-point or you hit TAB at the beginning of an empty line in sh-mode. So I'm assuming that pressing RET when in electric-indent-mode is triggering completion-at-point. But simply hitting RET in sh-mode does not do trigger this behavior. So it seems to have something to do with the interaction of org-mode, ivy-mode, electric-indent, and code blocks.

I'm running Emacs 27.1. I believe I'm using swiper version 20210202.2312.

basil-conto commented 3 years ago

Confirmed in Emacs 28 as well, but I have no idea yet why this only happens with ivy-mode.

If I toggle-debug-on-quit before invoking the completions, and then C-g once the completions come up, I get the following backtrace, FWIW:

Debugger entered--Lisp error: (quit)
  read-from-minibuffer("(): " "" (keymap keymap (36 . ivy-magic-read-file-env) (3 keymap (19 . ivy-rotate-sort) (1 . ivy-toggle-ignore) (15 . ivy-occur)) (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) (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) (25 . ivy-insert-current-full) (105 . ivy-insert-current) (106 . ivy-yank-word) (114 . ivy-toggle-regexp-quote) (97 . ivy-toggle-marks) (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)
  ivy-read("(): " ("./" "hexl" "../" "rcs2log" "emacs.pdmp" "spruch" "wesnoth-1.14_editor" "fortune" "hauptgericht" "cowthink" "regeln" "kuchen" "cowsay" "wesnoth-1.14-smallgui" "../" "mgba-qt" "wesnothd-1.14" "pyrogenesis" "mgba" "plaetzchen" "dessert" "sl" "xcowdream" "beilagen" "suppe" "xcowsay" "wesnoth" "wesnoth-1.14" "kalt" "xcowthink" "sauce" "xcowfortune" "salat" "supertuxkart" "brot" "0ad" "vorspeise" "../" "../" "hexgplc" "partx" "enchant-2" "dpkg-realpath" "pango-list" "ocamllex.byte" "cd-iccdump" "ocamlobjinfo.opt" "otangle" "fwupdagent" "desktop-file-install" ...) :predicate nil :initial-input "" :action ivy-completion-in-region-action :unwind #f(compiled-function () #<bytecode 0x19d65cda8be5d4fc>) :caller ivy-completion-in-region)
  ivy-completion-in-region(#<marker at 1 in *Org Src *scratch*[ sh ]*> 1 sh--cmd-completion-table nil)
  completion-in-region(#<marker at 1 in *Org Src *scratch*[ sh ]*> 1 sh--cmd-completion-table nil)
  completion-at-point()
  indent-for-tab-command(nil)
  funcall-interactively(indent-for-tab-command nil)
  call-interactively(indent-for-tab-command)
  org-babel-do-key-sequence-in-edit-buffer("\11")
  org-indent-line()
  indent-according-to-mode()
  electric-indent-post-self-insert-function()
  self-insert-command(1)
  newline(nil 1)
  org--newline(nil nil 1)
  org-return(nil nil 1)
  funcall-interactively(org-return nil nil 1)
  call-interactively(org-return nil nil)
  command-execute(org-return)
basil-conto commented 3 years ago

And here's a trace of what's happening without ivy-mode:

1 -> (completion-at-point)
| 2 -> (completion-in-region #<marker at 1 in *Org Src *scratch*[ sh ]*> 1 sh--cmd-completion-table nil)
| | 3 -> (completion--in-region #<marker at 1 in *Org Src *scratch*[ sh ]*> 1 sh--cmd-completion-table nil)
| | | 4 -> (completion-in-region-mode 1)
| | | 4 <- completion-in-region-mode: t
| | | 4 -> (completion--in-region-1 #<marker at 1 in *Org Src *scratch*[ sh ]*> 1)
| | | | 5 -> (completion--do-completion #<marker at 1 in *Org Src *scratch*[ sh ]*> 1)
| | | | | 6 -> (completion-try-completion "" sh--cmd-completion-table nil 0 (metadata))
| | | | | 6 <- completion-try-completion: ("" . 0)
| | | | | 6 -> (minibuffer-completion-help #<marker at 1 in *Org Src *scratch*[ sh ]*> 1)
| | | | | 6 <- minibuffer-completion-help: nil
| | | | 5 <- completion--do-completion: 2
| | | 4 <- completion--in-region-1: t
| | 3 <- completion--in-region: t
| 2 <- completion-in-region: t
1 <- completion-at-point: t
======================================================================
1 -> (completion-in-region--postch)
| 2 -> (completion-in-region-mode -1)
| | 3 -> (minibuffer-hide-completions)
| | 3 <- minibuffer-hide-completions: nil
| 2 <- completion-in-region-mode: nil
1 <- completion-in-region--postch: nil

Looks like completion-try-completion returns the same (empty) string that's trying to be completed, so it gathers that nothing's changed, and exits completion.