You are not logged in.

#1 2016-01-12 00:55:41

tutu
Member
Registered: 2015-11-11
Posts: 30

Forward/inverse search with SyncTeX, vim-LaTeX-suite and llpp

I wrote some simple bash scripts that binds together llpp pdf viewer and  vim to do forward and inverse search in LaTeX documents. I tried to mimic the syncing functionalities of SumatraPDF (a windows only program), without changes to the source code of the vim plugin LaTeX-suite or lllpp.

To use the scripts, you can copy them to some place in your path (/home/bin or /usr/local/bin) and add the line

let g:Tex_ViewRule_pdf = join(['llpp-LaTeX-view.sh', fnameescape(getcwd())])

to your vimrc or tex.vim. You will also need to change the function Tex_ForwardSearchLaTeX() in /usr/share/vim/vimfiles/ftplugin/latex-suite/compiler.vim or add it to your tex.vim

function! Tex_ForwardSearchLaTeX()
	if &ft != 'tex'
		echo "calling Tex_ForwardSeachLaTeX from a non-tex file"
		return
	end

	if Tex_GetVarValue('Tex_ViewRule_'.s:target) == ''
		return
	endif
	let viewer = Tex_GetVarValue('Tex_ViewRule_'.s:target)

	let l:origdir = fnameescape(getcwd())

	let mainfnameRoot = fnameescape(fnamemodify(Tex_GetMainFileName(), ':t:r'))
	let mainfnameFull = fnameescape(Tex_GetMainFileName(':p:r'))
	let target_file = mainfnameFull . "." . s:target
	let sourcefile = fnameescape(expand('%'))
	let sourcefileFull = fnameescape(expand('%:p'))
	let linenr = line('.')
	" cd to the location of the file to avoid problems with directory name
	" containing spaces.
	call Tex_CD(Tex_GetMainFileName(':p:h'))

	" inverse search tips taken from Dimitri Antoniou's tip and Benji Fisher's
	" tips on vim.sf.net (vim.sf.net tip #225)
	let execString = 'silent! !'
	if (has('win32') && (viewer =~? '^ *yap\( \|$\)'))

		let execString .= Tex_Stringformat('start %s -s %s%s %s', viewer, linenr, sourcefile, mainfnameRoot)

	elseif (has('macunix') && (viewer =~ '^ *\(Skim\|PDFView\|TeXniscope\)\( \|$\)'))
		" We're on a Mac using a traditional Mac viewer

		if viewer =~ '^ *Skim'

				let execString .= '/Applications/Skim.app/Contents/SharedSupport/displayline '
				let execString .= join([curlLine, target_file, sourcefileFull])

		elseif viewer =~ '^ *PDFView'

				let execString .= '/Applications/PDFView.app/Contents/MacOS/gotoline.sh '
				let execString .= join([curlLine, target_file, sourcefileFull])

		elseif viewer =~ '^ *TeXniscope'

				let execString .= '/Applications/TeXniscope.app/Contents/Resources/forward-search.sh '
				let execString .= join([curlLine, sourcefileFull, target_file])

		endif

	else
		" We're either UNIX or Mac and using a UNIX-type viewer

		" Check for the special DVI viewers first
		if viewer =~ '^ *\(xdvi\|xdvik\|kdvi\|okular\)\( \|$\)'
			let execString .= viewer." "

			if Tex_GetVarValue('Tex_UseEditorSettingInDVIViewer') == 1 &&
						\ exists('v:servername') &&
						\ viewer =~ '^ *xdvik\?\( \|$\)'

				let execString .= Tex_Stringformat('-name xdvi -sourceposition "%s %s" -editor "gvim --servername %s --remote-silent +\%l \%f" %s', linenr, sourcefile, v:servername, target_file)

			elseif viewer =~ '^ *kdvi'

				let execString .= Tex_Stringformat('--unique file:%s\#src:%s%s', target_file, linenr, sourcefile)

			elseif viewer =~ '^ *xdvik\?\( \|$\)'

				let execString .= Tex_Stringformat('-name xdvi -sourceposition "%s %s" %s', linenr, sourcefile, target_file)

			elseif viewer =~ '^ *okular'

				let execString .= Tex_Stringformat('--unique %s\#src:%s%s', target_file, linenr, sourcefileFull)

			endif

		else
			" We must be using a generic UNIX viewer
			" syntax is: viewer TARGET_FILE LINE_NUMBER SOURCE_FILE

			" The line below was add it to the original Tex_ForwardSearchLaTeX() to make sure we use the defined viewer in the viewing rule
			let execString .= viewer." "
			let execString .= join([target_file, linenr, sourcefile])

		endif

		" See if we should add &. On Mac (at least in MacVim), it seems
		" like this should NOT be added...
		if( Tex_GetVarValue('Tex_ExecuteUNIXViewerInForeground') != 1 )
			let execString = execString.' &'
		endif

	endif
