Showing posts with label pdfsync. Show all posts
Showing posts with label pdfsync. Show all posts

Sunday, March 23, 2008

SEEing LaTeX 28: Some Critical Notes on the 'see' Command Line Tool

I've used the see command line tool to relate a LaTeX previewer to SubEthaEdit using pdfsync. Unfortunately, I've become aware that the natural usage of see has a definite problem. Plugging in see and -g %line "%file" for the "PDFSync support" preferences in Skim doesn't work quite the way one would hope.

With that usage, which I'd consider to be the most natural, you wind up producing a new see process each time you command-click in Skim to switch over to SubEthaEdit. That process, due to shortcomings in the design of see, will hang around until you close the document in SubEthaEdit. Of course, if you're using SubEthaEdit and Skim together like that, you're in the middle of editing a LaTeX document, so you're not likely to be closing the document very promptly. Do that enough, and you could consume all the user processes allowed by Mac OS X. If you've not experience running out of user processes, let's just describe it as Not Fun.

I don't think it is likely to be a big problem, especially with the more friendly process limits in Mac OS X Leopard, but it is definitely a real problem. The problem gets compounded with each new usage of see for integrating external applications or reporting from a mode script. End result is that some caution is warranted when using see, and it should be omitted in favor of another approach, if necessary. Personally, I'm still using it.

I've requested an enhancement to see consisting of a 'quiet' mode, like seen in, e.g., grep. That would eliminate the issue, and, as a side benefit, considerably simplify using see from AppleScripts for SubEthaEdit modes. Let's hope the Coding Monkeys act on it.

Sunday, September 30, 2007

SEEing LaTeX 11: Typesetting Extended

In installment 10 of this series, I refactored the shell scripts used to compile and view a LaTeX document from SubEthaEdit. To change how a LaTeX document is compiled or viewed, it is now only necessary to change a variable, rather than messing around with the logic of the script. Let's take things a step further.

The relevant variables in the script are LATEX, PRODUCT_TYPE, and VIEWER. Their values in the script shown before were to use latexmk to build a PDF and PDFView to display it. However, other settings are possible. For example, setting
LATEX='pdflatex "$FILE"'
VIEWER='open "$PRODUCT"'
PRODUCT_TYPE=pdf
builds a PDF using pdflatex and shows it in Preview. These settings would be quite suitable for a "vanilla" installation, assuming no extras are installed beyond TeX.

A more flexible approach is to use those vanilla settings as defaults, and allow them to be overridden, giving
LATEX=${SEE_LATEX_COMPILER:-'pdflatex "$FILE"'}
VIEWER=${SEE_LATEX_VIEWER:-'open "$PRODUCT"'}
PRODUCT_TYPE="${SEE_LATEX_PRODUCT_TYPE:-pdf}"
Now, if we run the script from the shell, we can set environment variables to change how the script does its work.

Within SEE, the environment variables will be provided by the AppleScript that runs the script. The change is relatively simple: we extend the string that calls our shell script to also set the environment variables. Since a number of minor changes to the AppleScript have accumulated, I'll show the whole thing:
tell application "SubEthaEdit"
    if exists path of front document then
        if modified of front document then
            try
                save front document
            end try
        end if
        set filePath to path of front document
        set lineNumber to startLineNumber of selection of front document
        set modeResources to resource path of mode of front document
    else
        error "You have to save the document first"
    end if
end tell

set buildScript to prependEnvironment onto (join of {quotedForm for (modeResources & "/Scripts/shell/buildlatex.sh"), quotedForm for filePath, lineNumber} by space)

do shell script buildScript

on seescriptsettings()
    return {displayName:"Typeset and View PDF", shortDisplayName:"Typeset", keyboardShortcut:"@b", toolbarIcon:"ToolbarIconBuildAndRun", inDefaultToolbar:"yes", toolbarTooltip:"Typeset and view the current document", inContextMenu:"no"}
end seescriptsettings

on join of tokenList by delimiter
    set oldTIDs to text item delimiters of AppleScript
    set text item delimiters of AppleScript to delimiter
    set joinedString to tokenList as string
    set text item delimiters of AppleScript to oldTIDs
    return joinedString
end join

on quotedForm for baseString  
    quote & baseString & quote
end quotedForm

to prependEnvironment onto scriptString
    "export SEE_LATEX_COMPILER='latexmk -pdf -quiet \"$FILE\"'; export SEE_LATEX_PRODUCT_TYPE=pdf; export SEE_LATEX_VIEWER='/Applications/Skim.app/Contents/SharedSupport/displayline \"$LINE\" \"$PRODUCT\" \"$FILE\"';" & scriptString
