Showing posts with label scripts. Show all posts
Showing posts with label scripts. Show all posts

Tuesday, September 20, 2011

Duplex Printing from the Command Line to an HP LaserJet Printer

My department has several HP LaserJet printers available to access within the department via LPR and SMB. However, if you are working from a personal laptop connected to the university wireless, those servers will not be available to you. Instead, you must print by piping your documents through SSH to a department server that does have access.

Unfortunately, doing duplex printing (i.e., two-sided printing) to an HP LaserJet printer from the command line is not trivial. So, using the GSview documentation as a guide, I put together a small bash script (available for download as hplj_duplex_print) that does the trick.
#!/bin/bash

declare -a input_file
if test $# -eq 0; then
    input_file=("-")
else
    input_file=("$@")
fi

( echo -e "\e%-12345X@PJL JOB"
  echo "@PJL ENTER LANGUAGE = POSTSCRIPT"
  echo "<< /Duplex true /Tumble false >> setpagedevice"
  gs -sDEVICE=psmono -sPAPERSIZE=letter -q -sOutputFile=- \
    -dNOPAUSE -dBATCH "${input_file[@]}"
  echo -e "\e%-12345X@PJL EOJ"
  echo -e "\e%12345X"
  ) | lp -d your_HP_printer_spool_name
You should replace the your_HP_printer_spool_name with your printer's spool name. You might want to tweak some of the options (details below), but the general structure will remain the same. The opening and closing escape sequences communicate to the HP LaserJet printer that a PostScript file is coming. Then the setpagedevice PostScript directive instructs the printer to use its duplex module.

Regarding tweaking:
  • Again, make sure to change your_HP_printer_spool_name to your spool name. You may also want to change lp to lpr, but you will likely have to change -d to -P then.
  • You may want to change the gs (GhostScript) options to suit your purposes. For example, you can change the psmono device to one of the other GhostScript devices like psgray or psrgb.
  • The Tumble switch determines whether to do short-edge (true) or long-edge (false) duplex printing, and so this script defaults to the latter case. If you prefer vertical flipping, change the /Tumble false to /Tumble true. You might also make this a configurable command-line switch on the script.

Monday, March 07, 2011

MATLAB script to prove to you that the perfect squares are the switches that are toggled

Evidently, this problem exists in both "switch" and "locker" forms. Assume that there are 100 switches are initially off and numbered from 1 to 100.
  • First, you toggle multiples of 1 (i.e., every switch gets turned on),
  • and then you toggle multiples of 2 (i.e., every even-numbered switch gets turned off),
  • and then you toggle multiples of 3 (i.e., switches 3, 6, 9, 12, ... are toggled),
  • ...
  • and then you toggle multiples of 99 (i.e., switch 99 is toggled),
  • and then you toggle multiples of 100 (i.e., switch 100 is toggled).
After this process, which switches are "on"?

Examining the problem, you notice that switches are toggled the same number of times as they have unique factors. For example, switch 6 is toggled 4 times, which corresponds to its unique factors, 1, 2, 3, and 6. However, switch 4 is toggled only 3 times, which corresponds to its unique factors, 1, 2, and 4 (i.e., even though 4 = 2 × 2, the factor 2 is only represented in the list once because it is duplicated). Moreover, it is only the perfect squares (1, 4, 9, 16, 25, 36, 49, 64, 81, 100) that will have repeated factors (i.e., their whole square roots), and so it is only those switches that will be flipped and odd number of times. Furthermore, it is only those switches that will be "on" after this game.

To verify this to yourself, use a MATLAB script:
% All switches initially off
switches = zeros(1,100);

% Toggle multiples of the current switch, including the current switch
for i = 1:100
% These are the switches to toggle
ivec = i:i:100;

% xor'ing them with 1's toggles them
switches(ivec) = bitxor(switches(ivec), 1);
end

% Show the indexes of the switches that are "on" after this process
% (expect perfect squares: 1 4 9 16 25 36 49 64 81 100)
find( switches )
Running the script results in:
ans =

1     4     9    16    25    36    49    64    81   100
which is what we expected.

Of course, you could also keep track of how many times you made a flip. XOR can help with this too.
% All switches initially off
switches = zeros(1,100);
new_switches = zeros(1,100);
num_flips = zeros(1,100);

