Hook into man output - emacs

I want to hook into man output (from man.el) but the commands run asynchronously. Does anyone know how to set a process sentinel for the man command, or an alternative to hook the function?
For example, how can I replace the sit-for in the following snippet with a callback to run when man finishes its processing?
(defun get-some-help (cmd &optional num)
(let ((buf (man (concat (number-to-string (or num 3)) " " cmd))))
(sit-for 0.1) ;how to replace this?
(unless (buffer-live-p buf)
(message "Do something else instead"))))
(get-some-help "wait4")

Related

Emacs: what is the conventional way of receiving output from a process?

My aim is to get the output from a process in Emacs.
For example, M-x run-python gives me a python shell *Python* that I can send python code to. If I send print "hello world" to *Python*, I hope Emacs can know the result once the execution is finished and echo it in the mini-buffer.
Is it possible to add something like a callback?
Thanks to the comments from #lawlist , I solved my problem by creating the following filter function and assigning it to the process (*MozRepl* in my case) with (set-process-filter (get-buffer-process "*MozRepl*") 'moz-controller-repl-filter)
(defun moz-controller-repl-filter (proc string)
"Filter function of *MozRepl*.
It gets the useful output of *MozRepl*, store it in `moz-controller-repl-output` and `kill-ring`"
(when (buffer-live-p (process-buffer proc))
(unless (string= string "repl> ") ; ignore empty output (page up, page down, etc)
(setq moz-controller-repl-output
(replace-regexp-in-string "\"\\(.+\\)\"\nrepl> " "\\1" string))
(kill-new moz-controller-repl-output) ; append to kill-ring
(message moz-controller-repl-output) ; show the copied content in echo area
)
(with-current-buffer (process-buffer proc)
(let ((moving (= (point) (process-mark proc))))
(save-excursion
;; Insert the text, advancing the process marker.
(goto-char (process-mark proc))
(insert string)
(set-marker (process-mark proc) (point)))
(if moving (goto-char (process-mark proc)))))))

Window scrolling after start-process and pop-to-buffer

