Icicles - Key Binding Discussion

iciclesimage
Icicles

Note: This page is essentially obsolete – see Icicles - Customizing Key Bindings instead. Customizing key bindings is now quite easy. The content here might still help you as an additional reference, but it is not up-to-date.

This page is not for posting problems you are having binding keys; use IciclesIssues for that.

Most of this page is a dialog between TobyCubitt and DrewAdams that led to the creation of page Icicles - Customizing Key Bindings. Although obsolete, this page contains some additional information and explanation.



What if you want to change some of the Icicles key bindings?

You can put something similar to the following in your ~/.emacs file to restore the [up] and [down] history traversal bindings (replace the bindings for the Icicles commands with the ones you want):

  ;; restore the [up] and [down] history traversal bindings, and bind M-n and M-p
  ;; to prefix completion cycling
  (dolist (map (append (list minibuffer-local-completion-map
			     minibuffer-local-must-match-map)
		       (when (> emacs-major-version 21)
		         (list minibuffer-local-filename-completion-map))))
    (icicle-unmap 'previous-line map)
    (icicle-unmap 'next-line map)
    (define-key map [up] 'previous-history-element)
    (define-key map [down] 'next-history-element)
    (define-key map [?\M-p] 'icicle-previous-prefix-candidate)
    (define-key map [?\M-n] 'icicle-next-prefix-candidate))

TobyCubitt

Good example, Toby; thanks for adding it. That’s generally the right way to do it (for history keys or any others). Let me add a little more explanation:

  • If you want to use all of [up], [down], ‘C-p’, and ‘C-n’ for history traversal, then instead of unmapping `(previous|next)-line’ and binding [up] and [down], you can just remap to what you want:
        (icicle-remap 'previous-line 'previous-history-element map)
        (icicle-remap 'next-line 'next-history-element map)
  • If you do use ‘define-key’ to bind [up] and [down], then you don’t also need to unmap `(previous|next)-line’. That way, ‘C-p’ and ‘C-n’ will still be bound to `icicle-(previous|next)-prefix-candidate’ (which may or may not be what you want). Toby’s example gives ‘C-p’ and ‘C-n’ the same bindings in the MiniBuffer that they have globally: `(previous|next)-line’.
  • IOW, unless you want to use ‘C-p’ and ‘C-n’ for `(previous|next)-line’ in the minibuffer, you don’t need to both unmap and ‘define-key’ – you can either remap or ‘define-key’. What won’t work, however, is to simply unmap. If you do that, then you end up with [up], [down], ‘C-p’, and ‘C-n’ all doing in the minibuffer what they do globally: move to the previous/next line.
  • BTW, it would be better to use (boundp 'minibuffer-local-filename-completion-map) than (> emacs-major-version 21). Some early snapshots of Emacs 22 don’t use that variable yet. It’s generally better anyway to test with ‘unboundp’ and ‘fboundp’, because the test is more focused.

DrewAdams

Great! I was hoping you’d correct/comment on my example. Binding ‘C-p’ and ‘C-n’ to (previous|next)-line in the minibuffer doesn’t make much sense (I simplified the code I actually use in my .emacs, and didn’t notice it did this).

So, assuming I’ve not replaced one mistake with another, if you want to use [up] and [down] for history traversal in addition to `M-n|p’, and only leave `C-n|p’ for prefix completion cycling, the corrected code should read:

  ;; restore the [up] and [down] history traversal bindings, and bind M-n and M-p
  ;; to prefix completion cycling
  (dolist (map (append (list minibuffer-local-completion-map
			   minibuffer-local-must-match-map)
		       (when (boundp 'minibuffer-local-filename-completion-map)
		         (list minibuffer-local-filename-completion-map))))
    (define-key map [up] 'previous-history-element)
    (define-key map [down] 'next-history-element))

If you want to use ‘M-n’ and ‘M-p’ for prefix completion cycling now that [up] and [down] do history traversal, add two more lines to the loop (you could do this with icicle-remap instead, but this way is marginally more efficient):

    (define-key map [?\M-p] 'icicle-previous-prefix-candidate)
    (define-key map [?\M-n] 'icicle-next-prefix-candidate))

TobyCubitt

Drew, please feel free to correct/modify my examples, incorporate them properly into the page, and delete any of my comments that are no longer relevant. (Since this is more a documentation page than a discussion page, my feeling is that keeping it coherent should be emphasised over keeping the discussion for posterity – it’ll always be there in the page’s revision history. But it’s your call.)

As for using the (> emacs-major-version 21) test, I completely agree that testing with (f)boundp is better. But for consistency, I used the same test as is used in Icicles itself!

Perhaps my copy of Icicles is out of date…?

TobyCubitt

BTW, I persisted with the default keybindings for a while, assuming that I’d get accustomed to them eventually. But most programs (Emacs without icicles, bash, csh, most other shells, web browsers…) use [up] and [down] for history traversal, so I never got used to the keys doing something different in Emacs.

Since this is such a common convention, perhaps the default Icicles bindings should stick to it?

TobyCubitt

Toby –

Your corrected example looks OK to me.

I’ll probably clean up the page later, consolidating examples – or someone else can (feel free).

I believe that I use `f?boundp’ where possible in the code. I try to resort to testing the major version only when I cannot (or do not know how to) do otherwise. So, yes, your copy of Icicles might just be old – if not, please let me know where the test is, so I can fix it. BTW, this is not just a hypothetical problem or a concern with cosmetics – I noticed your version test because I tried your code and I use an old snapshot of Emacs 22 for which the version test fails.

I don’t want to change the default values for [up] and [down], but you’re in good company making that suggestion ;-). It’s good to put an example here (and perhaps in the library commentary) of how to change the bindings. There are a few reasons not to change the default behavior:

  • I want people to discover candidate cycling, and they are less likely to do so with other bindings.
  • I want people to try the Icicles history enhancements (see Icicles - History Enhancements), and they are less likely to do that if they just stick to their habit of using [up] and [down] for history traversal.
  • [up] and [down] are more convenient than ‘M-p’ and ‘M-n’, and I want to privilege candidate cycling over history traversal when it comes to convenience keys.
  • ‘C-p’ and ‘C-n’ are also more convenient, especially for some people, and I prefer to keep the same bindings for these as for [up] and [down].

People who are new to Icicles and perhaps even to Emacs are more likely to use the default bindings and end up discovering more of what Icicles has to offer this way. Those who feel strongly about bindings will still be able to change bindings as they like (thanks, in part, to your example!). They will likely do what you did: persist with the default bindings for a while, learning what Icicles has to offer. They will either end up liking the bindings or change them, but after getting to know Icicles a bit.

I use MS Windows, with ‘C-x’, ‘C-c’, and ‘C-v’ for cut, copy, and paste, but I don’t use CUA mode in Emacs (because the standard Emacs cut/copy/paste bindings are superior, and they fit better with the rest of Emacs). Yes, it’s sometimes a pain going back and forth – juggling two habits can lead to the occasional “gotcha!”. But it is doable. I look at [up] and [down] the same way, although I admit that I don’t use them much for history traversal in the shell etc. anyway.

As long as people can get the bindings they want, I think I’ll stick with the bindings that I myself prefer. I’ve taken that approach generally, although there are a few exceptions. – DrewAdams

Fair enough. It’s your package after all! I usually don’t care that much about key bindings, since it’s easy to change them. But minibuffer key bindings seem to be a trickier, the Icicles ones in particular because of the remapping. (It’s the first time I’ve had to work my way through elisp code to figure out how to change keybindings!).

Now that a cleaned up example is on the wiki and linked to the keybindings page, it’s no big deal.

I’ve downloaded the latest version of icicles, and the emacs-major-version tests are no longer there, so I guess my version was just out of date. (Is there an easy way to grab all the support libraries icicles.el now needs? I resorted to reading the comments and downloading them individually. A tar or zip archive would be great…)

TobyCubitt

I agree that it’s unfortunate that minibuffer bindings are a bit trickier. Your initiative to add an example helped a lot. If you or others think of other key-binding examples that might be helpful to add, please add them.

I don’t think that EmacsWiki allows for multiple-file zip archives and such. Also, it would be more of a pain to deal with in the case of a single component file that is updated.

I didn’t split the file for maintenance purposes, and I didn’t even split it along lines of logical dependency (you need the whole ball of wax). I split it mainly because it was too big for an EmacsWiki upload – I was getting bizarre errors. It’s probably just as well that it is split, though I do recognize that it’s a pain to download multiple files. If I updated it less often, there would be less of a hassle.

The driver library, icicles.el lists all of the required Icicles files, so if that list ever changes, that’s the place to look. – DrewAdams


How to resolve key-mapping conflicts between Icicles and other Packages

I had a key-sequence conflict between Icicles and OrgMode where the Shift-tab key (used by the Org Major mode) is remapped by the Icicles minor mode.

Org-mode uses shift-tab for managing the global visibility of the outline whereas Icicles remaps it for key completions. Specifically, Org-Mode expects the org-shifttab function to be bound to this key, whereas Icicles binds it to icicle-generic-S-tab.

The workarounds are to:

  1. Redefining the key-mapping for org-shifttab (not an option for me due to extensive muscle memory for this key in org-mode)
  2. Redefining the key-mapping for Icicles (yet another key to remember)
  3. re-defining ‘icicle-generic-S-tab’ to call ‘org-shifttab’ when in Org mode
  4. binding S-TAB to a command that calls ‘org-shifttab’ when in Org mode and ‘icicle-generic-S-tab’ otherwise.

The last option was the most workable, where shift-tab has the correct Icicles binding everywhere, except in Org major mode, where the Org-Mode functions take over. The following code snippet (in .emacs) implements this solution:

  (require 'icicles)
  (require 'lacarte)
 
  ;; Add a work around for the [S-tab] conflict between Org-Mode and
  ;; Icicles
  (add-hook 'icicle-mode-hook 'bind-my-icicle-keys)
  (defun bind-my-icicle-keys ()
   "Add the custom binding for [S-tab] when Icicles is used"
    (define-key icicle-mode-map [S-tab]
           'bind-my-s-tab-for-org-mode))
 
   (defun bind-my-s-tab-for-org-mode (&optional arg)
   "Binds [S-tab] to cycle the outline in Org-Mode
    and use the icicle mode functions otherwise."
      (interactive "P")
      (if (string= mode-name "Org")
          (org-shifttab arg)
         ;; (icicle-generic-S-tab) - This function is now obsolete
          (icicle-complete-keys)))
   ;; End of the work around
 
  (icicle-mode 1)

You can use this snippet for remapping any minor-mode key to call other functions in a major mode buffer.

AnupamSengupta

If it doesn’t work as it was in my case, then change bind-my-icicle-keys function with the following :

  (defun bind-my-icicle-keys ()
   "Add the custom binding for [S-tab] when Icicles is used"
    (define-key icicle-mode-map [(shift iso-lefttab)]
           'bind-my-s-tab-for-org-mode)
    (define-key icicle-mode-map [S-tab]
           'bind-my-s-tab-for-org-mode))

SewerynKokot

I have added some new options for customizing Icicles key bindings, which should make such code unnecessary. See, for example, ‘icicle-generic-S-tab-keys’, ‘icicle-prefix-complete-keys’, ‘icicle-apropos-complete-no-display-keys’, and ‘icicle-prefix-complete-no-display-keys’. – DrewAdams


key binding to icicle-occur command conflict to org-mode org-babel. So I would like to add these hooks to my configue file

    (add-hook 'org-mode-hook
    	  (lambda ()
    	    (define-key icicle-mode-map (kbd "C-c '") 'org-edit-special)))
    
    (add-hook 'lisp-mode-hook
    	  (lambda ()
    	    (define-key icicle-mode-map (kbd "C-c '") 'org-edit-src-exit))) 

DavidYoung

No. No need to do that. That’s what option `icicle-top-level-key-bindings’ is for. By default it binds `C-'’ to ‘icicle-occur’ – just remove that entry (it’s the fifth one in the list). – DrewAdams

But what is the best way to remove an internal value in the option `icicle-top-level-key-bindings’? It is a quite big list in its value. If I choose to remove that specific line through customize that variable, it would make my init file un-readable. So I need to write some function to make it in the runtime. Here is my function:

    (eval-after-load "icicles-opt.el"
     (add-hook 'icicle-mode-hook
              (lambda ()
                 (setq my-icicle-top-level-key-bindings
                         (mapcar (lambda (lst)
                                   (unless (string= "icicle-occur" (nth 1 lst)) lst))
                                  icicle-top-level-key-bindings))
                        (setq icicle-top-level-key-bindings my-icicle-top-level-key-bindings) )))
    
    (icy-mode)

DavidYoung

You can do that, but I don’t recommend it. What I recommend is to use a separate file for all Customize customizations. That’s what option ‘custom-file’ is for. That’s a good idea anyway, because it separates a file you edit manually (your init file) from the file where Customize makes automatic changes (the value of ‘custom-file’).

The Customize interface for changing, adding, and deleting individual members of a complex structure (such as a list like ‘icicle-top-level-key-bindings’) is straightforward and less error prone. And if you use ‘custom-file’ then you don’t care how large or how ugly the complex value is in the file – you never edit the Lisp sexp by hand.

In any case, if you do prefer to use Lisp then it’s better to use ‘custom-set-variable’ than ‘setq’. – DrewAdams



Icicles

DrewsElispLibraries referenced here: Lisp:icicles.el

CategoryKeys CategoryMenus CategoryCommands