7

Speedbar has a nice feature wherein the directory heading at the top of a files/directory buffer contains various text properties for the user to jump to any of the parent directories by placing the cursor on the corresponding name and pressing the enter key. I took it one step further and placed a text property at point-min to jump to root.

Q:  Is there an existing modification for dired-mode that accomplishes the same thing? If not, then this thread can be used to create such a new feature.

GOAL -- dired-mode:  For example, the heading directory in dired-mode is: /Users/HOME/data/emacs/lisp

  • Placing the cursor at point-min and pressing enter will open a dired buffer at /

  • Placing the cursor anywhere on the word Users and pressing enter will open a dired buffer at /Users

  • Placing the cursor anywhere on the word HOME and pressing enter will open a dired buffer at /Users/HOME.

  • Placing the cursor anywhere on the word data and pressing enter will open a dired buffer at /Users/HOME/data.

  • Placing the cursor anywhere on the word emacs and pressing enter will open a dired buffer at /Users/HOME/data/emacs.

lawlist
  • 18,826
  • 5
  • 37
  • 118
  • 1
    Sounds like you are describing breadcrumbs. This does not exist in vanilla Dired. And as far as I know, it does not yet exist in a Dired extension library. It might exist in a Dired alternative (e.g. Midnight Commander or some such). I added this feature to Emacs Info several years back. It might be worthwhile to add it to Dired too. Perhaps you will be the first to do so. ;-) – Drew Jun 23 '15 at 01:18
  • I meant that I added it (optionally) to the mode line in [Info+](http://www.emacswiki.org/emacs/InfoPlus), not to Emacs. I added breadcrumbs to Emacs at the top of the Info buffer. – Drew Jun 24 '15 at 20:54

3 Answers3

2
(require 'dired)

(defface dired-mouseover-face
  '((t (:foreground "green")))
  "Face for `dired-mouseover-face'."
  :group 'dired)

(defvar dired-mouse-map
  (let ((map (make-sparse-keymap)))
    (define-key map [mouse-2] 'dired-follow-link)
    (define-key map [return] 'dired-follow-link)
    (define-key map [follow-link] 'mouse-face)
      map)
  "Keymap for mouse when in `dired-mode'.")

;; Author:  Drew Adams -- http://emacs.stackexchange.com/a/13411/2287
(defun dired-follow-link (event)
"Follow the link in the dired directory heading, causing a new
dired buffer to be opened."
  (interactive (list last-nonmenu-event))
  (run-hooks 'mouse-leave-buffer-hook)
  (with-current-buffer (window-buffer (posn-window (event-start event)))
    (let ((path  (get-text-property (posn-point (event-start event)) 'breadcrumb)))
      (dired path))))

(defun dired-propertize-directory-heading ()
(interactive)
  (unless (buffer-narrowed-p)
    (let* (
        p beg end path peol
        (inhibit-read-only t) )
      (save-excursion
        (goto-char (point-min))
        (setq peol (point-at-eol))
        (set-text-properties (point) peol nil)
        (re-search-forward "\\([^/\\]+\\)[/\\]" peol t)
        (when (looking-back "\\(^ +\\)\\([a-zA-Z]:\\)?/")
          (setq p (match-end 1))
          (setq path (if (match-string 2) (concat (match-string 2) "/") "/"))
          (add-text-properties (point-min) (1- (match-end 0)) (list
            'breadcrumb path
            'mouse-face 'dired-mouseover-face
            'help-echo (format "mouse-2, RET: Follow the link to \"%s\"." path)
            'keymap dired-mouse-map)))
        (while (re-search-forward "\\([^/\\]+\\)[/\\]" peol t)
          (setq beg (match-beginning 1))
          (setq end (match-end 1))
          (setq path (buffer-substring-no-properties p end))
          (add-text-properties beg end (list
            'breadcrumb path
            'mouse-face 'dired-mouseover-face
            'help-echo (format "mouse-2, RET: Follow the link to \"%s\"." path)
            'keymap dired-mouse-map)))
        (setq path (buffer-substring-no-properties p (1- peol)))
        (add-text-properties (point) (1- peol) (list
          'breadcrumb path
          'mouse-face 'dired-mouseover-face
          'help-echo (format "mouse-2, RET: Follow the link to \"%s\"." path)
          'keymap dired-mouse-map))))))

(add-hook 'dired-after-readin-hook 'dired-propertize-directory-heading)

Example

lawlist
  • 18,826
  • 5
  • 37
  • 118
  • Nice -- this is very handy. – glucas Jun 24 '15 at 14:53
  • @glucas -- thanks for trying it out -- as I use it more in different situations, I will revise the regexp as needed -- e.g., remote servers and such (with tramp) haven't been tested yet and I primarily use OSX, with just an occasional use of Emacs for Window. At some point, I'll test it with dired+ and revise as needed for compatability. – lawlist Jun 24 '15 at 16:06
  • Cool. For what it's worth I'm trying this out on Windows, but have only done normal / local dir stuff so far. – glucas Jun 24 '15 at 20:00
2

I added a similar feature to Dired+ (dired+.el).

Turn on minor mode diredp-breadcrumbs-in-header-line-mode.

This puts breadcrumbs on a separate optional header line for the whole Dired buffer, not on each directory header (e.g. each inserted subdir). If you prefer the latter then see lawlist's approach.

If you want to turn it on automatically in all Dired buffers, you can do this:

(add-hook 'dired-before-readin-hook 'diredp-breadcrumbs-in-header-line-mode)

This is the code I use:

(define-minor-mode diredp-breadcrumbs-in-header-line-mode
    "Toggle the use of breadcrumbs in Dired header line.
    With arg, show breadcrumbs iff arg is positive."
  :init-value nil :group 'header-line :group 'Dired-Plus
  (unless (derived-mode-p 'dired-mode)
    (error "You must be in Dired or a mode derived from it to use this command"))
  (if diredp-breadcrumbs-in-header-line-mode
      (diredp-set-header-line-breadcrumbs)
    (setq header-line-format  (default-value 'header-line-format))))

(defun diredp-set-header-line-breadcrumbs ()
  "Show a header line with breadcrumbs to parent directories."
  (let ((parent  (diredp-parent-dir default-directory))
        (crumbs  ())
        (text    ""))
    (while parent
      (push parent crumbs)
      (setq parent  (diredp-parent-dir parent)))
    (dolist (dir  crumbs)
      (let ((crumbs-map  (make-sparse-keymap))
            (menu-map    (make-sparse-keymap "Breadcrumbs in Header Line")))
        (when dir
          (setq dir  (propertize
                      dir
                      'local-map
                      (progn (define-key crumbs-map [header-line mouse-1]
                               `(lambda () (interactive)
                                   (dired ,dir dired-actual-switches)))
                             (define-key crumbs-map [header-line mouse-2]
                               `(lambda () (interactive)
                                   (dired-other-window ,dir dired-actual-switches)))
                             crumbs-map)
                      'mouse-face 'mode-line-highlight
                      'help-echo "mouse-1: Dired; mouse-2: Dired in other window"))
          (setq text  (concat text (if (diredp-root-directory-p dir) "" "  ") dir)))
        (make-local-variable 'header-line-format)
        (setq header-line-format  text)))))
Drew
  • 75,699
  • 9
  • 109
  • 225
  • http://www.emacswiki.org/emacs/download/dired%2b.el hasn't yet been synchronized with http://www.emacswiki.org/emacs/dired%2b.el – lawlist Jun 25 '15 at 02:39
  • I must have had a cached version -- it's in sync now. :) I lightly tested the new feature and everything appears to work as advertised. – lawlist Jun 25 '15 at 04:10
1

Another approach to achieve the same thing. I've got this in use for a while now. To use it press mouse-2 on the directory name.

(require 'dired+)

(defadvice diredp-mouse-find-file-reuse-dir-buffer (before breadcrumb activate)
    (let (file)
    (with-current-buffer (window-buffer (posn-window (event-end event)))
      (save-excursion
    (goto-char (posn-point (event-end event)))
    (when (and (= (line-beginning-position) 1)
           (null (and (looking-back "^[[:blank:]]*") (= (char-after) ?/)))
           (search-forward-regexp "[/:]" (line-end-position) 'noErr))
      (search-backward-regexp "^[[:blank:]]*\\(.*\\).")
      (setq file (match-string-no-properties 1))
      (if (file-directory-p file)
          (progn
        (find-alternate-file (file-name-sans-versions file t))
        (deactivate-mark))
        (error "First line in dired buffer is no dir. I am confused.")
        ))))))

I know that this is hacky. But, it works for me.

If you do not want to require dired+ advice dired-mouse-find-file-other-window instead.

Tobias
  • 32,569
  • 1
  • 34
  • 75
  • Thank you for the mouse idea -- I've incorporated a variation of that idea into an alternative answer that uses text properties -- greatly appreciated. – lawlist Jun 23 '15 at 17:51