% Toggle multiples of the current switch, including the current switch
% (gratuitous use of bitxor as a demo)
for i = 1:100
% These are the switches to toggle
ivec = i:i:100;

% xor'ing them with 1's toggles them
new_switches(ivec) = bitxor(switches(ivec), 1);

% count the flips
% ( num_flips(ivec) = num_flips(ivec)+1  works too)
num_flips = num_flips + bitxor( new_switches, switches );

% commit new_switches to switches to maintain invariant
% (can omit new_switches by not using second bitxor above)
switches = new_switches;
end

% Show the indexes of the switches that are "on" after this process
% (expect perfect squares: 1 4 9 16 25 36 49 64 81 100)
find( switches )
Then, from the console, we can issue commands like:
num_flips( find(switches) )     % shows number of flips for switches ending "on"
num_flips( find(switches==0) )  % shows number of flips for switches ending "off"
find( mod(num_flips,2)==1 )     % verifies odd-count flips have perfect-square indexes
So that's fun.

Wednesday, February 16, 2011

More Quick Reference Cards

Remember that time when I was quick reference card happy [1, 2, 3, 4, 5]? Today, I accidentally found another good quickref card blog post by someone else (Refcards by Michael Goerz; see the original post for the source code and other versions of these cards):He also includes a few quick reference cards not written by him (Subversion (SVN), GDB, GNU Emacs, MySQL).

Friday, February 11, 2011

Scripts to get Mercurial up and running on OSU CSE machines (SunOS and Linux)

UPDATE: A day after I posted this, Mercurial and Python (and Git) were added as optional subscriptions for users of these machines. So login to your desired machine and execute subscribe, then select MERCURIAL and whatever PYTHON is available (version 2.4.x or higher). Quit subscribe to save your changes, and re-login (of course, you can also do the same thing with GIT).
If you are a student, staff member, or faculty member in the Computer Science and Engineering department at The Ohio State University, you may have found yourself wanting to use a DVCS like Mercurial (hg) for SCM. Unfortunately, the version of Python that comes bundled on these enterprise systems prevents installing Mercurial, and some other issues on the SunOS system (like the lack of round() in the math library) prevent building a recent version of Python 2 that is needed for installing Mercurial. There are ways around this mess, and I have done my best to automate them within a script.

So give it a shot:Download the appropriate script to your desired target machine. Next, edit the script (e.g., using pico, nano, vi, or emacs) to verify that the INSTALLDIR location at the top of the script is what is desired – if you are going to run the script on both types of machines, your INSTALLDIR must be different in the two scripts. Then run the script on the machine (e.g., ./install_hg_osu_cse_sun.sh) and follow the instructions. The script is interactive, and so you will be able to manage its behavior as it runs. Be sure to follow its instructions at the end about setting your PATH and PYTHONPATH; if you ran the script on both types of machines, you will have to be clever in your script RC/profile file to set these differently based on the machine you are on – I recommend using uname to detect the different machine type.

After that, you should have a working Mercurial. In the Linux script, you may adjust the Mercurial and Python 2 versions downloaded, but in the SunOS script, you need to leave the Python 2 version alone as later versions of Python will not build on the SunOS machines (due to the problems with the old math library). On either machine, if you are adventurous, you can use the installed Mercurial to clone the stable Mercurial repository (hg-stable) and keep your installed Mercurial up-to-date with the very latest stable version.

Tuesday, January 04, 2011

Drawing a circle in MATLAB (curved rectangle instead of approximating with filled polygon)