end prependEnvironment

The basic strategy is still to construct a string that calls our shell script and feed it into do shell script. The string is changed in two ways. First, since the shell script now takes a line number as a second argument, I get the current line from SEE and pass it in. Second, and of more immediate interest, I set the environment variables and prepend those to the earlier buildScript. I've simplified the construction by defining join, quotedForm, and prependEnvironment handlers.

PrependEnvironment sets the SEE_LATEX_COMPILER, SEE_LATEX_PRODUCT_TYPE, and SEE_LATEX_VIEWER environment variables, customizing the behavior of the shell script. In the above AppleScript, I have set the environment so that latexmk and Skim are used to build and view a PDF.

Sunday, July 1, 2007

SEEing LaTeX 3: From PDFView to SubEthaEdit

In my last post, I presented an AppleScript that took us from a LaTeX document in SubEthaEdit to an appropriate portion of the corresponding PDF document in PDFView. This useful action is possible thanks to the magic of pdfsync.

What's more, pdfsync can be used to work both ways. Let's take a look at how to go from a PDF document open in PDFView to the appropriate line in the LaTeX document. In PDFView, you can command-click in the PDF, which invokes a shell command to presumably take you to the right spot in your editor. This works very nicely in TextMate, for example.

PDFView has a "command" text field and an "arguments" text field in its preferences. I don't really see why it's broken into two fields, but that's how it is, so that's what we'll work with. The arguments can include "%file" and "%line" tokens to indicate the file and line number, respectively. PDFView substitutes those tokens appropriately, and runs the script.

SubEthaEdit has the see command line tool that lets us open a file. That will be our starting point. Shockingly, it doesn't have a switch to go to a particular line! We'll work around that with AppleScript. This will be needlessly ugly, I'm afraid.

The see tool opens a file, and makes it the front document. That is the behavior we want for the document, so we'll start there and build a shell script to extend the behavior. We won't try to expose all the options of see in our script, instead just opening a file and going to a given line. We'll call the script seeline, and take its first argument to be the filename.

The next step in the script is to set the selection in the front document to a line number given as the second script argument. This is easy enough with AppleScript, and is a fairly direct transcription of the English-language description. Unfortunately, that turns out not to be enough. The selection is set as desired, but the selection may not be visible! What's worse, there is nothing in SubEthaEdit's AppleScript dictionary that lets us scroll the view as needed.

SubEthaEdit does have a "Jump to Selection" item in its "Find" menu. We could just hit command-J after PDFView transfers us to the LaTeX document in SubEthaEdit, I guess, but it is inelegant, at best. Instead, let's try something else. AppleScript can be used to script the user interface. You may need to first open the AppleScript Utility (why isn't this a preference pane, anyway?) and check the "Enable GUI Scripting" box. We can then use System Events to directly work with the menus of SubEthaEdit, choosing the "Jump to Selection" item.

Taken all together, we get a script:
#!/bin/sh
#
# Brings document to front in SubEthaEdit, opening if necessary, and
# selects given line.
#

#$Id: seeline.sh,v 1.4 2007/07/01 18:28:31 mjb Exp $


/usr/bin/see "$1"
/usr/bin/osascript > /dev/null <<ASCPT

tell application "SubEthaEdit"
    tell front document to set selection to paragraph $2
end tell

tell application "System Events"
    tell process "SubEthaEdit"
        tell menu bar 1
            tell menu bar item "Find"
                tell menu 1
                    click menu item "Jump to Selection"
                end tell
            end tell
        end tell
    end tell
end tell
ASCPT

All the AppleScript is included as a here document, which prevents lots of trouble with how the shell processes quotes and other characters.

I'm not pleased with using UI scripting. It seems fragile and likely to break with updated version of SubEthaEdit. Clearly, this should be an option for the see command line tool, which pretty much means it needs to be handled by the developers.

Whatever my feelings on the aesthetics of UI scripting, the important question is something else: does it work? Yes, it does, and pretty well at that. I have saved the script as ~/Library/bin/seeline, and set the "Command" and "Arguments" in the PDFView preferences to '$HOME/Library/bin/seeline' and '"%file" %line', respectively. Command-clicking in the PDF takes me to the LaTeX file.

Edit: Fixed formatting of included script.

Update: As of version 3.0 of SubEthaEdit, the see command line tool has an option to go to a desired line.

