Make 'n'/'p' in image mode buffers respect dired sorting
The commands now also now work on archive and tar mode parent buffers. * doc/emacs/files.texi (Image Mode): Document it. * lisp/arc-mode.el (archive-goto-file): New function (bug#38647). (archive-next-file-displayer): Ditto. * lisp/image-mode.el (image-next-file): Reimplement to work on displayed dired buffers and the like. This means that `n' and `p' now works on the displayed ordering in the dired buffer, so if you've reversed the sorting, `n' picks the right "next" file. (image-mode--directory-buffers): New function. (image-mode--next-file): Ditto. * lisp/tar-mode.el (tar-goto-file): New function. (tar-next-file-displayer): Ditto.
This commit is contained in:
parent
7a56e5a44a
commit
361baa451a
5 changed files with 191 additions and 20 deletions
|
@ -2149,7 +2149,12 @@ To reset all transformations to the initial state, use
|
|||
@findex image-previous-file
|
||||
You can press @kbd{n} (@code{image-next-file}) and @kbd{p}
|
||||
(@code{image-previous-file}) to visit the next image file and the
|
||||
previous image file in the same directory, respectively.
|
||||
previous image file in the same directory, respectively. These
|
||||
commands will consult the ``parent'' dired buffer to determine what
|
||||
the next/previous image file is. These commands also work when
|
||||
opening a file from archive files (like zip or tar files), and will
|
||||
then instead consult the archive mode buffer. If neither an archive
|
||||
nor a dired ``parent'' buffer can be found, a dired buffer is opened.
|
||||
|
||||
@findex image-mode-mark-file
|
||||
@findex image-mode-unmark-file
|
||||
|
|
9
etc/NEWS
9
etc/NEWS
|
@ -538,6 +538,15 @@ took more than two seconds to display. The new algorithm maintains a
|
|||
decaying average of delays, and if this number gets too high, the
|
||||
animation is stopped.
|
||||
|
||||
+++
|
||||
*** The 'n' and 'p' commands (next/previous image) now respects dired order.
|
||||
These commands would previously display the next/previous image in
|
||||
alphabetical order, but will now find the "parent" dired buffer and
|
||||
select the next/previous image file according to how the files are
|
||||
sorted there. The commands have also been extended to work when the
|
||||
"parent" buffer is an archive mode (i.e., zip file or the like) or tar
|
||||
mode buffer.
|
||||
|
||||
** EWW
|
||||
|
||||
+++
|
||||
|
|
|
@ -989,6 +989,53 @@ using `make-temp-file', and the generated name is returned."
|
|||
(kill-local-variable 'buffer-file-coding-system)
|
||||
(after-insert-file-set-coding (- (point-max) (point-min))))))
|
||||
|
||||
(defun archive-goto-file (file)
|
||||
"Go to FILE in the current buffer.
|
||||
FILE should be a relative file name. If FILE can't be found,
|
||||
return nil. Otherwise point is returned."
|
||||
(let ((start (point))
|
||||
found)
|
||||
(goto-char (point-min))
|
||||
(while (and (not found)
|
||||
(not (eobp)))
|
||||
(forward-line 1)
|
||||
(when-let ((descr (archive-get-descr t)))
|
||||
(when (equal (archive--file-desc-ext-file-name descr) file)
|
||||
(setq found t))))
|
||||
(if (not found)
|
||||
(progn
|
||||
(goto-char start)
|
||||
nil)
|
||||
(point))))
|
||||
|
||||
(defun archive-next-file-displayer (file regexp n)
|
||||
"Return a closure to display the next file after FILE that matches REGEXP."
|
||||
(let ((short (replace-regexp-in-string "\\`.*:" "" file))
|
||||
next)
|
||||
(archive-goto-file short)
|
||||
(while (and (not next)
|
||||
;; Stop if we reach the end/start of the buffer.
|
||||
(if (> n 0)
|
||||
(not (eobp))
|
||||
(not (save-excursion
|
||||
(beginning-of-line)
|
||||
(bobp)))))
|
||||
(archive-next-line n)
|
||||
(when-let ((descr (archive-get-descr t)))
|
||||
(let ((candidate (archive--file-desc-ext-file-name descr))
|
||||
(buffer (current-buffer)))
|
||||
(when (and candidate
|
||||
(string-match-p regexp candidate))
|
||||
(setq next (lambda ()
|
||||
(kill-buffer (current-buffer))
|
||||
(switch-to-buffer buffer)
|
||||
(archive-extract)))))))
|
||||
(unless next
|
||||
;; If we didn't find a next/prev file, then restore
|
||||
;; point.
|
||||
(archive-goto-file short))
|
||||
next))
|
||||
|
||||
(defun archive-extract (&optional other-window-p event)
|
||||
"In archive mode, extract this entry of the archive into its own buffer."
|
||||
(interactive (list nil last-input-event))
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
|
||||
(require 'image)
|
||||
(require 'exif)
|
||||
(require 'dired)
|
||||
(eval-when-compile (require 'cl-lib))
|
||||
|
||||
;;; Image mode window-info management.
|
||||
|
@ -1085,28 +1086,87 @@ replacing the current Image mode buffer."
|
|||
(error "The buffer is not in Image mode"))
|
||||
(unless buffer-file-name
|
||||
(error "The current image is not associated with a file"))
|
||||
(let* ((file (file-name-nondirectory buffer-file-name))
|
||||
(images (image-mode--images-in-directory file))
|
||||
(idx 0))
|
||||
(catch 'image-visit-next-file
|
||||
(dolist (f images)
|
||||
(if (string= f file)
|
||||
(throw 'image-visit-next-file (1+ idx)))
|
||||
(setq idx (1+ idx))))
|
||||
(setq idx (mod (+ idx (or n 1)) (length images)))
|
||||
(let ((image (nth idx images))
|
||||
(dir (file-name-directory buffer-file-name)))
|
||||
(find-alternate-file image)
|
||||
;; If we have dired buffer(s) open to where this image is, then
|
||||
;; place point on it.
|
||||
(let ((next (image-mode--next-file buffer-file-name n)))
|
||||
(unless next
|
||||
(user-error "No %s file in this directory"
|
||||
(if (> n 0)
|
||||
"next"
|
||||
"prev")))
|
||||
(if (stringp next)
|
||||
(find-alternate-file next)
|
||||
(funcall next))))
|
||||
|
||||
(defun image-mode--directory-buffers (file)
|
||||
"Return a alist of type/buffer for all \"parent\" buffers to image FILE.
|
||||
This is normally a list of dired buffers, but can also be archive and
|
||||
tar mode buffers."
|
||||
(let ((buffers nil)
|
||||
(dir (file-name-directory file)))
|
||||
(cond
|
||||
((and (boundp 'tar-superior-buffer)
|
||||
tar-superior-buffer)
|
||||
(when (buffer-live-p tar-superior-buffer)
|
||||
(push (cons 'tar tar-superior-buffer) buffers)))
|
||||
((and (boundp 'archive-superior-buffer)
|
||||
archive-superior-buffer)
|
||||
(when (buffer-live-p archive-superior-buffer)
|
||||
(push (cons 'archive archive-superior-buffer) buffers)))
|
||||
(t
|
||||
;; Find a dired buffer.
|
||||
(dolist (buffer (buffer-list))
|
||||
(with-current-buffer buffer
|
||||
(when (and (derived-mode-p 'dired-mode)
|
||||
(with-current-buffer buffer
|
||||
(when (and (derived-mode-p 'dired-mode)
|
||||
(equal (file-truename dir)
|
||||
(file-truename default-directory)))
|
||||
(save-window-excursion
|
||||
(switch-to-buffer (current-buffer) t t)
|
||||
(dired-goto-file (expand-file-name image dir)))))))))
|
||||
(push (cons 'dired (current-buffer)) buffers))))
|
||||
;; If we can't find any buffers to navigate in, we open a dired
|
||||
;; buffer.
|
||||
(unless buffers
|
||||
(push (cons 'dired (find-file-noselect dir)) buffers)
|
||||
(message "Opened a dired buffer on %s" dir))))
|
||||
buffers))
|
||||
|
||||
(declare-function archive-next-file-displayer "arc-mode")
|
||||
(declare-function tar-next-file-displayer "tar-mode")
|
||||
|
||||
(defun image-mode--next-file (file n)
|
||||
"Go to the next image file in the parent buffer of FILE.
|
||||
This is typically a dired buffer, but may also be a tar/archive buffer.
|
||||
Return the next image file from that buffer.
|
||||
If N is negative, go to the previous file."
|
||||
(let ((regexp (image-file-name-regexp))
|
||||
(buffers (image-mode--directory-buffers file))
|
||||
next)
|
||||
(dolist (buffer buffers)
|
||||
;; We do this traversal for all the dired buffers open on this
|
||||
;; directory. There probably is just one, but we want to move
|
||||
;; point in all of them.
|
||||
(save-window-excursion
|
||||
(switch-to-buffer (cdr buffer) t t)
|
||||
(cl-case (car buffer)
|
||||
('dired
|
||||
(dired-goto-file file)
|
||||
(let (found)
|
||||
(while (and (not found)
|
||||
;; Stop if we reach the end/start of the buffer.
|
||||
(if (> n 0)
|
||||
(not (eobp))
|
||||
(not (bobp))))
|
||||
(dired-next-line n)
|
||||
(let ((candidate (dired-get-filename nil t)))
|
||||
(when (and candidate
|
||||
(string-match-p regexp candidate))
|
||||
(setq found candidate))))
|
||||
(if found
|
||||
(setq next found)
|
||||
;; If we didn't find a next/prev file, then restore
|
||||
;; point.
|
||||
(dired-goto-file file))))
|
||||
('archive
|
||||
(setq next (archive-next-file-displayer file regexp n)))
|
||||
('tar
|
||||
(setq next (tar-next-file-displayer file regexp n))))))
|
||||
next))
|
||||
|
||||
(defun image-previous-file (&optional n)
|
||||
"Visit the preceding image in the same directory as the current file.
|
||||
|
|
|
@ -922,6 +922,56 @@ actually appear on disk when you save the tar-file's buffer."
|
|||
(setq buffer-undo-list nil))))
|
||||
buffer))
|
||||
|
||||
(defun tar-goto-file (file)
|
||||
"Go to FILE in the current buffer.
|
||||
FILE should be a relative file name. If FILE can't be found,
|
||||
return nil. Otherwise point is returned."
|
||||
(let ((start (point))
|
||||
found)
|
||||
(goto-char (point-min))
|
||||
(while (and (not found)
|
||||
(not (eobp)))
|
||||
(forward-line 1)
|
||||
(when-let ((descriptor (ignore-errors (tar-get-descriptor))))
|
||||
(when (equal (tar-header-name descriptor) file)
|
||||
(setq found t))))
|
||||
(if (not found)
|
||||
(progn
|
||||
(goto-char start)
|
||||
nil)
|
||||
(point))))
|
||||
|
||||
(defun tar-next-file-displayer (file regexp n)
|
||||
"Return a closure to display the next file after FILE that matches REGEXP."
|
||||
(let ((short (replace-regexp-in-string "\\`.*!" "" file))
|
||||
next)
|
||||
;; The tar buffer chops off leading "./", so do the same
|
||||
;; here.
|
||||
(setq short (replace-regexp-in-string "\\`\\./" "" file))
|
||||
(tar-goto-file short)
|
||||
(while (and (not next)
|
||||
;; Stop if we reach the end/start of the buffer.
|
||||
(if (> n 0)
|
||||
(not (eobp))
|
||||
(not (save-excursion
|
||||
(beginning-of-line)
|
||||
(bobp)))))
|
||||
(tar-next-line n)
|
||||
(when-let ((descriptor (ignore-errors (tar-get-descriptor))))
|
||||
(let ((candidate (tar-header-name descriptor))
|
||||
(buffer (current-buffer)))
|
||||
(when (and candidate
|
||||
(string-match-p regexp candidate))
|
||||
(setq next (lambda ()
|
||||
(kill-buffer (current-buffer))
|
||||
(switch-to-buffer buffer)
|
||||
(tar-extract)))))))
|
||||
(unless next
|
||||
;; If we didn't find a next/prev file, then restore
|
||||
;; point.
|
||||
(tar-goto-file short))
|
||||
next))
|
||||
|
||||
(defun tar-extract (&optional other-window-p)
|
||||
"In Tar mode, extract this entry of the tar file into its own buffer."
|
||||
(interactive)
|
||||
|
|
Loading…
Add table
Reference in a new issue