LaTeX and PDFSync

From SkimWiki

Jump to: navigation, search

Skim offers powerful integration with LaTeX.

Contents

Reload updated PDF files

Skim can recognize when the PDF file is updated on disk, for example by a LaTeX process. Skim then offers to reload the file. If you choose Auto from the dialog, Skim will reload this document without asking for future updates.

Use this feature with care, as reloading the file will typically loose any notes. If you have unsaved edits, Skim will always ask you whether to reload, even if you have previously chosen Auto. When you choose No, you can still reload manually by choosing Revert from the File menu.

This feature should be turned on in the LaTeX preferences.

Note: Skim's automatic file updating mechanism gets disabled when the PDF file is deleted before it is replaced, because Skim tracks the file object rather than the location of the file. This is by design for good reasons, and it is the way any document based Cocoa application works. Some TeX scripts (e.g. simpdftex) remove the PDF file, and therefore Skim will not automatically reload the file produced by such processes.

Note: The auto-reload functionality will not work properly when you have to run a latex process more than once, for example to support references generated by bibtex, because Skim will be trying to reload the document when the second latex process is busy. You could instead run latex and bibtex together with forcing a Skim reload using the script below.

#!/bin/bash

# the first argument should be the tex file, either with or without extension
file="$1"
[ "${file:0:1}" == "/" ] || file="${PWD}/${file}"
pdffile="${file%.tex}.pdf"

# run pdflatex and bibtex, and open or reload the pdf  in Skim
pdflatex "${file}" && bibtex "${file}" && pdflatex "${file}" && pdflatex "${file}" && \
/usr/bin/osascript \
  -e "set theFile to \"${pdffile}\"" \
  -e "tell application \"Skim\"" \
  -e "activate" \
  -e "set theDocs to get documents whose path is theFile" \
  -e "if (count of theDocs) > 0 then revert theDocs" \
  -e "open (my POSIX file theFile)" \
  -e "end tell" -

PDFSync

If you are using the pdfsync package, you can switch back and forth between the PDF document and the text editor. At a minimum, your latex documents needs to contain a \usepackage{pdfsync} line for this to work.

There are two actions pdfsync may allow you to perform:

  1. Show a line in the LaTeX document corresponding to a point in the PDF in Skim (backward search)
  2. Show a point in the PDF in Skim corresponding to a line in the LateX document (forward search)

You may need to setup Skim and your LaTeX editor to make either one of these work.

Activating backward search from Skim

Assuming that you've set up Skim, as detailed below, Shift-Command-click on a point in a PDF document shown in Skim can open the LaTeX source file in a text editor, and have it jump to the corresponding line in the LaTeX file (backward search).

Choosing an editor command for backward search

To be able to do backward searches, you'll need to tell Skim how to find your favorite text editor. You do so in the Sync preferences.

This should work through a script or command line tool that opens the editor and let it jump to a given line. Several advanced text editors, such as TextMate, BBEdit, TextWrangler, Emacs, and Aquamacs Emacs, come with such tools. Some of them let you install those tools on your system.

You can choose the editor command and its arguments in the Sync preferences of Skim. Some presets are defined for common text editors. You can still customize the command for these presets by first selecting the preset editor from the popup, and then selecting Custom. You can then edit the path to the command. For example, you could give the full path to the tool inside the application bundle. Usually the tool can be found in the Resources folder. For example, for TextMate the full path for the editor command is /Applications/TextMate.app/Contents/Resources/mate. For the preset editors, Skim will always try to locate the tool in the editor's application bundle, so the tool does not need to be installed for those editors.

Make sure to escape special characters such as spaces in the command in the preferences, e.g. if you are using Aquamacs Emacs. You can enclose the command path in double-quotes, or you can use backslash-escapes (e.g. "\ " for an escaped space).

In the arguments for the editor command, you can use %line as a placeholder for the line number in the LaTeX file, and %file as a placeholder for the full path to the LaTeX file. Make sure you enclose the the latter in double-quotes as "%file", so spaces in the path will be properly escaped.

Editor script for TeXShop

