Function: ido-read-internal

ido-read-internal is a byte-compiled function defined in ido.el.gz.

Signature

(ido-read-internal ITEM PROMPT HIST &optional DEFAULT REQUIRE-MATCH INITIAL)

Documentation

Perform the ido-read-buffer and ido-read-file-name functions.

Return the name of a buffer or file selected. PROMPT is the prompt to give to the user. DEFAULT if given is the default item to start with. If REQUIRE-MATCH is non-nil, an existing file must be selected. If INITIAL is non-nil, it specifies the initial input string.

Source Code

;; Defined in /usr/src/emacs/lisp/ido.el.gz
;; Here is very briefly how ido-find-file works:
;;
;;  (ido-find-file)
;;    (ido-file-internal method)
;;       set ido-current-directory
;;       (ido-read-internal 'file ...)
;;          (while ...
;;             (ido-make-item-list ...)
;;             (ido-set-matches)
;;             (completing-read ... ido-text-init ...)
;;
;;               ... here user is allowed to type characters and commands
;;                   a command may set ido-exit and call (exit-minibuffer)
;;                   to make ido-read-internal do advanced tasks (or return)
;;
;;               ... ido-tidy and ido-exhibit are pre- and post-hooks
;;                   which are run before and after each user command.
;;
;;             return value from completing-read is stored in ido-final-text
;;             - ido-exit may cause further actions to be taken:
;;               'refresh - repeat loop (make-item-list, set-matches)
;;               'edit    - edit the prompt string, then repeat loop
;;               'keep    - repeat loop but don't (re)make-item-list
;;               'updir   - go up one directory, repeat loop
;;               else set ido-selected based on ido-final-text,
;;               optionally update ido-current-directory and repeat loop, or
;;               exit with the return value of ido-selected (file name)
;;       selected file name is returned from ido-read-internal,
;;       ido-exit and method determines what action is taken
;;       e.g. the file name may be ignored or joined with ido-current-directory, and
;;       the relevant function is called (find-file, write-file, etc).

(defun ido-read-internal (item prompt hist &optional default require-match initial)
  "Perform the `ido-read-buffer' and `ido-read-file-name' functions.
Return the name of a buffer or file selected.
PROMPT is the prompt to give to the user.
DEFAULT if given is the default item to start with.
If REQUIRE-MATCH is non-nil, an existing file must be selected.
If INITIAL is non-nil, it specifies the initial input string."
  (let
      ((ido-cur-item item)
       (ido-entry-buffer (current-buffer))
       (ido-process-ignore-lists t)
       (ido-process-ignore-lists-inhibit nil)
       (ido-set-default-item t)
       ido-default-item
       ido-selected
       ido-final-text
       (done nil)
       (icomplete-mode nil) ;; prevent icomplete starting up
       ;; Exported dynamic variables:
       ido-cur-list
       ido-ignored-list
       (ido-rotate-temp nil)
       (ido-keep-item-list nil)
       (ido-use-merged-list nil)
       (ido-try-merged-list t)
       (ido-pre-merge-state nil)
       (ido-case-fold ido-case-fold)
       (ido-enable-prefix ido-enable-prefix)
       (ido-enable-regexp ido-enable-regexp)
       (ido-show-confirm-message nil)
       )

    (ido-setup-completion-map)

    (setq ido-text-init
          (if (consp initial)
              (cons (car initial)
                    ;; `completing-read' uses 0-based index while
                    ;; `read-from-minibuffer' uses 1-based index.
                    (1+ (cdr initial)))
            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)
      (setq ido-rescan t)
      (setq ido-rotate nil)
      (setq ido-text "")
      (when ido-set-default-item
	(setq ido-default-item
	      (cond
	       ((eq item 'buffer)
		(if (bufferp default) (buffer-name default) default))
	       ((stringp default)
		(if (memq item '(file dir))
		    (file-name-nondirectory default)
		  default))
	       ((eq item 'file)
		(and ido-enable-last-directory-history
		     (let ((d (assoc ido-current-directory ido-last-directory-list)))
		       (and d (cdr d)))))))
	(if (member ido-default-item ido-ignore-item-temp-list)
	    (setq ido-default-item nil))
	(ido-trace "new default" ido-default-item)
	(if ido-default-item
	    (setq ido-initial-position 0))
	(setq ido-set-default-item nil))

      (if ido-process-ignore-lists-inhibit
	  (setq ido-process-ignore-lists nil))

      (if (and ido-use-merged-list (memq ido-try-merged-list '(t wide)) (not ido-keep-item-list))
	  (let ((olist ido-cur-list)
		(oign ido-ignored-list)
		(omat ido-matches)
		(l (ido-make-merged-file-list ido-text-init
					      (eq ido-use-merged-list 'auto)
					      (eq ido-try-merged-list 'wide))))
	    (ido-trace "merged" l)
	    (cond
	     ((not l)
	      (if (eq ido-try-merged-list 'wide)
		  (setq ido-pre-merge-state
			(list "" ido-current-directory olist oign omat)
			ido-cur-list nil
			ido-ignored-list nil
			ido-matches nil
			ido-keep-item-list t
			ido-try-merged-list (if (eq ido-use-merged-list 'auto) 'auto nil)
			ido-use-merged-list nil)
		(setq ido-cur-list olist
		      ido-ignored-list oign
		      ido-matches omat
		      ido-keep-item-list t
		      ido-try-merged-list (if (eq ido-use-merged-list 'auto) 'auto nil)
		      ido-use-merged-list nil)))
	     ((eq l t)
	      (setq ido-use-merged-list nil))
	     ((eq l 'input-pending-p)
	      (setq ido-try-merged-list t
		    ido-use-merged-list nil))
	     (t
	      (setq ido-pre-merge-state
		    (list ido-text-init ido-current-directory olist oign omat))
	      (ido-set-current-directory (car (cdr (car l))))
	      (if (ido-final-slash ido-text-init)
		  (setq ido-text-init ""))
	      (setq ido-cur-list l
		    ido-ignored-list nil
		    ido-matches l
		    ido-rescan nil
		    ido-keep-item-list t
		    ido-use-merged-list t)
	      (ido-trace "Merged" t)
	      ))))

      (cond
       (ido-keep-item-list
	(setq ido-keep-item-list nil
	      ido-rescan nil))
       ((eq ido-cur-item 'file)
	(setq ido-ignored-list nil
	      ido-cur-list (and (not ido-directory-nonreadable)
				(not ido-directory-too-big)
				(ido-make-file-list ido-default-item))))
       ((eq ido-cur-item 'dir)
	(setq ido-ignored-list nil
	      ido-cur-list (and (not ido-directory-nonreadable)
				(not ido-directory-too-big)
				(ido-make-dir-list ido-default-item))))
       ((eq ido-cur-item 'buffer)
	(setq ido-ignored-list nil
	      ido-cur-list (ido-make-buffer-list ido-default-item)))
       ((eq ido-cur-item 'list)
	(setq ido-ignored-list nil
	      ido-cur-list (ido-make-choice-list ido-default-item)))
       (t nil))
      (setq ido-rotate-temp nil)

      (if ido-process-ignore-lists-inhibit
	  (setq ido-process-ignore-lists t
		ido-process-ignore-lists-inhibit nil))

      (ido-set-matches)
      (if (and ido-matches (eq ido-try-merged-list 'auto))
	  (setq ido-try-merged-list t))
      (let ((max-mini-window-height (or ido-max-window-height
					(and (boundp 'max-mini-window-height)
					     max-mini-window-height)))
	   (ido-completing-read t)
	   (ido-require-match require-match)
	   (ido-use-mycompletion-depth (1+ (minibuffer-depth)))
	   (show-paren-mode nil)
	   ;; Postpone history adding till later
	   (history-add-new-input nil))
	;; prompt the user for the file name
	(setq ido-exit nil)
	(setq ido-final-text
	      (catch 'ido
		(read-from-minibuffer (ido-make-prompt item prompt)
				      (prog1 ido-text-init
					(setq ido-text-init nil))
				      ido-completion-map nil hist))))
      (ido-trace "read-from-minibuffer" ido-final-text)
      (and ido-completion-buffer
	   (get-buffer ido-completion-buffer)
	   (kill-buffer ido-completion-buffer))

      (ido-trace "\n_EXIT_" ido-exit)

      (cond
       ((eq ido-exit 'refresh)
	(if (and (eq ido-use-merged-list 'auto)
		 (or (input-pending-p)))
	    (setq ido-use-merged-list nil
		  ido-keep-item-list t))
	nil)

       ((eq ido-exit 'done)
	(setq done t
	      ido-selected ido-text
	      ido-exit nil))

       ((memq ido-exit '(edit chdir))
	(cond
	 ((memq ido-cur-item '(file dir))
	  (let* ((read-file-name-function nil)
		 (edit (eq ido-exit 'edit))
		 (d ido-current-directory)
		 (f ido-text-init)
		 (new t))
	    (setq ido-text-init "")
	    (while new
	      (setq new (if edit
			    (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)
		    edit t)
	      (if (or
		   (file-directory-p d)
		   (and (yes-or-no-p (format "Create directory %s? " d))
			(condition-case nil
			    (progn (make-directory d t) t)
			  (error
			   (message "Could not create directory")
			   (sit-for 1)
			   nil))))
		  (progn
		    (ido-set-current-directory d nil (eq ido-exit 'chdir))
		    (setq ido-text-init f
			  new nil))))))
	 (t
	  (setq ido-text-init
		(condition-case nil
		    (read-string (concat prompt "[EDIT] ") ido-final-text)
		  (quit ido-final-text)))))

	nil)

       ((eq ido-exit 'keep)
	(setq ido-keep-item-list t))

       ((memq ido-exit '(dired fallback find-file switch-to-buffer insert-buffer insert-file))
	(setq done t))

       ((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)
	    (when (string-match "\\`\\(/\\([^/]+[:@]\\)*\\)\\([^/]+\\)[:@]\\'" ido-current-directory)
	      (setq ido-text-init (match-string 3 ido-current-directory))
	      (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 (memq require-match '(confirm confirm-after-completion)))
	     (not (if ido-directory-too-big
		      (file-exists-p (concat ido-current-directory ido-final-text))
		    (ido-existing-item-p))))
	(error "Must specify valid item"))

       (t
	(setq ido-selected
	      (if (or (eq ido-exit 'takeprompt)
		      (null ido-matches))
		  ido-final-text
		;; else take head of list
		(ido-name (car ido-matches))))

	(cond
	 ((memq item '(buffer list))
	  (setq done t))

	 ((string-equal "./" ido-selected)
	  nil)

	 ((string-equal "../" ido-selected)
	  ;; cannot go up if already at the root-dir (Unix) or at the
	  ;; root-dir of a certain drive (Windows or MS-DOS).
	  (or (ido-is-root-directory)
	      (ido-set-current-directory (file-name-directory (substring ido-current-directory 0 -1))))
	  (setq ido-set-default-item t))

	 ((and (string-match (if ido-enable-tramp-completion ".[:@]\\'" ".:\\'") ido-selected)
	       (ido-is-root-directory) ;; Ange-ftp or Tramp
	       (not (ido-local-file-exists-p ido-selected)))
	  (ido-set-current-directory ido-current-directory ido-selected)
	  (ido-trace "tramp prefix" ido-selected)
	  (if (ido-is-slow-ftp-host)
	      (setq ido-exit 'fallback
		    done t)
	    (setq ido-set-default-item t)))

	 ((string-match (if (memq system-type '(windows-nt ms-dos))
			    "\\`[a-zA-Z]:\\|[/\\][^/\\]"
			  "/[^/]")
			ido-selected)
	  (ido-set-current-directory (file-name-directory ido-selected))
	  (setq ido-set-default-item t))

	 ((string-match "\\`~" ido-selected)
	  (ido-set-current-home ido-selected))

	 ((ido-final-slash ido-selected)
	  (if ido-enable-last-directory-history
	      (let ((x (assoc ido-current-directory ido-last-directory-list)))
		(if x
		    (setcdr x ido-selected)
		  (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)
	  (if ido-input-stack
	      ; automatically pop stack elements which match existing files or directories
	      (let (elt)
		(while (and (setq elt (car ido-input-stack))
			    (file-exists-p (concat ido-current-directory (cdr elt))))
		  (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))))))
    (add-to-history (cond
		     ((consp hist)
		      (or (car hist) 'minibuffer-history))
		     (hist hist)
		     (t 'minibuffer-history))
		    ido-selected)
    ido-selected))