endfunction

I insert two lines to the original Tex_ForwardSearchLaTex() function:

			" The line below was add it to the original Tex_ForwardSearchLaTeX() to make sure we use the defined viewer in the viewing rule
			let execString .= viewer." "

as you can see from the function listed above. You can simplify this function if you are planning to use only llpp, but I prefer to include the original code from LaTeX-suite, this way more readers of this post would be able to locate where to make the change or use the function posted here.

To setup llpp, make sure that ~/.config/llpp.conf has the following line

synctex-command='SyncTeX-inverse.sh'

You will need the packages: bc and xdotool. We will also need vim, vim-latexsuite, synctex command from texlive-bin and the AUR package llpp-git.

Once the scripts are in place, you should be able to type \ls in vim to open llpp and highlight with a rectangle the position correspondent to the tex file. Conversely, if you shift+click in a pdf typeset with synctex flag, vim will open in the line of the corresponding click.

I wish I could remove the dependencies of bc and xdotool, but I still haven't figure out a way to avoid them. Also there is a known issue that I only have a workaround: if there is a non remote instance of llpp already opened, nothing happens when \ls is typed. To solve this, you can use \lv to open a remote instance of llpp first and then \ls. I'm open to suggestions if someone have a better idea or improvements to the scripts. I use LaTeX quite often to write mathematical papers, so please let me know any improvements or suggestions to improve those scripts.

I hope this helps someone that was having trouble with syncing functionality of LaTeX files.

llpp-latex-view.sh

#!/bin/bash
# This script is called by the TeX editor. It just calls SyncTeX which calls
# the viewing script of the specific PDF viewer. This script passes relevant
# parameters from SyncTeX to the viewer specific script. If the target_file is
# the only argument, then a new remote instance of llpp is created.

# Assumptions:
# 1) The target_file can be a file on the current directory or the absolute
#    path to the pdf file.
# 2) The source_file is a relative path based on vim working directory
#    (vim_path).
# 3) The vim_path must be the path to vim working directory. If omitted, it
#    defaults to the environment variable PWD.