TeXShop does not have a built-in script for Skim to call. But you can write a custom script to do open TeXShop from Skim. An example script is the following.

#!/bin/bash

file="$1"
line="$2"

[ "${file:0:1}" == "/" ] || file="${PWD}/${file}"
[ "${line}" == "" ] && line=1

exec osascript \
  -e "set texFile to POSIX file \"${file}\"" \
  -e "tell application \"TeXShop\"" \
  -e "activate" \
  -e "open texFile" \
  -e "tell front document" \
  -e "refreshtext" \
  -e "goto line ${line}" \
  -e "end tell" \
  -e "end tell"

Save it to e.g. /usr/local/bin/texshop, make it executable, and set the editor command in Skim's preferences to texshop (you may need to use the full path) and the editor arguments to "%file" %line.

You could use such a script also for other scriptable editor aplications.

Editor Script for VIM

To call VIM, you can use the following script. Copy this script, and save it somewhere. Make sure you make it executable. Set the editor command in the Skim preferences to the path to the script, and the editor arguments to "%file" %line. (Thanks to Ted Pavlic.)

#!/bin/bash

file="$1"
line="$2"

[ "${file:0:1}" == "/" ] || file="${PWD}/$file"

exec osascript \
  -e "set ESC to ASCII character 27" \
  -e "tell application \"Vim\" to activate" \
  -e "tell application \"System Events\"" \
  -e "tell process \"Vim\"" \
  -e "keystroke ESC & \":set hidden\" & return " \
  -e "keystroke \":if bufexists('$file')\" & return " \
  -e "keystroke \":exe \\\":buffer \\\" . bufnr('$file')\"  & return " \
  -e "keystroke \":else \" & CR " \
  -e "keystroke \":    edit ${file// /\\\\ }\" & return " \
  -e "keystroke \":endif\" & return " \
  -e "keystroke \":$line\" & return " \
  -e "keystroke \"zO\" " \
  -e "end tell" \
  -e "end tell"

Considerations for Emacs

Some older versions of Emacs may require some extra changes to the .emacs configuration file to work properly for backward search. Also be aware that some versions of Emacs may not support pdfsync backward search at all. Moreover, Emacs needs to be running for backward search to work.

For Emacs.app and Aquamacs Emacs.app, the default tool emacsclient requires Emacs to be running for Skim to be able to call it. You may also use a simple script as the editor command, such as this script to open Emacs and load a file at a particular line.

For Skim to be able to call Emacs, you may need to put the following code in your .emacs file:

;; Starts the Emacs server
(server-start)

In addition, most people would want to make Emacs auto-raise when Skim opens it. If it doesn't do so, you can make it raise by adding the following lines:

;; Auto-raise Emacs on activation
(defun raise-emacs-on-aqua() 
    (shell-command "osascript -e 'tell application \"Emacs\" to activate' &"))
(add-hook 'server-switch-hook 'raise-emacs-on-aqua)

The ampersand after activate makes the command slightly more robust, but also opens up an *Async Shell Command*. You may experiment with removing it.

Setting up your editor for forward search

When you use pdfsync, Skim can load the PDF document and jump to the page corresponding to a line in the LaTeX file (forward search). To be able to do this, you'll need to set up your editor to call this script:

/Applications/Skim.app/Contents/SharedSupport/displayline %line "%pdffile" "%texfile"

The argument %line is the line number in the LaTeX file, "%pdffile" is the PDF file, and "%texfile" is the LateX source file. The last argument "%texfile" is optional. If it isn't supplied, it's derived from the "%pdffile" argument. It can be useful for multi-file LaTeX projects. Paths can be relative to the current directory for the script.

Refer to the documentation and help of your favorite text editor to find out how to be able to execute scripts and supply the arguments.

Alternative Script

Instead of the displayline script, you can also use a custom script to open a document in Skim. This could be integrated in the script called by the editor (e.g. for the TextMate setup). The following script, which is similar to the displayline script, opens the PDF file in Skim and forces a revert if the file is already opened. This can be useful if you don't want to use Skim's autoreload feature, for example when this does not work properly with your latex processing. Or when you find that the automatic refresh from Skim comes after the displayline script is called.

