diff lisp/dired/gmhist-mh.el @ 0:376386a54a3c r19-14

Import from CVS: tag r19-14
author cvs
date Mon, 13 Aug 2007 08:45:50 +0200
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/dired/gmhist-mh.el	Mon Aug 13 08:45:50 2007 +0200
@@ -0,0 +1,354 @@
+;;;; gmhist-mh.el - emulate proposed Emacs 19 builtin Minibuffer History
+;;;; Id: gmhist-mh.el,v 4.8 1991/09/20 13:15:40 sk RelBeta 
+
+;;;; This package redefines the functions
+;;;;
+;;;;     read-string
+;;;;     completing-read
+;;;;     write-region
+;;;;     delete-file
+;;;;     read-buffer
+;;;;     read-file-name
+;;;;     switch-to-buffer
+;;;;
+;;;; to implement the variables
+;;;;
+;;;;     minibuffer-history-symbol
+;;;;     file-history-symbol
+;;;;     buffer-history-symbol
+;;;;     buffer-history-lru-order
+;;;;     max-minibuffer-history-length
+;;;;
+;;;; and the hooks
+;;;;
+;;;;    after-write-region-hook
+;;;;    after-delete-file-hook
+
+(require 'gmhist)
+(provide 'gmhist-mh)
+
+(defvar max-minibuffer-history-length 'not-implemented)
+
+;;;; Redefining basic Emacs functions
+
+(defun gmhist-overwrite (fun)
+  ;; Overwrite FUN (a symbol, the name of a function) with gmhist-new-FUN.
+  ;; Save the old def of FUN in gmhist-old-FUN.
+  ;; Conventions: gmhist-FUN emulates FUN, but with history.
+  ;; 		  gmhist-new-FUN may take additional care of the case
+  ;; 		  that history is disabled before calling gmhist-FUN
+  ;; 		  to do the real work.
+  (let* ((fun-name (symbol-name fun))
+	 (old-name (intern (concat "gmhist-old-" fun-name)))
+	 (new-name (intern (concat "gmhist-new-" fun-name))))
+    (or (fboundp old-name)
+	(fset old-name (symbol-function fun)))
+    (fset fun new-name)))
+
+;;; Minibuffer history (not specialized like file or buffer history)
+
+;;; Should perhaps modify minibuffer keymaps directly:
+;;; minibuffer-local-completion-map
+;;; minibuffer-local-map
+;;; minibuffer-local-must-match-map
+;;; minibuffer-local-ns-map
+
+(defun gmhist-new-read-string (gnrs-prompt &optional initial-input)
+  "Read a string from the minibuffer, prompting with string PROMPT.
+If non-nil second arg INITIAL-INPUT is a string to insert before reading.
+See also `minibuffer-history-symbol'."
+  (if minibuffer-history-symbol
+      (gmhist-read-from-minibuffer gnrs-prompt initial-input gmhist-map)
+    (gmhist-old-read-string gnrs-prompt initial-input)))
+
+(gmhist-overwrite 'read-string)
+
+(defun gmhist-new-completing-read
+  (gncr-prompt table &optional predicate mustmatch initial)
+  "Read a string in the minibuffer, with completion and history.
+Args are PROMPT, TABLE, PREDICATE, REQUIRE-MATCH and INITIAL-INPUT.
+PROMPT is a string to prompt with; normally it ends in a colon and a space.
+TABLE is an alist whose elements' cars are strings, or an obarray (see
+  try-completion).
+PREDICATE limits completion to a subset of TABLE see try-completion
+  for details.
+If REQUIRE-MATCH is non-nil, the user is not allowed to exit unless
+ the input is (or completes to) an element of TABLE.
+ If it is also not t, Return does not exit if it does non-null completion.
+If INITIAL-INPUT is non-nil, insert it in the minibuffer initially.
+Case is ignored if ambient value of  completion-ignore-case  is non-nil.
+
+*** This is the gmhist version ***
+See variable `minibuffer-history-symbol'."
+  (if minibuffer-history-symbol
+      (gmhist-completing-read gncr-prompt table predicate mustmatch initial)
+    (gmhist-old-completing-read gncr-prompt table predicate mustmatch initial)))
+
+(gmhist-overwrite 'completing-read)
+
+;;; File history
+
+(defvar file-history (get file-history-symbol 'initial-hist)
+  "Default history of file names read with read-file-name.
+This symbol is the default value of file-history-symbol (q.v.).")
+
+(defvar insert-file-default nil
+  "*If non-nil, defaults for filenames will be inserted into the
+minibuffer prompt.  This has the advantage of putting the default onto
+the file-history (which see).")
+
+(defun gmhist-new-read-file-name (gnrfn-prompt
+				  &optional dir default mustmatch initial)
+    "Read file name, maintaining history in value of
+file-history-symbol, prompting with PROMPT, completing in directory DIR.
+
+Value is not expanded!  You must call expand-file-name yourself.
+
+Default name to third arg DEFAULT if user enters a null string.
+\(If DEFAULT is omitted, the visited file name is used.)
+
+Fourth arg MUSTMATCH non-nil means require existing file's name.
+Non-nil and non-t means also require confirmation after completion.
+
+Fifth arg INITIAL specifies text to start with.
+DIR defaults to current buffer's default-directory.
+
+*** This is the gmhist version ***
+
+It differs from the original read-file-name in providing a
+history of filenames in the variable whose name is the value of
+file-history-symbol (usually 'file-history) (both of which see).
+
+INITIAL defaults to default-directory's value if
+insert-default-directory is non-nil.  Also, if insert-file-default is
+non-nil, it inserts the DEFAULT string if no INITIAL is given, which
+has the advantage of putting the default onto the file-history.
+However, setting INITIAL to a string is a way for providing an
+editable default, something not possible with (pre Emacs-19)
+read-file-name.  Setting INITIAL and insert-default-directory to nil
+will yield a basename for the file, relative to default-directory.
+
+See function read-with-history-in for a list of properties you can put
+on file-history-symbol."
+    (if (null file-history-symbol)
+	(gmhist-old-read-file-name gnrfn-prompt dir default mustmatch)
+      (gmhist-read-file-name gnrfn-prompt dir default mustmatch
+			     (if (and insert-file-default
+				      (not initial))
+				 default
+			       initial))))
+
+;; It is a shame that none of the standard hooks are defvar'd!
+;; Also, the coexistence of `hooks' vs `hook' is annoying.
+;; The singular seems to be the majority, so I'll use that.
+
+(defvar after-write-region-hook nil
+  "Run after the gmhist version of `write-region'.
+The variables `start', `end', `filename', `append', `visit' are bound
+around the call to the hook.")
+
+;; Don't use &rest args, as the hook may want to take advantage of our
+;; arglist.
+(defun gmhist-new-write-region (start end filename
+				      &optional append visit)
+  "Write current region into specified file.
+When called from a program, takes three arguments:
+START, END and FILENAME.  START and END are buffer positions.
+Optional fourth argument APPEND if non-nil means
+  append to existing file contents (if any).
+Optional fifth argument VISIT if t means
+  set last-save-file-modtime of buffer to this file's modtime
+  and mark buffer not modified.
+If VISIT is neither t nor nil, it means do not print
+  the \"Wrote file\" message.
+
+*** This is the gmhist version ***
+See variable `after-write-region-hook'."
+  (interactive "r\nFWrite region to file: ")
+  (prog1
+      (gmhist-old-write-region start end filename append visit)
+    (condition-case err
+	;; basic-save-buffer would assume an error to mean
+	;; write-region failed
+	(run-hooks 'after-write-region-hook)
+      (error (message "Error in after-write-region-hook %s" err)
+	     (sit-for 1)))))
+
+(defvar after-delete-file-hook nil
+  "Run after the gmhist version of `delete-file'.
+The hook is run with `filename' bound to the filename.")
+
+(defun gmhist-new-delete-file (filename)
+  "Delete specified file.  One argument, a file name string.
+If file has multiple names, it continues to exist with the other names.
+
+*** This is the gmhist version ***
+See variable `after-delete-file-hook'."
+  (interactive "fDelete file: ")
+  (prog1
+      (gmhist-old-delete-file filename)
+    (condition-case err
+	;; We don't want callers to assume an error in the hook to
+	;; mean delete-file failed - or do we?
+	(run-hooks 'after-delete-file-hook)
+      (error (message "Error in after-delete-file-hook %s" err)
+	     (sit-for 1)))))
+
+(gmhist-overwrite 'read-file-name)
+(gmhist-overwrite 'write-region)
+(gmhist-overwrite 'delete-file)
+
+;; Redefining read-file-name does not suffice as interactive "f"
+;; calls the C version of read-file-name.
+;; gmhist-interactive of gmhist.el,v 4.4 and later understands the
+;; indirection from file-history-symbol to 'file-history (or whatever
+;; the current value may be).
+(gmhist-make-magic 'find-file              'file-history-symbol)
+(gmhist-make-magic 'find-file-other-window 'file-history-symbol)
+(gmhist-make-magic 'find-file-read-only    'file-history-symbol)
+(gmhist-make-magic 'insert-file            'file-history-symbol)
+(gmhist-make-magic 'load-file              'file-history-symbol)
+(gmhist-make-magic 'set-visited-file-name  'file-history-symbol)
+(gmhist-make-magic 'append-to-file         'file-history-symbol)
+;; write-region is wrapped by gmhist, no longer a subr, thus this works:
+(gmhist-make-magic 'write-region           'file-history-symbol)
+;; ditto for delete-file:
+(gmhist-make-magic 'delete-file            'file-history-symbol)
+(if gmhist-emacs-19-p
+    ;; In Emacs 19, these call the redefined read-file-name inside
+    ;; interactive, so we don't need to do anything
+    nil
+  (gmhist-make-magic 'write-file           'file-history-symbol)
+  (gmhist-make-magic 'find-alternate-file  'file-history-symbol))
+
+
+;;; Buffer history
+
+(defvar buffer-history-lru-order nil
+  "*If non-nil, the buffer history will be the complete buffer
+list in most recently used order (as returned by buffer-list).
+
+Usually, the buffer history is in the order entered using read-buffer.")
+
+(defvar buffer-history (get 'buffer-history 'initial-hist)
+  "History of all buffer names read with read-buffer.")
+
+(defun gmhist-new-read-buffer (gnrb-prompt &optional default existing)
+  "One arg PROMPT, a string.  Read the name of a buffer and return as a string.
+Prompts with PROMPT.
+Optional second arg is value to return if user enters an empty line.
+If optional third arg REQUIRE-MATCH is non-nil, only existing buffer names are allowed.
+
+*** This is the gmhist version ***
+
+See variables `buffer-history-symbol' and `buffer-history-lru-order'."
+  (if (and buffer-history-symbol
+	   buffer-history-lru-order)
+      (set buffer-history-symbol
+	   (mapcar (function buffer-name) (buffer-list))))
+  (gmhist-read-buffer gnrb-prompt default existing))
+
+(defun gmhist-new-switch-to-buffer (buffer &optional norecord)
+  "Select buffer BUFFER in the current window.
+BUFFER may be a buffer or a buffer name.
+Optional second arg NORECORD non-nil means
+do not put this buffer at the front of the list of recently selected ones.
+
+WARNING: This is NOT the way to work on another buffer temporarily
+within a Lisp program!  Use `set-buffer' instead.  That avoids messing with
+the window-buffer correspondences.
+
+*** This is the gmhist version ***
+
+It adds buffer-history to switch-to-buffer."
+  (interactive
+   ;; should perhaps bypass gmhist if NORECORD is given?
+   (list (gmhist-new-read-buffer "Switch to buffer: " (other-buffer) nil)))
+  (gmhist-old-switch-to-buffer buffer norecord))
+
+(gmhist-overwrite 'read-buffer)
+;; switch-to-buffer is a subr:
+(gmhist-overwrite 'switch-to-buffer)
+;; Redefining read-buffer does not suffice as interactive "b"
+;; calls the C version of read-buffer.
+;; gmhist-interactive of gmhist.el,v 4.4 and later understands the
+;; indirection from buffer-history-symbol to 'buffer-history (or
+;; whatever the current value may be).
+(mapcar (function (lambda (fun)
+		    (gmhist-make-magic fun 'buffer-history-symbol)))
+	'(switch-to-buffer-other-window ; files.el
+	  append-to-buffer		; the rest from simple.el
+	  prepend-to-buffer
+	  copy-to-buffer))
+
+
+;;; read-from-minibuffer
+;;; saved and defined in gmhist.el, just need to overwrite:
+
+(fset 'read-from-minibuffer 'gmhist-new-read-from-minibuffer)
+
+;; Now that we've redefined read-from-minibuffer we need to make sure
+;; that repeat-complex-command (C-x ESC), which calls
+;; read-from-minibuffer, adds the command to command-history and not
+;; to the ambient value of minibuffer-history-symbol.  The latter
+;; could be confusing if e.g. inside a C-x C-f a C-x ESC is done (with
+;; enable-recursive-minibuffers t): it would add a command to the
+;; file-history.
+
+;(defun repeat-complex-command (repeat-complex-command-arg)
+;  "Edit and re-evaluate last complex command, or ARGth from last.
+;A complex command is one which used the minibuffer.
+;The command is placed in the minibuffer as a Lisp form for editing.
+;The result is executed, repeating the command as changed.
+;If the command has been changed or is not the most recent previous command
+;it is added to the front of the command history.
+;Whilst editing the command, the following commands are available:
+;\\{repeat-complex-command-map}"
+;  (interactive "p")
+;  (let ((elt (nth (1- repeat-complex-command-arg) command-history))
+;	newcmd)
+;    (if elt
+;	(progn
+;	  (setq newcmd
+;		(let ((minibuffer-history-symbol nil))
+;		  ;; Don't let gmhist interfere with command-history.
+;		  ;; command-history is special because it's builtin to M-x.
+;		  ;; Also, gmhist would store commands as strings, not
+;		  ;; as s-exprs.
+;		  ;; When gmhist is implemented in C, M-x must be
+;		  ;; fixed to store strings, too.
+;		  (read-from-minibuffer "Redo: "
+;					(prin1-to-string elt)
+;					repeat-complex-command-map
+;					t)))
+;	  ;; If command to be redone does not match front of history,
+;	  ;; add it to the history.
+;	  (or (equal newcmd (car command-history))
+;	      (setq command-history (cons newcmd command-history)))
+;	  (eval newcmd))
+;      (ding))))
+
+;; Actually, it's easier to just use the gmhist re-implementation instead
+(define-key ctl-x-map "\e" 'gmhist-repeat-complex-command)
+
+(defun gmhist-repeat-complex-command (arg) ; C-x ESC
+  ;; This function from Mike Williams <Mike.Williams@comp.vuw.ac.nz>
+  "Edit and re-evaluate last complex command, or ARGth from last.
+A complex command is one which used the minibuffer.
+The command is placed in the minibuffer as a Lisp form for editing.
+The result is executed, repeating the command as changed.
+If the command has been changed or is not the most recent previous command
+it is added to the front of the command history."
+  (interactive "p")
+  (let ((print-escape-newlines t))
+    (put 'command-history 'backup arg)
+    (put 'command-history 'cursor-end t)
+    (eval (read-with-history-in 'command-history "Redo: " nil 'lisp))
+    (put 'command-history 'backup nil)))
+
+;; TODO:
+;; read-minibuffer
+;; eval-minibuffer
+;; read-no-blanks-input
+;; read-command
+;; read-variable