I'm trying to write a function that compiles some code, and if the compilation succeeds, it spawns the process and opens its output in a new window. The compilation bit works fine, but there's something weird going on with the second part. I wrote some code that looks like this:
(defun test-function ()
(with-current-buffer (get-buffer-create "*output*")
(erase-buffer)
(start-process "echo" (current-buffer) "echo" "hi")
(pop-to-buffer (current-buffer))))
This code almost works, but when it runs, the top of the screen seems to sit right below the actual output of the program. So, once echo quits, the screen looks like
Process echo finished
And scrolling up one line gives (the expected)
blah
Process echo finished
Is there a way to get it to start at the actual top of the buffer? I've tried things like scroll-up and goto-char before and after starting the process, but they don't seem to affect anything. From some other sources, it seems like I could attach a sentinel to the process and have it scroll up when there's output, but that seems like overkill just to scroll up at the beginning.
A bit of a hack, but for me this works:
(insert "\n")
(start-process ...
It looks like there is an \n before Process built into process.c. Perhaps someone can suggest for you how to modify this after Emacs has already been built -- if not, a custom build seems like an extreme solution.
Of course, you could use elisp code to go up and delete the hard return after the fact.
Searching 5342 files for "\nprocess"
/Users/HOME/Desktop/emacs-trunk/src/process.c:
6405 tem = BVAR (current_buffer, read_only);
6406 bset_read_only (current_buffer, Qnil);
6407: insert_string ("\nProcess ");
6408 { /* FIXME: temporary kludge. */
6409 Lisp_Object tem2 = p->name; Finsert (1, &tem2); }
/Users/HOME/Desktop/emacs-trunk/lisp/man.el:
1304 (substring msg 0 eos) msg))))
1305 (goto-char (point-max))
1306: (insert (format "\nprocess %s" msg))))
1307 ))
1308 (if delete-buff
/Users/HOME/Desktop/emacs-trunk/lisp/progmodes/sql.el:
3944 (if (and (eq (current-buffer) sql-buffer)
3945 (not buffer-read-only))
3946: (insert (format "\nProcess %s %s\n" process event))
3947 (message "Process %s %s" process event)))
3948
/Users/HOME/Desktop/emacs-trunk/lisp/shell.el:
641 (when (buffer-live-p buf)
642 (with-current-buffer buf
643: (insert (format "\nProcess %s %s\n" process event))))))
644
645 ;;;###autoload
4 matches across 4 files
Fixing it with a process sentinel:
(defun recenter-temp-buffer (process event)
(pop-to-buffer (process-buffer process)) (recenter-top-bottom))
(with-output-to-temp-buffer "test-buffer"
(set-process-sentinel
(start-process "test-process" "test-buffer" "echo" "hello")
'recenter-temp-buffer))
Note that the sentinel will call (recenter-top-bottom) on every status change, which may not be what you want.

Elisp sentinel on process waiting for input

I made a function, compiling the current latex file:
;close the *async pdflatex* window, when pdflatex finishes
(defun latex-sentinel (process event)
(message event)
(cond ((string-match-p "finished" event)
(progn
(kill-buffer "*async pdflatex*")
(message "pdflatex done")
(delete-other-windows)))))
(defun latex-compile ()
"Runs pdflatex on current file"
(interactive)
(let* ((file-name (shell-quote-argument (buffer-file-name)))
(process (start-process-shell-command
"pdflatex"
"*async pdflatex*"
(concat "pdflatex " file-name))))
(set-process-sentinel process 'latex-sentinel)
(setq new-window (split-window-below 40))
(set-window-buffer new-window "*async pdflatex*")
(other-window 1)))
(add-hook 'LaTeX-mode-hook (lambda ()
(define-key LaTeX-mode-map (kbd "<f2>") 'latex-compile)))
When there is an error, while compiling, pdflatex freezes, and I see this:
My current workflow:
Scroll up to see the error
kill-this-buffer - to kill pdflatex process
delete-window - to close *async pdflatex* window and get back to editing.
Is it possible to track, that the process has stopped and is waiting for user input? My current sentinel activates only on "finished" event. So I could automate my current workflow.
[ #Thomas: you don't need AUCTeX for that. The builtin latex-mode also provides a C-c C-c binding for that task. ]
In general, detecting that a process is "waiting for me" is difficult/impossible (at best you might monitor the process's CPU usage and if it's been 0% for a while you can decide that it's probably waiting for you, but even doing that is tricky since you need to find the proper OS-process to monitor and then use system-dependent operations to get the CPU usage). latex-modes usually "solve" this by passing \nonstopmode\input on pdflatex's command line.
I had the same difficulty. The following seems to be OK.
(defun latex-compile()
(interactive)
(save-buffer)
(set 'tex-to-pdf "pdflatex -interaction=nonstopmode")
(set 'file-name (shell-quote-argument (buffer-file-name)))
(set 'comm1 (concat tex-to-pdf " " file-name ))
(set-process-sentinel
(start-process-shell-command "latex-compile"
"*async latex-compile*"
comm1)
'tex-to-pdf-sentinel))
;;;
(defun tex-to-pdf-sentinel (process event)
(cond
( (string-match-p "finished" event)
(message "latex-compile complete"))
( (string-match-p "\\(exited\\|dumped\\)" event)
(message "error in latex-compile"))
))
I realize use of global variables with set is not advisable; this is just a minimal example.
You can set up a second sentilel when the first completes, e.g. so that a viewer opens to display the the .pdf output, or you want to ensure bibtex runs each time. This may save on repeated calls to C-c C-c in latex mode.

Running command line commands in Emacs, and receiving their output

I want to run a set of command line commands in a loop within emacs, with the loop stopping when the user taps a key.
This is in order to see an ascii 'video' appear in Emacs, which stops when you press a key.
I thought it would be fun to have image-to-ascii bit of text as a comment (with the image coming from my mac's camera).
I use imagesnap to take the camera image, and jp2a to convert it to ascii. I think imagesnap is mac only. Here's the code I have so far:
(defun ascii-video-comment ()
"Makes video comment, requires imagemagick, jp2a, imagesnap"
(interactive)
(shell-command "imagesnap -q ~/Desktop/emacs-snap.jpg")
(insert (shell-command-to-string "jp2a --width=48 ~/Desktop/emacs-snap.jpg"))
(shell-command "rm ~/Desktop/emacs-snap.jpg")
)
This just takes a snap from the camera, converts to ascii, inserts it into my file, and places the cursor after.
Like I say, I would like it to keep looping, giving the appearance of a slow ascii video, until i tap a key to select the current 'frame'.
Is this even possible?
EDIT
This is my current code, which I'm fairly happy with. It loops 20 times, and you can choose the current image by cancelling (C-g). Things seem to go wrong when you do it a second time though.
(defun ascii-video-comment ()
"Makes video comment, requires imagemagick, jp2a, imagesnap"
(interactive)
(cl-loop repeat 20 do
(shell-command "imagesnap -q ~/Desktop/ascii-video-comment.jpg")
(cua-set-mark)
(insert (shell-command-to-string "jp2a --width=120 ~/Desktop/ascii-video-comment.jpg"))
(shell-command "rm ~/Desktop/ascii-video-comment.jpg")
(comment-region (mark) (point))
(cua-set-mark)
(pop-global-mark)
(sit-for 0.1)
(undo)
)
)
On your EDIT "final code": don't use interactive commands in a lisp program: you code becomes brittle and inefficient.
E.g., the doc string for shell-command (C-h f shell-command RET) explicitly states:
In Elisp, you will often be better served by calling call-process or
start-process directly, since it offers more control and does not
impose the use of a shell (with its need to quote arguments)
Also, use delete-file instead of (shell-command "rm ...").
Do not use cua-set-mark, pop-global-mark, and, especially, undo in programs.
Bind a variable instead:
(let ((beg (point)))
(call-process "jp2a" nil t t "--width=120" "~/Desktop/ascii-video-comment.jpg")
(comment-region beg (point))
(sit-for 0.1)
(delete-region beg (point)))
AFAIR, Emacs doesn't provide API to poll for pending events, so there are two options. UPD: disregard that, should've read the manual beforehand, Emacs does provide API to poll for pending events:
(defun start-printing-messages-2 ()
(interactive)
(while (not (input-pending-p))
(loop-body-function)
(redisplay 'force)))
If you want a delay between command execution, there's sit-for for you:
(defun start-printing-messages-3 ()
(interactive)
(while (sit-for 0.05)
(loop-body-function)))
If you want that delay to start counting from beginning of loop body rather than its end (if your loop body might take significant time), you need to set up full-fledged timer execution: you basically run a function in a timer and add a post-command-hook that will kill that timer:
(defvar loop-run-count 0)
(defvar loop-timer-object nil)
(defun loop-body-function ()
(setq loop-run-count (1+ loop-run-count))
(message "The function was run %s times" loop-run-count))
(defun stop-printing-messages ()
(when loop-timer-object
(cancel-timer loop-timer-object)
(remove-hook 'post-command-hook 'stop-printing-messages)))
(defun start-printing-messages ()
(interactive)
(setq loop-run-count 0)
;; post-command-hook is added via timer too, because otherwise it
;; might get called right after this function completes and this
;; would kill the timer that didn't even start yet.
;; get killed right after creation.
(run-with-timer
0.01 nil (lambda ()
(add-hook 'post-command-hook 'stop-printing-messages)))
(setq loop-timer-object
(run-with-timer nil 0.01 'loop-body-function)))
You can wait for input with while-no-input and sit-for.
For the use case you describe, sit-for is what you need.
Note that you should combine the two shell calls with && or make a shell
script.
Here is a toy command that does what you need, but only flashing random numbers.
(defun flash-me ()
"flash random number until you press a key"
(interactive)
(let ((beg (copy-marker (point)))
(end (copy-marker (point) t)))
(loop do (progn
(delete-region beg end)
(insert (shell-command-to-string "echo $RANDOM")))
while (sit-for 1))
(set-marker beg nil)
(set-marker end nil)))

emacs extension to do system call, sleep, then reload buffer

I want to write an emacs extension such that when I do M-x, b, k, e the following things occur:
a system/shell call is executed where the last argument is the full path to the file of the buffer that is currently selected.
wait for the command to terminate or sleep for 3 seconds if it isn't possible to block for the return of a system call.
reload/restore the current buffer
How is this done?
This should be close:
(defun bke ()
(interactive)
(let ((buf-name (buffer-file-name)))
(with-temp-buffer
(shell-command (concat "your-command-here " buf-name) t))
(revert-buffer t t t))
Here you go (at least two of three)
1) Shell call with last argument
(defun b ()
(interactive)
(shell-command (concat (read-string "$ ") " " buffer-file-name)))
2) I do not know, sorry.
3) Reload file.
(defun e ()
(interactive)
(revert-buffer t t t))
Other than the key binding portion, this question is the same as: elisp: call command on current file.