In The Armchair

LaTeX Forward PDF Search with Emacs

Posted in Computers by Armchair Guy on November 15, 2010

I wrote a blog post on implementing inverse PDF search with okular and emacs here.  This post is about the reverse: forward search.  That is, with point at any position in the LaTeX source while editing in emacs, a keystroke causes okular to center the corresponding portion of the PDF in its viewable area. A nice overview of LaTeX synchronization can be found here.

In the comments on the inverse search post, B. Slade suggested the procedure at http://www.bleedingmind.com/index.php/2010/06/17/synctex-on-linux-and-mac-os-x-with-emacs for forward search.  However, the instructions there require installation of AuCTeX version 11.86, while the latest version in the Ubuntu 10.04 repositories have is 11.85.

I managed to kludge a solution for the AuCTeX shipping with Ubuntu 10.04 by slightly modifying some emacs code I found here: http://www.mail-archive.com/okular-devel@kde.org/msg04913.html. Most of the work was already done by Mark Altern and earlier authors; the only change was to tell it to use the .pdf instead of the .dvi.

A note of caution.  Forward search with okular is not very convenient.  This is because okular redisplays the PDF document every time you do a forward search — with a side “contents” pane and also repositioning the PDF.  So if you’ve removed the space-hogging contents pane (by pressing F7 twice) and zoomed and positioned the PDF to your liking, doing a forward search will undo all of that.  You’ll have to remove the contents pane again and re-zoom and re-position.  This severely limits the usefulness of forward search.  There doesn’t seem to be a way around this for now.

Anyway, here are the steps.

  1. Follow instructions here to set up inverse search.
  2. Source for okular-search.el is at the end of this post.  Copy it and put it in a file called okular-search.el.
  3. In your .emacs file, add the following code:
    
    (add-to-list 'load-path "/path/to/okular-search.el")
    (require 'okular-search)
    (add-hook 'LaTeX-mode-hook (lambda () (local-set-key "\C-x\C-j" 'okular-jump-to-line)))
    (add-hook 'tex-mode-hook (lambda () (local-set-key "\C-x\C-j" 'okular-jump-to-line)))
    

That’s it. Press C-x C-j to open a new okular viewing window. Subsequent presses of C-x C-j will reposition the PDF in that okular window to correspond to whatever’s at point in emacs.

Here’s the code for okular-search.el:


;;; (X)Emacs frontend to forward search with kdvi. See the section on
;;; FORWARD SEARCH in the kdvi manual for more information on forward
;;; search, and for an explanation how to use this script. This script
;;; is a modified version of the script "xdvi-search.el" by Stefan
;;; Ulrich, version 2000/03/13. The
;;; modifications were performed by Stefan Kebekus
;;; . Tested with Emacs 20.7.1 and Xemacs 21.4.
;;;
;;; This program is free software; you can redistribute it and/or
;;; modify it under the terms of the GNU General Public License as
;;; published by the Free Software Foundation; either version 2 of the
;;; License, or (at your option) any later version.
;;;
;;; This program is distributed in the hope that it will be useful,
;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;;; General Public License for more details.
;;;
;;; You should have received a copy of the GNU General Public License
;;; along with this program; if not, write to the Free Software
;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
;;; 02110-1301, USA.
;;;
;;; Please report bugs or improvements, etc. via the "Report bug"-Menu
;;; of okular.
;;;

(defvar okular-script "okular"
  "*Name of start script for okular.")

(defun okular-jump-to-line ()
  "Call okular-script to perform a `forward search' for current file and line number.
See contents of okular-script for details.
If AucTeX is used, the value of TeX-master-file is used as filename
for the master .dvi file; else, the return value of okular-master-file-name
is used (which see)."
  (interactive)
  (save-excursion
    (save-restriction
      (widen)
      (beginning-of-line 1)
      (let* (;;; current line in file, as found in the documentation
	     ;;; of emacs. Slightly non-intuitive.
	     (current-line (format "%d" (+ 1 (count-lines (point-min) (point)))))
	     ;;; name of the `main' .tex file, which is also used as .dvi basename:
	     (master-file (expand-file-name (if (fboundp 'TeX-master-file)
					     (TeX-master-file t)
					   (okular-get-masterfile (okular-master-file-name)))))
	     ;;; .dvi file name:
	     (pdf-file (concat (file-name-sans-extension master-file) ".pdf"))
	     ;;; current source file name.
	     (filename (expand-file-name (buffer-file-name))))
	(start-process "okular"
		       "okular-output" "okular" ;;; src-args
		      ;;; args for -sourceposition:
		       "--unique" (concat "file:" pdf-file "#src:" current-line filename)
		       )))))

(defun okular-get-masterfile (file)
  "Small helper function for AucTeX compatibility.
Converts the special value t that TeX-master might be set to
into a real file name."
  (if (eq file t)
      (buffer-file-name)
    file))

(defun okular-master-file-name ()
  "Emulate AucTeX's TeX-master-file function.
Partly copied from tex.el's TeX-master-file and TeX-add-local-master."
  (if (boundp 'TeX-master)
      TeX-master
    (let ((master-file (read-file-name "Master file (default this file): ")))
      (if (y-or-n-p "Save info as local variable? ")
	  (progn
	    (goto-char (point-max))
	    (if (re-search-backward "^\\([^\n]+\\)Local Variables:" nil t)
		(let* ((prefix (if (match-beginning 1)
				   (buffer-substring (match-beginning 1) (match-end 1))
				 ""))
		      (start (point)))
		  (re-search-forward (regexp-quote (concat prefix "End:")) nil t)
		  (if (re-search-backward (regexp-quote (concat prefix "TeX-master")) start t)
		      ;;; if TeX-master line exists already, replace it
		      (progn
			(beginning-of-line 1)
			(kill-line 1))
		    (beginning-of-line 1))
		  (insert prefix "TeX-master: " (prin1-to-string master-file) "\n"))
	      (insert "\n%%% Local Variables: "
;;; mode is of little use without AucTeX ...
;;;		      "\n%%% mode: " (substring (symbol-name major-mode) 0 -5)
		      "\n%%% TeX-master: " (prin1-to-string master-file)
		      "\n%%% End: \n"))
	    (save-buffer)
	    (message "(local variables written.)"))
	(message "(nothing written.)"))
      (set (make-local-variable 'TeX-master) master-file))))

(provide 'okular-search)
Advertisements

3 Responses

Subscribe to comments with RSS.

  1. B.Slade said, on December 30, 2010 at 9:18 pm

    Sometime in the past week whatever I had working before with forward search broke. I don’t know when, I don’t know how.

    I implemented the hack you give here. Many thanks for that.

    Question: why bind to C-x C-j? Why not C-c C-v?

    On the problems you mention with the contents panel/F7 annoyance etc.:
    (1) I had exactly the same problem with the bleedingmind procedure I was using before. But…:

    (2) The problem is limited (both with the old bleedingmind method and with your new hack) to documents which use the hyperref package. So I think it’s a limitation/quirk of Okular.

    • Armchair Guy said, on December 31, 2010 at 12:59 pm

      @B.Slade

      Good to hear this version is working for you! I found C-x C-j in the code I tweaked; I just didn’t change it is all. C-c C-v might make more sense.

      I hadn’t realized the connection with the hyperref package — all my files use it. Thanks for the clarification.

  2. beslayed said, on July 27, 2011 at 4:01 pm

    Have you updated to TeXlive 2011 yet? I’m having difficulty with forward search because of changes to synctex. Have asked about these various places (e.g. http://lists.gnu.org/archive/html/auctex/2011-07/msg00007.html ); haven’t had much luck in getting a response.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: