Compare commits

...

29 Commits

Author SHA1 Message Date
contrapunctus 0449244925 Update homepage 2022-05-11 23:48:08 +05:30
contrapunctus 6291d3b7b1 Fix regression in marking files in Dired 2022-05-11 23:43:11 +05:30
contrapunctus f286ce396d Fix regression in opening the file at point 2022-05-11 23:35:07 +05:30
contrapunctus 61f91e2464 Add new ideas 2022-05-11 21:48:05 +05:30
contrapunctus 9ff8f6d8e9 Try to match the order of files as displayed in the Dired buffer 2022-05-11 21:41:50 +05:30
contrapunctus 14057b156d doc: make Commentary relevant to users 2021-07-14 00:15:25 +05:30
contrapunctus 028409c3a9 doc(README): add Liberapay and MELPA badges 2021-07-13 23:45:21 +05:30
contrapunctus a531a7596e Use unique buffer name for process output 2021-05-14 14:48:58 +05:30
contrapunctus 3544c6b3a4 Open file at point from text files too 2021-04-06 19:10:10 +05:30
contrapunctus b8becd786c Extend TODO 2021-04-06 17:59:08 +05:30
contrapunctus ded8989e82 Add workaround for possible Emacs issue (see #9) 2020-09-03 10:03:27 +05:30
contrapunctus 678b411a8f TODO - add #10 for startup speed 2020-09-03 09:40:49 +05:30
contrapunctus b74f2c59a7 TODO - add example for #9 2020-08-04 03:21:28 +05:30
contrapunctus 9eb6a121bf Bump versions 2020-08-03 20:01:24 +05:30
contrapunctus 5b08ed004e README - reword Usage 2020-08-03 19:59:09 +05:30
contrapunctus 247cb7bdcb Rewrite sxiv-insert-subdirs using loop; try to fix error (issue #1) 2020-08-03 19:58:38 +05:30
contrapunctus 086bc5ae97 Compress code a little 2020-08-03 19:37:22 +05:30
contrapunctus a23d1639f8 Rename license files 2020-08-03 19:33:28 +05:30
contrapunctus f1a030c538 Prevent crashes in certain situations (todo #9) 2020-05-08 21:50:39 +05:30
contrapunctus 00861f086e Refactor (thanks, Steve Purcell!) 2020-03-29 11:34:55 +05:30
contrapunctus dae46e6f58 Add Cask file, require dired 2020-03-26 20:03:28 +05:30
contrapunctus ab89cd2d20 Add commentary, reorganize code 2020-03-25 13:49:18 +05:30
contrapunctus b8b53c104e Update homepage 2020-03-25 13:27:59 +05:30
contrapunctus efd484fc02 Bump versions 2020-03-25 11:44:56 +05:30
contrapunctus 7972b8f1a5 Add TODO item 2020-03-25 11:41:28 +05:30
contrapunctus cf4aa28c29 Add license information as docstrings 2020-03-25 11:40:46 +05:30
contrapunctus 40d5c41a98 Show message when starting sxiv 2020-02-10 18:17:58 +05:30
contrapunctus d6abe6645b Marking files now works recursively, too. 2020-01-14 12:37:37 +05:30
contrapunctus eef2f8bea9 Fix error when point is on a directory
The changes to fn-at-point-index weren't strictly necessary - the
error was already fixed with the change to fn-at-point - but I thought
it best to play it safe.
2020-01-14 11:27:52 +05:30
7 changed files with 207 additions and 83 deletions

View File

@ -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

9
Cask Normal file
View File

@ -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")

View File

@ -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

32
TODO.md Normal file
View File

@ -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.

View File

View File

201
sxiv.el
View File

@ -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"