Sync to HEAD
[bpt/emacs.git] / lisp / rfn-eshadow.el
CommitLineData
519f7ff6
MB
1;;; rfn-eshadow.el --- Highlight `shadowed' part of read-file-name input text
2;;
17230c90 3;; Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
519f7ff6
MB
4;;
5;; Author: Miles Bader <miles@gnu.org>
476cf013 6;; Keywords: convenience minibuffer
519f7ff6
MB
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;;
476cf013 27;; Defines the mode `file-name-shadow-mode'.
519f7ff6
MB
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;;
476cf013 34;; If `file-name-shadow-mode' is active, any part of the
519f7ff6 35;; minibuffer text that would be ignored because of this is given the
476cf013 36;; properties in `file-name-shadow-properties', which may
519f7ff6
MB
37;; be used to make the ignored text invisible, dim, etc.
38;;
39
40;;; Code:
41
42\f
43;;; Customization
44
476cf013 45(defconst file-name-shadow-properties-custom-type
519f7ff6
MB
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)
476cf013 58 (face :value file-name-shadow))
519f7ff6
MB
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
18a90ec7 95;;;###autoload
476cf013
MB
96(defcustom file-name-shadow-properties
97 '(face file-name-shadow field shadow)
519f7ff6 98 "Properties given to the `shadowed' part of a filename in the minibuffer.
476cf013 99Only used when `file-name-shadow-mode' is active.
519f7ff6 100If emacs is not running under a window system,
476cf013
MB
101`file-name-shadow-tty-properties' is used instead."
102 :type file-name-shadow-properties-custom-type
519f7ff6
MB
103 :group 'minibuffer)
104
18a90ec7 105;;;###autoload
476cf013 106(defcustom file-name-shadow-tty-properties
519f7ff6
MB
107 '(before-string "{" after-string "} " field shadow)
108 "Properties given to the `shadowed' part of a filename in the minibuffer.
476cf013 109Only used when `file-name-shadow-mode' is active and emacs
519f7ff6 110is not running under a window-system; if emacs is running under a window
476cf013
MB
111system, `file-name-shadow-properties' is used instead."
112 :type file-name-shadow-properties-custom-type
519f7ff6
MB
113 :group 'minibuffer)
114
476cf013 115(defface file-name-shadow
519f7ff6
MB
116 '((((background dark))
117 :foreground "grey50")
118 (t
119 :foreground "grey70"))
476cf013 120 "Face used by `file-name-shadow-mode' for the shadow."
519f7ff6
MB
121 :group 'minibuffer)
122
123\f
124;;; Internal variables
125
126;; Regexp to locate dividing point between shadow and real pathname
127(defconst rfn-eshadow-regexp
128 (cond ((memq system-type '(ms-dos windows-nt))
129 ;; This horrible regexp considers the following patterns as
130 ;; starting an absolute pathname, when following a `/' or an `\':
131 ;; L: / // ~ $ \\ \\\\
f4be0a12 132 "\\(.*[^/]+/+?\\|/*?\\|\\)\\(~\\|$[^$]\\|$\\'\\|[][\\^a-z]:\\|//?\\([^][\\^a-z/$~]\\|[^/$~][^:]\\|[^/$~]?\\'\\)\\)")
519f7ff6
MB
133 (t
134 ;; default is for unix-style filenames
f4be0a12 135 "\\(.*/\\)\\([/~]\\|$[^$]\\|$\\'\\)"))
519f7ff6
MB
136 "Regular expression used to match shadowed filenames.
137There should be at least one regexp group; the end of the first one
138is used as the end of the shadowed portion of the filename.")
139
140;; A list of minibuffers to which we've added a post-command-hook.
141(defvar rfn-eshadow-frobbed-minibufs nil)
142
143;; An overlay covering the shadowed part of the filename (local to the
144;; minibuffer).
145(defvar rfn-eshadow-overlay)
146(make-variable-buffer-local 'rfn-eshadow-overlay)
147
148\f
149;;; Hook functions
150
151;; This function goes on minibuffer-setup-hook
152(defun rfn-eshadow-setup-minibuffer ()
476cf013 153 "Set up a minibuffer for `file-name-shadow-mode'.
519f7ff6
MB
154The prompt and initial input should already have been inserted."
155 (when minibuffer-completing-file-name
156 (setq rfn-eshadow-overlay
157 (make-overlay (minibuffer-prompt-end) (minibuffer-prompt-end)))
158 ;; Give rfn-eshadow-overlay the user's props.
159 (let ((props
160 (if window-system
476cf013
MB
161 file-name-shadow-properties
162 file-name-shadow-tty-properties)))
519f7ff6
MB
163 (while props
164 (overlay-put rfn-eshadow-overlay (pop props) (pop props))))
165 ;; Turn on overlay evaporation so that we don't have to worry about
166 ;; odd effects when the overlay sits empty at the beginning of the
167 ;; minibuffer.
168 (overlay-put rfn-eshadow-overlay 'evaporate t)
169 ;; Add our post-command hook, and make sure can remove it later.
170 (add-to-list 'rfn-eshadow-frobbed-minibufs (current-buffer))
171 (add-hook 'post-command-hook #'rfn-eshadow-update-overlay nil t)))
172
173;; post-command-hook to update overlay
174(defun rfn-eshadow-update-overlay ()
175 "Update `rfn-eshadow-overlay' to cover shadowed part of minibuffer input.
176This is intended to be used as a minibuffer post-command-hook for
476cf013 177`file-name-shadow-mode'; the minibuffer should have already
519f7ff6
MB
178been set up by `rfn-eshadow-setup-minibuffer'."
179 ;; This is not really a correct implementation; it won't always do the
180 ;; right thing in the presence of environment variables that
181 ;; substitute-in-file-name would expand; currently it just assumes any
a01b7831 182 ;; environment variable contains an absolute filename.
519f7ff6 183 (save-excursion
17230c90
MB
184 (let ((inhibit-point-motion-hooks t))
185 (goto-char (minibuffer-prompt-end))
186 ;; Update the overlay (which will evaporate if it's empty).
187 (move-overlay rfn-eshadow-overlay
188 (point)
189 (if (looking-at rfn-eshadow-regexp)
190 (match-end 1)
191 (point))))))
519f7ff6
MB
192
193\f
194;;; Note this definition must be at the end of the file, because
195;;; `define-minor-mode' actually calls the mode-function if the
196;;; associated variable is non-nil, which requires that all needed
197;;; functions be already defined. [This is arguably a bug in d-m-m]
198;;;###autoload
476cf013 199(define-minor-mode file-name-shadow-mode
1ced831d
MB
200 "Toggle File-Name Shadow mode.
201When active, any part of a filename being read in the minibuffer
202that would be ignored (because the result is passed through
203`substitute-in-file-name') is given the properties in
476cf013 204`file-name-shadow-properties', which can be used to make
b2c8e6ab 205that portion dim, invisible, or otherwise less visually noticeable.
519f7ff6
MB
206
207With prefix argument ARG, turn on if positive, otherwise off.
208Returns non-nil if the new state is enabled."
209 :global t
210 :group 'minibuffer
476cf013 211 (if file-name-shadow-mode
519f7ff6
MB
212 ;; Enable the mode
213 (add-hook 'minibuffer-setup-hook 'rfn-eshadow-setup-minibuffer)
214 ;; Disable the mode
215 (remove-hook 'minibuffer-setup-hook 'rfn-eshadow-setup-minibuffer)
216 ;; Remove our entry from any post-command-hook variable's it's still in
217 (dolist (minibuf rfn-eshadow-frobbed-minibufs)
218 (with-current-buffer minibuf
219 (remove-hook 'post-command-hook #'rfn-eshadow-update-overlay t)))
220 (setq rfn-eshadow-frobbed-minibufs nil)))
221
222
223(provide 'rfn-eshadow)
224
6b61353c 225;;; arch-tag: dcf70a52-0115-4ec2-b1e3-4f8d3541a888
519f7ff6 226;;; rfn-eshadow.el ends here