unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
From: Jonas Bernoulli <jonas@bernoul.li>
To: 17000@debbugs.gnu.org
Subject: bug#17000: setup ido keymaps only once
Date: Wed, 12 Mar 2014 20:35:16 +0100	[thread overview]
Message-ID: <877g7zfbwr.fsf@bernoul.li> (raw)

Currently the ido keymaps are hard to modify because they are recreated
every time `ido-completing-read' is used.  This forces users to add a
function to `ido-minibuffer-setup' and do their `define-key's there.

I believe it is safe for the "base" ido keymaps to set the value when
the variable is defined, instead of delaying this until ido is actually
used, and then redoing that work whenever `ido-completing-read' is
called.

These are the keymaps which are currently set in `ido-init-completion-maps':
  ido-common-completion-map
  ido-file-completion-map
  ido-file-dir-completion-map
  ido-buffer-completion-map

`ido-completion-map' is different, it's a kind of "current-local-map".
Its value is set in `ido-setup-completion-map' by creating a new sparse
keymap, setting its parent to one of the above keymaps (depending on
what is currently being completed) and then possibly making some
adjustments depending on `ido-context-switch-command' and `viper-mode'.

`ido-setup-completion-map' is called every time `ido-read-internal' is
called, i.e. every time the user actually uses ido completion.  Therefor
`ido-completion-map' is set every time ido completion is used and so it
is safe to modify it using `ido-minibuffer-setup-hook' for just this one
call.

`ido-init-completion-maps' is *not* called every time ido completion is
used.  It is called only in `ido-common-initialization' which is called
only in `ido-mode' and `ido-completion-read', but not in
`ido-read-internal'.  The reason why `ido-completion-read' has to do the
common initialization is simple: it may be used by users and packages to
complete certain things without also using ido completion for everything
`ido-mode' itself supports.

Besides the initialization of the keymaps the "common initialization"
also includes adding functions to hooks.  I am arguing that the latter
should stay but that the keymaps shouldn't be recreated here and that it
is backward compatible to make that change.

While it is possible that some third-party code modifies one of the
`ido-*-completion-map's by using `ido-minibuffer-setup', that would be
a bug.  Instead the "final keymap", `ido-completion-map', should be
modified.  Even without the proposed change modifying one of the
`ido-*-completion-map's when using `ido-completing-read' with the
intention of having that only affect the current invocation would
actually affect later uses of ido completion because only
`ido-completing-read' re-runs `ido-init-completion-maps',
`ido-read-internal' does *not* do that.  Therefore changes to these
keymaps would remain in effect until the next time `ido-completing-read'
is used, uses of `ido-read-internal' that happen in between would use
the modified map.

  Best regards,
  Jonas

---

diff --git a/lisp/ido.el b/lisp/ido.el
index b16ab1f..b4a3b28 100644
--- a/lisp/ido.el
+++ b/lisp/ido.el
@@ -978,25 +978,96 @@ The fallback command is passed as an argument to the functions."
   :type 'hook
   :group 'ido)
 
-;;; Internal Variables
-
-;; Persistent variables
-
-(defvar ido-completion-map nil
-  "Currently active keymap for Ido commands.")
+;; Keymaps
 
-(defvar ido-common-completion-map nil
+(defvar ido-common-completion-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map "\C-a" 'ido-toggle-ignore)
+    (define-key map "\C-c" 'ido-toggle-case)
+    (define-key map "\C-e" 'ido-edit-input)
+    (define-key map "\t" 'ido-complete)
+    (define-key map " " 'ido-complete-space)
+    (define-key map "\C-j" 'ido-select-text)
+    (define-key map "\C-m" 'ido-exit-minibuffer)
+    (define-key map "\C-p" 'ido-toggle-prefix)
+    (define-key map "\C-r" 'ido-prev-match)
+    (define-key map "\C-s" 'ido-next-match)
+    (define-key map [?\C-.] 'ido-next-match)
+    (define-key map [?\C-,] 'ido-prev-match)
+    (define-key map "\C-t" 'ido-toggle-regexp)
+    (define-key map "\C-z" 'ido-undo-merge-work-directory)
+    (define-key map [(control ?\s)] 'ido-restrict-to-matches)
+    (define-key map [(meta ?\s)] 'ido-take-first-match)
+    (define-key map [(control ?@)] 'ido-restrict-to-matches)
+    (define-key map [right] 'ido-next-match)
+    (define-key map [left] 'ido-prev-match)
+    (define-key map "?" 'ido-completion-help)
+    ;; Magic commands.
+    (define-key map "\C-b" 'ido-magic-backward-char)
+    (define-key map "\C-f" 'ido-magic-forward-char)
+    (define-key map "\C-d" 'ido-magic-delete-char)
+    (set-keymap-parent map minibuffer-local-map)
+    (setq ido-common-completion-map map))
   "Keymap for all Ido commands.")
 
-(defvar ido-file-completion-map nil
+(defvar ido-file-completion-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map "\C-k" 'ido-delete-file-at-head)
+    (define-key map "\C-o" 'ido-copy-current-word)
+    (define-key map "\C-w" 'ido-copy-current-file-name)
+    (define-key map [(meta ?l)] 'ido-toggle-literal)
+    (set-keymap-parent map ido-file-dir-completion-map)
+    (setq ido-file-completion-map map))
   "Keymap for Ido file commands.")
 
-(defvar ido-file-dir-completion-map nil
+(defvar ido-file-dir-completion-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map "\C-x\C-b" 'ido-enter-switch-buffer)
+    (define-key map "\C-x\C-f" 'ido-fallback-command)
+    (define-key map "\C-x\C-d" 'ido-enter-dired)
+    (define-key map [down] 'ido-next-match-dir)
+    (define-key map [up]   'ido-prev-match-dir)
+    (define-key map [(meta up)] 'ido-prev-work-directory)
+    (define-key map [(meta down)] 'ido-next-work-directory)
+    (define-key map [backspace] 'ido-delete-backward-updir)
+    (define-key map "\d"        'ido-delete-backward-updir)
+    (define-key map [remap delete-backward-char] 'ido-delete-backward-updir) ; BS
+    (define-key map [remap backward-kill-word] 'ido-delete-backward-word-updir)  ; M-DEL
+
+    (define-key map [(control backspace)] 'ido-up-directory)
+    (define-key map "\C-l" 'ido-reread-directory)
+    (define-key map [(meta ?d)] 'ido-wide-find-dir-or-delete-dir)
+    (define-key map [(meta ?b)] 'ido-push-dir)
+    (define-key map [(meta ?v)] 'ido-push-dir-first)
+    (define-key map [(meta ?f)] 'ido-wide-find-file-or-pop-dir)
+    (define-key map [(meta ?k)] 'ido-forget-work-directory)
+    (define-key map [(meta ?m)] 'ido-make-directory)
+    (define-key map [(meta ?n)] 'ido-next-work-directory)
+    (define-key map [(meta ?o)] 'ido-prev-work-file)
+    (define-key map [(meta control ?o)] 'ido-next-work-file)
+    (define-key map [(meta ?p)] 'ido-prev-work-directory)
+    (define-key map [(meta ?s)] 'ido-merge-work-directories)
+    (set-keymap-parent map ido-common-completion-map)
+    (setq ido-file-dir-completion-map map))
   "Keymap for Ido file and directory commands.")
 
-(defvar ido-buffer-completion-map nil
+(defvar ido-buffer-completion-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map "\C-x\C-f" 'ido-enter-find-file)
+    (define-key map "\C-x\C-b" 'ido-fallback-command)
+    (define-key map "\C-k" 'ido-kill-buffer-at-head)
+    (define-key map "\C-o" 'ido-toggle-virtual-buffers)
+    (set-keymap-parent map ido-common-completion-map)
+    (setq ido-buffer-completion-map map))
   "Keymap for Ido buffer commands.")
 
+;;; Internal Variables
+
+;; Persistent variables
+
+(defvar ido-completion-map nil
+  "Currently active keymap for Ido commands.")
+
 (defvar  ido-file-history nil
   "History of files selected using `ido-find-file'.")
 
