aboutsummaryrefslogtreecommitdiffstats
path: root/lisp/eshell
diff options
context:
space:
mode:
authorJohn Wiegley2000-10-13 09:02:39 +0000
committerJohn Wiegley2000-10-13 09:02:39 +0000
commit8c6b1d83116d00e27f22e501e5ac4fea9a7ba182 (patch)
tree7f624b71b8c6ec4c388bc34b92a8ebe8d2fb20e5 /lisp/eshell
parente2c06b17a94a7b06cd27b643f8d5118243f06969 (diff)
downloademacs-8c6b1d83116d00e27f22e501e5ac4fea9a7ba182.tar.gz
emacs-8c6b1d83116d00e27f22e501e5ac4fea9a7ba182.zip
Added better remote directory support to Eshell, as well as a few bug
fixes. See the ChangeLog.
Diffstat (limited to 'lisp/eshell')
-rw-r--r--lisp/eshell/em-glob.el2
-rw-r--r--lisp/eshell/em-ls.el43
-rw-r--r--lisp/eshell/em-pred.el6
-rw-r--r--lisp/eshell/em-rebind.el2
-rw-r--r--lisp/eshell/em-unix.el158
-rw-r--r--lisp/eshell/esh-arg.el2
-rw-r--r--lisp/eshell/esh-mode.el5
-rw-r--r--lisp/eshell/esh-util.el120
8 files changed, 243 insertions, 95 deletions
diff --git a/lisp/eshell/em-glob.el b/lisp/eshell/em-glob.el
index 4cb3d1e40ce..ec8c1b2c37a 100644
--- a/lisp/eshell/em-glob.el
+++ b/lisp/eshell/em-glob.el
@@ -243,7 +243,7 @@ resulting regular expression."
243 243
244 (INCLUDE-REGEXP EXCLUDE-REGEXP (PRED-FUNC-LIST) (MOD-FUNC-LIST))" 244 (INCLUDE-REGEXP EXCLUDE-REGEXP (PRED-FUNC-LIST) (MOD-FUNC-LIST))"
245 (let ((paths (eshell-split-path glob)) 245 (let ((paths (eshell-split-path glob))
246 matches message-shown) 246 matches message-shown ange-cache)
247 (unwind-protect 247 (unwind-protect
248 (if (and (cdr paths) 248 (if (and (cdr paths)
249 (file-name-absolute-p (car paths))) 249 (file-name-absolute-p (car paths)))
diff --git a/lisp/eshell/em-ls.el b/lisp/eshell/em-ls.el
index cd16f049815..77e5d5577dc 100644
--- a/lisp/eshell/em-ls.el
+++ b/lisp/eshell/em-ls.el
@@ -192,9 +192,15 @@ really need to stick around for very long."
192 "Test whether, for ATTRS, the user UID can do what corresponds to INDEX. 192 "Test whether, for ATTRS, the user UID can do what corresponds to INDEX.
193This is really just for efficiency, to avoid having to stat the file 193This is really just for efficiency, to avoid having to stat the file
194yet again." 194yet again."
195 `(if (= (user-uid) (nth 2 ,attrs)) 195 `(if (numberp (nth 2 ,attrs))
196 (not (eq (aref (nth 8 ,attrs) ,index) ?-)) 196 (if (= (user-uid) (nth 2 ,attrs))
197 (,(eval func) ,file))) 197 (not (eq (aref (nth 8 ,attrs) ,index) ?-))
198 (,(eval func) ,file))
199 (not (eq (aref (nth 8 ,attrs)
200 (+ ,index (if (member (nth 2 ,attrs)
201 (eshell-current-ange-uids))
202 0 6)))
203 ?-))))
198 204
199(defcustom eshell-ls-highlight-alist nil 205(defcustom eshell-ls-highlight-alist nil
200 "*This alist correlates test functions to color. 206 "*This alist correlates test functions to color.
@@ -265,7 +271,8 @@ instead."
265 (defvar show-all) 271 (defvar show-all)
266 (defvar show-recursive) 272 (defvar show-recursive)
267 (defvar show-size) 273 (defvar show-size)
268 (defvar sort-method)) 274 (defvar sort-method)
275 (defvar ange-cache))
269 276
270(defun eshell-do-ls (&rest args) 277(defun eshell-do-ls (&rest args)
271 "Implementation of \"ls\" in Lisp, passing ARGS." 278 "Implementation of \"ls\" in Lisp, passing ARGS."
@@ -328,7 +335,7 @@ Sort entries alphabetically across.")
328 (setq listing-style 'by-columns)) 335 (setq listing-style 'by-columns))
329 (unless args 336 (unless args
330 (setq args (list "."))) 337 (setq args (list ".")))
331 (let ((eshell-ls-exclude-regexp eshell-ls-exclude-regexp)) 338 (let ((eshell-ls-exclude-regexp eshell-ls-exclude-regexp) ange-cache)
332 (when ignore-pattern 339 (when ignore-pattern
333 (unless (eshell-using-module 'eshell-glob) 340 (unless (eshell-using-module 'eshell-glob)
334 (error (concat "-I option requires that `eshell-glob'" 341 (error (concat "-I option requires that `eshell-glob'"
@@ -347,7 +354,7 @@ Sort entries alphabetically across.")
347 (file-name-absolute-p arg)) 354 (file-name-absolute-p arg))
348 (expand-file-name arg) 355 (expand-file-name arg)
349 arg) 356 arg)
350 (file-attributes arg)))) args) 357 (eshell-file-attributes arg)))) args)
351 t (expand-file-name default-directory))) 358 t (expand-file-name default-directory)))
352 (funcall flush-func))) 359 (funcall flush-func)))
353 360
@@ -379,7 +386,7 @@ name should be displayed as, etc. Think of it as cooking a FILEINFO."
379 (file-name-directory 386 (file-name-directory
380 (expand-file-name (car fileinfo)))))) 387 (expand-file-name (car fileinfo))))))
381 (setq attr 388 (setq attr
382 (file-attributes 389 (eshell-file-attributes
383 (let ((target (if dir 390 (let ((target (if dir
384 (expand-file-name (cadr fileinfo) dir) 391 (expand-file-name (cadr fileinfo) dir)
385 (cadr fileinfo)))) 392 (cadr fileinfo))))
@@ -425,16 +432,22 @@ whose cdr is the list of file attributes."
425 "%s%4d %-8s %-8s " 432 "%s%4d %-8s %-8s "
426 (or (nth 8 attrs) "??????????") 433 (or (nth 8 attrs) "??????????")
427 (or (nth 1 attrs) 0) 434 (or (nth 1 attrs) 0)
428 (or (and (not numeric-uid-gid) 435 (or (let ((user (nth 2 attrs)))
429 (nth 2 attrs) 436 (and (not numeric-uid-gid)
430 (eshell-substring 437 user
431 (user-login-name (nth 2 attrs)) 8)) 438 (eshell-substring
439 (if (numberp user)
440 (user-login-name user)
441 user) 8)))
432 (nth 2 attrs) 442 (nth 2 attrs)
433 "") 443 "")
434 (or (and (not numeric-uid-gid) 444 (or (let ((group (nth 3 attrs)))
435 (nth 3 attrs) 445 (and (not numeric-uid-gid)
436 (eshell-substring 446 group
437 (eshell-group-name (nth 3 attrs)) 8)) 447 (eshell-substring
448 (if (numberp group)
449 (eshell-group-name group)
450 group) 8)))
438 (nth 3 attrs) 451 (nth 3 attrs)
439 "")) 452 ""))
440 (let* ((str (eshell-ls-printable-size (nth 7 attrs))) 453 (let* ((str (eshell-ls-printable-size (nth 7 attrs)))
diff --git a/lisp/eshell/em-pred.el b/lisp/eshell/em-pred.el
index c3e3de5adbd..9708e2d793a 100644
--- a/lisp/eshell/em-pred.el
+++ b/lisp/eshell/em-pred.el
@@ -464,7 +464,7 @@ that 'ls -l' will show in the first column of its display. "
464 (forward-char) 464 (forward-char)
465 (setq type ?%))) 465 (setq type ?%)))
466 `(lambda (file) 466 `(lambda (file)
467 (let ((attrs (file-attributes (directory-file-name file)))) 467 (let ((attrs (eshell-file-attributes (directory-file-name file))))
468 (if attrs 468 (if attrs
469 (memq (aref (nth 8 attrs) 0) 469 (memq (aref (nth 8 attrs) 0)
470 ,(if (eq type ?%) 470 ,(if (eq type ?%)
@@ -489,7 +489,7 @@ that 'ls -l' will show in the first column of its display. "
489 (setq amount (string-to-number (match-string 0))) 489 (setq amount (string-to-number (match-string 0)))
490 (goto-char (match-end 0)) 490 (goto-char (match-end 0))
491 `(lambda (file) 491 `(lambda (file)
492 (let ((attrs (file-attributes file))) 492 (let ((attrs (eshell-file-attributes file)))
493 (if attrs 493 (if attrs
494 (,(if (eq qual ?-) 494 (,(if (eq qual ?-)
495 '< 495 '<
@@ -518,7 +518,7 @@ that 'ls -l' will show in the first column of its display. "
518 (setq amount (* (string-to-number (match-string 0)) quantum)) 518 (setq amount (* (string-to-number (match-string 0)) quantum))
519 (goto-char (match-end 0)) 519 (goto-char (match-end 0))
520 `(lambda (file) 520 `(lambda (file)
521 (let ((attrs (file-attributes file))) 521 (let ((attrs (eshell-file-attributes file)))
522 (if attrs 522 (if attrs
523 (,(if (eq qual ?-) 523 (,(if (eq qual ?-)
524 '< 524 '<
diff --git a/lisp/eshell/em-rebind.el b/lisp/eshell/em-rebind.el
index 0463a78ffb4..4caae2da425 100644
--- a/lisp/eshell/em-rebind.el
+++ b/lisp/eshell/em-rebind.el
@@ -232,7 +232,7 @@ lock it at that."
232Sends an EOF only if point is at the end of the buffer and there is no 232Sends an EOF only if point is at the end of the buffer and there is no
233input." 233input."
234 (interactive "p") 234 (interactive "p")
235 (let ((proc (get-buffer-process (current-buffer)))) 235 (let ((proc (eshell-interactive-process)))
236 (if (eobp) 236 (if (eobp)
237 (cond 237 (cond
238 ((/= (point) eshell-last-output-end) 238 ((/= (point) eshell-last-output-end)
diff --git a/lisp/eshell/em-unix.el b/lisp/eshell/em-unix.el
index 17e110f65ed..07f14c6e30a 100644
--- a/lisp/eshell/em-unix.el
+++ b/lisp/eshell/em-unix.el
@@ -122,6 +122,12 @@ Otherwise, `rmdir' is required."
122 :type 'boolean 122 :type 'boolean
123 :group 'eshell-unix) 123 :group 'eshell-unix)
124 124
125(defcustom eshell-du-prefer-over-ange nil
126 "*Use Eshell's du in ange-ftp remote directories.
127Otherwise, Emacs will attempt to use rsh to invoke du the machine."
128 :type 'boolean
129 :group 'eshell-unix)
130
125(require 'esh-opt) 131(require 'esh-opt)
126 132
127;;; Functions: 133;;; Functions:
@@ -296,7 +302,7 @@ Remove the DIRECTORY(ies), if they are empty.")
296 "Shuffle around some filesystem entries, using FUNC to do the work." 302 "Shuffle around some filesystem entries, using FUNC to do the work."
297 (if (null target) 303 (if (null target)
298 (error "%s: missing destination file" command)) 304 (error "%s: missing destination file" command))
299 (let ((attr-target (file-attributes target)) 305 (let ((attr-target (eshell-file-attributes target))
300 (is-dir (or (file-directory-p target) 306 (is-dir (or (file-directory-p target)
301 (and preview (not eshell-warn-dot-directories)))) 307 (and preview (not eshell-warn-dot-directories))))
302 attr) 308 attr)
@@ -315,8 +321,10 @@ Remove the DIRECTORY(ies), if they are empty.")
315 ((and attr-target 321 ((and attr-target
316 (or (not (eshell-under-windows-p)) 322 (or (not (eshell-under-windows-p))
317 (eq system-type 'ms-dos)) 323 (eq system-type 'ms-dos))
318 (setq attr (file-attributes (car files))) 324 (setq attr (eshell-file-attributes (car files)))
325 (nth 10 attr-target) (nth 10 attr)
319 (= (nth 10 attr-target) (nth 10 attr)) 326 (= (nth 10 attr-target) (nth 10 attr))
327 (nth 11 attr-target) (nth 11 attr)
320 (= (nth 11 attr-target) (nth 11 attr))) 328 (= (nth 11 attr-target) (nth 11 attr)))
321 (eshell-error (format "%s: `%s' and `%s' are the same file\n" 329 (eshell-error (format "%s: `%s' and `%s' are the same file\n"
322 command (car files) target))) 330 command (car files) target)))
@@ -339,10 +347,10 @@ Remove the DIRECTORY(ies), if they are empty.")
339 (let (eshell-warn-dot-directories) 347 (let (eshell-warn-dot-directories)
340 (if (and (not deep) 348 (if (and (not deep)
341 (eq func 'rename-file) 349 (eq func 'rename-file)
342 (= (nth 11 (file-attributes 350 (= (nth 11 (eshell-file-attributes
343 (file-name-directory 351 (file-name-directory
344 (expand-file-name source)))) 352 (expand-file-name source))))
345 (nth 11 (file-attributes 353 (nth 11 (eshell-file-attributes
346 (file-name-directory 354 (file-name-directory
347 (expand-file-name target)))))) 355 (expand-file-name target))))))
348 (apply 'eshell-funcalln func source target args) 356 (apply 'eshell-funcalln func source target args)
@@ -415,7 +423,7 @@ Remove the DIRECTORY(ies), if they are empty.")
415 (or (not no-dereference) 423 (or (not no-dereference)
416 (not (file-symlink-p (car args))))))) 424 (not (file-symlink-p (car args)))))))
417 (eshell-shorthand-tar-command ,command args) 425 (eshell-shorthand-tar-command ,command args)
418 (let (target) 426 (let (target ange-cache)
419 (if (> (length args) 1) 427 (if (> (length args) 1)
420 (progn 428 (progn
421 (setq target (car (last args))) 429 (setq target (car (last args)))
@@ -508,7 +516,7 @@ Create a link to the specified TARGET with optional LINK_NAME. If there is
508more than one TARGET, the last argument must be a directory; create links 516more than one TARGET, the last argument must be a directory; create links
509in DIRECTORY to each TARGET. Create hard links by default, symbolic links 517in DIRECTORY to each TARGET. Create hard links by default, symbolic links
510with '--symbolic'. When creating hard links, each TARGET must exist.") 518with '--symbolic'. When creating hard links, each TARGET must exist.")
511 (let (target no-dereference) 519 (let (target no-dereference ange-cache)
512 (if (> (length args) 1) 520 (if (> (length args) 1)
513 (progn 521 (progn
514 (setq target (car (last args))) 522 (setq target (car (last args)))
@@ -525,10 +533,24 @@ with '--symbolic'. When creating hard links, each TARGET must exist.")
525 nil)) 533 nil))
526 534
527(defun eshell/cat (&rest args) 535(defun eshell/cat (&rest args)
528 "Implementation of cat in Lisp." 536 "Implementation of cat in Lisp.
529 (if eshell-in-pipeline-p 537If in a pipeline, or the file is not a regular file, directory or
530 (throw 'eshell-replace-command 538symlink, then revert to the system's definition of cat."
531 (eshell-parse-command "*cat" (eshell-flatten-list args))) 539 (setq args (eshell-flatten-list args))
540 (if (or eshell-in-pipeline-p
541 (catch 'special
542 (eshell-for arg args
543 (unless (let ((attrs (eshell-file-attributes arg)))
544 (and attrs (memq (aref (nth 8 attrs) 0)
545 '(?d ?l ?-))))
546 (throw 'special t)))))
547 (let ((ext-cat (eshell-search-path "cat")))
548 (if ext-cat
549 (throw 'eshell-replace-command
550 (eshell-parse-command ext-cat args))
551 (if eshell-in-pipeline-p
552 (error "Eshell's `cat' does not work in pipelines")
553 (error "Eshell's `cat' cannot display one of the files given"))))
532 (eshell-init-print-buffer) 554 (eshell-init-print-buffer)
533 (eshell-eval-using-options 555 (eshell-eval-using-options
534 "cat" args 556 "cat" args
@@ -772,61 +794,69 @@ external command."
772 794
773(defun eshell/du (&rest args) 795(defun eshell/du (&rest args)
774 "Implementation of \"du\" in Lisp, passing ARGS." 796 "Implementation of \"du\" in Lisp, passing ARGS."
775 (if (eshell-search-path "du") 797 (setq args (if args
776 (throw 'eshell-replace-command 798 (eshell-flatten-list args)
777 (eshell-parse-command "*du" (eshell-flatten-list args))) 799 '(".")))
778 (eshell-eval-using-options 800 (let ((ext-du (eshell-search-path "du")))
779 "du" args 801 (if (and ext-du
780 '((?a "all" nil show-all 802 (not (catch 'have-ange-path
781 "write counts for all files, not just directories") 803 (eshell-for arg args
782 (nil "block-size" t block-size 804 (if (eq (find-file-name-handler (expand-file-name arg)
783 "use SIZE-byte blocks (i.e., --block-size SIZE)") 805 'directory-files)
784 (?b "bytes" nil by-bytes 806 'ange-ftp-hook-function)
785 "print size in bytes") 807 (throw 'have-ange-path t))))))
786 (?c "total" nil grand-total 808 (throw 'eshell-replace-command
787 "produce a grand total") 809 (eshell-parse-command ext-du args))
788 (?d "max-depth" t max-depth 810 (eshell-eval-using-options
789 "display data only this many levels of data") 811 "du" args
790 (?h "human-readable" 1024 human-readable 812 '((?a "all" nil show-all
791 "print sizes in human readable format") 813 "write counts for all files, not just directories")
792 (?H "is" 1000 human-readable 814 (nil "block-size" t block-size
793 "likewise, but use powers of 1000 not 1024") 815 "use SIZE-byte blocks (i.e., --block-size SIZE)")
794 (?k "kilobytes" 1024 block-size 816 (?b "bytes" nil by-bytes
795 "like --block-size 1024") 817 "print size in bytes")
796 (?L "dereference" nil dereference-links 818 (?c "total" nil grand-total
797 "dereference all symbolic links") 819 "produce a grand total")
798 (?m "megabytes" 1048576 block-size 820 (?d "max-depth" t max-depth
799 "like --block-size 1048576") 821 "display data only this many levels of data")
800 (?s "summarize" 0 max-depth 822 (?h "human-readable" 1024 human-readable
801 "display only a total for each argument") 823 "print sizes in human readable format")
802 (?x "one-file-system" nil only-one-filesystem 824 (?H "is" 1000 human-readable
803 "skip directories on different filesystems") 825 "likewise, but use powers of 1000 not 1024")
804 (nil "help" nil nil 826 (?k "kilobytes" 1024 block-size
805 "show this usage screen") 827 "like --block-size 1024")
806 :external "du" 828 (?L "dereference" nil dereference-links
807 :usage "[OPTION]... FILE... 829 "dereference all symbolic links")
830 (?m "megabytes" 1048576 block-size
831 "like --block-size 1048576")
832 (?s "summarize" 0 max-depth
833 "display only a total for each argument")
834 (?x "one-file-system" nil only-one-filesystem
835 "skip directories on different filesystems")
836 (nil "help" nil nil
837 "show this usage screen")
838 :external "du"
839 :usage "[OPTION]... FILE...
808Summarize disk usage of each FILE, recursively for directories.") 840Summarize disk usage of each FILE, recursively for directories.")
809 (unless by-bytes 841 (unless by-bytes
810 (setq block-size (or block-size 1024))) 842 (setq block-size (or block-size 1024)))
811 (if (and max-depth (stringp max-depth)) 843 (if (and max-depth (stringp max-depth))
812 (setq max-depth (string-to-int max-depth))) 844 (setq max-depth (string-to-int max-depth)))
813 ;; filesystem support means nothing under Windows 845 ;; filesystem support means nothing under Windows
814 (if (eshell-under-windows-p) 846 (if (eshell-under-windows-p)
815 (setq only-one-filesystem nil)) 847 (setq only-one-filesystem nil))
816 (unless args 848 (let ((size 0.0) ange-cache)
817 (setq args '("."))) 849 (while args
818 (let ((size 0.0)) 850 (if only-one-filesystem
819 (while args 851 (setq only-one-filesystem
820 (if only-one-filesystem 852 (nth 11 (eshell-file-attributes
821 (setq only-one-filesystem 853 (file-name-as-directory (car args))))))
822 (nth 11 (file-attributes 854 (setq size (+ size (eshell-du-sum-directory
823 (file-name-as-directory (car args)))))) 855 (directory-file-name (car args)) 0)))
824 (setq size (+ size (eshell-du-sum-directory 856 (setq args (cdr args)))
825 (directory-file-name (car args)) 0))) 857 (if grand-total
826 (setq args (cdr args))) 858 (eshell-print (concat (eshell-du-size-string size)
827 (if grand-total 859 "total\n"))))))))
828 (eshell-print (concat (eshell-du-size-string size)
829 "total\n")))))))
830 860
831(defvar eshell-time-start nil) 861(defvar eshell-time-start nil)
832 862
diff --git a/lisp/eshell/esh-arg.el b/lisp/eshell/esh-arg.el
index 8364ca9a7f6..985401fbe37 100644
--- a/lisp/eshell/esh-arg.el
+++ b/lisp/eshell/esh-arg.el
@@ -328,13 +328,13 @@ special character that is not itself a backslash."
328(defun eshell-parse-double-quote () 328(defun eshell-parse-double-quote ()
329 "Parse a double quoted string, which allows for variable interpolation." 329 "Parse a double quoted string, which allows for variable interpolation."
330 (when (eq (char-after) ?\") 330 (when (eq (char-after) ?\")
331 (forward-char)
332 (let* ((end (eshell-find-delimiter ?\" ?\" nil nil t)) 331 (let* ((end (eshell-find-delimiter ?\" ?\" nil nil t))
333 (eshell-current-quoted t)) 332 (eshell-current-quoted t))
334 (if (not end) 333 (if (not end)
335 (throw 'eshell-incomplete ?\") 334 (throw 'eshell-incomplete ?\")
336 (prog1 335 (prog1
337 (save-restriction 336 (save-restriction
337 (forward-char)
338 (narrow-to-region (point) end) 338 (narrow-to-region (point) end)
339 (list 'eshell-escape-arg 339 (list 'eshell-escape-arg
340 (eshell-parse-argument))) 340 (eshell-parse-argument)))
diff --git a/lisp/eshell/esh-mode.el b/lisp/eshell/esh-mode.el
index 1d79c8af701..4d32da81f05 100644
--- a/lisp/eshell/esh-mode.el
+++ b/lisp/eshell/esh-mode.el
@@ -524,8 +524,9 @@ sessions, such as when using `eshell-command'.")
524 (interactive) 524 (interactive)
525 (require 'etags) 525 (require 'etags)
526 (let ((inhibit-read-only t) 526 (let ((inhibit-read-only t)
527 (no-default (eobp))) 527 (no-default (eobp))
528 (setq tagname (find-tag-interactive "Find tag: " no-default)) 528 (find-tag-default-function 'ignore))
529 (setq tagname (car (find-tag-interactive "Find tag: ")))
529 (find-tag tagname next-p regexp-p))) 530 (find-tag tagname next-p regexp-p)))
530 531
531(defun eshell-move-argument (limit func property arg) 532(defun eshell-move-argument (limit func property arg)
diff --git a/lisp/eshell/esh-util.el b/lisp/eshell/esh-util.el
index 3d650928c62..84416893107 100644
--- a/lisp/eshell/esh-util.el
+++ b/lisp/eshell/esh-util.el
@@ -86,6 +86,15 @@ function `string-to-number'."
86 :type 'regexp 86 :type 'regexp
87 :group 'eshell-util) 87 :group 'eshell-util)
88 88
89(defcustom eshell-ange-ls-uids nil
90 "*List of user/host/id strings, used to determine remote ownership."
91 :type '(list (cons :tag "Host/User Pair"
92 (string :tag "Hostname")
93 (repeat (cons :tag "User/UID List"
94 (string :tag "Username")
95 (repeat :tag "UIDs" string)))))
96 :group 'eshell-util)
97
89;;; Internal Variables: 98;;; Internal Variables:
90 99
91(defvar eshell-group-names nil 100(defvar eshell-group-names nil
@@ -558,28 +567,123 @@ Unless optional argument INPLACE is non-nil, return a new string."
558(unless (fboundp 'directory-files-and-attributes) 567(unless (fboundp 'directory-files-and-attributes)
559 (defun directory-files-and-attributes (dir &optional full match nosort) 568 (defun directory-files-and-attributes (dir &optional full match nosort)
560 (documentation 'directory-files) 569 (documentation 'directory-files)
561 (let* ((dir (expand-file-name dir)) 570 (let ((dir (expand-file-name dir)) ange-cache)
562 (default-directory dir))
563 (mapcar 571 (mapcar
564 (function 572 (function
565 (lambda (file) 573 (lambda (file)
566 (cons file (file-attributes file)))) 574 (cons file (eshell-file-attributes (expand-file-name file dir)))))
567 (directory-files dir full match nosort))))) 575 (directory-files dir full match nosort)))))
568 576
577(eval-when-compile
578 (defvar ange-cache))
579
569(defun eshell-directory-files-and-attributes (dir &optional full match nosort) 580(defun eshell-directory-files-and-attributes (dir &optional full match nosort)
570 "Make sure to use the handler for `directory-file-and-attributes'." 581 "Make sure to use the handler for `directory-file-and-attributes'."
571 (let ((dfh (find-file-name-handler dir 'directory-files))) 582 (let* ((dir (expand-file-name dir))
583 (dfh (find-file-name-handler dir 'directory-files)))
572 (if (not dfh) 584 (if (not dfh)
573 (directory-files-and-attributes dir full match nosort) 585 (directory-files-and-attributes dir full match nosort)
574 (let* ((files (funcall dfh 'directory-files dir full match nosort)) 586 (let ((files (funcall dfh 'directory-files dir full match nosort))
575 (fah (find-file-name-handler dir 'file-attributes)) 587 (fah (find-file-name-handler dir 'file-attributes)))
576 (default-directory (expand-file-name dir)))
577 (mapcar 588 (mapcar
578 (function 589 (function
579 (lambda (file) 590 (lambda (file)
580 (cons file (funcall fah 'file-attributes file)))) 591 (cons file (if fah
592 (eshell-file-attributes
593 (expand-file-name file dir))
594 (file-attributes (expand-file-name file dir))))))
581 files))))) 595 files)))))
582 596
597(defun eshell-current-ange-uids ()
598 (if (string-match "/\\([^@]+\\)@\\([^:]+\\):" default-directory)
599 (let* ((host (match-string 2 default-directory))
600 (user (match-string 1 default-directory))
601 (host-users (assoc host eshell-ange-ls-uids)))
602 (when host-users
603 (setq host-users (cdr host-users))
604 (cdr (assoc user host-users))))))
605
606;; Add an autoload for parse-time-string
607(if (and (not (fboundp 'parse-time-string))
608 (locate-library "parse-time"))
609 (autoload 'parse-time-string "parse-time"))
610
611(defun eshell-parse-ange-ls (dir)
612 (let (entry)
613 (with-temp-buffer
614 (insert (ange-ftp-ls dir "-la" nil))
615 (goto-char (point-min))
616 (if (looking-at "^total [0-9]+$")
617 (forward-line 1))
618 ;; Some systems put in a blank line here.
619 (if (eolp) (forward-line 1))
620 (while (looking-at
621 `,(concat "\\([dlscb-][rwxst-]+\\)"
622 "\\s-*" "\\([0-9]+\\)" "\\s-+"
623 "\\(\\S-+\\)" "\\s-+"
624 "\\(\\S-+\\)" "\\s-+"
625 "\\([0-9]+\\)" "\\s-+" "\\(.*\\)"))
626 (let* ((perms (match-string 1))
627 (links (string-to-number (match-string 2)))
628 (user (match-string 3))
629 (group (match-string 4))
630 (size (string-to-number (match-string 5)))
631 (mtime
632 (if (fboundp 'parse-time-string)
633 (let ((moment (parse-time-string
634 (match-string 6))))
635 (if (nth 0 moment)
636 (setcar (nthcdr 5 moment)
637 (nth 5 (decode-time (current-time))))
638 (setcar (nthcdr 0 moment) 0)
639 (setcar (nthcdr 1 moment) 0)
640 (setcar (nthcdr 2 moment) 0))
641 (apply 'encode-time moment))
642 (ange-ftp-file-modtime (expand-file-name name dir))))
643 (name (ange-ftp-parse-filename))
644 symlink)
645 (if (string-match "\\(.+\\) -> \\(.+\\)" name)
646 (setq symlink (match-string 2 name)
647 name (match-string 1 name)))
648 (setq entry
649 (cons
650 (cons name
651 (list (if (eq (aref perms 0) ?d)
652 t
653 symlink)
654 links user group
655 nil mtime nil
656 size perms nil nil)) entry)))
657 (forward-line)))
658 entry))
659
660(defun eshell-file-attributes (file)
661 "Return the attributes of FILE, playing tricks if it's over ange-ftp."
662 (let* ((file (expand-file-name file))
663 (handler (find-file-name-handler file 'file-attributes))
664 entry)
665 (if (not handler)
666 (file-attributes file)
667 (if (eq (find-file-name-handler (file-name-directory file)
668 'directory-files)
669 'ange-ftp-hook-function)
670 (let ((base (file-name-nondirectory file))
671 (dir (file-name-directory file)))
672 (if (boundp 'ange-cache)
673 (setq entry (cdr (assoc base (cdr (assoc dir ange-cache))))))
674 (unless entry
675 (setq entry (eshell-parse-ange-ls dir))
676 (if (boundp 'ange-cache)
677 (setq ange-cache
678 (cons (cons dir entry)
679 ange-cache)))
680 (if entry
681 (let ((fentry (assoc base (cdr entry))))
682 (if fentry
683 (setq entry (cdr fentry))
684 (setq entry nil)))))))
685 (or entry (funcall handler 'file-attributes file)))))
686
583(defun eshell-copy-list (list) 687(defun eshell-copy-list (list)
584 "Return a copy of a list, which may be a dotted list. 688 "Return a copy of a list, which may be a dotted list.
585The elements of the list are not copied, just the list structure itself." 689The elements of the list are not copied, just the list structure itself."