Fixed #551: Ensure fully buffer local variables

This commit also involves a strong refactoring of the viewer code,
where individual viewers (general, mupdf, zathura) are separated into
individual modules. This makes it easier to distinguish common and
specialized code, as well as making the viewer interfaces clearer.
This commit is contained in:
Karl Yngve Lervåg 2016-09-17 12:43:37 +02:00
parent 4df9f85e45
commit 4ba99f83bd
5 changed files with 576 additions and 548 deletions

View File

@ -4,15 +4,6 @@
" Email: karl.yngve@gmail.com
"
let s:viewers = [
\ 'general',
\ 'mupdf',
\ 'zathura',
\ ]
for viewer in s:viewers
execute 'let s:' . viewer . ' = {}'
endfor
function! vimtex#view#init_options() " {{{1
call vimtex#util#set_default('g:vimtex_view_enabled', 1)
if !g:vimtex_view_enabled | return | endif
@ -21,37 +12,32 @@ function! vimtex#view#init_options() " {{{1
call vimtex#util#set_default('g:vimtex_view_use_temp_files', 0)
endfunction
" }}}1
function! vimtex#view#init_script() " {{{1
endfunction
" }}}1
function! vimtex#view#init_buffer() " {{{1
if !g:vimtex_view_enabled | return | endif
"
" Add viewer to the data blob
" Add viewer to the data blob (if it does not already exist)
"
if !has_key(b:vimtex, 'viewer')
let viewer = 's:' . g:vimtex_view_method
if !exists(viewer)
try
let b:vimtex.viewer = vimtex#view#{g:vimtex_view_method}#new()
catch /E117/
call vimtex#echo#warning('viewer '
\ . g:vimtex_view_method . ' does not exist!')
call vimtex#echo#echo('- Please see :h g:vimtex_view_method')
call vimtex#echo#wait()
let b:vimtex.viewer = {}
return
endif
endtry
execute 'let b:vimtex.viewer = ' . viewer
call b:vimtex.viewer.init()
" Make the following code more concise
let l:v = b:vimtex.viewer
"
" Add latexmk callback to callback hooks (if it exists)
"
if exists('*b:vimtex.viewer.latexmk_callback')
call add(g:vimtex_latexmk_callback_hooks,
\ 'b:vimtex.viewer.latexmk_callback')
if exists('*l:v.latexmk_callback')
call add(g:vimtex_latexmk_callback_hooks, 'l:v.latexmk_callback')
endif
"
@ -63,7 +49,7 @@ function! vimtex#view#init_buffer() " {{{1
if exists(hook)
execute 'let hookfunc = ''*'' . ' . hook
if exists(hookfunc)
execute 'let b:vimtex.viewer.hook_' . point . ' = function(' . hook . ')'
execute 'let l:v.hook_' . point . ' = function(' . hook . ')'
endif
endif
endfor
@ -92,528 +78,4 @@ endfunction
" }}}1
"
" Define viewers
"
" {{{1 General
function! s:general.init() dict " {{{2
"
" Set default options
"
call vimtex#util#set_default_os_specific('g:vimtex_view_general_viewer',
\ {
\ 'linux' : 'xdg-open',
\ 'mac' : 'open',
\ })
call vimtex#util#set_default('g:vimtex_view_general_options', '@pdf')
call vimtex#util#set_default('g:vimtex_view_general_options_latexmk', '')
if exists('g:vimtex_view_general_callback')
let self.latexmk_callback = function(g:vimtex_view_general_callback)
endif
if !executable(g:vimtex_view_general_viewer)
call vimtex#echo#warning('viewer "'
\ . g:vimtex_view_general_viewer . '" is not executable!')
call vimtex#echo#echo('- Please see :h g:vimtex_view_general_viewer')
call vimtex#echo#wait()
endif
if g:vimtex_view_use_temp_files
let self.out = b:vimtex.root . '/' . b:vimtex.name . '_vimtex.pdf'
let self.synctex = fnamemodify(self.out, ':r') . '.synctex.gz'
let self.copy_files = function('s:copy_files')
else
let self.out = b:vimtex.out()
let self.synctex = b:vimtex.ext('synctex.gz')
endif
endfunction
" }}}2
function! s:general.view(file) dict " {{{2
if empty(a:file)
let outfile = self.out
" Only copy files if they don't exist
if g:vimtex_view_use_temp_files
\ && s:output_not_readable(outfile)
call self.copy_files()
endif
else
let outfile = a:file
endif
if s:output_not_readable(outfile) | return | endif
" Parse options
let opts = g:vimtex_view_general_options
let opts = substitute(opts, '@line', line('.'), 'g')
let opts = substitute(opts, '@col', col('.'), 'g')
let opts = substitute(opts, '@tex',
\ vimtex#util#shellescape(expand('%:p')), 'g')
let opts = substitute(opts, '@pdf', vimtex#util#shellescape(outfile), 'g')
" Construct the command
let exe = {}
let exe.cmd = g:vimtex_view_general_viewer . ' ' . opts
call vimtex#util#execute(exe)
let self.cmd_view = exe.cmd
if has_key(self, 'hook_view')
call self.hook_view()
endif
endfunction
" }}}2
function! s:general.latexmk_append_argument() dict " {{{2
if g:vimtex_view_use_temp_files
return ' -view=none'
else
let l:option = g:vimtex_view_general_viewer
if !empty(g:vimtex_view_general_options_latexmk)
let l:option .= ' '
let l:option .= substitute(g:vimtex_view_general_options_latexmk,
\ '@line', line('.'), 'g')
endif
return vimtex#latexmk#add_option('pdf_previewer', l:option)
endif
endfunction
" }}}2
" }}}1
" {{{1 MuPDF
function! s:mupdf.init() dict " {{{2
" Only initialize once
if has_key(self, 'xwin_id') | return | endif
"
" Default MuPDF settings
"
call vimtex#util#set_default('g:vimtex_view_mupdf_options', '')
call vimtex#util#set_default('g:vimtex_view_mupdf_send_keys', '')
if !executable('mupdf')
call vimtex#echo#warning('MuPDF is not executable!')
call vimtex#echo#echo('- vimtex viewer will not work!')
call vimtex#echo#wait()
endif
if !executable('xdotool')
call vimtex#echo#warning('viewer MuPDF requires xdotool!')
endif
if g:vimtex_view_use_temp_files
let self.out = b:vimtex.root . '/' . b:vimtex.name . '_vimtex.pdf'
let self.synctex = fnamemodify(self.out, ':r') . '.synctex.gz'
let self.copy_files = function('s:copy_files')
else
let self.out = b:vimtex.out()
let self.synctex = b:vimtex.ext('synctex.gz')
endif
let self.class = 'MuPDF'
let self.xwin_id = 0
let self.view = function('s:view')
let self.xwin_exists = function('s:xwin_exists')
let self.xwin_get_id = function('s:xwin_get_id')
let self.xwin_send_keys = function('s:xwin_send_keys')
let self.focus_vim = function('s:focus_vim')
let self.focus_viewer = function('s:focus_viewer')
call self.xwin_exists()
endfunction
" }}}2
function! s:mupdf.start(outfile) dict " {{{2
let exe = {}
let exe.cmd = 'mupdf ' . g:vimtex_view_mupdf_options
let exe.cmd .= ' ' . vimtex#util#shellescape(a:outfile)
call vimtex#util#execute(exe)
let self.cmd_start = exe.cmd
call self.xwin_get_id()
call self.xwin_send_keys(g:vimtex_view_mupdf_send_keys)
call self.forward_search(a:outfile)
endfunction
" }}}2
function! s:mupdf.forward_search(outfile) dict " {{{2
if !executable('xdotool') | return | endif
if !executable('synctex') | return | endif
let self.cmd_synctex_view = 'synctex view -i '
\ . (line('.') + 1) . ':'
\ . (col('.') + 1) . ':'
\ . vimtex#util#shellescape(expand('%:p'))
\ . ' -o ' . vimtex#util#shellescape(a:outfile)
\ . " | grep -m1 'Page:' | sed 's/Page://' | tr -d '\n'"
let self.page = system(self.cmd_synctex_view)
if self.page > 0
let exe = {}
let exe.cmd = 'xdotool'
let exe.cmd .= ' type --window ' . self.xwin_id
let exe.cmd .= ' "' . self.page . 'g"'
call vimtex#util#execute(exe)
let self.cmd_forward_search = exe.cmd
endif
call self.focus_viewer()
endfunction
" }}}2
function! s:mupdf.reverse_search() dict " {{{2
if !executable('xdotool') | return | endif
if !executable('synctex') | return | endif
let outfile = b:vimtex.out()
if s:output_not_readable(outfile) | return | endif
if !self.xwin_exists()
call vimtex#echo#warning('reverse search failed (is MuPDF open?)')
return
endif
" Get page number
let self.cmd_getpage = 'xdotool getwindowname ' . self.xwin_id
let self.cmd_getpage .= " | sed 's:.* - \\([0-9]*\\)/.*:\\1:'"
let self.cmd_getpage .= " | tr -d '\n'"
let self.page = system(self.cmd_getpage)
if self.page <= 0 | return | endif
" Get file
let self.cmd_getfile = 'synctex edit '
let self.cmd_getfile .= "-o \"" . self.page . ':288:108:' . outfile . "\""
let self.cmd_getfile .= "| grep 'Input:' | sed 's/Input://' "
let self.cmd_getfile .= "| head -n1 | tr -d '\n' 2>/dev/null"
let self.file = system(self.cmd_getfile)
" Get line
let self.cmd_getline = 'synctex edit '
let self.cmd_getline .= "-o \"" . self.page . ':288:108:' . outfile . "\""
let self.cmd_getline .= "| grep -m1 'Line:' | sed 's/Line://' "
let self.cmd_getline .= "| head -n1 | tr -d '\n'"
let self.line = system(self.cmd_getline)
" Go to file and line
silent exec 'edit ' . fnameescape(self.file)
if self.line > 0
silent exec ':' . self.line
" Unfold, move to top line to correspond to top pdf line, and go to end of
" line in case the corresponding pdf line begins on previous pdf page.
normal! zvztg_
endif
endfunction
" }}}2
function! s:mupdf.latexmk_callback(status) dict " {{{2
if !a:status | return | endif
if g:vimtex_view_use_temp_files
call self.copy_files()
else
"
" Search for existing window created by latexmk
" It may be necessary to wait some time before it is opened and
" recognized. Sometimes it is very quick, other times it may take
" a second. This way, we don't block longer than necessary.
"
if !has_key(self, 'started_through_callback')
for l:dummy in range(30)
sleep 50m
if self.xwin_exists() | break | endif
endfor
endif
endif
if !self.xwin_exists() && !has_key(self, 'started_through_callback')
call self.start(self.out)
let self.started_through_callback = 1
endif
if g:vimtex_view_use_temp_files
call self.xwin_send_keys('r')
endif
call self.xwin_send_keys(g:vimtex_view_mupdf_send_keys)
if has_key(self, 'hook_callback')
call self.hook_callback()
endif
endfunction
" }}}2
function! s:mupdf.latexmk_append_argument() dict " {{{2
if g:vimtex_view_use_temp_files
let cmd = ' -view=none'
else
let cmd = vimtex#latexmk#add_option('new_viewer_always', '0')
let cmd .= vimtex#latexmk#add_option('pdf_update_method', '2')
let cmd .= vimtex#latexmk#add_option('pdf_update_signal', 'SIGHUP')
let cmd .= vimtex#latexmk#add_option('pdf_previewer',
\ 'mupdf ' . g:vimtex_view_mupdf_options)
endif
return cmd
endfunction
" }}}2
" }}}1
" {{{1 Zathura
function! s:zathura.init() dict " {{{2
" Only initialize once
if has_key(self, 'xwin_id') | return | endif
"
" Default Zathura settings
"
call vimtex#util#set_default('g:vimtex_view_zathura_options', '')
if !executable('zathura')
call vimtex#echo#warning('Zathura is not executable!')
call vimtex#echo#echo('- vimtex viewer will not work!')
call vimtex#echo#wait()
endif
if !executable('xdotool')
call vimtex#echo#warning('viewer Zathura requires xdotool!')
endif
if g:vimtex_view_use_temp_files
let self.out = b:vimtex.root . '/' . b:vimtex.name . '_vimtex.pdf'
let self.synctex = fnamemodify(self.out, ':r') . '.synctex.gz'
let self.copy_files = function('s:copy_files')
else
let self.out = b:vimtex.out()
let self.synctex = b:vimtex.ext('synctex.gz')
endif
let self.class = 'Zathura'
let self.xwin_id = 0
let self.view = function('s:view')
let self.xwin_get_id = function('s:xwin_get_id')
let self.xwin_exists = function('s:xwin_exists')
call self.xwin_exists()
endfunction
" }}}2
function! s:zathura.start(outfile) dict " {{{2
let exe = {}
let exe.cmd = 'zathura'
let exe.cmd .= ' -x "' . g:vimtex_latexmk_progname
\ . ' --servername ' . v:servername
\ . ' --remote +\%{line} \%{input}"'
let exe.cmd .= ' ' . g:vimtex_view_zathura_options
let exe.cmd .= ' ' . vimtex#util#shellescape(a:outfile)
call vimtex#util#execute(exe)
let self.cmd_start = exe.cmd
call self.xwin_get_id()
call self.forward_search(a:outfile)
endfunction
" }}}2
function! s:zathura.forward_search(outfile) dict " {{{2
if !filereadable(self.synctex) | return | endif
let exe = {}
let exe.cmd = 'zathura --synctex-forward '
let exe.cmd .= line('.')
let exe.cmd .= ':' . col('.')
let exe.cmd .= ':' . vimtex#util#shellescape(expand('%:p'))
let exe.cmd .= ' ' . vimtex#util#shellescape(a:outfile)
call vimtex#util#execute(exe)
let self.cmd_forward_search = exe.cmd
endfunction
" }}}2
function! s:zathura.latexmk_callback(status) dict " {{{2
if !a:status | return | endif
if g:vimtex_view_use_temp_files
call self.copy_files()
else
"
" Search for existing window created by latexmk
" It may be necessary to wait some time before it is opened and
" recognized. Sometimes it is very quick, other times it may take
" a second. This way, we don't block longer than necessary.
"
if !has_key(self, 'started_through_callback')
for l:dummy in range(30)
sleep 50m
if self.xwin_exists() | break | endif
endfor
endif
endif
if !self.xwin_exists() && !has_key(self, 'started_through_callback')
call self.start(self.out)
let self.started_through_callback = 1
endif
if has_key(self, 'hook_callback')
call self.hook_callback()
endif
endfunction
" }}}2
function! s:zathura.latexmk_append_argument() dict " {{{2
if g:vimtex_view_use_temp_files
let cmd = ' -view=none'
else
let cmd = vimtex#latexmk#add_option('new_viewer_always', '0')
let cmd .= vimtex#latexmk#add_option('pdf_previewer',
\ 'zathura ' . g:vimtex_view_zathura_options
\ . ' -x \"' . g:vimtex_latexmk_progname
\ . ' --servername ' . v:servername
\ . ' --remote +\%{line} \%{input}\" \%S')
endif
return cmd
endfunction
" }}}2
" }}}1
"
" Common functionality
"
function! s:view(file) dict " {{{1
if empty(a:file)
let outfile = self.out
else
let outfile = a:file
endif
if s:output_not_readable(outfile) | return | endif
if self.xwin_exists()
call self.forward_search(outfile)
else
if g:vimtex_view_use_temp_files
call self.copy_files()
endif
call self.start(outfile)
endif
if has_key(self, 'hook_view')
call self.hook_view()
endif
endfunction
" }}}1
function! s:output_not_readable(output) " {{{1
if !filereadable(a:output)
call vimtex#echo#warning('viewer can not read PDF file!')
return 1
else
return 0
endif
endfunction
" }}}1
function! s:xwin_get_id() dict " {{{1
if !executable('xdotool') | return 0 | endif
if self.xwin_id > 0 | return self.xwin_id | endif
" Allow some time for the viewer to start properly
sleep 500m
"
" Get the window ID
"
let cmd = 'xdotool search --class ' . self.class
let xwin_ids = split(system(cmd), '\n')
if len(xwin_ids) == 0
call vimtex#echo#warning(
\ 'viewer can not find ' . self.class . ' window ID!')
let self.xwin_id = 0
else
let self.xwin_id = xwin_ids[-1]
endif
return self.xwin_id
endfunction
" }}}1
function! s:xwin_exists() dict " {{{1
if !executable('xdotool') | return 0 | endif
"
" If xwin_id is already set, check if it still exists
"
if self.xwin_id > 0
let cmd = 'xdotool search --class ' . self.class
if index(split(system(cmd), '\n'), self.xwin_id) < 0
let self.xwin_id = 0
endif
endif
"
" If xwin_id is unset, check if matching viewer windows exist
"
if self.xwin_id == 0
let cmd = 'xdotool search --name ' . fnamemodify(self.out, ':t')
let result = split(system(cmd), '\n')
if len(result) > 0
let self.xwin_id = result[-1]
endif
endif
return (self.xwin_id > 0)
endfunction
" }}}1
function! s:xwin_send_keys(keys) dict " {{{1
if !executable('xdotool') | return | endif
if a:keys !=# ''
let cmd = 'xdotool key --window ' . self.xwin_id
let cmd .= ' ' . a:keys
silent call system(cmd)
endif
endfunction
" }}}1
function! s:copy_files() dict " {{{1
"
" Copy pdf file
"
if getftime(b:vimtex.out()) > getftime(self.out)
call writefile(readfile(b:vimtex.out(), 'b'), self.out, 'b')
endif
"
" Copy synctex file
"
let l:old = b:vimtex.ext('synctex.gz')
if getftime(l:old) > getftime(self.synctex)
call rename(l:old, self.synctex)
endif
endfunction
" }}}1
"
" Hook functions (used as default hooks in some cases)
"
function! s:focus_viewer() dict " {{{1
if !executable('xdotool') | return | endif
if self.xwin_id > 0
silent call system('xdotool windowfocus ' . self.xwin_id . ' --sync')
silent call system('xdotool windowraise ' . self.xwin_id)
endif
endfunction
" }}}1
function! s:focus_vim() dict " {{{1
if !executable('xdotool') | return | endif
silent call system('xdotool windowfocus ' . v:windowid . ' --sync')
silent call system('xdotool windowraise ' . v:windowid)
endfunction
" }}}1
" vim: fdm=marker sw=2