@@ -1503,7 +1574,6 @@ Removes badly formatted data and ignored directories."
   (ido-save-history))
 
 (defun ido-common-initialization ()
-  (ido-init-completion-maps)
   (add-hook 'minibuffer-setup-hook 'ido-minibuffer-setup)
   (add-hook 'choose-completion-string-functions 'ido-choose-completion-string))
 
@@ -1597,90 +1667,22 @@ This function also adds a hook to the minibuffer."
 
 
 ;;; IDO KEYMAP
-(defun ido-init-completion-maps ()
-  "Set up the completion keymaps used by Ido."
-
-  ;; Common map
-  (let ((map (make-sparse-keymap)))
-    (define-key map "\C-a" 'ido-toggle-ignore)
-    (define-key map "\C-c" 'ido-toggle-case)
-    (define-key map "\C-e" 'ido-edit-input)
-    (define-key map "\t" 'ido-complete)
-    (define-key map " " 'ido-complete-space)
-    (define-key map "\C-j" 'ido-select-text)
-    (define-key map "\C-m" 'ido-exit-minibuffer)
-    (define-key map "\C-p" 'ido-toggle-prefix)
-    (define-key map "\C-r" 'ido-prev-match)
-    (define-key map "\C-s" 'ido-next-match)
-    (define-key map [?\C-.] 'ido-next-match)
-    (define-key map [?\C-,] 'ido-prev-match)
-    (define-key map "\C-t" 'ido-toggle-regexp)
-    (define-key map "\C-z" 'ido-undo-merge-work-directory)
-    (define-key map [(control ?\s)] 'ido-restrict-to-matches)
-    (define-key map [(meta ?\s)] 'ido-take-first-match)
-    (define-key map [(control ?@)] 'ido-restrict-to-matches)
-    (define-key map [right] 'ido-next-match)
-    (define-key map [left] 'ido-prev-match)
-    (define-key map "?" 'ido-completion-help)
-    ;; Magic commands.
-    (define-key map "\C-b" 'ido-magic-backward-char)
-    (define-key map "\C-f" 'ido-magic-forward-char)
-    (define-key map "\C-d" 'ido-magic-delete-char)
-    (set-keymap-parent map minibuffer-local-map)
-    (setq ido-common-completion-map map))
-
-  ;; File and directory map
-  (let ((map (make-sparse-keymap)))
-    (define-key map "\C-x\C-b" 'ido-enter-switch-buffer)
-    (define-key map "\C-x\C-f" 'ido-fallback-command)
-    (define-key map "\C-x\C-d" 'ido-enter-dired)
-    (define-key map [down] 'ido-next-match-dir)
-    (define-key map [up]   'ido-prev-match-dir)
-    (define-key map [(meta up)] 'ido-prev-work-directory)
-    (define-key map [(meta down)] 'ido-next-work-directory)
-    (define-key map [backspace] 'ido-delete-backward-updir)
-    (define-key map "\d"        'ido-delete-backward-updir)
-    (define-key map [remap delete-backward-char] 'ido-delete-backward-updir) ; BS
-    (define-key map [remap backward-kill-word] 'ido-delete-backward-word-updir)  ; M-DEL
-
-    (define-key map [(control backspace)] 'ido-up-directory)
-    (define-key map "\C-l" 'ido-reread-directory)
-    (define-key map [(meta ?d)] 'ido-wide-find-dir-or-delete-dir)
-    (define-key map [(meta ?b)] 'ido-push-dir)
-    (define-key map [(meta ?v)] 'ido-push-dir-first)
-    (define-key map [(meta ?f)] 'ido-wide-find-file-or-pop-dir)
-    (define-key map [(meta ?k)] 'ido-forget-work-directory)
-    (define-key map [(meta ?m)] 'ido-make-directory)
-    (define-key map [(meta ?n)] 'ido-next-work-directory)
-    (define-key map [(meta ?o)] 'ido-prev-work-file)
-    (define-key map [(meta control ?o)] 'ido-next-work-file)
-    (define-key map [(meta ?p)] 'ido-prev-work-directory)
-    (define-key map [(meta ?s)] 'ido-merge-work-directories)
-    (set-keymap-parent map ido-common-completion-map)
-    (setq ido-file-dir-completion-map map))
 
-  ;; File only map
-  (let ((map (make-sparse-keymap)))
-    (define-key map "\C-k" 'ido-delete-file-at-head)
-    (define-key map "\C-o" 'ido-copy-current-word)
-    (define-key map "\C-w" 'ido-copy-current-file-name)
-    (define-key map [(meta ?l)] 'ido-toggle-literal)
-    (set-keymap-parent map ido-file-dir-completion-map)
-    (setq ido-file-completion-map map))
+(defun ido-setup-completion-map ()
+  "Set up the keymap for Ido.
 
-  ;; Buffer map
-  (let ((map (make-sparse-keymap)))
-    (define-key map "\C-x\C-f" 'ido-enter-find-file)
-    (define-key map "\C-x\C-b" 'ido-fallback-command)
-    (define-key map "\C-k" 'ido-kill-buffer-at-head)
-    (define-key map "\C-o" 'ido-toggle-virtual-buffers)
-    (set-keymap-parent map ido-common-completion-map)
-    (setq ido-buffer-completion-map map)))
+Create a keymap and depending on what is being completed set its
+parent to one of:
 
+  `ido-common-completion-map'
+  `ido-file-dir-completion-map'
+  `ido-file-completion-map'
+  `ido-buffer-completion-map'
 
-(defun ido-setup-completion-map ()
-  "Set up the keymap for Ido."
+If option `ido-context-switch-command' is non-nil or `viper-mode'
+is enabled some keybindings are changed in the keymap.
 
+Finally `ido-completion-map' is bound to the keymap."
   ;; generated every time so that it can inherit new functions.
   (let ((map (make-sparse-keymap))
 	(viper-p (if (boundp 'viper-mode) viper-mode)))





             reply	other threads:[~2014-03-12 19:35 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-03-12 19:35 Jonas Bernoulli [this message]
2014-03-12 23:36 ` bug#17000: setup ido keymaps only once Stefan Monnier
2014-03-13 15:35   ` Jonas Bernoulli
2014-12-08 23:39     ` Lars Magne Ingebrigtsen
2014-12-10  9:15       ` Jonas Bernoulli
2014-12-22 18:53     ` Jonas Bernoulli
2014-12-23  2:07   ` Leo Liu
2014-12-24 17:11     ` Dmitry Gutov
2014-12-25 22:44       ` Kim Storm
2015-01-18 15:17 ` Oleh Krehel
2015-01-19 11:58   ` Dmitry Gutov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=877g7zfbwr.fsf@bernoul.li \
    --to=jonas@bernoul.li \
    --cc=17000@debbugs.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).