How can one quickly browse through lots of files in Emacs?
Asked Answered
M

7

11

is there a way to quickly browse through lots of files in Emacs (24.3)? More specifically:

Let's assume an Emacs frame is split into two windows. Suppose focus is in the left window that has an open 'dired' buffer with lots of text files (or code). I would like to go up and down the list of files (e.g. with cursor keys), while at the same time the current file is shown in the right window. Even better the file is only viewed and closed once I move in the dired buffer to the next file. This would be very useful especially together with some 'omit' mode.

Can this be done in 'dired'? I also coudn't find this functionality in dired-x or in sunrise-commander. Is it possible?

The best candidates I tried already (and why they not solve the problem):

'v' which shows the current file, but also moves the attention

'C-o' which shows the current file, but after moving up or down, I have to press C-o again, also it generates lots of buffers

Thanks a lot for your help!

Miru answered 11/11, 2013 at 13:46 Comment(4)
I like v. You can then navigate with n/p when in view-mode. Also C-x C-q to edit.Lyndialyndon
Navigation with 'n' and 'p' doesn't work for me in view-mode, instead it "searches forward/backward for last regular expression".Miru
Ah, sorry it's my customization. I thought it was the default:)Lyndialyndon
You can also filter which files are displayed in dired mode marking them and then hiding, for example to hide all files ending in .elc you could do % m \.elc RET kNiggard
M
4

Thanks a lot for all those answers. Summarizing I created the following solution (extending the answer of "abo-abo"):

