EshellEnhancedLS

This makes Eshell’s ‘ls’ file names RET-able. Yay!

 (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 ted-eshell-ls-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 ted-eshell-ls-keymap)
                              ad-return-value)
         ad-return-value)))

At least on my setup (I tried on both Linux and W2k, running emacs 21), the function ted-eshell-ls-find-file does not work if point is before left-most character of file name. This is because the previous-single-property-change catches a point too far in the buffer and we get text we do not want to. The following modified function fixes this, but only for “short-listings” (that is, not ls -l). The solution is kinda ugly but it works:

      (defun ted-eshell-ls-find-file ()
        (interactive)
	(let ((fname (buffer-substring-no-properties
		      (previous-single-property-change (point) 'help-echo)
		      (next-single-property-change (point) 'help-echo))))
          ;; Remove any leading whitespace, including newline that might
          ;; be fetched by buffer-substring-no-properties
	  (setq fname (replace-regexp-in-string "^[ \t\n]*" "" fname))
          ;; Same for trailing whitespace and newline
	  (setq fname (replace-regexp-in-string "[ \t\n]*$" "" fname))
	  (cond
	   ((equal "" fname)
	    (message "No file name found at point"))
	   (fname
	    (find-file fname)))))

Now, if someone could fix it for long-listings too and describe how to bind the function to mouse-2 also, I would be one step closer to emacs-nirvana! :)MathiasDahl

Here’s mouse-2 clickability. – PatrickAnderson

OK, I’ve cleaned up the code a bit. Only one user-visible change: middle-clicking on a file no longer moves point to that filename. I found that this more closely matched the behavior my fingers expect. – EdwardOConnor