SEEing LaTeX 2: Opening the PDF in a Viewer

Getting completions for citations in SubEthaEdit is easy. Of course, someone else did all the work for us, so it should be easy! Let's try something a little more ambitious.

I generally use pdflatex. Thanks to pdfsync, a number of editors can integrate nicely with PDF viewers, albeit the viewers themselves must incorporate support for pdfsync. So, let's try to set up pdfsync support for SubEthaEdit. I'll focus on integrating SubEthaEdit with my current viewer of choice, PDFView. Sadly, PDFView appears not to be supported any more, but it's still useful and the basic approach should be the same for any viewer. For now, I'll just focus on going from SubEthaEdit to PDFView.

The mechanism for linking SubEthaEdit to PDFVIew will be AppleScript. You can have PDFView display a particular LaTeX line using AppleScript, which is just what we need. The strategy then is to get the line number for the selection in SubEthaEdit, figure out the file name for the PDF, and then tell PDFView to show the line number we obtained from SubEthaEdit. According to the SubEthaEdit scripting guide, we also need to include a seescriptsettings handler. Here, I present something simple, without working too hard to catch errors:
tell application "SubEthaEdit"
    tellfront document
        
set lineNumber to startLineNumber of selection
        set texFile to path
    end tell
end tell

set pdfFile to (text 1 through ((length of texFile) - 3) of texFile) & "pdf"

tell application "PDFView"
    activate
    display tex line lineNumber of file pdfFile
end tell

-- SubEthaEdit settings

on seescriptsettings()
    {displayName:"Show in PDFView", shortDisplayName:"PDFView", keyboardShortcut:"^~@o", toolbarIcon:"ToolbarPDFView.png", inDefaultToolbar:"yes", toolbarTooltip:"Opens PDF for document in PDFView", inContextMenu:"no"}
end seescriptsettings

I saved the above script as a compiled script into a copy of the LaTeX mode. Now, for a LaTeX document, the Mode menu in SubEthaEdit shows a script called "View in PDFView" which can be activated by a keyboard shortcut. It works well.

I also added an image to the LaTeX mode bundle to provide a toolbar item. I encountered some difficulties with this. The description in the scripting guide isn't very specific, it really just says to put images in the bundle. I got an appropriate image by copying the icon from the PDFView application bundle, and converting it to PNG (since that's what all the other images in SubEthaEdit mode bundles were). This didn't work. It took me some time to discover that the toolbar icon cannot be any size; the 128 by 128 pixel image I had simply didn't show up. Downsizing it to 32 by 32 using ImageWell solved the problem, providing a nice toolbar item. Of course, I normally leave the toolbar hidden, so I doubt I'll be using it much, but it is good to know how that works.

The script has a couple of oddities and shortcomings. The tell block for SubEthaEdit needs to get the selection and path for the front document. However, the scripting dictionary for SubEthaEdit has both documents containing windows and windows containing documents. Is tell front document the right thing to do? Should it be tell document of front window? Or maybe something else?

Also, I don't check to see if the document has been saved. I'm not really sure what the right solution is: unsaved changes won't be reflected in the PDF, anyway, so should I care? I'll revisit that later, assuming that I decide SubEthaEdit is suitable for my LaTeX needs.

Nor do I check to see if there is a document open at all. As far as I can tell, this is not an error. The script is mode dependent. Since the LaTeX mode is only active if there is a document open, there is thus no need to check.

The transformation of the LaTeX file path to a PDF file path is not done well. It should really be improved by properly splitting off the file extension, instead of just chopping off the last three characters and assuming we've gotten the file extension. While it is probably OK for LaTeX, I'm not sure if it could cause any problems. Again, this is something to fix later, once a more complete picture of editing LaTeX in SubEthaEdit takes shape.

The tell block for PDFView is weird. There aren't any changes I'd make, but it is just strange. If you open the script in Script Editor and compile it, the display tex line lineNumber of file pdfFile becomes display tex line lineNumber file pdfFile, which is syntactically invalid. However, you can run the script without first compiling, and it works fine. Which is really weird, because the script has to be compiled before running it, so it works once but fails the second time you run it. My solution was to do the editing in SubEthaEdit, compile it in Terminal using osacompile, and not worry about the matter. I suspect that the scripting dictionary in PDFView should just be considered in error, even though it can be made to work.

Next, I'll look at going the other direction, from PDFView to SubEthaEdit. A quite pleasant environment already looks possible.

Edit: Fixed formatting of included script.