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

Making fancy-dabbrev expansion triggers more configurable #14

Open
DivineDominion opened this issue Aug 14, 2021 · 2 comments
Open

Making fancy-dabbrev expansion triggers more configurable #14

DivineDominion opened this issue Aug 14, 2021 · 2 comments

Comments

@DivineDominion
Copy link

I like the lightweight fancy-dabbrev popoup and want to experiment with using it more. But as with #13 and #11, the global binding of tab is a bit brittle, so I was thinking about what one could do there.

Also, I intuitively want to hit arrow keys and return to select a completion from the popup window instead of tab, so tweaking key bindings was on my mind anyway.

Here's a couple of ideas I'd like to share to see if they're any good :)

  • Introduce an alist (I think?) like fancy-dabbrev-indent-command-per-mode that pairs mode names with their tab key overrides to make fancy-dabbrev-expand-or-indent flexible enough to call not just 1 globally set fancy-dabbrev-indent-command, but whichever command is needed by a mode.
    • Org uses org-cycle that wraps indent-for-tab-command in some special case handling, for example. Other modes can do the same. Users would expect the default tab behavior to be retained, but fancy-dabbrev-expand-or-indent at the moment would enforce indent-for-tab-command, which might not always be accurate. Should help with It doesn't work in orgmode #13?
    • fancy-dabbrev-expand-or-indent could be extended: match the current (major) mode to an entry from the fancy-dabbrev-indent-command-per-mode, falling back to fancy-dabbrev-indent-command if none is found.
    • Alternative considered: users can use add-hook to change the fancy-dabbrev-indent-command variable on a per-mode basis.
  • Use a transient key map when the popup is visible for fancy-dabbrev bindings.
    • Users can configure their key bindings for fancy-dabbrev actions in the transient keymap. E.g. I could add arrow key support in my init.el to select prev/next suggestion, and RET to expand, too, without a global key binding of RET similar to how TAB and fancy-dabbrev-expand-or-indent are bound.
    • Binding the tab key in a transient map should "win" over buffer- or mode-local key bindings. So fancy-dabbrev could just bind tab to fancy-dabbrev-expand. If no dabbrev is active, the transient map is not active, and tab does what it would do usually. (I need to test this more to check if that's true.)
    • This package could ditch the approach of a global key binding for fancy-dabbrev-expand-or-indent with its fallback to the default tab function completely, because the transient key map is not active most of the time.
    • Downsides: This assumes that dabbrev "just works" when users type, and that the fancy-dabbrev popup is triggered reliably, i.e. modes don't mess with that or prevent it from working. Global tab key binding triggering a fancy-dabbrev function might work more reliably if this isn't the case?

What do you think?

@jrosdahl
Copy link
Owner

Hi,

Thanks for the list of ideas! I don't think I'll have time to think them through in detail, but some quick comments:

I intuitively want to hit arrow keys and return to select a completion from the popup window instead of tab

I major reason for writing fancy-dabbrev in the first place was that I didn't find a completion package that supported "one key does it all" behavior just like plain dabbrev-expand works. Here's a more detailed discussion. I'm spontaneously not interested in making fancy-dabbrev work like e.g. company-mode where you select candidates with arrow keys since that would just duplicate functionality and make things more complex. Perhaps there is a way for you to customize company-mode instead, using dabbrev as a backend?

Alternative considered: users can use add-hook to change the fancy-dabbrev-indent-command variable on a per-mode basis.

That's what I would suggest to keep things simple.

@akirak
Copy link

akirak commented Mar 1, 2022

Hello, after experimenting with this package for a while, I reached the following solution:

(defcustom fancy-dabbrev-expansion-key "TAB"
  ""
  :type 'string)

(defun fancy-dabbrev-remap (map)
  (let* ((mode-cmd (keymap-lookup map fancy-dabbrev-expansion-key))
         (remapped-cmd (or mode-cmd
                           (with-temp-buffer
                             (keymap-lookup global-map fancy-dabbrev-expansion-key))))
         (fallback-cmd (or mode-cmd
                           (command-remapping remapped-cmd nil map)))
         (wrapper-cmd (intern (concat "fancy-dabbrev-expand-or-" (symbol-name fallback-cmd)))))
    (fset wrapper-cmd
          `(lambda ()
             (interactive)
             (let ((fancy-dabbrev-indent-command ',fallback-cmd))
               (fancy-dabbrev-expand-or-indent))))
    (define-key map (vector 'remap remapped-cmd) wrapper-cmd)))

With this function, you can remap the key on each map (see below), which would be suitable for use in one's init.el:

(with-eval-after-load 'org-keys
  (fancy-dabbrev-remap org-mode-map))

This seems to work for both major and minor mode maps.

I personally prefer the following wrapper definition. I am using C-e as the expansion key:

;;; Expand the dabbrev only after a self-insertion command, only once
`(lambda ()
    (interactive)
    (if (memq last-command fancy-dabbrev-self-insert-commands)
         (let ((fancy-dabbrev-indent-command ',fallback-cmd))
            (fancy-dabbrev-expand-or-indent))
       (call-interactively ',fallback-cmd)))

What do you think?

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