]> git.eshelyaron.com Git - emacs.git/commitdiff
*** empty log message ***
authorGerd Moellmann <gerd@gnu.org>
Fri, 23 Jun 2000 04:54:41 +0000 (04:54 +0000)
committerGerd Moellmann <gerd@gnu.org>
Fri, 23 Jun 2000 04:54:41 +0000 (04:54 +0000)
lisp/ChangeLog
lisp/eshell/esh-cmd.el [new file with mode: 0644]

index 61460d51a29236b8cd4aa5578cea2b566633394d..22877bb833526b899b8194eabf459d376516d75f 100644 (file)
@@ -1,5 +1,11 @@
 2000-06-23  Gerd Moellmann  <gerd@gnu.org>
 
+       * eshell/esh-util.el (eshell-sublist): Use eshell-copy-list
+       instead of copy-list.
+
+       * eshell/esh-mode.el (eshell-mode): Use eshell-copy-list instead
+       of copy-list.
+
        * subdirs.el: Add eshell subdirectory.
 
        * eshell: New subdirectory containing the Eshell package.
diff --git a/lisp/eshell/esh-cmd.el b/lisp/eshell/esh-cmd.el
new file mode 100644 (file)
index 0000000..b75a371
--- /dev/null
@@ -0,0 +1,1314 @@
+;;; esh-cmd --- command invocation
+
+;; Copyright (C) 1999, 2000 Free Sofware Foundation
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING.  If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+(provide 'esh-cmd)
+
+(eval-when-compile (require 'esh-maint))
+
+(defgroup eshell-cmd nil
+  "Executing an Eshell command is as simple as typing it in and
+pressing <RET>.  There are several different kinds of commands,
+however."
+  :tag "Command invocation"
+  :link '(info-link "(eshell.info)Command invocation")
+  :group 'eshell)
+
+;;; Commentary:
+
+;;;_* Invoking external commands
+;;
+;; External commands cause processes to be created, by loading
+;; external executables into memory.  This is what most normal shells
+;; do, most of the time.  For more information, see [External commands].
+;;
+;;;_* Invoking Lisp functions
+;;
+;; A Lisp function can be invoked using Lisp syntax, or command shell
+;; syntax.  For example, to run `dired' to edit the current directory:
+;;
+;;   /tmp $ (dired ".")
+;;
+;; Or:
+;;
+;;   /tmp $ dired .
+;;
+;; The latter form is preferable, but the former is more precise,
+;; since it involves no translations.  See [Argument parsing], to
+;; learn more about how arguments are transformed before passing them
+;; to commands.
+;;
+;; Ordinarily, if 'dired' were also available as an external command,
+;; the external version would be called in preference to any Lisp
+;; function of the same name.  To change this behavior so that Lisp
+;; functions always take precedence, set
+;; `eshell-prefer-lisp-functions' to t.
+
+(defcustom eshell-prefer-lisp-functions nil
+  "*If non-nil, prefer Lisp functions to external commands."
+  :type 'boolean
+  :group 'eshell-cmd)
+
+;;;_* Alias functions
+;;
+;; Whenever a command is specified using a simple name, such as 'ls',
+;; Eshell will first look for a Lisp function of the name `eshell/ls'.
+;; If it exists, it will be called in preference to any other command
+;; which might have matched the name 'ls' (such as command aliases,
+;; external commands, Lisp functions of that name, etc).
+;;
+;; This is the most flexible mechanism for creating new commands,
+;; since it does not pollute the global namespace, yet allows you to
+;; use all of Lisp's facilities to define that piece of functionality.
+;; Most of Eshell's "builtin" commands are defined as alias functions.
+;;
+;;;_* Lisp arguments
+;;
+;; It is possible to invoke a Lisp form as an argument.  This can be
+;; done either by specifying the form as you might in Lisp, or by
+;; using the '$' character to introduce a value-interpolation:
+;;
+;;   echo (+ 1 2)
+;;
+;; Or
+;;
+;;   echo $(+ 1 2)
+;;
+;; The two forms are equivalent.  The second is required only if the
+;; form being interpolated is within a string, or is a subexpression
+;; of a larger argument:
+;;
+;;   echo x$(+ 1 2) "String $(+ 1 2)"
+;;
+;; To pass a Lisp symbol as a argument, use the alternate quoting
+;; syntax, since the single quote character is far too overused in
+;; shell syntax:
+;;
+;;   echo #'lisp-symbol
+;;
+;; Backquote can also be used:
+;;
+;;   echo `(list ,lisp-symbol)
+;;
+;; Lisp arguments are identified using the following regexp:
+
+(defcustom eshell-lisp-regexp "\\([(`]\\|#'\\)"
+  "*A regexp which, if matched at beginning of an argument, means Lisp.
+Such arguments will be passed to `read', and then evaluated."
+  :type 'regexp
+  :group 'eshell-cmd)
+
+;;;_* Command hooks
+;;
+;; There are several hooks involved with command execution, which can
+;; be used either to change or augment Eshell's behavior.
+
+(defcustom eshell-pre-command-hook nil
+  "*A hook run before each interactive command is invoked."
+  :type 'hook
+  :group 'eshell-cmd)
+
+(defcustom eshell-post-command-hook nil
+  "*A hook run after each interactive command is invoked."
+  :type 'hook
+  :group 'eshell-cmd)
+
+(defcustom eshell-prepare-command-hook nil
+  "*A set of functions called to prepare a named command.
+The command name and its argument are in `eshell-last-command-name'
+and `eshell-last-arguments'.  The functions on this hook can change
+the value of these symbols if necessary.
+
+To prevent a command from executing at all, set
+`eshell-last-command-name' to nil."
+  :type 'hook
+  :group 'eshell-cmd)
+
+(defcustom eshell-named-command-hook nil
+  "*A set of functions called before a named command is invoked.
+Each function will be passed the command name and arguments that were
+passed to `eshell-named-command'.
+
+If any of the functions returns a non-nil value, the named command
+will not be invoked, and that value will be returned from
+`eshell-named-command'.
+
+In order to substitute an alternate command form for execution, the
+hook function should throw it using the tag `eshell-replace-command'.
+For example:
+
+  (add-hook 'eshell-named-command-hook 'subst-with-cd)
+  (defun subst-with-cd (command args)
+    (throw 'eshell-replace-command
+          (eshell-parse-command \"cd\" args)))
+
+Although useless, the above code will cause any non-glob, non-Lisp
+command (i.e., 'ls' as opposed to '*ls' or '(ls)') to be replaced by a
+call to `cd' using the arguments that were passed to the function."
+  :type 'hook
+  :group 'eshell-cmd)
+
+(defcustom eshell-pre-rewrite-command-hook
+  '(eshell-no-command-conversion
+    eshell-subcommand-arg-values)
+  "*A hook run before command rewriting begins.
+The terms of the command to be rewritten is passed as arguments, and
+may be modified in place.  Any return value is ignored."
+  :type 'hook
+  :group 'eshell-cmd)
+
+(defcustom eshell-rewrite-command-hook
+  '(eshell-rewrite-for-command
+    eshell-rewrite-while-command
+    eshell-rewrite-if-command
+    eshell-rewrite-sexp-command
+    eshell-rewrite-initial-subcommand
+    eshell-rewrite-named-command)
+  "*A set of functions used to rewrite the command argument.
+Once parsing of a command line is completed, the next step is to
+rewrite the initial argument into something runnable.
+
+A module may wish to associate special behavior with certain argument
+syntaxes at the beginning of a command line.  They are welcome to do
+so by adding a function to this hook.  The first function to return a
+substitute command form is the one used.  Each function is passed the
+command's full argument list, which is a list of sexps (typically
+forms or strings)."
+  :type 'hook
+  :group 'eshell-cmd)
+
+(defcustom eshell-post-rewrite-command-hook nil
+  "*A hook run after command rewriting is finished.
+Each function is passed the symbol containing the rewritten command,
+which may be modified directly.  Any return value is ignored."
+  :type 'hook
+  :group 'eshell-cmd)
+
+;;; Code:
+
+(require 'esh-util)
+(unless (eshell-under-xemacs-p)
+  (require 'eldoc))
+(require 'esh-arg)
+(require 'esh-proc)
+(require 'esh-ext)
+
+;;; User Variables:
+
+(defcustom eshell-cmd-load-hook '(eshell-cmd-initialize)
+  "*A hook that gets run when `eshell-cmd' is loaded."
+  :type 'hook
+  :group 'eshell-cmd)
+
+(defcustom eshell-debug-command nil
+  "*If non-nil, enable debugging code.  SSLLOOWW.
+This option is only useful for reporting bugs.  If you enable it, you
+will have to visit the file 'eshell-cmd.el' and run the command
+\\[eval-buffer]."
+  :type 'boolean
+  :group 'eshell-cmd)
+
+(defcustom eshell-deferrable-commands
+  '(eshell-named-command
+    eshell-lisp-command
+    eshell-process-identity)
+  "*A list of functions which might return an ansychronous process.
+If they return a process object, execution of the calling Eshell
+command will wait for completion (in the background) before finishing
+the command."
+  :type '(repeat function)
+  :group 'eshell-cmd)
+
+(defcustom eshell-subcommand-bindings
+  '((eshell-in-subcommand-p t)
+    (default-directory default-directory)
+    (process-environment (eshell-copy-environment)))
+  "*A list of `let' bindings for subcommand environments."
+  :type 'sexp
+  :group 'eshell-cmd)
+
+(put 'risky-local-variable 'eshell-subcommand-bindings t)
+
+(defvar eshell-ensure-newline-p nil
+  "If non-nil, ensure that a newline is emitted after a Lisp form.
+This can be changed by Lisp forms that are evaluated from the Eshell
+command line.")
+
+;;; Internal Variables:
+
+(defvar eshell-current-command nil)
+(defvar eshell-command-name nil)
+(defvar eshell-command-arguments nil)
+(defvar eshell-in-pipeline-p nil)
+(defvar eshell-in-subcommand-p nil)
+(defvar eshell-last-arguments nil)
+(defvar eshell-last-command-name nil)
+(defvar eshell-last-async-proc nil
+  "When this foreground process completes, resume command evaluation.")
+
+;;; Functions:
+
+(defsubst eshell-interactive-process ()
+  "Return currently running command process, if non-Lisp."
+  eshell-last-async-proc)
+
+(defun eshell-cmd-initialize ()
+  "Initialize the Eshell command processing module."
+  (set (make-local-variable 'eshell-current-command) nil)
+  (set (make-local-variable 'eshell-command-name) nil)
+  (set (make-local-variable 'eshell-command-arguments) nil)
+  (set (make-local-variable 'eshell-last-arguments) nil)
+  (set (make-local-variable 'eshell-last-command-name) nil)
+  (set (make-local-variable 'eshell-last-async-proc) nil)
+
+  (make-local-hook 'eshell-kill-hook)
+  (add-hook 'eshell-kill-hook 'eshell-resume-command nil t)
+
+  ;; make sure that if a command is over, and no process is being
+  ;; waited for, that `eshell-current-command' is set to nil.  This
+  ;; situation can occur, for example, if a Lisp function results in
+  ;; `debug' being called, and the user then types \\[top-level]
+  (make-local-hook 'eshell-post-command-hook)
+  (add-hook 'eshell-post-command-hook
+           (function
+            (lambda ()
+              (setq eshell-current-command nil
+                    eshell-last-async-proc nil))) nil t)
+
+  (make-local-hook 'eshell-parse-argument-hook)
+  (add-hook 'eshell-parse-argument-hook
+           'eshell-parse-subcommand-argument nil t)
+  (add-hook 'eshell-parse-argument-hook
+           'eshell-parse-lisp-argument nil t)
+
+  (when (eshell-using-module 'eshell-cmpl)
+    (make-local-hook 'pcomplete-try-first-hook)
+    (add-hook 'pcomplete-try-first-hook
+             'eshell-complete-lisp-symbols nil t)))
+
+(eshell-deftest var last-result-var
+  "\"last result\" variable"
+  (eshell-command-result-p "+ 1 2; + $$ 2" "3\n5\n"))
+
+(eshell-deftest var last-result-var2
+  "\"last result\" variable"
+  (eshell-command-result-p "+ 1 2; + $$ $$" "3\n6\n"))
+
+(eshell-deftest var last-arg-var
+  "\"last arg\" variable"
+  (eshell-command-result-p "+ 1 2; + $_ 4" "3\n6\n"))
+
+(defun eshell-complete-lisp-symbols ()
+  "If there is a user reference, complete it."
+  (let ((arg (pcomplete-actual-arg)))
+    (when (string-match (concat "\\`" eshell-lisp-regexp) arg)
+      (setq pcomplete-stub (substring arg (match-end 0))
+           pcomplete-last-completion-raw t)
+      (throw 'pcomplete-completions
+            (all-completions pcomplete-stub obarray 'boundp)))))
+
+;; Command parsing
+
+(defun eshell-parse-command (command &optional args top-level)
+  "Parse the COMMAND, adding ARGS if given.
+COMMAND can either be a string, or a cons cell demarcating a buffer
+region.  TOP-LEVEL, if non-nil, means that the outermost command (the
+user's input command) is being parsed, and that pre and post command
+hooks should be run before and after the command."
+  (let* (sep-terms
+        (terms
+         (append
+          (if (consp command)
+              (eshell-parse-arguments (car command) (cdr command))
+            (let ((here (point))
+                  (inhibit-point-motion-hooks t)
+                  after-change-functions)
+              (insert command)
+              (prog1
+                  (eshell-parse-arguments here (point))
+                (delete-region here (point)))))
+          args))
+        (commands
+         (mapcar
+          (function
+           (lambda (cmd)
+             (if (or (not (car sep-terms))
+                     (string= (car sep-terms) ";"))
+                 (setq cmd
+                       (eshell-parse-pipeline cmd (not (car sep-terms))))
+               (setq cmd
+                     (list 'eshell-do-subjob
+                           (list 'list (eshell-parse-pipeline cmd)))))
+             (setq sep-terms (cdr sep-terms))
+             (if eshell-in-pipeline-p
+                 cmd
+               (list 'eshell-trap-errors cmd))))
+          (eshell-separate-commands terms "[&;]" nil 'sep-terms))))
+    (let ((cmd commands))
+      (while cmd
+       (if (cdr cmd)
+           (setcar cmd (list 'eshell-commands (car cmd))))
+       (setq cmd (cdr cmd))))
+    (setq commands
+         (append (list 'progn)
+                 (if top-level
+                     (list '(run-hooks 'eshell-pre-command-hook)))
+                 (if (not top-level)
+                     commands
+                   (list
+                    (list 'catch (quote 'top-level)
+                          (append (list 'progn) commands))
+                    '(run-hooks 'eshell-post-command-hook)))))
+    (if top-level
+       (list 'eshell-commands commands)
+      commands)))
+
+(defun eshell-debug-show-parsed-args (terms)
+  "Display parsed arguments in the debug buffer."
+  (ignore
+   (if eshell-debug-command
+       (eshell-debug-command "parsed arguments" terms))))
+
+(defun eshell-no-command-conversion (terms)
+  "Don't convert the command argument."
+  (ignore
+   (if (and (listp (car terms))
+           (eq (caar terms) 'eshell-convert))
+       (setcar terms (cadr (car terms))))))
+
+(defun eshell-subcommand-arg-values (terms)
+  "Convert subcommand arguments {x} to ${x}, in order to take their values."
+  (setq terms (cdr terms))             ; skip command argument
+  (while terms
+    (if (and (listp (car terms))
+            (eq (caar terms) 'eshell-as-subcommand))
+       (setcar terms (list 'eshell-convert
+                           (list 'eshell-command-to-value
+                                 (car terms)))))
+    (setq terms (cdr terms))))
+
+(defun eshell-rewrite-sexp-command (terms)
+  "Rewrite a sexp in initial position, such as '(+ 1 2)'."
+  ;; this occurs when a Lisp expression is in first position
+  (if (and (listp (car terms))
+          (eq (caar terms) 'eshell-command-to-value))
+      (car (cdar terms))))
+
+(eshell-deftest cmd lisp-command
+  "Evaluate Lisp command"
+  (eshell-command-result-p "(+ 1 2)" "3"))
+
+(eshell-deftest cmd lisp-command-args
+  "Evaluate Lisp command (ignore args)"
+  (eshell-command-result-p "(+ 1 2) 3" "3"))
+
+(defun eshell-rewrite-initial-subcommand (terms)
+  "Rewrite a subcommand in initial position, such as '{+ 1 2}'."
+  (if (and (listp (car terms))
+          (eq (caar terms) 'eshell-as-subcommand))
+      (car terms)))
+
+(eshell-deftest cmd subcommand
+  "Run subcommand"
+  (eshell-command-result-p "{+ 1 2}" "3\n"))
+
+(eshell-deftest cmd subcommand-args
+  "Run subcommand (ignore args)"
+  (eshell-command-result-p "{+ 1 2} 3" "3\n"))
+
+(eshell-deftest cmd subcommand-lisp
+  "Run subcommand + Lisp form"
+  (eshell-command-result-p "{(+ 1 2)}" "3\n"))
+
+(defun eshell-rewrite-named-command (terms)
+  "If no other rewriting rule transforms TERMS, assume a named command."
+  (list (if eshell-in-pipeline-p
+           'eshell-named-command*
+         'eshell-named-command)
+       (car terms)
+       (and (cdr terms)
+            (append (list 'list) (cdr terms)))))
+
+(eshell-deftest cmd named-command
+  "Execute named command"
+  (eshell-command-result-p "+ 1 2" "3\n"))
+
+(eval-when-compile
+  (defvar eshell-command-body)
+  (defvar eshell-test-body))
+
+(defsubst eshell-invokify-arg (arg &optional share-output silent)
+  "Change ARG so it can be invoked from a structured command.
+
+SHARE-OUTPUT, if non-nil, means this invocation should share the
+current output stream, which is separately redirectable.  SILENT
+means the user and/or any redirections shouldn't see any output
+from this command.  If both SHARE-OUTPUT and SILENT are non-nil,
+the second is ignored."
+  ;; something that begins with `eshell-convert' means that it
+  ;; intends to return a Lisp value.  We want to get past this,
+  ;; but if it's not _actually_ a value interpolation -- in which
+  ;; we leave it alone.  In fact, the only time we muck with it
+  ;; is in the case of a {subcommand} that has been turned into
+  ;; the interpolation, ${subcommand}, by the parser because it
+  ;; didn't know better.
+  (if (and (listp arg)
+          (eq (car arg) 'eshell-convert)
+          (eq (car (cadr arg)) 'eshell-command-to-value))
+      (if share-output
+         (cadr (cadr arg))
+       (list 'eshell-commands (cadr (cadr arg))
+             silent))
+    arg))
+
+(defun eshell-rewrite-for-command (terms)
+  "Rewrite a `for' command into its equivalent Eshell command form.
+Because the implementation of `for' relies upon conditional evaluation
+of its argumbent (i.e., use of a Lisp special form), it must be
+implemented via rewriting, rather than as a function."
+  (if (and (stringp (car terms))
+          (string= (car terms) "for")
+          (stringp (nth 2 terms))
+          (string= (nth 2 terms) "in"))
+      (let ((body (car (last terms))))
+       (setcdr (last terms 2) nil)
+       (list
+        'let (list (list 'for-items
+                         (append
+                          (list 'append)
+                          (mapcar
+                           (function
+                            (lambda (elem)
+                              (if (listp elem)
+                                  elem
+                                (list 'list elem))))
+                           (cdddr terms))))
+                   (list 'eshell-command-body
+                         (list 'quote (list nil)))
+                   (list 'eshell-test-body
+                         (list 'quote (list nil))))
+        (list
+         'progn
+         (list
+          'while (list 'car (list 'symbol-value
+                                  (list 'quote 'for-items)))
+          (list
+           'progn
+           (list 'let
+                 (list (list (intern (cadr terms))
+                             (list 'car
+                                   (list 'symbol-value
+                                         (list 'quote 'for-items)))))
+                 (list 'eshell-protect
+                       (eshell-invokify-arg body t)))
+           (list 'setcar 'for-items
+                 (list 'cadr
+                       (list 'symbol-value
+                             (list 'quote 'for-items))))
+           (list 'setcdr 'for-items
+                 (list 'cddr
+                       (list 'symbol-value
+                             (list 'quote 'for-items))))))
+         (list 'eshell-close-handles
+               'eshell-last-command-status
+               (list 'list (quote 'quote)
+                     'eshell-last-command-result)))))))
+
+(defun eshell-structure-basic-command (func names keyword test body
+                                           &optional else vocal-test)
+  "With TERMS, KEYWORD, and two NAMES, structure a basic command.
+The first of NAMES should be the positive form, and the second the
+negative.  It's not likely that users should ever need to call this
+function.
+
+If VOCAL-TEST is non-nil, it means output from the test should be
+shown, as well as output from the body."
+  ;; If the test form begins with `eshell-convert', it means
+  ;; something data-wise will be returned, and we should let
+  ;; that determine the truth of the statement.
+  (unless (eq (car test) 'eshell-convert)
+    (setq test
+         (list 'progn test
+               (list 'eshell-exit-success-p))))
+
+  ;; should we reverse the sense of the test?  This depends
+  ;; on the `names' parameter.  If it's the symbol nil, yes.
+  ;; Otherwise, it can be a pair of strings; if the keyword
+  ;; we're using matches the second member of that pair (a
+  ;; list), we should reverse it.
+  (if (or (eq names nil)
+         (and (listp names)
+              (string= keyword (cadr names))))
+      (setq test (list 'not test)))
+
+  ;; finally, create the form that represents this structured
+  ;; command
+  (list
+   'let (list (list 'eshell-command-body
+                   (list 'quote (list nil)))
+             (list 'eshell-test-body
+                   (list 'quote (list nil))))
+   (list func test body else)
+   (list 'eshell-close-handles
+        'eshell-last-command-status
+        (list 'list (quote 'quote)
+              'eshell-last-command-result))))
+
+(defun eshell-rewrite-while-command (terms)
+  "Rewrite a `while' command into its equivalent Eshell command form.
+Because the implementation of `while' relies upon conditional
+evaluation of its argument (i.e., use of a Lisp special form), it
+must be implemented via rewriting, rather than as a function."
+  (if (and (stringp (car terms))
+          (member (car terms) '("while" "until")))
+      (eshell-structure-basic-command
+       'while '("while" "until") (car terms)
+       (eshell-invokify-arg (cadr terms) nil t)
+       (list 'eshell-protect
+            (eshell-invokify-arg (car (last terms)) t)))))
+
+(defun eshell-rewrite-if-command (terms)
+  "Rewrite an `if' command into its equivalent Eshell command form.
+Because the implementation of `if' relies upon conditional
+evaluation of its argument (i.e., use of a Lisp special form), it
+must be implemented via rewriting, rather than as a function."
+  (if (and (stringp (car terms))
+          (member (car terms) '("if" "unless")))
+      (eshell-structure-basic-command
+       'if '("if" "unless") (car terms)
+       (eshell-invokify-arg (cadr terms) nil t)
+       (eshell-invokify-arg
+       (if (= (length terms) 5)
+           (car (last terms 3))
+         (car (last terms))) t)
+       (eshell-invokify-arg
+       (if (= (length terms) 5)
+           (car (last terms))) t))))
+
+(defun eshell-exit-success-p ()
+  "Return non-nil if the last command was \"successful\".
+For a bit of Lisp code, this means a return value of non-nil.
+For an external command, it means an exit code of 0."
+  (if (string= eshell-last-command-name "#<Lisp>")
+      eshell-last-command-result
+    (= eshell-last-command-status 0)))
+
+(defun eshell-parse-pipeline (terms &optional final-p)
+  "Parse a pipeline from TERMS, return the appropriate Lisp forms."
+  (let* (sep-terms
+        (bigpieces (eshell-separate-commands terms "\\(&&\\|||\\)"
+                                             nil 'sep-terms))
+        (bp bigpieces)
+        (results (list t))
+        final)
+    (while bp
+      (let ((subterms (car bp)))
+       (let* ((pieces (eshell-separate-commands subterms "|"))
+              (p pieces))
+         (while p
+           (let ((cmd (car p)))
+             (run-hook-with-args 'eshell-pre-rewrite-command-hook cmd)
+             (setq cmd (run-hook-with-args-until-success
+                        'eshell-rewrite-command-hook cmd))
+             (run-hook-with-args 'eshell-post-rewrite-command-hook 'cmd)
+             (setcar p cmd))
+           (setq p (cdr p)))
+         (nconc results
+                (list
+                 (if (<= (length pieces) 1)
+                     (car pieces)
+                   (assert (not eshell-in-pipeline-p))
+                   (list 'eshell-execute-pipeline
+                         (list 'quote pieces))))))
+       (setq bp (cdr bp))))
+    ;; `results' might be empty; this happens in the case of
+    ;; multi-line input
+    (setq results (cdr results)
+         results (nreverse results)
+         final (car results)
+         results (cdr results)
+         sep-terms (nreverse sep-terms))
+    (while results
+      (assert (car sep-terms))
+      (setq final (eshell-structure-basic-command
+                  'if (string= (car sep-terms) "&&") "if"
+                  (list 'eshell-commands (car results))
+                  final
+                  nil t)
+           results (cdr results)
+           sep-terms (cdr sep-terms)))
+    final))
+
+(defun eshell-parse-subcommand-argument ()
+  "Parse a subcommand argument of the form '{command}'."
+  (if (and (not eshell-current-argument)
+          (not eshell-current-quoted)
+          (eq (char-after) ?\{)
+          (or (= (point-max) (1+ (point)))
+              (not (eq (char-after (1+ (point))) ?\}))))
+      (let ((end (eshell-find-delimiter ?\{ ?\})))
+       (if (not end)
+           (throw 'eshell-incomplete ?\{)
+         (when (eshell-arg-delimiter (1+ end))
+           (prog1
+               (list 'eshell-as-subcommand
+                     (eshell-parse-command (cons (1+ (point)) end)))
+             (goto-char (1+ end))))))))
+
+(defun eshell-parse-lisp-argument ()
+  "Parse a Lisp expression which is specified as an argument."
+  (if (and (not eshell-current-argument)
+          (not eshell-current-quoted)
+          (looking-at eshell-lisp-regexp))
+      (let* ((here (point))
+            (obj
+             (condition-case err
+                 (read (current-buffer))
+               (end-of-file
+                (throw 'eshell-incomplete ?\()))))
+       (if (eshell-arg-delimiter)
+           (list 'eshell-command-to-value
+                 (list 'eshell-lisp-command (list 'quote obj)))
+         (ignore (goto-char here))))))
+
+(defun eshell-separate-commands
+  (terms separator &optional reversed last-terms-sym)
+  "Separate TERMS using SEPARATOR.
+If REVERSED is non-nil, the list of separated term groups will be
+returned in reverse order.  If LAST-TERMS-SYM is a symbol, it's value
+will be set to a list of all the separator operators found (or '(list
+nil)' if none)."
+  (let ((sub-terms (list t))
+       (eshell-sep-terms (list t))
+       subchains)
+    (while terms
+      (if (and (consp (car terms))
+              (eq (caar terms) 'eshell-operator)
+              (string-match (concat "^" separator "$")
+                            (nth 1 (car terms))))
+         (progn
+           (nconc eshell-sep-terms (list (nth 1 (car terms))))
+           (setq subchains (cons (cdr sub-terms) subchains)
+                 sub-terms (list t)))
+       (nconc sub-terms (list (car terms))))
+      (setq terms (cdr terms)))
+    (if (> (length sub-terms) 1)
+       (setq subchains (cons (cdr sub-terms) subchains)))
+    (if reversed
+       (progn
+         (if last-terms-sym
+             (set last-terms-sym (reverse (cdr eshell-sep-terms))))
+         subchains)                    ; already reversed
+      (if last-terms-sym
+         (set last-terms-sym (cdr eshell-sep-terms)))
+      (nreverse subchains))))
+
+;;_* Command evaluation macros
+;;
+;; The structure of the following macros is very important to
+;; `eshell-do-eval' [Iterative evaluation]:
+;;
+;; @ Don't use forms that conditionally evaluate their arguments, such
+;;   as `setq', `if', `while', `let*', etc.  The only special forms
+;;   that can be used are `let', `condition-case' and
+;;   `unwind-protect'.
+;;
+;; @ The main body of a `let' can contain only one form.  Use `progn'
+;;   if necessary.
+;;
+;; @ The two `special' variables are `eshell-current-handles' and
+;;   `eshell-current-subjob-p'.  Bind them locally with a `let' if you
+;;   need to change them.  Change them directly only if your intention
+;;   is to change the calling environment.
+
+(defmacro eshell-do-subjob (object)
+  "Evaluate a command OBJECT as a subjob.
+We indicate thet the process was run in the background by returned it
+ensconced in a list."
+  `(let ((eshell-current-subjob-p t))
+     ,object))
+
+(defmacro eshell-commands (object &optional silent)
+  "Place a valid set of handles, and context, around command OBJECT."
+  `(let ((eshell-current-handles
+         (eshell-create-handles ,(not silent) 'append))
+        eshell-current-subjob-p)
+     ,object))
+
+(defmacro eshell-trap-errors (object)
+  "Trap any errors that occur, so they are not entirely fatal.
+Also, the variable `eshell-this-command-hook' is available for the
+duration of OBJECT's evaluation.  Note that functions should be added
+to this hook using `nconc', and *not* `add-hook'.
+
+Someday, when Scheme will become the dominant Emacs language, all of
+this grossness will be made to disappear by using `call/cc'..."
+  `(let ((eshell-this-command-hook (list 'ignore)))
+     (eshell-condition-case err
+        (prog1
+            ,object
+          (run-hooks 'eshell-this-command-hook))
+       (error
+       (run-hooks 'eshell-this-command-hook)
+       (eshell-errorn (error-message-string err))
+       (eshell-close-handles 1)))))
+
+(defmacro eshell-protect (object)
+  "Protect I/O handles, so they aren't get closed after eval'ing OBJECT."
+  `(progn
+     (eshell-protect-handles eshell-current-handles)
+     ,object))
+
+(defmacro eshell-do-pipelines (pipeline)
+  "Execute the commands in PIPELINE, connecting each to one another."
+  (when (setq pipeline (cadr pipeline))
+    `(let ((eshell-current-handles
+           (eshell-create-handles
+            (car (aref eshell-current-handles
+                       eshell-output-handle)) nil
+            (car (aref eshell-current-handles
+                       eshell-error-handle)) nil)))
+       (progn
+        ,(when (cdr pipeline)
+           `(let (nextproc)
+              (progn
+                (set 'nextproc
+                     (eshell-do-pipelines (quote ,(cdr pipeline))))
+                (eshell-set-output-handle ,eshell-output-handle
+                                          'append nextproc)
+                (eshell-set-output-handle ,eshell-error-handle
+                                          'append nextproc)
+                (set 'tailproc (or tailproc nextproc)))))
+        ,(let ((head (car pipeline)))
+           (if (memq (car head) '(let progn))
+               (setq head (car (last head))))
+           (when (memq (car head) eshell-deferrable-commands)
+             (ignore
+              (setcar head
+                      (intern-soft
+                       (concat (symbol-name (car head)) "*"))))))
+        ,(car pipeline)))))
+
+(defalias 'eshell-process-identity 'identity)
+
+(defmacro eshell-execute-pipeline (pipeline)
+  "Execute the commands in PIPELINE, connecting each to one another."
+  `(let ((eshell-in-pipeline-p t) tailproc)
+     (progn
+       (eshell-do-pipelines ,pipeline)
+       (eshell-process-identity tailproc))))
+
+(defmacro eshell-as-subcommand (command)
+  "Execute COMMAND using a temp buffer.
+This is used so that certain Lisp commands, such as `cd', when
+executed in a subshell, do not disturb the environment of the main
+Eshell buffer."
+  `(let ,eshell-subcommand-bindings
+     ,command))
+
+(defmacro eshell-do-command-to-value (object)
+  "Run a subcommand prepared by `eshell-command-to-value'.
+This avoids the need to use `let*'."
+  `(let ((eshell-current-handles
+         (eshell-create-handles value 'overwrite)))
+     (progn
+       ,object
+       (symbol-value value))))
+
+(defmacro eshell-command-to-value (object)
+  "Run OBJECT synchronously, returning its result as a string.
+Returns a string comprising the output from the command."
+  `(let ((value (make-symbol "eshell-temp")))
+     (eshell-do-command-to-value ,object)))
+
+;;;_* Iterative evaluation
+;;
+;; Eshell runs all of its external commands asynchronously, so that
+;; Emacs is not blocked while the operation is being performed.
+;; However, this introduces certain synchronization difficulties,
+;; since the Lisp code, once it returns, will not "go back" to finish
+;; executing the commands which haven't yet been started.
+;;
+;; What Eshell does to work around this problem (basically, the lack
+;; of threads in Lisp), is that it evaluates the command sequence
+;; iteratively.  Whenever an asynchronous process is begun, evaluation
+;; terminates and control is given back to Emacs.  When that process
+;; finishes, it will resume the evaluation using the remainder of the
+;; command tree.
+
+(defun eshell/eshell-debug (&rest args)
+  "A command for toggling certain debug variables."
+  (ignore
+   (cond
+    ((not args)
+     (if eshell-handle-errors
+        (eshell-print "errors\n"))
+     (if eshell-debug-command
+        (eshell-print "commands\n")))
+    ((or (string= (car args) "-h")
+        (string= (car args) "--help"))
+     (eshell-print "usage: eshell-debug [kinds]
+
+This command is used to aid in debugging problems related to Eshell
+itself.  It is not useful for anything else.  The recognized `kinds'
+at the moment are:
+
+  errors       stops Eshell from trapping errors
+  commands     shows command execution progress in `*eshell last cmd*'
+"))
+    (t
+     (while args
+       (cond
+       ((string= (car args) "errors")
+        (setq eshell-handle-errors (not eshell-handle-errors)))
+       ((string= (car args) "commands")
+        (setq eshell-debug-command (not eshell-debug-command))))
+       (setq args (cdr args)))))))
+
+(defun pcomplete/eshell-mode/eshell-debug ()
+  "Completion for the `debug' command."
+  (while (pcomplete-here '("errors" "commands"))))
+
+(defun eshell-debug-command (tag subform)
+  "Output a debugging message to '*eshell last cmd*'."
+  (let ((buf (get-buffer-create "*eshell last cmd*"))
+       (text (eshell-stringify eshell-current-command)))
+    (save-excursion
+      (set-buffer buf)
+      (if (not tag)
+         (erase-buffer)
+       (insert "\n\C-l\n" tag "\n\n" text
+               (if subform
+                   (concat "\n\n" (eshell-stringify subform)) ""))))))
+
+(defun eshell-eval-command (command &optional input)
+  "Evaluate the given COMMAND iteratively."
+  (if eshell-current-command
+      ;; we can just stick the new command at the end of the current
+      ;; one, and everything will happen as it should
+      (setcdr (last (cdr eshell-current-command))
+             (list (list 'let '((here (and (eobp) (point))))
+                         (and input
+                              (list 'insert-and-inherit
+                                    (concat input "\n")))
+                         '(if here
+                              (eshell-update-markers here))
+                         (list 'eshell-do-eval
+                               (list 'quote command)))))
+    (and eshell-debug-command
+        (save-excursion
+          (let ((buf (get-buffer-create "*eshell last cmd*")))
+            (set-buffer buf)
+            (erase-buffer)
+            (insert "command: \"" input "\"\n"))))
+    (setq eshell-current-command command)
+    (eshell-resume-eval)))
+
+(defun eshell-resume-command (proc status)
+  "Resume the current command when a process ends."
+  (when proc
+    (unless (or (string= "stopped" status)
+               (string-match eshell-reset-signals status))
+      (if (eq proc (eshell-interactive-process))
+         (eshell-resume-eval)))))
+
+(defun eshell-resume-eval ()
+  "Destructively evaluate a form which may need to be deferred."
+  (eshell-condition-case err
+      (progn
+       (setq eshell-last-async-proc nil)
+       (when eshell-current-command
+         (let* (retval
+                (proc (catch 'eshell-defer
+                        (ignore
+                         (setq retval
+                               (eshell-do-eval
+                                eshell-current-command))))))
+           (if proc
+               (ignore (setq eshell-last-async-proc proc))
+             (cadr retval)))))
+    (error
+     (error (error-message-string err)))))
+
+(defmacro eshell-manipulate (tag &rest commands)
+  "Manipulate a COMMAND form, with TAG as a debug identifier."
+  (if (not eshell-debug-command)
+      `(progn ,@commands)
+    `(progn
+       (eshell-debug-command ,(eval tag) form)
+       ,@commands
+       (eshell-debug-command ,(concat "done " (eval tag)) form))))
+
+(put 'eshell-manipulate 'lisp-indent-function 1)
+
+;; eshell-lookup-function, eshell-functionp, and eshell-macrop taken
+;; from edebug
+
+(defsubst eshell-lookup-function (object)
+  "Return the ultimate function definition of OBJECT."
+  (while (and (symbolp object) (fboundp object))
+    (setq object (symbol-function object)))
+  object)
+
+(defconst function-p-func
+  (if (eshell-under-xemacs-p)
+      'compiled-function-p
+    'byte-code-function-p))
+
+(defsubst eshell-functionp (object)
+  "Returns the function named by OBJECT, or nil if it is not a function."
+  (setq object (eshell-lookup-function object))
+  (if (or (subrp object)
+         (funcall function-p-func object)
+         (and (listp object)
+              (eq (car object) 'lambda)
+              (listp (car (cdr object)))))
+      object))
+
+(defsubst eshell-macrop (object)
+  "Return t if OBJECT is a macro or nil otherwise."
+  (setq object (eshell-lookup-function object))
+  (if (and (listp object)
+          (eq 'macro (car object))
+          (eshell-functionp (cdr object)))
+      t))
+
+(defun eshell-do-eval (form &optional synchronous-p)
+  "Evaluate form, simplifying it as we go.
+Unless SYNCHRONOUS-P is non-nil, throws `eshell-defer' if it needs to
+be finished later after the completion of an asynchronous subprocess."
+  (cond
+   ((not (listp form))
+    (list 'quote (eval form)))
+   ((memq (car form) '(quote function))
+    form)
+   (t
+    ;; skip past the call to `eshell-do-eval'
+    (when (eq (car form) 'eshell-do-eval)
+      (setq form (cadr (cadr form))))
+    ;; expand any macros directly into the form.  This is done so that
+    ;; we can modify any `let' forms to evaluate only once.
+    (if (eshell-macrop (car form))
+       (let ((exp (eshell-copy-tree (macroexpand form))))
+         (eshell-manipulate (format "expanding macro `%s'"
+                                    (symbol-name (car form)))
+           (setcar form (car exp))
+           (setcdr form (cdr exp)))))
+    (let ((args (cdr form)))
+      (cond
+       ((eq (car form) 'while)
+       ;; `eshell-copy-tree' is needed here so that the test argument
+       ;; doesn't get modified and thus always yield the same result.
+       (when (car eshell-command-body)
+         (assert (not synchronous-p))
+         (eshell-do-eval (car eshell-command-body))
+         (setcar eshell-command-body nil))
+       (unless (car eshell-test-body)
+         (setcar eshell-test-body (eshell-copy-tree (car args))))
+       (if (and (car eshell-test-body)
+                (not (eq (car eshell-test-body) 0)))
+           (while (cadr (eshell-do-eval (car eshell-test-body)))
+             (setcar eshell-test-body 0)
+             (setcar eshell-command-body (eshell-copy-tree (cadr args)))
+             (eshell-do-eval (car eshell-command-body) synchronous-p)
+             (setcar eshell-command-body nil)
+             (setcar eshell-test-body (eshell-copy-tree (car args)))))
+       (setcar eshell-command-body nil))
+       ((eq (car form) 'if)
+       ;; `eshell-copy-tree' is needed here so that the test argument
+       ;; doesn't get modified and thus always yield the same result.
+       (when (car eshell-command-body)
+         (assert (not synchronous-p))
+         (eshell-do-eval (car eshell-command-body))
+         (setcar eshell-command-body nil))
+       (unless (car eshell-test-body)
+         (setcar eshell-test-body (eshell-copy-tree (car args))))
+       (if (and (car eshell-test-body)
+                (not (eq (car eshell-test-body) 0)))
+           (if (cadr (eshell-do-eval (car eshell-test-body)))
+               (progn
+                 (setcar eshell-test-body 0)
+                 (setcar eshell-command-body (eshell-copy-tree (cadr args)))
+                 (eshell-do-eval (car eshell-command-body) synchronous-p))
+             (setcar eshell-test-body 0)
+             (setcar eshell-command-body (eshell-copy-tree (car (cddr args))))
+             (eshell-do-eval (car eshell-command-body) synchronous-p)))
+       (setcar eshell-command-body nil))
+       ((eq (car form) 'setcar)
+       (setcar (cdr args) (eshell-do-eval (cadr args) synchronous-p))
+       (eval form))
+       ((eq (car form) 'setcdr)
+       (setcar (cdr args) (eshell-do-eval (cadr args) synchronous-p))
+       (eval form))
+       ((memq (car form) '(let catch condition-case unwind-protect))
+       ;; `let', `condition-case' and `unwind-protect' have to be
+       ;; handled specially, because we only want to call
+       ;; `eshell-do-eval' on their first form.
+       ;;
+       ;; NOTE: This requires obedience by all forms which this
+       ;; function might encounter, that they do not contain
+       ;; other special forms.
+       (if (and (eq (car form) 'let)
+                (not (eq (car (cadr args)) 'eshell-do-eval)))
+           (eshell-manipulate "evaluating let args"
+             (eshell-for letarg (car args)
+               (if (and (listp letarg)
+                        (not (eq (cadr letarg) 'quote)))
+                   (setcdr letarg
+                           (list (eshell-do-eval
+                                  (cadr letarg) synchronous-p)))))))
+       (unless (eq (car form) 'unwind-protect)
+         (setq args (cdr args)))
+       (unless (eq (caar args) 'eshell-do-eval)
+         (eshell-manipulate "handling special form"
+           (setcar args (list 'eshell-do-eval
+                              (list 'quote (car args))
+                              synchronous-p))))
+       (eval form))
+       (t
+       (if (and args (not (memq (car form) '(run-hooks))))
+           (eshell-manipulate
+               (format "evaluating arguments to `%s'"
+                       (symbol-name (car form)))
+             (while args
+               (setcar args (eshell-do-eval (car args) synchronous-p))
+               (setq args (cdr args)))))
+       (cond
+        ((eq (car form) 'progn)
+         (car (last form)))
+        ((eq (car form) 'prog1)
+         (cadr form))
+        (t
+         (let (result new-form)
+           ;; If a command desire to replace its execution form with
+           ;; another command form, all it needs to do is throw the
+           ;; new form using the exception tag
+           ;; `eshell-replace-command'.  For example, let's say that
+           ;; the form currently being eval'd is:
+           ;;
+           ;;   (eshell-named-command \"hello\")
+           ;;
+           ;; Now, let's assume the 'hello' command is an Eshell
+           ;; alias, the definition of which yields the command:
+           ;;
+           ;;   (eshell-named-command \"echo\" (list \"Hello\" \"world\"))
+           ;;
+           ;; What the alias code would like to do is simply
+           ;; substitute the alias form for the original form.  To
+           ;; accomplish this, all it needs to do is to throw the
+           ;; substitution form with the `eshell-replace-command'
+           ;; tag, and the form will be replaced within the current
+           ;; command, and execution will then resume (iteratively)
+           ;; as before.  Thus, aliases can even contain references
+           ;; to asynchronous sub-commands, and things will still
+           ;; work out as they should.
+           (if (setq new-form
+                     (catch 'eshell-replace-command
+                       (ignore
+                        (setq result (eval form)))))
+               (progn
+                 (eshell-manipulate "substituting replacement form"
+                   (setcar form (car new-form))
+                   (setcdr form (cdr new-form)))
+                 (eshell-do-eval form synchronous-p))
+             (if (and (memq (car form) eshell-deferrable-commands)
+                      (not eshell-current-subjob-p)
+                      result
+                      (processp result))
+                 (if synchronous-p
+                     (eshell/wait result)
+                   (eshell-manipulate "inserting ignore form"
+                     (setcar form 'ignore)
+                     (setcdr form nil))
+                   (throw 'eshell-defer result))
+               (list 'quote result))))))))))))
+
+;; command invocation
+
+(defun eshell/which (command &rest names)
+  "Identify the COMMAND, and where it is located."
+  (eshell-for name (cons command names)
+    (let (program alias direct)
+      (if (eq (aref name 0) ?*)
+         (setq name (substring name 1)
+               direct t))
+      (if (and (not direct)
+              (eshell-using-module 'eshell-alias)
+              (setq alias
+                    (funcall (symbol-function 'eshell-lookup-alias)
+                             name)))
+         (setq program
+               (concat name " is an alias, defined as \""
+                       (cadr alias) "\"")))
+      (unless program
+       (setq program (eshell-search-path name))
+       (let* ((esym (eshell-find-alias-function name))
+              (sym (or esym (intern-soft name))))
+         (if (and sym (fboundp sym)
+                  (or esym eshell-prefer-lisp-functions
+                      (not program)))
+             (let ((desc (let ((inhibit-redisplay t))
+                           (save-window-excursion
+                             (prog1
+                                 (describe-function sym)
+                               (message nil))))))
+               (setq desc (substring desc 0
+                                     (1- (or (string-match "\n" desc)
+                                             (length desc)))))
+               (kill-buffer "*Help*")
+               (setq program (or desc name))))))
+      (if (not program)
+         (eshell-error (format "which: no %s in (%s)\n"
+                               name (getenv "PATH")))
+       (eshell-printn program)))))
+
+(defun eshell-named-command (command &optional args)
+  "Insert output from a plain COMMAND, using ARGS.
+COMMAND may result in an alias being executed, or a plain command."
+  (setq eshell-last-arguments args
+       eshell-last-command-name (eshell-stringify command))
+  (run-hook-with-args 'eshell-prepare-command-hook)
+  (assert (stringp eshell-last-command-name))
+  (if eshell-last-command-name
+      (or (run-hook-with-args-until-success
+          'eshell-named-command-hook eshell-last-command-name
+          eshell-last-arguments)
+         (eshell-plain-command eshell-last-command-name
+                               eshell-last-arguments))))
+
+(defalias 'eshell-named-command* 'eshell-named-command)
+
+(defun eshell-find-alias-function (name)
+  "Check whether a function called `eshell/NAME' exists."
+  (let* ((sym (intern-soft (concat "eshell/" name)))
+        (file (symbol-file sym))
+        module-sym)
+    (if (and file
+            (string-match "\\(em\\|esh\\)-\\(.*\\)\\(\\.el\\)?\\'" file))
+       (setq file (concat "eshell-" (match-string 2 file))))
+    (setq module-sym
+         (and sym file (fboundp 'symbol-file)
+              (intern (file-name-sans-extension
+                       (file-name-nondirectory file)))))
+    (and sym (functionp sym)
+        (or (not module-sym)
+            (eshell-using-module module-sym)
+            (memq module-sym (eshell-subgroups 'eshell)))
+        sym)))
+
+(defun eshell-plain-command (command args)
+  "Insert output from a plain COMMAND, using ARGS.
+COMMAND may result in either a Lisp function being executed by name,
+or an external command."
+  (let* ((esym (eshell-find-alias-function command))
+        (sym (or esym (intern-soft command))))
+    (if (and sym (fboundp sym)
+            (or esym eshell-prefer-lisp-functions
+                (not (eshell-search-path command))))
+       (eshell-lisp-command sym args)
+      (eshell-external-command command args))))
+
+(defun eshell-exec-lisp (printer errprint func-or-form args form-p)
+  "Execute a lisp FUNC-OR-FORM, maybe passing ARGS.
+PRINTER and ERRPRINT are functions to use for printing regular
+messages, and errors.  FORM-P should be non-nil if FUNC-OR-FORM
+represent a lisp form; ARGS will be ignored in that case."
+  (let (result)
+    (eshell-condition-case err
+       (progn
+         (setq result
+               (save-current-buffer
+                 (if form-p
+                     (eval func-or-form)
+                   (apply func-or-form args))))
+         (and result (funcall printer result))
+         result)
+      (error
+       (let ((msg (error-message-string err)))
+        (if (and (not form-p)
+                 (string-match "^Wrong number of arguments" msg)
+                 (fboundp 'eldoc-get-fnsym-args-string))
+            (let ((func-doc (eldoc-get-fnsym-args-string func-or-form)))
+              (setq msg (format "usage: %s" func-doc))))
+        (funcall errprint msg))
+       nil))))
+
+(defsubst eshell-apply* (printer errprint func args)
+  "Call FUNC, with ARGS, trapping errors and return them as output.
+PRINTER and ERRPRINT are functions to use for printing regular
+messages, and errors."
+  (eshell-exec-lisp printer errprint func args nil))
+
+(defsubst eshell-funcall* (printer errprint func &rest args)
+  "Call FUNC, with ARGS, trapping errors and return them as output."
+  (eshell-apply* printer errprint func args))
+
+(defsubst eshell-eval* (printer errprint form)
+  "Evaluate FORM, trapping errors and returning them."
+  (eshell-exec-lisp printer errprint form nil t))
+
+(defsubst eshell-apply (func args)
+  "Call FUNC, with ARGS, trapping errors and return them as output.
+PRINTER and ERRPRINT are functions to use for printing regular
+messages, and errors."
+  (eshell-apply* 'eshell-print 'eshell-error func args))
+
+(defsubst eshell-funcall (func &rest args)
+  "Call FUNC, with ARGS, trapping errors and return them as output."
+  (eshell-apply func args))
+
+(defsubst eshell-eval (form)
+  "Evaluate FORM, trapping errors and returning them."
+  (eshell-eval* 'eshell-print 'eshell-error form))
+
+(defsubst eshell-applyn (func args)
+  "Call FUNC, with ARGS, trapping errors and return them as output.
+PRINTER and ERRPRINT are functions to use for printing regular
+messages, and errors."
+  (eshell-apply* 'eshell-printn 'eshell-errorn func args))
+
+(defsubst eshell-funcalln (func &rest args)
+  "Call FUNC, with ARGS, trapping errors and return them as output."
+  (eshell-applyn func args))
+
+(defsubst eshell-evaln (form)
+  "Evaluate FORM, trapping errors and returning them."
+  (eshell-eval* 'eshell-printn 'eshell-errorn form))
+
+(defun eshell-lisp-command (object &optional args)
+  "Insert Lisp OBJECT, using ARGS if a function."
+  (setq eshell-last-arguments args
+       eshell-last-command-name "#<Lisp>")
+  (catch 'eshell-external               ; deferred to an external command
+    (let* ((eshell-ensure-newline-p (eshell-interactive-output-p))
+          (result
+           (if (functionp object)
+               (eshell-apply object args)
+             (eshell-eval object))))
+      (if (and eshell-ensure-newline-p
+              (save-excursion
+                (goto-char eshell-last-output-end)
+                (not (bolp))))
+         (eshell-print "\n"))
+      (eshell-close-handles 0 (list 'quote result)))))
+
+(defalias 'eshell-lisp-command* 'eshell-lisp-command)
+
+;;; esh-cmd.el ends here