2021-07-13 18:43:44 +00:00
|
|
|
;;; sxiv.el --- Run the Simple X Image Viewer, with Dired integration -*- lexical-binding: t; -*-
|
2020-01-12 18:08:56 +00:00
|
|
|
|
|
|
|
;; Author: contrapunctus <xmpp:contrapunctus@jabber.fr>
|
|
|
|
;; Maintainer: contrapunctus <xmpp:contrapunctus@jabber.fr>
|
2020-01-13 15:16:14 +00:00
|
|
|
;; Keywords: multimedia
|
2020-03-25 07:57:59 +00:00
|
|
|
;; Homepage: https://gitlab.com/contrapunctus/sxiv.el
|
2020-01-13 15:16:14 +00:00
|
|
|
;; Package-Requires: ((dash "2.16.0") (emacs "25.1"))
|
2021-05-14 09:18:58 +00:00
|
|
|
;; Version: 0.4.1
|
2020-01-12 17:48:12 +00:00
|
|
|
|
2020-03-25 06:10:46 +00:00
|
|
|
;; This is free and unencumbered software released into the public domain.
|
|
|
|
;;
|
|
|
|
;; Anyone is free to copy, modify, publish, use, compile, sell, or
|
|
|
|
;; distribute this software, either in source code form or as a compiled
|
|
|
|
;; binary, for any purpose, commercial or non-commercial, and by any
|
|
|
|
;; means.
|
|
|
|
;;
|
|
|
|
;; For more information, please refer to <https://unlicense.org>
|
|
|
|
|
2020-01-12 17:48:12 +00:00
|
|
|
;;; Commentary:
|
2021-07-13 18:43:44 +00:00
|
|
|
;; The main (and only) command is `M-x sxiv`.
|
2020-01-12 17:48:12 +00:00
|
|
|
;;
|
2021-07-13 18:43:44 +00:00
|
|
|
;; If it is run in a Dired buffer containing images, files marked in
|
|
|
|
;; sxiv (mark/unmark with `m`) will be marked in Dired. If the Dired
|
|
|
|
;; buffer has marked files, open only those files. With prefix
|
|
|
|
;; argument, or when only provided directories, run recursively.
|
|
|
|
;;
|
|
|
|
;; It can also be run from a text file containing one file name per
|
|
|
|
;; line.
|
|
|
|
|
2020-03-25 08:19:18 +00:00
|
|
|
;; `sxiv-filter' is the process filter, to insert subdirectories (via
|
|
|
|
;; `sxiv-insert-subdirs') and mark files marked in sxiv (via
|
|
|
|
;; `sxiv-dired-mark-files').
|
2020-01-12 17:48:12 +00:00
|
|
|
|
2020-03-26 14:33:28 +00:00
|
|
|
(require 'dired)
|
2020-01-12 17:33:34 +00:00
|
|
|
(require 'dash)
|
|
|
|
|
2020-01-12 17:48:12 +00:00
|
|
|
;;; Code:
|
|
|
|
|
2020-01-13 11:38:33 +00:00
|
|
|
(defgroup sxiv nil
|
|
|
|
"Run the Simple X Image Viewer."
|
2020-01-13 15:16:14 +00:00
|
|
|
:group 'multimedia)
|
2020-01-13 11:38:33 +00:00
|
|
|
|
|
|
|
(defcustom sxiv-arguments '("-a" "-f" "-o")
|
|
|
|
"Arguments to be passed to the sxiv process.
|
|
|
|
It must contain \"-o\" for marking in Dired buffers to function."
|
|
|
|
:type '(repeat string))
|
|
|
|
|
2020-01-13 13:26:29 +00:00
|
|
|
(defcustom sxiv-exclude-strings '()
|
|
|
|
"Exclude files whose paths match these strings."
|
|
|
|
:type '(repeat string))
|
|
|
|
|
2021-04-06 13:40:10 +00:00
|
|
|
(defcustom sxiv-after-exit-functions '(sxiv-dired-mark-files)
|
|
|
|
"Functions run after the sxiv process exits.
|
|
|
|
Each function must accept two arguments, the associated process
|
|
|
|
and a string, which is output just received from it."
|
|
|
|
:type '(repeat function))
|
|
|
|
|
2020-01-12 17:33:34 +00:00
|
|
|
(defvar sxiv--directory nil
|
|
|
|
"Directory `sxiv' was called from.
|
|
|
|
Used by `sxiv-filter' to know where to mark files.")
|
|
|
|
|
|
|
|
(defun sxiv-dired-marked-files-p ()
|
2020-01-12 17:48:12 +00:00
|
|
|
"Return t if there are marked files in the current Dired buffer.
|
|
|
|
With no marked files, or if not in a Dired buffer, return nil."
|
2020-03-29 06:04:55 +00:00
|
|
|
(and (derived-mode-p 'dired-mode)
|
|
|
|
(save-excursion
|
|
|
|
(goto-char (point-min))
|
|
|
|
(re-search-forward dired-re-mark nil t))))
|
2020-01-12 17:33:34 +00:00
|
|
|
|
2020-01-14 07:07:37 +00:00
|
|
|
(defun sxiv-insert-subdirs (paths)
|
|
|
|
"Insert subdirectories from PATHS into the current Dired buffer.
|
|
|
|
Return PATHS unchanged."
|
2020-08-03 14:28:38 +00:00
|
|
|
(cl-loop for path in paths
|
|
|
|
;; If the file does not exist in the current directory...
|
2020-09-03 04:33:27 +00:00
|
|
|
when (and (not (file-exists-p (file-name-nondirectory path)))
|
|
|
|
;; Workaround for what looks like an Emacs issue (see TODO #9)
|
|
|
|
(file-exists-p path)
|
2020-08-03 14:28:38 +00:00
|
|
|
;; ;; ...I don't understand why this is here!
|
|
|
|
;; ;; Why would there be a directory in the selected
|
|
|
|
;; ;; files, seeing as one can't mark directories in
|
|
|
|
;; ;; sxiv?
|
|
|
|
;; (file-directory-p path)
|
|
|
|
)
|
|
|
|
do (dired-insert-subdir (file-name-directory path))
|
|
|
|
finally return paths))
|
2020-01-14 07:07:37 +00:00
|
|
|
|
2021-04-06 13:40:10 +00:00
|
|
|
(defun sxiv-dired-mark-files (_process output)
|
|
|
|
"Open a `dired' buffer and mark any files marked by the user in `sxiv'."
|
2020-01-12 17:33:34 +00:00
|
|
|
(find-file sxiv--directory)
|
2021-04-06 13:40:10 +00:00
|
|
|
(let ((files (--> (split-string output "\n")
|
|
|
|
(-drop-last 1 it)
|
|
|
|
(sxiv-insert-subdirs it))))
|
|
|
|
(dired-mark-if
|
|
|
|
(and (not (looking-at-p dired-re-dot))
|
|
|
|
(not (eolp))
|
|
|
|
(let ((fn (dired-get-filename t t)))
|
|
|
|
(and fn (--find (equal fn it) files))))
|
|
|
|
"file")))
|
|
|
|
|
|
|
|
(defun sxiv-filter (process output)
|
|
|
|
"Used as process filter for `sxiv'.
|
|
|
|
OUTPUT is the output of the sxiv process as a string."
|
|
|
|
(run-hook-with-args 'sxiv-after-exit-functions process output))
|
|
|
|
|
|
|
|
(defun sxiv-paths-raw ()
|
2022-05-11 16:11:50 +00:00
|
|
|
"Return a list of strings containing absolute paths to files."
|
|
|
|
(cond ((derived-mode-p 'dired-mode)
|
|
|
|
(if (sxiv-dired-marked-files-p)
|
|
|
|
(dired-get-marked-files)
|
|
|
|
(let (list)
|
|
|
|
(dired-map-dired-file-lines
|
|
|
|
(lambda (name)
|
|
|
|
(setq list (cons name list))))
|
|
|
|
(reverse list))))
|
2021-04-06 13:40:10 +00:00
|
|
|
((derived-mode-p 'text-mode)
|
|
|
|
(split-string
|
|
|
|
(buffer-substring-no-properties (point-min) (point-max))
|
|
|
|
"\n"))
|
2022-05-11 16:11:50 +00:00
|
|
|
(t (user-error "sxiv: this is not a dired or text buffer"))))
|
2021-04-06 13:40:10 +00:00
|
|
|
|
|
|
|
(defun sxiv-file-at-point-index (&optional paths)
|
|
|
|
"Return index of file at point.
|
|
|
|
PATHS should be a list of relative file names as strings, and is
|
2021-07-13 18:43:44 +00:00
|
|
|
required for `dired-mode' buffers."
|
2021-04-06 13:40:10 +00:00
|
|
|
(cond ((derived-mode-p 'dired-mode)
|
|
|
|
(let* ((path-at-point (dired-file-name-at-point))
|
|
|
|
(image-at-point (and path-at-point
|
|
|
|
;; REVIEW - also check if file is an image?
|
|
|
|
(file-regular-p path-at-point)
|
|
|
|
(file-relative-name path-at-point)))
|
|
|
|
(index (when image-at-point
|
|
|
|
(--find-index (equal image-at-point it) paths))))
|
|
|
|
(when index (1+ index))))
|
|
|
|
((derived-mode-p 'text-mode)
|
|
|
|
(line-number-at-pos))))
|
2020-01-12 17:33:34 +00:00
|
|
|
|
|
|
|
(defun sxiv (&optional prefix)
|
|
|
|
"Run sxiv(1), the Simple X Image Viewer.
|
2022-05-11 16:11:50 +00:00
|
|
|
When run in a Dired buffer, open all files in the current
|
|
|
|
directory. Files marked in sxiv will be marked in Dired.
|
2020-01-12 17:33:34 +00:00
|
|
|
|
2022-05-11 16:11:50 +00:00
|
|
|
When run from a Dired buffer with marked files, open only those
|
2020-01-12 17:33:34 +00:00
|
|
|
files.
|
|
|
|
|
2020-01-12 17:48:12 +00:00
|
|
|
With prefix argument PREFIX, or when only provided directories,
|
|
|
|
run recursively (-r).
|
2020-01-12 17:33:34 +00:00
|
|
|
|
|
|
|
If run from a text file containing one file name per line, open
|
|
|
|
the files listed."
|
|
|
|
(interactive "P")
|
2021-04-06 13:40:10 +00:00
|
|
|
(let* ((paths (--remove (or (equal it ".") (equal it "..")
|
|
|
|
;; Currently, this takes effect even
|
|
|
|
;; when running from a text
|
|
|
|
;; file...should that be the case?
|
|
|
|
(-find (lambda (exclude)
|
|
|
|
(string-match-p exclude it))
|
|
|
|
sxiv-exclude-strings))
|
|
|
|
(sxiv-paths-raw)))
|
2020-01-13 10:45:03 +00:00
|
|
|
;; recurse with prefix arg, or if every path is a directory
|
2022-05-11 16:11:50 +00:00
|
|
|
(recurse (or prefix
|
|
|
|
(-every? #'file-directory-p paths)))
|
2020-01-12 17:33:34 +00:00
|
|
|
;; remove directories if not running recursively
|
2022-05-11 16:11:50 +00:00
|
|
|
(paths (if recurse
|
|
|
|
paths
|
|
|
|
(seq-remove #'file-directory-p paths)))
|
2021-04-06 13:40:10 +00:00
|
|
|
(index (sxiv-file-at-point-index paths))
|
|
|
|
(index (when index (number-to-string index)))
|
|
|
|
(recurse (if recurse "-r" "")))
|
2020-01-12 17:33:34 +00:00
|
|
|
(setq sxiv--directory default-directory)
|
2020-08-03 14:07:22 +00:00
|
|
|
(message "Running sxiv...")
|
|
|
|
(make-process :name "sxiv"
|
2021-05-14 09:18:58 +00:00
|
|
|
:buffer (generate-new-buffer-name "sxiv")
|
2020-08-03 14:07:22 +00:00
|
|
|
:command
|
|
|
|
(append '("sxiv")
|
|
|
|
sxiv-arguments
|
2021-04-06 13:40:10 +00:00
|
|
|
(when index (list "-n" index))
|
2020-08-03 14:07:22 +00:00
|
|
|
(list recurse "--")
|
|
|
|
paths)
|
|
|
|
:connection-type 'pipe
|
|
|
|
:filter #'sxiv-filter
|
|
|
|
:stderr "sxiv-errors")))
|
2020-01-12 17:33:34 +00:00
|
|
|
|
|
|
|
;; Local Variables:
|
|
|
|
;; nameless-current-name: "sxiv"
|
|
|
|
;; End:
|
2020-01-12 17:48:12 +00:00
|
|
|
|
|
|
|
(provide 'sxiv)
|
|
|
|
|
|
|
|
;;; sxiv.el ends here
|