View File

@ -0,0 +1,142 @@
" vimtex - LaTeX plugin for Vim
"
" Maintainer: Karl Yngve Lervåg
" Email: karl.yngve@gmail.com
"
function! vimtex#view#common#apply_xwin_template(class, viewer) " {{{1
let a:viewer.class = a:class
let a:viewer.xwin_id = 0
call extend(a:viewer, deepcopy(s:xwin_template))
call a:viewer.xwin_exists()
return a:viewer
endfunction
" }}}1
function! vimtex#view#common#use_temp_files_p(viewer) " {{{1
if g:vimtex_view_use_temp_files
let a:viewer.out = b:vimtex.root . '/' . b:vimtex.name . '_vimtex.pdf'
let a:viewer.synctex = fnamemodify(a:viewer.out, ':r') . '.synctex.gz'
let a:viewer.copy_files = function('s:copy_files')
else
let a:viewer.out = b:vimtex.out()
let a:viewer.synctex = b:vimtex.ext('synctex.gz')
endif
return a:viewer
endfunction
" }}}1
let s:xwin_template = {}
function! s:xwin_template.view(file) dict " {{{1
if empty(a:file)
let outfile = self.out
else
let outfile = a:file
endif
if !filereadable(outfile)
call vimtex#echo#warning('viewer can not read PDF file!')
return
endif
if self.xwin_exists()
call self.forward_search(outfile)
else
if g:vimtex_view_use_temp_files
call self.copy_files()
endif
call self.start(outfile)
endif
if has_key(self, 'hook_view')
call self.hook_view()
endif
endfunction
" }}}1
function! s:xwin_template.xwin_get_id() dict " {{{1
if !executable('xdotool') | return 0 | endif
if self.xwin_id > 0 | return self.xwin_id | endif
" Allow some time for the viewer to start properly
sleep 500m
"
" Get the window ID
"
let cmd = 'xdotool search --class ' . self.class
let xwin_ids = split(system(cmd), '\n')
if len(xwin_ids) == 0
call vimtex#echo#warning(
\ 'viewer can not find ' . self.class . ' window ID!')
let self.xwin_id = 0
else
let self.xwin_id = xwin_ids[-1]
endif
return self.xwin_id
endfunction
" }}}1
function! s:xwin_template.xwin_exists() dict " {{{1
if !executable('xdotool') | return 0 | endif
"
" If xwin_id is already set, check if it still exists
"
if self.xwin_id > 0
let cmd = 'xdotool search --class ' . self.class
if index(split(system(cmd), '\n'), self.xwin_id) < 0
let self.xwin_id = 0
endif
endif
"
" If xwin_id is unset, check if matching viewer windows exist
"
if self.xwin_id == 0
let cmd = 'xdotool search --name ' . fnamemodify(self.out, ':t')
let result = split(system(cmd), '\n')
if len(result) > 0
let self.xwin_id = result[-1]
endif
endif
return (self.xwin_id > 0)
endfunction
" }}}1
function! s:xwin_template.xwin_send_keys(keys) dict " {{{1
if !executable('xdotool') | return | endif
if a:keys !=# ''
let cmd = 'xdotool key --window ' . self.xwin_id
let cmd .= ' ' . a:keys
silent call system(cmd)
endif
endfunction
" }}}1
function! s:copy_files() dict " {{{1
"
" Copy pdf file
"
if getftime(b:vimtex.out()) > getftime(self.out)
call writefile(readfile(b:vimtex.out(), 'b'), self.out, 'b')
endif
"
" Copy synctex file
"
let l:old = b:vimtex.ext('synctex.gz')
if getftime(l:old) > getftime(self.synctex)
call rename(l:old, self.synctex)
endif
endfunction
" }}}1
" vim: fdm=marker sw=2