Today, someone I know googled for some help drawing a filled circle in MATLAB and asked me what I thought of the code that was found. The code found, which seems to be the conventional way to draw circles in MATLAB according to Internet posters, generates a polygonal approximation of a circle and then fills it. It goes something like this (where you can use linspace(0,2*pi,N+1) and daspect([1,1,1]) (or axis square) instead of two of the commands used here):
xc = 0;
yc = 0;
r = 2;
N = 256;
theta = (0:N)*2*pi/N;
x = r*cos(theta) + xc;
y = r*sin(theta) + yc;
fill(x, y, 'k');
axis equal;
where (xc,yc) is the coordinate of the center of the circle, r is the radius of the circle, and (N-1) is the number of sides of the polygon that is inscribed inside the desired circle (i.e., the polygon's corners intersect the circle). The circle is filled with the color black, which corresponds to the 'k' parameter of the fill command. To quickly get rid of the circle without clearing the figure, change the fill command so its figure handle gets assigned to a variable (e.g., h = fill(x,y,'k');) and you can delete that figure handle later (e.g., delete(h);). I notice that some people precede the fill command with a plot(x,y); command, but that is not necessary; the fill command will construct the closed finite polygon and put a (black) border around it by default, and so there is no need to draw the border ahead of time with plot.

[ Of course, there are methods very similar to the above that use a rotating complex phasor (i.e., a complex exponential from r*exp(i*theta)) and then let plot generate the projected Cartesian plane coordinates from the complex plane. These methods are equivalent but depend on MATLAB to do the trigonometry behind the scenes, which may or may not be faster... ]

What surprises me is that there is a perfectly nice built-in MATLAB command that will draw rectangles, rounded rectangles, circles, and ellipses very quickly essentially without having to approximate them with finite polygons. It is the rectangle command. Some of the people who posted code like the above example apparently know about the rectangle command (because they use it to verify that their circular approximation is sufficiently circular); however, I guess it's not ideal for them because it references the figure to a corner as opposed to its center. Nevertheless, a lot of people who might not be as picky may not know about the rectangle command, and so here's an example similar to the above.
w = 4;
xc = 0;
yc = 0;
rectangle('Curvature',[1 1], ...
          'Position',[xc-w/2 yc-w/2 w w], ...
          'FaceColor','k');
axis equal;
The 'Curvature' property tells MATLAB that the lines connecting the corners of the rectangle should have no straight portions. By decreasing each of the 1's to 0 in the curvature property, the circle looks more like a rounded rectangle with flat sides and rounded corners. The 'Position' property places the bottom-left corner of the rectangle in its first two elements and then sets the width and height of the "rectangle". So here, a circle centered at (xc, yc) is drawn with a radius of w/2. The circle is filled with 'FaceColor'. Again, axis equal; could be replaced with daspect([1,1,1]); or axis square;. Additionally, rectangle can be assigned to a variable (e.g., h = rectangle(...);) so that the rectangle can be easily removed later (e.g., delete(h);) without having to clear the figure. So this example draws a circle, but by playing with the rectangle parameters, it is easy to draw rectangles, rounded rectangles, and ellipses as well.

It is possible that the former method might be faster, but I can't imagine it would be much faster. The latter method seems more elegant and intuitive to me, and I have to imagine that's what the people at Mathworks would advise you to use if you called them up. Having said that, I have not called them up, and so you decide for yourself.

Wednesday, December 08, 2010

Tools for combining BibTeX, PDFs, and e-Readers

Quick links:
UPDATE: If you are looking for a simpler solution that updates PDF's in your BibTeX database with the corresponding BibTeX data, check out updatepdf.pl. Be careful though; the old PDF::API2 module only supports Adobe PDF 1.4 (i.e., compatibility-mode PDF's).
UPDATE: Apparently, you can also manage your Kindle collections efficiently using emacs, using Calibre, or manually so long as you're okay with possibly having to reboot your Kindle after every change. So it would be possible for me to add Kindle collections.json support to my fix-pdf-tags script; I just don't anticipate having the time to do that in the near future (plus, I don't own a Kindle anymore, and so I wouldn't be able to test it).
In trying to migrate to e-Readers, I've been experimenting with both the Amazon Kindle 3 and the Sony Daily Reader PRS-950. They both have nice features... I don't have time to go into a review, but I'll give a teaser...
  • Kindle PRO's: It has a nice web browser (that works on 3G too!), and makes it super easy to get new content onto the device. In fact, you can even download PDF's from Dropbox via the nifty browser (although e-mailing to your Amazon Kindle e-mail address is convenient too). Plus, Amazon makes for a nice e-Book store -- lots of the books I would want.
  • Kindle CON's: However, PDF's really have to be in compatibility mode (Acrobat 1.4). Otherwise, the Kindle will miss all of the metadata. More importantly, it is basically impossibledifficult to manage collections through the USB. So if you have hundreds of PDF's, you'll spend days tagging them via the clunky Kindle keyboard.
    • UPDATE: Apparently, the Kindle uses a simple SHA-1 hash of the file's full path as a key in the collections.json file that is accessible via USB. Consequently, you can manage your collections data more efficiently. You can do so with an emacs script or with a calibre plugin or manually. However, you may have to reboot your Kindle every time you make a change. At least with the older Kindles, the collections.json file was only read on boot. It's possible that the newer Kindles are smart enough to refresh collections data every time the USB is unplugged (like the Sony does), but I honestly don't know. I have a feeling that Hannes, the author of bibtex-kindle, knows though.
  • Sony Daily PRO's: It has the optical touch screen. It doesn't require compatibility-mode PDF's. It has a large screen. It has terrific page viewing options. In theory, the PDF note options are very nice, but e-Reader notes just seem tedious to me in general regardless of interface. More importantly, it is essentially an "open" platform so long as you are OK with a little bit of reverse engineering. It is easy to write a few scripts to manage your XML files, and so keeping your PDF's organized is easy for your average script kiddy.
  • Sony Daily CON's: The optical touch screen means the screen is sunk down so far that it the chassis casts a small shadow around the edge of the screen. The Sony case-with-light isn't as nice as the Kindle's case-with-light. The Sony Bookstore doesn't have as many books (or at least the books I care about). The zoom modes leave much to be desired. In PDF's that work fine on the Kindle, trying to click a word for dictionary lookup often leads to selecting a phrase (and there's nothing you can do about it).
