minad / corfu

:desert_island: corfu.el - COmpletion in Region FUnction
GNU General Public License v3.0
1.15k stars 43 forks source link

TAB completion with cape-file directories #351

Closed schrenker closed 1 year ago

schrenker commented 1 year ago

Hello,

I have this problem with TAB completion and completing directories with corfu+cape-file combo.

  1. Try completing file, starting with ./ string.
  2. Completion candidates appear, files with normal names, and directories with '/' suffix.
  3. Select directory with TAB.
  4. Try to complete another file or directory. In order to get further completion candidates inside just completed directory, I have to either know what's inside the directory or remove '/', and reinsert it. That gives new completion candidate list. Hitting tab doesn't cut it, because of TAB completion.

My question is, is there a way of either getting recursive completion candidates, so with subdirectiories, or prompting another corfu candidate list without deleting and reinserting the '/'. Could be even done with just pressing '/', to get candidate list instead of second slash.

This is a minor nuissance, but I thought maybe you would know how to resolve this.

My config for corfu and cape:

(use-package corfu
  :elpaca (corfu :files (:defaults "extensions/*"))
  :demand t
  :bind (:map corfu-map
              ("TAB" . corfu-next)
              ("<tab>" . corfu-next)
              ("[tab]" . corfu-next)
              ("S-TAB" . corfu-previous)
              ("<backtab>" . corfu-previous)
              ("[backtab]" . corfu-previous)
              ("C-<escape>" . corfu-quit)
              ("S-SPC" . corfu-insert-separator)
              ("C-S-n" . corfu-move-to-minibuffer))

  :config
  (unbind-key (kbd "M-n") 'corfu-map)
  (unbind-key (kbd "M-p") 'corfu-map)
  (defun corfu-move-to-minibuffer ()
    (interactive)
    (let ((completion-extra-properties corfu--extra)
          completion-cycle-threshold completion-cycling)
      (apply #'consult-completion-in-region completion-in-region--data)))
  ;; Auto-completion settings, must be set before calling `global-corfu-mode'.
  (setq corfu-auto t
        corfu-auto-prefix 3
        corfu-excluded-modes '(erc-mode
                               circe-mode
                               help-mode
                               gud-mode
                               vterm-mode)
        corfu-cycle t
        corfu-separator ?\s
        corfu-preselect 'prompt
        corfu-count 16
        corfu-max-width 120
        corfu-on-exact-match nil
        corfu-preview-current 'insert
        corfu-quit-at-boundary 'separator
        corfu-quit-no-match 'separator
        tab-always-indent 'complete)
  (add-to-list 'completion-category-overrides '(eglot (styles orderless)))
  (global-corfu-mode)
  (require 'corfu-history)
  (corfu-history-mode 1)
  (add-to-list 'savehist-additional-variables 'corfu-history)
  (require 'corfu-popupinfo)
  (setq corfu-popupinfo-delay '(1.0 . 1.0))
  (corfu-popupinfo-mode 1))

(use-package cape
  :after (eglot corfu)
  :init
  ;; Add `completion-at-point-functions', used by `completion-at-point'.
  (add-to-list 'completion-at-point-functions #'cape-dabbrev)
  (add-to-list 'completion-at-point-functions #'cape-file)
  (add-to-list 'completion-at-point-functions #'cape-elisp-block)
  :config
  (advice-add 'eglot-completion-at-point :around #'cape-wrap-buster))
minad commented 1 year ago

Hi!

Corfu with cape-file should behave as you expect in the default settings. As soon as you hit TAB the currently selected directory is inserted via corfu-complete. Then the subdirectories and subfiles are offered for completion.

The problem here is Tab n' Go (TNG) completion, where TAB is bound to corfu-next. In order to fix this you have to somehow invoke corfu-complete via some other key. I am not sure what the best approach would be, since I don't use TNG. One idea is to add a command bound to / which inserts a slash or calls corfu-complete where it makes sense. This is basically a design question. How should the TNG interaction model work when completing paths?

I hope this is helpful. I close the issue since it is a configuration question. Nevertheless feel free to continue the discussion. If we come up with something good we can either document it in the README or the wiki.

schrenker commented 1 year ago

This is something I will experiment with:

One idea is to add a command bound to / which inserts a slash or calls corfu-complete where it makes sense.

Thanks for quick reply!

minad commented 1 year ago

You're welcome. An easier alternative is to bind corfu-complete to M-TAB, in order to confirm the candidate with M-TAB. With TNG the corfu-complete binding is lost otherwise. I could document that right away in the README. Would that work for you? Maybe one could also look into other editors for how they handle file completion with TNG. Afaik TNG comes from some popular Vim completion UI.

schrenker commented 1 year ago

I think I'd rather experiment with your earlier suggestion. Even if it doesn't work, TNG is so baked into my style of working, I think I'd rather just delete the slash and go forward :D As I said, it is just a minor nuissance I can get over with. Thanks again for the replies, and thanks for great packages.

bcardoso commented 1 year ago

Probably a questionable workaround, but I'm achieving this behavior using the following advice for quite some time now:

(defun cape-x-cape-file-persist ()
  "If inserted symbol is a file path, call `cape-file' again."
  (interactive)
  (if (string-match "/$" (thing-at-point 'filename t))
      (cape-file t)))

(advice-add 'corfu-insert :after #'cape-x-cape-file-persist)