View File

@ -0,0 +1,110 @@
" vimtex - LaTeX plugin for Vim
"
" Maintainer: Karl Yngve Lervåg
" Email: karl.yngve@gmail.com
"
function! vimtex#view#general#new() " {{{1
"
" Set default options
"
call vimtex#util#set_default_os_specific('g:vimtex_view_general_viewer',
\ {
\ 'linux' : 'xdg-open',
\ 'mac' : 'open',
\ })
call vimtex#util#set_default('g:vimtex_view_general_options', '@pdf')
call vimtex#util#set_default('g:vimtex_view_general_options_latexmk', '')
"
" Check if the viewer is executable
"
if !executable(g:vimtex_view_general_viewer)
call vimtex#echo#warning('viewer "'
\ . g:vimtex_view_general_viewer . '" is not executable!')
call vimtex#echo#echo('- Please see :h g:vimtex_view_general_viewer')
call vimtex#echo#wait()
return {}
endif
"
" Start from standard template
"
let l:viewer = vimtex#view#common#use_temp_files_p(deepcopy(s:general))
"
" Add callback hook
"
if exists('g:vimtex_view_general_callback')
let l:viewer.latexmk_callback = function(g:vimtex_view_general_callback)
endif
return l:viewer
endfunction
" }}}1
let s:general = {}
function! s:general.view(file) dict " {{{1
if empty(a:file)
let outfile = self.out
" Only copy files if they don't exist
if g:vimtex_view_use_temp_files
\ && s:output_not_readable(outfile)
call self.copy_files()
endif
else
let outfile = a:file
endif
if s:output_not_readable(outfile) | return | endif
" Parse options
let opts = g:vimtex_view_general_options
let opts = substitute(opts, '@line', line('.'), 'g')
let opts = substitute(opts, '@col', col('.'), 'g')
let opts = substitute(opts, '@tex',
\ vimtex#util#shellescape(expand('%:p')), 'g')
let opts = substitute(opts, '@pdf', vimtex#util#shellescape(outfile), 'g')
" Construct the command
let exe = {}
let exe.cmd = g:vimtex_view_general_viewer . ' ' . opts
call vimtex#util#execute(exe)
let self.cmd_view = exe.cmd
if has_key(self, 'hook_view')
call self.hook_view()
endif
endfunction
" }}}1
function! s:general.latexmk_append_argument() dict " {{{1
if g:vimtex_view_use_temp_files
return ' -view=none'
else
let l:option = g:vimtex_view_general_viewer
if !empty(g:vimtex_view_general_options_latexmk)
let l:option .= ' '
let l:option .= substitute(g:vimtex_view_general_options_latexmk,
\ '@line', line('.'), 'g')
endif
return vimtex#latexmk#add_option('pdf_previewer', l:option)
endif
endfunction
" }}}1
function! s:output_not_readable(output) " {{{1
if !filereadable(a:output)
call vimtex#echo#warning('viewer can not read PDF file!')
return 1
else
return 0
endif
endfunction
" }}}1
" vim: fdm=marker sw=2

View File

@ -0,0 +1,194 @@
" vimtex - LaTeX plugin for Vim
"
" Maintainer: Karl Yngve Lervåg
" Email: karl.yngve@gmail.com
"
function! vimtex#view#mupdf#new() " {{{1
"
" Set default options
"
call vimtex#util#set_default('g:vimtex_view_mupdf_options', '')
call vimtex#util#set_default('g:vimtex_view_mupdf_send_keys', '')
"
" Check if the viewer is executable
"
if !executable('mupdf')
call vimtex#echo#warning('MuPDF is not executable!')
call vimtex#echo#echo('- vimtex viewer will not work!')
call vimtex#echo#wait()
return {}
endif
"
" Check if the xdotool is available
"
if !executable('xdotool')
call vimtex#echo#warning('MuPDF requires xdotool!')
return {}
endif
"
" Use the xwin template
"
return vimtex#view#common#apply_xwin_template('MuPDF',
\ vimtex#view#common#use_temp_files_p(deepcopy(s:mupdf)))
endfunction
" }}}1
let s:mupdf = {}
function! s:mupdf.start(outfile) dict " {{{1
let exe = {}
let exe.cmd = 'mupdf ' . g:vimtex_view_mupdf_options
let exe.cmd .= ' ' . vimtex#util#shellescape(a:outfile)
call vimtex#util#execute(exe)
let self.cmd_start = exe.cmd
call self.xwin_get_id()
call self.xwin_send_keys(g:vimtex_view_mupdf_send_keys)
call self.forward_search(a:outfile)
endfunction
" }}}1
function! s:mupdf.forward_search(outfile) dict " {{{1
if !executable('xdotool') | return | endif
if !executable('synctex') | return | endif
let self.cmd_synctex_view = 'synctex view -i '
\ . (line('.') + 1) . ':'
\ . (col('.') + 1) . ':'
\ . vimtex#util#shellescape(expand('%:p'))
\ . ' -o ' . vimtex#util#shellescape(a:outfile)
\ . " | grep -m1 'Page:' | sed 's/Page://' | tr -d '\n'"
let self.page = system(self.cmd_synctex_view)
if self.page > 0
let exe = {}
let exe.cmd = 'xdotool'
let exe.cmd .= ' type --window ' . self.xwin_id
let exe.cmd .= ' "' . self.page . 'g"'
call vimtex#util#execute(exe)
let self.cmd_forward_search = exe.cmd
endif
call self.focus_viewer()
endfunction
" }}}1
function! s:mupdf.reverse_search() dict " {{{1
if !executable('xdotool') | return | endif
if !executable('synctex') | return | endif
let outfile = b:vimtex.out()
if s:output_not_readable(outfile) | return | endif
if !self.xwin_exists()
call vimtex#echo#warning('reverse search failed (is MuPDF open?)')
return
endif
" Get page number
let self.cmd_getpage = 'xdotool getwindowname ' . self.xwin_id
let self.cmd_getpage .= " | sed 's:.* - \\([0-9]*\\)/.*:\\1:'"
let self.cmd_getpage .= " | tr -d '\n'"
let self.page = system(self.cmd_getpage)
if self.page <= 0 | return | endif
" Get file
let self.cmd_getfile = 'synctex edit '
let self.cmd_getfile .= "-o \"" . self.page . ':288:108:' . outfile . "\""
let self.cmd_getfile .= "| grep 'Input:' | sed 's/Input://' "
let self.cmd_getfile .= "| head -n1 | tr -d '\n' 2>/dev/null"
let self.file = system(self.cmd_getfile)
" Get line
let self.cmd_getline = 'synctex edit '
let self.cmd_getline .= "-o \"" . self.page . ':288:108:' . outfile . "\""
let self.cmd_getline .= "| grep -m1 'Line:' | sed 's/Line://' "
let self.cmd_getline .= "| head -n1 | tr -d '\n'"
let self.line = system(self.cmd_getline)
" Go to file and line
silent exec 'edit ' . fnameescape(self.file)
if self.line > 0
silent exec ':' . self.line
" Unfold, move to top line to correspond to top pdf line, and go to end of
" line in case the corresponding pdf line begins on previous pdf page.
normal! zvztg_
endif
endfunction
" }}}1
function! s:mupdf.latexmk_callback(status) dict " {{{1
if !a:status | return | endif
if g:vimtex_view_use_temp_files
call self.copy_files()
else
"
" Search for existing window created by latexmk
" It may be necessary to wait some time before it is opened and
" recognized. Sometimes it is very quick, other times it may take
" a second. This way, we don't block longer than necessary.
"
if !has_key(self, 'started_through_callback')
for l:dummy in range(30)
sleep 50m
if self.xwin_exists() | break | endif
endfor
endif
endif
if !self.xwin_exists() && !has_key(self, 'started_through_callback')
call self.start(self.out)
let self.started_through_callback = 1
endif
if g:vimtex_view_use_temp_files
call self.xwin_send_keys('r')
endif
call self.xwin_send_keys(g:vimtex_view_mupdf_send_keys)
if has_key(self, 'hook_callback')
call self.hook_callback()
endif
endfunction
" }}}1
function! s:mupdf.latexmk_append_argument() dict " {{{1
if g:vimtex_view_use_temp_files
let cmd = ' -view=none'
else
let cmd = vimtex#latexmk#add_option('new_viewer_always', '0')
let cmd .= vimtex#latexmk#add_option('pdf_update_method', '2')
let cmd .= vimtex#latexmk#add_option('pdf_update_signal', 'SIGHUP')
let cmd .= vimtex#latexmk#add_option('pdf_previewer',
\ 'mupdf ' . g:vimtex_view_mupdf_options)
endif
return cmd
endfunction
" }}}1
function! s:mupdf.focus_viewer() dict " {{{1
if !executable('xdotool') | return | endif
if self.xwin_id > 0
silent call system('xdotool windowfocus ' . self.xwin_id . ' --sync')
silent call system('xdotool windowraise ' . self.xwin_id)
endif
endfunction
" }}}1
function! s:mupdf.focus_vim() dict " {{{1
if !executable('xdotool') | return | endif
silent call system('xdotool windowfocus ' . v:windowid . ' --sync')
silent call system('xdotool windowraise ' . v:windowid)
endfunction
" }}}1
" vim: fdm=marker sw=2

View File

@ -0,0 +1,120 @@
" vimtex - LaTeX plugin for Vim
"
" Maintainer: Karl Yngve Lervåg
" Email: karl.yngve@gmail.com
"
function! vimtex#view#zathura#new() " {{{1
"
" Set default options
"
call vimtex#util#set_default('g:vimtex_view_zathura_options', '')
"
" Check if the viewer is executable
"
if !executable('zathura')
call vimtex#echo#warning('Zathura is not executable!')
call vimtex#echo#echo('- vimtex viewer will not work!')
call vimtex#echo#wait()
return {}
endif
"
" Check if the xdotool is available
"
if !executable('xdotool')
call vimtex#echo#warning('Zathura requires xdotool!')
return {}
endif
"
" Use the xwin template
"
return vimtex#view#common#apply_xwin_template('Zathura',
\ vimtex#view#common#use_temp_files_p(deepcopy(s:zathura)))
endfunction
" }}}1
let s:zathura = {}
function! s:zathura.start(outfile) dict " {{{1
let exe = {}
let exe.cmd = 'zathura'
let exe.cmd .= ' -x "' . g:vimtex_latexmk_progname
\ . ' --servername ' . v:servername
\ . ' --remote +\%{line} \%{input}"'
let exe.cmd .= ' ' . g:vimtex_view_zathura_options
let exe.cmd .= ' ' . vimtex#util#shellescape(a:outfile)
call vimtex#util#execute(exe)
let self.cmd_start = exe.cmd
call self.xwin_get_id()
call self.forward_search(a:outfile)
endfunction
" }}}1
function! s:zathura.forward_search(outfile) dict " {{{1
if !filereadable(self.synctex) | return | endif
let exe = {}
let exe.cmd = 'zathura --synctex-forward '
let exe.cmd .= line('.')
let exe.cmd .= ':' . col('.')
let exe.cmd .= ':' . vimtex#util#shellescape(expand('%:p'))
let exe.cmd .= ' ' . vimtex#util#shellescape(a:outfile)
call vimtex#util#execute(exe)
let self.cmd_forward_search = exe.cmd
endfunction
" }}}1
function! s:zathura.latexmk_callback(status) dict " {{{1
if !a:status | return | endif
if g:vimtex_view_use_temp_files
call self.copy_files()
else
"
" Search for existing window created by latexmk
" It may be necessary to wait some time before it is opened and
" recognized. Sometimes it is very quick, other times it may take
" a second. This way, we don't block longer than necessary.
"
if !has_key(self, 'started_through_callback')
for l:dummy in range(30)
sleep 50m
if self.xwin_exists() | break | endif
endfor
endif
endif
if !self.xwin_exists() && !has_key(self, 'started_through_callback')
call self.start(self.out)
let self.started_through_callback = 1
endif
if has_key(self, 'hook_callback')
call self.hook_callback()
endif
endfunction
" }}}1
function! s:zathura.latexmk_append_argument() dict " {{{1
if g:vimtex_view_use_temp_files
let cmd = ' -view=none'
else
let cmd = vimtex#latexmk#add_option('new_viewer_always', '0')
let cmd .= vimtex#latexmk#add_option('pdf_previewer',
\ 'zathura ' . g:vimtex_view_zathura_options
\ . ' -x \"' . g:vimtex_latexmk_progname
\ . ' --servername ' . v:servername
\ . ' --remote +\%{line} \%{input}\" \%S')
endif
return cmd
endfunction
" }}}1
" vim: fdm=marker sw=2