And there's plenty more to talk about, but those are the quick things off the top of my head. So it looks like I'm probably going to keep both... so I can have a diversity of e-Books available to me. Plus, the e-Book experience is a little nicer on the Kindle, but the PDF experience might be a little nicer on the Sony. It's hard to tell.

But what this post is really about is a utility I've put together that automatically manages my research PDF collection on either the Kindle or the Sony Reader. In particular,
  • It updates PDF's with metatags to match author/editor/title information from a central BibTeX database.
  • If you invoke it with a "kindle" argument, it converts PDF's to 1.4 so the Kindle can read the metatags.
  • If you invoke it with a "reader" argument, it also automatically generates categories based on file hierarchy (i.e., the folders in which your PDF files live). In fact, symbolic links indicate that multiple tags should be applied to the same file (i.e., the target of the symbolic link).
So maybe that will be helpful to someone (at least as an example to generate some ideas). The project started out as something customized for me, but I've tried to make the documentation clear (see the chunk at the top to start). Plus, most of the important custom information (paths, preferences, etc.) are at the top of the script.

Check out the most recent version of my fix_pdf_tags script; it resides in my bibtex_to_pdf Mercurial repository where you can view its change history.

P.S. I know that Calibre is an existing software package that has very similar aims and a nice graphical environment. However, it really is a poor choice for managing PDF research. Plus, the Calibre folks have basically written off Kindle users as poor schmucks with hobbled readers. More importantly for me, I'm much happier with scripted solutions that can be fired off quickly.

Tuesday, November 03, 2009

Making Vimperator 2.2+ work with Delicious keywords

This blog post echos the same information as issue 138, which describes a tiny plugin delicious_addon_kw_hack.js that can be used to restore compatibility with the Delicious add-on.
As discussed in issue 120, as of changeset da9c0a1a532d of Vimperator v2.2b1, Vimperator's ":open" will stop recognizing keywords imported from Delicious bookmarks via the the Delicious Firefox add-on.

A simple way to fix the problem is to drop the following code:
bookmarks.getSearchURL = function(text, useDefsearch) {
let url = null;
let postData = {};
let searchString =
(useDefsearch ? options["defsearch"] + " " : "")
+ text;

this.getSearchEngines();

url = window.getShortcutOrURI(searchString, postData);

if (url == searchString)
return null;

if (postData && postData.value)
return [url, postData.value];

return [url, null]; // can be null
}
into a file like delicious_addon_kw_hack.js into your ~/.vimperator/plugin/ directory (or the equivalent directory under Windows; see :help plugins for more details).

Tuesday, March 17, 2009

Perl script that generates CSV and BerkeleyDB versions of LTWA list

