Compare commits
29 Commits
v0.3.0
...
production
Author | SHA1 | Date |
---|---|---|
contrapunctus | 0449244925 | |
contrapunctus | 6291d3b7b1 | |
contrapunctus | f286ce396d | |
contrapunctus | 61f91e2464 | |
contrapunctus | 9ff8f6d8e9 | |
contrapunctus | 14057b156d | |
contrapunctus | 028409c3a9 | |
contrapunctus | a531a7596e | |
contrapunctus | 3544c6b3a4 | |
contrapunctus | b8becd786c | |
contrapunctus | ded8989e82 | |
contrapunctus | 678b411a8f | |
contrapunctus | b74f2c59a7 | |
contrapunctus | 9eb6a121bf | |
contrapunctus | 5b08ed004e | |
contrapunctus | 247cb7bdcb | |
contrapunctus | 086bc5ae97 | |
contrapunctus | a23d1639f8 | |
contrapunctus | f1a030c538 | |
contrapunctus | 00861f086e | |
contrapunctus | dae46e6f58 | |
contrapunctus | ab89cd2d20 | |
contrapunctus | b8b53c104e | |
contrapunctus | efd484fc02 | |
contrapunctus | 7972b8f1a5 | |
contrapunctus | cf4aa28c29 | |
contrapunctus | 40d5c41a98 | |
contrapunctus | d6abe6645b | |
contrapunctus | eef2f8bea9 |
21
CHANGELOG.md
21
CHANGELOG.md
|
@ -4,6 +4,27 @@ All notable changes to this project will be documented in this file.
|
|||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [0.4.1] - 2021-05-14
|
||||
### Fixed
|
||||
* Use unique buffer name for process output.
|
||||
|
||||
## [0.4.0] - 2021-04-06
|
||||
### Added
|
||||
* When launching from a text file, open sxiv with the image at point (using `-n`)
|
||||
|
||||
## [0.3.3] - 2020-08-03
|
||||
### Fixed
|
||||
* Error with selected files in a subdirectory (issue #1)
|
||||
|
||||
## [0.3.2] - 2020-05-08
|
||||
### Fixed
|
||||
* Workaround for crash in certain cases
|
||||
|
||||
## [0.3.1] - 2020-03-25
|
||||
### Added
|
||||
* Marking files now works recursively, too.
|
||||
* Show message when starting sxiv
|
||||
|
||||
## [0.3.0] - 2020-01-14
|
||||
### Added
|
||||
* Open sxiv at the image at point
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
(source gnu)
|
||||
(source melpa)
|
||||
|
||||
(package
|
||||
"sxiv.el"
|
||||
"0.4.1"
|
||||
"Run the Simple X Image Viewer")
|
||||
|
||||
(depends-on "dash" "2.16.0")
|
27
README.md
27
README.md
|
@ -1,3 +1,7 @@
|
|||
<a href="https://liberapay.com/contrapunctus/donate"><img alt="Donate using Liberapay" src="https://img.shields.io/liberapay/receives/contrapunctus.svg?logo=liberapay"></a>
|
||||
|
||||
<a href="https://melpa.org/#/sxiv"><img src="https://melpa.org/packages/sxiv-badge.svg"></a>
|
||||
|
||||
# sxiv.el
|
||||
Launch [sxiv](https://github.com/muennich/sxiv) (Simple X Image Viewer) from Emacs, with Dired integration.
|
||||
|
||||
|
@ -7,7 +11,9 @@ You can get `sxiv.el` from
|
|||
`sxiv.el` requires [dash.el](https://github.com/magnars/dash.el) and an installed [sxiv](https://github.com/muennich/sxiv) in your $PATH
|
||||
|
||||
## Usage
|
||||
`M-x sxiv` - entry point. Run it in a Dired buffer containing images. Files marked in sxiv will be marked in Dired.
|
||||
The main command is `M-x sxiv`.
|
||||
|
||||
Run it 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.
|
||||
|
||||
|
@ -15,15 +21,6 @@ With prefix argument, or when only provided directories, run recursively.
|
|||
|
||||
Run it from a text file containing one file name per line to open the listed files.
|
||||
|
||||
## TODO
|
||||
1. [x] Create user-customizable variable to hold default arguments
|
||||
2. [x] Start sxiv on the file at point (using `-n ...`)
|
||||
3. [x] Let user specify paths to be excluded.
|
||||
4. [ ] Mark files in subdirectories if run recursively (by inserting the subdirectory into the current buffer)
|
||||
5. [ ] Let user edit options (ideally with transient.el) when called with null argument/two prefix arguments
|
||||
6. [ ] When running with a lot of files, sxiv may take some time to start. Signal to the user that it is starting, and let them kill it if they want.
|
||||
7. What should be the behavior when we open Dired-marked files, then mark files within sxiv?
|
||||
|
||||
## Limitations
|
||||
* `sxiv-dired-marked-files-p` doesn't work as intended with non '*' markers (e.g. C or D)
|
||||
|
||||
|
@ -38,14 +35,20 @@ At a cursory glance, picpocket (v20180914)
|
|||
## Contributions and contact
|
||||
Feedback and MRs very welcome. 🙂
|
||||
|
||||
You may be interested in the [TODO.md](TODO.md)
|
||||
|
||||
Contact the creator and other Emacs users in the Emacs room on the Jabber network - [xmpp:emacs@salas.suchat.org?join](xmpp:emacs@salas.suchat.org?join) ([web chat](https://inverse.chat/#converse/room?jid=emacs@salas.suchat.org))
|
||||
|
||||
(For help in getting started with Jabber, [click here](https://xmpp.org/getting-started/))
|
||||
|
||||
## License
|
||||
sxiv.el is released under your choice of [Unlicense](https://unlicense.org/) and the [WTFPL](http://www.wtfpl.net/).
|
||||
I dream of a world where all software is liberated - transparent, trustable, and accessible for anyone to use or improve. But I don't want to make demands or threats (e.g. via legal conditions) to get there.
|
||||
|
||||
(See files [LICENSE](LICENSE) and [LICENSE.1](LICENSE.1)).
|
||||
I'd rather make a request - please do everything you can to help that dream come true. Please Unlicense as much software as you can.
|
||||
|
||||
sxiv.el is released under your choice of [Unlicense](https://unlicense.org/) or the [WTFPL](http://www.wtfpl.net/).
|
||||
|
||||
(See files [UNLICENSE](UNLICENSE) and [WTFPL](WTFPL)).
|
||||
|
||||
## Thanks
|
||||
wasamasa, bpalmer and #emacs for all their help and support
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
# TODO
|
||||
1. [x] Create user-customizable variable to hold default arguments
|
||||
2. [x] Start sxiv on the file at point (using `-n ...`)
|
||||
3. [x] Let user specify paths to be excluded.
|
||||
4. [x] Mark files in subdirectories if run recursively (by inserting the subdirectory into the current buffer)
|
||||
5. [ ] Let user edit options (ideally with transient.el) when called with null argument/two prefix arguments.
|
||||
* When files are marked in Dired - only display marked files, or ignore marks and run as usual
|
||||
* When files are marked in Dired and we mark files in sxiv - replace the selection, or unmark the files marked this time
|
||||
* Other options like running recursively, modifying arguments, etc
|
||||
6. [ ] When running with a lot of files, sxiv may take some time to start. Signal to the user that it is starting, and let them kill it if they want.
|
||||
7. [ ] `sxiv-exclude-strings` does not work recursively, because only the directories are passed to the process. Adding all files to the path might cause it to fail (bash length limit), or take a long time.
|
||||
* Use find(1) to pass the files?
|
||||
8. [ ] Make it work in `find-dired` buffers too
|
||||
9. [ ] Bug - sometimes, if a lot of files (usually over 50) are marked in sxiv, the input received by `sxiv-insert-subdirs` is incomplete - the first file name is a trailing segment of an actual existing filename, e.g. if a file is called `"foo/bar_baz.jpg"`, I might get something like `"r_baz.jpg"` as the first element.
|
||||
* I have no idea what's causing this or how to fix it. Help needed! :(
|
||||
10. [ ] Optimize startup speed, especially with a large number of files.
|
||||
11. [ ] When using a text file, mark files marked in sxiv.
|
||||
* Maybe using multiple-cursors or iedit?
|
||||
12. [x] When launching from a text file, open sxiv with the image at point (using `-n`).
|
||||
|
||||
Option menu when starting sxiv -
|
||||
1. recursive
|
||||
2. find | sxiv
|
||||
3. edit file/directory list
|
||||
|
||||
Prompt (hydra/read-multiple-choice) for what to do with selected files -
|
||||
1. mark in Dired (overwriting previous selection)
|
||||
2. append to existing Dired marks
|
||||
3. unmark from existing Dired marks
|
||||
4. copy as text
|
||||
5. save in file in sxiv launch directory (default file name in custom variable)
|
||||
...and other (extensible) actions.
|
201
sxiv.el
201
sxiv.el
|
@ -1,15 +1,37 @@
|
|||
;;; sxiv.el --- Run the sxiv image viewer -*- lexical-binding: t; -*-
|
||||
;;; sxiv.el --- Run the Simple X Image Viewer, with Dired integration -*- lexical-binding: t; -*-
|
||||
|
||||
;; Author: contrapunctus <xmpp:contrapunctus@jabber.fr>
|
||||
;; Maintainer: contrapunctus <xmpp:contrapunctus@jabber.fr>
|
||||
;; Keywords: multimedia
|
||||
;; Homepage: https://notabug.org/contrapunctus/sxiv.el/src/master/sxiv.el
|
||||
;; Homepage: https://tildegit.org/contrapunctus/sxiv
|
||||
;; Package-Requires: ((dash "2.16.0") (emacs "25.1"))
|
||||
;; Version: 0.3.0
|
||||
;; Version: 0.4.1
|
||||
|
||||
;; 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>
|
||||
|
||||
;;; Commentary:
|
||||
;; The main (and only) command is `M-x sxiv`.
|
||||
;;
|
||||
;; 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.
|
||||
;;
|
||||
;; `sxiv-filter' is the process filter, to insert subdirectories (via
|
||||
;; `sxiv-insert-subdirs') and mark files marked in sxiv (via
|
||||
;; `sxiv-dired-mark-files').
|
||||
|
||||
(require 'dired)
|
||||
(require 'dash)
|
||||
|
||||
;;; Code:
|
||||
|
@ -27,6 +49,12 @@ It must contain \"-o\" for marking in Dired buffers to function."
|
|||
"Exclude files whose paths match these strings."
|
||||
:type '(repeat string))
|
||||
|
||||
(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))
|
||||
|
||||
(defvar sxiv--directory nil
|
||||
"Directory `sxiv' was called from.
|
||||
Used by `sxiv-filter' to know where to mark files.")
|
||||
|
@ -34,40 +62,85 @@ Used by `sxiv-filter' to know where to mark files.")
|
|||
(defun sxiv-dired-marked-files-p ()
|
||||
"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."
|
||||
(if (equal major-mode 'dired-mode)
|
||||
(if (save-excursion
|
||||
(goto-char (point-min))
|
||||
(re-search-forward dired-re-mark nil t))
|
||||
t
|
||||
nil)
|
||||
nil))
|
||||
(and (derived-mode-p 'dired-mode)
|
||||
(save-excursion
|
||||
(goto-char (point-min))
|
||||
(re-search-forward dired-re-mark nil t))))
|
||||
|
||||
(defun sxiv-filter (_process output)
|
||||
"Open a `dired' buffer and mark any files marked by the user in `sxiv'.
|
||||
Used as process filter for `sxiv'.
|
||||
(defun sxiv-insert-subdirs (paths)
|
||||
"Insert subdirectories from PATHS into the current Dired buffer.
|
||||
Return PATHS unchanged."
|
||||
(cl-loop for path in paths
|
||||
;; If the file does not exist in the current directory...
|
||||
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)
|
||||
;; ;; ...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))
|
||||
|
||||
OUTPUT is the output of the sxiv process as a string."
|
||||
(defun sxiv-dired-mark-files (_process output)
|
||||
"Open a `dired' buffer and mark any files marked by the user in `sxiv'."
|
||||
(find-file sxiv--directory)
|
||||
(--> output
|
||||
(split-string it "\n")
|
||||
(-drop-last 1 it)
|
||||
(sxiv-dired-mark-files it)))
|
||||
(let ((files (--> (split-string output "\n")
|
||||
(-drop-last 1 it)
|
||||
(mapcar #'file-relative-name 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-dired-mark-files (files)
|
||||
"Mark FILES in the current (dired) buffer."
|
||||
(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 ()
|
||||
"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))))
|
||||
((derived-mode-p 'text-mode)
|
||||
(split-string
|
||||
(buffer-substring-no-properties (point-min) (point-max))
|
||||
"\n"))
|
||||
(t (user-error "sxiv: this is not a dired or text buffer"))))
|
||||
|
||||
(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
|
||||
required for `dired-mode' buffers."
|
||||
(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)
|
||||
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))))
|
||||
|
||||
(defun sxiv (&optional prefix)
|
||||
"Run sxiv(1), the Simple X Image Viewer.
|
||||
By default, when run in a Dired buffer, open all files in the
|
||||
current directory. Files marked in sxiv will be marked in Dired.
|
||||
When run in a Dired buffer, open all files in the current
|
||||
directory. Files marked in sxiv will be marked in Dired.
|
||||
|
||||
If run from a Dired buffer with marked files, open only those
|
||||
When run from a Dired buffer with marked files, open only those
|
||||
files.
|
||||
|
||||
With prefix argument PREFIX, or when only provided directories,
|
||||
|
@ -76,51 +149,37 @@ run recursively (-r).
|
|||
If run from a text file containing one file name per line, open
|
||||
the files listed."
|
||||
(interactive "P")
|
||||
(let* ((path-at-point (dired-file-name-at-point))
|
||||
(fn-at-point (when path-at-point
|
||||
(file-relative-name path-at-point)))
|
||||
(paths (cond ((sxiv-dired-marked-files-p)
|
||||
(dired-get-marked-files))
|
||||
((derived-mode-p 'text-mode)
|
||||
(--> (buffer-substring-no-properties (point-min)
|
||||
(point-max))
|
||||
(split-string it "\n")))
|
||||
(t (directory-files default-directory))))
|
||||
(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))
|
||||
paths))
|
||||
(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)))
|
||||
;; recurse with prefix arg, or if every path is a directory
|
||||
(recurse (or prefix
|
||||
(-every? #'file-directory-p paths)))
|
||||
(recurse (or prefix
|
||||
(-every? #'file-directory-p paths)))
|
||||
;; remove directories if not running recursively
|
||||
(paths (if recurse
|
||||
paths
|
||||
(seq-remove #'file-directory-p paths)))
|
||||
(fn-at-point-index (when fn-at-point
|
||||
(->> paths
|
||||
(--find-index (equal fn-at-point it))
|
||||
(1+)
|
||||
(number-to-string))))
|
||||
(recurse (if recurse "-r" ""))
|
||||
(proc (make-process :name "sxiv"
|
||||
:buffer "sxiv"
|
||||
:command
|
||||
(append '("sxiv")
|
||||
sxiv-arguments
|
||||
(when fn-at-point-index
|
||||
(list "-n" fn-at-point-index))
|
||||
(list recurse "--")
|
||||
paths)
|
||||
:connection-type 'pipe
|
||||
:stderr "sxiv-errors")))
|
||||
(paths (if recurse
|
||||
paths
|
||||
(seq-remove #'file-directory-p paths)))
|
||||
(index (sxiv-file-at-point-index paths))
|
||||
(index (when index (number-to-string index)))
|
||||
(recurse (if recurse "-r" "")))
|
||||
(setq sxiv--directory default-directory)
|
||||
(set-process-filter proc #'sxiv-filter)))
|
||||
(message "Running sxiv...")
|
||||
(make-process :name "sxiv"
|
||||
:buffer (generate-new-buffer-name "sxiv")
|
||||
:command
|
||||
(append '("sxiv")
|
||||
sxiv-arguments
|
||||
(when index (list "-n" index))
|
||||
(list recurse "--")
|
||||
paths)
|
||||
:connection-type 'pipe
|
||||
:filter #'sxiv-filter
|
||||
:stderr "sxiv-errors")))
|
||||
|
||||
;; Local Variables:
|
||||
;; nameless-current-name: "sxiv"
|
||||
|
|
Reference in New Issue