From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Jonas Bernoulli Newsgroups: gmane.emacs.bugs Subject: bug#17000: setup ido keymaps only once Date: Wed, 12 Mar 2014 20:35:16 +0100 Message-ID: <877g7zfbwr.fsf@bernoul.li> NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: text/plain X-Trace: ger.gmane.org 1394653882 15446 80.91.229.3 (12 Mar 2014 19:51:22 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Wed, 12 Mar 2014 19:51:22 +0000 (UTC) To: 17000@debbugs.gnu.org Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Wed Mar 12 20:51:30 2014 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by plane.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1WNpBZ-0003cT-G0 for geb-bug-gnu-emacs@m.gmane.org; Wed, 12 Mar 2014 20:51:29 +0100 Original-Received: from localhost ([::1]:34475 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WNpBZ-0002cW-29 for geb-bug-gnu-emacs@m.gmane.org; Wed, 12 Mar 2014 15:51:29 -0400 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:44574) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WNpBK-00026a-Go for bug-gnu-emacs@gnu.org; Wed, 12 Mar 2014 15:51:24 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1WNpB8-00087r-JR for bug-gnu-emacs@gnu.org; Wed, 12 Mar 2014 15:51:14 -0400 Original-Received: from debbugs.gnu.org ([140.186.70.43]:33766) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WNpB8-00087h-FE for bug-gnu-emacs@gnu.org; Wed, 12 Mar 2014 15:51:02 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.80) (envelope-from ) id 1WNpB7-0002Fc-R8 for bug-gnu-emacs@gnu.org; Wed, 12 Mar 2014 15:51:02 -0400 X-Loop: help-debbugs@gnu.org Resent-From: Jonas Bernoulli Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Wed, 12 Mar 2014 19:51:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: report 17000 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: X-Debbugs-Original-To: bug-gnu-emacs@gnu.org Original-Received: via spool by submit@debbugs.gnu.org id=B.13946538388600 (code B ref -1); Wed, 12 Mar 2014 19:51:01 +0000 Original-Received: (at submit) by debbugs.gnu.org; 12 Mar 2014 19:50:38 +0000 Original-Received: from localhost ([127.0.0.1]:34948 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.80) (envelope-from ) id 1WNpAi-0002EY-VC for submit@debbugs.gnu.org; Wed, 12 Mar 2014 15:50:37 -0400 Original-Received: from eggs.gnu.org ([208.118.235.92]:42723) by debbugs.gnu.org with esmtp (Exim 4.80) (envelope-from ) id 1WNpAf-0002EE-Ot for submit@debbugs.gnu.org; Wed, 12 Mar 2014 15:50:35 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1WNpAK-0007x9-W3 for submit@debbugs.gnu.org; Wed, 12 Mar 2014 15:50:33 -0400 Original-Received: from lists.gnu.org ([2001:4830:134:3::11]:49944) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WNpAK-0007r4-SU for submit@debbugs.gnu.org; Wed, 12 Mar 2014 15:50:12 -0400 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:41639) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WNow3-0002qu-7X for bug-gnu-emacs@gnu.org; Wed, 12 Mar 2014 15:35:34 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1WNovv-0003K8-K2 for bug-gnu-emacs@gnu.org; Wed, 12 Mar 2014 15:35:27 -0400 Original-Received: from mail.hostpark.net ([212.243.197.30]:49987) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WNovv-0003Jr-5k for bug-gnu-emacs@gnu.org; Wed, 12 Mar 2014 15:35:19 -0400 Original-Received: from localhost (localhost [127.0.0.1]) by mail.hostpark.net (Postfix) with ESMTP id 2735617312 for ; Wed, 12 Mar 2014 20:35:17 +0100 (CET) X-Virus-Scanned: by Hostpark/NetZone Mailprotection at hostpark.net Original-Received: from mail.hostpark.net ([127.0.0.1]) by localhost (mail1.hostpark.net [127.0.0.1]) (amavisd-new, port 10124) with ESMTP id aNHDiV8FoN6F for ; Wed, 12 Mar 2014 20:35:17 +0100 (CET) Original-Received: from lem (77-58-212-245.dclient.hispeed.ch [77.58.212.245]) (using TLSv1.2 with cipher DHE-RSA-AES128-SHA (128/128 bits)) (No client certificate requested) by mail.hostpark.net (Postfix) with ESMTPS id F35AF17156 for ; Wed, 12 Mar 2014 20:35:16 +0100 (CET) User-agent: mu4e 0.9.9.5; emacs 24.3.50.1 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.15 Precedence: list X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 140.186.70.43 X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Original-Sender: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.bugs:86786 Archived-At: 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)))