UPDATE: If you're wondering why I just didn't save the LTWA database and search it every time I needed to abbreviate a journal, it's because I wanted to optimize for speed downstream. That is, I did all the possible processing now to speed things up later. I've also augmented the script to do the opposite (and save the results in other smaller files) so that I can tell the downstream process to take longer (and possibly have better results with less spurious entries in the hash table). I've also updated the downstream script to save any successful lookups locally to speed up successive runs. Again, contact me if you want more details.
I'm sick of looking up ISO 4 standard journal abbreviations from the List of Title Word Abbreviations (LTWA) hosted at ISSN's LTWA online. The most annoying thing about LTWA online is that you can't get one big list unless you have them mail you a paper copy (for a price). So you have to resort to clicking each letter and waiting for the list for that letter to come up.

So I wrote a Perl script that automatically cURLs each LTWA online page down, processes it, and generates both CSV and BerkeleyDB (BDB) hash files containing a list of words and their associated official LTWA abbreviation. I use the BDB file in another script to automatically generate BibTeX database files for each of my journal papers (that script first checks a list of known-good journal abbreviations before trying to generate the abbreviation itself).

There were several challenges to such a task, and the list isn't perfect. I focused on one-word entries. For more complicated abbreviations, I figured I'd lean on my list of known-good journal abbreviations. That still left LTWA entries like "psycholog-" and "bulletin-" which use "-" to imply "and any other character." So I used a typical /usr/share/dict/words list to generate a list of English words that matched each pattern. Because such lists don't usually include plurals, I used Lingua::EN::Inflect to generate plurals and then took all of the plurals that included the singular (i.e., that would also match the LTWA pattern).

So that works well for me. Someday I might put the script and/or the files it produces on-line. For the moment, if you want any of these, contact me and let me know. I'll share.

Wednesday, March 11, 2009

"Interference" seems like an appropriate name

I got a request from a marketer that I link to his product from this blog:From him:
Inference is a Microsoft Office add-in that has a point-and-click interface for adding MATLAB code, .m files, and structured data to Word and Excel documents. If you use Microsoft Office, Inference is an alternative to EX Builder and Notebook for generating reports, reproducible research, and Office applications. And regardless of whether you use Office, Inference has an integrated development environment (Inference Studio) with an intelligent editor that features breakpoints and edit-and-continue.
I have no idea why you would possibly need such a thing. I view software like this as predatory—it preys on people who think they're helpless. They end up overlooking existing easy solutions (like using the debugging features of MATLAB's own editor) and get distracted from finding truly good solutions.

Perhaps I'm being a little too harsh. Interference's own website gives a better description of its features:
Inference for MATLAB allows you to:
  • Execute MATLAB code directly inside of Microsoft Word to create formatted reports that contain explanatory text and graphical/code output.
  • Execute MATLAB code directly inside of Microsoft Excel to create dynamic spreadsheets that leverage existing Excel functionality.
  • Store all of your MATLAB code, data, and M-Files inside a single Microsoft Word and Excel document.
If you have use for such a thing... Give it a whirl, but don't come to me for help.

(by the way, my LaTeX build environment does the equivalent of "Interference for MATLAB" for LaTeX users. Among other things, if you \includegraphics{image_name} and the build environment finds an image_name.m file, it will automatically generate an image_name.eps (or image_name.pdf) whenever the MATLAB script gets updated)

Saturday, December 29, 2007

PDFSync Inverse Searches in MacVim

Remember the post on doing inverse searches in Vim on OS X? The idea was to drop gvim-pdfsync into
/usr/local/bin
(or somewhere else in your PATH) and then execute
gvim-pdfsync "%file" %line
to do inverse searches in Vim for OS X just like you can in Windows or in other UNIXes. For example, in Skim, under the PDFSync section of the Sync tab of the Preferences, you can put
Preset: Custom
Command: gvim-pdfsync
Arguments: "%file" %line

For MacVim

I thought it might be nice if I published how to do the same thing in the nascent MacVim, which supports servers just like Vim for Windows. Provided that you've installed the mvim shell script somewhere in your PATH, you can setup Skim with
Preset: Custom
Command: mvim
Arguments: --remote-tab-silent +":%line;foldo!" "%file"

or, if you don't like tabs
Preset: Custom
Command: mvim
Arguments: --remote-silent +":%line;foldo!" "%file"

Retro-Approach

