]> code.delx.au - gnu-emacs/blobdiff - lisp/eshell/em-unix.el
(c-emacs-features): Fix typo in docstring.
[gnu-emacs] / lisp / eshell / em-unix.el
index 7f0414ef056552d09afcddfc74ae8735c081965e..9c55fe16b6dccd46fe06a9e06b41a461e08dac58 100644 (file)
@@ -1,6 +1,7 @@
-;;; em-unix --- UNIX command aliases
+;;; em-unix.el --- UNIX command aliases
 
-;; Copyright (C) 1999, 2000 Free Software Foundation
+;; Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004,
+;;   2005, 2006, 2007 Free Software Foundation, Inc.
 
 ;; Author: John Wiegley <johnw@gnu.org>
 
 
 ;; 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.
+;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
 
 (provide 'em-unix)
 
 (eval-when-compile (require 'esh-maint))
+(require 'eshell)
 
 (defgroup eshell-unix nil
   "This module defines many of the more common UNIX utilities as
@@ -76,7 +78,7 @@ receiving side of a command pipeline."
   :type 'boolean
   :group 'eshell-unix)
 
-(defcustom eshell-plain-locate-behavior nil
+(defcustom eshell-plain-locate-behavior (eshell-under-xemacs-p)
   "*If non-nil, standalone \"locate\" commands will behave normally.
 Standalone in this context means not redirected, and not on the
 receiving side of a command pipeline."
@@ -124,6 +126,11 @@ Otherwise, `rmdir' is required."
   :type 'boolean
   :group 'eshell-unix)
 
+(defcustom eshell-default-target-is-dot nil
+  "*If non-nil, the default destination for cp, mv or ln is `.'."
+  :type 'boolean
+  :group 'eshell-unix)
+
 (defcustom eshell-du-prefer-over-ange nil
   "*Use Eshell's du in ange-ftp remote directories.
 Otherwise, Emacs will attempt to use rsh to invoke du on the remote machine."
@@ -136,11 +143,14 @@ Otherwise, Emacs will attempt to use rsh to invoke du on the remote machine."
 
 (defun eshell-unix-initialize ()
   "Initialize the UNIX support/emulation code."
-  (make-local-hook 'eshell-post-command-hook)
   (when (eshell-using-module 'eshell-cmpl)
-    (make-local-hook 'pcomplete-try-first-hook)
     (add-hook 'pcomplete-try-first-hook
-             'eshell-complete-host-reference nil t)))
+             'eshell-complete-host-reference nil t))
+  (make-local-variable 'eshell-complex-commands)
+  (setq eshell-complex-commands
+       (append '("grep" "egrep" "fgrep" "agrep" "glimpse" "locate"
+                 "cat" "time" "cp" "mv" "make" "du" "diff")
+               eshell-complex-commands)))
 
 (defalias 'eshell/date     'current-time-string)
 (defalias 'eshell/basename 'file-name-nondirectory)
@@ -156,7 +166,10 @@ Otherwise, Emacs will attempt to use rsh to invoke du on the remote machine."
   "Invoke man, flattening the arguments appropriately."
   (funcall 'man (apply 'eshell-flatten-and-stringify args)))
 
+(put 'eshell/man 'eshell-no-numeric-conversions t)
+
 (defun eshell-remove-entries (path files &optional top-level)
+  "From PATH, remove all of the given FILES, perhaps interactively."
   (while files
     (if (string-match "\\`\\.\\.?\\'"
                      (file-name-nondirectory (car files)))
@@ -265,6 +278,8 @@ Remove (unlink) the FILE(s).")
      (setq args (cdr args)))
    nil))
 
+(put 'eshell/rm 'eshell-no-numeric-conversions t)
+
 (defun eshell/mkdir (&rest args)
   "Implementation of mkdir in Lisp."
   (eshell-eval-using-options
@@ -279,6 +294,8 @@ Create the DIRECTORY(ies), if they do not already exist.")
      (setq args (cdr args)))
    nil))
 
+(put 'eshell/mkdir 'eshell-no-numeric-conversions t)
+
 (defun eshell/rmdir (&rest args)
   "Implementation of rmdir in Lisp."
   (eshell-eval-using-options
@@ -293,6 +310,8 @@ Remove the DIRECTORY(ies), if they are empty.")
      (setq args (cdr args)))
    nil))
 
+(put 'eshell/rmdir 'eshell-no-numeric-conversions t)
+
 (eval-when-compile
   (defvar no-dereference)
   (defvar preview)
@@ -302,8 +321,6 @@ Remove the DIRECTORY(ies), if they are empty.")
 
 (defun eshell-shuffle-files (command action files target func deep &rest args)
   "Shuffle around some filesystem entries, using FUNC to do the work."
-  (if (null target)
-      (error "%s: missing destination file" command))
   (let ((attr-target (eshell-file-attributes target))
        (is-dir (or (file-directory-p target)
                    (and preview (not eshell-warn-dot-directories))))
@@ -325,9 +342,11 @@ Remove the DIRECTORY(ies), if they are empty.")
                 (eq system-type 'ms-dos))
             (setq attr (eshell-file-attributes (car files)))
             (nth 10 attr-target) (nth 10 attr)
-            (= (nth 10 attr-target) (nth 10 attr))
+            ;; Use equal, not -, since the inode and the device could
+            ;; cons cells.
+            (equal (nth 10 attr-target) (nth 10 attr))
             (nth 11 attr-target) (nth 11 attr)
-            (= (nth 11 attr-target) (nth 11 attr)))
+            (equal (nth 11 attr-target) (nth 11 attr)))
        (eshell-error (format "%s: `%s' and `%s' are the same file\n"
                              command (car files) target)))
        (t
@@ -349,12 +368,16 @@ Remove the DIRECTORY(ies), if they are empty.")
                (let (eshell-warn-dot-directories)
                  (if (and (not deep)
                           (eq func 'rename-file)
-                          (= (nth 11 (eshell-file-attributes
-                                      (file-name-directory
-                                       (expand-file-name source))))
-                             (nth 11 (eshell-file-attributes
-                                      (file-name-directory
-                                       (expand-file-name target))))))
+                          ;; Use equal, since the device might be a
+                          ;; cons cell.
+                          (equal (nth 11 (eshell-file-attributes
+                                          (file-name-directory
+                                           (directory-file-name
+                                            (expand-file-name source)))))
+                                 (nth 11 (eshell-file-attributes
+                                          (file-name-directory
+                                           (directory-file-name
+                                            (expand-file-name target)))))))
                      (apply 'eshell-funcalln func source target args)
                  (unless (file-directory-p target)
                    (if verbose
@@ -417,30 +440,35 @@ Remove the DIRECTORY(ies), if they are empty.")
            (format "tar %s %s" tar-args archive) args))))
 
 ;; this is to avoid duplicating code...
-(defmacro eshell-mvcp-template
-  (command action func query-var force-var &optional preserve)
-  `(if (and (string-match eshell-tar-regexp (car (last args)))
-           (or (> (length args) 2)
-               (and (file-directory-p (car args))
-                    (or (not no-dereference)
-                        (not (file-symlink-p (car args)))))))
-       (eshell-shorthand-tar-command ,command args)
-     (let (target ange-cache)
-       (if (> (length args) 1)
-          (progn
-            (setq target (car (last args)))
-            (setcdr (last args 2) nil))
-        (setq args nil))
-       (eshell-shuffle-files
-       ,command ,action args target ,func nil
-       ,@(append
-          `((if (and (or interactive
-                         ,query-var)
-                     (not force))
-                1 (or force ,force-var)))
-          (if preserve
-              (list preserve)))))
-     nil))
+(defmacro eshell-mvcpln-template (command action func query-var
+                                         force-var &optional preserve)
+  `(let ((len (length args)))
+     (if (or (= len 0)
+            (and (= len 1) (null eshell-default-target-is-dot)))
+        (error "%s: missing destination file or directory" ,command))
+     (if (= len 1)
+        (nconc args '(".")))
+     (setq args (eshell-stringify-list (eshell-flatten-list args)))
+     (if (and ,(not (equal command "ln"))
+             (string-match eshell-tar-regexp (car (last args)))
+             (or (> (length args) 2)
+                 (and (file-directory-p (car args))
+                      (or (not no-dereference)
+                          (not (file-symlink-p (car args)))))))
+        (eshell-shorthand-tar-command ,command args)
+       (let ((target (car (last args)))
+            ange-cache)
+        (setcdr (last args 2) nil)
+        (eshell-shuffle-files
+         ,command ,action args target ,func nil
+         ,@(append
+            `((if (and (or interactive
+                           ,query-var)
+                       (not force))
+                  1 (or force ,force-var)))
+            (if preserve
+                (list preserve)))))
+       nil)))
 
 (defun eshell/mv (&rest args)
   "Implementation of mv in Lisp."
@@ -455,6 +483,7 @@ Remove the DIRECTORY(ies), if they are empty.")
      (?v "verbose" nil verbose
         "explain what is being done")
      (nil "help" nil nil "show this usage screen")
+     :preserve-args
      :external "mv"
      :show-usage
      :usage "[OPTION]... SOURCE DEST
@@ -462,9 +491,11 @@ Remove the DIRECTORY(ies), if they are empty.")
 Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY.
 \[OPTION] DIRECTORY...")
    (let ((no-dereference t))
-     (eshell-mvcp-template "mv" "moving" 'rename-file
-                          eshell-mv-interactive-query
-                          eshell-mv-overwrite-files))))
+     (eshell-mvcpln-template "mv" "moving" 'rename-file
+                            eshell-mv-interactive-query
+                            eshell-mv-overwrite-files))))
+
+(put 'eshell/mv 'eshell-no-numeric-conversions t)
 
 (defun eshell/cp (&rest args)
   "Implementation of cp in Lisp."
@@ -487,6 +518,7 @@ Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY.
      (?v "verbose" nil verbose
         "explain what is being done")
      (nil "help" nil nil "show this usage screen")
+     :preserve-args
      :external "cp"
      :show-usage
      :usage "[OPTION]... SOURCE DEST
@@ -494,9 +526,11 @@ Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY.
 Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.")
    (if archive
        (setq preserve t no-dereference t recursive t))
-   (eshell-mvcp-template "cp" "copying" 'copy-file
-                        eshell-cp-interactive-query
-                        eshell-cp-overwrite-files preserve)))
+   (eshell-mvcpln-template "cp" "copying" 'copy-file
+                          eshell-cp-interactive-query
+                          eshell-cp-overwrite-files preserve)))
+
+(put 'eshell/cp 'eshell-no-numeric-conversions t)
 
 (defun eshell/ln (&rest args)
   "Implementation of ln in Lisp."
@@ -505,11 +539,13 @@ Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.")
    '((?h "help" nil nil "show this usage screen")
      (?s "symbolic" nil symbolic
         "make symbolic links instead of hard links")
-     (?i "interactive" nil interactive "request confirmation if target already exists")
+     (?i "interactive" nil interactive
+        "request confirmation if target already exists")
      (?f "force" nil force "remove existing destinations, never prompt")
      (?n "preview" nil preview
         "don't change anything on disk")
      (?v "verbose" nil verbose "explain what is being done")
+     :preserve-args
      :external "ln"
      :show-usage
      :usage "[OPTION]... TARGET [LINK_NAME]
@@ -518,33 +554,30 @@ Create a link to the specified TARGET with optional LINK_NAME.  If there is
 more than one TARGET, the last argument must be a directory;  create links
 in DIRECTORY to each TARGET.  Create hard links by default, symbolic links
 with '--symbolic'.  When creating hard links, each TARGET must exist.")
-   (let (target no-dereference ange-cache)
-     (if (> (length args) 1)
-        (progn
-          (setq target (car (last args)))
-          (setcdr (last args 2) nil))
-       (setq args nil))
-     (eshell-shuffle-files "ln" "linking" args target
-                          (if symbolic
-                              'make-symbolic-link
-                            'add-name-to-file) nil
-                          (if (and (or interactive
-                                       eshell-ln-interactive-query)
-                                   (not force))
-                              1 (or force eshell-ln-overwrite-files))))
-   nil))
+   (let ((no-dereference t))
+     (eshell-mvcpln-template "ln" "linking"
+                            (if symbolic
+                                'make-symbolic-link
+                              'add-name-to-file)
+                            eshell-ln-interactive-query
+                            eshell-ln-overwrite-files))))
+
+(put 'eshell/ln 'eshell-no-numeric-conversions t)
 
 (defun eshell/cat (&rest args)
   "Implementation of cat in Lisp.
 If in a pipeline, or the file is not a regular file, directory or
 symlink, then revert to the system's definition of cat."
-  (setq args (eshell-flatten-list args))
+  (setq args (eshell-stringify-list (eshell-flatten-list args)))
   (if (or eshell-in-pipeline-p
          (catch 'special
            (eshell-for arg args
-             (unless (let ((attrs (eshell-file-attributes arg)))
-                       (and attrs (memq (aref (nth 8 attrs) 0)
-                                        '(?d ?l ?-))))
+             (unless (or (and (stringp arg)
+                              (> (length arg) 0)
+                              (eq (aref arg 0) ?-))
+                         (let ((attrs (eshell-file-attributes arg)))
+                           (and attrs (memq (aref (nth 8 attrs) 0)
+                                            '(?d ?l ?-)))))
                (throw 'special t)))))
       (let ((ext-cat (eshell-search-path "cat")))
        (if ext-cat
@@ -581,6 +614,8 @@ Concatenate FILE(s), or standard input, to standard output.")
      ;; if the file does not end in a newline, do not emit one
      (setq eshell-ensure-newline-p nil))))
 
+(put 'eshell/cat 'eshell-no-numeric-conversions t)
+
 ;; special front-end functions for compilation-mode buffers
 
 (defun eshell/make (&rest args)
@@ -593,7 +628,10 @@ Concatenate FILE(s), or standard input, to standard output.")
                         (list 'quote (eshell-copy-environment))))))
        (compile (concat "make " (eshell-flatten-and-stringify args))))
     (throw 'eshell-replace-command
-          (eshell-parse-command "*make" (eshell-flatten-list args)))))
+          (eshell-parse-command "*make" (eshell-stringify-list
+                                         (eshell-flatten-list args))))))
+
+(put 'eshell/make 'eshell-no-numeric-conversions t)
 
 (defun eshell-occur-mode-goto-occurrence ()
   "Go to the occurrence the current line describes."
@@ -605,13 +643,12 @@ Concatenate FILE(s), or standard input, to standard output.")
 (defun eshell-occur-mode-mouse-goto (event)
   "In Occur mode, go to the occurrence whose line you click on."
   (interactive "e")
-  (let (buffer pos)
+  (let (pos)
     (save-excursion
       (set-buffer (window-buffer (posn-window (event-end event))))
       (save-excursion
        (goto-char (posn-point (event-end event)))
-       (setq pos (occur-mode-find-occurrence))
-       (setq buffer occur-buffer)))
+       (setq pos (occur-mode-find-occurrence))))
     (pop-to-buffer (marker-buffer pos))
     (goto-char (marker-position pos))))
 
@@ -627,7 +664,8 @@ available..."
              (default-directory default-dir))
          (erase-buffer)
          (occur-mode)
-         (let ((files (eshell-flatten-list (cdr args)))
+         (let ((files (eshell-stringify-list
+                       (eshell-flatten-list (cdr args))))
                (inhibit-redisplay t)
                string)
            (when (car args)
@@ -646,7 +684,6 @@ available..."
                (if string (insert string))
                (setq string nil
                      files (cdr files)))))
-         (setq occur-buffer (current-buffer))
          (local-set-key [mouse-2] 'eshell-occur-mode-mouse-goto)
          (local-set-key [(control ?c) (control ?c)]
                         'eshell-occur-mode-goto-occurrence)
@@ -670,14 +707,12 @@ external command."
                      (not eshell-in-subcommand-p))))
        (throw 'eshell-replace-command
               (eshell-parse-command (concat "*" command)
-                                    (eshell-flatten-list args)))
-      (let* ((compilation-process-setup-function
-             (list 'lambda nil
-                   (list 'setq 'process-environment
-                         (list 'quote (eshell-copy-environment)))))
-            (args (mapconcat 'identity
+                                    (eshell-stringify-list
+                                     (eshell-flatten-list args))))
+      (let* ((args (mapconcat 'identity
                              (mapcar 'shell-quote-argument
-                                     (eshell-flatten-list args))
+                                     (eshell-stringify-list
+                                      (eshell-flatten-list args)))
                              " "))
             (cmd (progn
                    (set-text-properties 0 (length args)
@@ -765,7 +800,7 @@ external command."
        (size 0.0))
     (while entries
       (unless (string-match "\\`\\.\\.?\\'" (caar entries))
-       (let* ((entry (concat path (char-to-string directory-sep-char)
+       (let* ((entry (concat path "/"
                              (caar entries)))
               (symlink (and (stringp (cadr (car entries)))
                             (cadr (car entries)))))
@@ -797,7 +832,7 @@ external command."
 (defun eshell/du (&rest args)
   "Implementation of \"du\" in Lisp, passing ARGS."
   (setq args (if args
-                (eshell-flatten-list args)
+                (eshell-stringify-list (eshell-flatten-list args))
               '(".")))
   (let ((ext-du (eshell-search-path "du")))
     (if (and ext-du
@@ -843,7 +878,7 @@ Summarize disk usage of each FILE, recursively for directories.")
        (unless by-bytes
         (setq block-size (or block-size 1024)))
        (if (and max-depth (stringp max-depth))
-          (setq max-depth (string-to-int max-depth)))
+          (setq max-depth (string-to-number max-depth)))
        ;; filesystem support means nothing under Windows
        (if (eshell-under-windows-p)
           (setq only-one-filesystem nil))
@@ -909,14 +944,14 @@ Show wall-clock time elapsed during execution of COMMAND.")
 
 (defun eshell/diff (&rest args)
   "Alias \"diff\" to call Emacs `diff' function."
-  (let ((orig-args (eshell-flatten-list args)))
+  (let ((orig-args (eshell-stringify-list (eshell-flatten-list args))))
     (if (or eshell-plain-diff-behavior
            (not (and (eshell-interactive-output-p)
                      (not eshell-in-pipeline-p)
                      (not eshell-in-subcommand-p))))
        (throw 'eshell-replace-command
               (eshell-parse-command "*diff" orig-args))
-      (setq args (eshell-copy-list orig-args))
+      (setq args (copy-sequence orig-args))
       (if (< (length args) 2)
          (throw 'eshell-replace-command
                 (eshell-parse-command "*diff" orig-args)))
@@ -933,14 +968,22 @@ Show wall-clock time elapsed during execution of COMMAND.")
               (throw 'eshell-replace-command
                      (eshell-parse-command "*diff" orig-args))))
          (when (fboundp 'diff-mode)
-           (diff-mode)
-           (set (make-local-variable 'eshell-diff-window-config) config)
-           (local-set-key [?q] 'eshell-diff-quit)
-           (if (fboundp 'turn-on-font-lock-if-enabled)
-               (turn-on-font-lock-if-enabled))))
-       (other-window 1)
-       (goto-char (point-min))
-       nil))))
+           (make-local-variable 'compilation-finish-functions)
+           (add-hook
+            'compilation-finish-functions
+            `(lambda (buff msg)
+               (with-current-buffer buff
+                 (diff-mode)
+                 (set (make-local-variable 'eshell-diff-window-config)
+                      ,config)
+                 (local-set-key [?q] 'eshell-diff-quit)
+                 (if (fboundp 'turn-on-font-lock-if-enabled)
+                     (turn-on-font-lock-if-enabled))
+                 (goto-char (point-min))))))
+         (pop-to-buffer (current-buffer))))))
+  nil)
+
+(put 'eshell/diff 'eshell-no-numeric-conversions t)
 
 (defun eshell/locate (&rest args)
   "Alias \"locate\" to call Emacs `locate' function."
@@ -951,18 +994,24 @@ Show wall-clock time elapsed during execution of COMMAND.")
          (and (stringp (car args))
               (string-match "^-" (car args))))
       (throw 'eshell-replace-command
-            (eshell-parse-command "*locate" (eshell-flatten-list args)))
+            (eshell-parse-command "*locate" (eshell-stringify-list
+                                             (eshell-flatten-list args))))
     (save-selected-window
       (let ((locate-history-list (list (car args))))
        (locate-with-filter (car args) (cadr args))))))
 
+(put 'eshell/locate 'eshell-no-numeric-conversions t)
+
 (defun eshell/occur (&rest args)
   "Alias \"occur\" to call Emacs `occur' function."
   (let ((inhibit-read-only t))
-    (if args
-       (error "usage: occur: (REGEXP)")
-      (occur (car args)))))
+    (if (> (length args) 2)
+       (error "usage: occur: (REGEXP &optional NLINES)")
+      (apply 'occur args))))
+
+(put 'eshell/occur 'eshell-no-numeric-conversions t)
 
 ;;; Code:
 
+;;; arch-tag: 2462edd2-a76a-4cf2-897d-92e9a82ac1c9
 ;;; em-unix.el ends here