Elisp sentinel on process waiting for input - emacs

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.

Related

emacs function after asynchonous command

I currently use emacs for making and editing LaTeX documents. When compiling, I use an external program to compile into pdf. Right now, with the following code in my .emacs file, emacs will start compiling the document into a pdf whenever I save the file.
(defun auto-compile-latex ()
(save-window-excursion
(async-shell-command (format "cd %s; scons -u" default-directory))))
(add-hook 'LaTeX-mode-hook '(lambda ()
(add-hook 'after-save-hook 'auto-compile-latex nil 'make-it-local)))
I prefer this over M-x compile, because I am more in the habit of saving, and it launches in the background, allowing me to continue working. However, I do not get a prominent notification when the compilation process finishes.
Ideally, I would want to run the following function whenever a compilation process finishes.
(defun latex-compilation-status (exit-code)
(if (/= exit-code 0)
(setq mode-name (propertize mode-name 'face 'font-lock-warning-face))
(setq mode-name (propertize mode-name 'face 'mode-line-highlight))))
That way, I can have the color in the mode line automatically change depending on whether the compilation was successful or not. However, looking through the emacs documentation, I have not found any mention of a hook that gets run after async-shell-command completes. I know that there is the message in the minibuffer stating the exit status of the subprocess, but if I am typing at the time, it is often hard to notice.
Alternatively, I could wait for the shell command to complete, then change the color immediately. However, this then makes the entirety of emacs freeze while compiling, which is not desired.
How would I go about having this indication applied at the end of the compilation, without having emacs freeze during the process?
You should try the command async-start from https://github.com/jwiegley/emacs-async
Thank you.
I ended up getting it using a modified version of lawlist's code.
This now has changes the color when starting to compile,
then changes it again to indicate success or failure.
;Automatically compile any latex documents when saved.
(defun auto-compile-latex ()
(setq mode-name (propertize mode-name 'face 'font-lock-string-face))
(set-process-sentinel
(start-process-shell-command "latex-compile" "latex-compile"
(format "cd %s; scons -u" default-directory))
'latex-compile-sentinel))
;Change the color after compilation. Still need to find the right hook to add it to.
(defun latex-compile-sentinel (process event)
(if (string-equal event "finished\n")
(setq mode-name (propertize mode-name 'face 'mode-line-highlight))
(setq mode-name (propertize mode-name 'face 'font-lock-warning-face))))
;Hooks for latex-mode
(add-hook 'LaTeX-mode-hook '(lambda ()
(add-hook 'after-save-hook 'auto-compile-latex nil 'make-it-local)))
As an aside, the emacs-async package did not work for this use.
I assume that this is because emacs-async starts the secondary functions in a separate process,
with some of the variables not propagated back to the parent process.
Here is another option using set-process-sentinel based upon a prior helpful answer by Francesco. Please do be careful, however, about using a let binding to define a start-process (which [in my lay opinion] is a definite "no no") because that would cause the process to begin immediately before its time. [FYI: Nicolas has gotten me out of quite a few jams in the past, so please be sure to take a good hard look at his solution also.]
Emacs: if latexmk finishes okay, then show pdf, else display errors
You would just add your function to the last part of the function dealing with success -- i.e., (when (= 0 (process-exit-status p)) . . .:
(defun latexmk ()
".latexmkrc contains the following entries (WITHOUT the four backslashes):
$pdflatex = 'pdflatex -file-line-error -synctex=1 %O %S && (cp \"%D\" \"%R.pdf\")';
$pdf_mode = 1;
$out_dir = '/tmp';"
(interactive)
(setq tex-file buffer-file-name)
(setq pdf-file (concat "/tmp/" (car (split-string
(file-name-nondirectory buffer-file-name) "\\.")) ".pdf"))
(setq line (format "%d" (line-number-at-pos)))
(setq skim "/Applications/Skim.app/Contents/SharedSupport/displayline")
(setq tex-output (concat "*" (file-name-nondirectory buffer-file-name) "*") )
(setq latexmk "/usr/local/texlive/2012/texmf-dist/scripts/latexmk/latexmk.pl")
(setq latexmkrc "/Users/HOME/.0.data/.0.emacs/.latexmkrc")
(if (buffer-modified-p)
(save-buffer))
(delete-other-windows)
(set-window-buffer (split-window-horizontally) (get-buffer-create tex-output))
(with-current-buffer tex-output (erase-buffer))
(set-process-sentinel
(start-process "compile" tex-output latexmk "-r" latexmkrc tex-file)
(lambda (p e) (when (= 0 (process-exit-status p))
(start-process "displayline" nil skim "-b" line pdf-file tex-file)
(switch-to-buffer (get-file-buffer tex-file))
(if (get-buffer-process (get-buffer tex-output))
(process-kill-without-query (get-buffer-process (get-buffer tex-output))))
(kill-buffer tex-output)
(delete-other-windows)))))
You could also arrange for your auto-compile-latex to run compile.

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

How to automatically kill buffer on terminal process exit in Emacs

How can I automatically kill the terminal buffer when the process associated with it ends.
I found much simpler method, define an advice on term-handle-exit
(defadvice term-handle-exit
(after term-kill-buffer-on-exit activate)
(kill-buffer))
I found that I can use process sentinels for that and set it using term-exec-hook
(add-hook 'term-exec-hook (lambda ()
(let* ((buff (current-buffer))
(proc (get-buffer-process buff)))
(lexical-let ((buff buff))
(set-process-sentinel proc (lambda (process event)
(if (string= event "finished\n")
(kill-buffer buff))))))))

How to automatically do org-mobile-push org-mobile pull in emacs

Since I am using org-mode to track my todo list in emacs, I like the iPhone app: MobileOrg, with it, I can access my todo list all day.
But here's the problem:
I have to manually org-mobile-push my changes from local file to mobile phone through dropbox, and org-mobile-pull the changes made by phone back.
How to make that automatically? Like adding some recipes in dotemacs file.
Add these two lines to dot emacs file:
(add-hook 'after-init-hook 'org-mobile-pull)
(add-hook 'kill-emacs-hook 'org-mobile-push)
With them, it automatically pulls the changes on emacs startup, and pushes the changes before emacs exits.
-- Update
If you never exit your Emacs, this solution might not work for you. So, another solution using idle timer
;; moble sync
(defvar org-mobile-sync-timer nil)
(defvar org-mobile-sync-idle-secs (* 60 10))
(defun org-mobile-sync ()
(interactive)
(org-mobile-pull)
(org-mobile-push))
(defun org-mobile-sync-enable ()
"enable mobile org idle sync"
(interactive)
(setq org-mobile-sync-timer
(run-with-idle-timer org-mobile-sync-idle-secs t
'org-mobile-sync)));
(defun org-mobile-sync-disable ()
"disable mobile org idle sync"
(interactive)
(cancel-timer org-mobile-sync-timer))
(org-mobile-sync-enable)
I just found out it is same as below answer, so, if you prefer the idle timer solution, please upvote tkf's answer.
I have something like this in my Emacs setting to do push and pull when I am away from computer.
(defvar my-org-mobile-sync-timer nil)
(defvar my-org-mobile-sync-secs (* 60 20))
(defun my-org-mobile-sync-pull-and-push ()
(org-mobile-pull)
(org-mobile-push)
(when (fboundp 'sauron-add-event)
(sauron-add-event 'my 3 "Called org-mobile-pull and org-mobile-push")))
(defun my-org-mobile-sync-start ()
"Start automated `org-mobile-push'"
(interactive)
(setq my-org-mobile-sync-timer
(run-with-idle-timer my-org-mobile-sync-secs t
'my-org-mobile-sync-pull-and-push)))
(defun my-org-mobile-sync-stop ()
"Stop automated `org-mobile-push'"
(interactive)
(cancel-timer my-org-mobile-sync-timer))
(my-org-mobile-sync-start)
Alternative is to put the following in cron job
(I found this here https://github.com/matburt/mobileorg-android/wiki/Scripting/):
emacs --batch --load ~/.emacs --eval "(org-mobile-pull)" --eval "(org-mobile-push)"
This code is taken from http://kenmankoff.com/2012/08/17/emacs-org-mode-and-mobileorg-auto-sync/, with a couple of details changed. You need to configure the variables in the beginning. This code will
Check every 30s whether MobileOrg has synced, and if so
Pull from MobileOrg.
Push to MobileOrg.
This is necessary to update the agenda views in MobileOrg.
With this behavior, you can be away from your computer, update some things in MobileOrg, sync, wait 30 seconds, sync again, and your mobile agenda view will be updated.
Whenever an org file is saved
Check whether the saved org file is supposed to be synced with MobileOrg, and if so
Wait for the user to become idle
Push to MobileOrg
Code for your .emacs file:
(require 'org-mobile)
;; Configure these two variables
(setq org-mobile-inbox-for-pull "~/Dropbox/org/mobile.org"
org-mobile-directory "~/Dropbox/MobileOrg")
(require 'gnus-async)
;; Define a timer variable
(defvar org-mobile-push-timer nil
"Timer that `org-mobile-push-timer' used to reschedule itself, or nil.")
;; Push to mobile when the idle timer runs out
(defun org-mobile-push-with-delay (secs)
(when org-mobile-push-timer
(cancel-timer org-mobile-push-timer))
(setq org-mobile-push-timer
(run-with-idle-timer
(* 1 secs) nil 'org-mobile-push)))
;; After saving files, start an idle timer after which we are going to push
(add-hook 'after-save-hook
(lambda ()
(if (or (eq major-mode 'org-mode) (eq major-mode 'org-agenda-mode))
(dolist (file (org-mobile-files-alist))
(if (string= (expand-file-name (car file)) (buffer-file-name))
(org-mobile-push-with-delay 10))))))
;; watch mobileorg.org for changes, and then call org-mobile-pull
(defun org-mobile-install-monitor (file secs)
(run-with-timer
0 secs
(lambda (f p)
(unless (< p (second (time-since (elt (file-attributes f) 5))))
(org-mobile-pull)
(org-mobile-push)))
file secs))
(defvar monitor-timer (org-mobile-install-monitor (concat org-mobile-directory "/mobileorg.org") 30)
"Check if file changed every 30 s.")
you can also push right after saving a note, like this:
(add-hook
'after-save-hook
(lambda ()
(if (string= buffer-file-name "<path to my notes.org>")
(org-mobile-push)
)
))
I use this elisp code from gist on my init.el and it works pretty well, except it doesn't have org-mobile-pull built in.
As a side solution, similar to Sandeep C's
;; for Emacs 24.3.1 insert next line
(require 'cl)
;; automatically org-mobile-push on save of a file
(add-hook
'after-save-hook
(lambda ()
(let (
(org-filenames (mapcar 'file-name-nondirectory (directory-files org-directory))) ; list of org file names (not paths)
(filename (file-name-nondirectory buffer-file-name)) ; list of the buffers filename (not path)
)
(if (find filename org-filenames :test #'string=)
(org-mobile-push)
)
)
)
)
I opted to simply push when saving, so I added this to my emacs init file:
(defun org-mobile-push-on-save ()
"Used in `after-save-hook'."
(when (memq this-command '(save-buffer save-some-buffers))
(org-mobile-push)))
(add-hook 'org-mode-hook
(lambda ()
(add-hook 'after-save-hook 'org-mobile-push-on-save nil 'make-local)))
In a nutshell, it adds an after-save-hook to org-mode buffers.
More info on the code:
https://emacs.stackexchange.com/a/14476/12694
https://stackoverflow.com/a/6141681/45881
For auto-pull, a timer as in other answers is probably a good way.

Emacs - Can't get buffer-offer-save working

I would like to have Emacs ask me whether I want to save a modified buffer, when that buffer is not associated with a file. To open a new buffer (not visiting a file) I have the following function in my .emacs file:
;; Creates a new empty buffer
(defun new-empty-buffer ()
"Opens a new empty buffer."
(interactive)
(let ((buf (generate-new-buffer "untitled")))
(switch-to-buffer buf)
(funcall (and default-major-mode))
(setq buffer-offer-save t)))
I thought setting "buffer-offer-save" to something not nil would made the trick. But whenever I kill the buffer with "kill-this-buffer", it gets instantly killed without asking anything.
This happens on GNU Emacs 23.1.1
Any ideas?
Thanks,
W
Edited to add use of buffers-offer-save. Note: the variable buffer-offer-save is only used upon exiting Emacs.
You can start with this code and customize it to what you want:
(add-to-list 'kill-buffer-query-functions 'ask-me-first)
(defun ask-me-first ()
"prompt when killing a buffer"
(if (or buffer-offer-save
(eq this-command 'kill-this-buffer)
(and (buffer-modified-p) (not (buffer-file-name))))
(y-or-n-p (format "Do you want to kill %s without saving? " (buffer-name)))
t))
Upon further reflection, that is a bit heavy-handed because you get prompted for all buffers that get killed, and there are often lots of temporary buffers that Emacs uses. If you just want to be prompted when you try to interactively kill a buffer (that isn't associated with a file).
You can use this advice which only prompts you when you're interactively trying to kill a buffer:
(defadvice kill-buffer (around kill-buffer-ask-first activate)
"if called interactively, prompt before killing"
(if (and (or buffer-offer-save (interactive-p))
(buffer-modified-p)
(not (buffer-file-name)))
(let ((answ (completing-read
(format "Buffer '%s' modified and not associated with a file, what do you want to do? (k)ill (s)ave (a)bort? " (buffer-name))
'("k" "s" "a")
nil
t)))
(when (cond ((string-match answ "k")
;; kill
t)
((string-match answ "s")
;; write then kill
(call-interactively 'write-file)
t)
(nil))
ad-do-it)
t)
;; not prompting, just do it
ad-do-it))
Modifying 'new-empty-buffer seems to make it work as I intended with Trey's defadvice.
;; Creates a new empty buffer
(defun new-empty-buffer ()
"Opens a new empty buffer."
(interactive)
(let ((buf (generate-new-buffer "untitled")))
(switch-to-buffer buf)
(funcall (and default-major-mode))
(put 'buffer-offer-save 'permanent-local t)
(setq buffer-offer-save t)))
This makes buffer-offer-save permanent local in our new buffer, so it won't get killed with the rest of the local variables when switching major modes.
buffer-offer-save asking on exiting Emacs but not on closing a buffer manually doesn't make sense, so why not “enlarge” its responsibilities?
(defadvice kill-buffer (around kill-buffer-ask activate)
"If `buffer-offer-save' is non-nil and a buffer is modified,
prompt before closing."
(if (and buffer-offer-save (buffer-modified-p))
(when (yes-or-no-p "The document isn't saved. Quit? ")
ad-do-it)
ad-do-it))
It will not prompt if untitled buffer is newly created. It will not prompt if you use kill-buffer from Elisp. It will not prompt on Emacs system buffers like *Messages*. But it will prompt if you created an empty buffer and wrote something in it.
See also my answer on creating an empty buffer.