# Input variables --------------------------------------------------------------
if (( $# == 1 || $# == 3 ));  then
    vim_path=$PWD
else
    vim_path=$(realpath $1)
fi
target_file=$2
linenr=$3
source_file=$4
# ------------------------------------------------------------------------------

# Local variables --------------------------------------------------------------
remote_file=/tmp/llpp.remote
# ------------------------------------------------------------------------------

# Find the relative path to source based on target_file location ---------------
dirPdf="$(dirname $(realpath $target_file))"
aPathToSrc="$vim_path/$source_file"
rPathFromPdfToSrc=${aPathToSrc#$dirPdf/}
# ------------------------------------------------------------------------------

# Call SyncTeX view command ----------------------------------------------------
if (( $# < 3 )); then

    rm -f $remote_file   # Delete previous remote file
    mkfifo $remote_file  # and create a new one

    llpp -remote $remote_file $target_file &  # Open llpp

else

    synctex view -i "$linenr:0:$rPathFromPdfToSrc" -o "$target_file" \
                 -x "llpp-SyncTeX.sh $target_file %{page} %{x} %{y} %{h} %{v} \
                                                  %{width} %{height}"

fi
# ------------------------------------------------------------------------------

llpp-SyncTeX.sh

#!/bin/bash
# llpp viewing script.
#
# It is necessary to have the following installed:
#   1) xdotool: find a llpp window. If it is associated to the remote file then
#      it is used to do the syncing.
#   2) bc: Used to do the numerical calulations.
#
# Known limitations
#   1) If there is a llpp window open and no one associated to the remote file,
#      nothing happens.

# Input variables --------------------------------------------------------------
target_file=$1
page=$2
x=$3
y=$4
h=$5
v=$6
width=$7
height=$8
# ------------------------------------------------------------------------------

# Local variables --------------------------------------------------------------
win_id=$(xdotool search --class "llpp")
remote_file="/tmp/llpp.remote"
# ------------------------------------------------------------------------------

# Look of the rectangle --------------------------------------------------------
red=0.7
green=0.7
blue=0.0
transparency=0.5
color="$red $green $blue $transparency"
# ------------------------------------------------------------------------------

# Calculating the top-left (x0,y0) and bottom-right (x1,y1) of the rectangle ---
x0=$h
y0=$(echo $v-$height | bc) 
x1=$(echo $h+$width | bc)
y1=$v
llpp_rect="echo prect $page $color $x0 $y0 $x1 $y1"
# ------------------------------------------------------------------------------

# Calculating coordinates to display the rectangle -----------------------------
goto_x=$(echo 0.95*$x0 | bc)
goto_y=$(echo 0.95*$y0 | bc)
llpp_goto="echo pgoto $page $goto_x $goto_y"
# ------------------------------------------------------------------------------

# Executing remote commands ----------------------------------------------------
if [ -z $win_id ]; then
	rm -f $remote_file   # Delete previous remote file
	mkfifo $remote_file  # and create a new one

        llpp -remote $remote_file $target_file &  # Open llpp

        echo clearrects > $remote_file  # Clear any previous rectangles
        sleep 0.1s                      # Wait until llpp is ready
        $llpp_goto > $remote_file       # Move page to desired place
        $llpp_rect > $remote_file       # Draw rectangle
else
        echo clearrects > $remote_file   # Clear any previous rectangles
	echo activatewin > $remote_file  # Activate llpp's window
        $llpp_goto > $remote_file        # Move page to desired place
        $llpp_rect > $remote_file        # Draw rectangle
fi
# ------------------------------------------------------------------------------

SyncTeX-inverse.sh

#!/bin/bash
# This script is called by the PDF viewer. It just calls SyncTeX, which evokes
# vim with synctex as server name. Other editors can also be used if the lines
# below are changed accordingly.

# Input variables --------------------------------------------------------------
pdf_file=$1
page=$(($2 + 1))  # This input is expected to start at zero
x=$3
y=$4
# ------------------------------------------------------------------------------

# Call SyncTeX edit command ----------------------------------------------------
synctex edit -o "$page:$x:$y:$pdf_file" \
        -x "gvim --servername synctex --remote-wait-silent +%{line} %{input}"
# ------------------------------------------------------------------------------

Last edited by tutu (2016-04-06 21:34:46)

Offline

#2 2016-06-12 11:11:21

navi_se
Member
Registered: 2015-07-06
Posts: 135

Re: Forward/inverse search with SyncTeX, vim-LaTeX-suite and llpp

Is the plugin LaTeX-suite for VIM strictly required?

Offline

#3 2016-06-12 18:07:52

tutu
Member
Registered: 2015-11-11
Posts: 30

Re: Forward/inverse search with SyncTeX, vim-LaTeX-suite and llpp

The scripts work directly from the command line. I use latex-suite to capture the current line I'm editing, the name of the TeX and PDF file. If you pass this information to the script it will have the same result as using latex-suite.

In other words, you can use this with different editors as well but you need to understand how your editor works to call external scripts and pass the information to llpp-latex-view.sh script.

Offline

#4 2016-06-12 18:22:57

Monoïde
Member
Registered: 2015-05-19
Posts: 2

Re: Forward/inverse search with SyncTeX, vim-LaTeX-suite and llpp

I consider vim-latexsuit pretty bad. It does too much useless stuff and nothing really helpful in my opinion. I am very happy to be a daily user of LaTeX-Box. By very far the very best LaTeX plugin for vim.

Because it seems to follow the topic, here is how I do (with Okular)
Backward search:
I launch vim in servermode, vim --servername tex
I added vim –servername tex –remote +%l %f in okular > settings > editor
Forward:
I put something like this in my tex.vim

tex.vim wrote:

[...]
function! SyncTexForward()
  let s:syncfile = LatexBox_GetOutputFile()
  let execstr = "silent !okular --unique ".s:syncfile."\\#src:".line(".").expand("%\:p").' >/dev/null&'
  exec execstr
endfunction
[...]

Of course, I take care of my latexmk.rc

$pdflatex="xelatex -halt-on-error -src-specials -synctex=1 %O %S";
[...]

Offline

#5 2016-06-12 18:38:17

tutu
Member
Registered: 2015-11-11
Posts: 30

Re: Forward/inverse search with SyncTeX, vim-LaTeX-suite and llpp

The point of the thread is not really which plugin you use to edit LaTeX, for sure there is a few a round. The idea is how to use a PDF viewer that do not use synctex libs and instead use the synctex binary that comes with texlive-bin.

I think okular is a fine PDF viewer, but llpp fits me better and, unfortunately, it does not use synctex libs. In the other hand, it uses mupdf to render PDF files. That's why I wrote some scripts to help me out. Ideally the scripts would not exist and everything would be done inside llpp using synctex libs.

Offline

Board footer

Powered by FluxBB