Alternatively, if you really liked the gvim-pdfsync approach and want something similar for mvim, put mvimtab-pdfsync or (if you don't like tabs) mvim-pdfsync in your PATH (e.g., in /usr/local/bin) and then setup Skim for:
Preset: Custom
Command: mvimtab-pdfsync
Arguments: "%file" %line

or (if you used mvim-pdfsync)
Preset: Custom
Command: mvim-pdfsync
Arguments: "%file" %line
I hope that helps.

Tuesday, July 17, 2007

Using Skim with MATLAB

I found a hint for using TeXShop as a MATLAB previewer on OS X, primarily because plots look better in PDF and TeXShop auto-updates files from disk. This was a tip from back in 2005. Since then, MATLAB's OS X plotting has gotten a lot better. Additionally, Skim has been invented.

Because of the advances in MATLAB, this may not be a useful hint anymore, but give this a try sometime:
figure(1);
set(gcf, 'Visible', 'off');
plot(x, y);
print(gcf, '-dpdf', 'figure1.pdf');
system('open -a Skim figure1.pdf');
Now, I believe there's a way to do this without having to plot first. That is, I think there's a way to plot to PDF without first generating that figure.

What's cool about this is that any future updates of the PDF will cause Skim to update automatically. Therefore, Skim becomes your plot viewer. That might be nice, right?

Using Skim, PDFSync, and TeXShop

UPDATE 3: I have updated the script to support command-line options that will prevent TeXShop from doing things like refreshing text (and trashing your unsaved changes), activating (taking your focus away), and opening (possibly getting in front of your view). Try the -h option for details.

UPDATE 2: There is a related Skim revision that will make it easier to use AppleScript for PDFSync interfacing. This change will prevent having to make UNIX shell scripts that must be modified with chmod.

UPDATE 1: As you can see in the Skim revision history, future versions of Skim will include their "Application Support" directory (e.g., ~/Library/Application Support/Skim/) as well as a "Scripts" subdirectory in their path. When that occurs, scripts like the one below can be stored there and executed from Skim without specifying the full path name.

I know there are ways to change TeXShop's previewer; however, I don't know how to do them. Additionally, I don't use TeXShop, so I have little incentive to look those things up.

However, I do use Skim, which is compatible with pdfsync, and recently someone asked me how they could get Skim to call up TeXShop at a particular line (as someone would want to do when using pdfsync).

For that, I generated a texshop script that looks like this (an earlier version of this can be found on the Skim wiki):
fileName="$1"
lineNumber="$2"
gotoString=""

[ "${fileName:0:1}" == "/" ] || fileName="${PWD}/${fileName}"
[ "${lineNumber}" == "" ] || gotoString="goto line ${lineNumber}"

exec osascript \
-e "set texFile to POSIX file \"${fileName}\"" \
-e "tell application \"TeXShop\"" \
-e "activate" \
-e "open texFile" \
-e "tell front document" \
-e "refreshtext" \
-e "${gotoString}" \
-e "end tell" \
-e "end tell"
To use this script, follow these steps:
  1. Save that file as something (preferably in the PATH somewhere, but this is not necessary) like
    /usr/local/bin/texshop
    or anywhere you would like (e.g., /Users/username/bin/texshop). However, if you place it somewhere differently, be sure to update the red text in these instructions.

  2. Next, chmod it 0755, as in
    chmod 0755 /usr/local/bin/texshop
    This can be done from the Terminal.

  3. Finally, tell Skim's PDFSync preferences (under Preferences->LaTeX or Preferences->Sync depending on your Skim version) to use a "Custom" editor with
    Command: /usr/local/bin/texshop
    Arguments: "%file" %line
    Make sure you click AWAY (e.g., onto a different tab) from the PDFSync settings before you close the Preferences. Otherwise, one of your text boxes may not get saved.
After this is done, doing Shift+Command+CLICK in Skim on a location in the PDF will bring up the source in TeXShop located at the that generated that point in the PDF.

Note that if you have saved texshop somewhere in your PATH, then you should be able to drop the /usr/local/bin/ from the front of the Command: line.

Wednesday, July 11, 2007

PDFSync inverse searches on Vim for OS X

FINAL UPDATE: See the new post, "PDFSync Inverse Searches in MacVim," for the state of the art on this subject.
UPDATE 8: Skim 0.6 and up supports spell checking of a PDF. This is a strange feature of a PDF viewer since Skim does not allow you to edit the PDF text directly. However, it makes a lot of sense when inverse searches are supported. After doing Shift+Command+CLICK on the misspelled word, the TeX editor will open up near the line of TeX where the word is found.

UPDATE 7: caveat Vimmer! Inverse searches in Skim are called up with Shift+Command+CLICK. This is fine; however, if you hold Shift+Command too long, the AppleScript for calling up Vim is going to get confused. In other words, be sure to release the modifier keys as soon as possible after the "click."

UPDATE 6: I found information about doing both forward and backward searches with Vim and PDFView (see also: using gotoline.sh). From these, I've made hacks to the VIM-LaTeX scripts for PDFView and other viewers (like Skim and TeXniscope). I will describe these hacks in another post.

UPDATE 5: See Vim Tip #225 and the corresponding wiki entry for information about both backward and FORWARD searches in Vim. I also found a nice LaTeX tools script for Vim that has forward searching built in. I found these pages linked from a page on xdvi inverse searches.

UPDATE 4: Very trivial updates have been made in a 1.03 version of this script.

UPDATE 3: I have posted a 1.02 version of this script. The changes are fairly trivial, but you might be interested in checking it out.

UPDATE 2: This script is now a part of the Skim wiki.

UPDATE 1: I have mirrored this post at my web site.

WINDOWS USERS: See "Performing inverse searches" from the VIM-LaTeX quick start guide.

I have posted information about this in a number of places [1, 2, 3, 4, 5]. I plan to add something at MacResearch sometime soon too.

The package PDFSync allows users to do "backward searches" or "inverse searches" from PDF viewers like iTeXMac, TeXniscope, Skim, and others. That is, if you generate a PDF with LaTeX (or Plain TeX or ConTeXt), you will be able to click on text in the PDF and have an editor open up and position the cursor at the TeX source code that generated that text. That can be very nice.

There is a related feature for DVI files, but there are very few good DVI viewers out there (TeXniscope comes close), so I just focus on PDFSync).

