In dired-mode
, I use an external quicklook tool on OSX called qlmanage
, which pops open a window displaying a human readable image of the file with mouse scrolling capabilities. If I hit the space bar, qlmanage
either displays the file or the process is deleted -- e.g., essentially an on/off switch.
I am having trouble figuring out how to move up or down in a dired-mode
buffer, such that qlmanage
will automatically display an image of the current line -- if an image is already being displayed -- but only do so after the previous process has successfully been killed with delete-process
. A successful kill of the qlmanage
process will return a process-exit-status
of 9
or the event string will equal killed\n
. I believe it is necessary to spawn a new process and sentinel when (= 9 (process-exit-status p)
; however, I am still confused by the nesting despite having had a few cups of coffee. I would like to have one function dired-qlmanage
that serves both purposes -- i.e., on/off with the space bar, or show next image if one is already displayed when moving up or down.
CAVEAT: The goal is to avoid having more than one active qlmanage
process at any given moment in time, which is why I am using a sentinel
.
FYI: "Deleting a running process sends a signal to terminate it (and its child processes, if any), and calls the process sentinel." [Emphasis added.] https://www.gnu.org/software/emacs/manual/html_node/elisp/Deleting-Processes.html
(require 'dired)
(require 'cl)
(defun dired-kill-last-process-named (name)
"Function initially written by @wvxvw, and revised by @lawlist."
(let (p)
(cl-loop with name-re =
(format "^%s\\(?:<\\([[:digit:]]+\\)>\\)?" (regexp-quote name))
for process in (process-list)
for pname = (process-name process)
if (string-match name-re pname)
collect (cons (string-to-number (or (match-string 1 pname) "0")) process)
into processes
finally
(let ((process (cdar (cl-sort processes '> :key 'car))))
(when (and process (get-process process))
(delete-process process)
(setq p process)))) p))
(defun dired-qlmanage ()
(interactive)
(unless (dired-kill-last-process-named "qlmanage")
(let ((current-node (dired-get-file-for-visit)))
(set-process-sentinel
(start-process "qlmanage" nil "/usr/bin/qlmanage" "-p" current-node)
(lambda (p e)
(setq e (replace-regexp-in-string "\n$" "" e))
(cond
((= 9 (process-exit-status p))
;; Should we spawn a new process with sentinel here?
(message "killed (9): %s | %s | %s" p e (process-exit-status p)))
((= 0 (process-exit-status p))
(message "finished (0): %s | %s | %s" p e (process-exit-status p)))
(t
(message "unknown (?): %s | %s | %s" p e (process-exit-status p)))))))))
(defun my-dired-previous-line (arg)
(interactive "^p")
(dired-previous-line arg)
(dired-qlmanage))
(defun my-dired-next-line (arg)
(interactive "^p")
(dired-next-line arg)
(dired-qlmanage))
(defun my-dired-quicklook ()
(interactive)
(dired-qlmanage))
(eval-after-load "dired" '(progn
(define-key dired-mode-map [down] 'my-dired-next-line)
(define-key dired-mode-map [up] 'my-dired-previous-line)
(define-key dired-mode-map (kbd "SPC") 'my-dired-quicklook)))