Revisión | b68a84da62e37509a68950a416f4b06ed6a1afe2 (tree) |
---|---|
Tiempo | 2008-06-04 08:59:42 |
Autor | iselllo |
Commiter | iselllo |
I added the file shell-command.el which I need to have autocompletion in a BASG open under emacs.
@@ -0,0 +1,405 @@ | ||
1 | +;;; shell-command.el --- enables tab-completion for `shell-command' | |
2 | + | |
3 | +;; Copyright (C) 1998-2007 TSUCHIYA Masatoshi <tsuchiya@namazu.org> | |
4 | + | |
5 | +;; Author: TSUCHIYA Masatoshi <tsuchiya@namazu.org> | |
6 | +;; Keywords: shell | |
7 | +;; Version: $Revision: 1.38 $ | |
8 | + | |
9 | +;; This program is free software; you can redistribute it and/or modify | |
10 | +;; it under the terms of the GNU General Public License as published by | |
11 | +;; the Free Software Foundation; either version 2, or (at your option) | |
12 | +;; any later version. | |
13 | + | |
14 | +;; This program is distributed in the hope that it will be useful, | |
15 | +;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | +;; GNU General Public License for more details. | |
18 | + | |
19 | +;; You should have received a copy of the GNU General Public License | |
20 | +;; along with this program; if not, you can either send email to this | |
21 | +;; program's maintainer or write to: The Free Software Foundation, | |
22 | +;; Inc.; 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
23 | + | |
24 | +;;; Commentary: | |
25 | + | |
26 | +;; This is an enhancement of shell-command, shell-command-on-region, | |
27 | +;; grep, grep-find, and compile, that enables tab-completion of | |
28 | +;; commands and dir/filenames within their input contexts. | |
29 | + | |
30 | +;; The latest version of this program can be downloaded from | |
31 | +;; http://namazu.org/~tsuchiya/elisp/shell-command.el. | |
32 | + | |
33 | +;;; Install: | |
34 | + | |
35 | +;; Install this file to appropriate directory, and put these lines | |
36 | +;; into your ~/.emacs. | |
37 | + | |
38 | +;; (require 'shell-command) | |
39 | +;; (shell-command-completion-mode) | |
40 | + | |
41 | +;;; Code: | |
42 | +(eval-when-compile | |
43 | + (require 'shell) | |
44 | + (require 'comint)) | |
45 | + | |
46 | +(eval-and-compile | |
47 | + ;; Stuffs to keep compatibility between Emacsen. | |
48 | + (if (locate-library "custom") | |
49 | + (require 'custom) | |
50 | + (or (fboundp 'defgroup) | |
51 | + (defmacro defgroup (symbol members doc &rest args) nil)) | |
52 | + (or (fboundp 'defcustom) | |
53 | + (defmacro defcustom (symbol value doc &rest args) | |
54 | + (list 'defvar symbol value doc)))) | |
55 | + ;; These macros, such as `when' and `unless' are imported from | |
56 | + ;; subr.el of Emacs-21.2. | |
57 | + (or (fboundp 'when) | |
58 | + (progn | |
59 | + (defmacro when (cond &rest body) | |
60 | + "If COND yields non-nil, do BODY, else return nil." | |
61 | + (list 'if cond (cons 'progn body))) | |
62 | + (put 'when 'edebug-form-spec '(form body)) | |
63 | + (put 'when 'lisp-indent-function 1))) | |
64 | + (or (fboundp 'unless) | |
65 | + (progn | |
66 | + (defmacro unless (cond &rest body) | |
67 | + "If COND yields nil, do BODY, else return nil." | |
68 | + (cons 'if (cons cond (cons nil body)))) | |
69 | + (put 'unless 'edebug-form-spec '(form body)) | |
70 | + (put 'unless 'lisp-indent-function 1)))) | |
71 | + | |
72 | +(defgroup shell-command nil | |
73 | + "Enable Tab completions for `shell-command' and related commands." | |
74 | + :group 'shell) | |
75 | + | |
76 | +(defcustom shell-command-complete-functions | |
77 | + '(shell-dynamic-complete-environment-variable | |
78 | + shell-dynamic-complete-command | |
79 | + shell-replace-by-expanded-directory | |
80 | + comint-dynamic-complete-filename) | |
81 | + "*Function list to complete shell commands." | |
82 | + :type '(repeat function) | |
83 | + :group 'shell-command) | |
84 | + | |
85 | +(defcustom shell-command-prompt | |
86 | + "Shell command [%w]%$ " | |
87 | + "*The prompt string for `shell-command' when tab-completion is enabled. | |
88 | +Some %-sequences are available to customize this variable. For more | |
89 | +detail, see the document of `shell-command-make-prompt-string'." | |
90 | + :type 'string | |
91 | + :group 'shell-command) | |
92 | + | |
93 | +(defcustom shell-command-on-region-prompt | |
94 | + "Shell command on region [%w]%$ " | |
95 | + "*Prompt string of `shell-command-on-region' when tab-completion is enabled. | |
96 | +Some %-sequences are available to customize this variable. For more | |
97 | +detail, see the document of `shell-command-make-prompt-string'." | |
98 | + :type 'string | |
99 | + :group 'shell-command) | |
100 | + | |
101 | +(defcustom shell-command-on-region-prompt-if-region-inactive | |
102 | + "Shell command on buffer [%w]%$ " | |
103 | + "*Prompt string of `shell-command-on-region' when tab-completion is enabled. | |
104 | +This string is used if `shell-command-on-region' is called when | |
105 | +there is no active region. | |
106 | +Some %-sequences are available to customize this variable. For more | |
107 | +detail, see the document of `shell-command-make-prompt-string'." | |
108 | + :type 'string | |
109 | + :group 'shell-command) | |
110 | + | |
111 | +(defcustom grep-prompt | |
112 | + "Run grep [%w]%$ " | |
113 | + "*Prompt string of `grep' when tab-completion is enabled. | |
114 | +Some %-sequences are available to customize this variable. For more | |
115 | +detail, see the document of `shell-command-make-prompt-string'." | |
116 | + :type 'string | |
117 | + :group 'shell-command) | |
118 | + | |
119 | +(defcustom grep-find-prompt | |
120 | + "Run find [%w]%$ " | |
121 | + "*Prompt string of `grep-find' when tab-completion is enabled. | |
122 | +Some %-sequences are available to customize this variable. For more | |
123 | +detail, see the document of `shell-command-make-prompt-string'." | |
124 | + :type 'string | |
125 | + :group 'shell-command) | |
126 | + | |
127 | +(defcustom compile-prompt | |
128 | + "Compile command [%w]%$ " | |
129 | + "*Prompt string of `compile' when tab-completion is enabled. | |
130 | +Some %-sequences are available to customize this variable. For more | |
131 | +detail, see the document of `shell-command-make-prompt-string'." | |
132 | + :type 'string | |
133 | + :group 'shell-command) | |
134 | + | |
135 | +(put 'shell-command/static-if 'lisp-indent-function 2) | |
136 | +(defmacro shell-command/static-if (cond then &rest else) | |
137 | + (if (eval cond) then (cons 'progn else))) | |
138 | + | |
139 | +(defun shell-command-make-prompt-string (format-string current-directory) "\ | |
140 | +Function to generate prompt string | |
141 | + | |
142 | +Use FORMAT-STRING to generate prompt string at the directory | |
143 | +CURRENT-DIRECTORY. The following `%' escapes are available for use in | |
144 | +FORMAT-STRING: | |
145 | + | |
146 | +%d the date in \"Weekday Month Date\" format \(e.g., \"Tue May 26\"\) | |
147 | +%h the hostname up to the first `.' | |
148 | +%H the hostname | |
149 | +%t the current time in 24-hour HH:MM:SS format | |
150 | +%T the current time in 12-hour HH:MM:SS format | |
151 | +%@ the current time in 12-hour am/pm format | |
152 | +%u the username of the current user | |
153 | +%w the current working directory | |
154 | +%W the basename of the current working directory | |
155 | +%$ if the effective UID is 0, a #, otherwise a $ | |
156 | +%% Insert a literal `%'. | |
157 | +" | |
158 | + (let ((case-fold-search nil) | |
159 | + start buf | |
160 | + (list (list format-string)) | |
161 | + (alist (let ((system-name (system-name)) | |
162 | + host-name | |
163 | + fqdn-name | |
164 | + (time (current-time)) | |
165 | + (dir (directory-file-name | |
166 | + (abbreviate-file-name current-directory)))) | |
167 | + (shell-command/static-if (featurep 'xemacs) | |
168 | + (cond | |
169 | + ((string= dir (user-home-directory)) | |
170 | + (setq dir "~")) | |
171 | + ((string-match (concat "^" | |
172 | + (regexp-quote | |
173 | + (file-name-as-directory | |
174 | + (user-home-directory)))) | |
175 | + dir) | |
176 | + (setq dir | |
177 | + (concat "~/" (substring dir (match-end 0))))))) | |
178 | + (if (string-match "^\\([^.]+\\)\\.[^.]" system-name) | |
179 | + (setq fqdn-name system-name | |
180 | + host-name (match-string 1 system-name)) | |
181 | + (setq host-name system-name | |
182 | + fqdn-name | |
183 | + (cond | |
184 | + ((and (boundp 'mail-host-address) | |
185 | + (stringp mail-host-address) | |
186 | + (string-match "\\." mail-host-address)) | |
187 | + mail-host-address) | |
188 | + ((and user-mail-address | |
189 | + (string-match "\\." user-mail-address) | |
190 | + (string-match "@\\(.*\\)\\'" | |
191 | + user-mail-address)) | |
192 | + (match-string 1 user-mail-address)) | |
193 | + (t system-name)))) | |
194 | + `(("%%" . "%") | |
195 | + ("%d" . ,(format-time-string "%a %b %e" time)) | |
196 | + ("%h" . ,host-name) | |
197 | + ("%H" . ,fqdn-name) | |
198 | + ("%t" . ,(format-time-string "%H:%M:%S" time)) | |
199 | + ("%T" . ,(format-time-string "%I:%M:%S" time)) | |
200 | + ("%@" . ,(format-time-string "%I:%M%p" time)) | |
201 | + ("%u" . ,(user-login-name)) | |
202 | + ("%w" . ,dir) | |
203 | + ("%W" . ,(file-name-nondirectory | |
204 | + (directory-file-name current-directory))) | |
205 | + ("%\\$" . ,(if (= (user-uid) 0) "#" "$")))))) | |
206 | + (while alist | |
207 | + (setq buf nil) | |
208 | + (while list | |
209 | + (setq start 0) | |
210 | + (while (string-match (car (car alist)) (car list) start) | |
211 | + (setq buf (cons (cdr (car alist)) | |
212 | + (cons (substring (car list) start | |
213 | + (match-beginning 0)) | |
214 | + buf)) | |
215 | + start (match-end 0))) | |
216 | + (setq buf (cons (substring (car list) start) buf) | |
217 | + list (cdr list))) | |
218 | + (setq list (nreverse buf) | |
219 | + alist (cdr alist))) | |
220 | + (apply 'concat list))) | |
221 | + | |
222 | +(defmacro shell-command/minibuffer-prompt-end () | |
223 | + (if (fboundp 'minibuffer-prompt-end) | |
224 | + '(minibuffer-prompt-end) | |
225 | + '(point-min))) | |
226 | + | |
227 | +(defun shell-command-read-minibuffer | |
228 | + (format-string current-directory &optional initial-contents | |
229 | + user-keymap read hist) | |
230 | + "Read a command string in the minibuffer, with completion." | |
231 | + (let ((keymap (make-sparse-keymap)) | |
232 | + (prompt (shell-command-make-prompt-string | |
233 | + format-string current-directory))) | |
234 | + (set-keymap-parent keymap (or user-keymap minibuffer-local-map)) | |
235 | + (define-key keymap "\t" | |
236 | + (lambda () | |
237 | + (interactive) | |
238 | + (let ((orig-function (symbol-function 'message))) | |
239 | + (unwind-protect | |
240 | + (progn | |
241 | + (defun message (string &rest arguments) | |
242 | + (let* ((s1 (concat prompt | |
243 | + (buffer-substring | |
244 | + (shell-command/minibuffer-prompt-end) | |
245 | + (point-max)))) | |
246 | + (s2 (apply (function format) string arguments)) | |
247 | + (w (- (window-width) | |
248 | + (string-width s1) | |
249 | + (string-width s2) | |
250 | + 1))) | |
251 | + (funcall orig-function | |
252 | + (if (>= w 0) | |
253 | + (concat s1 (make-string w ?\ ) s2) | |
254 | + s2)) | |
255 | + (if (sit-for 0.3) (funcall orig-function s1)) | |
256 | + s2)) | |
257 | + (require 'shell) | |
258 | + (require 'comint) | |
259 | + (run-hook-with-args-until-success | |
260 | + 'shell-command-complete-functions)) | |
261 | + (fset 'message orig-function))))) | |
262 | + (read-from-minibuffer prompt initial-contents keymap read hist))) | |
263 | + | |
264 | +;; This local bind of `current-load-list' is requred to keep the | |
265 | +;; position where real `shell-command' is defined. If this local bind | |
266 | +;; is removed, `find-function' will tell that `shell-command' is | |
267 | +;; defined in shell-command.el instaed of simple.el. | |
268 | +(let (current-load-list) | |
269 | + (defadvice shell-command | |
270 | + (before shell-command-with-completion disable compile) | |
271 | + "Defined in shell-command.el, to enable tab-completion of commands | |
272 | +and dir/filenames within the input context. Its prompt string is kept | |
273 | +by `shell-command-prompt'." | |
274 | + (interactive | |
275 | + (list | |
276 | + (shell-command-read-minibuffer shell-command-prompt | |
277 | + default-directory | |
278 | + nil nil nil 'shell-command-history) | |
279 | + current-prefix-arg)))) | |
280 | + | |
281 | +(let (current-load-list) | |
282 | + (defadvice shell-command-on-region | |
283 | + (before shell-command-on-region-with-completion disable compile) | |
284 | + "Defined in shell-command.el, to enable tab-completion of commands | |
285 | +and dir/filenames within the input context. This advice also makes | |
286 | +`shell-command-on-region' to use this current buffer as its input when | |
287 | +a region is visible and inactive. | |
288 | +Its prompt string is kept by `shell-command-on-region-prompt' and | |
289 | +`shell-command-on-region-prompt-if-region-inactive'." | |
290 | + (interactive | |
291 | + (let (beg end prompt) | |
292 | + (if (shell-command/static-if (featurep 'xemacs) | |
293 | + (and zmacs-regions (not (region-active-p))) | |
294 | + (and transient-mark-mode (not mark-active))) | |
295 | + (setq beg (point-min) | |
296 | + end (point-max) | |
297 | + prompt shell-command-on-region-prompt-if-region-inactive) | |
298 | + (unless (mark) | |
299 | + (error "The mark is not set now, so there is no region")) | |
300 | + (setq beg (region-beginning) | |
301 | + end (region-end) | |
302 | + prompt shell-command-on-region-prompt)) | |
303 | + (list beg end | |
304 | + (shell-command-read-minibuffer prompt default-directory | |
305 | + nil nil nil 'shell-command-history) | |
306 | + current-prefix-arg | |
307 | + current-prefix-arg | |
308 | + shell-command-default-error-buffer))))) | |
309 | + | |
310 | +(let (current-load-list) | |
311 | + (defadvice grep | |
312 | + (before grep-with-completion disable compile) | |
313 | + "Defined in shell-command.el, to enable tab-completion of commands | |
314 | +and dir/filenames within the input context. Its prompt string is kept | |
315 | +by `grep-prompt'." | |
316 | + (interactive | |
317 | + (let (grep-default (arg current-prefix-arg)) | |
318 | + (unless grep-command | |
319 | + (grep-compute-defaults)) | |
320 | + (when arg | |
321 | + (let* ((tag-default | |
322 | + (funcall (or find-tag-default-function | |
323 | + (get major-mode 'find-tag-default-function) | |
324 | + 'grep-tag-default)))) | |
325 | + (setq grep-default (or (car grep-history) grep-command)) | |
326 | + (when (string-match | |
327 | + "[^ ]+\\s +\\(-[^ ]+\\s +\\)*\\(\"[^\"]+\"\\|[^ ]+\\)" | |
328 | + grep-default) | |
329 | + (setq grep-default | |
330 | + (replace-match tag-default t t grep-default 2))))) | |
331 | + (list (shell-command-read-minibuffer grep-prompt | |
332 | + default-directory | |
333 | + (or grep-default grep-command) | |
334 | + nil nil 'grep-history)))))) | |
335 | + | |
336 | +(let (current-load-list) | |
337 | + (defadvice grep-find | |
338 | + (before grep-find-with-completion disable compile) | |
339 | + "Defined in shell-command.el, to enable tab-completion of commands | |
340 | +and dir/filenames within the input context. Its prompt string is kept | |
341 | +by `grep-find-prompt'." | |
342 | + (interactive | |
343 | + (progn | |
344 | + (unless grep-find-command | |
345 | + (grep-compute-defaults)) | |
346 | + (list (shell-command-read-minibuffer grep-find-prompt | |
347 | + default-directory | |
348 | + grep-find-command | |
349 | + nil nil 'grep-find-history)))))) | |
350 | + | |
351 | +(let (current-load-list) | |
352 | + (defadvice compile | |
353 | + (before compile-with-completion disable compile) | |
354 | + "Defined in shell-command.el, to enable tab-completion of commands | |
355 | +and dir/filenames within the input context. Its prompt string is kept | |
356 | +by `compile-prompt'." | |
357 | + (interactive | |
358 | + (if (or compilation-read-command current-prefix-arg) | |
359 | + (list (shell-command-read-minibuffer compile-prompt | |
360 | + default-directory | |
361 | + (eval compile-command) nil nil | |
362 | + '(compile-history . 1))) | |
363 | + (list (eval compile-command)))))) | |
364 | + | |
365 | +(defun shell-command-custom-set (symbol value) | |
366 | + "Set SYMBOL's value to VALUE, and enable or disable tab-completion | |
367 | +for following commands: `shell-command', `shell-command-on-region', | |
368 | +`grep', `grep-find' and `compile'." | |
369 | + (let ((commands | |
370 | + '(shell-command shell-command-on-region grep grep-find compile))) | |
371 | + (while commands | |
372 | + (funcall (if value 'ad-enable-advice 'ad-disable-advice) | |
373 | + (car commands) | |
374 | + 'before | |
375 | + (intern (concat (symbol-name (car commands)) | |
376 | + "-with-completion"))) | |
377 | + (ad-activate (car commands)) | |
378 | + (setq commands (cdr commands)))) | |
379 | + (set-default symbol value)) | |
380 | + | |
381 | +(defcustom shell-command-completion-mode nil | |
382 | + "*Non-nil means that tab-completion for some commands is enabled. | |
383 | +The commands are `shell-command', `shell-command-on-region', `grep', | |
384 | +`grep-find' and `compile'." | |
385 | + :type 'boolean | |
386 | + :set 'shell-command-custom-set | |
387 | + :group 'shell-command) | |
388 | + | |
389 | +;;;###autoload | |
390 | +(defun shell-command-completion-mode (&optional arg) | |
391 | + "Enable or disable tab-completion for some commands. | |
392 | +The commands are `shell-command', `shell-command-on-region', `grep', | |
393 | +`grep-find' and `compile'." | |
394 | + (interactive "P") | |
395 | + (prog1 (shell-command-custom-set 'shell-command-completion-mode | |
396 | + (if arg | |
397 | + (> (prefix-numeric-value arg) 0) | |
398 | + (not shell-command-completion-mode))) | |
399 | + (when (interactive-p) | |
400 | + (message "Tab-completion is %s" | |
401 | + (if shell-command-completion-mode "enabled" "disabled"))))) | |
402 | + | |
403 | +(provide 'shell-command) | |
404 | + | |
405 | +;;; shell-command.el ends here |