;; little modification to dired-mode that let's you browse through lots of files
(add-hook 'dired-mode-hook
  (lambda()
    (define-key dired-mode-map (kbd "C-o") 'dired-view-current)     ; was dired-display-file
    (define-key dired-mode-map (kbd "n")   'dired-view-next)           ; was dired-next-line
    (define-key dired-mode-map (kbd "p")   'dired-view-previous))) ; was dired-previous-line

(defun dired-view-next ()
  "Move down one line and view the current file in another window."
  (interactive)
  (dired-next-line)
  (dired-view-current))

(defun dired-view-previous ()
  "Move up one line and view the current file in another window."
  (interactive)
  (dired-previous-line)
  (dired-view-current))

(defun dired-view-current ()
  "View the current file in another window (possibly newly created)."
  (interactive)
  (if (not (window-parent))
      (split-window))                                   ; create a new window if necessary
  (let ((file (dired-get-file-for-visit))
        (dbuffer (current-buffer)))
    (other-window 1)                                          ; switch to the other window
    (unless (equal dbuffer (current-buffer))                 ; don't kill the dired buffer
      (if (or view-mode (equal major-mode 'dired-mode))   ; only if in view- or dired-mode
          (kill-buffer)))                                                    ; ... kill it
    (let ((filebuffer (get-file-buffer file)))
      (if filebuffer                              ; does a buffer already look at the file
          (switch-to-buffer filebuffer)                                    ; simply switch 
        (view-file file))                                                    ; ... view it
      (other-window -1))))                   ; give the attention back to the dired buffer

Three keys are changed:

  1. C-o to view the current item in another window (possibly create one).
  2. n to view the next item in another window.
  3. p to view the previous item in another window.

This can be used in a dired buffer. Note that only dired-mode buffers and view-mode buffers get killed while moving up and down. If a file is shown that another buffer is already visiting (not in view-mode), that buffer is shown as well, but not killed when moving to the next. Another subtlety is the case when the passively shown buffer is the dired buffer used for going through the list (this can easily happen, when going inside a folder with RET). To handle this case, we first check whether we are trying to kill the initial dired buffer.

Miru answered 12/11, 2013 at 15:35 Comment(1)
very nice thing! just discovered a tiny bug, at least in emacs 24 you need to pass the number 1 to dired-next/previous-line.Jaal
L
4

Here's how I do this with view-mode:

(add-hook 'view-mode-hook
      (lambda()
        (define-key view-mode-map (kbd "n") 'dired-view-next)
        (define-key view-mode-map (kbd "p") 'dired-view-prev)))

(defun dired-view-next ()
  "Move to next dired line and view ."
  (interactive)
  (quit-window)
  (dired-next-line 1)
  (dired-view-file))

(defun dired-view-prev ()
  "Move to next dired line and view ."
  (interactive)
  (quit-window)
  (dired-next-line -1)
  (dired-view-file))

UPD:

This one has two panes:

(defun dired-view-next-pane ()
  (interactive)
  (other-window 1)
  (if view-mode
      (kill-buffer))
  (other-window -1)
  (dired-next-line 1)
  (view-file-other-window
   (dired-get-file-for-visit))
  (other-window -1))
Lyndialyndon answered 11/11, 2013 at 14:34 Comment(4)
Where are these commands defined? I'm using 24.3.1 and I don't seem to have them.Cleanse
Ah sorry, I thought they were standard. I'll update the answerLyndialyndon
Thanks! Very useful and it is already quite close to what I am looking for. Even better would be to move up and down inside the dired window (as explained in the question).Miru
The view mode gnu.org/software/emacs/manual/html_node/emacs/View-Mode.html seems to be a read-only mode for a file or buffer. What's the rationale to use the view-mode-hook for key mapping for dried mode?Letter
C
4

A simple and generic (while not optimum) solution could be via the C-x () mechanism.

First open the two panes in Emacs, with - say - top one being dired.

  • Press o to open the first file in the 2nd pane.

Then you can start the repetition mechanism:

  • do C-x ( to start recording a macro
  • do C-x k and return to close the buffer
  • do o again to go back to dired
  • do down key to go to next file
  • do o to open next file in bottom pane
  • do C-x ) to end the macro

From that point (being in bottom pane, dired in top pane), doing a mere

  • C-x e (and then only e if there is no other operation in between)

will automatically

  • close bottom pane file, go to top pane, down to next file, open it in bottom pane

There is maybe a more specific way to do that, but knowing the macro mechanism is anyway very helpful in Emacs.

Cornered answered 11/11, 2013 at 15:0 Comment(0)
M
4

Thanks a lot for all those answers. Summarizing I created the following solution (extending the answer of "abo-abo"):

;; little modification to dired-mode that let's you browse through lots of files
(add-hook 'dired-mode-hook
  (lambda()
    (define-key dired-mode-map (kbd "C-o") 'dired-view-current)     ; was dired-display-file
    (define-key dired-mode-map (kbd "n")   'dired-view-next)           ; was dired-next-line
    (define-key dired-mode-map (kbd "p")   'dired-view-previous))) ; was dired-previous-line

(defun dired-view-next ()
  "Move down one line and view the current file in another window."
  (interactive)
  (dired-next-line)
  (dired-view-current))

(defun dired-view-previous ()
  "Move up one line and view the current file in another window."
  (interactive)
  (dired-previous-line)
  (dired-view-current))

(defun dired-view-current ()
  "View the current file in another window (possibly newly created)."
  (interactive)
  (if (not (window-parent))
      (split-window))                                   ; create a new window if necessary
  (let ((file (dired-get-file-for-visit))
        (dbuffer (current-buffer)))
    (other-window 1)                                          ; switch to the other window
    (unless (equal dbuffer (current-buffer))                 ; don't kill the dired buffer
      (if (or view-mode (equal major-mode 'dired-mode))   ; only if in view- or dired-mode
          (kill-buffer)))                                                    ; ... kill it
    (let ((filebuffer (get-file-buffer file)))
      (if filebuffer                              ; does a buffer already look at the file
          (switch-to-buffer filebuffer)                                    ; simply switch 
        (view-file file))                                                    ; ... view it
      (other-window -1))))                   ; give the attention back to the dired buffer

Three keys are changed:

  1. C-o to view the current item in another window (possibly create one).
  2. n to view the next item in another window.
  3. p to view the previous item in another window.

This can be used in a dired buffer. Note that only dired-mode buffers and view-mode buffers get killed while moving up and down. If a file is shown that another buffer is already visiting (not in view-mode), that buffer is shown as well, but not killed when moving to the next. Another subtlety is the case when the passively shown buffer is the dired buffer used for going through the list (this can easily happen, when going inside a folder with RET). To handle this case, we first check whether we are trying to kill the initial dired buffer.

Miru answered 12/11, 2013 at 15:35 Comment(1)
very nice thing! just discovered a tiny bug, at least in emacs 24 you need to pass the number 1 to dired-next/previous-line.Jaal
E
3
  1. Load Icicles.

  2. Define this command:

    (defun my-find-file ()
      "Like `icicle-find-file', but alt action views file temporarily.
    Alternate action keys such as `C-S-down' visit the candidate file in
    `view-mode' and kill the buffer of the last such viewed candidate."
      (interactive)
      (let ((icicle-candidate-alt-action-fn
             (lambda (file)
               (when (and my-last-viewed
                          (get-file-buffer my-last-viewed))
                 (kill-buffer (get-file-buffer my-last-viewed)))
               (setq my-last-viewed  (abbreviate-file-name file))
               (view-file file)
               (select-frame-set-input-focus
                  (window-frame (active-minibuffer-window))))))
        (icicle-find-file-of-content)))

    (defvar my-last-viewed nil
      "Last file viewed by alternate action of `my-find-file'.")

Then you can:

  1. Use M-x my-find-file (or bind it to a key - e.g., C-x C-f).
  2. Optionally type part of a file name, to limit the matching names.
  3. Optionally use down or up to cycle among file names.
  4. Use C-S-down to visit the next file in order.
  5. Repeat #4 to see other files in order.
  6. Repeat #2 or #3 to see other sets of files.
  7. End with RET to choose a file to visit or C-g to cancel.

Each file buffer you visited with C-S-down was killed when you viewed the next one. You can also mix in C-down or C-RET to also visit files whose buffers you do not want to kill automatically. (Change view-file to find-file if you don't want to visit in view-mode, which is read-only.)

[By default, the alternate action for icicle-find-file is icicle-alt-act-fn-for-type, which prompts you for a file- appropriate action to use on the particular candidate chosen for the action. Command my-find-file just substitutes a different alternate action function (for all candidates you choose).]

See also this thread from [email protected]. It is pretty much the same question as yours, I think. My replies there were pretty much the same as my reply here, but there are also replies from others that might help you as well.

Ethno answered 11/11, 2013 at 14:53 Comment(0)
H
2

Try

M-x speedbar

That might appeal to you

Hawkshaw answered 11/11, 2013 at 13:48 Comment(2)
Thanks for the suggestion of 'speedbar'. However, it doesn't solve my initial problem.Miru
A useful suggestion, though it does not answer the question.Dialectic
H
1

Another view-mode solution on top of ag-mode lists. I couldn't find a question for ag-mode, maybe this helps someone generalize a ffap-preview for any mode.

(defun directory-ag-results ()
  (save-excursion
    (goto-char (point-min))
    (search-forward "\"")
    (setq a (point))
    (search-forward "\"")
    (setq b (- (point) 1))
    (buffer-substring-no-properties a b)))

(defun search-item-path ()
  (let ((dir (directory-ag-results))
        (file-parts (split-string (substring-no-properties (thing-at-point 'filename)) ":")))
    (concat dir (nth 0 file-parts))))

(defun search-item-line ()
  (let ((file-parts (split-string (substring-no-properties (thing-at-point 'filename)) ":")))
    (- (string-to-number (nth 1 file-parts)) 1)))

(defun view-current ()
  "Quickly view the current file in another window."
  (if (not (window-parent))
      (split-window))                        ; create a new window if necessary
  (let ((file (search-item-path))
        (line (search-item-line))
        (dbuffer (current-buffer)))
    (other-window 1)                         ; switch to the other window
    (unless (equal dbuffer (current-buffer)) ; don't kill the dired buffer
      (if (or view-mode (equal major-mode 'dired-mode)) ; only if in view- or dired-mode
          (kill-buffer)))                               ; ... kill it
    (let ((filebuffer (get-file-buffer file)))
     (if filebuffer                     ; does a buffer already look at the file
          (switch-to-buffer filebuffer) ; simply switch
        (progn
          (view-file file)              ; ... view it
          (goto-char (point-min))
          (next-line line)))
      (other-window -1))))

(defun next-view-current ()
  (interactive)
  (next-line)
  (view-current))
(defun previous-view-current ()
  (interactive)
  (previous-line)
  (view-current))

(define-key ag-mode-map (kbd "M-p") 'previous-view-current)
(define-key ag-mode-map (kbd "M-n") 'next-view-current)

This is the one thing I think Sublime does better than Emacs. Blasphemy, I know! I like the "q to exit" feel of view-mode, rather than timer-based solutions, and like scrolling around a previewed file. This snippet navigates to the line number found in the search results, optimizing for browsing speed.

Note about the code: I tried polyfilling vc-root-dir from Emacs 25, but it doesn't really make sense for ag-mode since ag-mode's buffer is outside the repo you're searching in. I ended up pulling the root dir from the top of the "ag search" buffer.

Early stages. Improvements welcome.

Demo

Edit: It works for ag-mode, not dired. Demo gif.

Credits: abo-abo, user2979331

Hal answered 21/6, 2016 at 22:1 Comment(0)
B
0

In 2024, the package peep-dired does everything posted in the other answers, and I’m sure there are other packages as well. You don’t have to maintain copypasted or home-rolled lisp for this job.

Bennettbenni answered 24/10, 2022 at 17:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.