# HG changeset patch # User Kim F. Storm # Date 1115331358 0 # Node ID e002770fe3acffa2b693c7743b6dcd36292dd24f # Parent dc38e953666429a006311995a622a9b6127da70a (ido-setup-hook): New hook. (ido-define-mode-map-hook): Remove hook; use ido-setup-hook instead. (ido-input-stack): New var. (ido-define-mode-map): Bind M-b to ido-push-dir. Move old ido-next-work-file binding to M-O. Bind M-f to ido-wide-find-file-or-pop-dir. (ido-define-mode-map): Don't run ido-define-mode-map-hook. (ido-read-internal): Run ido-setup-hook. Catch quit in read-file-name and read-string to cancel edit. Handle new push, pop, and pop-all exit codes (for M-b/M-f). Automatically pop-all when completing a directory name (RET). (ido-file-internal): Add with-no-warnings around ffap and dired code. (ido-exit-minibuffer): Use exit-minibuffer instead of throw. (ido-wide-find-file, ido-wide-find-dir): Catch quit to cancel find. (ido-push-dir, ido-pop-dir, ido-wide-find-file-or-pop-dir): New functions for M-b/M-f to move among the directory components. (ido-make-merged-file-list): Catch quit to cancel merge. (ido-make-dir-list): Delete "." when ido-input-stack is non-empty. (ido-completion-help): No warnings for ido-completion-buffer-full. diff -r dc38e9536664 -r e002770fe3ac lisp/ido.el --- a/lisp/ido.el Thu May 05 22:15:45 2005 +0000 +++ b/lisp/ido.el Thu May 05 22:15:58 2005 +0000 @@ -251,8 +251,8 @@ ;; ;; Customize the `ido' group to change the `ido' functionality. ;; -;; To modify the keybindings, use the hook provided. For example: -;;(add-hook 'ido-define-mode-map-hook 'ido-my-keys) +;; To modify the keybindings, use the ido-setup-hook. For example: +;;(add-hook 'ido-setup-hook 'ido-my-keys) ;; ;;(defun ido-my-keys () ;; "Add my keybindings for ido." @@ -705,8 +705,11 @@ (const never)) :group 'ido) -(defcustom ido-define-mode-map-hook nil - "*Hook to define keys in `ido-mode-map' for extra keybindings." +(defcustom ido-setup-hook nil + "*Hook run after the ido variables and keymap has been setup. +The dynamic variable `ido-cur-item' contains the current type of item that +is read by ido, possible values are file, dir, buffer, and list. +Additional keys can be defined in `ido-mode-map'." :type 'hook :group 'ido) @@ -931,6 +934,9 @@ (defvar ido-text-init nil "The initial string for the users string it is typed in.") +(defvar ido-input-stack nil + "Stores the users strings when user hits M-b/M-f.") + (defvar ido-matches nil "List of files currently matching `ido-text'.") @@ -1399,13 +1405,14 @@ (define-key map [(meta backspace)] 'ido-delete-backward-word-updir) (define-key map [(control backspace)] 'ido-up-directory) (define-key map "\C-l" 'ido-reread-directory) - (define-key map [(meta ?b)] 'ido-next-work-file) (define-key map [(meta ?d)] 'ido-wide-find-dir) - (define-key map [(meta ?f)] 'ido-wide-find-file) + (define-key map [(meta ?b)] 'ido-push-dir) + (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 ?O)] 'ido-next-work-file) (define-key map [(meta ?p)] 'ido-prev-work-directory) (define-key map [(meta ?s)] 'ido-merge-work-directories) ) @@ -1431,8 +1438,7 @@ (define-key map [remap viper-del-backward-char-in-insert] 'ido-delete-backward-updir) (define-key map [remap viper-delete-backward-word] 'ido-delete-backward-word-updir))) - (setq ido-mode-map map) - (run-hooks 'ido-define-mode-map-hook))) + (setq ido-mode-map map))) (defun ido-final-slash (dir &optional fix-it) ;; return DIR if DIR has final slash. @@ -1601,6 +1607,10 @@ (ido-define-mode-map) (setq ido-text-init initial) + (setq ido-input-stack nil) + + (run-hooks 'ido-setup-hook) + (while (not done) (ido-trace "\n_LOOP_" ido-text-init) (setq ido-exit nil) @@ -1742,9 +1752,11 @@ (setq ido-text-init "") (while new (setq new (if edit - (read-file-name (concat prompt "[EDIT] ") - (expand-file-name d) - (concat d f) nil f) + (condition-case nil + (read-file-name (concat prompt "[EDIT] ") + (expand-file-name d) + (concat d f) nil f) + (quit (concat d f))) f) d (or (file-name-directory new) "/") f (file-name-nondirectory new) @@ -1763,7 +1775,11 @@ (setq ido-text-init f new nil)))))) (t - (setq ido-text-init (read-string (concat prompt "[EDIT] ") ido-final-text)))) + (setq ido-text-init + (condition-case nil + (read-string (concat prompt "[EDIT] ") ido-final-text) + (quit ido-final-text))))) + nil) ((eq ido-exit 'keep) @@ -1772,7 +1788,7 @@ ((memq ido-exit '(dired fallback find-file switch-to-buffer insert-buffer insert-file)) (setq done t)) - ((eq ido-exit 'updir) + ((memq ido-exit '(updir push)) ;; cannot go up if already at the root-dir (Unix) or at the ;; root-dir of a certain drive (Windows or MS-DOS). (if (ido-is-tramp-root) @@ -1781,9 +1797,31 @@ (ido-set-current-directory (match-string 1 ido-current-directory)) (setq ido-set-default-item t)) (unless (ido-is-root-directory) + (when (eq ido-exit 'push) + (setq ido-input-stack (cons (cons ido-cur-item ido-text) ido-input-stack)) + (setq ido-cur-item 'dir) + (setq ido-text-init (file-name-nondirectory (substring ido-current-directory 0 -1))) + (ido-trace "push" ido-input-stack)) (ido-set-current-directory (file-name-directory (substring ido-current-directory 0 -1))) (setq ido-set-default-item t)))) + ((eq ido-exit 'pop) + (ido-trace "pop" ido-input-stack) + (let ((elt (car ido-input-stack))) + (setq ido-input-stack (cdr ido-input-stack)) + (ido-set-current-directory (concat ido-current-directory ido-text)) + (setq ido-cur-item (car elt)) + (setq ido-text-init (cdr elt)))) + + ((eq ido-exit 'pop-all) + (ido-trace "pop-all" ido-input-stack) + (while ido-input-stack + (let ((elt (car ido-input-stack))) + (setq ido-input-stack (cdr ido-input-stack)) + (ido-set-current-directory (concat ido-current-directory ido-text)) + (setq ido-cur-item (car elt)) + (setq ido-text-init (cdr elt))))) + ;; Handling the require-match must be done in a better way. ((and require-match (not (if ido-directory-too-big @@ -1838,7 +1876,14 @@ (setq ido-last-directory-list (cons (cons ido-current-directory ido-selected) ido-last-directory-list))))) (ido-set-current-directory ido-current-directory ido-selected) - (setq ido-set-default-item t)) + (if ido-input-stack + (while ido-input-stack + (let ((elt (car ido-input-stack))) + (if (setq ido-input-stack (cdr ido-input-stack)) + (ido-set-current-directory ido-current-directory (cdr elt)) + (setq ido-text-init (cdr elt))) + (setq ido-cur-item (car elt)))) + (setq ido-set-default-item t))) (t (setq done t)))))) @@ -1968,10 +2013,11 @@ (require 'ffap) ;; Duplicate code from ffap-guesser as we want different behaviour for files and URLs. (cond - ((and ido-use-url-at-point - ffap-url-regexp - (ffap-fixup-url (or (ffap-url-at-point) - (ffap-gopher-at-point)))) + ((with-no-warnings + (and ido-use-url-at-point + ffap-url-regexp + (ffap-fixup-url (or (ffap-url-at-point) + (ffap-gopher-at-point))))) (setq ido-exit 'ffap filename t)) @@ -2041,7 +2087,8 @@ (ido-record-work-directory) (funcall method ido-current-directory) (if (eq method 'dired) - (dired-goto-file (expand-file-name file)))) + (with-no-warnings + (dired-goto-file (expand-file-name file))))) ((string-match "[[*?]" filename) (setq dirname (concat ido-current-directory filename)) (ido-record-command method dirname) @@ -2283,7 +2330,7 @@ (interactive) (if (or (not ido-require-match) (ido-existing-item-p)) - (throw 'exit nil))) + (exit-minibuffer))) (defun ido-select-text () "Select the buffer or file named by the prompt. @@ -2432,7 +2479,9 @@ (unless file (let ((enable-recursive-minibuffers t)) (setq file - (read-string (concat "Wide find file: " ido-current-directory) ido-text)))) + (condition-case nil + (read-string (concat "Wide find file: " ido-current-directory) ido-text) + (quit ""))))) (when (> (length file) 0) (setq ido-use-merged-list t ido-try-merged-list 'wide) (setq ido-exit 'refresh) @@ -2446,7 +2495,9 @@ (unless dir (let ((enable-recursive-minibuffers t)) (setq dir - (read-string (concat "Wide find directory: " ido-current-directory) ido-text)))) + (condition-case nil + (read-string (concat "Wide find directory: " ido-current-directory) ido-text) + (quit ""))))) (when (> (length dir) 0) (setq ido-use-merged-list t ido-try-merged-list 'wide) (setq ido-exit 'refresh) @@ -2454,6 +2505,26 @@ (setq ido-rotate-temp t) (exit-minibuffer))) +(defun ido-push-dir () + "Move to previous directory in file name, push current input on stack." + (interactive) + (setq ido-exit 'push) + (exit-minibuffer)) + +(defun ido-pop-dir (arg) + "Pop directory from input stack back to input. +With \\[universal-argument], pop all element." + (interactive "P") + (when ido-input-stack + (setq ido-exit (if arg 'pop-all 'pop)) + (exit-minibuffer))) + +(defun ido-wide-find-file-or-pop-dir (arg) + (interactive "P") + (if ido-input-stack + (ido-pop-dir arg) + (ido-wide-find-file))) + (defun ido-make-directory (&optional dir) "Prompt for DIR to create in current directory." (interactive) @@ -2771,67 +2842,69 @@ (defun ido-make-merged-file-list (text auto wide) (let (res) (message "Searching for `%s'...." text) - (if (and (ido-final-slash text) ido-dir-file-cache) - (if wide - (setq res (ido-wide-find-dirs-or-files - ido-current-directory (substring text 0 -1) ido-enable-prefix t)) - ;; Use list of cached directories - (let ((re (concat (regexp-quote (substring text 0 -1)) "[^/:]*/\\'")) - (dirs ido-dir-file-cache) - dir b d f) - (if nil ;; simple - (while dirs - (setq dir (car (car dirs)) - dirs (cdr dirs)) - (when (and (string-match re dir) - (not (ido-ignore-item-p dir ido-ignore-directories-merge)) - (file-directory-p dir)) - (setq b (substring dir 0 -1) - f (concat (file-name-nondirectory b) "/") - d (file-name-directory b) - res (cons (cons f d) res)))) + (condition-case nil + (if (and (ido-final-slash text) ido-dir-file-cache) + (if wide + (setq res (ido-wide-find-dirs-or-files + ido-current-directory (substring text 0 -1) ido-enable-prefix t)) + ;; Use list of cached directories + (let ((re (concat (regexp-quote (substring text 0 -1)) "[^/:]*/\\'")) + (dirs ido-dir-file-cache) + dir b d f) + (if nil ;; simple + (while dirs + (setq dir (car (car dirs)) + dirs (cdr dirs)) + (when (and (string-match re dir) + (not (ido-ignore-item-p dir ido-ignore-directories-merge)) + (file-directory-p dir)) + (setq b (substring dir 0 -1) + f (concat (file-name-nondirectory b) "/") + d (file-name-directory b) + res (cons (cons f d) res)))) + (while dirs + (setq dir (car dirs) + d (car dir) + dirs (cdr dirs)) + (when (not (ido-ignore-item-p d ido-ignore-directories-merge)) + (setq dir (cdr (cdr dir))) + (while dir + (setq f (car dir) + dir (cdr dir)) + (if (and (string-match re f) + (not (ido-ignore-item-p f ido-ignore-directories))) + (setq res (cons (cons f d) res))))) + (if (and auto (input-pending-p)) + (setq dirs nil + res t)))))) + (if wide + (setq res (ido-wide-find-dirs-or-files + ido-current-directory text ido-enable-prefix nil)) + (let ((ido-text text) + (dirs ido-work-directory-list) + (must-match (and text (> (length text) 0))) + dir fl) + (if (and auto (not (member ido-current-directory dirs))) + (setq dirs (cons ido-current-directory dirs))) (while dirs (setq dir (car dirs) - d (car dir) dirs (cdr dirs)) - (when (not (ido-ignore-item-p d ido-ignore-directories-merge)) - (setq dir (cdr (cdr dir))) - (while dir - (setq f (car dir) - dir (cdr dir)) - (if (and (string-match re f) - (not (ido-ignore-item-p f ido-ignore-directories))) - (setq res (cons (cons f d) res))))) + (when (and dir (stringp dir) + (or ido-merge-ftp-work-directories + (not (ido-is-ftp-directory dir))) + (file-directory-p dir) + ;; TODO. check for nonreadable and too-big. + (setq fl (if (eq ido-cur-item 'file) + (ido-make-file-list1 dir t) + (ido-make-dir-list1 dir t)))) + (if must-match + (setq fl (ido-set-matches1 fl))) + (if fl + (setq res (nconc fl res)))) (if (and auto (input-pending-p)) (setq dirs nil res t)))))) - (if wide - (setq res (ido-wide-find-dirs-or-files - ido-current-directory text ido-enable-prefix nil)) - (let ((ido-text text) - (dirs ido-work-directory-list) - (must-match (and text (> (length text) 0))) - dir fl) - (if (and auto (not (member ido-current-directory dirs))) - (setq dirs (cons ido-current-directory dirs))) - (while dirs - (setq dir (car dirs) - dirs (cdr dirs)) - (when (and dir (stringp dir) - (or ido-merge-ftp-work-directories - (not (ido-is-ftp-directory dir))) - (file-directory-p dir) - ;; TODO. check for nonreadable and too-big. - (setq fl (if (eq ido-cur-item 'file) - (ido-make-file-list1 dir t) - (ido-make-dir-list1 dir t)))) - (if must-match - (setq fl (ido-set-matches1 fl))) - (if fl - (setq res (nconc fl res)))) - (if (and auto (input-pending-p)) - (setq dirs nil - res t)))))) + (quit (setq res t))) (if (and res (not (eq res t))) (setq res (ido-sort-merged-list res auto))) (when (and (or ido-rotate-temp ido-rotate-file-list-default) @@ -3063,7 +3136,8 @@ (setq ido-temp-list (cons default ido-temp-list)))) (setq ido-temp-list (delete "." ido-temp-list)) - (setq ido-temp-list (cons "." ido-temp-list)) + (unless ido-input-stack + (setq ido-temp-list (cons "." ido-temp-list))) (run-hooks 'ido-make-dir-list-hook) ido-temp-list)) @@ -3265,7 +3339,8 @@ (if (pos-visible-in-window-p (point-max) win) (if (or ido-completion-buffer-all-completions (boundp 'ido-completion-buffer-full)) (set-window-start win (point-min)) - (set (make-local-variable 'ido-completion-buffer-full) t) + (with-no-warnings + (set (make-local-variable 'ido-completion-buffer-full) t)) (setq full-list t display-it t)) (scroll-other-window))