reddit / emacs

How to put icons into eshell 'ls'?

mclearc · 2022-09-11 17:33
I'm trying to have eshell show icons of files and dirs using 'ls' via all-the-icons. The below code works for line display (e.g. 'ls -l'). But not for the simple column display. Anyone have any ideas what the problem might be? https://preview.redd.it/17vupxw0m9n91.png?width=3100&format=png&auto=webp&s=16c48e3119f14f69d86bd28b4b1f2e5bdb379bc9 and here's the function: (defun lem-eshell-icons (f file) (let* ((name (funcall f file)) (icon (if (eq (cadr file) t) (all-the-icons-icon-for-dir (car file)) (all-the-icons-icon-for-file (car file))))) (concat icon name ))) (advice-add 'eshell-ls-decorated-name :around #'lem-eshell-icons) EDIT: Thanks to organicbookworm I now have the following working code (note this includes iconification and dir marking as well...) EDIT2: Forgot to include the keymap & related code...(now added). For the whole eshell config see: [https://github.com/Lambda-Emacs/lambda-emacs/blob/main/.local/lambda-library/lambda-setup/lem-setup-eshell.el](https://github.com/Lambda-Emacs/lambda-emacs/blob/main/.local/lambda-library/lambda-setup/lem-setup-eshell.el) (defun lem-eshell-prettify (file) "Add features to listings in `eshell/ls' output. The features are: 1. Add decoration like 'ls -F': * Mark directories with a `/' * Mark executables with a `*' 2. Make each listing into a clickable link to open the corresponding file or directory. 3. Add icons (requires `all-the-icons`) This function is meant to be used as advice around `eshell-ls-annotate', where FILE is the cons describing the file." (let* ((name (car file)) (icon (if (eq (cadr file) t) (all-the-icons-icon-for-dir name) (all-the-icons-icon-for-file name))) (suffix (cond ;; Directory ((eq (cadr file) t) "/") ;; Executable ((and (/= (user-uid) 0) ; root can execute anything (eshell-ls-applicable (cdr file) 3 #'file-executable-p (car file))) "*")))) (cons (concat " " icon " " (propertize name 'keymap eshell-ls-file-keymap 'mouse-face 'highlight 'file-name (expand-file-name (substring-no-properties (car file)) default-directory)) (when (and suffix (not (string-suffix-p suffix name))) (propertize suffix 'face 'shadow))) (cdr file) ))) (defun eshell-ls-file-at-point () "Get the full path of the Eshell listing at point." (get-text-property (point) 'file-name)) (defun eshell-ls-find-file () "Open the Eshell listing at point." (interactive) (find-file (eshell-ls-file-at-point))) (defun eshell-ls-delete-file () "Delete the Eshell listing at point." (interactive) (let ((file (eshell-ls-file-at-point))) (when (yes-or-no-p (format "Delete file %s?" file)) (delete-file file 'trash)))) (defvar eshell-ls-file-keymap (let ((map (make-sparse-keymap))) (define-key map (kbd "RET") #'eshell-ls-find-file) (define-key map (kbd "<return>") #'eshell-ls-find-file) (define-key map [mouse-1] #'eshell-ls-find-file) (define-key map (kbd "D") #'eshell-ls-delete-file) map) "Keys in effect when point is over a file from `eshell/ls'.") (advice-add #'eshell-ls-annotate :filter-return #'lem-eshell-prettify) And it looks like this: https://preview.redd.it/v3ot6rr4lfn91.png?width=3116&format=png&auto=webp&s=eb25ef9c7b77dcbfa8e319bd21bbd4874b46e1b4 &#x200B;
deaddyfreddy · 2022-09-11 17:57
I just use `dired`+`all-the-icons-dired`
mclearc · 2022-09-11 18:02
Sure - so do I. But I’d like to have the icons in eshell too.
xplosm · 2022-09-11 20:12
Is using `exa` as an `ls` alternative an option? I don’t remember if eshell lets you use other non-lisp alternatives…
mclearc · 2022-09-11 20:20
It is! I discovered yesterday that you can just alias ‘ls’ to it. That’s what I’ll do if I can’t get this working. But I’d prefer a pure elisp solution if possible.
mclearc · 2022-09-11 20:26
I guess I should say that I’m also just confused as to why the code works for ls -a but not for the column view (where the icons are duplicated).
ivotade · 2022-09-11 23:54
If I change the code to this (defun lem-eshell-icons (f file) (let* ((name (funcall f file))) (concat "A" name ))) (advice-add 'eshell-ls-decorated-name :around #'lem-eshell-icons) the `-l` output is correct, a non-colored `A` followed by the colored name show up. But if it is `ls` witout options, it comes with a non-colored `A`, followed by a collored `A`, and then the colored name. So I guess somewhere in eshell code for naked `ls` it is calling the function twice. The eshell code is too big, too many indirections, so with my shitty debugging skills, I change the code to (defun lem-eshell-icons (f file) (let* ((name (funcall f file))) (backtrace) (concat "A" name ))) and execute in a folder with just one file. I confirm my suspicions. The default eshell code is [idempotent](https://en.wikipedia.org/wiki/Idempotence#Idempotent_functions). So I guess you can either fix/change another part of the eshell code or make your function not change the name if it is already changed, if possible.
mclearc · 2022-09-12 00:32
Thanks for this. I’ve done some poking into the em-ls code but haven’t yet figured out what the precise issue is. But I’m glad to see that others are reproducing the problem. If I figure out the issue I’ll certainly post it above.
_viz_ · 2022-09-12 00:49
You might want to reconsider this eye candy since you will be making the output harder to manipulate into a new input.
mclearc · 2022-09-12 00:58
Yeah that’s a fair point, though it would be nice to have at least the option….
gopar · 2022-09-12 01:34
If you use exa, you can use the \`--icons\` param to avoid writing elisp and potentially breaking something: https://the.exa.website/features/icons
mclearc · 2022-09-12 01:40
Yes, thanks. Like I said above I will probably end up doing this (I already use it in iTerm). But I wanted to be sure I wasn't missing something about doing this in pure elisp.
organic-bookworm · 2022-09-12 07:44
I did a bit of debugging. If you are fine with link *targets* (i.e. `link -> target` lines in `ls -la` output) not being iconified, here's an edited snippet (defun lem-eshell-icons (file) (let* ((name (car file)) (icon (if (eq (cadr file) t) (all-the-icons-icon-for-dir name) (all-the-icons-icon-for-file name)))) (cons (concat icon name) (cdr file) ))) (advice-add #'eshell-ls-annotate :filter-return #'lem-eshell-icons) We can do targets too, but that would be less pretty.
mclearc · 2022-09-12 13:32
Looks great! Nice work -- thanks! I'll edit my question with the final code (which includes iconified file names)
_viz_ · 2022-09-12 15:38
You can put them behind a comment character but at that point why even bother?
divinedominion · 2022-09-13 07:10
/u/mclearc Your changed code doesn't work on it's own: $ ls Symbol’s value as variable is void: eshell-ls-file-keymap That's used here: (propertize name 'keymap eshell-ls-file-keymap 'mouse-face 'highlight 'file-name (expand-file-name (substring-no-properties (car file)) default-directory)) I copied the "make output of ls clickable" code from https://www.emacswiki.org/emacs/EshellEnhancedLS and changed the keymap's name to get it to work somewhat: (eval-after-load "em-ls" '(progn (defun ted-eshell-ls-find-file-at-point (point) "RET on Eshell's `ls' output to open files." (interactive "d") (find-file (buffer-substring-no-properties (previous-single-property-change point 'help-echo) (next-single-property-change point 'help-echo)))) (defun pat-eshell-ls-find-file-at-mouse-click (event) "Middle click on Eshell's `ls' output to open files. From Patrick Anderson via the wiki." (interactive "e") (ted-eshell-ls-find-file-at-point (posn-point (event-end event)))) (let ((map (make-sparse-keymap))) (define-key map (kbd "RET") 'ted-eshell-ls-find-file-at-point) (define-key map (kbd "<return>") 'ted-eshell-ls-find-file-at-point) (define-key map (kbd "<mouse-2>") 'pat-eshell-ls-find-file-at-mouse-click) (defvar eshell-ls-file-keymap map)) (defadvice eshell-ls-decorated-name (after ted-electrify-ls activate) "Eshell's `ls' now lets you click or RET on file names to open them." (add-text-properties 0 (length ad-return-value) (list 'help-echo "RET, mouse-2: visit this file" 'mouse-face 'highlight 'keymap eshell-ls-file-keymap) ad-return-value) ad-return-value)))
mclearc · 2022-09-13 12:35
Thanks -- I had forgotten to include the keymap & related. Now added above, as well as a link to the full eshell config.