summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJSDurand <mmemmew@gmail.com>2023-02-25 15:47:33 +0800
committerJSDurand <mmemmew@gmail.com>2023-02-25 15:47:33 +0800
commit6f2a5b73aaf4d2610935d8bb476fc470475a1098 (patch)
tree35f2f4aab91425998b74bc9ac601614deada07ed
parentc08a289e59f27efb00c91c0276876a64925b9308 (diff)
eshell: improve the method to group directories first
* eshell-conf.el (em-term, dir-literal, show-recursive, sort-method) (show-all, show-almost-all, listing-style, human-readable) (numeric-uid-gid, block-size, reverse-list, show-size, insert-func) (flush-func, error-func): Just variables that are needed by Eshell implementation of ls. (eshell/l): Equivalent with calling `eshell/dl` with "-glah" in front of arguments. (durand-eshell-group-entries-by-directory): Obsolete function. (durand-eshell-ls-dirs-first): A variable that controls whether to group directories first. (durand-eshell-ls-sort-entries, eshell-ls-sort-entries): An advice around the original sorting function, which groups directories into a separate list, to be sorted before the rest. This approach respects the original sorting method, and performs no extra sorting, as opposed to the previous approach.
-rw-r--r--eshell-conf.el168
1 files changed, 149 insertions, 19 deletions
diff --git a/eshell-conf.el b/eshell-conf.el
index 866d4bf..25ffffb 100644
--- a/eshell-conf.el
+++ b/eshell-conf.el
@@ -31,6 +31,7 @@
(require 'eshell))
(require 'esh-util)
(require 'em-term)
+(require 'em-ls)
(require 'ring)
(require 'type-break)
@@ -371,31 +372,160 @@ candidates."
;;; convenient ls
-;;;###autoload
+(defvar dir-literal nil)
+(defvar show-recursive nil)
+(defvar sort-method nil)
+(defvar show-all nil)
+(defvar show-almost-all nil)
+(defvar listing-style nil)
+(defvar human-readable nil)
+(defvar numeric-uid-gid nil)
+(defvar block-size nil)
+(defvar reverse-list nil)
+(defvar show-size nil)
+(defvar insert-func nil)
+(defvar flush-func nil)
+(defvar error-func nil)
+
(defun eshell/l (&rest args)
- "Equivalent with ls -ahl ARGS.
-If called without ARGS, then use ./ instead."
- (eshell/ls "-hal" (or args "./")))
+ "Equivalent with \"dl -alhg ARGS\"."
+ (eshell/dl "-alhg" (or args ".")))
+
+(defun eshell/dl (&rest args)
+ "My enhanced implementation of \"ls\" in Emacs Lisp, with ARGS.
+See `eshell/l` for the original version.
+
+I added the option of \"g\" for grouping directories first."
+ (let ((insert-func 'eshell-buffered-print)
+ (error-func 'eshell-error)
+ (flush-func 'eshell-flush))
+ (funcall flush-func -1)
+ ;; Process the command arguments, and begin listing files.
+ (eshell-eval-using-options
+ "ls" (if eshell-ls-initial-args
+ (list eshell-ls-initial-args args)
+ args)
+ '((?a "all" nil show-all
+ "do not ignore entries starting with .")
+ (?A "almost-all" nil show-almost-all
+ "do not list implied . and ..")
+ (?c nil by-ctime sort-method
+ "sort by last status change time")
+ (?d "directory" nil dir-literal
+ "list directory entries instead of contents")
+ (?k "kilobytes" 1024 block-size
+ "using 1024 as the block size")
+ (?h "human-readable" 1024 human-readable
+ "print sizes in human readable format")
+ (?H "si" 1000 human-readable
+ "likewise, but use powers of 1000 not 1024")
+ (?I "ignore" t ignore-pattern
+ "do not list implied entries matching pattern")
+ (?l nil long-listing listing-style
+ "use a long listing format")
+ (?n "numeric-uid-gid" nil numeric-uid-gid
+ "list numeric UIDs and GIDs instead of names")
+ (?r "reverse" nil reverse-list
+ "reverse order while sorting")
+ (?s "size" nil show-size
+ "print size of each file, in blocks")
+ (?t nil by-mtime sort-method
+ "sort by modification time")
+ (?u nil by-atime sort-method
+ "sort by last access time")
+ (?x nil by-lines listing-style
+ "list entries by lines instead of by columns")
+ (?C nil by-columns listing-style
+ "list entries by columns")
+ (?L "dereference" nil dereference-links
+ "list entries pointed to by symbolic links")
+ (?R "recursive" nil show-recursive
+ "list subdirectories recursively")
+ (?g "group-directories-first" nil durand-eshell-ls-dirs-first
+ "group directories first")
+ (?S nil by-size sort-method
+ "sort by file size")
+ (?U nil unsorted sort-method
+ "do not sort; list entries in directory order")
+ (?X nil by-extension sort-method
+ "sort alphabetically by entry extension")
+ (?1 nil single-column listing-style
+ "list one file per line")
+ (nil "dired" nil dired-flag
+ "Here for compatibility with GNU ls.")
+ (nil "help" nil nil
+ "show this usage display")
+ :external "ls"
+ :usage "[OPTION]... [FILE]...
+List information about the FILEs (the current directory by default).
+Sort entries alphabetically across.")
+ ;; setup some defaults, based on what the user selected
+ (unless block-size
+ (setq block-size eshell-ls-default-blocksize))
+ (unless listing-style
+ (setq listing-style 'by-columns))
+ (unless args
+ (setq args (list ".")))
+ (let ((eshell-ls-exclude-regexp eshell-ls-exclude-regexp))
+ (when ignore-pattern
+ (unless (eshell-using-module 'eshell-glob)
+ (error (concat "-I option requires that `eshell-glob'"
+ " be a member of `eshell-modules-list'")))
+ (set-text-properties 0 (length ignore-pattern) nil ignore-pattern)
+ (setq eshell-ls-exclude-regexp
+ (if eshell-ls-exclude-regexp
+ (concat "\\(" eshell-ls-exclude-regexp "\\|"
+ (eshell-glob-regexp ignore-pattern) "\\)")
+ (eshell-glob-regexp ignore-pattern))))
+ ;; list the files!
+ (eshell-ls-entries
+ (mapcar (lambda (arg)
+ (cons (if (and (eshell-under-windows-p)
+ (file-name-absolute-p arg))
+ (expand-file-name arg)
+ arg)
+ (eshell-file-attributes
+ arg (if numeric-uid-gid 'integer 'string))))
+ args)
+ t (expand-file-name default-directory)))
+ (funcall flush-func))))
;;; Group directories first in `eshell/ls'
-(defun durand-eshell-group-entries-by-directory (entries)
- "Sort ENTRIES so that directories come before non-directories."
- (sort entries
- (lambda (l r)
- (cond
- ((string= (car l) "."))
- ((string= (car r) ".") nil)
- ((string= (car l) ".."))
- ((string= (car r) "..") nil)
- ((and (file-directory-p (car l))
- (file-directory-p (car r)))
- (string-lessp (car l) (car r)))
- ((file-directory-p (car l)))
- ((file-directory-p (car r)) nil)))))
+(defvar durand-eshell-ls-dirs-first nil
+ "The variable that controls whether
+`durand-eshell-ls-sort-entries' puts directories first.")
+
+(defun durand-eshell-ls-sort-entries (old-fun entries)
+ "An advice around `eshell-ls-sort-entries'.
+OLD-FUN should be `eshell-ls-sort-entries'.
+
+ENTRIES will be split into two lists, one for directories, and
+the other for non-directory files. Then each list is passed to
+OLD-FUN separately. The two results are then concatenated.
+
+This can preserve the original sorting method."
+ (cond
+ (durand-eshell-ls-dirs-first
+ (let (durand-dir-files durand-other-files)
+ (mapc
+ (lambda (file)
+ (cond
+ ((cond
+ ((stringp file) (file-directory-p file))
+ ((consp file) (eshell-ls-filetype-p (cdr file) ?d))
+ ((user-error "Invalid file: %S" file)))
+ (setq durand-dir-files (cons file durand-dir-files)))
+ ((setq durand-other-files (cons file durand-other-files)))))
+ entries)
+ (append
+ (funcall old-fun durand-dir-files)
+ (funcall old-fun durand-other-files))))
+ ((funcall old-fun entries))))
(advice-add #'eshell-ls-sort-entries
- :after #'durand-eshell-group-entries-by-directory)
+ :around #'durand-eshell-ls-sort-entries)
+
;;; Integration with Tramp