I use Vim with VIM-LaTeX to do my document preparation. I would like to also be able to use PDFSync. However, while inverse searching is supported in Windows, it is not easily done in OS X.

I found a thread describing how to do inverse searching with AppleScript that issues raw commands to Vim. I decided to take that AppleScript, package it into a bash script, and fix it so that it had no problem handling files with spaces or symlinked files or multiple files with the same base name. The result is this script:
#!/bin/bash

filename="$1"
lineNum="$2"

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

exec osascript \
-e "set ESC to ASCII character of 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('$filename')\" & return " \
-e "keystroke \":exe \\\":buffer \\\" . bufnr('${filename}')\" & return " \
-e "keystroke \":else \" & return " \
-e "keystroke \": edit ${filename// /\\\\ }\" & return " \
-e "keystroke \":endif\" & return " \
-e "keystroke \":${lineNum}\" & return " \
-e "keystroke \"zO\" " \
-e "end tell" \
-e "end tell"
Copy that script in a place (preferably in your PATH) like
/usr/local/bin/gvim-pdfsync
and chmod it 0755. That is, do
chmod 0755 /usr/local/bin/gvim-pdfsync
Then you can use the script like
gvim-pdfsync "%file" %line
where %file is the name of the file to be opened and %line is the line to place the cursor on. So, for Skim, you would put in your LaTeX (or Sync) preferences under "PDFSync" support:
Preset: Custom
Command: gvim-pdfsync
Arguments: "%file" %line
After configuring Skim, BE SURE TO CLICK AWAY FROM THE TEXT BOXES before closing the configuration. For example, click on one of the other tabs. Otherwise, the dialog box may not record your changes to the last text box you changed.

I hope that's useful to someone.

Friday, July 06, 2007

Script to open file in TeXniscope from command line

UPDATE 2: A much fancier version of this script is now available. It has options that make it easier to make TeXniscope update its file and position (via PDFSync or DVI source specials) in the background. The options are described briefly with the -h parameter.

UPDATE 1: A more mature version of this script is now available. It has a usage line. It checks for the existence of files. It tries to guess at a file name if the file does not exist. It's a little more convenient for the command-line user.

