Lyx clickable hyperlinks

If you are trying to use lyx as a lab-book (like me) then it’s quite handy to link to local files. You can do this with a hyperlink but the pdf viewers support of these can be a bit limited (for very good reason). You can however persuade lyx to lauch the links pretty effectively.

If you click edit externaly then lyx has a crack at launching it

You need:

  • Lyx 1.6(ish)
  • Python 2.6(ish)

I’ve not tried this on linux, I suspect its different way of associating files with applications might cause problems, but on windows it works well for local files.

Setup Lyx

default.def

To get the hyperlink out of lyx I’ve used the clipboard. This command first selects the link then copies it then launches a script called relay.py which launches the appropriate thing.

  • Create the file “$User$\AppData\Roaming\LyX16\command\default.def” with the following contents (make sure you replace $Program_Files$ with the right path.
\define "link" "command-sequence char-forward-select; copy; vc-command U \"$Program_Files$/LyX16/bin/\" \"relay.py\""

$Program_Files$/LyX16/bin/

Add the context menu

To allow us to call the command from within lyx we need to add a context menu to the hyperlink inset.

  • Copy stdcontext.inc from “$Program_Files$\LyX16\Resources\ui” to $User$\AppData\Roaming\LyX16\ui” (you can edit it in place but the installers wipe it)
  • Add the following code before the last “End”.
#
# Inset hyperlink context menu
#
  Menu "context-href"
  Item "Settings...|S" "next-inset-toggle"
  Separator
  Item "Edit Externally...|x" "call link"
End

Python scripts

Launcher.py

This file grabs the contents of the clipboard and parses out the path of the hyperlink which is in the form:

[path||name]

There’s a bit of windows specific code at the bottom to make it launch explorer if it’s passed a folder.

import subprocess
import win32clipboard as w
import os

#get the contents of the clipboard (horrible hack)
w.OpenClipboard()
d=w.GetClipboardData(w.CF_TEXT)
w.CloseClipboard()

print d

#set up the pattern matcher for "[x||x]" (it doesn't always come in nicely for some reason)
import re
re1='(\\[.*?\\])'
rg = re.compile(re1,re.IGNORECASE|re.DOTALL)
m = rg.search(d)
found=m.group(1)

#strip and split it, get the path
path = str.split(found[1:-1],'|')[0]
print path

if os.path.isdir(path):
 path = "explorer "+path
#launch it but don't wait
proc = subprocess.Popen([path], shell=True, stdin=None, stdout=None, stderr=None, close_fds=True)

Relay.py

All this file does is execute launch.py. Sadly it can’t be called directly because lyx hangs until the command returns which in turn makes the clipboard hang.

 import subprocess
 #launch it but don't wait (if you don't do this then the clipboard doesn't work properly because lyx hangs!
 proc = subprocess.Popen(["launch.py"], shell=True, stdin=None, stdout=None, stderr=None, close_fds=True)

Done

Restart lyx and try loading a local hyperlink, right click and select “Edit Externally…”. I’ll put in a filter for web links at some point. If it’s not working then try launching lyx from the command line with:

lyx -dbg server

and see what it spits out to the console.

Leave a Reply