diff options
| author | Miles Bader | 2001-10-05 13:29:25 +0000 |
|---|---|---|
| committer | Miles Bader | 2001-10-05 13:29:25 +0000 |
| commit | 519f7ff698b11dfe050aa9f7d844c47acac1e1f6 (patch) | |
| tree | 45e65396f219239950592289ea44002f7a8a364c | |
| parent | c165ad4044ba73d15aa77db7ce418d281a6f0236 (diff) | |
| download | emacs-519f7ff698b11dfe050aa9f7d844c47acac1e1f6.tar.gz emacs-519f7ff698b11dfe050aa9f7d844c47acac1e1f6.zip | |
Initial checkin.
| -rw-r--r-- | lisp/rfn-eshadow.el | 226 |
1 files changed, 226 insertions, 0 deletions
diff --git a/lisp/rfn-eshadow.el b/lisp/rfn-eshadow.el new file mode 100644 index 00000000000..a0effdd7064 --- /dev/null +++ b/lisp/rfn-eshadow.el | |||
| @@ -0,0 +1,226 @@ | |||
| 1 | ;;; rfn-eshadow.el --- Highlight `shadowed' part of read-file-name input text | ||
| 2 | ;; | ||
| 3 | ;; Copyright (C) 2000, 2001 Free Software Foundation, Inc. | ||
| 4 | ;; | ||
| 5 | ;; Author: Miles Bader <miles@gnu.org> | ||
| 6 | ;; Keywords: convenience | ||
| 7 | |||
| 8 | ;; This file is part of GNU Emacs. | ||
| 9 | |||
| 10 | ;; GNU Emacs is free software; you can redistribute it and/or modify | ||
| 11 | ;; it under the terms of the GNU General Public License as published by | ||
| 12 | ;; the Free Software Foundation; either version 2, or (at your option) | ||
| 13 | ;; any later version. | ||
| 14 | |||
| 15 | ;; GNU Emacs is distributed in the hope that it will be useful, | ||
| 16 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 17 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 18 | ;; GNU General Public License for more details. | ||
| 19 | |||
| 20 | ;; You should have received a copy of the GNU General Public License | ||
| 21 | ;; along with GNU Emacs; see the file COPYING. If not, write to the | ||
| 22 | ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
| 23 | ;; Boston, MA 02111-1307, USA. | ||
| 24 | |||
| 25 | ;;; Commentary: | ||
| 26 | ;; | ||
| 27 | ;; Defines the mode `read-file-name-electric-shadow-mode'. | ||
| 28 | ;; | ||
| 29 | ;; The `read-file-name' function passes its result through | ||
| 30 | ;; `substitute-in-file-name', so any part of the string preceding | ||
| 31 | ;; multiple slashes (or a drive indicator on MS-DOS/MS-Windows) is | ||
| 32 | ;; ignored. | ||
| 33 | ;; | ||
| 34 | ;; If `read-file-name-electric-shadow-mode' is active, any part of the | ||
| 35 | ;; minibuffer text that would be ignored because of this is given the | ||
| 36 | ;; properties in `read-file-name-electric-shadow-properties', which may | ||
| 37 | ;; be used to make the ignored text invisible, dim, etc. | ||
| 38 | ;; | ||
| 39 | |||
| 40 | ;;; Code: | ||
| 41 | |||
| 42 | |||
| 43 | ;;; Customization | ||
| 44 | |||
| 45 | (defconst read-file-name-electric-shadow-properties-custom-type | ||
| 46 | '(list | ||
| 47 | (checklist :inline t | ||
| 48 | (const :tag "Invisible" | ||
| 49 | :doc "Make shadowed part of filename invisible" | ||
| 50 | :format "%t%n%h" | ||
| 51 | :inline t | ||
| 52 | (invisible t intangible t)) | ||
| 53 | (list :inline t | ||
| 54 | :format "%v" | ||
| 55 | :tag "Face" | ||
| 56 | :doc "Display shadowed part of filename using a different face" | ||
| 57 | (const :format "" face) | ||
| 58 | (face :value read-file-name-electric-shadow)) | ||
| 59 | (list :inline t | ||
| 60 | :format "%t: %v%h" | ||
| 61 | :tag "Brackets" | ||
| 62 | ;; Note the 4 leading spaces in the doc string; | ||
| 63 | ;; this is hack to get around the fact that the | ||
| 64 | ;; newline after the second string widget comes | ||
| 65 | ;; from the string widget, and doesn't indent | ||
| 66 | ;; correctly. We could use a :size attribute to | ||
| 67 | ;; make the second string widget not have a | ||
| 68 | ;; terminating newline, but this makes it impossible | ||
| 69 | ;; to enter trailing whitespace, and it's desirable | ||
| 70 | ;; that it be possible. | ||
| 71 | :doc " Surround shadowed part of filename with brackets" | ||
| 72 | (const :format "" before-string) | ||
| 73 | (string :format "%v" :size 4 :value "{") | ||
| 74 | (const :format "" after-string) | ||
| 75 | ;; see above about why the 2nd string doesn't use :size | ||
| 76 | (string :format " and: %v" :value "} ")) | ||
| 77 | (list :inline t | ||
| 78 | :format "%t: %v%n%h" | ||
| 79 | :tag "String" | ||
| 80 | :doc "Display a string instead of the shadowed part of filename" | ||
| 81 | (const :format "" display) | ||
| 82 | (string :format "%v" :size 15 :value "<...ignored...>")) | ||
| 83 | (const :tag "Avoid" | ||
| 84 | :doc "Try to keep cursor out of shadowed part of filename" | ||
| 85 | :format "%t%n%h" | ||
| 86 | :inline t | ||
| 87 | (field shadow))) | ||
| 88 | (repeat :inline t | ||
| 89 | :tag "Other Properties" | ||
| 90 | (list :inline t | ||
| 91 | :format "%v" | ||
| 92 | (symbol :tag "Property") | ||
| 93 | (sexp :tag "Value"))))) | ||
| 94 | |||
| 95 | (defcustom read-file-name-electric-shadow-properties | ||
| 96 | '(face read-file-name-electric-shadow field shadow) | ||
| 97 | "Properties given to the `shadowed' part of a filename in the minibuffer. | ||
| 98 | Only used when `read-file-name-electric-shadow-mode' is active. | ||
| 99 | If emacs is not running under a window system, | ||
| 100 | `read-file-name-electric-shadow-tty-properties' is used instead." | ||
| 101 | :type read-file-name-electric-shadow-properties-custom-type | ||
| 102 | :group 'minibuffer) | ||
| 103 | |||
| 104 | (defcustom read-file-name-electric-shadow-tty-properties | ||
| 105 | '(before-string "{" after-string "} " field shadow) | ||
| 106 | "Properties given to the `shadowed' part of a filename in the minibuffer. | ||
| 107 | Only used when `read-file-name-electric-shadow-mode' is active and emacs | ||
| 108 | is not running under a window-system; if emacs is running under a window | ||
| 109 | system, `read-file-name-electric-shadow-properties' is used instead." | ||
| 110 | :type read-file-name-electric-shadow-properties-custom-type | ||
| 111 | :group 'minibuffer) | ||
| 112 | |||
| 113 | (defface read-file-name-electric-shadow | ||
| 114 | '((((background dark)) | ||
| 115 | :foreground "grey50") | ||
| 116 | (t | ||
| 117 | :foreground "grey70")) | ||
| 118 | "Face used by `read-file-name-electric-shadow-mode' for the shadow." | ||
| 119 | :group 'minibuffer) | ||
| 120 | |||
| 121 | |||
| 122 | ;;; Internal variables | ||
| 123 | |||
| 124 | ;; Regexp to locate dividing point between shadow and real pathname | ||
| 125 | (defconst rfn-eshadow-regexp | ||
| 126 | (cond ((memq system-type '(ms-dos windows-nt)) | ||
| 127 | ;; This horrible regexp considers the following patterns as | ||
| 128 | ;; starting an absolute pathname, when following a `/' or an `\': | ||
| 129 | ;; L: / // ~ $ \\ \\\\ | ||
| 130 | "\\(.*[^/]+/+?\\|/*?\\|\\)\\([$~]\\|[][\\^a-z]:\\|//?\\([^][\\^a-z/$~]\\|[^/$~][^:]\\|[^/$~]?\\'\\)\\)") | ||
| 131 | (t | ||
| 132 | ;; default is for unix-style filenames | ||
| 133 | "\\(.*/\\)[/$~]")) | ||
| 134 | "Regular expression used to match shadowed filenames. | ||
| 135 | There should be at least one regexp group; the end of the first one | ||
| 136 | is used as the end of the shadowed portion of the filename.") | ||
| 137 | |||
| 138 | ;; A list of minibuffers to which we've added a post-command-hook. | ||
| 139 | (defvar rfn-eshadow-frobbed-minibufs nil) | ||
| 140 | |||
| 141 | ;; An overlay covering the shadowed part of the filename (local to the | ||
| 142 | ;; minibuffer). | ||
| 143 | (defvar rfn-eshadow-overlay) | ||
| 144 | (make-variable-buffer-local 'rfn-eshadow-overlay) | ||
| 145 | |||
| 146 | |||
| 147 | ;;; Hook functions | ||
| 148 | |||
| 149 | ;; This function goes on minibuffer-setup-hook | ||
| 150 | (defun rfn-eshadow-setup-minibuffer () | ||
| 151 | "Set up a minibuffer for `read-file-name-electric-shadow-mode'. | ||
| 152 | The prompt and initial input should already have been inserted." | ||
| 153 | (when minibuffer-completing-file-name | ||
| 154 | (setq rfn-eshadow-overlay | ||
| 155 | (make-overlay (minibuffer-prompt-end) (minibuffer-prompt-end))) | ||
| 156 | ;; Give rfn-eshadow-overlay the user's props. | ||
| 157 | (let ((props | ||
| 158 | (if window-system | ||
| 159 | read-file-name-electric-shadow-properties | ||
| 160 | read-file-name-electric-shadow-tty-properties))) | ||
| 161 | (while props | ||
| 162 | (overlay-put rfn-eshadow-overlay (pop props) (pop props)))) | ||
| 163 | ;; Turn on overlay evaporation so that we don't have to worry about | ||
| 164 | ;; odd effects when the overlay sits empty at the beginning of the | ||
| 165 | ;; minibuffer. | ||
| 166 | (overlay-put rfn-eshadow-overlay 'evaporate t) | ||
| 167 | ;; Add our post-command hook, and make sure can remove it later. | ||
| 168 | (add-to-list 'rfn-eshadow-frobbed-minibufs (current-buffer)) | ||
| 169 | (add-hook 'post-command-hook #'rfn-eshadow-update-overlay nil t))) | ||
| 170 | |||
| 171 | ;; post-command-hook to update overlay | ||
| 172 | (defun rfn-eshadow-update-overlay () | ||
| 173 | "Update `rfn-eshadow-overlay' to cover shadowed part of minibuffer input. | ||
| 174 | This is intended to be used as a minibuffer post-command-hook for | ||
| 175 | `read-file-name-electric-shadow-mode'; the minibuffer should have already | ||
| 176 | been set up by `rfn-eshadow-setup-minibuffer'." | ||
| 177 | ;; This is not really a correct implementation; it won't always do the | ||
| 178 | ;; right thing in the presence of environment variables that | ||
| 179 | ;; substitute-in-file-name would expand; currently it just assumes any | ||
| 180 | ;; environment variable contains an absolute filename. It doesn't | ||
| 181 | ;; handle MS-DOS-type drive specs like substitute-in-file-name does. | ||
| 182 | (save-excursion | ||
| 183 | ;; Note that this should use `minibuffer-prompt-end' instead of | ||
| 184 | ;; `field-end', but for now we use the latter so that it works | ||
| 185 | ;; properly with old definitions of minibuffer-prompt-end. | ||
| 186 | (goto-char (field-end (point-min))) | ||
| 187 | ;; Update the overlay (which will evaporate if it's empty). | ||
| 188 | (move-overlay rfn-eshadow-overlay | ||
| 189 | (point) | ||
| 190 | (if (looking-at rfn-eshadow-regexp) | ||
| 191 | (match-end 1) | ||
| 192 | (point))))) | ||
| 193 | |||
| 194 | |||
| 195 | ;;; Note this definition must be at the end of the file, because | ||
| 196 | ;;; `define-minor-mode' actually calls the mode-function if the | ||
| 197 | ;;; associated variable is non-nil, which requires that all needed | ||
| 198 | ;;; functions be already defined. [This is arguably a bug in d-m-m] | ||
| 199 | ;;;###autoload | ||
| 200 | (define-minor-mode read-file-name-electric-shadow-mode | ||
| 201 | "Toggle Read-File-Name Electric Shadow mode | ||
| 202 | When active, any part of the a filename being read in the minibuffer | ||
| 203 | that would be ignored because the result is passed through | ||
| 204 | `substitute-in-file-name' is given the properties in | ||
| 205 | `read-file-name-electric-shadow-properties', which can be used to make | ||
| 206 | that portion dim, invisible, or otherwise less visually noticable. | ||
| 207 | |||
| 208 | With prefix argument ARG, turn on if positive, otherwise off. | ||
| 209 | Returns non-nil if the new state is enabled." | ||
| 210 | :global t | ||
| 211 | :group 'minibuffer | ||
| 212 | (if read-file-name-electric-shadow-mode | ||
| 213 | ;; Enable the mode | ||
| 214 | (add-hook 'minibuffer-setup-hook 'rfn-eshadow-setup-minibuffer) | ||
| 215 | ;; Disable the mode | ||
| 216 | (remove-hook 'minibuffer-setup-hook 'rfn-eshadow-setup-minibuffer) | ||
| 217 | ;; Remove our entry from any post-command-hook variable's it's still in | ||
| 218 | (dolist (minibuf rfn-eshadow-frobbed-minibufs) | ||
| 219 | (with-current-buffer minibuf | ||
| 220 | (remove-hook 'post-command-hook #'rfn-eshadow-update-overlay t))) | ||
| 221 | (setq rfn-eshadow-frobbed-minibufs nil))) | ||
| 222 | |||
| 223 | |||
| 224 | (provide 'rfn-eshadow) | ||
| 225 | |||
| 226 | ;;; rfn-eshadow.el ends here | ||