Here's a script to open a (PDF or PostScript) file in TeXniscope from the command line:
#!/bin/sh

[ "`echo $*|cut -c 1`" == "/" ] || filename_prefix="`pwd`"

exec osascript \
-e "tell application \"TeXniscope\"" \
-e "activate" \
-e "open file ((POSIX file \"$filename_prefix/$*\") as string)" \
-e "refresh of the front document" \
-e "end tell";
or, alternatively,
#!/bin/bash

arguments="$*"
[ "${arguments:0:1}" == "/" ] || filename_prefix="$PWD"

exec osascript \
-e "tell application \"TeXniscope\"" \
-e "activate" \
-e "open file ((POSIX file \"$filename_prefix/$*\") as string)" \
-e "refresh of the front document" \
-e "end tell";

Create an executable script called texniscope (e.g., /usr/local/bin/texniscope that is chmod'd 755) and try texniscope FILENAME where FILENAME is the name of the PDF or PostScript file that you want to open (be sure to include the file extension).

This allows you to use TeXniscope as a LaTeX document viewer in the VIM-LaTeX suite for Vim.

See also: Script to open file in Skim from command line

I use this for Vim/GVim; however, this script was inspired by code in an example in the TeXniscope help file for making TeXniscope work with iTeXMac. See the TeXniscope documentation for information on how to build a script that will let iTeXMac call TeXniscope from the command-line (and even make use of PDFSync [CTAN, iTM]).

Script to open file in Skim from command line

UPDATE 4: I have updated the script to accept command line options. A -h option gives help text describing the new usage. The options can prevent Skim from being activated or opening the file. This may be useful when trying to get Skim to update in the background.

UPDATE 3: I have updated the script to check for whether or not files exist, try to guess the right files if they don't, and bail if it fails. It also has support for PS and DVI files. Also fixed a problem with symlinked files.

UPDATE 2: I have generated a more mature version of this script that also has the ability to position Skim's PDF view at a position corresponding to a line of your TeX source (provided you built the PDF with pdfsync).

UPDATE 1: As discussed in this feature request and this Wiki entry, in iTeXMac, you can also try
Skim.app/Contents/SharedSupport/displayline %line "%pdffile" "%texfile"
which lets you make use of Skim's PDFSync support. The Wiki page includes instructions on using this in Emacs and TextMate as well. If you just want to open the file, you might try
Skim.app/Contents/SharedSupport/displayline 1 "%pdffile"
but this might break if the TEX file isn't available (so maybe you should still use the AppleScript below).

Here's a script to open a (PDF or PostScript) file in Skim from the command line:
#!/bin/sh

[ "`echo $*|cut -c 1`" == "/" ] || filename_prefix="`pwd`"

exec osascript \
-e "tell application \"Skim\"" \
-e "activate" \
-e "open ((POSIX file \"$filename_prefix/$*\") as string)" \
-e "revert front document" \
-e "end tell";
or, alternatively,
#!/bin/bash

arguments="$*"
[ "${arguments:0:1}" == "/" ] || filename_prefix="$PWD"

exec osascript \
-e "tell application \"Skim\"" \
-e "activate" \
-e "open ((POSIX file \"$filename_prefix/$*\") as string)" \
-e "revert front document" \
-e "end tell";

Create an executable script called skim (e.g., /usr/local/bin/skim that is chmod'd 755) and try skim FILENAME where FILENAME is the name of the PDF or PostScript file that you want to open (be sure to include the file extension).

This allows you to use Skim as a LaTeX document viewer in the VIM-LaTeX suite for Vim.

NOTE ABOUT revert: The line with revert in it requires Skim version 0.5 or higher. If you don't have that version of Skim (or you don't care about refreshing the document), then delete that line.

See also: Script to open file in TeXniscope from command line

I use this for Vim/GVim; however, this script was inspired by code in an example in the TeXniscope help file for making TeXniscope work with iTeXMac. See the TeXniscope documentation for information on how to build a script that will let iTeXMac call TeXniscope from the command-line (and even make use of PDFSync [CTAN, iTM]). It should be easy to modify the script they give there to call Skim instead of TeXniscope; use my script here as an example. Note that Skim's AppleScript also supports all of the goto line stuff of TeXniscope. However, the syntax is different; see the Skim AppleScript dictionary for more information.