#!/bin/bash

line=$1
file="$2"

[ $# -gt 2 ] && source="$3" || source="${file%.pdf}.tex"

[ "${file:0:1}" == "/" ] || file="${PWD}/${file}"
[ "${source:0:1}" == "/" ] || source="${PWD}/${source}"

echo -ne "${line}\x00${file}\x00${source}" | \
/usr/bin/osascript \
  -e "set argv to do shell script \"/bin/cat\"" \
  -e "set AppleScript's text item delimiters to ASCII character 0" \
  -e "set {theLine, theFile, theSource} to text items of argv" \
  -e "tell application \"Skim\"" \
  -e "activate" \
  -e "set theDocs to get documents whose path is theFile" \
  -e "if (count of theDocs) > 0 then revert theDocs" \
  -e "open (my POSIX file theFile)" \
  -e "tell front document to go to TeX line (theLine as integer) from (my POSIX file theSource)" \
  -e "end tell" -

A slightly modified version of this script could also be used to just revert the document in Skim after a latex run, without further using PDFSync - for example if your editor allows script hooks, but those do not have access to the line number. Then simply leave out the lines for the line and the source variables.

If you are wondering about the weird lies involving the echo and cat commands, this is a trick to pass non-ASCII characters in the path variables to osascript. Simply including something like "set theFile to \"${file}\"" in the AppleScript lines (as in some sample scripts above) would not work when the path contains non-ASCII characters, such as accented characters.

Setting up TextMate

TextMate now has native support for PDFSync in Skim, which is included with the LaTeX bundle. To activate it, choose "Show in PDF Viewer (pdfsync)" from the Latex pop-up menu.

TextMate should also do the reloading for Skim after typesetting, so it is best to turn off automatic checking for file changes on the Skim Sync preference pane.

If you want to set it manually, or you want to customize this behavior, you can open up the Bundle Editor (Control+Option+Command+B), select LaTeX and create (or replace the TeXniscope one) a new item, calling it (for example) "Show in Skim (pdfsync)". You may insert the following as the commands:

FILE="${TM_LATEX_MASTER:-$TM_FILEPATH}"
SCRIPT="$(find_app Skim.app)/Contents/SharedSupport/displayline"

# Switch to the right directory
cd "${TM_PROJECT_DIRECTORY:-$TM_DIRECTORY}"
cd "$(dirname "$TM_LATEX_MASTER")"

if [[ -x "$SCRIPT" ]]; then
    "$SCRIPT" &>/dev/console $TM_LINE_NUMBER "${FILE%.tex}.pdf" "${TM_FILEPATH}"
else
    echo "Unable to locate Skim."
fi

Setting up Emacs

Some newer versions of Emacs, in particular Aquamacs Emacs version 1.3 and later, may already have pdfsync support for Skim build in, so you don't need to do anything to make pdfsync work with Skim. Otherwise you may make the following changes to your .emacs file.

To be able to jump to the relevant page in the PDF document, you can add the following to your .emacs file:

;; The following only works with AUCTeX loaded
(require 'tex-site)
(add-hook 'TeX-mode-hook
    (lambda ()
        (add-to-list 'TeX-output-view-style
            '("^pdf$" "."
              "/Applications/Skim.app/Contents/SharedSupport/displayline %n %o %b")))
)

Additionally, you probably want to set the following default values. The second one is only relevant if you use multi-file LaTeX projects.

;; Use PDF mode by default
(setq-default TeX-PDF-mode t)
;; Make emacs aware of multi-file projects
(setq-default TeX-master nil)

Opening Skim from other editors

If you use latex with some other editor, for example VIM from the command line, you could always use a custom script to open a file in Skim. Save the following script to a file, and make sure it is executable.

#!/bin/bash

file="$1"
[ "${file:0:1}" == "/" ] || file=${PWD}/${file}

exec osascript \
  -e "tell application \"Skim\"" \
  -e "activate" \
  -e "open POSIX file \"${file}\"" \
  -e "end tell"

Disclaimer: these directions were partly taken from the PDFView pages.

Personal tools