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.
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.