38414
|
1 ;;; esh-cmd.el --- command invocation
|
29873
|
2
|
64701
|
3 ;; Copyright (C) 1999, 2000, 2002, 2003, 2004,
|
68648
|
4 ;; 2005, 2006 Free Software Foundation, Inc.
|
29873
|
5
|
32526
|
6 ;; Author: John Wiegley <johnw@gnu.org>
|
|
7
|
29873
|
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
|
64085
|
22 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
23 ;; Boston, MA 02110-1301, USA.
|
29873
|
24
|
|
25 (provide 'esh-cmd)
|
|
26
|
|
27 (eval-when-compile (require 'esh-maint))
|
|
28
|
|
29 (defgroup eshell-cmd nil
|
|
30 "Executing an Eshell command is as simple as typing it in and
|
|
31 pressing <RET>. There are several different kinds of commands,
|
|
32 however."
|
|
33 :tag "Command invocation"
|
54568
|
34 ;; :link '(info-link "(eshell)Command invocation")
|
29873
|
35 :group 'eshell)
|
|
36
|
|
37 ;;; Commentary:
|
|
38
|
|
39 ;;;_* Invoking external commands
|
|
40 ;;
|
|
41 ;; External commands cause processes to be created, by loading
|
|
42 ;; external executables into memory. This is what most normal shells
|
|
43 ;; do, most of the time. For more information, see [External commands].
|
|
44 ;;
|
|
45 ;;;_* Invoking Lisp functions
|
|
46 ;;
|
|
47 ;; A Lisp function can be invoked using Lisp syntax, or command shell
|
|
48 ;; syntax. For example, to run `dired' to edit the current directory:
|
|
49 ;;
|
|
50 ;; /tmp $ (dired ".")
|
|
51 ;;
|
|
52 ;; Or:
|
|
53 ;;
|
|
54 ;; /tmp $ dired .
|
|
55 ;;
|
|
56 ;; The latter form is preferable, but the former is more precise,
|
|
57 ;; since it involves no translations. See [Argument parsing], to
|
|
58 ;; learn more about how arguments are transformed before passing them
|
|
59 ;; to commands.
|
|
60 ;;
|
|
61 ;; Ordinarily, if 'dired' were also available as an external command,
|
|
62 ;; the external version would be called in preference to any Lisp
|
|
63 ;; function of the same name. To change this behavior so that Lisp
|
|
64 ;; functions always take precedence, set
|
|
65 ;; `eshell-prefer-lisp-functions' to t.
|
|
66
|
|
67 (defcustom eshell-prefer-lisp-functions nil
|
|
68 "*If non-nil, prefer Lisp functions to external commands."
|
|
69 :type 'boolean
|
|
70 :group 'eshell-cmd)
|
|
71
|
|
72 ;;;_* Alias functions
|
|
73 ;;
|
|
74 ;; Whenever a command is specified using a simple name, such as 'ls',
|
|
75 ;; Eshell will first look for a Lisp function of the name `eshell/ls'.
|
|
76 ;; If it exists, it will be called in preference to any other command
|
|
77 ;; which might have matched the name 'ls' (such as command aliases,
|
|
78 ;; external commands, Lisp functions of that name, etc).
|
|
79 ;;
|
|
80 ;; This is the most flexible mechanism for creating new commands,
|
|
81 ;; since it does not pollute the global namespace, yet allows you to
|
|
82 ;; use all of Lisp's facilities to define that piece of functionality.
|
|
83 ;; Most of Eshell's "builtin" commands are defined as alias functions.
|
|
84 ;;
|
|
85 ;;;_* Lisp arguments
|
|
86 ;;
|
|
87 ;; It is possible to invoke a Lisp form as an argument. This can be
|
|
88 ;; done either by specifying the form as you might in Lisp, or by
|
|
89 ;; using the '$' character to introduce a value-interpolation:
|
|
90 ;;
|
|
91 ;; echo (+ 1 2)
|
|
92 ;;
|
|
93 ;; Or
|
|
94 ;;
|
|
95 ;; echo $(+ 1 2)
|
|
96 ;;
|
|
97 ;; The two forms are equivalent. The second is required only if the
|
|
98 ;; form being interpolated is within a string, or is a subexpression
|
|
99 ;; of a larger argument:
|
|
100 ;;
|
|
101 ;; echo x$(+ 1 2) "String $(+ 1 2)"
|
|
102 ;;
|
|
103 ;; To pass a Lisp symbol as a argument, use the alternate quoting
|
|
104 ;; syntax, since the single quote character is far too overused in
|
|
105 ;; shell syntax:
|
|
106 ;;
|
|
107 ;; echo #'lisp-symbol
|
|
108 ;;
|
|
109 ;; Backquote can also be used:
|
|
110 ;;
|
|
111 ;; echo `(list ,lisp-symbol)
|
|
112 ;;
|
|
113 ;; Lisp arguments are identified using the following regexp:
|
|
114
|
|
115 (defcustom eshell-lisp-regexp "\\([(`]\\|#'\\)"
|
|
116 "*A regexp which, if matched at beginning of an argument, means Lisp.
|
|
117 Such arguments will be passed to `read', and then evaluated."
|
|
118 :type 'regexp
|
|
119 :group 'eshell-cmd)
|
|
120
|
|
121 ;;;_* Command hooks
|
|
122 ;;
|
|
123 ;; There are several hooks involved with command execution, which can
|
|
124 ;; be used either to change or augment Eshell's behavior.
|
|
125
|
|
126 (defcustom eshell-pre-command-hook nil
|
|
127 "*A hook run before each interactive command is invoked."
|
|
128 :type 'hook
|
|
129 :group 'eshell-cmd)
|
|
130
|
|
131 (defcustom eshell-post-command-hook nil
|
|
132 "*A hook run after each interactive command is invoked."
|
|
133 :type 'hook
|
|
134 :group 'eshell-cmd)
|
|
135
|
|
136 (defcustom eshell-prepare-command-hook nil
|
|
137 "*A set of functions called to prepare a named command.
|
|
138 The command name and its argument are in `eshell-last-command-name'
|
|
139 and `eshell-last-arguments'. The functions on this hook can change
|
|
140 the value of these symbols if necessary.
|
|
141
|
|
142 To prevent a command from executing at all, set
|
|
143 `eshell-last-command-name' to nil."
|
|
144 :type 'hook
|
|
145 :group 'eshell-cmd)
|
|
146
|
|
147 (defcustom eshell-named-command-hook nil
|
|
148 "*A set of functions called before a named command is invoked.
|
|
149 Each function will be passed the command name and arguments that were
|
|
150 passed to `eshell-named-command'.
|
|
151
|
|
152 If any of the functions returns a non-nil value, the named command
|
|
153 will not be invoked, and that value will be returned from
|
|
154 `eshell-named-command'.
|
|
155
|
|
156 In order to substitute an alternate command form for execution, the
|
|
157 hook function should throw it using the tag `eshell-replace-command'.
|
|
158 For example:
|
|
159
|
|
160 (add-hook 'eshell-named-command-hook 'subst-with-cd)
|
|
161 (defun subst-with-cd (command args)
|
|
162 (throw 'eshell-replace-command
|
|
163 (eshell-parse-command \"cd\" args)))
|
|
164
|
|
165 Although useless, the above code will cause any non-glob, non-Lisp
|
|
166 command (i.e., 'ls' as opposed to '*ls' or '(ls)') to be replaced by a
|
|
167 call to `cd' using the arguments that were passed to the function."
|
|
168 :type 'hook
|
|
169 :group 'eshell-cmd)
|
|
170
|
|
171 (defcustom eshell-pre-rewrite-command-hook
|
|
172 '(eshell-no-command-conversion
|
|
173 eshell-subcommand-arg-values)
|
|
174 "*A hook run before command rewriting begins.
|
|
175 The terms of the command to be rewritten is passed as arguments, and
|
|
176 may be modified in place. Any return value is ignored."
|
|
177 :type 'hook
|
|
178 :group 'eshell-cmd)
|
|
179
|
|
180 (defcustom eshell-rewrite-command-hook
|
|
181 '(eshell-rewrite-for-command
|
|
182 eshell-rewrite-while-command
|
|
183 eshell-rewrite-if-command
|
|
184 eshell-rewrite-sexp-command
|
|
185 eshell-rewrite-initial-subcommand
|
|
186 eshell-rewrite-named-command)
|
|
187 "*A set of functions used to rewrite the command argument.
|
|
188 Once parsing of a command line is completed, the next step is to
|
|
189 rewrite the initial argument into something runnable.
|
|
190
|
|
191 A module may wish to associate special behavior with certain argument
|
|
192 syntaxes at the beginning of a command line. They are welcome to do
|
|
193 so by adding a function to this hook. The first function to return a
|
|
194 substitute command form is the one used. Each function is passed the
|
|
195 command's full argument list, which is a list of sexps (typically
|
|
196 forms or strings)."
|
|
197 :type 'hook
|
|
198 :group 'eshell-cmd)
|
|
199
|
|
200 (defcustom eshell-post-rewrite-command-hook nil
|
|
201 "*A hook run after command rewriting is finished.
|
|
202 Each function is passed the symbol containing the rewritten command,
|
|
203 which may be modified directly. Any return value is ignored."
|
|
204 :type 'hook
|
|
205 :group 'eshell-cmd)
|
|
206
|
33020
|
207 (defcustom eshell-complex-commands nil
|
|
208 "*A list of commands names or functions, that determine complexity.
|
|
209 That is, if a command is defined by a function named eshell/NAME,
|
|
210 and NAME is part of this list, it is invoked as a complex command.
|
|
211 Complex commands are always correct, but run much slower. If a
|
|
212 command works fine without being part of this list, then it doesn't
|
|
213 need to be.
|
|
214
|
|
215 If an entry is a function, it will be called with the name, and should
|
|
216 return non-nil if the command is complex."
|
|
217 :type '(repeat :tag "Commands"
|
|
218 (choice (string :tag "Name")
|
|
219 (function :tag "Predicate")))
|
|
220 :group 'eshell-cmd)
|
|
221
|
29873
|
222 ;;; Code:
|
|
223
|
|
224 (require 'esh-util)
|
|
225 (unless (eshell-under-xemacs-p)
|
|
226 (require 'eldoc))
|
|
227 (require 'esh-arg)
|
|
228 (require 'esh-proc)
|
|
229 (require 'esh-ext)
|
|
230
|
|
231 ;;; User Variables:
|
|
232
|
|
233 (defcustom eshell-cmd-load-hook '(eshell-cmd-initialize)
|
|
234 "*A hook that gets run when `eshell-cmd' is loaded."
|
|
235 :type 'hook
|
|
236 :group 'eshell-cmd)
|
|
237
|
|
238 (defcustom eshell-debug-command nil
|
|
239 "*If non-nil, enable debugging code. SSLLOOWW.
|
|
240 This option is only useful for reporting bugs. If you enable it, you
|
|
241 will have to visit the file 'eshell-cmd.el' and run the command
|
|
242 \\[eval-buffer]."
|
|
243 :type 'boolean
|
|
244 :group 'eshell-cmd)
|
|
245
|
|
246 (defcustom eshell-deferrable-commands
|
|
247 '(eshell-named-command
|
|
248 eshell-lisp-command
|
|
249 eshell-process-identity)
|
|
250 "*A list of functions which might return an ansychronous process.
|
|
251 If they return a process object, execution of the calling Eshell
|
|
252 command will wait for completion (in the background) before finishing
|
|
253 the command."
|
|
254 :type '(repeat function)
|
|
255 :group 'eshell-cmd)
|
|
256
|
|
257 (defcustom eshell-subcommand-bindings
|
|
258 '((eshell-in-subcommand-p t)
|
|
259 (default-directory default-directory)
|
|
260 (process-environment (eshell-copy-environment)))
|
|
261 "*A list of `let' bindings for subcommand environments."
|
|
262 :type 'sexp
|
|
263 :group 'eshell-cmd)
|
|
264
|
|
265 (put 'risky-local-variable 'eshell-subcommand-bindings t)
|
|
266
|
|
267 (defvar eshell-ensure-newline-p nil
|
|
268 "If non-nil, ensure that a newline is emitted after a Lisp form.
|
|
269 This can be changed by Lisp forms that are evaluated from the Eshell
|
|
270 command line.")
|
|
271
|
|
272 ;;; Internal Variables:
|
|
273
|
|
274 (defvar eshell-current-command nil)
|
|
275 (defvar eshell-command-name nil)
|
|
276 (defvar eshell-command-arguments nil)
|
|
277 (defvar eshell-in-pipeline-p nil)
|
|
278 (defvar eshell-in-subcommand-p nil)
|
|
279 (defvar eshell-last-arguments nil)
|
|
280 (defvar eshell-last-command-name nil)
|
|
281 (defvar eshell-last-async-proc nil
|
|
282 "When this foreground process completes, resume command evaluation.")
|
|
283
|
|
284 ;;; Functions:
|
|
285
|
|
286 (defsubst eshell-interactive-process ()
|
|
287 "Return currently running command process, if non-Lisp."
|
|
288 eshell-last-async-proc)
|
|
289
|
|
290 (defun eshell-cmd-initialize ()
|
|
291 "Initialize the Eshell command processing module."
|
|
292 (set (make-local-variable 'eshell-current-command) nil)
|
|
293 (set (make-local-variable 'eshell-command-name) nil)
|
|
294 (set (make-local-variable 'eshell-command-arguments) nil)
|
|
295 (set (make-local-variable 'eshell-last-arguments) nil)
|
|
296 (set (make-local-variable 'eshell-last-command-name) nil)
|
|
297 (set (make-local-variable 'eshell-last-async-proc) nil)
|
|
298
|
|
299 (add-hook 'eshell-kill-hook 'eshell-resume-command nil t)
|
|
300
|
|
301 ;; make sure that if a command is over, and no process is being
|
|
302 ;; waited for, that `eshell-current-command' is set to nil. This
|
|
303 ;; situation can occur, for example, if a Lisp function results in
|
|
304 ;; `debug' being called, and the user then types \\[top-level]
|
|
305 (add-hook 'eshell-post-command-hook
|
|
306 (function
|
|
307 (lambda ()
|
|
308 (setq eshell-current-command nil
|
|
309 eshell-last-async-proc nil))) nil t)
|
|
310
|
|
311 (add-hook 'eshell-parse-argument-hook
|
|
312 'eshell-parse-subcommand-argument nil t)
|
|
313 (add-hook 'eshell-parse-argument-hook
|
|
314 'eshell-parse-lisp-argument nil t)
|
|
315
|
|
316 (when (eshell-using-module 'eshell-cmpl)
|
|
317 (add-hook 'pcomplete-try-first-hook
|
|
318 'eshell-complete-lisp-symbols nil t)))
|
|
319
|
|
320 (eshell-deftest var last-result-var
|
|
321 "\"last result\" variable"
|
|
322 (eshell-command-result-p "+ 1 2; + $$ 2" "3\n5\n"))
|
|
323
|
|
324 (eshell-deftest var last-result-var2
|
|
325 "\"last result\" variable"
|
|
326 (eshell-command-result-p "+ 1 2; + $$ $$" "3\n6\n"))
|
|
327
|
|
328 (eshell-deftest var last-arg-var
|
|
329 "\"last arg\" variable"
|
|
330 (eshell-command-result-p "+ 1 2; + $_ 4" "3\n6\n"))
|
|
331
|
|
332 (defun eshell-complete-lisp-symbols ()
|
|
333 "If there is a user reference, complete it."
|
|
334 (let ((arg (pcomplete-actual-arg)))
|
|
335 (when (string-match (concat "\\`" eshell-lisp-regexp) arg)
|
|
336 (setq pcomplete-stub (substring arg (match-end 0))
|
|
337 pcomplete-last-completion-raw t)
|
|
338 (throw 'pcomplete-completions
|
|
339 (all-completions pcomplete-stub obarray 'boundp)))))
|
|
340
|
|
341 ;; Command parsing
|
|
342
|
|
343 (defun eshell-parse-command (command &optional args top-level)
|
|
344 "Parse the COMMAND, adding ARGS if given.
|
|
345 COMMAND can either be a string, or a cons cell demarcating a buffer
|
|
346 region. TOP-LEVEL, if non-nil, means that the outermost command (the
|
|
347 user's input command) is being parsed, and that pre and post command
|
|
348 hooks should be run before and after the command."
|
|
349 (let* (sep-terms
|
|
350 (terms
|
|
351 (append
|
|
352 (if (consp command)
|
|
353 (eshell-parse-arguments (car command) (cdr command))
|
|
354 (let ((here (point))
|
|
355 (inhibit-point-motion-hooks t)
|
|
356 after-change-functions)
|
|
357 (insert command)
|
|
358 (prog1
|
|
359 (eshell-parse-arguments here (point))
|
|
360 (delete-region here (point)))))
|
|
361 args))
|
|
362 (commands
|
|
363 (mapcar
|
|
364 (function
|
|
365 (lambda (cmd)
|
|
366 (if (or (not (car sep-terms))
|
|
367 (string= (car sep-terms) ";"))
|
|
368 (setq cmd
|
|
369 (eshell-parse-pipeline cmd (not (car sep-terms))))
|
|
370 (setq cmd
|
|
371 (list 'eshell-do-subjob
|
|
372 (list 'list (eshell-parse-pipeline cmd)))))
|
|
373 (setq sep-terms (cdr sep-terms))
|
|
374 (if eshell-in-pipeline-p
|
|
375 cmd
|
|
376 (list 'eshell-trap-errors cmd))))
|
|
377 (eshell-separate-commands terms "[&;]" nil 'sep-terms))))
|
|
378 (let ((cmd commands))
|
|
379 (while cmd
|
|
380 (if (cdr cmd)
|
|
381 (setcar cmd (list 'eshell-commands (car cmd))))
|
|
382 (setq cmd (cdr cmd))))
|
|
383 (setq commands
|
|
384 (append (list 'progn)
|
|
385 (if top-level
|
|
386 (list '(run-hooks 'eshell-pre-command-hook)))
|
|
387 (if (not top-level)
|
|
388 commands
|
|
389 (list
|
|
390 (list 'catch (quote 'top-level)
|
|
391 (append (list 'progn) commands))
|
|
392 '(run-hooks 'eshell-post-command-hook)))))
|
|
393 (if top-level
|
|
394 (list 'eshell-commands commands)
|
|
395 commands)))
|
|
396
|
|
397 (defun eshell-debug-show-parsed-args (terms)
|
|
398 "Display parsed arguments in the debug buffer."
|
|
399 (ignore
|
|
400 (if eshell-debug-command
|
|
401 (eshell-debug-command "parsed arguments" terms))))
|
|
402
|
|
403 (defun eshell-no-command-conversion (terms)
|
|
404 "Don't convert the command argument."
|
|
405 (ignore
|
|
406 (if (and (listp (car terms))
|
|
407 (eq (caar terms) 'eshell-convert))
|
|
408 (setcar terms (cadr (car terms))))))
|
|
409
|
|
410 (defun eshell-subcommand-arg-values (terms)
|
|
411 "Convert subcommand arguments {x} to ${x}, in order to take their values."
|
|
412 (setq terms (cdr terms)) ; skip command argument
|
|
413 (while terms
|
|
414 (if (and (listp (car terms))
|
|
415 (eq (caar terms) 'eshell-as-subcommand))
|
|
416 (setcar terms (list 'eshell-convert
|
|
417 (list 'eshell-command-to-value
|
|
418 (car terms)))))
|
|
419 (setq terms (cdr terms))))
|
|
420
|
|
421 (defun eshell-rewrite-sexp-command (terms)
|
|
422 "Rewrite a sexp in initial position, such as '(+ 1 2)'."
|
|
423 ;; this occurs when a Lisp expression is in first position
|
|
424 (if (and (listp (car terms))
|
|
425 (eq (caar terms) 'eshell-command-to-value))
|
|
426 (car (cdar terms))))
|
|
427
|
|
428 (eshell-deftest cmd lisp-command
|
|
429 "Evaluate Lisp command"
|
|
430 (eshell-command-result-p "(+ 1 2)" "3"))
|
|
431
|
|
432 (eshell-deftest cmd lisp-command-args
|
|
433 "Evaluate Lisp command (ignore args)"
|
|
434 (eshell-command-result-p "(+ 1 2) 3" "3"))
|
|
435
|
|
436 (defun eshell-rewrite-initial-subcommand (terms)
|
|
437 "Rewrite a subcommand in initial position, such as '{+ 1 2}'."
|
|
438 (if (and (listp (car terms))
|
|
439 (eq (caar terms) 'eshell-as-subcommand))
|
|
440 (car terms)))
|
|
441
|
|
442 (eshell-deftest cmd subcommand
|
|
443 "Run subcommand"
|
|
444 (eshell-command-result-p "{+ 1 2}" "3\n"))
|
|
445
|
|
446 (eshell-deftest cmd subcommand-args
|
|
447 "Run subcommand (ignore args)"
|
|
448 (eshell-command-result-p "{+ 1 2} 3" "3\n"))
|
|
449
|
|
450 (eshell-deftest cmd subcommand-lisp
|
|
451 "Run subcommand + Lisp form"
|
|
452 (eshell-command-result-p "{(+ 1 2)}" "3\n"))
|
|
453
|
|
454 (defun eshell-rewrite-named-command (terms)
|
|
455 "If no other rewriting rule transforms TERMS, assume a named command."
|
65167
2980740e3f1c
(eshell-rewrite-named-command): Changed the code around a bit so that
John Wiegley <johnw@newartisans.com>
diff
changeset
|
456 (let ((sym (if eshell-in-pipeline-p
|
2980740e3f1c
(eshell-rewrite-named-command): Changed the code around a bit so that
John Wiegley <johnw@newartisans.com>
diff
changeset
|
457 'eshell-named-command*
|
2980740e3f1c
(eshell-rewrite-named-command): Changed the code around a bit so that
John Wiegley <johnw@newartisans.com>
diff
changeset
|
458 'eshell-named-command))
|
2980740e3f1c
(eshell-rewrite-named-command): Changed the code around a bit so that
John Wiegley <johnw@newartisans.com>
diff
changeset
|
459 (cmd (car terms))
|
2980740e3f1c
(eshell-rewrite-named-command): Changed the code around a bit so that
John Wiegley <johnw@newartisans.com>
diff
changeset
|
460 (args (cdr terms)))
|
2980740e3f1c
(eshell-rewrite-named-command): Changed the code around a bit so that
John Wiegley <johnw@newartisans.com>
diff
changeset
|
461 (if args
|
2980740e3f1c
(eshell-rewrite-named-command): Changed the code around a bit so that
John Wiegley <johnw@newartisans.com>
diff
changeset
|
462 (list sym cmd (append (list 'list) (cdr terms)))
|
2980740e3f1c
(eshell-rewrite-named-command): Changed the code around a bit so that
John Wiegley <johnw@newartisans.com>
diff
changeset
|
463 (list sym cmd))))
|
29873
|
464
|
|
465 (eshell-deftest cmd named-command
|
|
466 "Execute named command"
|
|
467 (eshell-command-result-p "+ 1 2" "3\n"))
|
|
468
|
|
469 (eval-when-compile
|
|
470 (defvar eshell-command-body)
|
|
471 (defvar eshell-test-body))
|
|
472
|
|
473 (defsubst eshell-invokify-arg (arg &optional share-output silent)
|
|
474 "Change ARG so it can be invoked from a structured command.
|
|
475
|
|
476 SHARE-OUTPUT, if non-nil, means this invocation should share the
|
|
477 current output stream, which is separately redirectable. SILENT
|
|
478 means the user and/or any redirections shouldn't see any output
|
|
479 from this command. If both SHARE-OUTPUT and SILENT are non-nil,
|
|
480 the second is ignored."
|
|
481 ;; something that begins with `eshell-convert' means that it
|
|
482 ;; intends to return a Lisp value. We want to get past this,
|
|
483 ;; but if it's not _actually_ a value interpolation -- in which
|
|
484 ;; we leave it alone. In fact, the only time we muck with it
|
|
485 ;; is in the case of a {subcommand} that has been turned into
|
|
486 ;; the interpolation, ${subcommand}, by the parser because it
|
|
487 ;; didn't know better.
|
|
488 (if (and (listp arg)
|
|
489 (eq (car arg) 'eshell-convert)
|
|
490 (eq (car (cadr arg)) 'eshell-command-to-value))
|
|
491 (if share-output
|
|
492 (cadr (cadr arg))
|
|
493 (list 'eshell-commands (cadr (cadr arg))
|
|
494 silent))
|
|
495 arg))
|
|
496
|
|
497 (defun eshell-rewrite-for-command (terms)
|
|
498 "Rewrite a `for' command into its equivalent Eshell command form.
|
|
499 Because the implementation of `for' relies upon conditional evaluation
|
|
500 of its argumbent (i.e., use of a Lisp special form), it must be
|
|
501 implemented via rewriting, rather than as a function."
|
|
502 (if (and (stringp (car terms))
|
|
503 (string= (car terms) "for")
|
|
504 (stringp (nth 2 terms))
|
|
505 (string= (nth 2 terms) "in"))
|
|
506 (let ((body (car (last terms))))
|
|
507 (setcdr (last terms 2) nil)
|
|
508 (list
|
|
509 'let (list (list 'for-items
|
|
510 (append
|
|
511 (list 'append)
|
|
512 (mapcar
|
|
513 (function
|
|
514 (lambda (elem)
|
|
515 (if (listp elem)
|
|
516 elem
|
|
517 (list 'list elem))))
|
29875
|
518 (cdr (cddr terms)))))
|
29873
|
519 (list 'eshell-command-body
|
|
520 (list 'quote (list nil)))
|
|
521 (list 'eshell-test-body
|
|
522 (list 'quote (list nil))))
|
|
523 (list
|
|
524 'progn
|
|
525 (list
|
|
526 'while (list 'car (list 'symbol-value
|
|
527 (list 'quote 'for-items)))
|
|
528 (list
|
|
529 'progn
|
|
530 (list 'let
|
|
531 (list (list (intern (cadr terms))
|
|
532 (list 'car
|
|
533 (list 'symbol-value
|
|
534 (list 'quote 'for-items)))))
|
33020
|
535 (list 'eshell-protect
|
|
536 (eshell-invokify-arg body t)))
|
29873
|
537 (list 'setcar 'for-items
|
|
538 (list 'cadr
|
|
539 (list 'symbol-value
|
|
540 (list 'quote 'for-items))))
|
|
541 (list 'setcdr 'for-items
|
|
542 (list 'cddr
|
|
543 (list 'symbol-value
|
|
544 (list 'quote 'for-items))))))
|
|
545 (list 'eshell-close-handles
|
|
546 'eshell-last-command-status
|
|
547 (list 'list (quote 'quote)
|
|
548 'eshell-last-command-result)))))))
|
|
549
|
|
550 (defun eshell-structure-basic-command (func names keyword test body
|
|
551 &optional else vocal-test)
|
|
552 "With TERMS, KEYWORD, and two NAMES, structure a basic command.
|
|
553 The first of NAMES should be the positive form, and the second the
|
|
554 negative. It's not likely that users should ever need to call this
|
|
555 function.
|
|
556
|
|
557 If VOCAL-TEST is non-nil, it means output from the test should be
|
|
558 shown, as well as output from the body."
|
|
559 ;; If the test form begins with `eshell-convert', it means
|
|
560 ;; something data-wise will be returned, and we should let
|
|
561 ;; that determine the truth of the statement.
|
|
562 (unless (eq (car test) 'eshell-convert)
|
|
563 (setq test
|
|
564 (list 'progn test
|
|
565 (list 'eshell-exit-success-p))))
|
|
566
|
|
567 ;; should we reverse the sense of the test? This depends
|
|
568 ;; on the `names' parameter. If it's the symbol nil, yes.
|
|
569 ;; Otherwise, it can be a pair of strings; if the keyword
|
|
570 ;; we're using matches the second member of that pair (a
|
|
571 ;; list), we should reverse it.
|
|
572 (if (or (eq names nil)
|
|
573 (and (listp names)
|
|
574 (string= keyword (cadr names))))
|
|
575 (setq test (list 'not test)))
|
|
576
|
|
577 ;; finally, create the form that represents this structured
|
|
578 ;; command
|
|
579 (list
|
|
580 'let (list (list 'eshell-command-body
|
|
581 (list 'quote (list nil)))
|
|
582 (list 'eshell-test-body
|
|
583 (list 'quote (list nil))))
|
|
584 (list func test body else)
|
|
585 (list 'eshell-close-handles
|
|
586 'eshell-last-command-status
|
|
587 (list 'list (quote 'quote)
|
|
588 'eshell-last-command-result))))
|
|
589
|
|
590 (defun eshell-rewrite-while-command (terms)
|
|
591 "Rewrite a `while' command into its equivalent Eshell command form.
|
|
592 Because the implementation of `while' relies upon conditional
|
|
593 evaluation of its argument (i.e., use of a Lisp special form), it
|
|
594 must be implemented via rewriting, rather than as a function."
|
|
595 (if (and (stringp (car terms))
|
|
596 (member (car terms) '("while" "until")))
|
|
597 (eshell-structure-basic-command
|
|
598 'while '("while" "until") (car terms)
|
|
599 (eshell-invokify-arg (cadr terms) nil t)
|
33020
|
600 (list 'eshell-protect
|
29873
|
601 (eshell-invokify-arg (car (last terms)) t)))))
|
|
602
|
|
603 (defun eshell-rewrite-if-command (terms)
|
|
604 "Rewrite an `if' command into its equivalent Eshell command form.
|
|
605 Because the implementation of `if' relies upon conditional
|
|
606 evaluation of its argument (i.e., use of a Lisp special form), it
|
|
607 must be implemented via rewriting, rather than as a function."
|
|
608 (if (and (stringp (car terms))
|
|
609 (member (car terms) '("if" "unless")))
|
|
610 (eshell-structure-basic-command
|
|
611 'if '("if" "unless") (car terms)
|
|
612 (eshell-invokify-arg (cadr terms) nil t)
|
33020
|
613 (list 'eshell-protect
|
|
614 (eshell-invokify-arg
|
38007
fa54203d014a
(eshell-exit-success-p): Use a string-match to test if the last
John Wiegley <johnw@newartisans.com>
diff
changeset
|
615 (if (= (length terms) 4)
|
fa54203d014a
(eshell-exit-success-p): Use a string-match to test if the last
John Wiegley <johnw@newartisans.com>
diff
changeset
|
616 (car (last terms 2))
|
33020
|
617 (car (last terms))) t))
|
38007
fa54203d014a
(eshell-exit-success-p): Use a string-match to test if the last
John Wiegley <johnw@newartisans.com>
diff
changeset
|
618 (if (= (length terms) 4)
|
33020
|
619 (list 'eshell-protect
|
|
620 (eshell-invokify-arg
|
|
621 (car (last terms)))) t))))
|
29873
|
622
|
|
623 (defun eshell-exit-success-p ()
|
|
624 "Return non-nil if the last command was \"successful\".
|
|
625 For a bit of Lisp code, this means a return value of non-nil.
|
|
626 For an external command, it means an exit code of 0."
|
38007
fa54203d014a
(eshell-exit-success-p): Use a string-match to test if the last
John Wiegley <johnw@newartisans.com>
diff
changeset
|
627 (if (save-match-data
|
fa54203d014a
(eshell-exit-success-p): Use a string-match to test if the last
John Wiegley <johnw@newartisans.com>
diff
changeset
|
628 (string-match "#<\\(Lisp object\\|function .*\\)>"
|
fa54203d014a
(eshell-exit-success-p): Use a string-match to test if the last
John Wiegley <johnw@newartisans.com>
diff
changeset
|
629 eshell-last-command-name))
|
29873
|
630 eshell-last-command-result
|
|
631 (= eshell-last-command-status 0)))
|
|
632
|
|
633 (defun eshell-parse-pipeline (terms &optional final-p)
|
|
634 "Parse a pipeline from TERMS, return the appropriate Lisp forms."
|
|
635 (let* (sep-terms
|
|
636 (bigpieces (eshell-separate-commands terms "\\(&&\\|||\\)"
|
|
637 nil 'sep-terms))
|
|
638 (bp bigpieces)
|
|
639 (results (list t))
|
|
640 final)
|
|
641 (while bp
|
|
642 (let ((subterms (car bp)))
|
|
643 (let* ((pieces (eshell-separate-commands subterms "|"))
|
|
644 (p pieces))
|
|
645 (while p
|
|
646 (let ((cmd (car p)))
|
|
647 (run-hook-with-args 'eshell-pre-rewrite-command-hook cmd)
|
|
648 (setq cmd (run-hook-with-args-until-success
|
|
649 'eshell-rewrite-command-hook cmd))
|
|
650 (run-hook-with-args 'eshell-post-rewrite-command-hook 'cmd)
|
|
651 (setcar p cmd))
|
|
652 (setq p (cdr p)))
|
|
653 (nconc results
|
|
654 (list
|
|
655 (if (<= (length pieces) 1)
|
|
656 (car pieces)
|
|
657 (assert (not eshell-in-pipeline-p))
|
|
658 (list 'eshell-execute-pipeline
|
|
659 (list 'quote pieces))))))
|
|
660 (setq bp (cdr bp))))
|
|
661 ;; `results' might be empty; this happens in the case of
|
|
662 ;; multi-line input
|
|
663 (setq results (cdr results)
|
|
664 results (nreverse results)
|
|
665 final (car results)
|
|
666 results (cdr results)
|
|
667 sep-terms (nreverse sep-terms))
|
|
668 (while results
|
|
669 (assert (car sep-terms))
|
|
670 (setq final (eshell-structure-basic-command
|
|
671 'if (string= (car sep-terms) "&&") "if"
|
33020
|
672 (list 'eshell-protect (car results))
|
|
673 (list 'eshell-protect final)
|
29873
|
674 nil t)
|
|
675 results (cdr results)
|
|
676 sep-terms (cdr sep-terms)))
|
|
677 final))
|
|
678
|
|
679 (defun eshell-parse-subcommand-argument ()
|
|
680 "Parse a subcommand argument of the form '{command}'."
|
|
681 (if (and (not eshell-current-argument)
|
|
682 (not eshell-current-quoted)
|
|
683 (eq (char-after) ?\{)
|
|
684 (or (= (point-max) (1+ (point)))
|
|
685 (not (eq (char-after (1+ (point))) ?\}))))
|
|
686 (let ((end (eshell-find-delimiter ?\{ ?\})))
|
|
687 (if (not end)
|
|
688 (throw 'eshell-incomplete ?\{)
|
|
689 (when (eshell-arg-delimiter (1+ end))
|
|
690 (prog1
|
|
691 (list 'eshell-as-subcommand
|
|
692 (eshell-parse-command (cons (1+ (point)) end)))
|
|
693 (goto-char (1+ end))))))))
|
|
694
|
|
695 (defun eshell-parse-lisp-argument ()
|
|
696 "Parse a Lisp expression which is specified as an argument."
|
|
697 (if (and (not eshell-current-argument)
|
|
698 (not eshell-current-quoted)
|
|
699 (looking-at eshell-lisp-regexp))
|
|
700 (let* ((here (point))
|
|
701 (obj
|
|
702 (condition-case err
|
|
703 (read (current-buffer))
|
|
704 (end-of-file
|
|
705 (throw 'eshell-incomplete ?\()))))
|
|
706 (if (eshell-arg-delimiter)
|
|
707 (list 'eshell-command-to-value
|
|
708 (list 'eshell-lisp-command (list 'quote obj)))
|
|
709 (ignore (goto-char here))))))
|
|
710
|
33020
|
711 (defun eshell-separate-commands (terms separator &optional
|
|
712 reversed last-terms-sym)
|
29873
|
713 "Separate TERMS using SEPARATOR.
|
|
714 If REVERSED is non-nil, the list of separated term groups will be
|
49477
|
715 returned in reverse order. If LAST-TERMS-SYM is a symbol, its value
|
29873
|
716 will be set to a list of all the separator operators found (or '(list
|
|
717 nil)' if none)."
|
|
718 (let ((sub-terms (list t))
|
|
719 (eshell-sep-terms (list t))
|
|
720 subchains)
|
|
721 (while terms
|
|
722 (if (and (consp (car terms))
|
|
723 (eq (caar terms) 'eshell-operator)
|
|
724 (string-match (concat "^" separator "$")
|
|
725 (nth 1 (car terms))))
|
|
726 (progn
|
|
727 (nconc eshell-sep-terms (list (nth 1 (car terms))))
|
|
728 (setq subchains (cons (cdr sub-terms) subchains)
|
|
729 sub-terms (list t)))
|
|
730 (nconc sub-terms (list (car terms))))
|
|
731 (setq terms (cdr terms)))
|
|
732 (if (> (length sub-terms) 1)
|
|
733 (setq subchains (cons (cdr sub-terms) subchains)))
|
|
734 (if reversed
|
|
735 (progn
|
|
736 (if last-terms-sym
|
|
737 (set last-terms-sym (reverse (cdr eshell-sep-terms))))
|
|
738 subchains) ; already reversed
|
|
739 (if last-terms-sym
|
|
740 (set last-terms-sym (cdr eshell-sep-terms)))
|
|
741 (nreverse subchains))))
|
|
742
|
|
743 ;;_* Command evaluation macros
|
|
744 ;;
|
|
745 ;; The structure of the following macros is very important to
|
|
746 ;; `eshell-do-eval' [Iterative evaluation]:
|
|
747 ;;
|
|
748 ;; @ Don't use forms that conditionally evaluate their arguments, such
|
|
749 ;; as `setq', `if', `while', `let*', etc. The only special forms
|
|
750 ;; that can be used are `let', `condition-case' and
|
|
751 ;; `unwind-protect'.
|
|
752 ;;
|
|
753 ;; @ The main body of a `let' can contain only one form. Use `progn'
|
|
754 ;; if necessary.
|
|
755 ;;
|
|
756 ;; @ The two `special' variables are `eshell-current-handles' and
|
|
757 ;; `eshell-current-subjob-p'. Bind them locally with a `let' if you
|
|
758 ;; need to change them. Change them directly only if your intention
|
|
759 ;; is to change the calling environment.
|
|
760
|
|
761 (defmacro eshell-do-subjob (object)
|
|
762 "Evaluate a command OBJECT as a subjob.
|
62789
74e26c83386f
(eshell-eval-command): If the return value of `eshell-resume-eval' is
John Wiegley <johnw@newartisans.com>
diff
changeset
|
763 We indicate that the process was run in the background by returning it
|
29873
|
764 ensconced in a list."
|
|
765 `(let ((eshell-current-subjob-p t))
|
|
766 ,object))
|
|
767
|
|
768 (defmacro eshell-commands (object &optional silent)
|
|
769 "Place a valid set of handles, and context, around command OBJECT."
|
|
770 `(let ((eshell-current-handles
|
|
771 (eshell-create-handles ,(not silent) 'append))
|
|
772 eshell-current-subjob-p)
|
|
773 ,object))
|
|
774
|
|
775 (defmacro eshell-trap-errors (object)
|
|
776 "Trap any errors that occur, so they are not entirely fatal.
|
|
777 Also, the variable `eshell-this-command-hook' is available for the
|
|
778 duration of OBJECT's evaluation. Note that functions should be added
|
|
779 to this hook using `nconc', and *not* `add-hook'.
|
|
780
|
|
781 Someday, when Scheme will become the dominant Emacs language, all of
|
|
782 this grossness will be made to disappear by using `call/cc'..."
|
|
783 `(let ((eshell-this-command-hook (list 'ignore)))
|
|
784 (eshell-condition-case err
|
|
785 (prog1
|
|
786 ,object
|
|
787 (run-hooks 'eshell-this-command-hook))
|
|
788 (error
|
|
789 (run-hooks 'eshell-this-command-hook)
|
|
790 (eshell-errorn (error-message-string err))
|
|
791 (eshell-close-handles 1)))))
|
|
792
|
31241
|
793 (defmacro eshell-copy-handles (object)
|
|
794 "Duplicate current I/O handles, so OBJECT works with its own copy."
|
|
795 `(let ((eshell-current-handles
|
|
796 (eshell-create-handles
|
|
797 (car (aref eshell-current-handles
|
|
798 eshell-output-handle)) nil
|
|
799 (car (aref eshell-current-handles
|
|
800 eshell-error-handle)) nil)))
|
|
801 ,object))
|
|
802
|
29873
|
803 (defmacro eshell-protect (object)
|
|
804 "Protect I/O handles, so they aren't get closed after eval'ing OBJECT."
|
|
805 `(progn
|
|
806 (eshell-protect-handles eshell-current-handles)
|
|
807 ,object))
|
|
808
|
|
809 (defmacro eshell-do-pipelines (pipeline)
|
|
810 "Execute the commands in PIPELINE, connecting each to one another."
|
|
811 (when (setq pipeline (cadr pipeline))
|
31241
|
812 `(eshell-copy-handles
|
|
813 (progn
|
|
814 ,(when (cdr pipeline)
|
|
815 `(let (nextproc)
|
|
816 (progn
|
|
817 (set 'nextproc
|
|
818 (eshell-do-pipelines (quote ,(cdr pipeline))))
|
|
819 (eshell-set-output-handle ,eshell-output-handle
|
|
820 'append nextproc)
|
|
821 (eshell-set-output-handle ,eshell-error-handle
|
|
822 'append nextproc)
|
|
823 (set 'tailproc (or tailproc nextproc)))))
|
|
824 ,(let ((head (car pipeline)))
|
|
825 (if (memq (car head) '(let progn))
|
|
826 (setq head (car (last head))))
|
|
827 (when (memq (car head) eshell-deferrable-commands)
|
|
828 (ignore
|
|
829 (setcar head
|
|
830 (intern-soft
|
|
831 (concat (symbol-name (car head)) "*"))))))
|
|
832 ,(car pipeline)))))
|
|
833
|
|
834 (defmacro eshell-do-pipelines-synchronously (pipeline)
|
|
835 "Execute the commands in PIPELINE in sequence synchronously.
|
|
836 Output of each command is passed as input to the next one in the pipeline.
|
|
837 This is used on systems where `start-process' is not supported."
|
|
838 (when (setq pipeline (cadr pipeline))
|
|
839 `(let (result)
|
29873
|
840 (progn
|
|
841 ,(when (cdr pipeline)
|
31241
|
842 `(let (output-marker)
|
29873
|
843 (progn
|
31241
|
844 (set 'output-marker ,(point-marker))
|
29873
|
845 (eshell-set-output-handle ,eshell-output-handle
|
31241
|
846 'append output-marker)
|
29873
|
847 (eshell-set-output-handle ,eshell-error-handle
|
31241
|
848 'append output-marker))))
|
29873
|
849 ,(let ((head (car pipeline)))
|
|
850 (if (memq (car head) '(let progn))
|
|
851 (setq head (car (last head))))
|
31241
|
852 ;;; FIXME: is deferrable significant here?
|
29873
|
853 (when (memq (car head) eshell-deferrable-commands)
|
|
854 (ignore
|
|
855 (setcar head
|
|
856 (intern-soft
|
|
857 (concat (symbol-name (car head)) "*"))))))
|
31241
|
858 ;; The last process in the pipe should get its handles
|
|
859 ;; redirected as we found them before running the pipe.
|
|
860 ,(if (null (cdr pipeline))
|
|
861 `(progn
|
|
862 (set 'eshell-current-handles tail-handles)
|
|
863 (set 'eshell-in-pipeline-p nil)))
|
|
864 (set 'result ,(car pipeline))
|
|
865 ;; tailproc gets the result of the last successful process in
|
|
866 ;; the pipeline.
|
|
867 (set 'tailproc (or result tailproc))
|
|
868 ,(if (cdr pipeline)
|
|
869 `(eshell-do-pipelines-synchronously (quote ,(cdr pipeline))))
|
|
870 result))))
|
29873
|
871
|
|
872 (defalias 'eshell-process-identity 'identity)
|
|
873
|
|
874 (defmacro eshell-execute-pipeline (pipeline)
|
|
875 "Execute the commands in PIPELINE, connecting each to one another."
|
|
876 `(let ((eshell-in-pipeline-p t) tailproc)
|
|
877 (progn
|
31241
|
878 ,(if (fboundp 'start-process)
|
|
879 `(eshell-do-pipelines ,pipeline)
|
|
880 `(let ((tail-handles (eshell-create-handles
|
|
881 (car (aref eshell-current-handles
|
|
882 ,eshell-output-handle)) nil
|
|
883 (car (aref eshell-current-handles
|
|
884 ,eshell-error-handle)) nil)))
|
|
885 (eshell-do-pipelines-synchronously ,pipeline)))
|
29873
|
886 (eshell-process-identity tailproc))))
|
|
887
|
|
888 (defmacro eshell-as-subcommand (command)
|
|
889 "Execute COMMAND using a temp buffer.
|
|
890 This is used so that certain Lisp commands, such as `cd', when
|
|
891 executed in a subshell, do not disturb the environment of the main
|
|
892 Eshell buffer."
|
|
893 `(let ,eshell-subcommand-bindings
|
|
894 ,command))
|
|
895
|
|
896 (defmacro eshell-do-command-to-value (object)
|
|
897 "Run a subcommand prepared by `eshell-command-to-value'.
|
|
898 This avoids the need to use `let*'."
|
|
899 `(let ((eshell-current-handles
|
|
900 (eshell-create-handles value 'overwrite)))
|
|
901 (progn
|
|
902 ,object
|
|
903 (symbol-value value))))
|
|
904
|
|
905 (defmacro eshell-command-to-value (object)
|
|
906 "Run OBJECT synchronously, returning its result as a string.
|
|
907 Returns a string comprising the output from the command."
|
|
908 `(let ((value (make-symbol "eshell-temp")))
|
|
909 (eshell-do-command-to-value ,object)))
|
|
910
|
|
911 ;;;_* Iterative evaluation
|
|
912 ;;
|
|
913 ;; Eshell runs all of its external commands asynchronously, so that
|
|
914 ;; Emacs is not blocked while the operation is being performed.
|
|
915 ;; However, this introduces certain synchronization difficulties,
|
|
916 ;; since the Lisp code, once it returns, will not "go back" to finish
|
|
917 ;; executing the commands which haven't yet been started.
|
|
918 ;;
|
|
919 ;; What Eshell does to work around this problem (basically, the lack
|
|
920 ;; of threads in Lisp), is that it evaluates the command sequence
|
|
921 ;; iteratively. Whenever an asynchronous process is begun, evaluation
|
|
922 ;; terminates and control is given back to Emacs. When that process
|
|
923 ;; finishes, it will resume the evaluation using the remainder of the
|
|
924 ;; command tree.
|
|
925
|
|
926 (defun eshell/eshell-debug (&rest args)
|
|
927 "A command for toggling certain debug variables."
|
|
928 (ignore
|
|
929 (cond
|
|
930 ((not args)
|
|
931 (if eshell-handle-errors
|
|
932 (eshell-print "errors\n"))
|
|
933 (if eshell-debug-command
|
|
934 (eshell-print "commands\n")))
|
|
935 ((or (string= (car args) "-h")
|
|
936 (string= (car args) "--help"))
|
|
937 (eshell-print "usage: eshell-debug [kinds]
|
|
938
|
|
939 This command is used to aid in debugging problems related to Eshell
|
|
940 itself. It is not useful for anything else. The recognized `kinds'
|
|
941 at the moment are:
|
|
942
|
|
943 errors stops Eshell from trapping errors
|
|
944 commands shows command execution progress in `*eshell last cmd*'
|
|
945 "))
|
|
946 (t
|
|
947 (while args
|
|
948 (cond
|
|
949 ((string= (car args) "errors")
|
|
950 (setq eshell-handle-errors (not eshell-handle-errors)))
|
|
951 ((string= (car args) "commands")
|
|
952 (setq eshell-debug-command (not eshell-debug-command))))
|
|
953 (setq args (cdr args)))))))
|
|
954
|
|
955 (defun pcomplete/eshell-mode/eshell-debug ()
|
|
956 "Completion for the `debug' command."
|
|
957 (while (pcomplete-here '("errors" "commands"))))
|
|
958
|
|
959 (defun eshell-debug-command (tag subform)
|
|
960 "Output a debugging message to '*eshell last cmd*'."
|
|
961 (let ((buf (get-buffer-create "*eshell last cmd*"))
|
|
962 (text (eshell-stringify eshell-current-command)))
|
|
963 (save-excursion
|
|
964 (set-buffer buf)
|
|
965 (if (not tag)
|
|
966 (erase-buffer)
|
|
967 (insert "\n\C-l\n" tag "\n\n" text
|
|
968 (if subform
|
|
969 (concat "\n\n" (eshell-stringify subform)) ""))))))
|
|
970
|
33020
|
971 (defun eshell-invoke-directly (command input)
|
|
972 (let ((base (cadr (nth 2 (nth 2 (cadr command))))) name)
|
|
973 (if (and (eq (car base) 'eshell-trap-errors)
|
|
974 (eq (car (cadr base)) 'eshell-named-command))
|
|
975 (setq name (cadr (cadr base))))
|
|
976 (and name (stringp name)
|
|
977 (not (member name eshell-complex-commands))
|
|
978 (catch 'simple
|
|
979 (progn
|
|
980 (eshell-for pred eshell-complex-commands
|
|
981 (if (and (functionp pred)
|
|
982 (funcall pred name))
|
|
983 (throw 'simple nil)))
|
|
984 t))
|
|
985 (fboundp (intern-soft (concat "eshell/" name))))))
|
|
986
|
29873
|
987 (defun eshell-eval-command (command &optional input)
|
|
988 "Evaluate the given COMMAND iteratively."
|
|
989 (if eshell-current-command
|
|
990 ;; we can just stick the new command at the end of the current
|
|
991 ;; one, and everything will happen as it should
|
|
992 (setcdr (last (cdr eshell-current-command))
|
|
993 (list (list 'let '((here (and (eobp) (point))))
|
|
994 (and input
|
|
995 (list 'insert-and-inherit
|
|
996 (concat input "\n")))
|
|
997 '(if here
|
|
998 (eshell-update-markers here))
|
|
999 (list 'eshell-do-eval
|
|
1000 (list 'quote command)))))
|
|
1001 (and eshell-debug-command
|
|
1002 (save-excursion
|
|
1003 (let ((buf (get-buffer-create "*eshell last cmd*")))
|
|
1004 (set-buffer buf)
|
|
1005 (erase-buffer)
|
|
1006 (insert "command: \"" input "\"\n"))))
|
|
1007 (setq eshell-current-command command)
|
31241
|
1008 (let ((delim (catch 'eshell-incomplete
|
|
1009 (eshell-resume-eval))))
|
42971
|
1010 ;; On systems that don't support async subprocesses, eshell-resume
|
|
1011 ;; can return t. Don't treat that as an error.
|
62789
74e26c83386f
(eshell-eval-command): If the return value of `eshell-resume-eval' is
John Wiegley <johnw@newartisans.com>
diff
changeset
|
1012 (if (listp delim)
|
74e26c83386f
(eshell-eval-command): If the return value of `eshell-resume-eval' is
John Wiegley <johnw@newartisans.com>
diff
changeset
|
1013 (setq delim (car delim)))
|
42971
|
1014 (if (and delim (not (eq delim t)))
|
62789
74e26c83386f
(eshell-eval-command): If the return value of `eshell-resume-eval' is
John Wiegley <johnw@newartisans.com>
diff
changeset
|
1015 (error "Unmatched delimiter: %c" delim)))))
|
29873
|
1016
|
|
1017 (defun eshell-resume-command (proc status)
|
|
1018 "Resume the current command when a process ends."
|
|
1019 (when proc
|
31241
|
1020 (unless (or (not (stringp status))
|
|
1021 (string= "stopped" status)
|
29873
|
1022 (string-match eshell-reset-signals status))
|
|
1023 (if (eq proc (eshell-interactive-process))
|
|
1024 (eshell-resume-eval)))))
|
|
1025
|
|
1026 (defun eshell-resume-eval ()
|
|
1027 "Destructively evaluate a form which may need to be deferred."
|
|
1028 (eshell-condition-case err
|
|
1029 (progn
|
|
1030 (setq eshell-last-async-proc nil)
|
|
1031 (when eshell-current-command
|
|
1032 (let* (retval
|
|
1033 (proc (catch 'eshell-defer
|
|
1034 (ignore
|
|
1035 (setq retval
|
|
1036 (eshell-do-eval
|
|
1037 eshell-current-command))))))
|
31241
|
1038 (if (eshell-processp proc)
|
29873
|
1039 (ignore (setq eshell-last-async-proc proc))
|
|
1040 (cadr retval)))))
|
|
1041 (error
|
|
1042 (error (error-message-string err)))))
|
|
1043
|
|
1044 (defmacro eshell-manipulate (tag &rest commands)
|
|
1045 "Manipulate a COMMAND form, with TAG as a debug identifier."
|
|
1046 (if (not eshell-debug-command)
|
|
1047 `(progn ,@commands)
|
|
1048 `(progn
|
|
1049 (eshell-debug-command ,(eval tag) form)
|
|
1050 ,@commands
|
|
1051 (eshell-debug-command ,(concat "done " (eval tag)) form))))
|
|
1052
|
|
1053 (put 'eshell-manipulate 'lisp-indent-function 1)
|
|
1054
|
|
1055 ;; eshell-lookup-function, eshell-functionp, and eshell-macrop taken
|
|
1056 ;; from edebug
|
|
1057
|
|
1058 (defsubst eshell-lookup-function (object)
|
|
1059 "Return the ultimate function definition of OBJECT."
|
|
1060 (while (and (symbolp object) (fboundp object))
|
|
1061 (setq object (symbol-function object)))
|
|
1062 object)
|
|
1063
|
|
1064 (defconst function-p-func
|
48211
|
1065 (if (fboundp 'compiled-function-p)
|
29873
|
1066 'compiled-function-p
|
|
1067 'byte-code-function-p))
|
|
1068
|
|
1069 (defsubst eshell-functionp (object)
|
|
1070 "Returns the function named by OBJECT, or nil if it is not a function."
|
|
1071 (setq object (eshell-lookup-function object))
|
|
1072 (if (or (subrp object)
|
|
1073 (funcall function-p-func object)
|
|
1074 (and (listp object)
|
|
1075 (eq (car object) 'lambda)
|
|
1076 (listp (car (cdr object)))))
|
|
1077 object))
|
|
1078
|
|
1079 (defsubst eshell-macrop (object)
|
|
1080 "Return t if OBJECT is a macro or nil otherwise."
|
|
1081 (setq object (eshell-lookup-function object))
|
|
1082 (if (and (listp object)
|
|
1083 (eq 'macro (car object))
|
|
1084 (eshell-functionp (cdr object)))
|
|
1085 t))
|
|
1086
|
|
1087 (defun eshell-do-eval (form &optional synchronous-p)
|
|
1088 "Evaluate form, simplifying it as we go.
|
|
1089 Unless SYNCHRONOUS-P is non-nil, throws `eshell-defer' if it needs to
|
|
1090 be finished later after the completion of an asynchronous subprocess."
|
|
1091 (cond
|
|
1092 ((not (listp form))
|
|
1093 (list 'quote (eval form)))
|
|
1094 ((memq (car form) '(quote function))
|
|
1095 form)
|
|
1096 (t
|
|
1097 ;; skip past the call to `eshell-do-eval'
|
|
1098 (when (eq (car form) 'eshell-do-eval)
|
|
1099 (setq form (cadr (cadr form))))
|
|
1100 ;; expand any macros directly into the form. This is done so that
|
|
1101 ;; we can modify any `let' forms to evaluate only once.
|
|
1102 (if (eshell-macrop (car form))
|
|
1103 (let ((exp (eshell-copy-tree (macroexpand form))))
|
|
1104 (eshell-manipulate (format "expanding macro `%s'"
|
|
1105 (symbol-name (car form)))
|
|
1106 (setcar form (car exp))
|
|
1107 (setcdr form (cdr exp)))))
|
|
1108 (let ((args (cdr form)))
|
|
1109 (cond
|
|
1110 ((eq (car form) 'while)
|
|
1111 ;; `eshell-copy-tree' is needed here so that the test argument
|
|
1112 ;; doesn't get modified and thus always yield the same result.
|
|
1113 (when (car eshell-command-body)
|
|
1114 (assert (not synchronous-p))
|
|
1115 (eshell-do-eval (car eshell-command-body))
|
31241
|
1116 (setcar eshell-command-body nil)
|
|
1117 (setcar eshell-test-body nil))
|
29873
|
1118 (unless (car eshell-test-body)
|
|
1119 (setcar eshell-test-body (eshell-copy-tree (car args))))
|
31241
|
1120 (while (cadr (eshell-do-eval (car eshell-test-body)))
|
|
1121 (setcar eshell-command-body (eshell-copy-tree (cadr args)))
|
|
1122 (eshell-do-eval (car eshell-command-body) synchronous-p)
|
|
1123 (setcar eshell-command-body nil)
|
|
1124 (setcar eshell-test-body (eshell-copy-tree (car args))))
|
29873
|
1125 (setcar eshell-command-body nil))
|
|
1126 ((eq (car form) 'if)
|
|
1127 ;; `eshell-copy-tree' is needed here so that the test argument
|
|
1128 ;; doesn't get modified and thus always yield the same result.
|
31241
|
1129 (if (car eshell-command-body)
|
|
1130 (progn
|
|
1131 (assert (not synchronous-p))
|
|
1132 (eshell-do-eval (car eshell-command-body)))
|
|
1133 (unless (car eshell-test-body)
|
|
1134 (setcar eshell-test-body (eshell-copy-tree (car args))))
|
|
1135 (if (cadr (eshell-do-eval (car eshell-test-body)))
|
|
1136 (setcar eshell-command-body (eshell-copy-tree (cadr args)))
|
|
1137 (setcar eshell-command-body (eshell-copy-tree (car (cddr args)))))
|
|
1138 (eshell-do-eval (car eshell-command-body) synchronous-p))
|
|
1139 (setcar eshell-command-body nil)
|
|
1140 (setcar eshell-test-body nil))
|
29873
|
1141 ((eq (car form) 'setcar)
|
|
1142 (setcar (cdr args) (eshell-do-eval (cadr args) synchronous-p))
|
|
1143 (eval form))
|
|
1144 ((eq (car form) 'setcdr)
|
|
1145 (setcar (cdr args) (eshell-do-eval (cadr args) synchronous-p))
|
|
1146 (eval form))
|
|
1147 ((memq (car form) '(let catch condition-case unwind-protect))
|
|
1148 ;; `let', `condition-case' and `unwind-protect' have to be
|
|
1149 ;; handled specially, because we only want to call
|
|
1150 ;; `eshell-do-eval' on their first form.
|
|
1151 ;;
|
|
1152 ;; NOTE: This requires obedience by all forms which this
|
|
1153 ;; function might encounter, that they do not contain
|
|
1154 ;; other special forms.
|
|
1155 (if (and (eq (car form) 'let)
|
|
1156 (not (eq (car (cadr args)) 'eshell-do-eval)))
|
|
1157 (eshell-manipulate "evaluating let args"
|
|
1158 (eshell-for letarg (car args)
|
|
1159 (if (and (listp letarg)
|
|
1160 (not (eq (cadr letarg) 'quote)))
|
|
1161 (setcdr letarg
|
|
1162 (list (eshell-do-eval
|
|
1163 (cadr letarg) synchronous-p)))))))
|
|
1164 (unless (eq (car form) 'unwind-protect)
|
|
1165 (setq args (cdr args)))
|
|
1166 (unless (eq (caar args) 'eshell-do-eval)
|
|
1167 (eshell-manipulate "handling special form"
|
|
1168 (setcar args (list 'eshell-do-eval
|
|
1169 (list 'quote (car args))
|
|
1170 synchronous-p))))
|
|
1171 (eval form))
|
|
1172 (t
|
|
1173 (if (and args (not (memq (car form) '(run-hooks))))
|
|
1174 (eshell-manipulate
|
|
1175 (format "evaluating arguments to `%s'"
|
|
1176 (symbol-name (car form)))
|
|
1177 (while args
|
|
1178 (setcar args (eshell-do-eval (car args) synchronous-p))
|
|
1179 (setq args (cdr args)))))
|
|
1180 (cond
|
|
1181 ((eq (car form) 'progn)
|
|
1182 (car (last form)))
|
|
1183 ((eq (car form) 'prog1)
|
|
1184 (cadr form))
|
|
1185 (t
|
33020
|
1186 ;; If a command desire to replace its execution form with
|
|
1187 ;; another command form, all it needs to do is throw the new
|
|
1188 ;; form using the exception tag `eshell-replace-command'.
|
|
1189 ;; For example, let's say that the form currently being
|
|
1190 ;; eval'd is:
|
|
1191 ;;
|
|
1192 ;; (eshell-named-command "hello")
|
|
1193 ;;
|
|
1194 ;; Now, let's assume the 'hello' command is an Eshell alias,
|
|
1195 ;; the definition of which yields the command:
|
|
1196 ;;
|
|
1197 ;; (eshell-named-command "echo" (list "Hello" "world"))
|
|
1198 ;;
|
|
1199 ;; What the alias code would like to do is simply substitute
|
|
1200 ;; the alias form for the original form. To accomplish
|
|
1201 ;; this, all it needs to do is to throw the substitution
|
|
1202 ;; form with the `eshell-replace-command' tag, and the form
|
|
1203 ;; will be replaced within the current command, and
|
|
1204 ;; execution will then resume (iteratively) as before.
|
|
1205 ;; Thus, aliases can even contain references to asynchronous
|
|
1206 ;; sub-commands, and things will still work out as they
|
|
1207 ;; should.
|
29873
|
1208 (let (result new-form)
|
|
1209 (if (setq new-form
|
|
1210 (catch 'eshell-replace-command
|
|
1211 (ignore
|
|
1212 (setq result (eval form)))))
|
|
1213 (progn
|
|
1214 (eshell-manipulate "substituting replacement form"
|
|
1215 (setcar form (car new-form))
|
|
1216 (setcdr form (cdr new-form)))
|
|
1217 (eshell-do-eval form synchronous-p))
|
|
1218 (if (and (memq (car form) eshell-deferrable-commands)
|
|
1219 (not eshell-current-subjob-p)
|
|
1220 result
|
31241
|
1221 (eshell-processp result))
|
29873
|
1222 (if synchronous-p
|
|
1223 (eshell/wait result)
|
|
1224 (eshell-manipulate "inserting ignore form"
|
|
1225 (setcar form 'ignore)
|
|
1226 (setcdr form nil))
|
|
1227 (throw 'eshell-defer result))
|
|
1228 (list 'quote result))))))))))))
|
|
1229
|
|
1230 ;; command invocation
|
|
1231
|
|
1232 (defun eshell/which (command &rest names)
|
|
1233 "Identify the COMMAND, and where it is located."
|
|
1234 (eshell-for name (cons command names)
|
|
1235 (let (program alias direct)
|
37817
431f430082e9
(eshell/which): Use `eshell-explicit-command-char' instead of ?*.
John Wiegley <johnw@newartisans.com>
diff
changeset
|
1236 (if (eq (aref name 0) eshell-explicit-command-char)
|
29873
|
1237 (setq name (substring name 1)
|
|
1238 direct t))
|
|
1239 (if (and (not direct)
|
|
1240 (eshell-using-module 'eshell-alias)
|
|
1241 (setq alias
|
|
1242 (funcall (symbol-function 'eshell-lookup-alias)
|
|
1243 name)))
|
|
1244 (setq program
|
|
1245 (concat name " is an alias, defined as \""
|
|
1246 (cadr alias) "\"")))
|
|
1247 (unless program
|
|
1248 (setq program (eshell-search-path name))
|
|
1249 (let* ((esym (eshell-find-alias-function name))
|
|
1250 (sym (or esym (intern-soft name))))
|
55968
|
1251 (if (and (or esym (and sym (fboundp sym)))
|
|
1252 (or eshell-prefer-lisp-functions (not direct)))
|
29873
|
1253 (let ((desc (let ((inhibit-redisplay t))
|
|
1254 (save-window-excursion
|
|
1255 (prog1
|
|
1256 (describe-function sym)
|
|
1257 (message nil))))))
|
|
1258 (setq desc (substring desc 0
|
|
1259 (1- (or (string-match "\n" desc)
|
|
1260 (length desc)))))
|
31241
|
1261 (if (buffer-live-p (get-buffer "*Help*"))
|
|
1262 (kill-buffer "*Help*"))
|
29873
|
1263 (setq program (or desc name))))))
|
|
1264 (if (not program)
|
|
1265 (eshell-error (format "which: no %s in (%s)\n"
|
|
1266 name (getenv "PATH")))
|
|
1267 (eshell-printn program)))))
|
|
1268
|
37662
cb20d33bef50
(eshell-lisp-command): Don't perform numeric conversions if a Lisp
John Wiegley <johnw@newartisans.com>
diff
changeset
|
1269 (put 'eshell/which 'eshell-no-numeric-conversions t)
|
cb20d33bef50
(eshell-lisp-command): Don't perform numeric conversions if a Lisp
John Wiegley <johnw@newartisans.com>
diff
changeset
|
1270
|
29873
|
1271 (defun eshell-named-command (command &optional args)
|
|
1272 "Insert output from a plain COMMAND, using ARGS.
|
|
1273 COMMAND may result in an alias being executed, or a plain command."
|
|
1274 (setq eshell-last-arguments args
|
|
1275 eshell-last-command-name (eshell-stringify command))
|
|
1276 (run-hook-with-args 'eshell-prepare-command-hook)
|
|
1277 (assert (stringp eshell-last-command-name))
|
|
1278 (if eshell-last-command-name
|
|
1279 (or (run-hook-with-args-until-success
|
|
1280 'eshell-named-command-hook eshell-last-command-name
|
|
1281 eshell-last-arguments)
|
|
1282 (eshell-plain-command eshell-last-command-name
|
|
1283 eshell-last-arguments))))
|
|
1284
|
|
1285 (defalias 'eshell-named-command* 'eshell-named-command)
|
|
1286
|
|
1287 (defun eshell-find-alias-function (name)
|
|
1288 "Check whether a function called `eshell/NAME' exists."
|
|
1289 (let* ((sym (intern-soft (concat "eshell/" name)))
|
59121
|
1290 (file (symbol-file sym 'defun)))
|
37442
f4b209194d8c
(eshell-find-alias-function): Return t in the case where the function
John Wiegley <johnw@newartisans.com>
diff
changeset
|
1291 ;; If the function exists, but is defined in an eshell module
|
f4b209194d8c
(eshell-find-alias-function): Return t in the case where the function
John Wiegley <johnw@newartisans.com>
diff
changeset
|
1292 ;; that's not currently enabled, don't report it as found
|
29873
|
1293 (if (and file
|
|
1294 (string-match "\\(em\\|esh\\)-\\(.*\\)\\(\\.el\\)?\\'" file))
|
37442
f4b209194d8c
(eshell-find-alias-function): Return t in the case where the function
John Wiegley <johnw@newartisans.com>
diff
changeset
|
1295 (let ((module-sym
|
29873
|
1296 (intern (file-name-sans-extension
|
37442
f4b209194d8c
(eshell-find-alias-function): Return t in the case where the function
John Wiegley <johnw@newartisans.com>
diff
changeset
|
1297 (file-name-nondirectory
|
f4b209194d8c
(eshell-find-alias-function): Return t in the case where the function
John Wiegley <johnw@newartisans.com>
diff
changeset
|
1298 (concat "eshell-" (match-string 2 file)))))))
|
37450
b1c5785dbec5
(eshell-find-alias-function): Corrected the fix from last night, since
John Wiegley <johnw@newartisans.com>
diff
changeset
|
1299 (if (and (functionp sym)
|
b1c5785dbec5
(eshell-find-alias-function): Corrected the fix from last night, since
John Wiegley <johnw@newartisans.com>
diff
changeset
|
1300 (or (null module-sym)
|
b1c5785dbec5
(eshell-find-alias-function): Corrected the fix from last night, since
John Wiegley <johnw@newartisans.com>
diff
changeset
|
1301 (eshell-using-module module-sym)
|
b1c5785dbec5
(eshell-find-alias-function): Corrected the fix from last night, since
John Wiegley <johnw@newartisans.com>
diff
changeset
|
1302 (memq module-sym (eshell-subgroups 'eshell))))
|
37442
f4b209194d8c
(eshell-find-alias-function): Return t in the case where the function
John Wiegley <johnw@newartisans.com>
diff
changeset
|
1303 sym))
|
f4b209194d8c
(eshell-find-alias-function): Return t in the case where the function
John Wiegley <johnw@newartisans.com>
diff
changeset
|
1304 ;; Otherwise, if it's bound, return it.
|
f4b209194d8c
(eshell-find-alias-function): Return t in the case where the function
John Wiegley <johnw@newartisans.com>
diff
changeset
|
1305 (if (functionp sym)
|
f4b209194d8c
(eshell-find-alias-function): Return t in the case where the function
John Wiegley <johnw@newartisans.com>
diff
changeset
|
1306 sym))))
|
29873
|
1307
|
|
1308 (defun eshell-plain-command (command args)
|
|
1309 "Insert output from a plain COMMAND, using ARGS.
|
|
1310 COMMAND may result in either a Lisp function being executed by name,
|
|
1311 or an external command."
|
|
1312 (let* ((esym (eshell-find-alias-function command))
|
|
1313 (sym (or esym (intern-soft command))))
|
|
1314 (if (and sym (fboundp sym)
|
|
1315 (or esym eshell-prefer-lisp-functions
|
|
1316 (not (eshell-search-path command))))
|
|
1317 (eshell-lisp-command sym args)
|
|
1318 (eshell-external-command command args))))
|
|
1319
|
|
1320 (defun eshell-exec-lisp (printer errprint func-or-form args form-p)
|
|
1321 "Execute a lisp FUNC-OR-FORM, maybe passing ARGS.
|
|
1322 PRINTER and ERRPRINT are functions to use for printing regular
|
|
1323 messages, and errors. FORM-P should be non-nil if FUNC-OR-FORM
|
|
1324 represent a lisp form; ARGS will be ignored in that case."
|
|
1325 (let (result)
|
|
1326 (eshell-condition-case err
|
|
1327 (progn
|
|
1328 (setq result
|
|
1329 (save-current-buffer
|
|
1330 (if form-p
|
|
1331 (eval func-or-form)
|
|
1332 (apply func-or-form args))))
|
|
1333 (and result (funcall printer result))
|
|
1334 result)
|
|
1335 (error
|
|
1336 (let ((msg (error-message-string err)))
|
|
1337 (if (and (not form-p)
|
|
1338 (string-match "^Wrong number of arguments" msg)
|
|
1339 (fboundp 'eldoc-get-fnsym-args-string))
|
|
1340 (let ((func-doc (eldoc-get-fnsym-args-string func-or-form)))
|
|
1341 (setq msg (format "usage: %s" func-doc))))
|
|
1342 (funcall errprint msg))
|
|
1343 nil))))
|
|
1344
|
|
1345 (defsubst eshell-apply* (printer errprint func args)
|
|
1346 "Call FUNC, with ARGS, trapping errors and return them as output.
|
|
1347 PRINTER and ERRPRINT are functions to use for printing regular
|
|
1348 messages, and errors."
|
|
1349 (eshell-exec-lisp printer errprint func args nil))
|
|
1350
|
|
1351 (defsubst eshell-funcall* (printer errprint func &rest args)
|
|
1352 "Call FUNC, with ARGS, trapping errors and return them as output."
|
|
1353 (eshell-apply* printer errprint func args))
|
|
1354
|
|
1355 (defsubst eshell-eval* (printer errprint form)
|
|
1356 "Evaluate FORM, trapping errors and returning them."
|
|
1357 (eshell-exec-lisp printer errprint form nil t))
|
|
1358
|
|
1359 (defsubst eshell-apply (func args)
|
|
1360 "Call FUNC, with ARGS, trapping errors and return them as output.
|
|
1361 PRINTER and ERRPRINT are functions to use for printing regular
|
|
1362 messages, and errors."
|
|
1363 (eshell-apply* 'eshell-print 'eshell-error func args))
|
|
1364
|
|
1365 (defsubst eshell-funcall (func &rest args)
|
|
1366 "Call FUNC, with ARGS, trapping errors and return them as output."
|
|
1367 (eshell-apply func args))
|
|
1368
|
|
1369 (defsubst eshell-eval (form)
|
|
1370 "Evaluate FORM, trapping errors and returning them."
|
|
1371 (eshell-eval* 'eshell-print 'eshell-error form))
|
|
1372
|
|
1373 (defsubst eshell-applyn (func args)
|
|
1374 "Call FUNC, with ARGS, trapping errors and return them as output.
|
|
1375 PRINTER and ERRPRINT are functions to use for printing regular
|
|
1376 messages, and errors."
|
|
1377 (eshell-apply* 'eshell-printn 'eshell-errorn func args))
|
|
1378
|
|
1379 (defsubst eshell-funcalln (func &rest args)
|
|
1380 "Call FUNC, with ARGS, trapping errors and return them as output."
|
|
1381 (eshell-applyn func args))
|
|
1382
|
|
1383 (defsubst eshell-evaln (form)
|
|
1384 "Evaluate FORM, trapping errors and returning them."
|
|
1385 (eshell-eval* 'eshell-printn 'eshell-errorn form))
|
|
1386
|
|
1387 (defun eshell-lisp-command (object &optional args)
|
|
1388 "Insert Lisp OBJECT, using ARGS if a function."
|
|
1389 (catch 'eshell-external ; deferred to an external command
|
|
1390 (let* ((eshell-ensure-newline-p (eshell-interactive-output-p))
|
|
1391 (result
|
|
1392 (if (functionp object)
|
37662
cb20d33bef50
(eshell-lisp-command): Don't perform numeric conversions if a Lisp
John Wiegley <johnw@newartisans.com>
diff
changeset
|
1393 (progn
|
cb20d33bef50
(eshell-lisp-command): Don't perform numeric conversions if a Lisp
John Wiegley <johnw@newartisans.com>
diff
changeset
|
1394 (setq eshell-last-arguments args
|
cb20d33bef50
(eshell-lisp-command): Don't perform numeric conversions if a Lisp
John Wiegley <johnw@newartisans.com>
diff
changeset
|
1395 eshell-last-command-name
|
cb20d33bef50
(eshell-lisp-command): Don't perform numeric conversions if a Lisp
John Wiegley <johnw@newartisans.com>
diff
changeset
|
1396 (concat "#<function " (symbol-name object) ">"))
|
cb20d33bef50
(eshell-lisp-command): Don't perform numeric conversions if a Lisp
John Wiegley <johnw@newartisans.com>
diff
changeset
|
1397 ;; if any of the arguments are flagged as numbers
|
cb20d33bef50
(eshell-lisp-command): Don't perform numeric conversions if a Lisp
John Wiegley <johnw@newartisans.com>
diff
changeset
|
1398 ;; waiting for conversion, convert them now
|
cb20d33bef50
(eshell-lisp-command): Don't perform numeric conversions if a Lisp
John Wiegley <johnw@newartisans.com>
diff
changeset
|
1399 (unless (get object 'eshell-no-numeric-conversions)
|
cb20d33bef50
(eshell-lisp-command): Don't perform numeric conversions if a Lisp
John Wiegley <johnw@newartisans.com>
diff
changeset
|
1400 (while args
|
cb20d33bef50
(eshell-lisp-command): Don't perform numeric conversions if a Lisp
John Wiegley <johnw@newartisans.com>
diff
changeset
|
1401 (let ((arg (car args)))
|
cb20d33bef50
(eshell-lisp-command): Don't perform numeric conversions if a Lisp
John Wiegley <johnw@newartisans.com>
diff
changeset
|
1402 (if (and (stringp arg)
|
cb20d33bef50
(eshell-lisp-command): Don't perform numeric conversions if a Lisp
John Wiegley <johnw@newartisans.com>
diff
changeset
|
1403 (> (length arg) 0)
|
53051
bf3ee9e2ceda
(eshell-lisp-command): Do not late-convert string arguments to numbers
John Wiegley <johnw@newartisans.com>
diff
changeset
|
1404 (not (text-property-not-all
|
bf3ee9e2ceda
(eshell-lisp-command): Do not late-convert string arguments to numbers
John Wiegley <johnw@newartisans.com>
diff
changeset
|
1405 0 (length arg) 'number t arg)))
|
37665
|
1406 (setcar args (string-to-number arg))))
|
37662
cb20d33bef50
(eshell-lisp-command): Don't perform numeric conversions if a Lisp
John Wiegley <johnw@newartisans.com>
diff
changeset
|
1407 (setq args (cdr args))))
|
cb20d33bef50
(eshell-lisp-command): Don't perform numeric conversions if a Lisp
John Wiegley <johnw@newartisans.com>
diff
changeset
|
1408 (eshell-apply object eshell-last-arguments))
|
cb20d33bef50
(eshell-lisp-command): Don't perform numeric conversions if a Lisp
John Wiegley <johnw@newartisans.com>
diff
changeset
|
1409 (setq eshell-last-arguments args
|
cb20d33bef50
(eshell-lisp-command): Don't perform numeric conversions if a Lisp
John Wiegley <johnw@newartisans.com>
diff
changeset
|
1410 eshell-last-command-name "#<Lisp object>")
|
29873
|
1411 (eshell-eval object))))
|
|
1412 (if (and eshell-ensure-newline-p
|
|
1413 (save-excursion
|
|
1414 (goto-char eshell-last-output-end)
|
|
1415 (not (bolp))))
|
|
1416 (eshell-print "\n"))
|
|
1417 (eshell-close-handles 0 (list 'quote result)))))
|
|
1418
|
|
1419 (defalias 'eshell-lisp-command* 'eshell-lisp-command)
|
|
1420
|
52401
|
1421 ;;; arch-tag: 8e4f3867-a0c5-441f-96ba-ddd142d94366
|
29873
|
1422 ;;; esh-cmd.el ends here
|