9

I've run into a problem viewing pdf documentation files with AucTex. I use pdf-tools to view PDF files from within Emacs, and I've set emacsclient -n as my default pdf-viewer (via xdg-mime on Debian Linux). This works fine in most circumstances, but it breaks the (Tex-documentation-texdoc ...) function of Auctex (C-c ?).

I've narrowed the problem down to a single line of code. When I try to view the documentation for the listings package, TeX-documentation-texdoc turns this into the following sexp:

(shell-command-to-string "texdoc --view  listings")

texdoc in turn calls emacsclient to actually open the file (based on how I've configured my desktop via xdg). However, at this point, the Emacs hangs and I need to quit (C-g) to get control back. After that, no new pdf is opened. The same thing happens if I try to call emacsclient directly:

(shell-command-to-string "emacsclient -n tmp.pdf")

Both commands work at the command line (i.e., emacsclient -n tmp.pdf and texdoc --view listings.

My question is, in an instance like this, how do I call emacsclient from within Emacs? (and I know I could just open the pdf file with find-file; that's not an option here as I need to call an external process (texdoc) to find the file, and that process then invokes emacsclient).

  • Why not just use texdoc -M --list listings to find the file, and then use find-file? – suvayu Dec 22 '16 at 18:25
  • @suvayu Just convenience. Another alternative is switching to a terminal to call texdoc --view and then switching back to Emacs when it opens the file. But I think there should be a way to do this in a single step from Emacs? – Tyler Dec 22 '16 at 18:31
  • 1
    Can (async-shell-command "emacsclient -n tmp.pdf") solve the problem? – Name Dec 22 '16 at 20:49
  • 1
    @Name interesting - (async-shell-command "emacsclient -n tmp.pdf") works, but not (async-shell-command "texdoc --view listings") doesn't. So that's a useful clue. – Tyler Dec 22 '16 at 21:13
  • 1
    Does C-u C-c ? work? It first shows the list of docs related to the package, then opens the viewer with (call-process "texdoc" nil 0 nil "--just-view" doc). – giordano Dec 23 '16 at 16:19
5

The solution is to run texdoc within an asynchronous process.

The best way to do that is probably to use start-file-process instead of shell-command-to-string (which is a handy function for quick&dirty code when it's more expedient to write a little shell script than the corresponding Elisp code, but is otherwise better avoided in my experience).

But it will require substantial changes to the surrounding code, since start-file-process does not return the process's output directly, instead it lets you indicate in which buffer to place the output and then you have to use set-process-sentinel to a callback function that fetches the output from that buffer and does "whatever needs to be done with it" when the command finishes.

  • In the specific case of running texdoc in AUCTeX I find the use of a sentinel a bit of an overkill, since this isn't a fundamental feature (like it is the opening of the viewer for the output document, in which case we do use the sentinel). – giordano Dec 24 '16 at 1:18
  • I have no idea why the "-to-string" function was used, so I don't know what is done with the command's output. If this output is needed (as suggested by the use of ...-to-string), then an async solution will either need a process-filter or a proces-sentinel. If not, then the code can maybe use something like (shell-command "texdoc --view listings &"). – Stefan Dec 24 '16 at 1:37
  • It's explained in the comments to TeX-documentation-texdoc: the ...-to-string variant is used to show to users possible error messages (for example when no documentation is found). In addition, texdoc nonexistingpackage returns 0, but the sentinel may be used to parse the output. – giordano Dec 24 '16 at 1:42
  • Then a sentinel seems to be the best option. – Stefan Dec 24 '16 at 4:38
  • I can't find an invocation of start-file-process that actually works here. (start-file-process "texdoc" "*texdoc*" "texdoc" "--view" "listings") creates the buffer *texdoc*, to which is inserted "Process texdoc finished", and the pdf never opens. The same thing happens when I set the xdg-mime pdf viewer to evince as well. – Tyler Jan 2 '17 at 14:35
1

If you only need to feed back a request to Emacs, without waiting for an answer, then you can run emacsclient in the background. Under Unix-style OSes (Linux, macOS, Cygwin, …):

emacsclient … &

Under native Windows:

start emacsclient …
  • Sure, but in this particular case I need to call a program (texdoc) that then calls (emacsclient). The additional level of redirection is causing problems. – Tyler Jan 2 '17 at 14:05
  • @Tyler texdoc is asynchronous (i.e. you aren't waiting for it to complete), isn't it? So you could apply the same principle: run texdoc … & as the shell command. – Gilles Jan 2 '17 at 14:38
  • We tried that up in the comments under my question; it works when calling emacsclient directly, but not when calling texdoc. – Tyler Jan 2 '17 at 14:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.