aboutsummaryrefslogtreecommitdiffstats
path: root/lisp
diff options
context:
space:
mode:
authorJohn Wiegley2000-10-29 05:18:48 +0000
committerJohn Wiegley2000-10-29 05:18:48 +0000
commitdace60cfea488a9cc8a775109c56b66907aa6abb (patch)
tree364b9c0114540a5f51a42e1e28a37b98714edaee /lisp
parent657f9cb8b7f7c3a9687f3998319ce63346ef13a4 (diff)
downloademacs-dace60cfea488a9cc8a775109c56b66907aa6abb.tar.gz
emacs-dace60cfea488a9cc8a775109c56b66907aa6abb.zip
See ChangeLog
Diffstat (limited to 'lisp')
-rw-r--r--lisp/ChangeLog123
-rw-r--r--lisp/calendar/timeclock.el434
-rw-r--r--lisp/eshell/em-alias.el7
-rw-r--r--lisp/eshell/em-dirs.el6
-rw-r--r--lisp/eshell/em-glob.el5
-rw-r--r--lisp/eshell/em-ls.el74
-rw-r--r--lisp/eshell/em-script.el3
-rw-r--r--lisp/eshell/em-smart.el35
-rw-r--r--lisp/eshell/em-unix.el129
-rw-r--r--lisp/eshell/esh-cmd.el120
-rw-r--r--lisp/eshell/esh-groups.el1
-rw-r--r--lisp/eshell/esh-maint.el68
-rw-r--r--lisp/eshell/esh-mode.el11
-rw-r--r--lisp/eshell/esh-module.el6
-rw-r--r--lisp/eshell/esh-test.el8
-rw-r--r--lisp/eshell/esh-util.el14
-rw-r--r--lisp/textmodes/flyspell.el56
17 files changed, 809 insertions, 291 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index 903612bed0b..706751d315a 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,124 @@
12000-10-28 John Wiegley <johnw@gnu.org>
2
3 * textmodes/flyspell.el (flyspell-maybe-correct-transposition):
4 Changed this function to operate on a temporary buffer instead of
5 the main buffer. This not only keeps flyspell from marking a
6 buffer as changed that wasn't, but it solves the jumpy cursor
7 problem when attempts are made to edit incorrect words.
8 (flyspell-maybe-correct-doubling): Same change as for
9 `flyspell-maybe-correct-transposition'.
10
11 * calendar/timeclock.el (timeclock-log): Doc fix.
12 (timeclock-last-event): Doc fix.
13 (timeclock-log): Kill the timelog buffer after appending a new
14 event.
15 (timeclock-find-discrep): Use a temp buffer to read in the
16 timelog, instead of visiting the file.
17 (timeclock-log-data): A new function, along with a host of helper
18 functions, for the purpose of making timelog data accessible to
19 programmers.
20
21 * eshell/esh-mode.el (window-height test): Make certain that
22 `eshell-stringify-t' is non-nil.
23 (eshell-password-prompt-regexp): Changed to a much simpler
24 password regexp.
25 (eshell-send-input): If `eshell-invoke-directly' returns t,
26 directly invoke the parsed command using `eval'. This improves
27 turn-around time on simple commands by a factor of three or
28 greater, such as cd, ls, pwd, etc. -- which get used very often.
29 It also conserves thousands of cons cells per call (since
30 `eshell-do-eval' consumes memory like a Cookie Monster set loose
31 in the Pacific Cookie Company).
32
33 * eshell/esh-test.el (eshell-test): Whitespace fix.
34
35 * eshell/em-ls.el (eshell-ls-insert-directory): Make
36 `eshell-ls-initial-args' nil when inserting directory contents.
37
38 * eshell/em-script.el (eshell-script-initialize): Add names to
39 `eshell-complex-commands, since `source' and `.' are complex.
40
41 * eshell/esh-cmd.el (eshell-rewrite-for-command,
42 eshell-rewrite-while-command): Use `eshell-protect' instead of
43 `eshell-copy-handles'.
44 (eshell-rewrite-if-command): Use `eshell-protect' to wrap the call
45 bodies.
46 (eshell-separate-commands): Whitespace fix.
47 (eshell-complex-commands): Added a new list of names, for
48 determining whether a given command is as simple as it looks.
49 (eshell-invoke-directly): New function. Returns t if a command
50 should be invoked directly (using `eval'), rather than indirectly
51 using `eshell-do-eval'.
52 (eshell-do-eval): Whitespace fix.
53
54 * eshell/em-unix.el (eshell-default-target-is-dot): New variable,
55 which provides an emulation of the DOS shell behavior of assuming
56 that cp/mv/ln should copy/move/link to the current directory.
57 (eshell-remove-entries): Added a doc string.
58 (eshell-shuffle-files): Removed the check for `target' being null.
59 (eshell-mvcp-template, eshell-mvcpln-template): Renamed
60 `eshell-mvcp-template' to `eshell-mvcpln-template', and extended
61 it to do a smarter check of whether a destination was provided.
62 (eshell/mv, eshell/cp): Enable `:preserve-args'.
63 (eshell/ln): Enable `:preserve-args', and use
64 `eshell-mvcpln-template' to implement the body of the function.
65 (eshell/cat, eshell/make, eshell-poor-mans-grep, eshell-grep,
66 eshell/du, eshell/diff, eshell/locate): Stringify the argument
67 list after flattening it. This makes it possible to cat files
68 with numerical names.
69 (eshell-unix-initialize): Added several names to
70 `eshell-complex-commands.
71 (eshell-unix-command-complex-p): Return t if a given command name
72 may result in external processes being invoked.
73
74 * eshell/em-glob.el (eshell-glob-show-progress): Make this
75 variable nil by default, since it slows down glob processing by a
76 factor of two or more, and increases memory consumption.
77
78 * eshell/em-smart.el: Added a note about how memory consumptive
79 smart display mode can be (at least this is true in Emacs 21).
80 (eshell-smart-initialize): Whitespace fix.
81 (eshell-refresh-windows): Use `if' instead of `when'.
82 (eshell-smart-scroll-window): Calling `save-current-buffer' was
83 not necessary.
84 (eshell-currently-handling-window): Added a missing global
85 variable.
86
87 * eshell/em-ls.el (eshell-do-ls): Code simplification.
88 (eshell-ls-sort-entries, eshell-ls-entries, eshell-ls-dir):
89 Whitespace fix.
90 (eshell-ls-exclude-hidden): Added this variable in addition to
91 `eshell-ls-exclude-regexp'. This one prevents files beginning
92 with . from even being read, which can improve memory consumption
93 quite a bit.
94 (eshell-ls-dir): If `eshell-ls-exclude-hidden' is non-nil, do not
95 read file entries beginning with a dot. In home directories with
96 lots of hidden files, fully two-thirds of the time spent in ls is
97 used to read directory entries that are immediately thrown away.
98 (eshell-ls-initial-args): Added back this configuration variable,
99 for specifying default initial arguments to every call to ls.
100 Much faster than using an alias to do the same thing.
101 (eshell-do-ls): Use `eshell-ls-initial-args', if set.
102 (eshell-ls-dir): Whitespace change.
103
104 * eshell/em-dirs.el (eshell/pwd): Small code simplification.
105
106 * eshell/esh-util.el: Don't require `ange-ftp' if it's not
107 available.
108 (eshell-stringify-t): Added a customization variable, to indicate
109 whether `t' should be rendered as a string at all. If not, one
110 can still determine if the result of an expression is true using
111 "file-exists-p FILE && echo true".
112 (eshell-stringify): If `eshell-stringify-t' is nil, don't
113 stringify t!
114
115 * eshell/esh-module.el: Whitespace fix.
116
117 * eshell/em-alias.el (eshell-alias-initialize): Added
118 `eshell-command-aliased-p' to `eshell-complex-commands'.
119 (eshell-command-aliased-p): New function that returns t if a
120 command name names an aliased.
121
12000-10-29 Michael Kifer <kifer@cs.sunysb.edu> 1222000-10-29 Michael Kifer <kifer@cs.sunysb.edu>
2 123
3 * viper-cmd.el (viper-preserve-cursor-color): new test that avoids 124 * viper-cmd.el (viper-preserve-cursor-color): new test that avoids
@@ -865,7 +986,7 @@
865 * align.el, pcomplete.el, calendar/timeclock.el, 986 * align.el, pcomplete.el, calendar/timeclock.el,
866 eshell/esh-module.el, eshell/eshell.el: Removed URL reference. 987 eshell/esh-module.el, eshell/eshell.el: Removed URL reference.
867 988
868 * calendar/timeclock.el (timeclock-find-discrep): A fix to same 989 * calendar/timeclock.el (timeclock-find-discrep): A fix to some
869 faulty math, where holiday hours were being computing as seconds. 990 faulty math, where holiday hours were being computing as seconds.
870 991
8712000-10-13 John Wiegley <johnw@gnu.org> 9922000-10-13 John Wiegley <johnw@gnu.org>
diff --git a/lisp/calendar/timeclock.el b/lisp/calendar/timeclock.el
index 265406d2e5f..d96250dde1d 100644
--- a/lisp/calendar/timeclock.el
+++ b/lisp/calendar/timeclock.el
@@ -4,7 +4,7 @@
4 4
5;; Author: John Wiegley <johnw@gnu.org> 5;; Author: John Wiegley <johnw@gnu.org>
6;; Created: 25 Mar 1999 6;; Created: 25 Mar 1999
7;; Version: 2.2 7;; Version: 2.3
8;; Keywords: calendar data 8;; Keywords: calendar data
9 9
10;; This file is part of GNU Emacs. 10;; This file is part of GNU Emacs.
@@ -222,8 +222,7 @@ in the modeline. See the variable `timeclock-modeline-display'."
222 222
223(defvar timeclock-last-event nil 223(defvar timeclock-last-event nil
224 "A list containing the last event that was recorded. 224 "A list containing the last event that was recorded.
225The format of this list is (CODE TIME PROJECT). PROJECT will be 225The format of this list is (CODE TIME PROJECT).")
226non-nil only if CODE is \"o\" or \"O\".")
227 226
228(defvar timeclock-last-event-workday nil 227(defvar timeclock-last-event-workday nil
229 "The number of seconds in the workday of `timeclock-last-event'.") 228 "The number of seconds in the workday of `timeclock-last-event'.")
@@ -455,7 +454,7 @@ as with time remaining, where negative time really means overtime)."
455 (truncate (/ (abs seconds) 60 60)) 454 (truncate (/ (abs seconds) 60 60))
456 (% (truncate (/ (abs seconds) 60)) 60)))) 455 (% (truncate (/ (abs seconds) 60)) 60))))
457 456
458(defun timeclock-workday-remaining (&optional today-only) 457(defsubst timeclock-workday-remaining (&optional today-only)
459 "Return a the number of seconds until the workday is complete. 458 "Return a the number of seconds until the workday is complete.
460The amount returned is relative to the value of `timeclock-workday'. 459The amount returned is relative to the value of `timeclock-workday'.
461If TODAY-ONLY is non-nil, the value returned will be relative only to 460If TODAY-ONLY is non-nil, the value returned will be relative only to
@@ -463,7 +462,7 @@ the time worked today, and not to past time. This argument only makes
463a difference if `timeclock-relative' is non-nil." 462a difference if `timeclock-relative' is non-nil."
464 (- (timeclock-find-discrep today-only))) 463 (- (timeclock-find-discrep today-only)))
465 464
466(defun timeclock-currently-in-p () 465(defsubst timeclock-currently-in-p ()
467 "Return non-nil if the user is currently clocked in." 466 "Return non-nil if the user is currently clocked in."
468 (equal (car timeclock-last-event) "i")) 467 (equal (car timeclock-last-event) "i"))
469 468
@@ -483,7 +482,7 @@ See `timeclock-relative' for more information about the meaning of
483 (message string) 482 (message string)
484 string))) 483 string)))
485 484
486(defun timeclock-workday-elapsed (&optional relative) 485(defsubst timeclock-workday-elapsed (&optional relative)
487 "Return a the number of seconds worked so far today. 486 "Return a the number of seconds worked so far today.
488If RELATIVE is non-nil, the amount returned will be relative to past 487If RELATIVE is non-nil, the amount returned will be relative to past
489time worked. The default is to return only the time that has elapsed 488time worked. The default is to return only the time that has elapsed
@@ -505,7 +504,7 @@ non-nil, the amount returned will be relative to past time worked."
505 (message string) 504 (message string)
506 string))) 505 string)))
507 506
508(defun timeclock-when-to-leave (&optional today-only) 507(defsubst timeclock-when-to-leave (&optional today-only)
509 "Return a time value representing at when the workday ends today. 508 "Return a time value representing at when the workday ends today.
510If TODAY-ONLY is non-nil, the value returned will be relative only to 509If TODAY-ONLY is non-nil, the value returned will be relative only to
511the time worked today, and not to past time. This argument only makes 510the time worked today, and not to past time. This argument only makes
@@ -578,9 +577,8 @@ non-nil."
578(defun timeclock-log (code &optional project) 577(defun timeclock-log (code &optional project)
579 "Log the event CODE to the timeclock log, at the time of call. 578 "Log the event CODE to the timeclock log, at the time of call.
580If PROJECT is a string, it represents the project which the event is 579If PROJECT is a string, it represents the project which the event is
581being logged for. Normally only \"out\" events specify a project." 580being logged for. Normally only \"in\" events specify a project."
582 (save-excursion 581 (with-current-buffer (find-file-noselect timeclock-file)
583 (set-buffer (find-file-noselect timeclock-file))
584 (goto-char (point-max)) 582 (goto-char (point-max))
585 (if (not (bolp)) 583 (if (not (bolp))
586 (insert "\n")) 584 (insert "\n"))
@@ -603,42 +601,40 @@ being logged for. Normally only \"out\" events specify a project."
603 timeclock-last-period))) 601 timeclock-last-period)))
604 (setq timeclock-last-event (list code now project))) 602 (setq timeclock-last-event (list code now project)))
605 (save-buffer) 603 (save-buffer)
606 (run-hooks 'timeclock-event-hook))) 604 (run-hooks 'timeclock-event-hook)
605 (kill-buffer (current-buffer))))
607 606
608(defun timeclock-read-moment () 607(defvar timeclock-moment-regexp
608 (concat "\\([bhioO]\\)\\s-+"
609 "\\([0-9]+\\)/\\([0-9]+\\)/\\([0-9]+\\)\\s-+"
610 "\\([0-9]+\\):\\([0-9]+\\):\\([0-9]+\\)[ \t]*" "\\([^\n]*\\)"))
611
612(defsubst timeclock-read-moment ()
609 "Read the moment under point from the timelog." 613 "Read the moment under point from the timelog."
610 (save-excursion 614 (if (looking-at timeclock-moment-regexp)
611 (beginning-of-line) 615 (let ((code (match-string 1))
612 (let ((eol (save-excursion (end-of-line) (point)))) 616 (year (string-to-number (match-string 2)))
613 (if (re-search-forward 617 (mon (string-to-number (match-string 3)))
614 (concat "^\\(.\\)\\s-+" 618 (mday (string-to-number (match-string 4)))
615 "\\([0-9]+\\)/\\([0-9]+\\)/\\([0-9]+\\)\\s-+" 619 (hour (string-to-number (match-string 5)))
616 "\\([0-9]+\\):\\([0-9]+\\):\\([0-9]+\\)\\s-*" 620 (min (string-to-number (match-string 6)))
617 "\\(.*\\)") eol t) 621 (sec (string-to-number (match-string 7)))
618 (let ((code (match-string 1)) 622 (project (match-string 8)))
619 (year (string-to-number (match-string 2))) 623 (list code (encode-time sec min hour mday mon year) project))))
620 (mon (string-to-number (match-string 3))) 624
621 (mday (string-to-number (match-string 4))) 625(defsubst timeclock-time-to-seconds (time)
622 (hour (string-to-number (match-string 5)))
623 (min (string-to-number (match-string 6)))
624 (sec (string-to-number (match-string 7)))
625 (project (match-string 8)))
626 (list code (encode-time sec min hour mday mon year)
627 project))))))
628
629(defun timeclock-time-to-seconds (time)
630 "Convert TIME to a floating point number." 626 "Convert TIME to a floating point number."
631 (+ (* (car time) 65536.0) 627 (+ (* (car time) 65536.0)
632 (cadr time) 628 (cadr time)
633 (/ (or (car (cdr (cdr time))) 0) 1000000.0))) 629 (/ (or (car (cdr (cdr time))) 0) 1000000.0)))
634 630
635(defun timeclock-seconds-to-time (seconds) 631(defsubst timeclock-seconds-to-time (seconds)
636 "Convert SECONDS (a floating point number) to an Emacs time structure." 632 "Convert SECONDS (a floating point number) to an Emacs time structure."
637 (list (floor seconds 65536) 633 (list (floor seconds 65536)
638 (floor (mod seconds 65536)) 634 (floor (mod seconds 65536))
639 (floor (* (- seconds (ffloor seconds)) 1000000)))) 635 (floor (* (- seconds (ffloor seconds)) 1000000))))
640 636
641(defun timeclock-time-to-date (time) 637(defsubst timeclock-time-to-date (time)
642 "Convert the TIME value to a textual date string." 638 "Convert the TIME value to a textual date string."
643 (format-time-string "%Y/%m/%d" time)) 639 (format-time-string "%Y/%m/%d" time))
644 640
@@ -655,49 +651,376 @@ This is only provided for coherency when used by
655 (cadr timeclock-last-event))) 651 (cadr timeclock-last-event)))
656 timeclock-last-period)) 652 timeclock-last-period))
657 653
654(defsubst timeclock-entry-length (entry)
655 (- (timeclock-time-to-seconds (cadr entry))
656 (timeclock-time-to-seconds (car entry))))
657
658(defsubst timeclock-entry-begin (entry)
659 (car entry))
660
661(defsubst timeclock-entry-end (entry)
662 (cadr entry))
663
664(defsubst timeclock-entry-project (entry)
665 (nth 2 entry))
666
667(defsubst timeclock-entry-comment (entry)
668 (nth 3 entry))
669
670
671(defsubst timeclock-entry-list-length (entry-list)
672 (let ((length 0))
673 (while entry-list
674 (setq length (+ length (timeclock-entry-length (car entry-list))))
675 (setq entry-list (cdr entry-list)))
676 length))
677
678(defsubst timeclock-entry-list-begin (entry-list)
679 (timeclock-entry-begin (car entry-list)))
680
681(defsubst timeclock-entry-list-end (entry-list)
682 (timeclock-entry-end (car (last entry-list))))
683
684(defsubst timeclock-entry-list-span (entry-list)
685 (- (timeclock-time-to-seconds (timeclock-entry-list-end entry-list))
686 (timeclock-time-to-seconds (timeclock-entry-list-begin entry-list))))
687
688(defsubst timeclock-entry-list-break (entry-list)
689 (- (timeclock-entry-list-span entry-list)
690 (timeclock-entry-list-length entry-list)))
691
692(defsubst timeclock-entry-list-projects (entry-list)
693 (let (projects)
694 (while entry-list
695 (let ((project (timeclock-entry-project (car entry-list))))
696 (if projects
697 (add-to-list 'projects project)
698 (setq projects (list project))))
699 (setq entry-list (cdr entry-list)))
700 projects))
701
702
703(defsubst timeclock-day-required (day)
704 (car day))
705
706(defsubst timeclock-day-length (day)
707 (timeclock-entry-list-length (cdr day)))
708
709(defsubst timeclock-day-debt (day)
710 (- (timeclock-day-required day)
711 (timeclock-day-length day)))
712
713(defsubst timeclock-day-begin (day)
714 (timeclock-entry-list-begin (cdr day)))
715
716(defsubst timeclock-day-end (day)
717 (timeclock-entry-list-end (cdr day)))
718
719(defsubst timeclock-day-span (day)
720 (timeclock-entry-list-span (cdr day)))
721
722(defsubst timeclock-day-break (day)
723 (timeclock-entry-list-break (cdr day)))
724
725(defsubst timeclock-day-projects (day)
726 (timeclock-entry-list-projects (cdr day)))
727
728(defmacro timeclock-day-list-template (func)
729 `(let ((length 0))
730 (while day-list
731 (setq length (+ length (,(eval func) (car day-list))))
732 (setq day-list (cdr day-list)))
733 length))
734
735(defun timeclock-day-list-required (day-list)
736 (timeclock-day-list-template 'timeclock-day-required))
737
738(defun timeclock-day-list-length (day-list)
739 (timeclock-day-list-template 'timeclock-day-length))
740
741(defun timeclock-day-list-debt (day-list)
742 (timeclock-day-list-template 'timeclock-day-debt))
743
744(defsubst timeclock-day-list-begin (day-list)
745 (timeclock-day-begin (car day-list)))
746
747(defsubst timeclock-day-list-end (day-list)
748 (timeclock-day-end (car (last day-list))))
749
750(defun timeclock-day-list-span (day-list)
751 (timeclock-day-list-template 'timeclock-day-span))
752
753(defun timeclock-day-list-break (day-list)
754 (timeclock-day-list-template 'timeclock-day-break))
755
756(defun timeclock-day-list-projects (day-list)
757 (let (projects)
758 (while day-list
759 (let ((projs (timeclock-day-projects (car day-list))))
760 (while projs
761 (if projects
762 (add-to-list 'projects (car projs))
763 (setq projects (list (car projs))))
764 (setq projs (cdr projs))))
765 (setq day-list (cdr day-list)))
766 projects))
767
768
769(defsubst timeclock-current-debt (&optional log-data)
770 (nth 0 (or log-data (timeclock-log-data))))
771
772(defsubst timeclock-day-alist (&optional log-data)
773 (nth 1 (or log-data (timeclock-log-data))))
774
775(defun timeclock-day-list (&optional log-data)
776 (let ((alist (timeclock-day-alist log-data))
777 day-list)
778 (while alist
779 (setq day-list (cons (cdar alist) day-list)
780 alist (cdr alist)))
781 day-list))
782
783(defsubst timeclock-project-alist (&optional log-data)
784 (nth 2 (or log-data (timeclock-log-data))))
785
786
787(defun timeclock-log-data (&optional recent-only filename)
788 "Return the contents of the timelog file, in a useful format.
789A timelog contains data in the form of a single entry per line.
790Each entry has the form:
791
792 CODE YYYY/MM/DD HH:MM:SS [COMMENT]
793
794CODE is one of: b, h, i, o or O. COMMENT is optional when the code is
795i, o or O. The meanings of the codes are:
796
797 b Set the current time balance, or \"time debt\". Useful when
798 archiving old log data, when a debt must be carried forward.
799 The COMMENT here is the number of seconds of debt.
800
801 h Set the required working time for the given day. This must
802 be the first entry for that day. The COMMENT in this case is
803 the number of hours that must be worked. Floating point
804 amounts are allowed.
805
806 i Clock in. The COMMENT in this case should be the name of the
807 project worked on.
808
809 o Clock out. COMMENT is unnecessary, but can be used to provide
810 a description of how the period went, for example.
811
812 O Final clock out. Whatever project was being worked on, it is
813 now finished. Useful for creating summary reports.
814
815When this function is called, it will return a data structure with the
816following format:
817
818 (DEBT ENTRIES-BY-DAY ENTRIES-BY-PROJECT)
819
820DEBT is a floating point number representing the number of seconds
821\"owed\" before any work was done. For a new file (one without a 'b'
822entry), this is always zero.
823
824The two entries lists have similar formats. They are both alists,
825where the CAR is the index, and the CDR is a list of time entries.
826For ENTRIES-BY-DAY, the CAR is a textual date string, of the form
827YYYY/MM/DD. For ENTRIES-BY-PROJECT, it is the name of the project
828worked on, or t for the default project.
829
830The CDR for ENTRIES-BY-DAY is slightly different than for
831ENTRIES-BY-PROJECT. It has the following form:
832
833 (DAY-LENGTH TIME-ENTRIES...)
834
835For ENTRIES-BY-PROJECT, there is no DAY-LENGTH member. It is simply a
836list of TIME-ENTRIES. Note that if DAY-LENGTH is nil, it means
837whatever is the default should be used.
838
839A TIME-ENTRY is a recorded time interval. It has the following format
840\(although generally one does not have to manipulate these entries
841directly; see below):
842
843 (BEGIN-TIME END-TIME PROJECT [COMMENT] [FINAL-P])
844
845Anyway, suffice it to say there are a lot of structures. Typically
846the user is expected to manipulate to the day(s) or project(s) that he
847or she wants, at which point the following helper functions may be
848used:
849
850 timeclock-day-required
851 timeclock-day-length
852 timeclock-day-debt
853 timeclock-day-begin
854 timeclock-day-end
855 timeclock-day-span
856 timeclock-day-break
857 timeclock-day-projects
858
859 timeclock-day-list-required
860 timeclock-day-list-length
861 timeclock-day-list-debt
862 timeclock-day-list-begin
863 timeclock-day-list-end
864 timeclock-day-list-span
865 timeclock-day-list-break
866 timeclock-day-list-projects
867
868 timeclock-entry-length
869 timeclock-entry-begin
870 timeclock-entry-end
871 timeclock-entry-project
872 timeclock-entry-comment
873
874 timeclock-entry-list-length
875 timeclock-entry-list-begin
876 timeclock-entry-list-end
877 timeclock-entry-list-span
878 timeclock-entry-list-break
879 timeclock-entry-list-projects
880
881A few comments should make the use of the above functions obvious:
882
883 `required' is the amount of time that must be spent during a day, or
884 sequence of days, in order to have no debt.
885
886 `length' is the actual amount of time that was spent.
887
888 `debt' is the difference between required time and length. A
889 negative debt signifies overtime.
890
891 `begin' is the earliest moment at which work began.
892
893 `end' is the final moment work was done.
894
895 `span' is the difference between begin and end.
896
897 `break' is the difference between span and length.
898
899 `project' is the project that was worked on, and `projects' is a
900 list of all the projects that were worked on during a given period.
901
902 `comment', where it applies, could mean anything.
903
904There are a few more functions available, for locating day and entry
905lists:
906
907 timeclock-day-alist LOG-DATA
908 timeclock-project-alist LOG-DATA
909 timeclock-current-debt LOG-DATA
910
911See the documentation for the given function if more info is needed."
912 (let* ((log-data (list 0.0 nil nil))
913 (now (current-time))
914 (todays-date (timeclock-time-to-date now))
915 last-date-limited last-date-seconds last-date
916 (line 0) last beg day entry)
917 (with-temp-buffer
918 (insert-file-contents (or filename timeclock-file))
919 (when recent-only
920 (goto-char (point-max))
921 (unless (re-search-backward "^b\\s-+" nil t)
922 (goto-char (point-min))))
923 (while (or (setq event (timeclock-read-moment))
924 (and beg (not last)
925 (setq last t event (list "o" now))))
926 (setq line (1+ line))
927 (cond ((equal (car event) "b")
928 (setcar log-data (string-to-number (nth 2 event))))
929 ((equal (car event) "h")
930 (setq last-date-limited (timeclock-time-to-date (cadr event))
931 last-date-seconds (* (string-to-number (nth 2 event))
932 3600.0)))
933 ((equal (car event) "i")
934 (if beg
935 (error "Error in format of timelog file, line %d" line)
936 (setq beg t))
937 (setq entry (list (cadr event) nil
938 (and (> (length (nth 2 event)) 0)
939 (nth 2 event))))
940 (let ((date (timeclock-time-to-date (cadr event))))
941 (if (and last-date
942 (not (equal date last-date)))
943 (setcar (cdr log-data)
944 (cons (cons last-date day)
945 (cadr log-data)))
946 (setq day (list (and last-date-limited
947 last-date-seconds))))
948 (setq last-date date
949 last-date-limited nil)))
950 ((equal (downcase (car event)) "o")
951 (if (not beg)
952 (error "Error in format of timelog file, line %d" line)
953 (setq beg nil))
954 (setcar (cdr entry) (cadr event))
955 (let ((desc (and (> (length (nth 2 event)) 0)
956 (nth 2 event))))
957 (if desc
958 (nconc entry (list (nth 2 event))))
959 (if (equal (car event) "O")
960 (nconc entry (if desc
961 (list t)
962 (list nil t))))
963 (nconc day (list entry))
964 (setq desc (nth 2 entry))
965 (let ((proj (assoc desc (nth 2 log-data))))
966 (if (not proj)
967 (setcar (cddr log-data)
968 (cons (cons desc (list entry))
969 (car (cddr log-data))))
970 (nconc (cdr proj) (list entry)))))))
971 (forward-line))
972 (if day
973 (setcar (cdr log-data)
974 (cons (cons last-date day)
975 (cadr log-data))))
976 log-data)))
977
658(defun timeclock-find-discrep (&optional today-only) 978(defun timeclock-find-discrep (&optional today-only)
659 "Find overall discrepancy from `timeclock-workday' (in seconds). 979 "Find overall discrepancy from `timeclock-workday' (in seconds).
660If TODAY-ONLY is non-nil, the discrepancy will be not be relative, and 980If TODAY-ONLY is non-nil, the discrepancy will be not be relative, and
661will correspond only to the amount of time elapsed today. This is 981will correspond only to the amount of time elapsed today. This is
662identical to what would be return if `timeclock-relative' were nil." 982identical to what would be return if `timeclock-relative' were nil."
663 (let* ((now (current-time)) (first t) 983 ;; This is not implemented in terms of the functions above, because
984 ;; it's a bit wasteful to read all of that data in, just to throw
985 ;; away more than 90% of the information afterwards.
986 (let* ((now (current-time))
664 (todays-date (timeclock-time-to-date now)) 987 (todays-date (timeclock-time-to-date now))
665 accum event beg last-date 988 (first t) (accum 0)
666 last-date-limited last-date-seconds avg) 989 event beg last-date avg
990 last-date-limited last-date-seconds)
667 (unless timeclock-discrepancy 991 (unless timeclock-discrepancy
668 (setq timeclock-project-list nil 992 (setq timeclock-project-list nil
669 timeclock-last-project nil 993 timeclock-last-project nil
670 timeclock-reason-list nil) 994 timeclock-reason-list nil
671 (save-excursion 995 timeclock-elapsed 0)
672 (set-buffer (find-file-noselect timeclock-file)) 996 (with-temp-buffer
673 (goto-char (point-min)) 997 (insert-file-contents timeclock-file)
674 (setq accum 0) 998 (goto-char (point-max))
675 (setq timeclock-elapsed 0) 999 (unless (re-search-backward "^b\\s-+" nil t)
1000 (goto-char (point-min)))
676 (while (setq event (timeclock-read-moment)) 1001 (while (setq event (timeclock-read-moment))
677 (cond ((equal (car event) "h") 1002 (cond ((equal (car event) "b")
1003 (setq accum (string-to-number (nth 2 event))))
1004 ((equal (car event) "h")
678 (setq last-date-limited 1005 (setq last-date-limited
679 (timeclock-time-to-date (cadr event)) 1006 (timeclock-time-to-date (cadr event))
680 last-date-seconds 1007 last-date-seconds
681 (* (string-to-number (nth 2 event)) 3600))) 1008 (* (string-to-number (nth 2 event)) 3600.0)))
682 ((equal (car event) "i") 1009 ((equal (car event) "i")
683 (when (and (nth 2 event) 1010 (when (and (nth 2 event)
684 (> (length (nth 2 event)) 0)) 1011 (> (length (nth 2 event)) 0))
685 (add-to-list 'timeclock-project-list (nth 2 event)) 1012 (add-to-list 'timeclock-project-list (nth 2 event))
686 (setq timeclock-last-project (nth 2 event))) 1013 (setq timeclock-last-project (nth 2 event)))
687 (let ((date (timeclock-time-to-date (cadr event)))) 1014 (let ((date (timeclock-time-to-date (cadr event))))
688 (if (and last-date 1015 (if (and timeclock-relative
689 timeclock-relative 1016 (if last-date
690 (not (equal date last-date))) 1017 (not (equal date last-date))
691 (setq accum (- accum 1018 first))
692 (if last-date-limited
693 last-date-seconds
694 timeclock-workday)))
695 (unless (or last-date (not first))
696 (setq first nil 1019 (setq first nil
697 accum (- accum 1020 accum (- accum
698 (if last-date-limited 1021 (if last-date-limited
699 last-date-seconds 1022 last-date-seconds
700 timeclock-workday))))) 1023 timeclock-workday))))
701 (setq last-date date 1024 (setq last-date date
702 last-date-limited nil) 1025 last-date-limited nil)
703 (if beg 1026 (if beg
@@ -712,8 +1035,7 @@ identical to what would be return if `timeclock-relative' were nil."
712 (if (not beg) 1035 (if (not beg)
713 (error "Error in format of timelog file!") 1036 (error "Error in format of timelog file!")
714 (setq timeclock-last-period 1037 (setq timeclock-last-period
715 (- (timeclock-time-to-seconds (cadr event)) 1038 (- (timeclock-time-to-seconds (cadr event)) beg)
716 beg)
717 accum (+ timeclock-last-period accum) 1039 accum (+ timeclock-last-period accum)
718 beg nil))) 1040 beg nil)))
719 (if (equal last-date todays-date) 1041 (if (equal last-date todays-date)
diff --git a/lisp/eshell/em-alias.el b/lisp/eshell/em-alias.el
index 85e4e97e692..a407bf5deb8 100644
--- a/lisp/eshell/em-alias.el
+++ b/lisp/eshell/em-alias.el
@@ -151,7 +151,12 @@ command, which will automatically write them to the file named by
151 (add-hook 'eshell-alternate-command-hook 'eshell-fix-bad-commands t t) 151 (add-hook 'eshell-alternate-command-hook 'eshell-fix-bad-commands t t)
152 (eshell-read-aliases-list) 152 (eshell-read-aliases-list)
153 (make-local-hook 'eshell-named-command-hook) 153 (make-local-hook 'eshell-named-command-hook)
154 (add-hook 'eshell-named-command-hook 'eshell-maybe-replace-by-alias t t)) 154 (add-hook 'eshell-named-command-hook 'eshell-maybe-replace-by-alias t t)
155 (make-local-variable 'eshell-complex-commands)
156 (add-to-list 'eshell-complex-commands 'eshell-command-aliased-p))
157
158(defun eshell-command-aliased-p (name)
159 (member name eshell-command-aliases-list))
155 160
156(defun eshell/alias (&optional alias &rest definition) 161(defun eshell/alias (&optional alias &rest definition)
157 "Define an ALIAS in the user's alias list using DEFINITION." 162 "Define an ALIAS in the user's alias list using DEFINITION."
diff --git a/lisp/eshell/em-dirs.el b/lisp/eshell/em-dirs.el
index 02d1eb3076b..0c147f14be6 100644
--- a/lisp/eshell/em-dirs.el
+++ b/lisp/eshell/em-dirs.el
@@ -297,7 +297,7 @@ Thus, this does not include the current directory.")
297 (file-name-as-directory (cdr user)))) 297 (file-name-as-directory (cdr user))))
298 eshell-user-names))))))) 298 eshell-user-names)))))))
299 299
300(defun eshell/pwd (&rest args) ; ignored 300(defun eshell/pwd (&rest args)
301 "Change output from `pwd` to be cleaner." 301 "Change output from `pwd` to be cleaner."
302 (let* ((path default-directory) 302 (let* ((path default-directory)
303 (len (length path))) 303 (len (length path)))
@@ -307,8 +307,8 @@ Thus, this does not include the current directory.")
307 (string-match "\\`[A-Za-z]:[\\\\/]\\'" path)))) 307 (string-match "\\`[A-Za-z]:[\\\\/]\\'" path))))
308 (setq path (substring path 0 (1- (length path))))) 308 (setq path (substring path 0 (1- (length path)))))
309 (if eshell-pwd-convert-function 309 (if eshell-pwd-convert-function
310 (setq path (funcall eshell-pwd-convert-function path))) 310 (funcall eshell-pwd-convert-function path)
311 path)) 311 path)))
312 312
313(defun eshell-expand-multiple-dots (path) 313(defun eshell-expand-multiple-dots (path)
314 "Convert '...' to '../..', '....' to '../../..', etc.. 314 "Convert '...' to '../..', '....' to '../../..', etc..
diff --git a/lisp/eshell/em-glob.el b/lisp/eshell/em-glob.el
index b281cee4fd7..f4f9ebbe5b6 100644
--- a/lisp/eshell/em-glob.el
+++ b/lisp/eshell/em-glob.el
@@ -81,8 +81,9 @@ by zsh for filename generation."
81 :type 'boolean 81 :type 'boolean
82 :group 'eshell-glob) 82 :group 'eshell-glob)
83 83
84(defcustom eshell-glob-show-progress t 84(defcustom eshell-glob-show-progress nil
85 "*If non-nil, display progress messages during a recursive glob." 85 "*If non-nil, display progress messages during a recursive glob.
86This option slows down recursive glob processing by quite a bit."
86 :type 'boolean 87 :type 'boolean
87 :group 'eshell-glob) 88 :group 'eshell-glob)
88 89
diff --git a/lisp/eshell/em-ls.el b/lisp/eshell/em-ls.el
index 2afef625f55..534ea932c3c 100644
--- a/lisp/eshell/em-ls.el
+++ b/lisp/eshell/em-ls.el
@@ -57,6 +57,12 @@ properties to colorize its output based on the setting of
57 :type 'hook 57 :type 'hook
58 :group 'eshell-ls) 58 :group 'eshell-ls)
59 59
60(defcustom eshell-ls-initial-args nil
61 "*If non-nil, this list of args is included before any call to `ls'.
62This is useful for enabling human-readable format (-h), for example."
63 :type '(repeat :tag "Arguments" string)
64 :group 'eshell-ls)
65
60(defcustom eshell-ls-use-in-dired nil 66(defcustom eshell-ls-use-in-dired nil
61 "*If non-nil, use `eshell-ls' to read directories in dired." 67 "*If non-nil, use `eshell-ls' to read directories in dired."
62 :set (lambda (symbol value) 68 :set (lambda (symbol value)
@@ -77,11 +83,18 @@ properties to colorize its output based on the setting of
77 :type 'integer 83 :type 'integer
78 :group 'eshell-ls) 84 :group 'eshell-ls)
79 85
80(defcustom eshell-ls-exclude-regexp "\\`\\." 86(defcustom eshell-ls-exclude-regexp nil
81 "*Unless -a is specified, files matching this regexp will not be shown." 87 "*Unless -a is specified, files matching this regexp will not be shown."
82 :type 'regexp 88 :type 'regexp
83 :group 'eshell-ls) 89 :group 'eshell-ls)
84 90
91(defcustom eshell-ls-exclude-hidden t
92 "*Unless -a is specified, files beginning with . will not be shown.
93Using this boolean, instead of `eshell-ls-exclude-regexp', is both
94faster and conserves more memory."
95 :type 'boolean
96 :group 'eshell-ls)
97
85(defcustom eshell-ls-use-colors t 98(defcustom eshell-ls-use-colors t
86 "*If non-nil, use colors in file listings." 99 "*If non-nil, use colors in file listings."
87 :type 'boolean 100 :type 'boolean
@@ -196,13 +209,13 @@ This is really just for efficiency, to avoid having to stat the file
196yet again." 209yet again."
197 `(if (numberp (nth 2 ,attrs)) 210 `(if (numberp (nth 2 ,attrs))
198 (if (= (user-uid) (nth 2 ,attrs)) 211 (if (= (user-uid) (nth 2 ,attrs))
199 (not (eq (aref (nth 8 ,attrs) ,index) ?-)) 212 (not (eq (aref (nth 8 ,attrs) ,index) ?-))
200 (,(eval func) ,file)) 213 (,(eval func) ,file))
201 (not (eq (aref (nth 8 ,attrs) 214 (not (eq (aref (nth 8 ,attrs)
202 (+ ,index (if (member (nth 2 ,attrs) 215 (+ ,index (if (member (nth 2 ,attrs)
203 (eshell-current-ange-uids)) 216 (eshell-current-ange-uids))
204 0 6))) 217 0 6)))
205 ?-)))) 218 ?-))))
206 219
207(defcustom eshell-ls-highlight-alist nil 220(defcustom eshell-ls-highlight-alist nil
208 "*This alist correlates test functions to color. 221 "*This alist correlates test functions to color.
@@ -248,7 +261,8 @@ instead."
248 (symbol-value 'font-lock-buffers))))) 261 (symbol-value 'font-lock-buffers)))))
249 (let ((insert-func 'insert) 262 (let ((insert-func 'insert)
250 (error-func 'insert) 263 (error-func 'insert)
251 (flush-func 'ignore)) 264 (flush-func 'ignore)
265 eshell-ls-initial-args)
252 (eshell-do-ls (append switches (list file)))))))) 266 (eshell-do-ls (append switches (list file))))))))
253 267
254(defsubst eshell/ls (&rest args) 268(defsubst eshell/ls (&rest args)
@@ -281,7 +295,9 @@ instead."
281 (funcall flush-func -1) 295 (funcall flush-func -1)
282 ;; process the command arguments, and begin listing files 296 ;; process the command arguments, and begin listing files
283 (eshell-eval-using-options 297 (eshell-eval-using-options
284 "ls" args 298 "ls" (if eshell-ls-initial-args
299 (list eshell-ls-initial-args args)
300 args)
285 `((?a "all" nil show-all 301 `((?a "all" nil show-all
286 "show all files in directory") 302 "show all files in directory")
287 (?c nil by-ctime sort-method 303 (?c nil by-ctime sort-method
@@ -343,11 +359,11 @@ Sort entries alphabetically across.")
343 (error (concat "-I option requires that `eshell-glob'" 359 (error (concat "-I option requires that `eshell-glob'"
344 " be a member of `eshell-modules-list'"))) 360 " be a member of `eshell-modules-list'")))
345 (set-text-properties 0 (length ignore-pattern) nil ignore-pattern) 361 (set-text-properties 0 (length ignore-pattern) nil ignore-pattern)
346 (if eshell-ls-exclude-regexp 362 (setq eshell-ls-exclude-regexp
347 (setq eshell-ls-exclude-regexp 363 (if eshell-ls-exclude-regexp
348 (concat "\\(" eshell-ls-exclude-regexp "\\|" 364 (concat "\\(" eshell-ls-exclude-regexp "\\|"
349 (eshell-glob-regexp ignore-pattern) "\\)")) 365 (eshell-glob-regexp ignore-pattern) "\\)")
350 (setq eshell-ls-exclude-regexp (eshell-glob-regexp ignore-pattern)))) 366 (eshell-glob-regexp ignore-pattern))))
351 ;; list the files! 367 ;; list the files!
352 (eshell-ls-entries 368 (eshell-ls-entries
353 (mapcar (function 369 (mapcar (function
@@ -356,7 +372,8 @@ Sort entries alphabetically across.")
356 (file-name-absolute-p arg)) 372 (file-name-absolute-p arg))
357 (expand-file-name arg) 373 (expand-file-name arg)
358 arg) 374 arg)
359 (eshell-file-attributes arg)))) args) 375 (eshell-file-attributes arg))))
376 args)
360 t (expand-file-name default-directory))) 377 t (expand-file-name default-directory)))
361 (funcall flush-func))) 378 (funcall flush-func)))
362 379
@@ -491,12 +508,13 @@ relative to that directory."
491 (file-relative-name dir root-dir) 508 (file-relative-name dir root-dir)
492 (expand-file-name dir))) 509 (expand-file-name dir)))
493 (cdr dirinfo))) ":\n")) 510 (cdr dirinfo))) ":\n"))
494 (let ((entries 511 (let ((entries (eshell-directory-files-and-attributes
495 (eshell-directory-files-and-attributes dir nil nil t))) 512 dir nil (and (not show-all)
496 (unless show-all 513 eshell-ls-exclude-hidden
497 (while (and entries 514 "\\`[^.]") t)))
498 (string-match eshell-ls-exclude-regexp 515 (when (and (not show-all) eshell-ls-exclude-regexp)
499 (caar entries))) 516 (while (and entries (string-match eshell-ls-exclude-regexp
517 (caar entries)))
500 (setq entries (cdr entries))) 518 (setq entries (cdr entries)))
501 (let ((e entries)) 519 (let ((e entries))
502 (while (cdr e) 520 (while (cdr e)
@@ -552,17 +570,13 @@ In Eshell's implementation of ls, ENTRIES is always reversed."
552 (let ((result 570 (let ((result
553 (cond 571 (cond
554 ((eq sort-method 'by-atime) 572 ((eq sort-method 'by-atime)
555 (eshell-ls-compare-entries 573 (eshell-ls-compare-entries l r 4 'eshell-time-less-p))
556 l r 4 'eshell-time-less-p))
557 ((eq sort-method 'by-mtime) 574 ((eq sort-method 'by-mtime)
558 (eshell-ls-compare-entries 575 (eshell-ls-compare-entries l r 5 'eshell-time-less-p))
559 l r 5 'eshell-time-less-p))
560 ((eq sort-method 'by-ctime) 576 ((eq sort-method 'by-ctime)
561 (eshell-ls-compare-entries 577 (eshell-ls-compare-entries l r 6 'eshell-time-less-p))
562 l r 6 'eshell-time-less-p))
563 ((eq sort-method 'by-size) 578 ((eq sort-method 'by-size)
564 (eshell-ls-compare-entries 579 (eshell-ls-compare-entries l r 7 '<))
565 l r 7 '<))
566 ((eq sort-method 'by-extension) 580 ((eq sort-method 'by-extension)
567 (let ((lx (file-name-extension 581 (let ((lx (file-name-extension
568 (directory-file-name (car l)))) 582 (directory-file-name (car l))))
@@ -699,8 +713,8 @@ need to be printed."
699 (if (and need-return (not dir-literal)) 713 (if (and need-return (not dir-literal))
700 (funcall insert-func "\n")) 714 (funcall insert-func "\n"))
701 (eshell-ls-dir dir show-names 715 (eshell-ls-dir dir show-names
702 (unless (file-name-absolute-p (car dir)) 716 (unless (file-name-absolute-p (car dir)) root-dir)
703 root-dir) size-width) 717 size-width)
704 (setq need-return t)))) 718 (setq need-return t))))
705 719
706(defun eshell-ls-find-column-widths (files) 720(defun eshell-ls-find-column-widths (files)
diff --git a/lisp/eshell/em-script.el b/lisp/eshell/em-script.el
index d6a8ea54e2f..8967426cadf 100644
--- a/lisp/eshell/em-script.el
+++ b/lisp/eshell/em-script.el
@@ -63,6 +63,9 @@ This includes when running `eshell-command'."
63 (string= (file-name-nondirectory file) 63 (string= (file-name-nondirectory file)
64 "eshell")) . eshell/source) 64 "eshell")) . eshell/source)
65 eshell-interpreter-alist)) 65 eshell-interpreter-alist))
66 (make-local-variable 'eshell-complex-commands)
67 (setq eshell-complex-commands
68 (append '("source" ".") eshell-complex-commands))
66 ;; these two variables are changed through usage, but we don't want 69 ;; these two variables are changed through usage, but we don't want
67 ;; to ruin it for other modules 70 ;; to ruin it for other modules
68 (let (eshell-inside-quote-regexp 71 (let (eshell-inside-quote-regexp
diff --git a/lisp/eshell/em-smart.el b/lisp/eshell/em-smart.el
index cc02f2fedc3..9bef8b10d20 100644
--- a/lisp/eshell/em-smart.el
+++ b/lisp/eshell/em-smart.el
@@ -77,6 +77,11 @@ it to get a real sense of how it works."
77;; scroll, etc. 77;; scroll, etc.
78;; 78;;
79;; @ Like I said, it's not really comprehensible until you try it! ;) 79;; @ Like I said, it's not really comprehensible until you try it! ;)
80;;
81;; One disadvantage of this module is that it increases Eshell's
82;; memory consumption by a factor of two or more. With small commands
83;; (such as pwd), where the screen is mostly full, consumption can
84;; increase by orders of magnitude.
80 85
81;;; User Variables: 86;;; User Variables:
82 87
@@ -154,6 +159,7 @@ The options are `begin', `after' or `end'."
154 159
155(defvar eshell-smart-displayed nil) 160(defvar eshell-smart-displayed nil)
156(defvar eshell-smart-command-done nil) 161(defvar eshell-smart-command-done nil)
162(defvar eshell-currently-handling-window nil)
157 163
158;;; Functions: 164;;; Functions:
159 165
@@ -175,19 +181,17 @@ The options are `begin', `after' or `end'."
175 181
176 (make-local-hook 'pre-command-hook) 182 (make-local-hook 'pre-command-hook)
177 (make-local-hook 'after-change-functions) 183 (make-local-hook 'after-change-functions)
178 (add-hook 'after-change-functions 184 (add-hook 'after-change-functions 'eshell-disable-after-change nil t)
179 'eshell-disable-after-change nil t)
180 185
181 (make-local-hook 'eshell-input-filter-functions) 186 (make-local-hook 'eshell-input-filter-functions)
182 (add-hook 'eshell-input-filter-functions 187 (add-hook 'eshell-input-filter-functions 'eshell-smart-display-setup nil t)
183 'eshell-smart-display-setup nil t)
184 188
185 (make-local-variable 'eshell-smart-command-done) 189 (make-local-variable 'eshell-smart-command-done)
186 (make-local-hook 'eshell-post-command-hook) 190 (make-local-hook 'eshell-post-command-hook)
187 (add-hook 'eshell-post-command-hook 191 (add-hook 'eshell-post-command-hook
188 (function 192 (function
189 (lambda () 193 (lambda ()
190 (setq eshell-smart-command-done t))) t t) 194 (setq eshell-smart-command-done t))) t t)
191 195
192 (unless (eq eshell-review-quick-commands t) 196 (unless (eq eshell-review-quick-commands t)
193 (add-hook 'eshell-post-command-hook 197 (add-hook 'eshell-post-command-hook
@@ -198,10 +202,9 @@ The options are `begin', `after' or `end'."
198 (unless eshell-currently-handling-window 202 (unless eshell-currently-handling-window
199 (let ((inhibit-point-motion-hooks t) 203 (let ((inhibit-point-motion-hooks t)
200 (eshell-currently-handling-window t)) 204 (eshell-currently-handling-window t))
201 (save-current-buffer 205 (save-selected-window
202 (save-selected-window 206 (select-window wind)
203 (select-window wind) 207 (eshell-smart-redisplay)))))
204 (eshell-smart-redisplay))))))
205 208
206(defun eshell-refresh-windows (&optional frame) 209(defun eshell-refresh-windows (&optional frame)
207 "Refresh all visible Eshell buffers." 210 "Refresh all visible Eshell buffers."
@@ -210,10 +213,10 @@ The options are `begin', `after' or `end'."
210 (function 213 (function
211 (lambda (wind) 214 (lambda (wind)
212 (with-current-buffer (window-buffer wind) 215 (with-current-buffer (window-buffer wind)
213 (when eshell-mode 216 (if eshell-mode
214 (let (window-scroll-functions) 217 (let (window-scroll-functions)
215 (eshell-smart-scroll-window wind (window-start)) 218 (eshell-smart-scroll-window wind (window-start))
216 (setq affected t)))))) 219 (setq affected t))))))
217 0 frame) 220 0 frame)
218 (if affected 221 (if affected
219 (let (window-scroll-functions) 222 (let (window-scroll-functions)
diff --git a/lisp/eshell/em-unix.el b/lisp/eshell/em-unix.el
index 7f0414ef056..c9b3d418b83 100644
--- a/lisp/eshell/em-unix.el
+++ b/lisp/eshell/em-unix.el
@@ -124,6 +124,11 @@ Otherwise, `rmdir' is required."
124 :type 'boolean 124 :type 'boolean
125 :group 'eshell-unix) 125 :group 'eshell-unix)
126 126
127(defcustom eshell-default-target-is-dot nil
128 "*If non-nil, the default destination for cp, mv or ln is `.'."
129 :type 'boolean
130 :group 'eshell-unix)
131
127(defcustom eshell-du-prefer-over-ange nil 132(defcustom eshell-du-prefer-over-ange nil
128 "*Use Eshell's du in ange-ftp remote directories. 133 "*Use Eshell's du in ange-ftp remote directories.
129Otherwise, Emacs will attempt to use rsh to invoke du on the remote machine." 134Otherwise, Emacs will attempt to use rsh to invoke du on the remote machine."
@@ -140,7 +145,12 @@ Otherwise, Emacs will attempt to use rsh to invoke du on the remote machine."
140 (when (eshell-using-module 'eshell-cmpl) 145 (when (eshell-using-module 'eshell-cmpl)
141 (make-local-hook 'pcomplete-try-first-hook) 146 (make-local-hook 'pcomplete-try-first-hook)
142 (add-hook 'pcomplete-try-first-hook 147 (add-hook 'pcomplete-try-first-hook
143 'eshell-complete-host-reference nil t))) 148 'eshell-complete-host-reference nil t))
149 (make-local-variable 'eshell-complex-commands)
150 (setq eshell-complex-commands
151 (append '("grep" "egrep" "fgrep" "agrep" "glimpse" "locate"
152 "cat" "time" "cp" "mv" "make" "du" "diff")
153 eshell-complex-commands)))
144 154
145(defalias 'eshell/date 'current-time-string) 155(defalias 'eshell/date 'current-time-string)
146(defalias 'eshell/basename 'file-name-nondirectory) 156(defalias 'eshell/basename 'file-name-nondirectory)
@@ -157,6 +167,7 @@ Otherwise, Emacs will attempt to use rsh to invoke du on the remote machine."
157 (funcall 'man (apply 'eshell-flatten-and-stringify args))) 167 (funcall 'man (apply 'eshell-flatten-and-stringify args)))
158 168
159(defun eshell-remove-entries (path files &optional top-level) 169(defun eshell-remove-entries (path files &optional top-level)
170 "From PATH, remove all of the given FILES, perhaps interactively."
160 (while files 171 (while files
161 (if (string-match "\\`\\.\\.?\\'" 172 (if (string-match "\\`\\.\\.?\\'"
162 (file-name-nondirectory (car files))) 173 (file-name-nondirectory (car files)))
@@ -302,8 +313,6 @@ Remove the DIRECTORY(ies), if they are empty.")
302 313
303(defun eshell-shuffle-files (command action files target func deep &rest args) 314(defun eshell-shuffle-files (command action files target func deep &rest args)
304 "Shuffle around some filesystem entries, using FUNC to do the work." 315 "Shuffle around some filesystem entries, using FUNC to do the work."
305 (if (null target)
306 (error "%s: missing destination file" command))
307 (let ((attr-target (eshell-file-attributes target)) 316 (let ((attr-target (eshell-file-attributes target))
308 (is-dir (or (file-directory-p target) 317 (is-dir (or (file-directory-p target)
309 (and preview (not eshell-warn-dot-directories)))) 318 (and preview (not eshell-warn-dot-directories))))
@@ -417,30 +426,35 @@ Remove the DIRECTORY(ies), if they are empty.")
417 (format "tar %s %s" tar-args archive) args)))) 426 (format "tar %s %s" tar-args archive) args))))
418 427
419;; this is to avoid duplicating code... 428;; this is to avoid duplicating code...
420(defmacro eshell-mvcp-template 429(defmacro eshell-mvcpln-template (command action func query-var
421 (command action func query-var force-var &optional preserve) 430 force-var &optional preserve)
422 `(if (and (string-match eshell-tar-regexp (car (last args))) 431 `(let ((len (length args)))
423 (or (> (length args) 2) 432 (if (or (= len 0)
424 (and (file-directory-p (car args)) 433 (and (= len 1) (null eshell-default-target-is-dot)))
425 (or (not no-dereference) 434 (error "%s: missing destination file or directory" ,command))
426 (not (file-symlink-p (car args))))))) 435 (if (= len 1)
427 (eshell-shorthand-tar-command ,command args) 436 (nconc args '(".")))
428 (let (target ange-cache) 437 (setq args (eshell-stringify-list (eshell-flatten-list args)))
429 (if (> (length args) 1) 438 (if (and ,(not (equal command "ln"))
430 (progn 439 (string-match eshell-tar-regexp (car (last args)))
431 (setq target (car (last args))) 440 (or (> (length args) 2)
432 (setcdr (last args 2) nil)) 441 (and (file-directory-p (car args))
433 (setq args nil)) 442 (or (not no-dereference)
434 (eshell-shuffle-files 443 (not (file-symlink-p (car args)))))))
435 ,command ,action args target ,func nil 444 (eshell-shorthand-tar-command ,command args)
436 ,@(append 445 (let ((target (car (last args)))
437 `((if (and (or interactive 446 ange-cache)
438 ,query-var) 447 (setcdr (last args 2) nil)
439 (not force)) 448 (eshell-shuffle-files
440 1 (or force ,force-var))) 449 ,command ,action args target ,func nil
441 (if preserve 450 ,@(append
442 (list preserve))))) 451 `((if (and (or interactive
443 nil)) 452 ,query-var)
453 (not force))
454 1 (or force ,force-var)))
455 (if preserve
456 (list preserve)))))
457 nil)))
444 458
445(defun eshell/mv (&rest args) 459(defun eshell/mv (&rest args)
446 "Implementation of mv in Lisp." 460 "Implementation of mv in Lisp."
@@ -455,6 +469,7 @@ Remove the DIRECTORY(ies), if they are empty.")
455 (?v "verbose" nil verbose 469 (?v "verbose" nil verbose
456 "explain what is being done") 470 "explain what is being done")
457 (nil "help" nil nil "show this usage screen") 471 (nil "help" nil nil "show this usage screen")
472 :preserve-args
458 :external "mv" 473 :external "mv"
459 :show-usage 474 :show-usage
460 :usage "[OPTION]... SOURCE DEST 475 :usage "[OPTION]... SOURCE DEST
@@ -462,9 +477,9 @@ Remove the DIRECTORY(ies), if they are empty.")
462Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY. 477Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY.
463\[OPTION] DIRECTORY...") 478\[OPTION] DIRECTORY...")
464 (let ((no-dereference t)) 479 (let ((no-dereference t))
465 (eshell-mvcp-template "mv" "moving" 'rename-file 480 (eshell-mvcpln-template "mv" "moving" 'rename-file
466 eshell-mv-interactive-query 481 eshell-mv-interactive-query
467 eshell-mv-overwrite-files)))) 482 eshell-mv-overwrite-files))))
468 483
469(defun eshell/cp (&rest args) 484(defun eshell/cp (&rest args)
470 "Implementation of cp in Lisp." 485 "Implementation of cp in Lisp."
@@ -487,6 +502,7 @@ Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY.
487 (?v "verbose" nil verbose 502 (?v "verbose" nil verbose
488 "explain what is being done") 503 "explain what is being done")
489 (nil "help" nil nil "show this usage screen") 504 (nil "help" nil nil "show this usage screen")
505 :preserve-args
490 :external "cp" 506 :external "cp"
491 :show-usage 507 :show-usage
492 :usage "[OPTION]... SOURCE DEST 508 :usage "[OPTION]... SOURCE DEST
@@ -494,9 +510,9 @@ Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY.
494Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.") 510Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.")
495 (if archive 511 (if archive
496 (setq preserve t no-dereference t recursive t)) 512 (setq preserve t no-dereference t recursive t))
497 (eshell-mvcp-template "cp" "copying" 'copy-file 513 (eshell-mvcpln-template "cp" "copying" 'copy-file
498 eshell-cp-interactive-query 514 eshell-cp-interactive-query
499 eshell-cp-overwrite-files preserve))) 515 eshell-cp-overwrite-files preserve)))
500 516
501(defun eshell/ln (&rest args) 517(defun eshell/ln (&rest args)
502 "Implementation of ln in Lisp." 518 "Implementation of ln in Lisp."
@@ -505,11 +521,13 @@ Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.")
505 '((?h "help" nil nil "show this usage screen") 521 '((?h "help" nil nil "show this usage screen")
506 (?s "symbolic" nil symbolic 522 (?s "symbolic" nil symbolic
507 "make symbolic links instead of hard links") 523 "make symbolic links instead of hard links")
508 (?i "interactive" nil interactive "request confirmation if target already exists") 524 (?i "interactive" nil interactive
525 "request confirmation if target already exists")
509 (?f "force" nil force "remove existing destinations, never prompt") 526 (?f "force" nil force "remove existing destinations, never prompt")
510 (?n "preview" nil preview 527 (?n "preview" nil preview
511 "don't change anything on disk") 528 "don't change anything on disk")
512 (?v "verbose" nil verbose "explain what is being done") 529 (?v "verbose" nil verbose "explain what is being done")
530 :preserve-args
513 :external "ln" 531 :external "ln"
514 :show-usage 532 :show-usage
515 :usage "[OPTION]... TARGET [LINK_NAME] 533 :usage "[OPTION]... TARGET [LINK_NAME]
@@ -518,27 +536,19 @@ Create a link to the specified TARGET with optional LINK_NAME. If there is
518more than one TARGET, the last argument must be a directory; create links 536more than one TARGET, the last argument must be a directory; create links
519in DIRECTORY to each TARGET. Create hard links by default, symbolic links 537in DIRECTORY to each TARGET. Create hard links by default, symbolic links
520with '--symbolic'. When creating hard links, each TARGET must exist.") 538with '--symbolic'. When creating hard links, each TARGET must exist.")
521 (let (target no-dereference ange-cache) 539 (let ((no-dereference t))
522 (if (> (length args) 1) 540 (eshell-mvcpln-template "ln" "linking"
523 (progn 541 (if symbolic
524 (setq target (car (last args))) 542 'make-symbolic-link
525 (setcdr (last args 2) nil)) 543 'add-name-to-file)
526 (setq args nil)) 544 eshell-ln-interactive-query
527 (eshell-shuffle-files "ln" "linking" args target 545 eshell-ln-overwrite-files))))
528 (if symbolic
529 'make-symbolic-link
530 'add-name-to-file) nil
531 (if (and (or interactive
532 eshell-ln-interactive-query)
533 (not force))
534 1 (or force eshell-ln-overwrite-files))))
535 nil))
536 546
537(defun eshell/cat (&rest args) 547(defun eshell/cat (&rest args)
538 "Implementation of cat in Lisp. 548 "Implementation of cat in Lisp.
539If in a pipeline, or the file is not a regular file, directory or 549If in a pipeline, or the file is not a regular file, directory or
540symlink, then revert to the system's definition of cat." 550symlink, then revert to the system's definition of cat."
541 (setq args (eshell-flatten-list args)) 551 (setq args (eshell-stringify-list (eshell-flatten-list args)))
542 (if (or eshell-in-pipeline-p 552 (if (or eshell-in-pipeline-p
543 (catch 'special 553 (catch 'special
544 (eshell-for arg args 554 (eshell-for arg args
@@ -593,7 +603,8 @@ Concatenate FILE(s), or standard input, to standard output.")
593 (list 'quote (eshell-copy-environment)))))) 603 (list 'quote (eshell-copy-environment))))))
594 (compile (concat "make " (eshell-flatten-and-stringify args)))) 604 (compile (concat "make " (eshell-flatten-and-stringify args))))
595 (throw 'eshell-replace-command 605 (throw 'eshell-replace-command
596 (eshell-parse-command "*make" (eshell-flatten-list args))))) 606 (eshell-parse-command "*make" (eshell-stringify-list
607 (eshell-flatten-list args))))))
597 608
598(defun eshell-occur-mode-goto-occurrence () 609(defun eshell-occur-mode-goto-occurrence ()
599 "Go to the occurrence the current line describes." 610 "Go to the occurrence the current line describes."
@@ -627,7 +638,8 @@ available..."
627 (default-directory default-dir)) 638 (default-directory default-dir))
628 (erase-buffer) 639 (erase-buffer)
629 (occur-mode) 640 (occur-mode)
630 (let ((files (eshell-flatten-list (cdr args))) 641 (let ((files (eshell-stringify-list
642 (eshell-flatten-list (cdr args))))
631 (inhibit-redisplay t) 643 (inhibit-redisplay t)
632 string) 644 string)
633 (when (car args) 645 (when (car args)
@@ -670,14 +682,16 @@ external command."
670 (not eshell-in-subcommand-p)))) 682 (not eshell-in-subcommand-p))))
671 (throw 'eshell-replace-command 683 (throw 'eshell-replace-command
672 (eshell-parse-command (concat "*" command) 684 (eshell-parse-command (concat "*" command)
673 (eshell-flatten-list args))) 685 (eshell-stringify-list
686 (eshell-flatten-list args))))
674 (let* ((compilation-process-setup-function 687 (let* ((compilation-process-setup-function
675 (list 'lambda nil 688 (list 'lambda nil
676 (list 'setq 'process-environment 689 (list 'setq 'process-environment
677 (list 'quote (eshell-copy-environment))))) 690 (list 'quote (eshell-copy-environment)))))
678 (args (mapconcat 'identity 691 (args (mapconcat 'identity
679 (mapcar 'shell-quote-argument 692 (mapcar 'shell-quote-argument
680 (eshell-flatten-list args)) 693 (eshell-stringify-list
694 (eshell-flatten-list args)))
681 " ")) 695 " "))
682 (cmd (progn 696 (cmd (progn
683 (set-text-properties 0 (length args) 697 (set-text-properties 0 (length args)
@@ -797,7 +811,7 @@ external command."
797(defun eshell/du (&rest args) 811(defun eshell/du (&rest args)
798 "Implementation of \"du\" in Lisp, passing ARGS." 812 "Implementation of \"du\" in Lisp, passing ARGS."
799 (setq args (if args 813 (setq args (if args
800 (eshell-flatten-list args) 814 (eshell-stringify-list (eshell-flatten-list args))
801 '("."))) 815 '(".")))
802 (let ((ext-du (eshell-search-path "du"))) 816 (let ((ext-du (eshell-search-path "du")))
803 (if (and ext-du 817 (if (and ext-du
@@ -909,7 +923,7 @@ Show wall-clock time elapsed during execution of COMMAND.")
909 923
910(defun eshell/diff (&rest args) 924(defun eshell/diff (&rest args)
911 "Alias \"diff\" to call Emacs `diff' function." 925 "Alias \"diff\" to call Emacs `diff' function."
912 (let ((orig-args (eshell-flatten-list args))) 926 (let ((orig-args (eshell-stringify-list (eshell-flatten-list args))))
913 (if (or eshell-plain-diff-behavior 927 (if (or eshell-plain-diff-behavior
914 (not (and (eshell-interactive-output-p) 928 (not (and (eshell-interactive-output-p)
915 (not eshell-in-pipeline-p) 929 (not eshell-in-pipeline-p)
@@ -951,7 +965,8 @@ Show wall-clock time elapsed during execution of COMMAND.")
951 (and (stringp (car args)) 965 (and (stringp (car args))
952 (string-match "^-" (car args)))) 966 (string-match "^-" (car args))))
953 (throw 'eshell-replace-command 967 (throw 'eshell-replace-command
954 (eshell-parse-command "*locate" (eshell-flatten-list args))) 968 (eshell-parse-command "*locate" (eshell-stringify-list
969 (eshell-flatten-list args))))
955 (save-selected-window 970 (save-selected-window
956 (let ((locate-history-list (list (car args)))) 971 (let ((locate-history-list (list (car args))))
957 (locate-with-filter (car args) (cadr args)))))) 972 (locate-with-filter (car args) (cadr args))))))
diff --git a/lisp/eshell/esh-cmd.el b/lisp/eshell/esh-cmd.el
index 6d2ede0a72c..7d5a53625f5 100644
--- a/lisp/eshell/esh-cmd.el
+++ b/lisp/eshell/esh-cmd.el
@@ -203,6 +203,21 @@ which may be modified directly. Any return value is ignored."
203 :type 'hook 203 :type 'hook
204 :group 'eshell-cmd) 204 :group 'eshell-cmd)
205 205
206(defcustom eshell-complex-commands nil
207 "*A list of commands names or functions, that determine complexity.
208That is, if a command is defined by a function named eshell/NAME,
209and NAME is part of this list, it is invoked as a complex command.
210Complex commands are always correct, but run much slower. If a
211command works fine without being part of this list, then it doesn't
212need to be.
213
214If an entry is a function, it will be called with the name, and should
215return non-nil if the command is complex."
216 :type '(repeat :tag "Commands"
217 (choice (string :tag "Name")
218 (function :tag "Predicate")))
219 :group 'eshell-cmd)
220
206;;; Code: 221;;; Code:
207 222
208(require 'esh-util) 223(require 'esh-util)
@@ -518,8 +533,8 @@ implemented via rewriting, rather than as a function."
518 (list 'car 533 (list 'car
519 (list 'symbol-value 534 (list 'symbol-value
520 (list 'quote 'for-items))))) 535 (list 'quote 'for-items)))))
521 (list 'eshell-copy-handles 536 (list 'eshell-protect
522 (eshell-invokify-arg body t))) 537 (eshell-invokify-arg body t)))
523 (list 'setcar 'for-items 538 (list 'setcar 'for-items
524 (list 'cadr 539 (list 'cadr
525 (list 'symbol-value 540 (list 'symbol-value
@@ -583,7 +598,7 @@ must be implemented via rewriting, rather than as a function."
583 (eshell-structure-basic-command 598 (eshell-structure-basic-command
584 'while '("while" "until") (car terms) 599 'while '("while" "until") (car terms)
585 (eshell-invokify-arg (cadr terms) nil t) 600 (eshell-invokify-arg (cadr terms) nil t)
586 (list 'eshell-copy-handles 601 (list 'eshell-protect
587 (eshell-invokify-arg (car (last terms)) t))))) 602 (eshell-invokify-arg (car (last terms)) t)))))
588 603
589(defun eshell-rewrite-if-command (terms) 604(defun eshell-rewrite-if-command (terms)
@@ -596,13 +611,15 @@ must be implemented via rewriting, rather than as a function."
596 (eshell-structure-basic-command 611 (eshell-structure-basic-command
597 'if '("if" "unless") (car terms) 612 'if '("if" "unless") (car terms)
598 (eshell-invokify-arg (cadr terms) nil t) 613 (eshell-invokify-arg (cadr terms) nil t)
599 (eshell-invokify-arg 614 (list 'eshell-protect
600 (if (= (length terms) 5) 615 (eshell-invokify-arg
601 (car (last terms 3)) 616 (if (= (length terms) 5)
602 (car (last terms))) t) 617 (car (last terms 3))
603 (eshell-invokify-arg 618 (car (last terms))) t))
604 (if (= (length terms) 5) 619 (if (= (length terms) 5)
605 (car (last terms))) t)))) 620 (list 'eshell-protect
621 (eshell-invokify-arg
622 (car (last terms)))) t))))
606 623
607(defun eshell-exit-success-p () 624(defun eshell-exit-success-p ()
608 "Return non-nil if the last command was \"successful\". 625 "Return non-nil if the last command was \"successful\".
@@ -651,8 +668,8 @@ For an external command, it means an exit code of 0."
651 (assert (car sep-terms)) 668 (assert (car sep-terms))
652 (setq final (eshell-structure-basic-command 669 (setq final (eshell-structure-basic-command
653 'if (string= (car sep-terms) "&&") "if" 670 'if (string= (car sep-terms) "&&") "if"
654 (list 'eshell-commands (car results)) 671 (list 'eshell-protect (car results))
655 final 672 (list 'eshell-protect final)
656 nil t) 673 nil t)
657 results (cdr results) 674 results (cdr results)
658 sep-terms (cdr sep-terms))) 675 sep-terms (cdr sep-terms)))
@@ -690,8 +707,8 @@ For an external command, it means an exit code of 0."
690 (list 'eshell-lisp-command (list 'quote obj))) 707 (list 'eshell-lisp-command (list 'quote obj)))
691 (ignore (goto-char here)))))) 708 (ignore (goto-char here))))))
692 709
693(defun eshell-separate-commands 710(defun eshell-separate-commands (terms separator &optional
694 (terms separator &optional reversed last-terms-sym) 711 reversed last-terms-sym)
695 "Separate TERMS using SEPARATOR. 712 "Separate TERMS using SEPARATOR.
696If REVERSED is non-nil, the list of separated term groups will be 713If REVERSED is non-nil, the list of separated term groups will be
697returned in reverse order. If LAST-TERMS-SYM is a symbol, it's value 714returned in reverse order. If LAST-TERMS-SYM is a symbol, it's value
@@ -772,21 +789,6 @@ this grossness will be made to disappear by using `call/cc'..."
772 (eshell-errorn (error-message-string err)) 789 (eshell-errorn (error-message-string err))
773 (eshell-close-handles 1))))) 790 (eshell-close-handles 1)))))
774 791
775;; (defun eshell-copy-or-protect-handles ()
776;; (if (eshell-processp (car (aref eshell-current-handles
777;; eshell-output-handle)))
778;; (eshell-protect-handles eshell-current-handles)
779;; (eshell-create-handles
780;; (car (aref eshell-current-handles
781;; eshell-output-handle)) nil
782;; (car (aref eshell-current-handles
783;; eshell-error-handle)) nil)))
784
785;; (defmacro eshell-copy-handles (object)
786;; "Duplicate current I/O handles, so OBJECT works with its own copy."
787;; `(let ((eshell-current-handles (eshell-copy-or-protect-handles)))
788;; ,object))
789
790(defmacro eshell-copy-handles (object) 792(defmacro eshell-copy-handles (object)
791 "Duplicate current I/O handles, so OBJECT works with its own copy." 793 "Duplicate current I/O handles, so OBJECT works with its own copy."
792 `(let ((eshell-current-handles 794 `(let ((eshell-current-handles
@@ -965,6 +967,22 @@ at the moment are:
965 (if subform 967 (if subform
966 (concat "\n\n" (eshell-stringify subform)) "")))))) 968 (concat "\n\n" (eshell-stringify subform)) ""))))))
967 969
970(defun eshell-invoke-directly (command input)
971 (let ((base (cadr (nth 2 (nth 2 (cadr command))))) name)
972 (if (and (eq (car base) 'eshell-trap-errors)
973 (eq (car (cadr base)) 'eshell-named-command))
974 (setq name (cadr (cadr base))))
975 (and name (stringp name)
976 (not (member name eshell-complex-commands))
977 (catch 'simple
978 (progn
979 (eshell-for pred eshell-complex-commands
980 (if (and (functionp pred)
981 (funcall pred name))
982 (throw 'simple nil)))
983 t))
984 (fboundp (intern-soft (concat "eshell/" name))))))
985
968(defun eshell-eval-command (command &optional input) 986(defun eshell-eval-command (command &optional input)
969 "Evaluate the given COMMAND iteratively." 987 "Evaluate the given COMMAND iteratively."
970 (if eshell-current-command 988 (if eshell-current-command
@@ -1163,29 +1181,29 @@ be finished later after the completion of an asynchronous subprocess."
1163 ((eq (car form) 'prog1) 1181 ((eq (car form) 'prog1)
1164 (cadr form)) 1182 (cadr form))
1165 (t 1183 (t
1184 ;; If a command desire to replace its execution form with
1185 ;; another command form, all it needs to do is throw the new
1186 ;; form using the exception tag `eshell-replace-command'.
1187 ;; For example, let's say that the form currently being
1188 ;; eval'd is:
1189 ;;
1190 ;; (eshell-named-command "hello")
1191 ;;
1192 ;; Now, let's assume the 'hello' command is an Eshell alias,
1193 ;; the definition of which yields the command:
1194 ;;
1195 ;; (eshell-named-command "echo" (list "Hello" "world"))
1196 ;;
1197 ;; What the alias code would like to do is simply substitute
1198 ;; the alias form for the original form. To accomplish
1199 ;; this, all it needs to do is to throw the substitution
1200 ;; form with the `eshell-replace-command' tag, and the form
1201 ;; will be replaced within the current command, and
1202 ;; execution will then resume (iteratively) as before.
1203 ;; Thus, aliases can even contain references to asynchronous
1204 ;; sub-commands, and things will still work out as they
1205 ;; should.
1166 (let (result new-form) 1206 (let (result new-form)
1167 ;; If a command desire to replace its execution form with
1168 ;; another command form, all it needs to do is throw the
1169 ;; new form using the exception tag
1170 ;; `eshell-replace-command'. For example, let's say that
1171 ;; the form currently being eval'd is:
1172 ;;
1173 ;; (eshell-named-command \"hello\")
1174 ;;
1175 ;; Now, let's assume the 'hello' command is an Eshell
1176 ;; alias, the definition of which yields the command:
1177 ;;
1178 ;; (eshell-named-command \"echo\" (list \"Hello\" \"world\"))
1179 ;;
1180 ;; What the alias code would like to do is simply
1181 ;; substitute the alias form for the original form. To
1182 ;; accomplish this, all it needs to do is to throw the
1183 ;; substitution form with the `eshell-replace-command'
1184 ;; tag, and the form will be replaced within the current
1185 ;; command, and execution will then resume (iteratively)
1186 ;; as before. Thus, aliases can even contain references
1187 ;; to asynchronous sub-commands, and things will still
1188 ;; work out as they should.
1189 (if (setq new-form 1207 (if (setq new-form
1190 (catch 'eshell-replace-command 1208 (catch 'eshell-replace-command
1191 (ignore 1209 (ignore
diff --git a/lisp/eshell/esh-groups.el b/lisp/eshell/esh-groups.el
index 218bd2a2e52..d82cdff4ffd 100644
--- a/lisp/eshell/esh-groups.el
+++ b/lisp/eshell/esh-groups.el
@@ -132,4 +132,3 @@ functions, or as aliases which make some of Emacs' behavior more
132naturally accessible within Emacs." 132naturally accessible within Emacs."
133 :tag "Extra alias functions" 133 :tag "Extra alias functions"
134 :group 'eshell-module) 134 :group 'eshell-module)
135
diff --git a/lisp/eshell/esh-maint.el b/lisp/eshell/esh-maint.el
index 13b3597b4ce..89e50401c67 100644
--- a/lisp/eshell/esh-maint.el
+++ b/lisp/eshell/esh-maint.el
@@ -48,7 +48,7 @@
48;; (interactive) 48;; (interactive)
49;; (require 'autoload) 49;; (require 'autoload)
50;; (setq generated-autoload-file 50;; (setq generated-autoload-file
51;; (expand-file-name (car command-line-args-left))) 51;; (expand-file-name (car command-line-args-left)))
52;; (setq command-line-args-left (cdr command-line-args-left)) 52;; (setq command-line-args-left (cdr command-line-args-left))
53;; (batch-update-autoloads)) 53;; (batch-update-autoloads))
54 54
@@ -65,23 +65,23 @@
65;; Core Functionality\n") 65;; Core Functionality\n")
66;; (eshell-for module 66;; (eshell-for module
67;; (sort (eshell-subgroups 'eshell) 67;; (sort (eshell-subgroups 'eshell)
68;; (function 68;; (function
69;; (lambda (a b) 69;; (lambda (a b)
70;; (string-lessp (symbol-name a) 70;; (string-lessp (symbol-name a)
71;; (symbol-name b))))) 71;; (symbol-name b)))))
72;; (insert (format "* %-34s" 72;; (insert (format "* %-34s"
73;; (concat (get module 'custom-tag) "::")) 73;; (concat (get module 'custom-tag) "::"))
74;; (symbol-name module) ".\n")) 74;; (symbol-name module) ".\n"))
75;; (insert "\nOptional Functionality\n") 75;; (insert "\nOptional Functionality\n")
76;; (eshell-for module 76;; (eshell-for module
77;; (sort (eshell-subgroups 'eshell-module) 77;; (sort (eshell-subgroups 'eshell-module)
78;; (function 78;; (function
79;; (lambda (a b) 79;; (lambda (a b)
80;; (string-lessp (symbol-name a) 80;; (string-lessp (symbol-name a)
81;; (symbol-name b))))) 81;; (symbol-name b)))))
82;; (insert (format "* %-34s" 82;; (insert (format "* %-34s"
83;; (concat (get module 'custom-tag) "::")) 83;; (concat (get module 'custom-tag) "::"))
84;; (symbol-name module) ".\n")) 84;; (symbol-name module) ".\n"))
85;; (insert "@end menu\n")) 85;; (insert "@end menu\n"))
86 86
87;; (defun eshell-make-texi () 87;; (defun eshell-make-texi ()
@@ -91,27 +91,27 @@
91;; (require 'texidoc) 91;; (require 'texidoc)
92;; (require 'pcomplete) 92;; (require 'pcomplete)
93;; (apply 'texidoc-files 'eshell-generate-main-menu "eshell.doci" 93;; (apply 'texidoc-files 'eshell-generate-main-menu "eshell.doci"
94;; (append 94;; (append
95;; (list "eshell.el") 95;; (list "eshell.el")
96;; (sort (mapcar 96;; (sort (mapcar
97;; (function 97;; (function
98;; (lambda (sym) 98;; (lambda (sym)
99;; (let ((name (symbol-name sym))) 99;; (let ((name (symbol-name sym)))
100;; (if (string-match "\\`eshell-\\(.*\\)" name) 100;; (if (string-match "\\`eshell-\\(.*\\)" name)
101;; (setq name (concat "esh-" (match-string 1 name)))) 101;; (setq name (concat "esh-" (match-string 1 name))))
102;; (concat name ".el")))) 102;; (concat name ".el"))))
103;; (eshell-subgroups 'eshell)) 103;; (eshell-subgroups 'eshell))
104;; 'string-lessp) 104;; 'string-lessp)
105;; (sort (mapcar 105;; (sort (mapcar
106;; (function 106;; (function
107;; (lambda (sym) 107;; (lambda (sym)
108;; (let ((name (symbol-name sym))) 108;; (let ((name (symbol-name sym)))
109;; (if (string-match "\\`eshell-\\(.*\\)" name) 109;; (if (string-match "\\`eshell-\\(.*\\)" name)
110;; (setq name (concat "em-" (match-string 1 name)))) 110;; (setq name (concat "em-" (match-string 1 name))))
111;; (concat name ".el")))) 111;; (concat name ".el"))))
112;; (eshell-subgroups 'eshell-module)) 112;; (eshell-subgroups 'eshell-module))
113;; 'string-lessp) 113;; 'string-lessp)
114;; (list "eshell.texi")))) 114;; (list "eshell.texi"))))
115 115
116;; (defun eshell-make-readme () 116;; (defun eshell-make-readme ()
117;; "Make the README file from eshell.el." 117;; "Make the README file from eshell.el."
diff --git a/lisp/eshell/esh-mode.el b/lisp/eshell/esh-mode.el
index ad513c47a0b..5da511626c5 100644
--- a/lisp/eshell/esh-mode.el
+++ b/lisp/eshell/esh-mode.el
@@ -180,9 +180,7 @@ inserted. They return the string as it should be inserted."
180 :group 'eshell-mode) 180 :group 'eshell-mode)
181 181
182(defcustom eshell-password-prompt-regexp 182(defcustom eshell-password-prompt-regexp
183 "\\(\\([Oo]ld \\|[Nn]ew \\|Kerberos \\|CVS \\|'s \\|login \\|^\\)\ 183 "[Pp]ass\\(word\\|phrase\\).*:\\s *\\'"
184[Pp]assword\\|pass phrase\\|\\(Enter\\|Repeat\\) passphrase\\)\
185\\( for [^@ \t\n]+@[^@ \t\n]+\\)?:\\s *\\'"
186 "*Regexp matching prompts for passwords in the inferior process. 184 "*Regexp matching prompts for passwords in the inferior process.
187This is used by `eshell-watch-for-password-prompt'." 185This is used by `eshell-watch-for-password-prompt'."
188 :type 'regexp 186 :type 'regexp
@@ -462,7 +460,8 @@ sessions, such as when using `eshell-command'.")
462 460
463(eshell-deftest var window-height 461(eshell-deftest var window-height
464 "LINES equals window height" 462 "LINES equals window height"
465 (eshell-command-result-p "= $LINES (window-height)" "t\n")) 463 (let ((eshell-stringify-t t))
464 (eshell-command-result-p "= $LINES (window-height)" "t\n")))
466 465
467(defun eshell-command-started () 466(defun eshell-command-started ()
468 "Indicate in the modeline that a command has started." 467 "Indicate in the modeline that a command has started."
@@ -736,7 +735,9 @@ newline."
736 (run-hooks 'eshell-input-filter-functions) 735 (run-hooks 'eshell-input-filter-functions)
737 (and (catch 'eshell-terminal 736 (and (catch 'eshell-terminal
738 (ignore 737 (ignore
739 (eshell-eval-command cmd input))) 738 (if (eshell-invoke-directly cmd input)
739 (eval cmd)
740 (eshell-eval-command cmd input))))
740 (eshell-life-is-too-much))))) 741 (eshell-life-is-too-much)))))
741 (quit 742 (quit
742 (eshell-reset t) 743 (eshell-reset t)
diff --git a/lisp/eshell/esh-module.el b/lisp/eshell/esh-module.el
index 3eab199201e..f09f1ac7b24 100644
--- a/lisp/eshell/esh-module.el
+++ b/lisp/eshell/esh-module.el
@@ -24,7 +24,9 @@
24 24
25(provide 'esh-module) 25(provide 'esh-module)
26 26
27(eval-when-compile (require 'esh-maint) (require 'cl)) 27(eval-when-compile
28 (require 'esh-maint)
29 (require 'cl))
28 30
29(defgroup eshell-module nil 31(defgroup eshell-module nil
30 "The `eshell-module' group is for Eshell extension modules, which 32 "The `eshell-module' group is for Eshell extension modules, which
@@ -85,7 +87,7 @@ customizing the variable `eshell-modules-list'."
85 (equal (file-name-nondirectory byte-compile-current-file) 87 (equal (file-name-nondirectory byte-compile-current-file)
86 "esh-modu.el")))) 88 "esh-modu.el"))))
87 (let* ((directory (file-name-directory byte-compile-current-file)) 89 (let* ((directory (file-name-directory byte-compile-current-file))
88 (elc-file (expand-file-name "esh-groups.elc" directory))) 90 (elc-file (expand-file-name "esh-groups.elc" directory)))
89 (eshell-load-defgroups directory) 91 (eshell-load-defgroups directory)
90 (if (file-exists-p elc-file) (delete-file elc-file))))) 92 (if (file-exists-p elc-file) (delete-file elc-file)))))
91 93
diff --git a/lisp/eshell/esh-test.el b/lisp/eshell/esh-test.el
index 6a14541ab39..acfb409da57 100644
--- a/lisp/eshell/esh-test.el
+++ b/lisp/eshell/esh-test.el
@@ -173,12 +173,12 @@
173 system-configuration 173 system-configuration
174 (cond ((featurep 'motif) ", Motif") 174 (cond ((featurep 'motif) ", Motif")
175 ((featurep 'x-toolkit) ", X toolkit") 175 ((featurep 'x-toolkit) ", X toolkit")
176 (t ""))) "\n") 176 (t ""))))
177 (switch-to-buffer test-buffer) 177 (switch-to-buffer test-buffer)
178 (delete-other-windows)) 178 (delete-other-windows))
179 (eshell-for funcname 179 (eshell-for funcname (sort (all-completions "eshell-test--"
180 (sort (all-completions "eshell-test--" obarray 'functionp) 180 obarray 'functionp)
181 'string-lessp) 181 'string-lessp)
182 (with-current-buffer test-buffer 182 (with-current-buffer test-buffer
183 (insert "\n")) 183 (insert "\n"))
184 (funcall (intern-soft funcname))) 184 (funcall (intern-soft funcname)))
diff --git a/lisp/eshell/esh-util.el b/lisp/eshell/esh-util.el
index 01c0ff2c76e..3d8dedc6bae 100644
--- a/lisp/eshell/esh-util.el
+++ b/lisp/eshell/esh-util.el
@@ -36,6 +36,14 @@
36 36
37;;; User Variables: 37;;; User Variables:
38 38
39(defcustom eshell-stringify-t t
40 "*If non-nil, the string representation of t is 't'.
41If nil, t will be represented only in the exit code of the function,
42and not printed as a string. This causes Lisp functions to behave
43similarly to external commands, as far as successful result output."
44 :type 'boolean
45 :group 'eshell-util)
46
39(defcustom eshell-group-file "/etc/group" 47(defcustom eshell-group-file "/etc/group"
40 "*If non-nil, the name of the group file on your system." 48 "*If non-nil, the name of the group file on your system."
41 :type '(choice (const :tag "No group file" nil) file) 49 :type '(choice (const :tag "No group file" nil) file)
@@ -305,7 +313,9 @@ If N or M is nil, it means the end of the list."
305 ((numberp object) 313 ((numberp object)
306 (number-to-string object)) 314 (number-to-string object))
307 (t 315 (t
308 (pp-to-string object)))) 316 (unless (and (eq object t)
317 (not eshell-stringify-t))
318 (pp-to-string object)))))
309 319
310(defsubst eshell-stringify-list (args) 320(defsubst eshell-stringify-list (args)
311 "Convert each element of ARGS into a string value." 321 "Convert each element of ARGS into a string value."
@@ -611,7 +621,7 @@ Unless optional argument INPLACE is non-nil, return a new string."
611 (autoload 'parse-time-string "parse-time")) 621 (autoload 'parse-time-string "parse-time"))
612 622
613(eval-when-compile 623(eval-when-compile
614 (require 'ange-ftp)) 624 (load "ange-ftp" t))
615 625
616(defun eshell-parse-ange-ls (dir) 626(defun eshell-parse-ange-ls (dir)
617 (let (entry) 627 (let (entry)
diff --git a/lisp/textmodes/flyspell.el b/lisp/textmodes/flyspell.el
index fe95b3faa59..74c07f19602 100644
--- a/lisp/textmodes/flyspell.el
+++ b/lisp/textmodes/flyspell.el
@@ -1986,7 +1986,7 @@ The word checked is the word at the mouse position."
1986 menu)))) 1986 menu))))
1987 1987
1988;*---------------------------------------------------------------------*/ 1988;*---------------------------------------------------------------------*/
1989;* Some example functions for real autocrrecting */ 1989;* Some example functions for real autocrrecting xb */
1990;*---------------------------------------------------------------------*/ 1990;*---------------------------------------------------------------------*/
1991(defun flyspell-maybe-correct-transposition (beg end poss) 1991(defun flyspell-maybe-correct-transposition (beg end poss)
1992 "Apply 'transpose-chars' to all points in the region BEG to END and 1992 "Apply 'transpose-chars' to all points in the region BEG to END and
@@ -1994,17 +1994,24 @@ return t if any those result in a possible replacement suggested by ispell
1994in POSS. Otherwise the change is undone. 1994in POSS. Otherwise the change is undone.
1995 1995
1996This function is meant to be added to 'flyspell-incorrect-hook'." 1996This function is meant to be added to 'flyspell-incorrect-hook'."
1997 (when (consp poss) 1997 (when (consp poss)
1998 (catch 'done 1998 (catch 'done
1999 (save-excursion 1999 (let ((str (buffer-substring beg end))
2000 (goto-char (1+ beg)) 2000 (i 0) (len (- end beg)) tmp)
2001 (while (< (point) end) 2001 (while (< (1+ i) len)
2002 (transpose-chars 1) 2002 (setq tmp (aref str i))
2003 (when (member (buffer-substring beg end) (nth 2 poss)) 2003 (aset str i (aref str (1+ i)))
2004 (throw 'done t)) 2004 (aset str (1+ i) tmp)
2005 (transpose-chars -1) 2005 (when (member str (nth 2 poss))
2006 (forward-char)) 2006 (save-excursion
2007 nil)))) 2007 (goto-char (+ beg i 1))
2008 (transpose-chars 1))
2009 (throw 'done t))
2010 (setq tmp (aref str i))
2011 (aset str i (aref str (1+ i)))
2012 (aset str (1+ i) tmp)
2013 (setq i (1+ i))))
2014 nil)))
2008 2015
2009(defun flyspell-maybe-correct-doubling (beg end poss) 2016(defun flyspell-maybe-correct-doubling (beg end poss)
2010 "For each doubled charachter in the region BEG to END, remove one and 2017 "For each doubled charachter in the region BEG to END, remove one and
@@ -2014,21 +2021,18 @@ in POSS. Otherwise the change is undone.
2014This function is meant to be added to 'flyspell-incorrect-hook'." 2021This function is meant to be added to 'flyspell-incorrect-hook'."
2015 (when (consp poss) 2022 (when (consp poss)
2016 (catch 'done 2023 (catch 'done
2017 (save-excursion 2024 (let ((str (buffer-substring beg end))
2018 (let ((last (char-after beg)) 2025 (i 0) (len (- end beg)))
2019 this) 2026 (while (< (1+ i) len)
2020 (goto-char (1+ beg)) 2027 (when (and (= (aref str i) (aref str (1+ i)))
2021 (while (< (point) end) 2028 (member (concat (substring str 0 (1+ i))
2022 (setq this (char-after)) 2029 (substring str (+ i 2)))
2023 (if (not (char-equal this last)) 2030 (nth 2 poss)))
2024 (forward-char) 2031 (goto-char (+ beg i))
2025 (delete-char 1) 2032 (delete-char 1)
2026 (when (member (buffer-substring beg (1- end)) (nth 2 poss)) 2033 (throw 'done t))
2027 (throw 'done t)) 2034 (setq i (1+ i))))
2028 ;; undo 2035 nil)))
2029 (insert-char this 1))
2030 (setq last this))
2031 nil)))))
2032 2036
2033;*---------------------------------------------------------------------*/ 2037;*---------------------------------------------------------------------*/
2034;* flyspell-already-abbrevp ... */ 2038;* flyspell-already-abbrevp ... */