" Vimball Archiver by Charles E. Campbell, Jr., Ph.D. UseVimball finish autoload/atplib.vim [[[1 980 " Title: Vim library for ATP filetype plugin. " Author: Marcin Szamotulski " Email: mszamot [AT] gmail [DOT] com " Note: This file is a part of Automatic Tex Plugin for Vim. " URL: https://launchpad.net/automatictexplugin " Language: tex " Source ATPRC File: function! atplib#ReadATPRC() "{{{ if ( has("unix") || has("max") || has("macunix") ) " Note: in $HOME/.atprc file the user can set all the local buffer " variables without using autocommands " " Note: it must be sourced at the begining because some options handle " how atp will load (for example if we load history or not) " It also should be run at the end if the user defines mapping that " should be overwrite the ATP settings (this is done via " autocommand). let atprc_file=get(split(globpath($HOME, '.atprc.vim', 1), "\n"), 0, "") if !filereadable(atprc_file) let atprc_file = get(split(globpath(&rtp, "**/ftplugin/ATP_files/atprc.vim"), '\n'), 0, "") endif if filereadable(atprc_file) execute 'source ' . fnameescape(atprc_file) endif else let atprc_file = get(split(globpath(&rtp, "**/ftplugin/ATP_files/atprc.vim"), '\n'), 0, "") if filereadable(atprc_file) execute 'source ' . fnameescape(atprc_file) endif endif endfunction "}}} " Kill: function! atplib#KillPIDs(pids,...) "{{{ if len(a:pids) == 0 && a:0 == 0 return endif python << END import os, signal from signal import SIGKILL pids=vim.eval("a:pids") for pid in pids: try: os.kill(int(pid),SIGKILL) except OSError: pass END endfunction "}}} " Write: function! atplib#write(command,...) "{{{ let time = reltime() let backup = &backup let writebackup = &writebackup let project = b:atp_ProjectScript " Disable WriteProjectScript if a:command =~# '^\(AU\|nobackup\)$' set nobackup set nowritebackup " eventsignore, for example updateing tags with this BufWrite... " groups will be disabled. let eventignore = &eventignore let &eventignore.=(&eventignore == "" ? "" : ",").g:atp_write_eventignore endif let b:atp_ProjectScript = 0 let main_file = atplib#FullPath(b:atp_MainFile) let silent = ( a:0 ? a:1 : "" ) " This works for single files: if a:0 > 0 && a:1 == "silent" silent! update else update endif let b:atp_changedtick = b:changedtick " This works for projects, but it is too slow: " bufdo call atplib#update(main_file, silent) if a:command =~# '^\(AU\|nobackup\)$' let &backup = backup let &writebackup = writebackup let &eventignore = eventignore endif let b:atp_ProjectScript = project let g:time_update = reltimestr(reltime(time)) endfunction "}}} function! atplib#update(main_file, ...) "{{{ if !(exists("b:atp_MainFile") && a:main_file == atplib#FullPath(b:atp_MainFile)) return endif if a:0 > 0 && a:1 == "silent" silent! update else update endif endfunction "}}} function! atplib#WriteProject(command,...) "{{{ let silent = a:0 >=1 ? a:1 : '' let flist = [b:atp_MainFile] call extend(flist, b:ListOfFiles) for file in flist let bufnr_saved = bufnr("%") if bufloaded(file) exe "buffer ".bufnr(file) exe silent." ".a:command endif exe "buffer ".bufnr_saved endfor endfunction "}}} " Log: function! atplib#Log(file, string, ...) "{{{1 if finddir(g:atp_TempDir, "/") == "" call mkdir(g:atp_TempDir, "p", 0700) endif if a:0 >= 1 call delete(g:atp_TempDir."/".a:file) else exe "redir >> ".g:atp_TempDir."/".a:file silent echo a:string redir END endif endfunction "}}}1 function! atplib#pyeval(string) " {{{1 if has("python") return pyeval(a:string) elseif has("python3") return py3eval(a:string) endif endfunction "}}}1 " Status Line: fun! atplib#ProgressBar() "{{{1 if !g:atp_statusNotif " Do not put any message if user dosn't want it. return "" endif if !exists("g:atp_DEV_no_check") || !g:atp_DEV_no_check if g:atp_Compiler =~ '\ 0 let atp_running= len(b:atp_LatexPIDs) elseif len(b:atp_BibtexPIDs) > 0 let atp_running= len(b:atp_BibtexPIDs) else return '' endif else " for g:atp_Compiler='bash' let atp_running=b:atp_running for cmd in keys(g:CompilerMsg_Dict) if b:atp_TexCompiler =~ '^\s*' . cmd . '\s*$' let Compiler = g:CompilerMsg_Dict[cmd] break else let Compiler = b:atp_TexCompiler endif endfor if atp_running >= 2 return atp_running." ".Compiler elseif atp_running >= 1 return Compiler else return "" endif endif endif for cmd in keys(g:CompilerMsg_Dict) if b:atp_TexCompiler =~ '^\s*' . cmd . '\s*$' let Compiler = g:CompilerMsg_Dict[cmd] break else let Compiler = b:atp_TexCompiler endif endfor " For g:atp_Compiler='python' if exists("g:atp_callback") && g:atp_callback if exists("b:atp_LatexPIDs") && len(b:atp_LatexPIDs)>0 if exists("g:atp_ProgressBarValues") && type(g:atp_ProgressBarValues) == 4 && get(g:atp_ProgressBarValues,bufnr("%"), {}) != {} let max = max(values(get(g:atp_ProgressBarValues, bufnr("%")))) let progress_bar="[".max."]".( g:atp_statusOutDir ? " " : "" ) else let progress_bar="" endif if atp_running >= 2 return atp_running." ".Compiler." ".progress_bar elseif atp_running >= 1 return Compiler." ".progress_bar else return "" endif elseif exists("b:atp_BibtexPIDs") && len(b:atp_BibtexPIDs)>0 return b:atp_BibCompiler elseif exists("b:atp_MakeindexPIDs") && len(b:atp_MakeindexPIDs)>0 return "makeindex" endif else if g:atp_ProgressBar try let pb_file = readfile(g:atp_ProgressBarFile) catch /.*:/ let pb_file = [] endtry if len(pb_file) let progressbar = Compiler." [".get(pb_file, 0, "")."]" " let progressbar = Compiler else let progressbar = "" endif else let progressbar = "" endif return progressbar endif return "" endf fun! atplib#StatusOutDir() "{{{1 if exists("b:atp_OutDir") if b:atp_OutDir != "" let status= "Output dir: " . pathshorten(substitute(b:atp_OutDir,"\/\s*$","","")) else let status= "Output dir: not set" endif endif return status endf fun! atplib#CurentSection() " {{{1 if &l:filetype !~ 'tex$' || expand("%:e") != 'tex' return "" endif let winsavedview = winsaveview() try if exists("b:atp_MainFile") && bufloaded(atplib#FullPath(b:atp_MainFile)) let file = getbufline(bufnr(atplib#FullPath(b:atp_MainFile)), 0, "$") elseif exists("b:atp_MainFile") && filereadable(atplib#FullPath(b:atp_MainFile)) let file = readfile(atplib#FullPath(b:atp_MainFile)) else let s:document_class = "" endif for fline in file if fline =~# '^\([^%]\|\\%\)*\\documentclass\>' break endif endfor let s:document_class = matchstr(fline, '\\documentclass\[.*\]{\s*\zs[^}]*\ze\s*}') catch /E\(484\|121\):/ if !exists("s:document_class") let s:document_class = "" endif endtry if s:document_class == "beamer" let saved_pos = getpos(".") if getline(line(".")) =~ '^\([^%]\|\\%\)*\\end\s*{\s*frame\s*}' call cursor(line(".")-1, len(getline(line(".")))) endif keepjumps call searchpair('^\([^%]\|\\%\)*\\begin\s*{\s*frame\s*}', '', '^\([^%]\|\\%\)*\\end\s*{\s*frame\s*}', 'cbW', '', \ search('^\([^%]\|\\%\)*\\begin\s*{\s*frame\s*}', 'bnW')) let limit = search('^\([^%]\|\\%\)*\\end\s*{\s*frame\s*}', 'nW') let pos = [ line("."), col(".") ] keepjumps call search('^\([^%]\|\\%\)*\frametitle\>\zs{', 'W', limit) if pos != getpos(".")[1:2] let a = @a if mode() ==# 'n' " We can't use this normal mode command in visual mode. keepjumps normal! "ayi} let title = substitute(@a, '\_s\+', ' ', 'g') let @a = a else let title = matchstr(getline(line(".")), '\\frametitle\s*{\s*\zs[^}]*\ze\(}\|$\)') let title = substitute(title, '\s\+', ' ', 'g') let title = substitute(title, '\s\+$', '', 'g') if getline(line(".")) =~ '\\frametitle\s*{[^}]*$' let title .= " ".matchstr(getline(line(".")+1), '\s*\zs[^}]*\ze\(}\|$\)') endif endif call winrestview(winsavedview) return substitute(strpart(title,0,b:atp_TruncateStatusSection/2), '\_s*$', '','') else call cursor(saved_pos[1:2]) return "" endif endif let names = atplib#motion#ctoc() let chapter_name = get(names, 0, '') let section_name = get(names, 1, '') let subsection_name = get(names, 2, '') let g:names = names if chapter_name == "" && section_name == "" && subsection_name == "" return "" elseif chapter_name != "" if section_name != "" return substitute(strpart(chapter_name,0,b:atp_TruncateStatusSection/2), '\_s*$', '','') . "/" . substitute(strpart(section_name,0,b:atp_TruncateStatusSection/2), '\_s*$', '','') else return substitute(strpart(chapter_name,0,b:atp_TruncateStatusSection), '\_s*$', '','') endif elseif chapter_name == "" && section_name != "" if subsection_name != "" return substitute(strpart(section_name,0,b:atp_TruncateStatusSection/2), '\_s*$', '','') . "/" . substitute(strpart(subsection_name,0,b:atp_TruncateStatusSection/2), '\_s*$', '','') else return substitute(strpart(section_name,0,b:atp_TruncateStatusSection), '\_s*$', '','') endif elseif chapter_name == "" && section_name == "" && subsection_name != "" return substitute(strpart(subsection_name,0,b:atp_TruncateStatusSection), '\_s*$', '','') endif endf "}}}1 "Make g:atp_TempDir, where log files are stored. function! atplib#TempDir() "{{{1 " Return temporary directory, unique for each user. if has("python") python << END import vim, tempfile, os USER=os.getenv("USER") tmp=tempfile.mkdtemp(suffix="", prefix="atp_") vim.command("let g:atp_TempDir='"+tmp+"'") END else let td = tempname() let g:atp_TempDir=substitute(td, '\d\+$', "atp_debug", '') call mkdir(g:atp_TempDir, "p", 0700) endif endfunction fun! atplib#joinpath(path1, path2) " {{{1 let idx = match(a:path1, '\/\s*$') if idx != -1 let path1 = a:path1[:(idx-1)] else let path1 = a:path1 endif let idx = len(matchstr(a:path2, '\s*\/')) if idx != 0 let path2 = a:path2[(idx):] else let path2 = a:path2 endif return path1.'/'.path2 endfun function! atplib#RelativePath(path, rel) "{{{1 " Return {path} relative to {rel}, if not under {rel} return {path} let current_dir = getcwd() exe "lcd " . fnameescape(a:rel) let rel_path = fnamemodify(a:path, ':.') exe "lcd " . fnameescape(current_dir) return rel_path endfunction "}}}1 function! atplib#FullPath(file_name) "{{{1 " Return fullpath let cwd = getcwd() if a:file_name == fnamemodify(fnamemodify(a:file_name, ":t"), ":p") " if a:file_name is already a full path " Note: fnamemodify(a:file_name, ":p") will not return what I need if " a:file_name ="some_dir/file.tex" " " I should first change directory to ... to what? (i.e. before the if " condition). let file_path = a:file_name else let project_dir = "" if exists("b:atp_ProjectDir") && exists("b:ListOfFiles") && \ index(map(copy(b:ListOfFiles)+[b:atp_MainFile], 'fnamemodify(v:val, ":t")'), fnamemodify(a:file_name, ":t")) != -1 " check the current buffer. let project_dir = b:atp_ProjectDir else " else, search in all buffer variables b:ListOfFiles for the correct " b:atp_ProjectDir variable. for i in filter(range(1,bufnr("$")), 'bufloaded(v:val)') if type(getbufvar(i, "ListOfFiles")) == 3 if index(map(getbufvar(i, "ListOfFiles")+[getbufvar(i,"atp_MainFile")], 'fnamemodify(v:val, ":t")'), fnamemodify(a:file_name, ":t")) != -1 let project_dir = getbufvar(i, "atp_ProjectDir") let bufname = bufname(i) break endif endif endfor endif if project_dir != "" try exe "lcd " . fnameescape(project_dir) let file_path = fnamemodify(a:file_name, ":p") exe "lcd " . fnameescape(cwd) catch /E344:/ " If project_dir points to non existing path " this will show not the right place: if stridx(project_dir, 'fugitive:') == 0 return a:file_name " else " echohl ErrorMsg " echomsg "E344: in atplib#FullPath(): b:atp_ProjectDir=".project_dir." does not exist" " echohl Normal endif let file_path = fnamemodify(a:file_name, ":p") endtry else let file_path = fnamemodify(a:file_name, ":p") endif endif return file_path endfunction "}}}1 " Table: "{{{ atplibTable, atplib#FormatListinColumns, atplib#PrintTable function! atplib#Table(list, spaces) " take a list of lists and make a list which is nicely formated (to echo it) " spaces = list of spaces between columns. "maximal length of columns: let max_list=[] let new_list=[] for i in range(len(a:list[0])) let max=max(map(deepcopy(a:list), "len(v:val[i])")) call add(max_list, max) endfor for row in a:list let new_row=[] let i=0 for el in row let new_el=el.join(map(range(max([0,max_list[i]-len(el)+get(a:spaces,i,0)])), "' '"), "") call add(new_row, new_el) let i+=1 endfor call add(new_list, new_row) endfor return map(new_list, "join(v:val, '')") endfunction function! atplib#FormatListinColumns(list,s) " take a list and reformat it into many columns " a:s is the number of spaces between columns " for example of usage see atplib#PrintTable let max_len=max(map(copy(a:list), 'len(v:val)')) let new_list=[] let k=&l:columns/(max_len+a:s) let len=len(a:list) let column_len=len/k for i in range(0, column_len) let entry=[] for j in range(0,k) call add(entry, get(a:list, i+j*(column_len+1), "")) endfor call add(new_list,entry) endfor return new_list endfunction " Take list format it with atplib#FormatListinColumns and then with " atplib#Table (which makes columns of equal width) function! atplib#PrintTable(list, spaces) " a:list - list to print " a:spaces - nr of spaces between columns let list = atplib#FormatListinColumns(a:list, a:spaces) let nr_of_columns = max(map(copy(list), 'len(v:val)')) let spaces_list = ( nr_of_columns == 1 ? [0] : map(range(1,nr_of_columns-1), 'a:spaces') ) return atplib#Table(list, spaces_list) endfunction "}}} function! atplib#qflength() "{{{ let lines = 1 " i.e. open with one more line than needed. for qf in getqflist() let text=substitute(qf['text'], '\_s\+', ' ', 'g') let lines+=(len(text))/&l:columns+1 endfor return lines endfunction "}}} function! atplib#Let(varname, varvalue) "{{{ exe "let ".substitute(string(a:varname), "'", "", "g")."=".substitute(string(a:varvalue), "''\\@!", "", "g") endfunction "}}} " IMap Functions: " {{{ " With a:1 = "!" (bang) remove texMathZoneT (tikzpicture from MathZones). function! atplib#IsInMath(...) let line = a:0 >= 2 ? a:2 : line(".") let col = a:0 >= 3 ? a:3 : col(".")-1 if a:0 > 0 && a:1 == "!" let atp_MathZones=filter(copy(g:atp_MathZones), "v:val != 'texMathZoneT'") else let atp_MathZones=copy(g:atp_MathZones) endif call filter(atp_MathZones, 'v:val !~ ''\''') if atplib#complete#CheckSyntaxGroups(['texMathZoneV', 'texMathZoneW', 'texMathZoneX', 'texMathZoneY']) return 1 else return atplib#complete#CheckSyntaxGroups(atp_MathZones, line, col) && \ !atplib#complete#CheckSyntaxGroups(['texMathText'], line, col) endif endfunction function! atplib#MakeMaps(maps, ...) let aucmd = ( a:0 >= 1 ? a:1 : '' ) for map in a:maps if map[3] != "" && ( !exists(map[5]) || {map[5]} > 0 || \ exists(map[5]) && {map[5]} == 0 && aucmd == 'InsertEnter' ) if exists(map[5]) && {map[5]} == 0 && aucmd == 'InsertEnter' exe "let ".map[5]." =1" endif exe map[0]." ".map[1]." ".map[2].map[3]." ".map[4] endif endfor endfunction function! atplib#DelMaps(maps) for map in a:maps let cmd = matchstr(map[0], '[^m]\ze\%(nore\)\=map') . "unmap" let arg = ( map[1] =~ '' ? '' : '' ) try exe cmd." ".arg." ".map[2].map[3] catch /E31:/ endtry endfor endfunction " From TeX_9 plugin: function! atplib#IsLeft(lchar,...) let nr = ( a:0 >= 1 ? a:1 : 0 ) let left = getline('.')[col('.')-2-nr] if left ==# a:lchar return 1 else return 0 endif endfunction function! atplib#ToggleIMaps(var, augroup, ...) if exists("s:isinmath") && \ ( atplib#IsInMath() == s:isinmath ) && \ ( a:0 >= 2 && a:2 ) && \ a:augroup == 'CursorMovedI' return endif if a:augroup == 'CursorMovedI' call SetMathVimOptions('CursorMovedI') endif if atplib#IsInMath() call atplib#MakeMaps(a:var, a:augroup) else call atplib#DelMaps(a:var) if a:0 >= 1 && len(a:1) call atplib#MakeMaps(a:1) endif endif let s:isinmath = atplib#IsInMath() endfunction "}}} " Toggle on/off Completion " {{{1 atplib#OnOffComp function! atplib#OnOffComp(ArgLead, CmdLine, CursorPos) return filter(['on', 'off'], 'v:val =~ "^" . a:ArgLead') endfunction "}}}1 " Toggle on/off/local Completion " {{{1 atplib#OnOffComp function! atplib#OnOffLocalComp(ArgLead, CmdLine, CursorPos) return filter(['on', 'off', 'local'], 'v:val =~ "^" . a:ArgLead') endfunction "}}}1 " Find Vim Server: find server 'hosting' a file and move to the line. " {{{1 atplib#FindAndOpen " Can be used to sync gvim with okular. " just set in okular: " settings>okular settings>Editor " Editor Custom Text Editor " Command gvim --servername GVIM --remote-expr "atplib#FindAndOpen('%f','%l', '%c')" " You can also use this with vim but you should start vim with " vim --servername VIM " and use servername VIM in the Command above. function! atplib#ServerListOfFiles() exe "redir! > " . g:atp_TempDir."/ServerListOfFiles.log" let file_list = [] for nr in range(1, bufnr('$')) " map fnamemodify(v:val, ":p") is not working if we are in another " window with file in another dir. So we are not using this (it might " happen that we end up in a wrong server though). if exists("main_file") unlet main_file endif let main_file = getbufvar(nr, "atp_MainFile") let log_file = ( expand("%:e") =~# '^_\?log$' ) if exists("files") unlet files endif let files = getbufvar(nr, "ListOfFiles") if string(main_file) != "" && !log_file call add(file_list, main_file) endif if type(files) == 3 && !log_file call extend(file_list, files) endif endfor call filter(file_list, 'v:val != ""') redir end return file_list endfunction fun! atplib#PyLog(file, message,...) if !has("python") return endif let mode = a:0 ? a:1 : 'a' python << EOF import vim fname = vim.eval('a:file') message = vim.eval('a:message') mode = vim.eval('mode') if not message.endswith('\n'): message += '\n' with open(fname, mode) as fo: fo.write(message) EOF endfun function! atplib#FindAndOpen(file, output_file, line, ...) let col = ( a:0 >= 1 && a:1 > 0 ? a:1 : 1 ) let file = ( fnamemodify(simplify(a:file), ":e") == "tex" ? simplify(a:file) : fnamemodify(simplify(a:file), ":p:r") . ".tex" ) let file_t = fnamemodify(file, ":t") let main_file = ( fnamemodify(simplify(a:output_file), ":e") == "tex" ? simplify(a:output_file) : fnamemodify(simplify(a:output_file), ":p:r") . ".tex" ) let main_file_t = fnamemodify(file, ":t") let server_list = split(serverlist(), "\n") exe "redir! > /tmp/FindAndOpen.log" if len(server_list) == 0 " No server is hosting the file exe "edit ".fnameescape(a:file) call cursor(a:line, col) redraw redir END return 0 endif let open = "buffer" let use_server = "" let use_servers = [] let server_filedict = {} for server in server_list let file_list=split(remote_expr(server, 'atplib#ServerListOfFiles()'), "\n") let server_filedict[server]=file_list " Note: atplib#ServerListOfFiles returns all the files loaded by the " server plus all corresponding values of b:ListOfFiles let cond_1 = (index(file_list, file) != "-1") let cond_2 = (index(file_list, file_t) != "-1") if cond_1 let use_server = server break elseif cond_2 call add(use_servers, server) endif endfor if use_server == "" " If b:ListOfFiles was not defined, the previous for would not return " a server, run again, but now looking for the main file. for server in keys(server_filedict) let file_list=aserver_filedict[server] " Note: atplib#ServerListOfFiles returns all the files loaded by the " server plus all corresponding values of b:ListOfFiles let cond_1 = (index(file_list, main_file) != "-1") let cond_2 = (index(file_list, main_file_t) != "-1") if cond_1 let use_server = server break elseif cond_2 call add(use_servers, server) endif endfor endif " If we could not find file name with full path in server list use the " first server where is fnamemodify(file, ":t"). if use_server == "" let use_server=get(use_servers, 0, "") endif if use_server != "" if !remote_expr(use_server, 'bufloaded("'.file.'")') " Change the jump list by setting the ' mark: call remote_send(user_server, ":mark `") call system(v:progname." --servername ".use_server." --remote-wait +".a:line." ".fnameescape(file) . " &") else " Test this for file names with spaces let bufwinnr = remote_expr(use_server, 'bufwinnr("'.file.'")') let bufnr = remote_expr(use_server, "bufnr('".file."')") if bufwinnr == "-1" " The buffer is in a different tab page. let tabpage = 0 " Find the correct tabpage: for tabnr in range(1, remote_expr(use_server, 'tabpagenr("$")')) let tabbuflist = split(remote_expr(use_server, 'tabpagebuflist("'.tabnr.'")'), "\n") let tabbuflist_names = split(remote_expr(use_server, 'map(tabpagebuflist("'.tabnr.'"), "bufname(v:val)")'), "\n") if count(tabbuflist_names, file) || count(tabfublist_names, file_t) let tabpage = tabnr break endif endfor " Goto to the tabpage: if tabpage && remote_expr(use_server, 'tabpagenr()') != tabpage call remote_send(use_server, ':tabnext '.tabpage.'') elseif !tabpage " The file is not present in any file, but the buffer is " loaded. call remote_send(use_server, ':buffer '.bufnr) endif " Check the bufwinnr once again: let bufwinnr = remote_expr(use_server, 'bufwinnr("'.file.'")') endif " winnr() doesn't work remotely, this is a substitute: let remote_file = remote_expr(use_server, 'expand("%:t")') if string(remote_file) != string(file_t) if bufwinnr != -1 call remote_send(use_server, ":".bufwinnr."wincmd w") else call remote_send(use_server, ":buffer ".bufnr."") endif endif " Change the jump list by setting the ' mark: call remote_send(use_server, ":mark `") " Set the ' mark (jump list), cursor position and redraw: call remote_send(use_server, ":call cursor(".a:line.",".col."):redraw") endif else " No server is hosting the file exe "edit ".fnameescape(a:file) call cursor(a:line, col) redraw redir END return v:servername endif redir END return use_server endfunction "}}}1 " Various Comparing Functions: "{{{1 atplib#CompareNumbers function! atplib#CompareNumbers(i1, i2) return ( str2nr(a:i1) == str2nr(a:i2) ? 0 : ( str2nr(a:i1) > str2nr(a:i2) ? 1 : -1 ) ) endfunction "}}}1 " {{{1 atplib#CompareCoordinates " Each list is an argument with two values: " listA=[ line_nrA, col_nrA] usually given by searchpos() function " listB=[ line_nrB, col_nrB] " returns 1 iff A is before B fun! atplib#CompareCoordinates(listA,listB) if a:listA[0] < a:listB[0] || \ a:listA[0] == a:listB[0] && a:listA[1] < a:listB[1] || \ a:listA == [0,0] " the meaning of the last is that if the searchpos() has not found the " beginning (a:listA) then it should return 1 : the env is not started. return 1 else return 0 endif endfun "}}}1 " {{{1 atplib#CompareCoordinates_leq " Each list is an argument with two values! " listA=[ line_nrA, col_nrA] usually given by searchpos() function " listB=[ line_nrB, col_nrB] " returns 1 iff A is smaller or equal to B function! atplib#CompareCoordinates_leq(listA,listB) if a:listA[0] < a:listB[0] || \ a:listA[0] == a:listB[0] && a:listA[1] <= a:listB[1] || \ a:listA == [0,0] " the meaning of the last is that if the searchpos() has not found the " beginning (a:listA) then it should return 1 : the env is not started. return 1 else return 0 endif endfunction "}}}1 " {{{1 atplib#CompareStarAfter " This is used by atplib#complete#TabCompletion to put abbreviations of starred environment after not starred version function! atplib#CompareStarAfter(i1, i2) if a:i1 !~ '\*' && a:i2 !~ '\*' if a:i1 == a:i2 return 0 elseif a:i1 < a:i2 return -1 else return 1 endif else let i1 = substitute(a:i1, '\*', '', 'g') let i2 = substitute(a:i2, '\*', '', 'g') if i1 == i2 if a:i1 =~ '\*' && a:i2 !~ '\*' return 1 else return -1 endif return 0 elseif i1 < i2 return -1 else return 1 endif endif endfunction " }}}1 " ReadInputFile function reads finds a file in tex style and returns the list " of its lines. " {{{1 atplib#ReadInputFile " this function looks for an input file: in the list of buffers, under a path if " it is given, then in the b:atp_OutDir. " directory. The last argument if equal to 1, then look also " under g:texmf. function! atplib#ReadInputFile(ifile,check_texmf) let input_file = [] " read the buffer or read file if the buffer is not listed. if buflisted(fnamemodify(a:ifile,":t")) let input_file=getbufline(fnamemodify(a:ifile,":t"),1,'$') " if the ifile is given with a path it should be tried to read from there elseif filereadable(a:ifile) let input_file=readfile(a:ifile) elseif filereadable(atplib#joinpath(expand(b:atp_ProjectDir), fnamemodify(a:ifile,":t"))) let input_file=readfile(atplib#joinpath(expand(b:atp_ProjectDir), fnamemodify(a:ifile,":t"))) " if not then try to read it from b:atp_OutDir elseif filereadable(atplib#joinpath(expand(b:atp_OutDir), fnamemodify(a:ifile,":t"))) let input_file=readfile(atplib#joinpath(expand(b:atp_OutDir), fnamemodify(a:ifile,":t"))) " the last chance is to look for it in the g:texmf directory elseif a:check_texmf && filereadable(findfile(a:ifile,g:texmf . '**')) let input_file=readfile(findfile(a:ifile,g:texmf . '**')) endif return input_file endfunction "}}}1 " URL query: (by some strange reason this is not working moved to url_query.py) " function! atplib#URLquery(url) "{{{ " python << EOF " import urllib2, tempfile, vim " url = vim.eval("a:url") " print(url) " temp = tempfile.mkstemp("", "atp_ams_") " " f = open(temp[1], "w+") " data = urllib2.urlopen(url) " f.write(data.read()) " vim.command("return '"+temp[1]+"'") " EOF " endfunction "}}} " This function sets the window options common for toc and bibsearch windows. "{{{1 atplib#setwindow " this function sets the options of BibSearch, ToC and Labels windows. function! atplib#setwindow() " These options are set in the command line " +setl\\ buftype=nofile\\ filetype=bibsearch_atp " +setl\\ buftype=nofile\\ filetype=toc_atp\\ nowrap " +setl\\ buftype=nofile\\ filetype=toc_atp\\ syntax=labels_atp setlocal nonumber setlocal norelativenumber setlocal winfixwidth setlocal noswapfile setlocal nobuflisted if &filetype == "bibsearch_atp" " setlocal winwidth=30 setlocal nospell endif " nnoremap l "keepalt normal l" " nnoremap h "keepalt normal h" endfunction " }}}1 " {{{1 atplib#count function! atplib#count(line, keyword,...) let method = ( a:0 == 0 || a:1 == 0 ) ? 0 : 1 let line=a:line let i=0 if method==0 while stridx(line, a:keyword) != '-1' let line = strpart(line, stridx(line, a:keyword)+1) let i +=1 endwhile elseif method==1 let pat = a:keyword.'\zs' while line =~ pat let line = strpart(line, match(line, pat)) let i +=1 endwhile endif return i endfunction " }}}1 " Used to append / at the end of a directory name " {{{1 atplib#append fun! atplib#append(where, what) return substitute(a:where, a:what . '\s*$', '', '') . a:what endfun " }}}1 " Used to append extension to a file name (if there is no extension). " {{{1 atplib#append_ext " extension has to be with a dot. fun! atplib#append_ext(fname, ext) return substitute(a:fname, a:ext . '\s*$', '', '') . a:ext endfun " }}}1 fu! atplib#VimToPyPattern(pattern) " {{{1 " \( -> ( and ( -> \(, " \) -> ) and ) -> \), let pattern = substitute(a:pattern, '[()]', "\\\\&", "g") let pattern = substitute(pattern, '\\\@ | and | -> \| let pattern = substitute(pattern, '|', '\\|', 'g') let pattern = substitute(pattern, '\\\\|', '|', 'g') " ( ... \& ... ) -> ( " See ":help /zero-width" return pattern endfu " List Functions: " atplib#Extend {{{1 " arguments are the same as for extend(), but it adds only the entries which " are not present. function! atplib#Extend(list_a,list_b,...) let list_a=deepcopy(a:list_a) let list_b=deepcopy(a:list_b) let diff=filter(list_b,'count(l:list_a,v:val) == 0') if a:0 == 0 return extend(list_a,diff) else return extend(list_a,diff, a:1) endif endfunction " }}}1 " {{{1 atplib#Add function! atplib#Add(list,what) let new=[] for element in a:list call add(new,element . a:what) endfor return new endfunction "}}}1 " String Functions: function! atplib#TexKeyword() " {{{ let isk = &isk let &isk = g:atp_iskeyword let line = getline(line(".")) let beg = matchstr(line[:(col(".")-1)], '\\\k*$') if empty(beg) let beg = matchstr(line[:(col(".")-1)], '\k*$') endif let end = matchstr(line[col("."):], '^\k*') let &isk = isk return beg.end endfunction " }}} " vim:fdm=marker:ff=unix:noet:ts=8:sw=4:fdc=1 autoload/atplib/bibsearch.vim [[[1 826 " Title: Vim library for ATP filetype plugin. " Author: Marcin Szamotulski " Email: mszamot [AT] gmail [DOT] com " Note: This file is a part of Automatic Tex Plugin for Vim. " URL: https://launchpad.net/automatictexplugin " Language: tex " Last Modified: " BIB SEARCH: " These are all bibsearch related variables and functions. "{{{ atplib#bibsearch#variables let atplib#bibsearch#bibflagsdict={ \ 't' : ['title', 'title '], 'a' : ['author', 'author '], \ 'b' : ['booktitle', 'booktitle '], 'c' : ['mrclass', 'mrclass '], \ 'e' : ['editor', 'editor '], 'j' : ['journal', 'journal '], \ 'f' : ['fjournal', 'fjournal '], 'y' : ['year', 'year '], \ 'n' : ['number', 'number '], 'v' : ['volume', 'volume '], \ 's' : ['series', 'series '], 'p' : ['pages', 'pages '], \ 'P' : ['publisher', 'publisher '], 'N' : ['note', 'note '], \ 'S' : ['school', 'school '], 'h' : ['howpublished', 'howpublished '], \ 'o' : ['organization', 'organization '], 'I' : ['institution' , 'institution '], \ 'u' : ['url', 'url '], \ 'H' : ['homepage', 'homepage '], 'i' : ['issn', 'issn '], \ 'k' : ['key', 'key '], 'R' : ['mrreviewer', 'mrreviewer ']} " they do not work in the library script :( " using g:bibflags... . " let atplib#bibflagslist=keys(atplib#bibsearch#bibflagsdict) " let atplib#bibflagsstring=join(atplib#bibflagslist,'') "}}} "{{{ atplib#bibsearch#searchbib " This is the main search engine. " ToDo should not search in comment lines. " To make it work after kpsewhich is searching for bib path. " let s:bibfiles=FindBibFiles(bufname('%')) function! atplib#bibsearch#searchbib(pattern, bibdict, ...) " for tex files this should be a flat search. let flat = &filetype == "plaintex" ? 1 : 0 let bang = a:0 >=1 ? a:1 : "" let atp_MainFile = atplib#FullPath(b:atp_MainFile) " Make a pattern which will match for the elements of the list g:bibentries let pattern = '^\s*@\%(\<'.g:bibentries[0].'\>' for bibentry in g:bibentries['1':len(g:bibentries)] let pattern = pattern . '\|\<' . bibentry . '\>' endfor let pattern = pattern . '\)' " This pattern matches all entry lines: author = \| title = \| ... let pattern_b = '^\s*\%(' for bibentry in keys(g:bibflagsdict) let pattern_b = pattern_b . '\|\<' . g:bibflagsdict[bibentry][0] . '\>' endfor let pattern_b.='\)\s*=' if g:atp_debugBS exe "redir! >>".g:atp_TempDir."/BibSearch.log" silent! echo "==========atplib#bibsearch#searchbib===================" silent! echo "atplib#bibsearch#searchbib_bibfiles=" . string(s:bibfiles) silent! echo "a:pattern=" . a:pattern silent! echo "pattern=" . pattern silent! echo "pattern_b=" . pattern_b silent! echo "bang=" . bang silent! echo "flat=" . flat endif unlet bibentry let b:bibentryline={} " READ EACH BIBFILE IN TO DICTIONARY s:bibdict, WITH KEY NAME BEING THE bibfilename let s:bibdict={} let l:bibdict={} for l:f in keys(a:bibdict) let s:bibdict[l:f]=[] " read the bibfile if it is in b:atp_OutDir or in g:atp_raw_bibinputs directory " ToDo: change this to look in directories under g:atp_raw_bibinputs. " (see also ToDo in FindBibFiles 284) " for l:path in split(g:atp_raw_bibinputs, ',') " " it might be problem when there are multiple libraries with the " " same name under different locations (only the last one will " " survive) " let s:bibdict[l:f]=readfile(fnameescape(findfile(atplib#append(l:f,'.bib'), atplib#append(l:path,"/") . "**"))) " endfor let l:bibdict[l:f]=copy(a:bibdict[l:f]) " clear the s:bibdict values from lines which begin with % call filter(l:bibdict[l:f], ' v:val !~ "^\\s*\\%(%\\|@\\cstring\\)"') endfor if g:atp_debugBS silent! echo "values(l:bibdict) len(l:bibdict[v:val]) = " . string(map(deepcopy(l:bibdict), "len(v:val)")) endif if a:pattern != "" for l:f in keys(a:bibdict) let l:list=[] let l:nr=1 for l:line in l:bibdict[l:f] " Match Pattern: " if the line matches find the beginning of this bib field and add its " line number to the list l:list " remove ligatures and brackets {,} from the line let line_without_ligatures = substitute(substitute(l:line,'\C{\|}\|\\\%("\|`\|\^\|=\|\.\|c\|\~\|v\|u\|d\|b\|H\|t\)\s*','','g'), "\\\\'\\s*", '', 'g') let line_without_ligatures = substitute(line_without_ligatures, '\C\\oe', 'oe', 'g') let line_without_ligatures = substitute(line_without_ligatures, '\C\\OE', 'OE', 'g') let line_without_ligatures = substitute(line_without_ligatures, '\C\\ae', 'ae', 'g') let line_without_ligatures = substitute(line_without_ligatures, '\C\\AE', 'AE', 'g') let line_without_ligatures = substitute(line_without_ligatures, '\C\\o', 'o', 'g') let line_without_ligatures = substitute(line_without_ligatures, '\C\\O', 'O', 'g') let line_without_ligatures = substitute(line_without_ligatures, '\C\\i', 'i', 'g') let line_without_ligatures = substitute(line_without_ligatures, '\C\\j', 'j', 'g') let line_without_ligatures = substitute(line_without_ligatures, '\C\\l', 'l', 'g') let line_without_ligatures = substitute(line_without_ligatures, '\C\\L', 'L', 'g') if line_without_ligatures =~? a:pattern if g:atp_debugBS silent! echo "line_without_ligatures that matches " . line_without_ligatures silent! echo "____________________________________" endif let l:true=1 let l:t=0 while l:true == 1 let l:tnr=l:nr-l:t if g:atp_debugBS silent! echo " l:tnr=" . string(l:tnr) . " l:bibdict[". string(l:f) . "][" . string(l:tnr-1) . "]=" . string(l:bibdict[l:f][l:tnr-1]) endif " go back until the line will match pattern (which " should be the beginning of the bib field. if l:bibdict[l:f][l:tnr-1] =~? pattern && l:tnr >= 0 let l:true=0 let l:list=add(l:list,l:tnr) elseif l:tnr <= 0 let l:true=0 endif let l:t+=1 endwhile endif let l:nr+=1 endfor if g:atp_debugBS silent! echo "A l:list=" . string(l:list) endif " CLEAR THE l:list FROM ENTRIES WHICH APPEAR TWICE OR MORE --> l:clist let l:pentry="A" " We want to ensure that l:entry (a number) and l:pentry are different for l:entry in l:list if l:entry != l:pentry if count(l:list,l:entry) > 1 while count(l:list,l:entry) > 1 let l:eind=index(l:list,l:entry) call remove(l:list,l:eind) endwhile endif let l:pentry=l:entry endif endfor " This is slower than the algorithm above! " call sort(filter(l:list, "count(l:list, v:val) == 1"), "atplib#CompareNumbers") if g:atp_debugBS silent! echo "B l:list=" . string(l:list) endif let b:bibentryline=extend(b:bibentryline,{ l:f : l:list }) if g:atp_debugBS silent! echo "atplib#bibsearch b:bibentryline= (pattern != '') " . string(b:bibentryline) endif endfor endif " CHECK EACH BIBFILE let l:bibresults={} " if the pattern was empty make it faster. if a:pattern == "" for l:bibfile in keys(l:bibdict) let l:bibfile_len=len(l:bibdict[l:bibfile]) let s:bibd={} let l:nr=0 while l:nr < l:bibfile_len let l:line=l:bibdict[l:bibfile][l:nr] if l:line =~ pattern let s:lbibd={} let s:lbibd["bibfield_key"]=l:line let l:beg_line=l:nr+1 let l:nr+=1 let l:line=l:bibdict[l:bibfile][l:nr] let l:y=1 while l:line !~ pattern && l:nr < l:bibfile_len let l:line=l:bibdict[l:bibfile][l:nr] let l:lkey=tolower( \ matchstr( \ strpart(l:line,0, \ stridx(l:line,"=") \ ),'\<\w*\>' \ )) " CONCATENATE LINES IF IT IS NOT ENDED let l:y=1 if l:lkey != "" let s:lbibd[l:lkey]=l:line " IF THE LINE IS SPLIT ATTACH NEXT LINE let l:nline=get(l:bibdict[l:bibfile],l:nr+l:y) while l:nline !~ '=' && \ l:nline !~ pattern && \ (l:nr+l:y) < l:bibfile_len let s:lbibd[l:lkey]=substitute(s:lbibd[l:lkey],'\s*$','','') . " ". substitute(get(l:bibdict[l:bibfile],l:nr+l:y),'^\s*','','') let l:line=get(l:bibdict[l:bibfile],l:nr+l:y) let l:y+=1 let l:nline=get(l:bibdict[l:bibfile],l:nr+l:y) if l:y > 30 echoerr "ATP-Error /see :h atp-errors-bibsearch/, missing '}', ')' or '\"' in bibentry (check line " . l:nr . ") in " . l:f . " line=".l:line break endif endwhile if l:nline =~ pattern let l:y=1 endif endif let l:nr+=l:y unlet l:y endwhile let l:nr-=1 call extend(s:bibd, { l:beg_line : s:lbibd }) else let l:nr+=1 endif endwhile let l:bibresults[l:bibfile]=s:bibd endfor if g:atp_debugBS silent! echo "atplib#bibsearch#searchbib_bibresults A =" . l:bibresults endif return l:bibresults endif " END OF NEW CODE: (up) for l:bibfile in keys(b:bibentryline) let l:f=l:bibfile . ".bib" "s:bibdict[l:f]) CHECK EVERY STARTING LINE (we are going to read bibfile from starting " line till the last matching } let s:bibd={} for l:linenr in b:bibentryline[l:bibfile] let l:nr=l:linenr-1 let l:i=atplib#count(get(l:bibdict[l:bibfile],l:linenr-1),"{")-atplib#count(get(l:bibdict[l:bibfile],l:linenr-1),"}") let l:j=atplib#count(get(l:bibdict[l:bibfile],l:linenr-1),"(")-atplib#count(get(l:bibdict[l:bibfile],l:linenr-1),")") let s:lbibd={} let s:lbibd["bibfield_key"]=get(l:bibdict[l:bibfile],l:linenr-1) if s:lbibd["bibfield_key"] !~ '@\w\+\s*{.\+' let l:l=0 while get(l:bibdict[l:bibfile],l:linenr-l:l) =~ '^\s*$' let l:l+=1 endwhile let s:lbibd["bibfield_key"] .= get(l:bibdict[l:bibfile],l:linenr+l:l) let s:lbibd["bibfield_key"] = substitute(s:lbibd["bibfield_key"], '\s', '', 'g') endif let l:x=1 " we go from the first line of bibentry, i.e. @article{ or @article(, until the { and ( " will close. In each line we count brackets. while l:i>0 || l:j>0 let l:tlnr=l:x+l:linenr let l:pos=atplib#count(get(l:bibdict[l:bibfile],l:tlnr-1),"{") let l:neg=atplib#count(get(l:bibdict[l:bibfile],l:tlnr-1),"}") let l:i+=l:pos-l:neg let l:pos=atplib#count(get(l:bibdict[l:bibfile],l:tlnr-1),"(") let l:neg=atplib#count(get(l:bibdict[l:bibfile],l:tlnr-1),")") let l:j+=l:pos-l:neg let l:lkey=tolower( \ matchstr( \ strpart(get(l:bibdict[l:bibfile],l:tlnr-1),0, \ stridx(get(l:bibdict[l:bibfile],l:tlnr-1),"=") \ ),'\<\w*\>' \ )) if l:lkey != "" let s:lbibd[l:lkey]=get(l:bibdict[l:bibfile],l:tlnr-1) let l:y=0 " IF THE LINE IS SPLIT ATTACH NEXT LINE if get(l:bibdict[l:bibfile],l:tlnr-1) !~ '\%()\|}\|"\)\s*,\s*\%(%.*\)\?$' " \ get(l:bibdict[l:bibfile],l:tlnr) !~ pattern_b let l:lline=substitute(get(l:bibdict[l:bibfile],l:tlnr+l:y-1),'\\"\|\\{\|\\}\|\\(\|\\)','','g') let l:pos=atplib#count(l:lline,"{") let l:neg=atplib#count(l:lline,"}") let l:m=l:pos-l:neg let l:pos=atplib#count(l:lline,"(") let l:neg=atplib#count(l:lline,")") let l:n=l:pos-l:neg let l:o=atplib#count(l:lline,"\"") " this checks if bracets {}, and () and "" appear in pairs in the current line: if l:m>0 || l:n>0 || l:o>l:o/2*2 while l:m>0 || l:n>0 || l:o>l:o/2*2 let l:pos=atplib#count(get(l:bibdict[l:bibfile],l:tlnr+l:y),"{") let l:neg=atplib#count(get(l:bibdict[l:bibfile],l:tlnr+l:y),"}") let l:m+=l:pos-l:neg let l:pos=atplib#count(get(l:bibdict[l:bibfile],l:tlnr+l:y),"(") let l:neg=atplib#count(get(l:bibdict[l:bibfile],l:tlnr+l:y),")") let l:n+=l:pos-l:neg let l:o+=atplib#count(get(l:bibdict[l:bibfile],l:tlnr+l:y),"\"") " Let's append the next line: let s:lbibd[l:lkey]=substitute(s:lbibd[l:lkey],'\s*$','','') . " ". substitute(get(l:bibdict[l:bibfile],l:tlnr+l:y),'^\s*','','') let l:y+=1 if l:y > 30 echoerr "ATP-Error /see :h atp-errors-bibsearch/, missing '}', ')' or '\"' in bibentry at line " . l:linenr . " (check line " . l:tlnr . ") in " . l:f) break endif endwhile endif endif endif " we have to go line by line and we could skip l:y+1 lines, but we have to " keep l:m, l:o values. It do not saves much. let l:x+=1 if l:x > 30 echoerr "ATP-Error /see :h atp-errors-bibsearch/, missing '}', ')' or '\"' in bibentry at line " . l:linenr . " in " . l:f break endif let b:x=l:x unlet l:tlnr endwhile let s:bibd[l:linenr]=s:lbibd unlet s:lbibd endfor let l:bibresults[l:bibfile]=s:bibd endfor if g:atp_debugBS silent! echo "atplib#bibsearch#searchbib_bibresults A =" . string(l:bibresults) redir END endif return l:bibresults endfunction "}}} " {{{ atplib#bibsearch#searchbib_py function! atplib#bibsearch#searchbib_py(bang,pattern, bibfiles, ...) " for tex files this should be a flat search. let flat = &filetype == "plaintex" ? 1 : 0 let bang = a:0 >=1 ? a:1 : "" let atp_MainFile = atplib#FullPath(b:atp_MainFile) let b:atp_BibFiles=a:bibfiles if a:bang != "!" let pattern = atplib#VimToPyPattern(a:pattern) else let pattern = a:pattern endif python << END import vim import re import locale from atplib.atpvim import readlines files=vim.eval("b:atp_BibFiles") def remove_ligatures(string): string = re.sub("\\\\'\s*", '', re.sub('{|}|\\\\(?:"|`|\^|=|\.|c|~|v|u|d|b|H|t)\s*', '', string)) string = re.sub('\\\\oe', 'oe', string) string = re.sub('\\\\OE', 'OE', string) string = re.sub('\\\\ae', 'ae', string) string = re.sub('\\\\AE', 'AE', string) string = re.sub('\\\\o', 'o', string) string = re.sub('\\\\O', 'O', string) string = re.sub('\\\\i', 'i', string) string = re.sub('\\\\j', 'j', string) string = re.sub('\\\\l', 'l', string) string = re.sub('\\\\L', 'L', string) return string def remove_quotes(string): line=re.sub("'", "\"", string) line=re.sub('\\\\', '', line) return line type_pattern=re.compile('\s*@(article|book|mvbook|inbook|bookinbook|suppbook|booklet|collection|mvcollection|incollection|suppcollection|manual|misc|online|patent|periodical|supppertiodical|proceedings|mvproceedings|inproceedings|reference|mvreference|inreference|report|set|thesis|unpublished|custom[a-f]|conference|electronic|masterthesis|phdthesis|techreport|www)', re.I) # types=['abstract', 'addendum', 'afterword', 'annotation', 'author', 'authortype', 'bookauthor', 'bookpaginator', 'booksupbtitle', 'booktitle', 'booktitleaddon', 'chapter', 'commentator', 'date', 'doi', 'edition', 'editor', 'editora', 'editorb', 'editorc', 'editortype', 'editoratype', 'editorbtype', 'editorctype', 'eid', 'eprint', 'eprintclass', 'eprinttype', 'eventdate', 'eventtile', 'file', 'forword', 'holder', 'howpublished', 'indxtitle', 'institution', 'introduction', 'isan', 'isbn', 'ismn', 'isrn', 'issn', 'issue', 'issuesubtitle', 'issuetitle', 'iswc', 'journalsubtitle', 'journaltitle', 'label', 'language', 'library', 'location', 'mainsubtitle', 'maintitle', 'maintitleaddon', 'month', 'nameaddon', 'note', 'number', 'organization', 'origdate', 'origlanguage', 'origpublisher', 'origname', 'pages', 'pagetotal', 'pagination', 'part', 'publisher', 'pubstate', 'reprinttitle', 'series', 'shortauthor', 'shorteditor', 'shorthand', 'shorthandintro', 'shortjournal', 'shortseries', 'subtitle', 'title', 'titleaddon', 'translator', 'type', 'url', 'urldate', 'venue', 'version', 'volume', 'volumes', 'year', 'crossref', 'entryset', 'entrysubtype', 'execute', 'mrreviewer'] types=['author', 'bookauthor', 'booktitle', 'date', 'editor', 'eprint', 'eprintclass', 'eprinttype', 'howpublished', 'institution', 'journal', 'month', 'note', 'number', 'organization', 'pages', 'publisher', 'school', 'series', 'subtitle', 'title', 'url', 'year', 'mrreviewer', 'volume', 'pages'] def parse_bibentry(bib_entry): bib={} bib['bibfield_key']=(re.sub('\\r$', '', bib_entry[0])) nr=1 while nr < len(bib_entry)-1: line=bib_entry[nr] if not re.match('\s*%', line): if not re.search('=', line): while not re.search('=', line) and nr < len(bib_entry)-1: val=re.sub('\s*$', '', bib[p_e_type])+" "+re.sub('^\s*', '', re.sub('\t', ' ', line)) val=re.sub('%.*', '', val) bib[p_e_type]=(remove_quotes(re.sub('\\r$', '', val))) nr+=1 line=bib_entry[nr] else: v_break=False for e_type in types: if re.match('\s*%s\s*=' % e_type, line, re.I): # TODO: this is not working when title is two lines long! line=re.sub('%.*', '', line) bib[e_type]=remove_quotes(re.sub('\\r$', '', re.sub('\t', ' ', line))) p_e_type=e_type nr+=1 v_break=True break if not v_break: nr+=1 return bib pattern=vim.eval("pattern") if pattern == "": pat="" else: pat=pattern pattern=re.compile(pat, re.I) pattern_b=re.compile('\s*@\w+\s*{.+', re.I) bibresults={} for file in files: file_l = readlines(file) file_len=len(file_l) lnr=0 bibresults[file]={} while lnr < file_len: lnr+=1 line=file_l[lnr-1] if re.search('@string', line): continue line_without_ligatures=remove_ligatures(line) if re.search(pattern, line_without_ligatures): """find first line""" b_lnr=lnr b_line=line while not re.match(pattern_b, b_line) and b_lnr >= 1: b_lnr-=1 b_line=file_l[b_lnr-1] """find last line""" e_lnr=lnr e_line=line if re.match(pattern_b, e_line): lnr+=1 e_lnr=lnr line=file_l[lnr-1] e_line=file_l[lnr-1] while not re.match(pattern_b, e_line) and e_lnr <= file_len: e_lnr+=1 e_line=file_l[min(e_lnr-1, file_len-1)] e_lnr-=1 e_line=file_l[min(e_lnr-1, file_len-1)] while re.match('\s*$', e_line): e_lnr-=1 e_line=file_l[e_lnr-1] bib_entry=file_l[b_lnr-1:e_lnr] if bib_entry != [] and not re.search('@string', bib_entry[0]): entry_dict=parse_bibentry(bib_entry) bibresults[file][str(b_lnr)]=entry_dict if lnr < e_lnr: lnr=e_lnr else: lnr+=1 if int(vim.eval("v:version")) < 703 or int(vim.eval("v:version")) == 703 and not int(vim.eval("has('patch569')")): import json vim.command("let bibresults=%s" % json.dumps(bibresults)) END if v:version == 703 && has('patch569') || v:version > 703 let bibresults = pyeval("bibresults") endif return bibresults endfunction "}}} " {{{ atplib#bibsearch#SearchBibItems " the argument should be b:atp_MainFile but in any case it is made in this way. " it specifies in which file to search for include files. function! atplib#bibsearch#SearchBibItems() let time=reltime() let atp_MainFile = atplib#FullPath(b:atp_MainFile) " we are going to make a dictionary { citekey : label } (see :h \bibitem) let l:citekey_label_dict={} " make a list of include files. let l:includefile_list=[] if !exists("b:ListOfFiles") || !exists("b:TypeDict") call TreeOfFiles(b:atp_MainFile) endif let i=1 for f in b:ListOfFiles let type = get(b:TypeDict, f, 'no_type') if type == 'no_type' && i call TreeOfFiles(b:atp_MainFile) let i=0 endif if b:TypeDict[f] == "input" call add(l:includefile_list, f) endif endfor call add(l:includefile_list, atp_MainFile) call map(l:includefile_list, 'atplib#FullPath(v:val)') if has("python") python << PEND import vim import re import atplib.atpvim as atp files=vim.eval("l:includefile_list") citekey_label_dict={} for f in files: f_l=atp.read(f).split("\n") for line in f_l: if re.match('[^%]*\\\\bibitem', line): match=re.search('\\\\bibitem\s*(?:\[([^\]]*)\])?\s*{([^}]*)}\s*(.*)', line) if match: label=match.group(1) if label == None: label = "" key=match.group(2) if key == None: key = "" rest=match.group(3) if rest == None: rest = "" if key != "": citekey_label_dict[key]={ 'label' : label, 'rest' : rest } vim.command("let l:citekey_label_dict="+str(citekey_label_dict)) PEND else " search for bibitems in all include files. for l:ifile in l:includefile_list let l:input_file = atplib#ReadInputFile(l:ifile,0) " search for bibitems and make a dictionary of labels and citekeys for l:line in l:input_file if l:line =~# '^[^%]*\\bibitem' let l:label=matchstr(l:line,'\\bibitem\s*\[\zs[^]]*\ze\]') let l:key=matchstr(l:line,'\\bibitem\s*\%(\[[^]]*\]\)\?\s*{\zs[^}]*\ze}') let l:rest=matchstr(l:line,'\\bibitem\s*\%(\[[^]]*\]\)\?\s*{[^}]*}\s*\zs') if l:key != "" call extend(l:citekey_label_dict, { l:key : { 'label' : l:label, 'rest' : l:rest } }, 'error') endif endif endfor endfor endif let g:time_SearchBibItems=reltimestr(reltime(time)) return l:citekey_label_dict endfunction " }}} "{{{ atplib#bibsearch#showresults " FLAGS: " for currently supported flags see ':h atp_bibflags' " All - all flags " L - last flag " a - author " e - editor " t - title " b - booktitle " j - journal " s - series " y - year " n - number " v - volume " p - pages " P - publisher " N - note " S - school " h - howpublished " o - organization " i - institution " R - mrreviewer function! atplib#bibsearch#showresults(bang, bibresults, flags, pattern, bibdict) "if nothing was found inform the user and return: if len(a:bibresults) == count(a:bibresults, {}) echo "BibSearch: no bib fields matched." if g:atp_debugBS exe "redir! >> ".g:atp_TempDir."/BibSeach.log" silent! echo "==========atplib#bibsearch#showresults=================" silent! echo "atplib#bibsearch#showresults return A - no bib fields matched. " redir END endif return 0 elseif g:atp_debugBS exe "redir! >> ".g:atp_TempDir."/BibSearch.log" silent! echo "==========atplib#bibsearch#showresults=================" silent! echo "atplib#bibsearch#showresults return B - found something. " redir END endif function! s:showvalue(value) return substitute(strpart(a:value,stridx(a:value,"=")+1),'^\s*','','') endfunction let s:z=1 let l:ln=1 let l:listofkeys={} "--------------SET UP FLAGS-------------------------- let l:allflagon=0 let l:flagslist=[] let l:kwflagslist=[] " flags o and i are synonims: (but refer to different entry keys): if a:flags =~# 'i' && a:flags !~# 'o' let l:flags=substitute(a:flags,'i','io','') elseif a:flags !~# 'i' && a:flags =~# 'o' let l:flags=substitute(a:flags,'o','oi','') endif if a:flags !~# 'All' if a:flags =~# 'L' " if strpart(a:flags,0,1) != '+' " let l:flags=b:atp_LastBibFlags . substitute(a:flags, 'L', '', 'g') " else let l:flags=b:atp_LastBibFlags . substitute(a:flags, 'L', '', 'g') " endif let g:atp_LastBibFlags = deepcopy(b:atp_LastBibFlags) else if a:flags == "" let l:flags=g:defaultbibflags elseif strpart(a:flags,0,1) != '+' && a:flags !~ 'All' let l:flags=a:flags elseif strpart(a:flags,0,1) == '+' && a:flags !~ 'All' let l:flags=g:defaultbibflags . strpart(a:flags,1) endif endif let b:atp_LastBibFlags=substitute(l:flags,'+\|L','','g') if l:flags != "" let l:expr='\C[' . g:bibflagsstring . ']' while len(l:flags) >=1 let l:oneflag=strpart(l:flags,0,1) " if we get a flag from the variable g:bibflagsstring we copy it to the list l:flagslist if l:oneflag =~ l:expr let l:flagslist=add(l:flagslist, l:oneflag) let l:flags=strpart(l:flags,1) " if we get '@' we eat ;) two letters to the list l:kwflagslist elseif l:oneflag == '@' let l:oneflag=strpart(l:flags,0,2) if index(keys(g:kwflagsdict),l:oneflag) != -1 let l:kwflagslist=add(l:kwflagslist,l:oneflag) endif let l:flags=strpart(l:flags,2) " remove flags which are not defined elseif l:oneflag !~ l:expr && l:oneflag != '@' let l:flags=strpart(l:flags,1) endif endwhile endif else " if the flag 'All' was specified. let l:flagslist=split(g:defaultallbibflags, '\zs') let l:af=substitute(a:flags,'All','','g') for l:kwflag in keys(g:kwflagsdict) if a:flags =~ '\C' . l:kwflag call extend(l:kwflagslist,[l:kwflag]) endif endfor endif "NEW: if there are only keyword flags append default flags if len(l:kwflagslist) > 0 && len(l:flagslist) == 0 let l:flagslist=split(g:defaultbibflags,'\zs') endif " Open a new window. let l:bufnr=bufnr("___Bibsearch: " . a:pattern . "___" ) if l:bufnr != -1 let l:bdelete=l:bufnr . "bwipeout" exe l:bdelete endif unlet l:bufnr let l:openbuffer=" +setl\\ buftype=nofile\\ filetype=bibsearch_atp " . fnameescape("___Bibsearch: " . a:pattern . "___") if g:vertical ==1 let l:openbuffer="keepalt vsplit " . l:openbuffer let l:skip="" else let l:openbuffer="keepalt split " . l:openbuffer let l:skip=" " endif let BufNr = bufnr("%") let LineNr = line(".") let ColNr = col(".") silent exe l:openbuffer " set the window options silent call atplib#setwindow() " make a dictionary of clear values, which we will fill with found entries. " the default value is no, which after all is matched and not showed " SPEED UP: let l:values={'bibfield_key' : 'nokey'} for l:flag in g:bibflagslist let l:values_clear=extend(l:values,{ g:bibflagsdict[l:flag][0] : 'no' . g:bibflagsdict[l:flag][0] }) endfor " SPEED UP: let l:kwflag_pattern="\\C" let l:len_kwflgslist=len(l:kwflagslist) let l:kwflagslist_rev=reverse(deepcopy(l:kwflagslist)) for l:lkwflag in l:kwflagslist if index(l:kwflagslist_rev,l:lkwflag) == 0 let l:kwflag_pattern.=g:kwflagsdict[l:lkwflag] else let l:kwflag_pattern.=g:kwflagsdict[l:lkwflag].'\|' endif endfor " let b:kwflag_pattern=l:kwflag_pattern for l:bibfile in keys(a:bibresults) if a:bibresults[l:bibfile] != {} call setline(l:ln, "Found in " . l:bibfile ) let l:ln+=1 endif for l:linenr in copy(sort(keys(a:bibresults[l:bibfile]), "atplib#CompareNumbers")) let l:values=deepcopy(l:values_clear) let b:values=l:values " fill l:values with a:bibrsults let l:values["bibfield_key"]=a:bibresults[l:bibfile][l:linenr]["bibfield_key"] " for l:key in keys(l:values) " if l:key != 'key' && get(a:bibresults[l:bibfile][l:linenr],l:key,"no" . l:key) != "no" . l:key " let l:values[l:key]=a:bibresults[l:bibfile][l:linenr][l:key] " endif " SPEED UP: call extend(l:values,a:bibresults[l:bibfile][l:linenr],'force') " endfor " ----------------------------- SHOW ENTRIES ------------------------- " first we check the keyword flags, @a,@b,... it passes if at least one flag " is matched let l:check=0 " for l:lkwflag in l:kwflagslist " let l:kwflagpattern= '\C' . g:kwflagsdict[l:lkwflag] " if l:values['bibfield_key'] =~ l:kwflagpattern " let l:check=1 " endif " endfor if l:values['bibfield_key'] =~ l:kwflag_pattern let l:check=1 endif if l:check == 1 || len(l:kwflagslist) == 0 let l:linenumber=index(a:bibdict[l:bibfile],l:values["bibfield_key"])+1 call setline(l:ln,s:z . ". line " . l:linenumber . " " . l:values["bibfield_key"]) let l:ln+=1 let l:c0=atplib#count(l:values["bibfield_key"],'{')-atplib#count(l:values["bibfield_key"],'(') " this goes over the entry flags: for l:lflag in l:flagslist " we check if the entry was present in bibfile: if l:values[g:bibflagsdict[l:lflag][0]] != "no" . g:bibflagsdict[l:lflag][0] " if l:values[g:bibflagsdict[l:lflag][0]] =~ a:pattern call setline(l:ln, l:skip . g:bibflagsdict[l:lflag][1] . " = " . s:showvalue(l:values[g:bibflagsdict[l:lflag][0]])) let l:ln+=1 " else " call setline(l:ln, l:skip . g:bibflagsdict[l:lflag][1] . " = " . s:showvalue(l:values[g:bibflagsdict[l:lflag][0]])) " let l:ln+=1 " endif endif endfor let l:lastline=getline(line('$')) let l:c1=atplib#count(l:lastline,'{')-atplib#count(l:lastline,'}') let l:c2=atplib#count(l:lastline,'(')-atplib#count(l:lastline,')') let l:c3=atplib#count(l:lastline,'\"') if l:c0 == 1 && l:c1 == -1 call setline(line('$'),substitute(l:lastline,'}\s*$','','')) call setline(l:ln,'}') let l:ln+=1 elseif l:c0 == 1 && l:c1 == 0 call setline(l:ln,'}') let l:ln+=1 elseif l:c0 == -1 && l:c2 == -1 call setline(line('$'),substitute(l:lastline,')\s*$','','')) call setline(l:ln,')') let l:ln+=1 elseif l:c0 == -1 && l:c1 == 0 call setline(l:ln,')') let l:ln+=1 endif let l:listofkeys[s:z]=l:values["bibfield_key"] let s:z+=1 endif endfor endfor if g:atp_debugBS let g:pattern = a:pattern endif if (has("python") || g:atp_bibsearch == "python") && a:bang == "!" let pattern_tomatch = atplib#VimToPyPattern(a:pattern) else let pattern_tomatch = a:pattern endif let pattern_tomatch = substitute(pattern_tomatch, '\Co', 'oe\\=', 'g') let pattern_tomatch = substitute(pattern_tomatch, '\CO', 'OE\\=', 'g') let pattern_tomatch = substitute(pattern_tomatch, '\Ca', 'ae\\=', 'g') let pattern_tomatch = substitute(pattern_tomatch, '\CA', 'AE\\=', 'g') if g:atp_debugBS let g:pm = pattern_tomatch endif let pattern_tomatch = join(split(pattern_tomatch, '\zs\\\@!\\\@= 1 ? a:1 : "" ) endfunction " }}} " atplib#callback#MakeidxReturnCode {{{ function! atplib#callback#MakeidxReturnCode(returncode,...) let b:atp_MakeidxReturnCode=a:returncode let b:atp_MakeidxOutput= ( a:0 >= 1 ? a:1 : "" ) endfunction " }}} " atplib#callback#Signs {{{ function! atplib#callback#Signs(bufnr) if has("signs") if a:bufnr != bufnr("%") if bufwinnr(str2nr(a:bufnr)) != -1 let cwinnr = bufwinnr(bufnr("%")) exe bufwinnr(str2nr(a:bufnr))."wincmd w" else return endif endif sign unplace * " This unplaces also signs not in the current buffer " This unplaces only signs in the current buffer, but uses " redir => var | signs place buffer=a:bufnr | redir END " construct which shows signs on the srceen for a second. " " There should be a function which lists signs. " " let more = &more " let lz = &lz " set nomore " setl lz " redir => unplace_signs " silent exe "sign place buffer=".a:bufnr " redir END " let &more = more " let &lz = lz " let signs = split(unplace_signs, "\n") " call map(signs, 'matchstr(v:val, ''\\zs\d\+\ze'')') " for sign in signs " exe "sign unplace ".sign." buffer=".a:bufnr " endfor " unlet sign " unlet signs " unlet unplace_signs " There is no way of getting list of defined signs in the current buffer. " Thus there is no proper way of deleting them. I overwrite them using " numbers as names. The vim help tells that there might be at most 120 " signs. " But this is not undefineing signs. let qflist=getqflist() let i=1 for item in qflist if item['type'] == 'E' let hl = 'ErrorMsg' elseif item['type'] == 'W' let hl = 'WarningMsg' else let hl = 'Normal' endif exe 'sign define '.i.' text='.item['type'].': texthl='.hl if g:atp_ParseLog let file = bufname(item['bufnr']) if file != "" && bufloaded(file) exe 'sign place '.i.' line='.item['lnum'].' name='.i.' file='.file endif else exe 'sign place '.i.' line='.item['lnum'].' name='.i.' file='.expand('%:p') endif let i+=1 endfor if exists("cwinnr") exe cwinnr."wincmd w" unlet cwinnr endif endif endfunction "}}} " atplib#callback#CallBack {{{ " a:mode = a:verbose of s:compiler ( one of 'default', 'silent', " 'debug', 'verbose') " a:commnad = a:commmand of s:compiler " ( a:commnad = 'AU' if run from background) " " Uses b:atp_TexReturnCode which is equal to the value returned by tex " compiler. function! atplib#callback#CallBack(bufnr,mode,...) " If the compiler was called by autocommand. let AU = ( a:0 >= 1 ? a:1 : 'COM' ) " Was compiler called to make bibtex let BIBTEX = ( a:0 >= 2 ? a:2 : "False" ) let BIBTEX = ( BIBTEX == "True" || BIBTEX == 1 ? 1 : 0 ) let MAKEIDX = ( a:0 >= 3 ? a:3 : "False" ) let MAKEIDX = ( MAKEIDX == "TRUE" || MAKEIDX == 1 ? 1 : 0 ) if g:atp_debugCallBack exe "redir! > ".g:atp_TempDir."/CallBack.log" endif for cmd in keys(g:CompilerMsg_Dict) if b:atp_TexCompiler =~ '^\s*' . cmd . '\s*$' let Compiler = g:CompilerMsg_Dict[cmd] break else let Compiler = b:atp_TexCompiler endif endfor let b:atp_running = b:atp_running - 1 " Read the log file cgetfile if v:version < 703 || v:version == 703 && !has("patch648") call atplib#compiler#FilterQuickFix() endif " signs if g:atp_signs call atplib#callback#Signs(a:bufnr) endif if g:atp_debugCallBack silent echo "file=".expand("%:p") silent echo "g:atp_HighlightErrors=".g:atp_HighlightErrors endif if g:atp_HighlightErrors call atplib#callback#HighlightErrors() endif " /this cgetfile is not working (?)/ let error = len(getqflist()) + (BIBTEX ? b:atp_BibtexReturnCode : 0) " If the log file is open re read it / it has 'autoread' opion set / checktime " redraw the status line /for the notification to appear as fast as " possible/ if a:mode != 'verbose' redrawstatus endif " redraw has values -0,1 " 1 do not redraw " 0 redraw " i.e. redraw at the end of function (this is done to not redraw twice in " this function) let l:clist = 0 let atp_DebugMode = t:atp_DebugMode if b:atp_TexReturnCode == 0 && ( a:mode == 'silent' || atp_DebugMode == 'silent' ) && g:atp_DebugMode_AU_change_cmdheight let &l:cmdheight=g:atp_cmdheight endif if g:atp_debugCallBack let g:debugCB = 0 let g:debugCB_mode = a:mode let g:debugCB_error = error silent echo "mode=".a:mode."\nerror=".error endif let msg_list = [] let showed_message = 0 if a:mode == "silent" && !error if t:atp_QuickFixOpen if g:atp_debugCallBack let g:debugCB .= 7 endif if a:mode =~ "^auto" && t:atp_QuickFixOpen cclose call add(msg_list, ["[ATP:] no errors, closing quick fix window.", "Normal"]) endif endif " elseif a:mode == "silent" && AU == "COM" " if b:atp_TexReturnCode " let showed_message = 1 " call add(msg_list, ["[ATP:] ".Compiler." returned with exit code ".b:atp_TexReturnCode.".", 'ErrorMsg', 'after']) " endif " if BIBTEX && b:atp_BibtexReturnCode " let showed_message = 1 " call add(msg_list, ["[ATP:] ".b:atp_BibCompiler." returned with exit code ".b:atp_BibtexReturnCode.".", 'ErrorMsg', 'after']) " endif " if MAKEIDX && b:atp_Makeindex " let showed_message = 1 " call add(msg_list, ["[ATP:] makeidx returned with exit code ".b:atp_MakeidxReturnCode.".", 'ErrorMsg', 'after']) " endif endif if a:mode =~ 'auto' && !error if g:atp_debugCallBack let g:debugCB .= 3 endif call add(msg_list,["[ATP:] ".b:atp_TexCompiler." returned without errors [b:atp_ErrorFormat=".b:atp_ErrorFormat."]".(g:atp_DefaultDebugMode=='silent'&&atp_DebugMode!='silent'?"\ngoing out of debuging mode.": "."), "Normal", "after"]) let showed_message = 1 let t:atp_DebugMode = g:atp_DefaultDebugMode if a:mode =~ "auto" && t:atp_QuickFixOpen cclose endif let &l:cmdheight = g:atp_cmdheight endif " debug mode with errors if a:mode ==? 'debug' && error if len(getqflist()) if g:atp_debugCallBack let g:debugCB .= 4 endif let &l:cmdheight = g:atp_DebugModeCmdHeight let showed_message = 1 if b:atp_ReloadOnError || b:atp_Viewer !~ '^\s*xpdf\>' call add(msg_list, ["[ATP:] ".Compiler." returned with exit code " . b:atp_TexReturnCode . ".", (b:atp_TexReturnCode ? "ErrorMsg" : "Normal"), "before"]) else call add(msg_list, ["[ATP:] ".Compiler." returned with exit code " . b:atp_TexReturnCode . " output file not reloaded.", (b:atp_TexReturnCode ? "ErrorMsg" : "Normal"), "before"]) endif if !t:atp_QuickFixOpen let l:clist = 1 endif endif if BIBTEX && b:atp_BibtexReturnCode let l:clist = 1 call add(msg_list, [ "[Bib:] ".b:atp_BibtexCompiler." returned with exit code ".b:atp_BibtexReturnCode .".", "ErrorMsg", "after"]) call add(msg_list, [ "BIBTEX_OUTPUT" , "Normal", "after"]) endif if MAKEIDX && b:atp_MakeidxReturnCode let l:clist = 1 call add(msg_list, [ "[Bib:] makeidx returned with exit code ".b:atp_MakeidxReturnCode .".", "ErrorMsg", "after"]) call add(msg_list, [ "MAKEIDX_OUTPUT" , "Normal", "after"]) endif " In debug mode, go to first error. if a:mode ==# "Debug" if g:atp_debugCallBack let g:debugCB .= 6 endif cc endif endif if msg_list == [] if g:atp_debugCallBack redir END endif return endif " Count length of the message: let msg_len = len(msg_list) if len(filter(copy(msg_list), "v:val[0] == 'BIBTEX_OUTPUT'")) let msg_len += (BIBTEX ? len(split(b:atp_BibtexOutput, "\\n")) - 1 : - 1 ) endif if len(filter(copy(msg_list), "v:val[0] == 'MAKEIDX_OUTPUT'")) let msg_len += (MAKEIDX ? len(split(b:atp_MakeidxOutput, "\\n")) - 1 : - 1 ) endif " We never show qflist: (that's why it is commented out) " let msg_len += ((len(getqflist()) <= 7 && !t:atp_QuickFixOpen) ? len(getqflist()) : 0 ) " Show messages/clist if g:atp_debugCallBack let g:msg_list = msg_list let g:clist = l:clist silent echo "msg_list=\n**************\n".join(msg_list, "\n")."\n**************" silent echo "l:clist=".l:clist endif let cmdheight = &l:cmdheight if msg_len <= 2 let add=0 elseif msg_len <= 7 let add=1 else let add=2 endif let &l:cmdheight = max([cmdheight, msg_len+add]) let g:msg_len=msg_len if l:clist && len(getqflist()) > 7 && !t:atp_QuickFixOpen let winnr = winnr() copen exe winnr."wincmd w" elseif (a:mode ==? "debug") && !t:atp_QuickFixOpen let l:clist = 1 endif redraw let before_msg = filter(copy(msg_list), "v:val[2] == 'before'") let after_msg = filter(copy(msg_list), "v:val[2] == 'after'") for msg in before_msg exe "echohl " . msg[1] echo msg[0] endfor let l:redraw = 1 if l:clist && len(getqflist()) <= 7 && !t:atp_QuickFixOpen if g:atp_debugCallBack let g:debugCB .= "clist" endif try clist catch E42: endtry let l:redraw = 0 endif for msg in after_msg exe "echohl " . msg[1] if msg[0] !=# "BIBTEX_OUTPUT" echo msg[0] else echo " ".substitute(b:atp_BibtexOutput, "\n", "\n ", "g") " let bib_output=split(b:atp_BibtexOutput, "\n") " let len=max([10,len(bib_output)]) " below split +setl\ buftype=nofile\ noswapfile Bibtex\ Output " setl nospell " setl nonumber " setl norelativenumber " call append(0,bib_output) " resize 10 " redraw! " normal gg " nmap q :bd let g:debugCB .=" BIBTEX_output " endif endfor echohl None if len(msg_list)==0 redraw endif let &l:cmdheight = cmdheight if g:atp_debugCallBack redir END endif endfunction "}}} "{{{ atplib#callback#LatexPID "Store LatexPIDs in a variable function! atplib#callback#LatexPID(pid) call add(b:atp_LatexPIDs, a:pid) let b:atp_LastLatexPID=a:pid endfunction "}}} "{{{ atplib#callback#BibtexPID "Store BibtexPIDs in a variable function! atplib#callback#BibtexPID(pid) call add(b:atp_BibtexPIDs, a:pid) endfunction "}}} "{{{ atplib#callback#MakeindexPID "Store MakeindexPIDs in a variable function! atplib#callback#MakeindexPID(pid) call add(b:atp_MakeindexPIDs, a:pid) let b:atp_LastMakeindexPID =a:pid endfunction "}}} "{{{ atplib#callback#PythonPID "Store PythonPIDs in a variable function! atplib#callback#PythonPID(pid) call add(b:atp_PythonPIDs, a:pid) endfunction "}}} "{{{ atplib#callback#MakeindexPID "Store MakeindexPIDs in a variable function! atplib#callback#PythonPIDs(pid) call add(b:atp_PythonPIDs, a:pid) let b:atp_LastPythonPID =a:pid endfunction "}}} "{{{ atplib#callback#PIDsRunning function! atplib#callback#PIDsRunning(var) " a:var is a string, and might be one of 'b:atp_LatexPIDs', 'b:atp_BibtexPIDs' or " 'b:atp_MakeindexPIDs'. PIDs that are not running are removed from this list. python << EOL import sys import re import vim import psutil var = vim.eval("a:var") pids = vim.eval(var) if len(pids) > 0: ps_list=psutil.get_pid_list() rmpids=[] for lp in pids: run=False for p in ps_list: if str(lp) == str(p): run=True break if not run: rmpids.append(lp) rmpids.sort() rmpids.reverse() for pid in rmpids: vim.eval("filter("+var+", 'v:val !~ \""+str(pid)+"\"')") EOL endfunction "}}} "{{{ atplib#callback#ProgressBar function! atplib#callback#ProgressBar(value,pid,bufnr) if !exists("g:atp_callback") || !g:atp_callback return endif if !exists("g:atp_ProgressBarValues") let g:atp_ProgressBarValues = { a:bufnr : {} } endif if !has_key(g:atp_ProgressBarValues, a:bufnr) call extend(g:atp_ProgressBarValues, { a:bufnr, {} }) endif if a:value != 'end' let g:atp_ProgressBarValues[a:bufnr][a:pid] = a:value else call remove(g:atp_ProgressBarValues[a:bufnr], a:pid) endif if bufwinnr(a:bufnr) != -1 redrawstatus endif endfunction "}}} "{{{ atplib#callback#redrawstatus function! atplib#callback#redrawstatus() redrawstatus endfunction "}}} "{{{ atplib#callback#CursorMoveI " function! atplib#callback#CursorMoveI() " if mode() != "i" " return " endif " let cursor_pos=[ line("."), col(".")] " call feedkeys("\", "n") " call cursor(cursor_pos) " endfunction "}}} " {{{ atplib#callback#HighlightErrors function! atplib#callback#HighlightErrors() call atplib#callback#ClearHighlightErrors() let qf_list = getqflist() for error in qf_list if error.type ==? 'e' let hlgroup = g:atp_Highlight_ErrorGroup else let hlgroup = g:atp_Highlight_WarningGroup endif if hlgroup == "" continue endif let m_id = matchadd(hlgroup, '\%'.error.lnum.'l.*', 20) call add(s:matchid, m_id) let error_msg=split(error.text, "\n") endfor endfunction "}}} " {{{ atplib#callback#ClearHighlightErrors function! atplib#callback#ClearHighlightErrors() if !exists("s:matchid") let s:matchid=[] return endif for m_id in s:matchid try silent call matchdelete(m_id) catch /E803:/ endtry endfor let s:matchid=[] endfunction "}}} "{{{ atplib#callback#Echo function! atplib#callback#Echo(msg, cmd, hlgroup, ...) if a:0 >= 1 && a:1 redraw endif exe "echohl ".a:hlgroup exe a:cmd." '".a:msg."'" echohl None endfunction "}}} " vim:fdm=marker:ff=unix:noet:ts=8:sw=4:fdc=1 autoload/atplib/common.vim [[[1 127 " Author: Marcin Szamotulski " Description: This script has functions which have to be called before ATP_files/options.vim " Note: This file is a part of Automatic Tex Plugin for Vim. " Language: tex " This file contains set of functions which are needed to set to set the atp " options and some common tools. " Set the project name "{{{ atplib#common#SetProjectName (function and autocommands) " This function sets the main project name (b:atp_MainFile) " " It is used by EditInputFile which copies the value of this variable to every " input file included in the main source file. " " nmap gf (GotoFile function) is not using this function. " " the b:atp_MainFile variable is set earlier in the startup " (by the augroup ATP_Syntax_TikzZone), calling SetProjectName to earlier cause " problems (g:atp_raw_bibinputs undefined). " " ToDo: CHECK IF THIS IS WORKS RECURSIVELY? " ToDo: THIS FUNCTION SHUOLD NOT SET AUTOCOMMANDS FOR AuTeX function! " every tex file should be compiled (the compiler function calls the " right file to compile! " " {{{ atplib#common#SetProjectName ( function ) " store a list of all input files associated to some file function! atplib#common#SetProjectName(...) let bang = ( a:0 >= 1 ? a:1 : "" ) " do we override b:atp_project let did = ( a:0 >= 2 ? a:2 : 1 ) " do we check if the project name was set " but also overrides the current b:atp_MainFile when 0 " if the project name was already set do not set it for the second time " (which sets then b:atp_MainFile to wrong value!) if &filetype == "fd_atp" " this is needed for EditInputFile function to come back to the main " file. let b:atp_MainFile = ( g:atp_RelativePath ? expand("%:t") : expand("%:p") ) let s:did_project_name = 1 endif let g:did_project_name = (exists("s:did_project_name") ? s:did_project_name : -1) if exists("s:did_project_name") && s:did_project_name && did && exists("b:atp_MainFile") return " project name was already set" else let s:did_project_name = 1 endif let b:atp_MainFile = exists("b:atp_MainFile") && did ? b:atp_MainFile : \ ( g:atp_RelativePath ? expand("%:t") : expand("%:p") ) if !exists("b:atp_ProjectDir") let b:atp_ProjectDir = ( exists("b:atp_ProjectScriptFile") ? fnamemodify(b:atp_ProjectScriptFile, ":h") : fnamemodify(resolve(expand("%:p")), ":h") ) endif endfunction " }}} "}}} " This functions sets the value of b:atp_OutDir variable " {{{ atplib#common#SetOutDir " This options are set also when editing .cls files. " It can overwrite the value of b:atp_OutDir " if arg != 0 then set errorfile option accordingly to b:atp_OutDir " if a:0 >0 0 then b:atp_atp_OutDir is set iff it doesn't exsits. function! atplib#common#SetOutDir(arg, ...) if exists("b:atp_OutDir") && a:0 >= 1 return "atp_OutDir EXISTS" endif " if the user want to be asked for b:atp_OutDir if g:askfortheoutdir == 1 let b:atp_OutDir=substitute(input("Where to put output? do not escape white spaces "), '\\\s', ' ', 'g') endif if ( get(getbufvar(bufname("%"),""),"outdir","optionnotset") == "optionnotset" \ && g:askfortheoutdir != 1 \ || b:atp_OutDir == "" && g:askfortheoutdir == 1 ) \ && !exists("$TEXMFOUTPUT") let b:atp_OutDir=( exists("b:atp_ProjectScriptFile") ? fnamemodify(b:atp_ProjectScriptFile, ":h") : fnamemodify(resolve(expand("%:p")), ":h") ) elseif exists("$TEXMFOUTPUT") let b:atp_OutDir=substitute($TEXMFOUTPUT, '\\\s', ' ', 'g') endif " if arg != 0 then set errorfile option accordingly to b:atp_OutDir if bufname("") =~ ".tex$" && a:arg != 0 call atplib#common#SetErrorFile() endif if exists("g:outdir_dict") let g:outdir_dict = extend(g:outdir_dict, {fnamemodify(bufname("%"),":p") : b:atp_OutDir }) else let g:outdir_dict = { fnamemodify(bufname("%"),":p") : b:atp_OutDir } endif return b:atp_OutDir endfunction " }}} " This function sets vim 'errorfile' option. "{{{ atplib#common#SetErrorFile " let &l:errorfile=b:atp_OutDir . fnameescape(fnamemodify(expand("%"),":t:r")) .".(g:atp_ParseLog ? "_" : "")." "log" if !exists("g:atp_ParseLog") let g:atp_ParseLog = has("python") endif function! atplib#common#SetErrorFile() " set b:atp_OutDir if it is not set if !exists("b:atp_OutDir") call atplib#common#SetOutDir(0) endif " set the b:atp_MainFile varibale if it is not set (the project name) if !exists("b:atp_MainFile") call atplib#common#SetProjectName() endif let main_file = atplib#FullPath(b:atp_MainFile) " vim doesn't like escaped spaces in file names ( cg, filereadable(), " writefile(), readfile() - all acepts a non-escaped white spaces) let &l:errorfile = atplib#joinpath(expand(b:atp_OutDir), fnamemodify(main_file,":t:r") . ".".(g:atp_ParseLog ? "_" : "")."log") return &l:errorfile endfunction "}}} " vim:fdm=marker:tw=85:ff=unix:noet:ts=8:sw=4:fdc=1 autoload/atplib/compiler.vim [[[1 2627 " Author: Marcin Szamotulski " Note: this file contain the main compiler function and related tools, to " view the output, see error file. " Note: This file is a part of Automatic Tex Plugin for Vim. " Language: tex " Internal Variables " {{{ " This limits how many consecutive runs there can be maximally. " Note: compile.py script has hardcoded the same value. let s:runlimit = 9 " }}} " This is the function to view output. It calls compiler if the output is a not " readable file. " {{{ atplib#compiler#ViewOutput " a:1 == "RevSearch" if run from RevSearch() function and the output file doesn't " exsists call compiler and RevSearch(). function! atplib#compiler#ViewOutput(bang,tex_file,xpdf_server,...) let tex_file = atplib#FullPath(a:tex_file) let fwd_search = ( a:bang == "!" ? 1 : 0 ) " Set the correct output extension (if nothing matches set the default '.pdf') let ext = get(g:atp_CompilersDict, matchstr(b:atp_TexCompiler, '^\s*\zs\S\+\ze'), ".pdf") " Read the global options from g:atp_{b:atp_Viewer}Options variables let global_options = join(map(copy(exists("g:atp_".matchstr(b:atp_Viewer, '^\s*\zs\S\+\ze')."Options") ? g:atp_{matchstr(b:atp_Viewer, '^\s*\zs\S\+\ze')}Options : []), 'shellescape(v:val)'), " ") let local_options = join(map(copy(exists("b:atp_".matchstr(b:atp_Viewer, '^\s*\zs\S\+\ze')."Options") ? getbufvar(bufnr("%"), "atp_".matchstr(b:atp_Viewer, '^\s*\zs\S\+\ze')."Options") : []), 'shellescape(v:val)'), " ") " Follow the symbolic link let link=resolve(tex_file) if link != tex_file let outfile = fnamemodify(link, ":r") . ext else let outfile = atplib#joinpath(expand(b:atp_OutDir), fnamemodify(a:tex_file, ':t:r') . ext) endif if b:atp_Viewer == "xpdf" let viewer = b:atp_Viewer . " -remote " . shellescape(a:xpdf_server) else let viewer = b:atp_Viewer . " " endif if g:atp_debugV let g:global_options = global_options let g:local_options = local_options let g:viewer = viewer let g:outfile = outfile let g:tex_file = a:tex_file endif let view_cmd = viewer." ".global_options." ".local_options." ".shellescape(outfile)." &" if g:atp_debugV let g:view_cmd = view_cmd endif if filereadable(outfile) if b:atp_Viewer == "xpdf" call system(view_cmd) else call system(view_cmd) redraw! endif else echomsg "[ATP:] output file do not exists. Calling " . b:atp_TexCompiler if fwd_search if g:atp_Compiler == 'python' call atplib#compiler#PythonCompiler( 0, 2, 1, 'silent' , "AU" , tex_file, "") else call atplib#compiler#Compiler( 0, 2, 1, 'silent' , "AU" , tex_file, "") endif else if g:atp_Compiler == 'python' call atplib#compiler#PythonCompiler( 0, 1, 1, 'silent' , "AU" , tex_file, "") else call atplib#compiler#Compiler( 0, 1, 1, 'silent' , "AU" , tex_file, "") endif endif endif if fwd_search let msg = "[SyncTex:] waiting for the viewer " let i=1 let max=20 while !atplib#compiler#IsRunning(b:atp_Viewer, outfile) && i<=max echo msg sleep 100m redraw let msg.="." let i+=1 endwhile exe "sleep ".g:atp_OpenAndSyncSleepTime if i<=max call atplib#compiler#SyncTex("", 0, fnamemodify(a:tex_file, ':t'), a:xpdf_server) else echohl WarningMsg echomsg "[SyncTex:] viewer is not running" echohl None endif endif endfunction "}}} " Forward Search: " {{{ atplib#compiler#GetSyncData function! atplib#compiler#GetSyncData(line, col, file) if !filereadable(atplib#joinpath(expand(b:atp_OutDir), fnamemodify(a:file, ":t:r").'.synctex.gz')) redraw! " We use "system(cmd)" rather than ATP :Tex command, since we " don't want to background. let cmd=b:atp_TexCompiler." -output-directory=".shellescape(expand(b:atp_OutDir))." ".join(split(b:atp_TexOptions, ','), " ")." ".shellescape(atplib#FullPath(a:file)) if b:atp_TexOptions !~ '\%(-synctex\s*=\s*1\|-src-specials\>\)' echomsg "[SyncTex:] b:atp_TexOptions does not contain -synctex=1 or -src-specials switches!" return else echomsg "[SyncTex:] calling ".get(g:CompilerMsg_Dict, b:atp_TexCompiler, b:atp_TexCompiler)." to generate synctex data. Wait a moment..." endif call system(cmd) endif " Note: synctex view -i line:col:tex_file -o output_file " tex_file must be full path. let synctex_cmd="synctex view -i ".a:line.":".a:col.":'".expand("%:p")."' -o '".atplib#joinpath(expand(b:atp_OutDir), fnamemodify(a:file,":r").".pdf'") " SyncTex is fragile for the file name: if it is file name or full path, it " must agree literally with what is written in .synctex.gz file " first we try with full path then fullpath with /./ included and then with file name without path. let synctex_output=split(system(synctex_cmd), "\n") if get(synctex_output, 1, '') =~ '^SyncTex Warning: No tag for' " Write better test (above) let cwd = getcwd() exe "lcd ".fnameescape(b:atp_ProjectDir) let path = getcwd()."/./".expand("%:.") exe "lcd ".fnameescape(cwd) let synctex_cmd="synctex view -i ".a:line.":".a:col.":'".path. "' -o '".fnamemodify(atplib#FullPath(a:file), ":r").".pdf'" let synctex_output=split(system(synctex_cmd), "\n") if get(synctex_output, 1, '') =~ '^SyncTex Warning:' return [ "no_sync", get(synctex_output, 1, ''), 0 ] endif let synctex_output=split(system(synctex_cmd), "\n") if get(synctex_output, 1, '') =~ '^SyncTex Warning: No tag for' let synctex_cmd="synctex view -i ".a:line.":".a:col.":'".a:file. "' -o '".fnamemodify(atplib#FullPath(a:file), ":r").".pdf'" let synctex_output=split(system(synctex_cmd), "\n") if get(synctex_output, 1, '') =~ '^SyncTex Warning:' return [ "no_sync", get(synctex_output, 1, ''), 0 ] endif endif endif if g:atp_debugSync let g:synctex_cmd=synctex_cmd let g:synctex_output=copy(synctex_output) endif let page_list=copy(synctex_output) call filter(page_list, "v:val =~ '^\\cpage:\\d\\+'") let page=get(page_list, 0, "no_sync") let y_coord_list=copy(synctex_output) call filter(y_coord_list, "v:val =~ '^\\cy:\\d\\+'") let y_coord=get(y_coord_list, 0, "no sync data") let y_coord= ( y_coord != "no sync data" ? matchstr(y_coord, 'y:\zs[0-9.]*') : y_coord ) let x_coord_list=copy(synctex_output) call filter(x_coord_list, "v:val =~ '^\\cx:\\d\\+'") let x_coord=get(x_coord_list, 0, "no sync data") let x_coord= ( x_coord != "no sync data" ? matchstr(x_coord, 'x:\zs[0-9.]*') : x_coord ) if g:atp_debugSync let g:page=page let g:y_coord=y_coord let g:x_coord=x_coord endif if page == "no_sync" return [ "no_sync", "No SyncTex Data: try on another line (or recompile the document).", 0 ] endif let page_nr=matchstr(page, '^\cPage:\zs\d\+') let [ b:atp_synctex_pagenr, b:atp_synctex_ycoord, b:atp_synctex_xcoord ] = [ page_nr, y_coord, x_coord ] return [ page_nr, y_coord, x_coord ] endfunction function! atplib#compiler#SyncShow( page_nr, y_coord) if a:y_coord < 300 let height="top" elseif a:y_coord < 500 let height="middle" else let height="bottom" endif if a:page_nr != "no_sync" echomsg "[SyncTex:] ".height." of page ".a:page_nr else echohl WarningMsg echomsg "[SyncTex:] ".a:y_coord " echomsg " You cannot forward search on comment lines, if this is not the case try one or two lines above/below" echohl None endif endfunction "}}} " {{{ atplib#compiler#SyncTex function! atplib#compiler#SyncTex(bang, mouse, main_file, xpdf_server, ...) if g:atp_debugSyncTex exe "redir! > ".g:atp_TempDir."/SyncTex.log" endif let output_check = ( a:0 >= 1 && a:1 == 0 ? 0 : 1 ) let IsRunning_check = ( a:bang == "!" ? 0 : 1 ) let dryrun = ( a:0 >= 2 && a:2 == 1 ? 1 : 0 ) " Mouse click is mapped to ... => thus it first changes " the cursor position. let [ line, col ] = [ line("."), col(".") ] let main_file = atplib#FullPath(a:main_file) let ext = get(g:atp_CompilersDict, matchstr(b:atp_TexCompiler, '^\s*\zs\S\+\ze'), ".pdf") let output_file = atplib#joinpath(expand(b:atp_OutDir), fnamemodify(main_file,":t:r") . ext) if !filereadable(output_file) && output_check " Here should be a test if viewer is running, this can be made with python. " this is way viewer starts not well when using :SyncTex command while Viewer " is not running. " call atplib#compiler#ViewOutput("sync") " if g:atp_debugSyncTex " silent echo "ViewOutput sync" " redir END " endif echohl WarningMsg echomsg "[SyncTex:] no output file" echohl None return 2 endif if IsRunning_check if (!atplib#compiler#IsRunning(b:atp_Viewer, output_file, a:xpdf_server) && output_check) "Note: I should test here if Xpdf is not holding a file (it might be not "visible through cmdline arguments -> this happens if file is opened in "another server. We can use: xpdf -remote a:xpdf_server "run('echo %f')" echohl WarningMsg echomsg "[SyncTex:] please open the file first. (if file is opend add bang \"!\")" echohl None return endif endif if b:atp_Viewer == "xpdf" let [ page_nr, y_coord, x_coord ] = atplib#compiler#GetSyncData(line, col, a:main_file) let sync_cmd_page = "xpdf -remote " . shellescape(a:xpdf_server) . " -exec 'gotoPage(".page_nr.")'" let sync_cmd_y = "xpdf -remote " . shellescape(a:xpdf_server) . " -exec 'scrollDown(".y_coord.")'" let sync_cmd_x = "xpdf -remote " . shellescape(a:xpdf_server) . " -exec 'scrollRight(".x_coord.")'" " let sync_cmd = "xpdf -remote " . shellescape(a:xpdf_server) . " -exec 'gotoPage(".page_nr.")'"." -exec 'scrollDown(".y_coord.")'"." -exec 'scrollRight(".x_coord.")'" " There is a bug in xpdf. We need to sleep between sending commands: let sleep = ( g:atp_XpdfSleepTime ? 'sleep '.string(g:atp_XpdfSleepTime).'s;' : '' ) let sync_cmd = "(".sync_cmd_page.";".sleep.sync_cmd_y.")&" if !dryrun call system(sync_cmd) call atplib#compiler#SyncShow(page_nr, y_coord) endif elseif b:atp_Viewer == "okular" let [ page_nr, y_coord, x_coord ] = atplib#compiler#GetSyncData(line, col, a:main_file) " This will not work in project files. (so where it is mostly needed.) let sync_cmd = "okular --unique ".shellescape(fnamemodify(main_file, ":p:r").".pdf")."\\#src:".line.shellescape(expand("%:p"))." &" if !dryrun call system(sync_cmd) call atplib#compiler#SyncShow(page_nr, y_coord) endif elseif b:atp_Viewer =~ '^\s*open' let [ page_nr, y_coord, x_coord ] = atplib#compiler#GetSyncData(line, col, a:main_file) let sync_cmd = g:atp_DisplaylinePath." ".line." ".shellescape(fnamemodify(atplib#FullPath(b:atp_MainFile), ":r").".pdf")." ".shellescape(expand("%:p"))." &" if !dryrun call system(sync_cmd) call atplib#compiler#SyncShow(page_nr, y_coord) endif elseif b:atp_Viewer == "evince" let curr_file = atplib#FullPath(expand("%:p")) let evince_sync=split(globpath(&rtp, "ftplugin/ATP_files/evince_sync.py"), "\n")[0] let sync_cmd = g:atp_Python." ".shellescape(evince_sync)." EVINCE ".shellescape(output_file)." ".line." ".shellescape(curr_file) call system(sync_cmd) elseif b:atp_Viewer =~ '^\s*xdvi\>' if exists("g:atp_xdviOptions") let options = " ".join(map(copy(g:atp_xdviOptions), 'shellescape(v:val)'), " ") elseif exists("b:atp_xdviOptions") let options = " ".join(map(copy(b:atp_xdviOptions), 'shellescape(v:val)'), " ") else let options = " " endif let sync_cmd = "xdvi ".options. \ " -editor '".v:progname." --servername ".v:servername. \ " --remote-wait +%l %f' -sourceposition ". \ line.":".col.shellescape(fnameescape(fnamemodify(expand("%"),":p"))). \ " ".fnameescape(output_file)." &" if !dryrun call system(sync_cmd) endif if g:atp_debugSyncTex silent echo "sync_cmd=".sync_cmd endif else let sync_cmd="" if g:atp_debugSyncTex silent echo "sync_cmd=EMPTY" endif endif if g:atp_debugSyncTex let g:sync_cmd = sync_cmd endif if g:atp_debugSyncTex redir END endif return endfunction "}}} " " This function gets the pid of the running compiler " ToDo: review, LatexBox has a better approach! "{{{ Get PID Functions function! atplib#compiler#getpid() let atplib#compiler#command="ps -ef | grep -v " . $SHELL . " | grep " . b:atp_TexCompiler . " | grep -v grep | grep " . fnameescape(expand("%")) . " | awk 'BEGIN {ORS=\" \"} {print $2}'" let atplib#compiler#var = system(atplib#compiler#command) return atplib#compiler#var endfunction " The same but using python (it is not used) " TODO: end this. function! atplib#compiler#PythonGetPID() python << EOF import psutil latex = vim.eval("b:atp_TexCompiler") # Make dictionary: xpdf_servername : file # to test if the server host file use: # basename(xpdf_server_file_dict().get(server, ['_no_file_'])[0]) == basename(file) ps_list=psutil.get_pid_list() latex_running = False for pr in ps_list: try: name=psutil.Process(pr).name cmdline=psutil.Process(pr).cmdline if name == latex: latex_pid=pr latex_running=True break except psutil.error.NoSuchProcess: pass except psutil.error.AccessDenied: pass if latex_running: vim.command("let atplib#compiler#var=%s" % latex_pid) else: vim.command("let atplib#compiler#var=''") EOF endfunction function! atplib#compiler#GetPID() if g:atp_Compiler == "bash" let atplib#compiler#var=atplib#compiler#getpid() if atplib#compiler#var != "" echomsg "[ATP:] ".b:atp_TexCompiler . " pid(s): " . atplib#compiler#var else let b:atp_running = 0 echomsg "[ATP:] ".b:atp_TexCompiler . " is not running" endif else call atplib#callback#PIDsRunning("b:atp_LatexPIDs") if len(b:atp_LatexPIDs) > 0 echomsg "[ATP:] ".b:atp_TexCompiler . " pid(s): " . join(b:atp_LatexPIDs, ", ") else let b:atp_LastLatexPID = 0 echomsg "[ATP:] ".b:atp_TexCompiler . " is not running" endif endif endfunction "}}} " This function compares two files: file written on the disk a:file and the current " buffer "{{{ atplib#compiler#compare " relevant variables: " g:atp_compare_embedded_comments " g:atp_compare_double_empty_lines " Problems: " This function is too slow it takes 0.35 sec on file with 2500 lines. " Ideas: " Maybe just compare current line! " (search for the current line in the written " file with vimgrep) function! atplib#compiler#compare(file) let l:buffer=getbufline(bufname("%"),"1","$") " rewrite l:buffer to remove all comments let l:buffer=filter(l:buffer, 'v:val !~ "^\s*%"') let l:i = 0 if g:atp_compare_double_empty_lines == 0 || g:atp_compare_embedded_comments == 0 while l:i < len(l:buffer)-1 let l:rem=0 " remove comment lines at the end of a line if g:atp_compare_embedded_comments == 0 let l:buffer[l:i] = substitute(l:buffer[l:i],'%.*$','','') endif " remove double empty lines (i.e. from two conecutive empty lines " the first one is deleted, the second remains), if the line was " removed we do not need to add 1 to l:i (this is the role of " l:rem). if g:atp_compare_double_empty_lines == 0 && l:i< len(l:buffer)-2 if l:buffer[l:i] =~ '^\s*$' && l:buffer[l:i+1] =~ '^\s*$' call remove(l:buffer,l:i) let l:rem=1 endif endif if l:rem == 0 let l:i+=1 endif endwhile endif " do the same with a:file let l:file=filter(a:file, 'v:val !~ "^\s*%"') let l:i = 0 if g:atp_compare_double_empty_lines == 0 || g:atp_compare_embedded_comments == 0 while l:i < len(l:file)-1 let l:rem=0 " remove comment lines at the end of a line if g:atp_compare_embedded_comments == 0 let l:file[l:i] = substitute(a:file[l:i],'%.*$','','') endif " remove double empty lines (i.e. from two conecutive empty lines " the first one is deleted, the second remains), if the line was " removed we do not need to add 1 to l:i (this is the role of " l:rem). if g:atp_compare_double_empty_lines == 0 && l:i < len(l:file)-2 if l:file[l:i] =~ '^\s*$' && l:file[l:i+1] =~ '^\s*$' call remove(l:file,l:i) let l:rem=1 endif endif if l:rem == 0 let l:i+=1 endif endwhile endif " This is the way to make it not sensitive on new line signs. " let file_j = join(l:file) " let buffer_j = join(l:buffer) " return file_j !=# buffer_j return l:file !=# l:buffer endfunction " function! atplib#compiler#sompare(file) " return Compare(a:file) " endfunction " This is very fast (0.002 sec on file with 2500 lines) " but the proble is that vimgrep greps the buffer rather than the file! " so it will not indicate any differences. function! atplib#compiler#NewCompare() let line = getline(".") let lineNr = line(".") let saved_loclist = getloclist(0) try exe "lvimgrep /^". escape(line, '\^$') . "$/j " . fnameescape(expand("%:p")) catch /E480:/ endtry " call setloclist(0, saved_loclist) let loclist = getloclist(0) call map(loclist, "v:val['lnum']") return !(index(loclist, lineNr)+1) endfunction "}}} " This function copies the file a:input to a:output "{{{ atplib#compiler#copy function! atplib#compiler#copy(input,output) call writefile(readfile(a:input),a:output) endfunction "}}} "{{{ atplib#compiler#GetSid function! atplib#compiler#GetSid() return matchstr(expand(''), '\zs\d\+_\ze.*$') endfunction let atplib#compiler#compiler_SID = atplib#compiler#GetSid() "}}} "{{{ atplib#compiler#SidWrap function! atplib#compiler#SidWrap(func) return atplib#compiler#compiler_SID . a:func endfunction "}}} " {{{ atplib#compiler#SetBiberSettings function! atplib#compiler#SetBiberSettings() if b:atp_BibCompiler !~# '^\s*biber\>' return elseif !exists("atplib#compiler#biber_keep_done") let atplib#compiler#biber_keep_done = 1 if index(g:atp_keep, "run.xml") == -1 let g:atp_keep += [ "run.xml" ] endif if index(g:atp_keep, "bcf") == -1 let g:atp_keep += [ "bcf" ] endif endif endfunction "}}} " {{{ atplib#compiler#IsRunning " This function checks if program a:program is running a file a:file. " a:file should be full path to the file. function! atplib#compiler#IsRunning(program, file, ...) " Since there is an issue in psutil on OS X, we cannot run this function: " http://code.google.com/p/psutil/issues/detail?id=173 " Reported by F.Heiderich. if has("mac") || has("gui_mac") let atplib#compiler#running=1 return atplib#compiler#running endif let s:return_is_running=0 python << EOF import vim, psutil, os, pwd from psutil import NoSuchProcess x=0 program =vim.eval("a:program") f =vim.eval("a:file") pat ="|".join(vim.eval("a:000")) for pid in psutil.get_pid_list(): try: p=psutil.Process(pid) if p.username == pwd.getpwuid(os.getuid())[0] and re.search(program, p.cmdline[0]): for arg in p.cmdline: if arg == f or re.search(pat, arg): x=1 break if x: break except psutil.error.NoSuchProcess: pass except psutil.error.AccessDenied: pass except IndexError: pass vim.command("let s:return_is_running=%d" % x) EOF let l:return=s:return_is_running unlet s:return_is_running return l:return endfunction " }}} "{{{ atplib#compiler#Kill " This function kills all running latex processes. " a slightly better approach would be to kill compile.py scripts " the argument is a list of pids " a:1 if present supresses a message. function! atplib#compiler#Kill(bang) if !has("python") if a:bang != "!" echohl WarningMsg echomsg "[ATP:] you need python support." echohl None endif return endif if len(b:atp_LatexPIDs) call atplib#KillPIDs(b:atp_LatexPIDs) endif if len(b:atp_PythonPIDs) call atplib#KillPIDs(b:atp_PythonPIDs) endif if has_key(g:atp_ProgressBarValues, bufnr("%")) let g:atp_ProgressBarValues[bufnr("%")]={} endif let b:atp_running = 0 endfunction "}}} " THE MAIN COMPILER FUNCTIONs: " This function is called to run TeX compiler and friends as many times as necessary. " Makes references and bibliographies (supports bibtex), indexes. "{{{ atplib#compiler#MakeLatex " Function Arguments: function! atplib#compiler#MakeLatex(bang, mode, start) if fnamemodify(&l:errorfile, ":p") != atplib#joinpath(expand(b:atp_OutDir),fnamemodify(b:atp_MainFile, ":t:r").".".(g:atp_ParseLog ? "_" : "")."log") exe "setl errorfile=".atplib#joinpath(expand(b:atp_OutDir),fnamemodify(b:atp_MainFile, ":t:r").".".(g:atp_ParseLog ? "_" : "")."log") endif if a:mode =~# '^s\%[ilent]$' let mode = 'silent' elseif a:mode =~# '^d\%[ebug]$' let mode = 'debug' elseif a:mode =~# 'D\%[ebug]$' let mode = 'Debug' elseif a:mode =~# '^v\%[erbose]$' let mode = 'debug' else let mode = t:atp_DebugMode endif " and a:bang are not yet used by makelatex.py let PythonMakeLatexPath = split(globpath(&rtp, "ftplugin/ATP_files/makelatex.py"), "\n")[0] let interaction = ( mode=="verbose" ? b:atp_VerboseLatexInteractionMode : 'nonstopmode' ) let tex_options = shellescape(b:atp_TexOptions.',-interaction='.interaction) let ext = get(g:atp_CompilersDict, matchstr(b:atp_TexCompiler, '^\s*\zs\S\+\ze'), ".pdf") let ext = substitute(ext, '\.', '', '') let global_options = join((exists("g:atp_".matchstr(b:atp_Viewer, '^\s*\zs\S\+\ze')."Options") ? g:atp_{matchstr(b:atp_Viewer, '^\s*\zs\S\+\ze')}Options : []), ";") let local_options = join((exists("b:atp_".matchstr(b:atp_Viewer, '^\s*\zs\S\+\ze')."Options") ? getbufvar(bufnr("%"), "atp_".matchstr(b:atp_Viewer, '^\s*\zs\S\+\ze')."Options") : []), ";") if global_options != "" let viewer_options = global_options.";".local_options else let viewer_options = local_options endif let reload_viewer = ( index(g:atp_ReloadViewers, b:atp_Viewer)+1 ? ' --reload-viewer ' : '' ) let reload_on_error = ( b:atp_ReloadOnError ? ' --reload-on-error ' : '' ) let bibliographies = join(keys(filter(copy(b:TypeDict), "v:val == 'bib'")), ',') let cmd=g:atp_Python." ".PythonMakeLatexPath. \ " --texfile ".shellescape(atplib#FullPath(b:atp_MainFile)). \ " --bufnr ".bufnr("%"). \ " --start ".a:start. \ " --output-format ".ext. \ " --verbose ".mode. \ " --cmd ".b:atp_TexCompiler. \ " --bibcmd ".b:atp_BibCompiler. \ " --bibliographies ".shellescape(bibliographies). \ " --outdir ".shellescape(expand(b:atp_OutDir)). \ " --keep ". shellescape(join(g:atp_keep, ',')). \ " --tex-options ".tex_options. \ " --servername ".v:servername. \ " --viewer ".shellescape(b:atp_Viewer). \ " --xpdf-server ".shellescape(b:atp_XpdfServer). \ " --viewer-options ".shellescape(viewer_options). \ " --progname ".v:progname. \ " --logdir ".shellescape(g:atp_TempDir). \ " --tempdir ".shellescape(b:atp_TempDir). \ (g:atp_callback ? "" : " --no-callback "). \ (t:atp_DebugMode=='verbose'||mode=='verbose'?' --env ""': " --env ".shellescape(b:atp_TexCompilerVariable)). \ reload_viewer . reload_on_error unlockvar g:atp_TexCommand let g:atp_TexCommand=cmd lockvar g:atp_TexCommand " Write file if a:bang == "!" call atplib#WriteProject('update') else call atplib#write("COM", "silent") endif if mode == "verbose" exe ":!".cmd elseif has("win16") || has("win32") || has("win64") let output=system(cmd) else let output=system(cmd." &") endif endfunction "}}} " {{{ atplib#compiler#PythonCompiler function! atplib#compiler#PythonCompiler(bibtex, start, runs, verbose, command, filename, bang, ...) " a:1 = b:atp_XpdfServer (default value) if fnamemodify(&l:errorfile, ":p") != atplib#joinpath(expand(b:atp_OutDir),fnamemodify(a:filename, ":t:r").".".(g:atp_ParseLog ? "_" : "")."log") exe "setl errorfile=".fnameescape(atplib#joinpath(expand(b:atp_OutDir),fnamemodify(a:filename, ":t:r").".".(g:atp_ParseLog ? "_" : "")."log")) endif " Kill comiple.py scripts if there are too many of them. if len(b:atp_PythonPIDs) >= b:atp_MaxProcesses && b:atp_MaxProcesses let a=copy(b:atp_LatexPIDs) try if b:atp_KillYoungest " Remove the newest PIDs (the last in the b:atp_PythonPIDs) let pids=remove(b:atp_LatexPIDs, b:atp_MaxProcesses, -1) else " Remove the oldest PIDs (the first in the b:atp_PythonPIDs) /works nicely/ let pids=remove(b:atp_LatexPIDs, 0, max([len(b:atp_PythonPIDs)-b:atp_MaxProcesses-1,0])) endif call atplib#KillPIDs(pids) catch E684: endtry endif " Set biber setting on the fly call atplib#compiler#SetBiberSettings() if !has('gui') && a:verbose == 'verbose' && len(b:atp_LatexPIDs) > 0 redraw! echomsg "[ATP:] please wait until compilation stops." return " This is not working: (I should kill compile.py scripts) echomsg "[ATP:] killing all instances of ".get(g:CompilerMsg_Dict,b:atp_TexCompiler,'TeX') call atplib#KillPIDs(b:atp_LatexPIDs,1) sleep 1 PID endif " Debug varibles " On Unix the output of compile.py run by this function is available at " g:atp_TempDir/compiler.py.log if g:atp_debugPythonCompiler call atplib#Log("PythonCompiler.log", "", "init") call atplib#Log("PythonCompiler.log", "a:bibtex=".a:bibtex) call atplib#Log("PythonCompiler.log", "a:start=".a:start) call atplib#Log("PythonCompiler.log", "a:runs=".a:runs) call atplib#Log("PythonCompiler.log", "a:verbose=".a:verbose) call atplib#Log("PythonCompiler.log", "a:command=".a:command) call atplib#Log("PythonCompiler.log", "a:filename=".a:filename) call atplib#Log("PythonCompiler.log", "a:bang=".a:bang) endif if !exists("t:atp_DebugMode") let t:atp_DebugMode = g:atp_DefaultDebugMode endif if t:atp_DebugMode !~ 'verbose$' && a:verbose !~ 'verbose$' let b:atp_LastLatexPID = -1 endif if t:atp_DebugMode !~ "silent$" && b:atp_TexCompiler !~ "luatex" && \ (b:atp_TexCompiler =~ "^\s*\%(pdf\|xetex\)" && b:atp_Viewer == "xdvi" ? 1 : \ b:atp_TexCompiler !~ "^\s*pdf" && b:atp_TexCompiler !~ "xetex" && (b:atp_Viewer == "xpdf" || b:atp_Viewer == "epdfview" || b:atp_Viewer == "acroread" || b:atp_Viewer == "kpdf")) echohl WaningMsg | echomsg "[ATP:] your ".b:atp_TexCompiler." and ".b:atp_Viewer." are not compatible:" echomsg " b:atp_TexCompiler=" . b:atp_TexCompiler echomsg " b:atp_Viewer=" . b:atp_Viewer echohl None endif if !has('clientserver') if has("win16") || has("win32") || has("win64") || has("win95") echohl WarningMsg echomsg "[ATP:] ATP needs +clientserver vim compilation option." echohl None else echohl WarningMsg echomsg "[ATP:] python compiler needs +clientserver vim compilation option." echomsg " falling back to g:atp_Compiler=\"bash\"" echohl None let g:atp_Compiler = "bash" return endif endif " Set options for compile.py let interaction = ( a:verbose=="verbose" ? b:atp_VerboseLatexInteractionMode : 'nonstopmode' ) let tex_options = b:atp_TexOptions.',-interaction='.interaction let ext = get(g:atp_CompilersDict, matchstr(b:atp_TexCompiler, '^\s*\zs\S\+\ze'), ".pdf") let ext = substitute(ext, '\.', '', '') let viewer = matchstr(b:atp_Viewer, '^\s*\zs\S\+\ze') let global_options = join((exists("g:atp_".viewer."Options") ? {"g:atp_".viewer."Options"} : []), ";") let local_options = join((exists("b:atp_".viewer."Options") ? {"b:atp_".viewer."Options"} : []), ";") if global_options != "" let viewer_options = global_options.";".local_options else let viewer_options = local_options endif " let bang = ( a:bang == '!' ? ' --bang ' : '' ) " this is the old bang (used furthere in the code: when " equal to '!' the function wasn't not makeing a copy of aux file let bang = "" let bibtex = ( a:bibtex ? ' --bibtex ' : '' ) let reload_on_error = ( b:atp_ReloadOnError ? ' --reload-on-error ' : '' ) let gui_running = ( has("gui_running") ? ' --gui-running ' : '' ) let reload_viewer = ( index(g:atp_ReloadViewers, b:atp_Viewer)+1 ? ' --reload-viewer ' : '' ) let aucommand = ( a:command == "AU" ? ' --aucommand ' : '' ) let no_progress_bar = ( g:atp_ProgressBar ? '' : ' --no-progress-bar ' ) let bibliographies = join(keys(filter(copy(b:TypeDict), "v:val == 'bib'")), ',') let autex_wait = ( b:atp_autex_wait ? ' --autex_wait ' : '') let xpdf_server = ( a:0 >= 1 ? a:1 : b:atp_XpdfServer ) " Set the command let cmd=g:atp_Python." ".g:atp_PythonCompilerPath." --command ".b:atp_TexCompiler \ ." --tex-options ".shellescape(tex_options) \ ." --tempdir ".shellescape(b:atp_TempDir) \ ." --output-dir ".shellescape(expand(b:atp_OutDir)) \ ." --verbose ".a:verbose \ ." --file ".shellescape(atplib#FullPath(a:filename)) \ ." --bufnr ".bufnr("%") \ ." --output-format ".ext \ ." --runs ".a:runs \ ." --servername ".v:servername \ ." --start ".a:start \ ." --viewer ".shellescape(b:atp_Viewer) \ ." --xpdf-server ".shellescape(xpdf_server) \ ." --viewer-options ".shellescape(viewer_options) \ ." --keep ". shellescape(join(g:atp_keep, ',')) \ ." --progname ".v:progname \ ." --bibcommand ".b:atp_BibCompiler \ ." --bibliographies ".shellescape(bibliographies) \ ." --logdir ".shellescape(g:atp_TempDir) \ .(g:atp_callback ? "" : " --no-callback ") \ ." --progressbar_file " . shellescape(g:atp_ProgressBarFile) \ .(t:atp_DebugMode=~'verbose$'||a:verbose=~'verbose$'?' --env ""': " --env ".shellescape(b:atp_TexCompilerVariable)) \ . bang . bibtex . reload_viewer . reload_on_error . gui_running . aucommand . no_progress_bar \ . autex_wait " Write file if g:atp_debugPythonCompiler call atplib#Log("PythonCompiler.log", "PRE WRITING b:atp_changedtick=".b:atp_changedtick." b:changedtick=".b:changedtick) endif if a:bang == "!" call atplib#WriteProject('write') else call atplib#write(a:command, "silent") endif if g:atp_debugPythonCompiler call atplib#Log("PythonCompiler.log", "POST WRITING b:atp_changedtick=".b:atp_changedtick." b:changedtick=".b:changedtick) endif unlockvar g:atp_TexCommand let g:atp_TexCommand = cmd lockvar g:atp_TexCommand " Call compile.py let b:atp_running += ( a:verbose != "verbose" ? 1 : 0 ) if a:verbose == "verbose" exe ":!".cmd elseif g:atp_debugPythonCompiler && has("unix") call system(cmd." 2".g:atp_TempDir."/PythonCompiler.log &") elseif has("win16") || has("win32") || has("win64") call system(cmd) else call system(cmd." &") endif if g:atp_debugPythonCompiler call atplib#Log("PythonCompiler.log", "END b:atp_changedtick=".b:atp_changedtick." b:changedtick=".b:changedtick) endif endfunction " }}} " {{{ atplib#compiler#LocalCompiler function! atplib#compiler#LocalCompiler(mode, runs, ...) let debug_mode = ( a:0 && a:1 != "" ? a:1 : 'silent' ) let subfiles = atplib#search#SearchPackage('subfiles') let file = expand("%:p") let tmpdir = b:atp_TempDir . matchstr(tempname(), '\/\w\+\/\d\+') let extensions = [ 'aux', 'bbl' ] let main_file = atplib#FullPath(b:atp_MainFile) if a:mode == "n" && subfiles " if subfiles package is used. " compilation is done in the current directory. python << ENDPYTHON import vim, os, os.path, shutil, re file = vim.eval("file") basename = os.path.splitext(file)[0] mainfile_base = os.path.splitext(vim.eval("main_file"))[0] # read the local aux file (if present) find all new \newlabel{} commands # if they are present in the original aux file substitute them (this part is # not working) if not add them at the end. Note that after running pdflatex # the local aux file becomes agian short. if os.path.exists(basename+".aux"): local_aux_file = open(basename+".aux", "r") local_aux = local_aux_file.readlines() local_aux_file.close() if os.path.exists(mainfile_base+".aux"): main_aux_file = open(mainfile_base+".aux", "r") main_aux = main_aux_file.readlines() main_aux_file.close() else: main_aux = [] # There is no sens of comparing main_aux and local_aux! pattern = re.compile('^\\\\newlabel.*$', re.M) local_labels = re.findall(pattern, "".join(local_aux)) def get_labels(line): return re.match('\\\\newlabel\s*{([^}]*)}', line).group(1) local_labels_names = map(get_labels, local_labels) local_labels_dict = dict(zip(local_labels_names, local_labels)) values = {} for label in local_labels_names: match = re.search('^\\\\newlabel\s*{'+re.escape(label)+'}.*', "\n".join(main_aux), re.M) if not match: main_aux.append(local_labels_dict[label]+"\n") main_aux_file = open(mainfile_base+".aux", "w") main_aux_file.write("".join(main_aux)) main_aux_file.close() # copy the main aux file to local directory extensions = vim.eval("extensions") for ext in extensions: if os.path.exists(mainfile_base+"."+ext): try: shutil.copy(mainfile_base+"."+ext, basename+"."+ext) except shutil.Error: pass ENDPYTHON if g:atp_Compiler == 'python' call atplib#compiler#PythonCompiler(0,0,a:runs,debug_mode,'COM',expand("%:p"),"",b:atp_LocalXpdfServer) else call atplib#compiler#Compiler(0,0,a:runs,debug_mode, 'COM', expand(":p"), "", b:atp_LocalXpdfServer) endif endif endfunction " }}} " {{{ atplib#compiler#Compiler " This is the MAIN FUNCTION which sets the command and calls it. " NOTE: the argument is not escaped! " a:verbose = silent/verbose/debug " debug -- switch to show errors after compilation. " verbose -- show compiling procedure. " silent -- compile silently (gives status information if fails) " a:start = 0/1/2 " 1 start viewer " 2 start viewer and make reverse search " function! atplib#compiler#Compiler(bibtex, start, runs, verbose, command, filename, bang, ...) " a:1 = b:atp_XpdfServer (default value) let XpdfServer = ( a:0 >= 1 ? a:1 : b:atp_XpdfServer ) if fnamemodify(&l:errorfile, ":p") != atplib#joinpath(expand(b:atp_OutDir),fnamemodify(a:filename, ":t:r").".".(g:atp_ParseLog ? "_" : "")."log") exe "setl errorfile=".atplib#joinpath(fnameescape(expand(b:atp_OutDir),fnamemodify(a:filenamt, ":t:r").".".(g:atp_ParseLog ? "_" : "")."log")) endif " Set biber setting on the fly call atplib#compiler#SetBiberSettings() if !has('gui') && a:verbose == 'verbose' && b:atp_running > 0 redraw! echomsg "[ATP:] please wait until compilation stops." return endif if g:atp_debugCompiler exe "redir! > ".g:atp_TempDir."/Compiler.log" silent echomsg "________ATP_COMPILER_LOG_________" silent echomsg "changedtick=" . b:changedtick . " atp_changedtick=" . b:atp_changedtick silent echomsg "a:bibtex=" . a:bibtex . " a:start=" . a:start . " a:runs=" . a:runs . " a:verbose=" . a:verbose . " a:command=" . a:command . " a:filename=" . a:filename . " a:bang=" . a:bang silent echomsg "1 b:changedtick=" . b:changedtick . " b:atp_changedtick" . b:atp_changedtick . " b:atp_running=" . b:atp_running endif if has('clientserver') && !empty(v:servername) && g:atp_callback && a:verbose != 'verbose' let b:atp_running+=1 endif " IF b:atp_TexCompiler is not compatible with the viewer " ToDo: (move this in a better place). (luatex can produce both pdf and dvi " files according to options so this is not the right approach.) if !exists("t:atp_DebugMode") let t:atp_DebugMode = g:atp_DefaultDebugMode endif if t:atp_DebugMode !=? "silent" && b:atp_TexCompiler !~? "luatex" && \ (b:atp_TexCompiler =~ "^\s*\%(pdf\|xetex\)" && b:atp_Viewer == "xdvi" ? 1 : \ b:atp_TexCompiler !~ "^\s*pdf" && b:atp_TexCompiler !~ "xetex" && (b:atp_Viewer == "xpdf" || b:atp_Viewer == "epdfview" || b:atp_Viewer == "acroread" || b:atp_Viewer == "kpdf")) echohl WaningMsg | echomsg "[ATP:] your ".b:atp_TexCompiler." and ".b:atp_Viewer." are not compatible:" echomsg " b:atp_TexCompiler=" . b:atp_TexCompiler echomsg " b:atp_Viewer=" . b:atp_Viewer echohl None endif " There is no need to run more than ~5 (s:runlimit=9) consecutive runs " this prevents from running tex as many times as the current line " what can be done by a mistake using the range for the command. if ( a:runs > s:runlimit ) let runs = s:runlimit else let runs = a:runs endif let tmpdir=b:atp_TempDir . matchstr(tempname(), '\/\w\+\/\d\+') let tmpfile=atplib#append(tmpdir, "/") . fnamemodify(a:filename,":t:r") if g:atp_debugCompiler let g:tmpdir=tmpdir let g:tmpfile=tmpfile endif call system("mkdir -m 0700 -p ".shellescape(tmpdir)) " if exists("*mkdir") " call mkdir(tmpdir, "p", 0700) " else " echoerr "[ATP:] Your vim doesn't have mkdir function, please try the python compiler." " return " endif " SET THE NAME OF OUTPUT FILES " first set the extension pdf/dvi let ext = get(g:atp_CompilersDict, matchstr(b:atp_TexCompiler, '^\s*\zs\S\+\ze'), ".pdf") " check if the file is a symbolic link, if it is then use the target " name. let link=system("readlink " . a:filename) if link != "" let basename=fnamemodify(link,":r") else let basename=a:filename endif " finally, set the output file names. let outfile = atplib#joinpath(expand(b:atp_OutDir), fnamemodify(basename,":t:r") . ext) let outaux = atplib#joinpath(expand(b:atp_OutDir), fnamemodify(basename,":t:r") . ".aux") let outbbl = atplib#joinpath(expand(b:atp_OutDir), fnamemodify(basename,":t:r") . ".bbl") let tmpaux = fnamemodify(tmpfile, ":r") . ".aux" let tmpbbl = fnamemodify(tmpfile, ":r") . ".bbl" let tmptex = fnamemodify(tmpfile, ":r") . ".tex" let outlog = atplib#joinpath(expand(b:atp_OutDir), fnamemodify(basename,":t:r") . ".log") let syncgzfile = atplib#joinpath(expand(b:atp_OutDir), fnamemodify(basename,":t:r") . ".synctex.gz") let syncfile = atplib#joinpath(expand(b:atp_OutDir), fnamemodify(basename,":t:r") . ".synctex") " COPY IMPORTANT FILES TO TEMP DIRECTORY WITH CORRECT NAME " except log and aux files. let list = copy(g:atp_keep) call filter(list, 'v:val != "log"') for i in list let ftc = atplib#joinpath(expand(b:atp_OutDir), fnamemodify(basename,":t:r") . "." . i) if filereadable(ftc) call atplib#compiler#copy(ftc,tmpfile . "." . i) endif endfor " HANDLE XPDF RELOAD let reload_viewer = ( index(g:atp_ReloadViewers, b:atp_Viewer) == '-1' ? ' --reload-viewer ' : '' ) if b:atp_Viewer =~ '^\s*xpdf\>' && reload_viewer if a:start "if xpdf is not running and we want to run it. let Reload_Viewer = b:atp_Viewer . " -remote " . shellescape(XpdfServer) . " " . shellescape(outfile) . " ; " else " TIME: this take 1/3 of time! 0.039 call atplib#compiler#xpdfpid() " I could use here atplib#compiler#XpdPid(), the reason to not use it is that " then there is a way to run ATP without python. if atplib#compiler#xpdfpid != "" "if xpdf is running (then we want to reload it). "This is where I use 'ps' command to check if xpdf is "running. let Reload_Viewer = b:atp_Viewer . " -remote " . shellescape(XpdfServer) . " -reload ; " else "if xpdf is not running (but we do not want "to run it). let Reload_Viewer = " " endif endif else if a:start " if b:atp_Viewer is not running and we want to open it. " the name of this variable is not missleading ... let Reload_Viewer = b:atp_Viewer . " " . shellescape(outfile) . " ; " " If run through RevSearch command use source specials rather than " just reload: if str2nr(a:start) == 2 let synctex = atplib#compiler#SidWrap('SyncTex') let callback_rs_cmd = v:progname . " --servername " . v:servername . " --remote-expr " . "'".synctex."()' ; " let Reload_Viewer = callback_rs_cmd endif else " If b:atp_Viewer is not running then we do not want to " open it. let Reload_Viewer = " " endif endif if g:atp_debugCompiler let g:Reload_Viewer = Reload_Viewer endif " IF OPENING NON EXISTING OUTPUT FILE " only xpdf needs to be run before (we are going to reload it) if a:start && b:atp_Viewer == "xpdf" let xpdf_options = ( exists("g:atp_xpdfOptions") ? join(map(copy(g:atp_xpdfOptions), 'shellescape(v:val)'), " ") : "" )." ".(exists("b:xpdfOptions") ? join(map(copy(getbufvar(0, "atp_xpdfOptions")), 'shellescape(v:val)'), " ") : " ") let start = b:atp_Viewer . " -remote " . shellescape(XpdfServer) . " " . xpdf_options . " & " else let start = "" endif " SET THE COMMAND let interaction = ( a:verbose=="verbose" ? b:atp_VerboseLatexInteractionMode : 'nonstopmode' ) let variable = ( a:verbose!="verbose" ? substitute(b:atp_TexCompilerVariable, ';', ' ', 'g') : '' ) let comp = variable . " " . b:atp_TexCompiler . " " . substitute(b:atp_TexOptions, ',', ' ','g') . " -interaction=" . interaction . " -output-directory=" . shellescape(tmpdir) . " " . shellescape(a:filename) let vcomp = variable . " " . b:atp_TexCompiler . " " . substitute(b:atp_TexOptions, ',', ' ','g') . " -interaction=". interaction . " -output-directory=" . shellescape(tmpdir) . " " . shellescape(a:filename) " make function: " let make = "vim --servername " . v:servername . " --remote-expr 'MakeLatex\(\"".tmptex."\",1,0\)'" if a:verbose == 'verbose' let texcomp=vcomp else let texcomp=comp endif if runs >= 2 && a:bibtex != 1 " how many times we want to call b:atp_TexCompiler let i=1 while i < runs - 1 let i+=1 let texcomp=texcomp . " ; " . comp endwhile if a:verbose != 'verbose' let texcomp=texcomp . " ; " . comp else let texcomp=texcomp . " ; " . vcomp endif endif if a:bibtex == 1 " this should be decided using the log file as well. if filereadable(outaux) " call atplib#compiler#copy(outaux,tmpfile . ".aux") let texcomp="bibtex " . shellescape(fnamemodify(outaux, ":t")) . "; ".g:atp_cpcmd." ".shellescape(outbbl)." ".shellescape(tmpbbl).";" . comp . " 1>/dev/null 2>&1 " else let texcomp=comp.";clear;".g:atp_cpcmd." ".shellescape(tmpaux)." ".shellescape(outaux)."; bibtex ".shellescape(fnamemodify(outaux, ":t")).";".g:atp_cpcmd." ".shellescape(outbbl)." ".shellescape(tmpbbl)."; ".comp." 1>/dev/null 2>&1 " endif if a:verbose != 'verbose' let texcomp=texcomp . " ; " . comp else let texcomp=texcomp . " ; " . vcomp endif endif " catch the status if has('clientserver') && v:servername != "" && g:atp_callback == 1 let catchstatus_cmd = v:progname . ' --servername ' . v:servername . ' --remote-expr ' . \ shellescape('atplib#callback#TexReturnCode') . '\($?\) ; ' else let catchstatus_cmd = '' endif " copy output file (.pdf\|.ps\|.dvi) " let cpoptions = "--remove-destination" let cpoptions = "" let cpoutfile = g:atp_cpcmd." ".cpoptions." ".shellescape(atplib#append(tmpdir,"/"))."*".ext." ".shellescape(atplib#append(expand(b:atp_OutDir),"/"))." ; " if a:start let command = "(" . texcomp . " ; (" . catchstatus_cmd . " " . cpoutfile . " " . Reload_Viewer . " ) || ( ". catchstatus_cmd . " " . cpoutfile . ") ; " else " Reload on Error: " for xpdf it copies the out file but does not reload the xpdf " server for other viewers it simply doesn't copy the out file. if b:atp_ReloadOnError || a:bang == "!" if a:bang == "!" let command="( ".texcomp." ; ".catchstatus_cmd." ".g:atp_cpcmd." ".cpoptions." ".shellescape(tmpaux)." ".shellescape(expand(b:atp_OutDir))." ; ".cpoutfile." ".Reload_Viewer else let command="( (".texcomp." && ".g:atp_cpcmd." ".cpoptions." ".shellescape(tmpaux)." ".shellescape(expand(b:atp_OutDir))." ) ; ".catchstatus_cmd." ".cpoutfile." ".Reload_Viewer endif else if b:atp_Viewer =~ '\' let command="( ".texcomp." && (".catchstatus_cmd.cpoutfile." ".Reload_Viewer." ".g:atp_cpcmd." ".cpoptions." ".shellescape(tmpaux)." ".shellescape(expand(b:atp_OutDir))." ) || (".catchstatus_cmd." ".cpoutfile.") ; " else let command="(".texcomp." && (".catchstatus_cmd.cpoutfile." ".Reload_Viewer." ".g:atp_cpcmd." ".cpoptions." ".shellescape(tmpaux)." ".shellescape(expand(b:atp_OutDir))." ) || (".catchstatus_cmd.") ; " endif endif endif if g:atp_debugCompiler silent echomsg "Reload_Viewer=" . Reload_Viewer let g:Reload_Viewer = Reload_Viewer let g:command = command elseif g:atp_debugCompiler >= 2 silent echomsg "command=" . command endif " Preserve files with extension belonging to the g:atp_keep list variable. let copy_cmd="" let j=1 for i in g:atp_keep " ToDo: this can be done using internal vim functions. if i != "aux" let copycmd=g:atp_cpcmd." ".cpoptions." ".shellescape(atplib#append(tmpdir,"/")). \ "*.".i." ".shellescape(atplib#append(expand(b:atp_OutDir),"/")) else let copycmd=g:atp_cpcmd." ".cpoptions." ".shellescape(atplib#append(tmpdir,"/")). \ "*.".i." ".shellescape(atplib#append(expand(b:atp_OutDir),"/".fnamemodify(b:atp_MainFile, ":t:r")."_aux")) endif if j == 1 let copy_cmd=copycmd else let copy_cmd=copy_cmd . " ; " . copycmd endif let j+=1 endfor if g:atp_debugCompiler let g:copy_cmd = copy_cmd endif let command=command . " " . copy_cmd . " ; " " Callback: if has('clientserver') && v:servername != "" && g:atp_callback == 1 " let callback = atplib#compiler#SidWrap('CallBack') let callback_cmd = v:progname . ' --servername ' . v:servername . ' --remote-expr ' . \ shellescape('atplib#callback#CallBack').'\(\"'.bufnr("%").'\",\"'.a:verbose.'\",\"'.a:command.'\",\"'.a:bibtex.'\"\)'. " ; " let command = command . " " . callback_cmd if g:atp_debugCompiler silent echomsg "callback_cmd=" . callback_cmd endif endif let rmtmp="rm -rf " . shellescape(fnamemodify(tmpdir, ":h")) . "; " let command=command . " " . rmtmp . ") &" if str2nr(a:start) != 0 let command=start . command endif " Take care about backup and writebackup options. if g:atp_debugCompiler silent echomsg "BEFORE WRITING: b:changedtick=" . b:changedtick . " b:atp_changedtick=" . b:atp_changedtick . " b:atp_running=" . b:atp_running endif call atplib#write(a:command, "silent") if g:atp_debugCompiler silent echomsg "AFTER WRITING: b:changedtick=" . b:changedtick . " b:atp_changedtick=" . b:atp_changedtick . " b:atp_running=" . b:atp_running endif if a:verbose != 'verbose' " "cd ".shellescape(tmpdir).";". let g:atp_TexOutput=system(command) else let command="!clear;" . texcomp . " " . cpoutfile . " " . copy_cmd exe command endif unlockvar g:atp_TexCommand let g:atp_TexCommand=command lockvar g:atp_TexCommand if g:atp_debugCompiler silent echomsg "command=" . command redir END endif endfunction "}}} "{{{ aptlib#compiler#ThreadedCompiler function! atplib#compiler#ThreadedCompiler(bibtex, start, runs, verbose, command, filename, bang) " Write file: if g:atp_debugPythonCompiler call atplib#Log("ThreadedCompiler.log", "", "init") call atplib#Log("ThreadedCompiler.log", "PRE WRITING b:atp_changedtick=".b:atp_changedtick." b:changedtick=".b:changedtick) endif let bang = "" " this is the old bang (used furthere in the code: when " equal to '!' the function wasn't not makeing a copy of aux file if a:bang == "!" call atplib#WriteProject('update') else call atplib#write(a:command, "silent") endif if g:atp_debugPythonCompiler call atplib#Log("ThreadedCompiler.log", "POST WRITING b:atp_changedtick=".b:atp_changedtick." b:changedtick=".b:changedtick) endif " Kill comiple.py scripts if there are too many of them. if len(b:atp_PythonPIDs) >= b:atp_MaxProcesses && b:atp_MaxProcesses let a=copy(b:atp_LatexPIDs) try if b:atp_KillYoungest " Remove the newest PIDs (the last in the b:atp_PythonPIDs) let pids=remove(b:atp_LatexPIDs, b:atp_MaxProcesses, -1) else " Remove the oldest PIDs (the first in the b:atp_PythonPIDs) /works nicely/ let pids=remove(b:atp_LatexPIDs, 0, max([len(b:atp_PythonPIDs)-b:atp_MaxProcesses-1,0])) endif echomsg string(a)." ".string(pids)." ".string(b:atp_LatexPIDs) call atplib#KillPIDs(pids) catch E684: endtry echomsg string(b:atp_LatexPIDs) endif " Set biber setting on the fly call atplib#compiler#SetBiberSettings() if !has('gui') && a:verbose == 'verbose' && len(b:atp_LatexPIDs) > 0 redraw! echomsg "[ATP:] please wait until compilation stops." return " This is not working: (I should kill compile.py scripts) echomsg "[ATP:] killing all instances of ".get(g:CompilerMsg_Dict,b:atp_TexCompiler,'TeX') call atplib#KillPIDs(b:atp_LatexPIDs,1) sleep 1 PID endif " Debug varibles " On Unix the output of compile.py run by this function is available at " g:atp_TempDir/compiler.py.log if g:atp_debugPythonCompiler call atplib#Log("ThreadedCompiler.log", "", "init") call atplib#Log("ThreadedCompiler.log", "a:bibtex=".a:bibtex) call atplib#Log("ThreadedCompiler.log", "a:start=".a:start) call atplib#Log("ThreadedCompiler.log", "a:runs=".a:runs) call atplib#Log("ThreadedCompiler.log", "a:verbose=".a:verbose) call atplib#Log("ThreadedCompiler.log", "a:command=".a:command) call atplib#Log("ThreadedCompiler.log", "a:filename=".a:filename) call atplib#Log("ThreadedCompiler.log", "a:bang=".a:bang) endif if !exists("t:atp_DebugMode") let t:atp_DebugMode = g:atp_DefaultDebugMode endif if t:atp_DebugMode != 'verbose' && a:verbose != 'verbose' let b:atp_LastLatexPID = -1 endif if t:atp_DebugMode != "silent" && b:atp_TexCompiler !~ "luatex" && \ (b:atp_TexCompiler =~ "^\s*\%(pdf\|xetex\)" && b:atp_Viewer == "xdvi" ? 1 : \ b:atp_TexCompiler !~ "^\s*pdf" && b:atp_TexCompiler !~ "xetex" && (b:atp_Viewer == "xpdf" || b:atp_Viewer == "epdfview" || b:atp_Viewer == "acroread" || b:atp_Viewer == "kpdf")) echohl WaningMsg | echomsg "[ATP:] your ".b:atp_TexCompiler." and ".b:atp_Viewer." are not compatible:" echomsg " b:atp_TexCompiler=" . b:atp_TexCompiler echomsg " b:atp_Viewer=" . b:atp_Viewer echohl None endif if !has('clientserver') if has("win16") || has("win32") || has("win64") || has("win95") echohl WarningMsg echomsg "[ATP:] ATP needs +clientserver vim compilation option." echohl None else echohl WarningMsg echomsg "[ATP:] python compiler needs +clientserver vim compilation option." echomsg " falling back to g:atp_Compiler=\"bash\"" echohl None let g:atp_Compiler = "bash" return endif endif " Set options for compile.py let interaction = ( a:verbose=="verbose" ? b:atp_VerboseLatexInteractionMode : 'nonstopmode' ) let tex_options = b:atp_TexOptions.',-interaction='.interaction " let g:tex_options=tex_options let ext = get(g:atp_CompilersDict, matchstr(b:atp_TexCompiler, '^\s*\zs\S\+\ze'), ".pdf") let ext = substitute(ext, '\.', '', '') let global_options = join((exists("g:atp_".matchstr(b:atp_Viewer, '^\s*\zs\S\+\ze')."Options") ? g:atp_{matchstr(b:atp_Viewer, '^\s*\zs\S\+\ze')}Options : []), ";") let local_options = join(( exists("atp_".matchstr(b:atp_Viewer, '^\s*\zs\S\+\ze')."Options") ? getbufvar(bufnr("%"), "atp_".matchstr(b:atp_Viewer, '^\s*\zs\S\+\ze')."Options") : []), ";") if global_options != "" let viewer_options = global_options.";".local_options else let viewer_options = local_options endif let file = atplib#FullPath(a:filename) let bang = ( a:bang == '!' ? ' --bang ' : '' ) let bibtex = ( a:bibtex ? ' --bibtex ' : '' ) let reload_on_error = ( b:atp_ReloadOnError ? ' --reload-on-error ' : '' ) let gui_running = ( has("gui_running") ? ' --gui-running ' : '' ) let reload_viewer = ( index(g:atp_ReloadViewers, b:atp_Viewer)+1 ? ' --reload-viewer ' : '' ) let aucommand = ( a:command == "AU" ? ' --aucommand ' : '' ) let no_progress_bar = ( g:atp_ProgressBar ? '' : ' --no-progress-bar ' ) let bibliographies = join(keys(filter(copy(b:TypeDict), "v:val == 'bib'")), ',') let autex_wait = ( b:atp_autex_wait ? ' --autex_wait ' : '') let keep = join(g:atp_keep, ',') python << ENDPYTHON import vim, threading import sys, errno, os.path, shutil, subprocess, psutil, re, tempfile, optparse, glob import traceback, atexit from os import chdir, mkdir, putenv, devnull from collections import deque #################################### # # Functions: # #################################### def nonempty(string): if str(string) == '': return False else: return True def decode_list(byte): return byte.decode() def latex_progress_bar(cmd): # Run latex and send data for progress bar, child = subprocess.Popen(cmd, stdout=subprocess.PIPE) # If I remove the code below and only put child.wait() # then vim crashes. pid = child.pid vim.eval("atplib#callback#LatexPID("+str(pid)+")") debug_file.write("latex pid "+str(pid)+"\n") stack = deque([]) while True: try: out = child.stdout.read(1).decode() except UnicodeDecodeError: debug_file.write("UNICODE DECODE ERROR:\n") debug_file.write(child.stdout.read(1)) debug_file.write("\n") debug_file.write("stack="+''.join(stack)+"\n") out = "" if out == '' and child.poll() != None: break if out != '': stack.append(out) if len(stack)>10: stack.popleft() match = re.match('\[(\n?\d(\n|\d)*)({|\])',str(''.join(stack))) if match: vim.eval("atplib#callback#ProgressBar("+match.group(1)[match.start():match.end()]+","+str(pid)+")") child.wait() vim.eval("atplib#callback#ProgressBar('end',"+str(pid)+")") vim.eval("atplib#callback#PIDsRunning(\"b:atp_LatexPIDs\")") return child def xpdf_server_file_dict(): # Make dictionary of the type { xpdf_servername : [ file, xpdf_pid ] }, # to test if the server host file use: # basename(xpdf_server_file_dict().get(server, ['_no_file_'])[0]) == basename(file) # this dictionary always contains the full path (Linux). # TODO: this is not working as I want to: # when the xpdf was opened first without a file it is not visible in the command line # I can use 'xpdf -remote -exec "run('echo %f')"' # where get_filename is a simple program which returns the filename. # Then if the file matches I can just reload, if not I can use: # xpdf -remote -exec "openFile(file)" ps_list=psutil.get_pid_list() server_file_dict={} for pr in ps_list: try: name=psutil.Process(pr).name cmdline=psutil.Process(pr).cmdline if name == 'xpdf': try: ind=cmdline.index('-remote') except: ind=0 if ind != 0 and len(cmdline) >= 1: server_file_dict[cmdline[ind+1]]=[cmdline[len(cmdline)-1], pr] except psutil.error.NoSuchProcess: pass except psutil.error.AccessDenied: pass return server_file_dict #################################### # # Options: # #################################### tex_file = vim.eval("b:atp_MainFile") command = vim.eval("b:atp_TexCompiler") bibcommand = vim.eval("b:atp_BibCompiler") progname = vim.eval("v:progname") if vim.eval("aucommand") == ' --aucommand ': aucommand_bool = True aucommand="AU" else: aucommand_bool = False aucommand="COM" command_opt = list(filter(nonempty,re.split('\s*,\s*', vim.eval("tex_options")))) mainfile_fp = vim.eval("file") output_format = vim.eval("ext") if output_format == "pdf": extension = ".pdf" else: extension = ".dvi" runs = int(vim.eval("a:runs")) servername = vim.eval("v:servername") start = str(vim.eval("a:start")) viewer = vim.eval("b:atp_Viewer") if vim.eval("autex_wait") == "--autex_wait": autex_wait = True else: autex_wait = False XpdfServer = vim.eval("b:atp_XpdfServer") viewer_rawopt = re.split('\s*;\s*', vim.eval("viewer_options")) viewer_it = list(filter(nonempty, viewer_rawopt)) viewer_opt =[] for opt in viewer_it: viewer_opt.append(opt) viewer_rawopt = viewer_opt if viewer == "xpdf" and XpdfServer != None: viewer_opt.extend(["-remote", XpdfServer]) verbose = vim.eval("a:verbose") keep = vim.eval("keep").split(',') keep = list(filter(nonempty, keep)) def keep_filter_aux(string): if string == 'aux': return False else: return True def keep_filter_log(string): if string == 'log': return False else: return True def mysplit(string): return re.split('\s*=\s*', string) env = list(map(mysplit, list(filter(nonempty, re.split('\s*;\s*',vim.eval("b:atp_TexCompilerVariable")))))) # Boolean options if vim.eval("reload_viewer") == ' --reload-viewer ': reload_viewer = True else: reload_viewer = False if vim.eval("bibtex") == ' --bibtex ': bibtex = True else: bibtex = False bibliographies = vim.eval("bibliographies").split(",") bibliographies = list(filter(nonempty, bibliographies)) if vim.eval("a:bang") == "!": bang = True else: bang = False if vim.eval("reload_on_error") == ' --reload-on-error ': reload_on_error = True else: reload_on_error = False if vim.eval("gui_running") == ' --gui-running ': gui_running = True else: gui_running = False if vim.eval("no_progress_bar") == ' --no-progress-bar ': progress_bar = False else: progress_bar = True # Debug file should be changed for sth platform independent # There should be a switch to get debug info. logdir = vim.eval("g:atp_TempDir") script_logfile = os.path.join(logdir, 'compile.log') debug_file = open(script_logfile, 'w') debug_file.write("COMMAND "+command+"\n") debug_file.write("BIBCOMMAND "+bibcommand+"\n") debug_file.write("BIBCOMMAND "+bibcommand+"\n") debug_file.write("AUCOMMAND "+aucommand+"\n") debug_file.write("PROGNAME "+progname+"\n") debug_file.write("COMMAND_OPT "+str(command_opt)+"\n") debug_file.write("MAINFILE_FP "+str(mainfile_fp)+"\n") debug_file.write("OUTPUT FORMAT "+str(output_format)+"\n") debug_file.write("EXT "+extension+"\n") debug_file.write("RUNS "+str(runs)+"\n") debug_file.write("VIM_SERVERNAME "+str(servername)+"\n") debug_file.write("START "+str(start)+"\n") debug_file.write("VIEWER "+str(viewer)+"\n") debug_file.write("XPDF_SERVER "+str(XpdfServer)+"\n") debug_file.write("VIEWER_OPT "+str(viewer_opt)+"\n") debug_file.write("DEBUG MODE (verbose) "+str(verbose)+"\n") debug_file.write("KEEP "+str(keep)+"\n") debug_file.write("BIBLIOGRAPHIES "+str(bibliographies)+"\n") # debug_file.write("ENV OPTION "+str(options.env)+"\n") debug_file.write("ENV "+str(env)+"\n") debug_file.write("*BIBTEX "+str(bibtex)+"\n") debug_file.write("*BANG "+str(bang)+"\n") debug_file.write("*RELOAD_VIEWER "+str(reload_viewer)+"\n") debug_file.write("*RELOAD_ON_ERROR "+str(reload_on_error)+"\n") debug_file.write("*GUI_RUNNING "+str(gui_running)+"\n") debug_file.write("*PROGRESS_BAR "+str(progress_bar)+"\n") class LatexThread( threading.Thread ): def run( self ): # Author: Marcin Szamotulski # This file is a part of Automatic TeX Plugin for Vim. # readlink is not available on Windows. readlink=True try: from os import readlink except ImportError: readlink=False # Cleanup on exit: def cleanup(debug_file): debug_file.close() shutil.rmtree(tmpdir) # atexit.register(cleanup, debug_file) #################################### # # Arguments: # #################################### global tex_file, command, bibcommand, progname, aucommand_bool, aucommand global command_opt, mainfile_fp, output_format, extension, runs, servername, start global viewer, autex_wait, XpdfServer, viewer_rawopt, viewer_it, viewer_opt global viewer_rawopt, verbose, keep, env global reload_viewer, bibtex, bibliographies, bang, reload_on_error, gui_running, progress_bar # If mainfile_fp is not a full path make it. # glob=glob.glob(os.path.join(os.getcwd(),mainfile_fp)) # if len(glob) != 0: # mainfile_fp = glob[0] mainfile = os.path.basename(mainfile_fp) mainfile_dir = os.path.dirname(mainfile_fp) if mainfile_dir == "": mainfile_fp = os.path.join(os.getcwd(), mainfile) mainfile = os.path.basename(mainfile_fp) mainfile_dir= os.path.dirname(mainfile_fp) if os.path.islink(mainfile_fp): if readlink: mainfile_fp = os.readlink(mainfile_fp) # The above line works if the symlink was created with full path. mainfile = os.path.basename(mainfile_fp) mainfile_dir= os.path.dirname(mainfile_fp) mainfile_dir = os.path.normcase(mainfile_dir) [basename, ext] = os.path.splitext(mainfile) output_fp = os.path.splitext(mainfile_fp)[0]+extension try: # Send pid to ATP: if verbose != "verbose": vim.eval("atplib#callback#PythonPID("+str(os.getpid())+")") #################################### # # Make temporary directory, # Copy files and Set Environment: # #################################### cwd = os.getcwd() if not os.path.exists(os.path.join(mainfile_dir,".tmp")): # This is the main tmp dir (./.tmp) # it will not be deleted by this script # as another instance might be using it. # it is removed by Vim on exit. os.mkdir(os.path.join(mainfile_dir,".tmp")) tmpdir = tempfile.mkdtemp(dir=os.path.join(mainfile_dir,".tmp"),prefix="") debug_file.write("TMPDIR: "+tmpdir+"\n") tmpaux = os.path.join(tmpdir,basename+".aux") command_opt.append('-output-directory='+tmpdir) latex_cmd = [command]+command_opt+[mainfile_fp] debug_file.write("COMMAND "+str(latex_cmd)+"\n") debug_file.write("COMMAND "+" ".join(latex_cmd)+"\n") # Copy important files to output directory: # /except the log file/ os.chdir(mainfile_dir) for ext in filter(keep_filter_log,keep): file_cp=basename+"."+ext if os.path.exists(file_cp): shutil.copy(file_cp, tmpdir) tempdir_list = os.listdir(tmpdir) debug_file.write("\nls tmpdir "+str(tempdir_list)+"\n") # Set environment for var in env: debug_file.write("ENV "+var[0]+"="+var[1]+"\n") os.putenv(var[0], var[1]) # Link local bibliographies: for bib in bibliographies: if os.path.exists(os.path.join(mainfile_dir,os.path.basename(bib))): os.symlink(os.path.join(mainfile_dir,os.path.basename(bib)),os.path.join(tmpdir,os.path.basename(bib))) #################################### # # Compile: # #################################### # Start Xpdf (this can be done before compelation, because we can load file # into afterwards) in this way Xpdf starts faster (it is already running when # file compiles). # TODO: this might cause problems when the tex file is very simple and short. # Can we test if xpdf started properly? okular doesn't behave nicely even with # --unique switch. # Latex might not run this might happedn with bibtex (?) latex_returncode=0 if bibtex and os.path.exists(tmpaux): if bibcommand == 'biber': bibfname = basename else: bibfname = basename+".aux" debug_file.write("\nBIBTEX1"+str([bibcommand, bibfname])+"\n") os.chdir(tmpdir) bibtex_popen=subprocess.Popen([bibcommand, bibfname], stdout=subprocess.PIPE) vim.eval("atplib#callback#BibtexPID('"+str(bibtex_popen.pid)+"')") vim.eval("atplib#callback#redrawstatus()") bibtex_popen.wait() vim.eval("atplib#callback#PIDsRunning(\"b:atp_BibtexPIDs\")") os.chdir(mainfile_dir) bibtex_returncode=bibtex_popen.returncode bibtex_output=re.sub('"', '\\"', bibtex_popen.stdout.read()) debug_file.write("BIBTEX RET CODE "+str(bibtex_returncode)+"\nBIBTEX OUTPUT\n"+bibtex_output+"\n") if verbose != 'verbose': vim.eval("atplib#callback#BibtexReturnCode('"+str(bibtex_returncode)+"',\""+str(bibtex_output)+"\")") else: print(bibtex_output) # We need run latex at least 2 times bibtex=False runs=max([runs, 2]) # If bibtex contained errros we stop: # if not bibtex_returncode: # runs=max([runs, 2]) # else: # runs=1 elif bibtex: # we need run latex at least 3 times runs=max([runs, 3]) debug_file.write("\nRANGE="+str(range(1,runs+1))+"\n") debug_file.write("RUNS="+str(runs)+"\n") for i in range(1, runs+1): debug_file.write("RUN="+str(i)+"\n") debug_file.write("DIR="+str(os.getcwd())+"\n") tempdir_list = os.listdir(tmpdir) debug_file.write("ls tmpdir "+str(tempdir_list)+"\n") debug_file.write("BIBTEX="+str(bibtex)+"\n") if verbose == 'verbose' and i == runs: # compiler() contains here ( and not bibtex ) debug_file.write("VERBOSE"+"\n") latex=subprocess.Popen(latex_cmd) pid=latex.pid debug_file.write("latex pid "+str(pid)+"\n") latex.wait() latex_returncode=latex.returncode debug_file.write("latex ret code "+str(latex_returncode)+"\n") else: if progress_bar and verbose != 'verbose': latex=latex_progress_bar(latex_cmd) else: latex = subprocess.Popen(latex_cmd, stdout=subprocess.PIPE) pid = latex.pid vim.eval("atplib#callback#LatexPID("+str(pid)+")") debug_file.write("latex pid "+str(pid)+"\n") latex.wait() vim.eval("atplib#callback#PIDsRunning(\"b:atp_LatexPIDs\")") latex_returncode=latex.returncode debug_file.write("latex return code "+str(latex_returncode)+"\n") tempdir_list = os.listdir(tmpdir) debug_file.write("JUST AFTER LATEX ls tmpdir "+str(tempdir_list)+"\n") # Return code of compilation: if verbose != "verbose": vim.eval("atplib#callback#TexReturnCode('"+str(latex_returncode)+"')") if bibtex and i == 1: if bibcommand == 'biber': bibfname = basename else: bibfname = basename+".aux" debug_file.write("BIBTEX2 "+str([bibcommand, bibfname])+"\n") debug_file.write(os.getcwd()+"\n") tempdir_list = os.listdir(tmpdir) debug_file.write("ls tmpdir "+str(tempdir_list)+"\n") os.chdir(tmpdir) bibtex_popen=subprocess.Popen([bibcommand, bibfname], stdout=subprocess.PIPE) vim.eval("atplib#callback#BibtexPID('"+str(bibtex_popen.pid)+"')") vim.eval("atplib#callback#redrawstatus()") bibtex_popen.wait() vim.eval("atplib#callback#PIDsRunning(\"b:atp_BibtexPIDs\")") os.chdir(mainfile_dir) bibtex_returncode=bibtex_popen.returncode bibtex_output=re.sub('"', '\\"', bibtex_popen.stdout.read()) debug_file.write("BIBTEX2 RET CODE"+str(bibtex_returncode)+"\n") if verbose != 'verbose': vim.eval("atplib#callback#BibtexReturnCode('"+str(bibtex_returncode)+"',\""+str(bibtex_output)+"\")") else: print(bibtex_output) # If bibtex had errors we stop, # at this point tex file was compiled at least once. # if bibtex_returncode: # debug_file.write("BIBTEX BREAKE "+str(bibtex_returncode)+"\n") # break #################################### # # Copy Files: # #################################### # Copy files: os.chdir(tmpdir) for ext in list(filter(keep_filter_aux,keep))+[output_format]: file_cp=basename+"."+ext if os.path.exists(file_cp): debug_file.write(file_cp+' ') shutil.copy(file_cp, mainfile_dir) # Copy aux file if there were no compilation errors or if it doesn't exists in mainfile_dir. # copy aux file to _aux file (for atplib#tools#GrepAuxFile) if latex_returncode == 0 or not os.path.exists(os.path.join(mainfile_dir, basename+".aux")): file_cp=basename+".aux" if os.path.exists(file_cp): shutil.copy(file_cp, mainfile_dir) file_cp=basename+".aux" if os.path.exists(file_cp): shutil.copy(file_cp, os.path.join(mainfile_dir, basename+"._aux")) os.chdir(cwd) #################################### # # Call Back Communication: # #################################### if verbose != "verbose": debug_file.write("CALL BACK "+"atplib#callback#CallBack('"+str(verbose)+"','"+aucommand+"','"+str(bibtex)+"')"+"\n") vim.eval("atplib#callback#CallBack('"+str(verbose)+"','"+aucommand+"','"+str(bibtex)+"')") # return code of compelation is returned before (after each compilation). #################################### # # Reload/Start Viewer: # #################################### if re.search(viewer, '^\s*xpdf\e') and reload_viewer: # The condition tests if the server XpdfServer is running xpdf_server_dict=xpdf_server_file_dict() cond = xpdf_server_dict.get(XpdfServer, ['_no_file_']) != ['_no_file_'] debug_file.write("XPDF SERVER DICT="+str(xpdf_server_dict)+"\n") debug_file.write("COND="+str(cond)+":"+str(reload_on_error)+":"+str(bang)+"\n") debug_file.write("COND="+str( not reload_on_error or bang )+"\n") debug_file.write(str(xpdf_server_dict)+"\n") if start == 1: run=['xpdf'] run.extend(viewer_opt) run.append(output_fp) debug_file.write("D1: "+str(run)+"\n") subprocess.Popen(run) elif cond and ( reload_on_error or latex_returncode == 0 or bang ): run=['xpdf', '-remote', XpdfServer, '-reload'] subprocess.Popen(run, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) debug_file.write("D2: "+str(['xpdf', '-remote', XpdfServer, '-reload'])+"\n") else: if start >= 1: run=[viewer] run.extend(viewer_opt) run.append(output_fp) debug_file.write("RUN "+str(run)+"\n") subprocess.Popen(run, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) if start == 2: vim.eval("atplib#SyncTex()") #################################### # # Clean: # #################################### except Exception: error_str=re.sub("'", "''",re.sub('"', '\\"', traceback.format_exc())) traceback.print_exc(None, debug_file) vim.eval("atplib#callback#Echo(\"[ATP:] error in compile.py, catched python exception:\n"+error_str+"[ATP info:] this error message is recorded in compile.py.log under g:atp_TempDir\",'echo','ErrorMsg')") # cleanup(debug_file) # return(latex_returncode) LatexThread().start() ENDPYTHON endfunction "}}} " {{{ atplib#compiler#tex [test function] function! atplib#compiler#tex() " Notes: " this goes well untill status line is calling functions or functions which " are called via autocommands. Strange errors occur, for example: " Error detected while processing function 106_HighlightMatchingPair..LatexBox_InComment: " line 3: " E121: Undefined variable: a:var " and other similar errors. Mainly (if not only) errors E121. python << ENDPYTHON import vim, threading import sys, errno, os.path, shutil, subprocess, psutil, re, tempfile, optparse, glob import traceback, atexit from os import chdir, mkdir, putenv, devnull from collections import deque def latex_progress_bar(cmd): # Run latex and send data for progress bar, child = subprocess.Popen(cmd, stdout=subprocess.PIPE) # If I remove the code below and only put child.wait() # then vim crashes. pid = child.pid vim.eval("atplib#callback#LatexPID("+str(pid)+")") stack = deque([]) while True: try: out = child.stdout.read(1).decode() except UnicodeDecodeError: out = "" if out == '' and child.poll() != None: break if out != '': stack.append(out) if len(stack)>10: stack.popleft() match = re.match('\[(\n?\d(\n|\d)*)({|\])',str(''.join(stack))) if match: vim.eval("atplib#callback#ProgressBar("+match.group(1)[match.start():match.end()]+","+str(pid)+")") child.wait() vim.eval("atplib#callback#ProgressBar('end',"+str(pid)+")") vim.eval("atplib#callback#PIDsRunning(\"b:atp_LatexPIDs\")") return child class LatexThread( threading.Thread ): def run( self ): file=vim.eval("b:atp_MainFile") latex_progress_bar(['pdflatex', file]) LatexThread().start() ENDPYTHON endfunction "}}} " AUTOMATIC TEX PROCESSING: " {{{ atplib#compiler#auTeX " This function calls the compilers in the background. It Needs to be a global " function (it is used in options.vim, there is a trick to put function into " a dictionary ... ) function! atplib#compiler#auTeX(...) if !exists("b:atp_changedtick") let b:atp_changedtick = b:changedtick endif if g:atp_debugauTeX echomsg "*****************" echomsg "b:atp_changedtick=".b:atp_changedtick." b:changedtick=".b:changedtick endif if mode() == 'i' && b:atp_updatetime_insert == 0 || \ mode()=='n' && b:atp_updatetime_normal == 0 if g:atp_debugauTeX echomsg "autex is off for the mode: ".mode() endif return "autex is off for the mode: ".mode()." (see :help mode())" endif if mode() == 'i' && g:atp_noautex_in_math && atplib#IsInMath() return "noautex in math mode" endif " Wait if the compiler is running. The problem is that CursorHoldI autocommands " are not triggered more than once after 'updatetime'. " if index(split(g:atp_autex_wait, ','), mode()) != -1 " " \ !b:atp_autex_wait " if g:atp_Compiler == "python" " call atplib#callback#PIDsRunning("b:atp_PythonPIDs") " else " call atplib#callback#PIDsRunning("b:atp_LatexPIDs") " endif " call atplib#callback#PIDsRunning("b:atp_BibtexPIDs") " echo string(b:atp_BibtexPIDs) " if g:atp_Compiler == "python" && len(b:atp_PythonPIDs) || " \ g:atp_Compiler == "bash" && len(b:atp_LatexPIDs) || " \ len(b:atp_BibtexPIDs) " " unlockvar b:atp_autex_wait " " let b:atp_autex_wait=1 " " lockvar b:atp_autex_wait " if g:atp_debugauTeX " echomsg "autex wait" " endif " return " endif " " else " " unlockvar b:atp_autex_wait " " let b:atp_autex_wait=0 " " lockvar b:atp_autex_wait " endif " Using vcscommand plugin the diff window ends with .tex thus the autocommand " applies but the filetype is 'diff' thus we can switch tex processing by: if &l:filetype !~ "tex$" echo "wrong file type" return "wrong file type" endif let atp_MainFile = atplib#FullPath(b:atp_MainFile) " let mode = ( g:atp_DefaultDebugMode == 'verbose' ? 'debug' : g:atp_DefaultDebugMode ) let mode = substitute(t:atp_DebugMode, 'verbose$', 'debug', '') if !b:atp_autex if g:atp_debugauTeX echomsg "autex is off" endif return "autex is off" endif " If the file (or input file is modified) compile the document if filereadable(expand("%")) " if !exists("b:atp_changedtick") " let b:atp_changedtick = b:changedtick " endif if g:atp_Compare ==? "changedtick" let cond = ( b:changedtick != b:atp_changedtick ) else let cond = ( atplib#compiler#compare(readfile(expand("%"))) ) endif if g:atp_debugauTeX let g:cond=cond if g:atp_debugauTeX echomsg "COND=".cond endif endif if cond " This is for changedtick only let b:atp_changedtick = b:changedtick + 1 " +1 because atplib#compiler#Compiler saves the file what increases b:changedtick by 1. " this is still needed as I use not nesting BufWritePost autocommand to set " b:atp_changedtick (by default autocommands do not nest). Alternate solution is to " run atplib#compiler#AuTeX() with nested autocommand (|autocmd-nested|). But this seems " to be less user friendly, nested autocommands allows only 10 levels of " nesting (which seems to be high enough). " " if atplib#compiler#NewCompare() if g:atp_Compiler == 'python' if b:atp_autex == 1 " if g:atp_devversion == 0 call atplib#compiler#PythonCompiler(0, 0, b:atp_auruns, mode, "AU", atp_MainFile, "") " else " call atplib#compiler#ThreadedCompiler(0, 0, b:atp_auruns, mode, "AU", atp_MainFile, "") " endif else call atplib#compiler#LocalCompiler("n", 1) endif else call atplib#compiler#Compiler(0, 0, b:atp_auruns, mode, "AU", atp_MainFile, "") endif redraw if g:atp_debugauTeX echomsg "compile" endif return "compile" endif " if compiling for the first time else try " Do not write project script file while saving the file. let atp_ProjectScript = ( exists("g:atp_ProjectScript") ? g:atp_ProjectScript : -1 ) let g:atp_ProjectScript = 0 w if atp_ProjectScript == -1 unlet g:atp_ProjectScript else let g:atp_ProjectScript = atp_ProjectScript endif catch /E212:/ echohl ErrorMsg if g:atp_debugauTeX echomsg expand("%") . "E212: Cannon open file for writing" endif echohl None if g:atp_debugauTeX echomsg " E212" endif return " E212" catch /E382:/ " This option can be set by VCSCommand plugin using VCSVimDiff command if g:atp_debugauTeX echomsg " E382" endif return " E382" endtry if g:atp_Compiler == 'python' call atplib#compiler#PythonCompiler(0, 0, b:atp_auruns, mode, "AU", atp_MainFile, "") else call atplib#compiler#Compiler(0, 0, b:atp_auruns, mode, "AU", atp_MainFile, "") endif redraw if g:atp_debugauTeX echomsg "compile for the first time" endif return "compile for the first time" endif if g:atp_debugauTeX echomsg "files does not differ" endif return "files does not differ" endfunction "}}} " Related Functions " {{{ atplib#compiler#TeX " a:runs = how many consecutive runs " a:1 = one of 'default','silent', 'debug', 'verbose' " if not specified uses 'default' mode " (g:atp_DefaultDebugMode). function! atplib#compiler#TeX(runs, bang, ...) let atp_MainFile = atplib#FullPath(b:atp_MainFile) if !exists("t:atp_DebugMode") let t:atp_DebugMode = g:atp_DefaultDebugMode endif if a:0 >= 1 let mode = ( a:1 != 'default' ? a:1 : t:atp_DebugMode ) else let mode = t:atp_DebugMode endif let match = matchlist(mode, '^\(auto\)\?\(.*$\)') let auto = match[1] let mode = match[2] if mode =~# '^s\%[ilent]$' let mode = 'silent' elseif mode =~# '^d\%[ebug]$' let mode = 'debug' elseif mode =~# 'D\%[ebug]$' let mode = 'Debug' elseif mode =~# '^v\%[erbose]$' let mode = 'verbose' else let mode = t:atp_DebugMode endif let mode = auto . mode for cmd in keys(g:CompilerMsg_Dict) if b:atp_TexCompiler =~ '^\s*' . cmd . '\s*$' let Compiler = g:CompilerMsg_Dict[cmd] break else let Compiler = b:atp_TexCompiler endif endfor if l:mode != 'silent' if a:runs > 2 && a:runs <= 5 echo "[ATP:] ".Compiler . " will run " . a:1 . " times." elseif a:runs == 2 echo "[ATP:] ".Compiler . " will run twice." elseif a:runs == 1 echo "[ATP:] ".Compiler . " will run once." elseif a:runs > 5 echo "[ATP:] ".Compiler . " will run " . s:runlimit . " times." endif endif if g:atp_Compiler == 'python' call atplib#compiler#PythonCompiler(0,0, a:runs, mode, "COM", atp_MainFile, a:bang) else call atplib#compiler#Compiler(0,0, a:runs, mode, "COM", atp_MainFile, a:bang) endif endfunction "}}} "{{{ atplib#compiler#DebugComp() function! atplib#compiler#DebugComp(A,L,P) return "silent\ndebug\nDebug\nverbose" endfunction "}}} "{{{ atplib#compiler#Bibtex function! atplib#compiler#SimpleBibtex() let bibcommand = b:atp_BibCompiler." " let atp_MainFile = atplib#FullPath(b:atp_MainFile) if b:atp_BibCompiler =~ '^\s*biber\>' let file = fnamemodify(resolve(atp_MainFile),":t:r") else let file = fnamemodify(resolve(atp_MainFile),":t:r") . ".aux" endif let auxfile = fnamemodify(resolve(atp_MainFile),":t:r") . ".aux" " When oupen_out = p (in texmf.cnf) bibtex can only open files in the working " directory and they should no be given with full path: " p (paranoid) : as `r' and disallow going to parent directories, and " restrict absolute paths to be under $TEXMFOUTPUT. let saved_cwd = getcwd() exe "lcd " . fnameescape(expand(b:atp_OutDir)) let g:cwd = getcwd() if filereadable(auxfile) let command = bibcommand . shellescape(file) let b:atp_BibtexOutput=system(command) let b:atp_BibtexReturnCode=v:shell_error echo b:atp_BibtexOutput else echo "[ATP:] aux file " . auxfile . " not readable." endif exe "lcd " . fnameescape(saved_cwd) endfunction function! atplib#compiler#Bibtex(bang, ...) if a:0 >= 1 && a:1 =~# '^o\%[utput]$' redraw! if exists("b:atp_BibtexReturnCode") echo "[Bib:] BibTeX returned with exit code " . b:atp_BibtexReturnCode endif if exists("b:atp_BibtexOutput") echo substitute(b:atp_BibtexOutput, '\(^\zs\|\n\)', '\1 ', "g") else echo "No BibiTeX output." endif return elseif a:bang == "" call atplib#compiler#SimpleBibtex() return endif let atp_MainFile = atplib#FullPath(b:atp_MainFile) let g:a=a:0 if a:0 >= 1 let mode = ( a:1 != 'default' ? a:1 : t:atp_DebugMode ) else let mode = t:atp_DebugMode endif if mode =~# '^s\%[ilent]$' let mode = 'silent' elseif mode =~# '^d\%[ebug]$' let mode = 'debug' elseif mode =~# 'D\%[ebug]$' let mode = 'Debug' elseif mode =~# '^v\%[erbose]$' let mode = 'verbose' else let mode = t:atp_DebugMode endif if g:atp_Compiler == 'python' call atplib#compiler#PythonCompiler(1, 0, 0, mode, "COM", atp_MainFile, "") else call atplib#compiler#Compiler(1, 0, 0, mode, "COM", atp_MainFile, "") endif endfunction function! atplib#compiler#BibtexComp(A,L,P) return "silent\ndebug\nDebug\nverbose\noutput" endfunction "}}} " Show Errors Function " (some error tools are in various.vim: ':ShowErrors o') " {{{ SHOW ERRORS " " this functions sets errorformat according to the flag given in the argument, " possible flags: " e - errors (or empty flag) " w - all warning messages (LaTeX warning, Citation warnings, Reference Warnings, Package warnings) " c - citation warning messages " r - reference warning messages " f - font warning messages " fi - font warning and info messages " F - files " o - open log file " h - overfull and underfull \hbox /g:atp_ParseLog only/ " p - package info messages ('Package \w\+ Info: ') /g:atp_ParseLog only/ " P - packages (lines which start with 'Package: ') " {{{ atplib#compiler#SetErrorFormat " first argument is a word in flags " the default is a:1=e /show only error messages/ function! atplib#compiler#SetErrorFormat(cgetfile,...) " Get the bufnr of tex file corresponding to the &l:errorfile let bufnr = bufnr(fnamemodify(&l:errorfile, ":r").".tex") let carg = !exists("w:quickfix_title") && exists("b:atp_ErrorFormat") \ ? b:atp_ErrorFormat \ : getbufvar((bufnr), "atp_ErrorFormat") let atp_ErrorFormat = ( exists("b:atp_ErrorFormat") ? b:atp_ErrorFormat : getbufvar((bufnr), "atp_ErrorFormat") ) " This a:cgetfile == 1 only if run by the command :ErrorFormat let efm = ( a:0 >= 1 ? a:1 : '' ) if efm == "" || a:0 == 0 echo "[ATP:] current error format: ".atp_ErrorFormat return endif let carg_raw = ( a:0 >= 1 ? a:1 : g:atp_DefaultErrorFormat ) let carg_lists = split(carg_raw, '\ze[+-]') for carg_r in carg_lists let carg_list= split(carg_r, '\zs') if carg_list[0] =~ '^[+-]$' let add=remove(carg_list,0) else let add=0 endif for i in range(0, len(carg_list)-2) if carg_list[i] == 'f' && get(carg_list,i+1, "") == "i" call remove(carg_list, i+1) let carg_list[i]="fi" endif endfor if carg_r =~ '^+' for flag in carg_list if flag !=# 'f' && atp_ErrorFormat !~# flag || flag == 'f' && atp_ErrorFormat !~# 'fi\@!' let carg .= flag endif endfor elseif carg_r =~ '^-' for flag in carg_list if flag !=# 'f' let carg=substitute(carg, '\C'.flag, '', 'g') else let carg=substitute(carg, '\Cfi\@!', '', 'g') endif endfor else let carg=carg_r endif endfor let b:atp_ErrorFormat = carg if exists("w:quickfix_title") call setbufvar(bufnr, "atp_ErrorFormat", carg) endif let &l:errorformat="" if ( carg =~ 'e' || carg =~? 'all' ) if g:atp_ParseLog let efm = 'LaTeX\ %trror::%f::%l::%c::%m' else let efm = "%E!\ LaTeX\ Error:\ %m,\%E!\ %m,%E!pdfTeX Error:\ %m" endif if &l:errorformat == "" let &l:errorformat= efm else let &l:errorformat= &l:errorformat . "," . efm endif endif if ( carg =~ 'w' || carg =~? 'all' ) if g:atp_ParseLog let efm = 'LaTeX\ %tarning::%f::%l::%c::%m,Citation\ %tarning::%f::%l::%c::%m,Reference\ LaTeX\ %tarning::%f::%l::%c::%m,Package %tarning::%f::%l::0::%m' else let efm='%WLaTeX\ %tarning:\ %m\ on\ input\ line\ %l%., \%WLaTeX\ %.%#Warning:\ %m, \%Z(Font) %m\ on\ input\ line\ %l%., \%+W%.%#\ at\ lines\ %l--%*\\d' endif " let efm= " \'%+WLaTeX\ %.%#Warning:\ %.%#line\ %l%.%#, " \%+W%.%#\ at\ lines\ %l--%*\\d, " \%WLaTeX\ %.%#Warning:\ %m' if &l:errorformat == "" let &l:errorformat=efm else let &l:errorformat= &l:errorformat . ',' . efm " let &l:errorformat= &l:errorformat . ',%+WLaTeX\ %.%#Warning:\ %.%#line\ %l%.%#, " \%WLaTeX\ %.%#Warning:\ %m, " \%+W%.%#\ at\ lines\ %l--%*\\d' endif endif if g:atp_ParseLog && ( carg =~# 'h' || carg =~? 'all' ) let efm = "hbox %tarning::%f::%l::0::%m" if &l:errorformat == "" let &l:errorformat=efm else let &l:errorformat= &l:errorformat . ',' . efm endif endif if ( carg =~ '\Cc' || carg =~? 'all' ) " NOTE: " I would like to include 'Reference/Citation' as an error message (into %m) " but not include the 'LaTeX Warning:'. I don't see how to do that actually. " The only solution, that I'm aware of, is to include the whole line using " '%+W' but then the error messages are long and thus not readable. if g:atp_ParseLog let efm = "Citation\ %tarning::%f::%l::%c::%m" else let efm = "%WLaTeX\ Warning:\ Citation\ %m\ on\ input\ line\ %l%.%#" endif if &l:errorformat == "" let &l:errorformat = efm else let &l:errorformat = &l:errorformat.",".efm endif endif if ( carg =~ '\Cr' || carg =~? 'all' ) if g:atp_ParseLog let efm = "Reference\ LaTeX\ %tarning::%f::%l::%c::%m" else let efm = "%WLaTeX\ Warning:\ Reference %m on\ input\ line\ %l%.%#,%WLaTeX\ %.%#Warning:\ Reference %m,%C %m on input line %l%.%#" endif if &l:errorformat == "" let &l:errorformat = efm else let &l:errorformat = &l:errorformat.",".efm endif endif if carg =~ '\Cf' || carg =~# 'All' if g:atp_ParseLog let efm = "LaTeX\ Font\ %tarning::%f::%l::%c::%m" else let efm = "%WLaTeX\ Font\ Warning:\ %m,%Z(Font) %m on input line %l%.%#" endif if &l:errorformat == "" let &l:errorformat = efm else let &l:errorformat = &l:errorformat.",".efm endif endif if carg =~ '\Cfi' || carg =~# 'All' if g:atp_ParseLog let efm = 'LaTeX\ Font %tnfo::%f::%l::%c::%m' else let efm = '%ILatex\ Font\ Info:\ %m on input line %l%.%#, \%ILatex\ Font\ Info:\ %m, \%Z(Font) %m\ on input line %l%.%#, \%C\ %m on input line %l%.%#' endif if &l:errorformat == "" let &l:errorformat = efm else let &l:errorformat = &l:errorformat.','.efm endif endif if carg =~ '\CF' || carg =~# 'All' if g:atp_ParseLog let efm = "%tnput File::%f::%l::%c::%m,%tnput Package::%f::%l::%c::%m" else let efm = '%+P)%#%\\s%#(%f,File: %m,Package: %m,Document Class: %m,LaTeX2e %m' endif if &l:errorformat == "" let &l:errorformat = efm else let &l:errorformat = &l:errorformat . ',' . efm endif endif if g:atp_ParseLog && (carg =~ '\Cp' || carg =~# 'All') let efm = "Package %tnfo::%f::%l::0::%m" if &l:errorformat == "" let &l:errorformat = efm else let &l:errorformat = &l:errorformat.','.efm endif endif if carg =~ '\CP' || carg =~# 'All' if g:atp_ParseLog let efm = "Input %tackage::%f::0::0::%m" else let efm = 'Package: %m' endif if &l:errorformat == "" let &l:errorformat = efm else let &l:errorformat = &l:errorformat.','.efm endif endif if &l:errorformat != "" && !g:atp_ParseLog " let pm = ( g:atp_show_all_lines == 1 ? '+' : '-' ) " let l:dont_ignore = 0 " if carg =~ '\CA\cll' " let l:dont_ignore = 1 " let pm = '+' " endif let l:dont_ignore= 1 let pm = '+' let &l:errorformat = &l:errorformat.", \%-C<%.%#>%.%#, \%-Zl.%l\ , \%-Zl.%l\ %m, \%-ZI've inserted%.%#, \%-ZThe control sequence%.%#, \%-ZYour command was ignored%.%#, \%-ZYou've closed more groups than you opened%.%#, \%-ZThe `$' that I just saw%.%#, \%-ZA number should have been here%.%#, \%-ZI'm ignoring this;%.%#, \%-ZI suspect you've forgotten%.%#, \%-GSee LaTeX%.%#, \%-GType\ \ H\ %m, \%-C\\s%#%m, \%-C%.%#-%.%#, \%-C%.%#[]%.%#, \%-C[]%.%#, \%-C%.%#%[{}\\]%.%#, \%-G ...%.%#, \%-G%.%#\ (C)\ %.%#, \%-G(see\ the\ transcript%.%#), \%-G\\s%#, \%-G%.%#" " These two appeared before l.%l (cannot be -Z): " \%-GSee LaTeX%.%#, " \%-GType\ \ H\ %m, let &l:errorformat = &l:errorformat.", \%".pm."O(%*[^()])%r, \%".pm."O%*[^()](%*[^()])%r, \%".pm."P(%f%r, \%".pm."P\ %\\=(%f%r, \%".pm."P%*[^()](%f%r, \%".pm."P[%\\d%[^()]%#(%f%r" let &l:errorformat = &l:errorformat.", \%".pm."Q)%r, \%".pm."Q%*[^()])%r, \%".pm."Q[%\\d%*[^()])%r" endif if a:cgetfile try cgetfile call atplib#compiler#FilterQuickFix() catch E40: endtry if g:atp_signs call atplib#callback#Signs(bufnr("%")) endif endif let eventignore=&eventignore set eventignore=BufEnter,BufLeave if !exists("t:atp_QuickFixOpen") let t:atp_QuickFixOpen = 0 windo let t:atp_QuickFixOpen+= ( &buftype == 'quickfix' ) wincmd w endif if t:atp_QuickFixOpen let winnr=winnr() " Quickfix is opened, jump to it and change the size copen exe "resize ".min([atplib#qflength(), g:atp_DebugModeQuickFixHeight]) exe winnr."wincmd w" endif let &eventignore=eventignore if add != "0" echo "[ATP:] current error format: ".b:atp_ErrorFormat endif endfunction "}}} function! atplib#compiler#FilterQuickFix() "{{{ if !g:atp_ParseLog return endif let qflist = getqflist() call filter(qflist, 'v:val["type"] != ""') let new_qflist = [] for item in qflist call remove(item, "valid") call add(new_qflist, item) endfor call setqflist(new_qflist) endfunction "}}} "{{{ atplib#compiler#ShowErrors " each argument can be a word in flags as for atplib#compiler#SetErrorFormat (except the " word 'whole') + two other flags: all (include all errors) and ALL (include " all errors and don't ignore any line - this overrides the variables " g:atp_ignore_unmatched and g:atp_show_all_lines. function! atplib#compiler#ShowErrors(bang,...) " It is not atplib#compiler# because it is run from atplib#callback#CallBack() let local_errorfile = ( a:0 >= 1 ? a:1 : 0 ) let error_format = b:atp_ErrorFormat " remember the old error format to set it back, unless bang is present. let l:arg = ( a:0 >= 2 ? a:2 : b:atp_ErrorFormat ) let show_message = ( a:0 >= 3 ? a:3 : 1 ) if local_errorfile if !exists("errorfile") let errorfile = &l:errorfile endif let &l:errorfile = atplib#joinpath(expand(b:atp_OutDir), expand("%:t:r")."._log") else if exists("errorfile") let &l:errorfile = errorfile unlet errorfile endif endif let errorfile = &l:errorfile " read the log file and merge warning lines " filereadable doesn't like shellescaped file names not fnameescaped. " The same for readfile() and writefile() built in functions. if !filereadable(errorfile) echohl WarningMsg echo "[ATP:] no error file: " . errorfile echohl None return endif let log=readfile(errorfile) if !g:atp_ParseLog let nr=1 for line in log if line =~ "LaTeX Warning:" && get(log, nr, '') !~ "^$" let newline=line . log[nr] let log[nr-1]=newline call remove(log,nr) endif let nr+=1 endfor call writefile(log, errorfile) endif if l:arg =~# 'o' OpenLog return elseif l:arg =~ 'b' echo b:atp_BibtexOutput return endif call atplib#compiler#SetErrorFormat(0, l:arg) " read the log file cgetfile call atplib#compiler#FilterQuickFix() " signs if g:atp_signs call atplib#callback#Signs(bufnr("%")) endif " final stuff if len(getqflist()) == 0 if show_message echo "[ATP:] no errors :)" . (local_errorfile ? " in ".fnamemodify(&l:errorfile, ":.") : "") endif else clist endif if empty(a:bang) && l:arg != error_format call atplib#compiler#SetErrorFormat(0, error_format) cgetfile endif endfunction "}}} if !exists("*ListErrorsFlags") function! atplib#compiler#ListErrorsFlags(A,L,P) let flags=['e', 'w', 'r', 'c', 'f', 'F', 'h', 'p', 'P', 'o', 'all', 'All'] if !g:atp_ParseLog call remove(flags, index(flags, 'p')) endif return join(flags, "\n") endfunction endif if !exists("*ListErrorsFlags_A") function! atplib#compiler#ListErrorsFlags_A(A,L,P) " This has no o flag. let flags=['e', 'w', 'r', 'c', 'f', 'fi', 'F', 'h', 'p', 'P', 'all', 'All'] if !g:atp_ParseLog call remove(flags, index(flags, 'p')) endif return join(flags, "\n") endfunction endif "}}} " vim:fdm=marker:tw=85:ff=unix:noet:ts=8:sw=4:fdc=1 autoload/atplib/complete.vim [[[1 3516 " Title: Vim library for ATP filetype plugin. " Author: Marcin Szamotulski " Email: mszamot [AT] gmail [DOT] com " Note: This file is a part of Automatic Tex Plugin for Vim. " URL: https://launchpad.net/automatictexplugin " Language: tex " Check If Closed: " This functions checks if an environment is closed/opened. " atplib#complete#CheckClosed {{{1 " check if last bpat is closed. " starting from the current line, limits the number of " lines to search. It returns 0 if the environment is not closed or the line " number where it is closed (an env is cannot be closed in 0 line) " ToDo: the two function should only check not commented lines! " " Method 0 makes mistakes if the pattern is \begin:\end, if " \begin{env_name}:\end{env_names} rather no (unless there are nested " environments in the same name. " Method 1 doesn't make mistakes and thus is preferable. " after testing I shall remove method 0 " Method 2 doesn't makes less mistakes than method 1 (which makes them :/) but it is only for " brackets, returns >0 if the bracket is closed 0 if it is not. try function! atplib#complete#CheckClosed(bpat, epat, line, col, limit,...) " NOTE: THIS IS MUCH FASTER !!! or SLOWER !!! ??? " " let l:pos_saved=getpos(".") " let l:cline=line(".") " if a:line != l:cline " let l:col=len(getline(a:line)) " keepjumps call setpos(".",[0,a:line,l:col,0]) " endif " let l:line=searchpair(a:bpat,'',a:epat,'nWr','',max([(a:line+a:limit),1])) " if a:line != l:cline " keepjumps call setpos(".",l:pos_saved) " endif " return l:line let time = reltime() let l:method = ( a:0 >= 1 ? a:1 : 0 ) let saved_pos = getpos(".") " let l:count_method = ( a:0 >= 2 ? a:2 : 1 ) let l:len = len(getbufline(bufname("%"),1,'$')) let l:nr = a:line let cline = line(".") if a:limit == "$" || a:limit == "-1" let l:limit=l:len-a:line else let l:limit=a:limit endif if g:atp_debugCheckClosed let g:saved_pos = getpos(".") let g:nr = a:line let g:bpat = a:bpat let g:limit = l:limit endif if g:atp_debugCheckClosed == 1 call atplib#Log("CheckClosed.log","", "init") endif if l:method==0 " {{{2 while l:nr <= a:line+l:limit let l:line=getline(l:nr) " Remove comments: let l:line=substitute(l:line, '\(\\\@> cline=".cline."> cpos_bpat_count=".cpos_bpat_count." cpos_epat_count=".cpos_epat_count) endif endif " Strip comments: let comment_match = match(l:line, '\%(\\\\\|\\\@= 0 if g:atp_debugCheckClosed call atplib#Log("CheckClosed.log", l:nr." l:bpat_count=".l:bpat_count." l:epat_count=".l:epat_count." ".l:line) if l:nr == saved_pos[1] call atplib#Log("CheckClosed.log", l:nr." l:closed_before_count=".l:closed_before_count) endif if l:nr >= saved_pos[1] call atplib#Log("CheckClosed.log", "cond (closed-opened)=".cond." value=".(l:epat_count - l:closed_before_count - l:bpat_count)) endif endif if l:nr >= saved_pos[1] && cond let g:time_CheckClosed=reltimestr(reltime(time)) if g:atp_debugCheckClosed let g:return = l:nr endif return l:nr endif let l:nr+=1 endwhile let g:time_CheckClosed=reltimestr(reltime(time)) return 0 elseif l:method==3 " {{{2 " This is a special method for brackets. " But it is too slow! " silent echomsg "***************" let saved_pos = getpos(".") call cursor(a:line, a:col) let c_pos = [a:line, a:col] let line = a:line " silent echomsg "a:line=".a:line." c_pos=".string(c_pos)." a:limit=".a:limit." cond=".string(a:line-c_pos[0] <= a:limit) while a:line-c_pos[0] <= a:limit let pos=searchpairpos(a:bpat, '', a:epat, 'b') " silent echomsg string(pos) if pos == [0, 0] " silent echomsg "C1" call cursor(saved_pos[1], saved_pos[2]) let g:time_CheckClosed=reltimestr(reltime(time)) return c_pos[0] endif if pos == c_pos " silent echomsg "C2" call cursor(saved_pos[1], saved_pos[2]) let g:time_CheckClosed=reltimestr(reltime(time)) return 0 endif if atplib#CompareCoordinates(c_pos, pos) " silent echomsg "C3" call cursor(saved_pos[1], saved_pos[2]) let g:time_CheckClosed=reltimestr(reltime(time)) return 0 endif let c_pos = copy(pos) endwhile " silent echomsg "C4" call cursor(saved_pos[1], saved_pos[2]) let g:time_CheckClosed=reltimestr(reltime(time)) return 1 endif endfunction catch /E127:/ endtry " }}}1 " {{{1 atplib#complete#CheckClosed_math " This functions makes a test if in line math is closed. This works well with " \(:\) and \[:\] but not yet with $:$ and $$:$$. " a:mathZone = texMathZoneV or texMathZoneW or texMathZoneX or texMathZoneY " The function return 1 if the mathZone is to be closed (i.e. it is not closed). function! atplib#complete#CheckClosed_math(mathZone) let time = reltime() let synstack = map(synstack(line("."), max([1, col(".")-1])), "synIDattr( v:val, 'name')") let check = 0 let patterns = { \ 'texMathZoneV' : [ '\\\@' " (some times one wants to have a command which opens an environment. " Todo: write a faster function using searchpairpos() which returns correct " values. function! atplib#complete#CheckOpened(bpat,epat,line,limit) " this is almost good: " let l:line=searchpair(a:bpat,'',a:epat,'bnWr','',max([(a:line-a:limit),1])) " return l:line let l:len=len(getbufline(bufname("%"),1,'$')) let l:nr=a:line if a:limit == "^" || a:limit == "-1" let l:limit=a:line-1 else let l:limit=a:limit endif while l:nr >= a:line-l:limit && l:nr >= 1 let l:line=getline(l:nr) if l:nr == a:line if substitute(strpart(l:line,0,getpos(".")[2]), a:bpat . '.\{-}' . a:epat,'','g') \ =~ a:bpat return l:nr endif else " if l:check_mode == 0 " if substitute(l:line, a:bpat . '.\{-}' . a:epat,'','g') " \ =~ a:bpat " " check if it is closed up to the place where we start. (There " " is no need to check after, it will be checked anyway " " b a serrate call in atplib#complete#TabCompletion. " if !atplib#complete#CheckClosed(a:bpat,a:epat,l:nr,0,a:limit,0) " " LAST CHANGE 1->0 above " " let b:cifo_return=2 . " " . l:nr " return l:nr " endif " endif " elseif l:check_mode == 1 if substitute(l:line, a:bpat . '.\{-}' . a:epat,'','g') \ =~ '\%(\\def\|\%(re\)\?newcommand\)\@= a:line " let b:cifo_return=2 . " " . l:nr return l:nr endif endif " endif endif let l:nr-=1 endwhile return 0 endfunction " }}}1 " {{{1 atplib#complete#CheckSyntaxGroups " This functions returns one if one of the environment given in the list " a:zones is present in they syntax stack at line a:1 and column a:0. " a:zones = a list of zones " a:1 = line nr (default: current cursor line) " a:2 = column nr (default: column before the current cursor position) " The function doesn't make any checks if the line and column supplied are " valid /synstack() function returns 0 rather than [] in such a case/. function! atplib#complete#CheckSyntaxGroups(zones,...) let line = a:0 >= 1 ? a:1 : line(".") let col = a:0 >= 2 ? a:2 : col(".")-1 let col = max([1, col]) let zones = copy(a:zones) let synstack_raw = synstack(line, col) if type(synstack_raw) != 3 unlet synstack_raw return 0 endif let synstack = map(synstack_raw, 'synIDattr(v:val, "name")') return max(map(zones, "count(synstack, v:val)")) endfunction " atplib#complete#CopyIndentation {{{1 function! atplib#complete#CopyIndentation(line) let raw_indent = split(a:line,'\s\zs') let indent = "" for char in raw_indent if char =~ '^\%(\s\|\t\)' let indent.=char else break endif endfor return indent endfunction "}}}1 " Close Environments And Brackets: " atplib#complete#CloseLastEnvironment {{{1 " a:1 = i (append before, so the cursor will be after - the dafult) " a (append after) " a:2 = math the pairs \(:\), $:$, \[:\] or $$:$$ (if filetype is " plaintex or b:atp_TexFlavor="plaintex") " environment " by the way, treating the math pairs together is very fast. " a:3 = environment name (if present and non zero sets a:2 = environment) " if one wants to find an environment name it must be 0 or "" or not " given at all. " a:4 = line and column number (in a vim list) where environment is opened " a:5 = return only (only return the closing code (implemented only for a:2="math") " ToDo: Ad a highlight to messages!!! AND MAKE IT NOT DISAPPEAR SOME HOW? " (redrawing doesn't help) CHECK lazyredraw. " Note: this function tries to not double the checks what to close if it is " given in the arguments, and find only the information that is not given " (possibly all the information as all arguments can be omitted). function! atplib#complete#CloseLastEnvironment(...) let time = reltime() let l:com = a:0 >= 1 ? a:1 : 'i' let l:close = a:0 >= 2 && a:2 != "" ? a:2 : 0 if a:0 >= 3 let l:env_name = ( a:3 == "" ? 0 : a:3 ) let l:close = ( a:3 != '' ? "environment" : l:close ) else let l:env_name = 0 endif let l:bpos_env = ( a:0 >= 4 ? a:4 : [0, 0] ) let return_only = ( a:0 >= 5 ? a:5 : 0 ) if g:atp_debugCloseLastEnvironment call atplib#Log('CloseLastEnvironment.log', '', 'init') let g:CLEargs = string(l:com) . " " . string(l:close) . " " . string(l:env_name) . " " . string(l:bpos_env) silent echo "args=".g:CLEargs let g:close = l:close let g:env_name = l:env_name let g:bpos_env = l:bpos_env call atplib#Log('CloseLastEnvironment.log', 'ARGS = '.g:CLEargs) endif " {{{2 find the begining line of environment to close (if we are closing " an environment) if l:env_name == 0 && ( l:close == "environment" || l:close == 0 ) && l:close != "math" let filter = 'strpart(getline(''.''), 0, col(''.'') - 1) =~ ''\\\@', 'bnW') " Check if one of \(:\), \[:\], $:$, $$:$$ is opened using syntax " file. If it is fined the starting position. let synstack = map(synstack(line("."),max([1, col(".")-1])), 'synIDattr(v:val, "name")') if g:atp_debugCloseLastEnvironment let g:synstackCLE = deepcopy(synstack) let g:openCLE = getline(".")[col(".")-1] . getline(".")[col(".")] call atplib#Log('CloseLastEnvironment.log', "g:openCLE=".string(g:openCLE)) call atplib#Log('CloseLastEnvironment.log', 'synstack='.string(synstack)) endif let bound_1 = getline(".")[col(".")-1] . getline(".")[col(".")] =~ '^\\\%((\|)\)$' let math_1 = (index(synstack, 'texMathZoneV') != -1 && !bound_1 ? 1 : 0 ) if math_1 if l:bpos_env == [0, 0] let bpos_math_1 = searchpos('\%(\%(\\\)\@= 1 let l:close = 'math' elseif l:env_name let l:close = 'environment' else if g:atp_debugCloseLastEnvironment call atplib#Log('CloseLastEnvironment.log', "return: l:env_name=".string(l:env_name)." && math_1+...+math_4=".string(math_1+math_2+math_3+math_4)) endif let g:time_CloseLastEnvironment = reltimestr(reltime(time)) return '' endif endif if g:atp_debugCloseLastEnvironment let g:close = l:close call atplib#Log('CloseLastEnvironment.log', 'l:close='.l:close) call atplib#Log('CloseLastEnvironment.log', 'l:env_name='.l:env_name) endif let l:env=l:env_name "}}}2 if l:close == "0" || l:close == 'math' && !exists("begin_line") if g:atp_debugCloseLastEnvironment call atplib#Log('CloseLastEnvironment.log', 'there was nothing to close') endif let g:time_CloseLastEnvironment = reltimestr(reltime(time)) return '' endif if ( &filetype != "plaintex" && b:atp_TexFlavor != "plaintex" && exists("math_4") && math_4 ) echohl ErrorMsg echomsg "[ATP:] $$:$$ in LaTeX are deprecated (this breaks some LaTeX packages)" echomsg " You can set b:atp_TexFlavor = 'plaintex', and ATP will ignore this. " echohl None if g:atp_debugCloseLastEnvironment call atplib#Log('CloseLastEnvironment.log', "return A") endif let g:time_CloseLastEnvironment = reltimestr(reltime(time)) return '' endif if l:env_name =~ '^\s*document\s*$' if g:atp_debugCloseLastEnvironment call atplib#Log('CloseLastEnvironment.log', "return B") endif let g:time_CloseLastEnvironment = reltimestr(reltime(time)) return '' endif let l:cline = getline(".") let l:pos = getpos(".") if l:close == "math" let l:line = getline(l:begin_line) elseif l:close == "environment" let l:line = getline(l:bpos_env[0]) endif if g:atp_debugCloseLastEnvironment let g:line = ( exists("l:line") ? l:line : 0 ) call atplib#Log('CloseLastEnvironment.log', "g:line=".g:line) endif " Copy the indentation of what we are closing. let l:eindent=atplib#complete#CopyIndentation(l:line) "{{{2 close environment if l:close == 'environment' " Info message redraw " echomsg "[ATP:] closing " . l:env_name . " from line " . l:bpos_env[0] " Rules: " env & \[ \]: close in the same line " unless it starts in a serrate line, " \( \): close in the same line. "{{{3 close environment in the same line if l:line != "" && l:line !~ '^\s*\%(\$\|\$\$\|[^\\]\\%(\|\\\@= 0 let [ l:line_nr, l:col_nr ]=searchpos('\%(%.*\)\@ 0 let l:max=max(l:cenv_lines) let l:pos[1]=l:max+1 " find the first closed item below the last closed " pair (below l:pos[1]). (I assume every env is in " a seprate line! let l:end=atplib#complete#CheckClosed('\%(%.*\)\@= l:end call append(l:end-1, l:eindent . l:str) echomsg "[ATP:] closing " . l:env_name . " from line " . l:bpos_env[0] . " at line " . l:end call setpos(".",[0,l:end,len(l:eindent.l:str)+1,0]) endif else if line(".") >= l:max call append(l:pos_saved[1], l:eindent . l:str) keepjumps call setpos(".",l:pos_saved) echomsg "[ATP:] closing " . l:env_name . " from line " . l:bpos_env[0] . " at line " . (line(".")+1) call setpos(".",[0,l:pos_saved[1]+1,len(l:eindent.l:str)+1,0]) elseif line(".") < l:max call append(l:max, l:eindent . l:str) echomsg "[ATP:] closing " . l:env_name . " from line " . l:bpos_env[0] . " at line " . (l:max+1) call setpos(".",[0,l:max+1,len(l:eindent.l:str)+1,0]) endif endif else let l:pos[1]=l:line_nr let l:pos[2]=1 " put cursor at the end of the line where not closed \begin was " found keepjumps call setpos(".",[0,l:line_nr,len(getline(l:line_nr)),0]) let l:cline = getline(l:pos_saved[1]) if g:atp_debugCloseLastEnvironment let g:cline = l:cline let g:pos_saved = copy(l:pos_saved) let g:line = l:pos_saved[1] endif let l:iline=searchpair('\\begin{','','\\end{','nW') if l:iline > l:line_nr && l:iline <= l:pos_saved[1] call append(l:iline-1, l:eindent . l:str) echomsg "[ATP:] closing " . l:env_name . " from line " . l:bpos_env[0] . " at line " . l:iline let l:pos_saved[2]+=len(l:str) call setpos(".",[0,l:iline,len(l:eindent.l:str)+1,0]) else if l:cline =~ '\\begin{\%('.l:uenv.'\)\@!' call append(l:pos_saved[1]-1, l:eindent . l:str) echomsg "[ATP:] closing " . l:env_name . " from line " . l:bpos_env[0] . " at line " . l:pos_saved[1] let l:pos_saved[2]+=len(l:str) call setpos(".",[0,l:pos_saved[1],len(l:eindent.l:str)+1,0]) elseif l:cline =~ '^\s*$' call append(l:pos_saved[1]-1, l:eindent . l:str) echomsg "[ATP:] closing " . l:env_name . " from line " . l:bpos_env[0] . " at line " . l:pos_saved[1] let l:pos_saved[2]+=len(l:str) call setpos(".",[0,l:pos_saved[1]+1,len(l:eindent.l:str)+1,0]) else call append(l:pos_saved[1], l:eindent . l:str) echomsg "[ATP:] closing " . l:env_name . " from line " . l:bpos_env[0] . " at line " . (l:pos_saved[1]+1) " Do not move corsor if: '\begin{env_name}' if l:cline !~ '\\begin\s*{\s*\%('.l:uenv.'\)\s*}' let l:pos_saved[2]+=len(l:str) call setpos(".",[0,l:pos_saved[1]+1,len(l:eindent.l:str)+1,0]) else call setpos(".", l:pos_saved) endif endif endif if g:atp_debugCloseLastEnvironment silent echo "return E" redir END endif let g:time_CloseLastEnvironment = reltimestr(reltime(time)) return '' endif else if g:atp_debugCloseLastEnvironment silent echo "return F" redir END endif let g:time_CloseLastEnvironment = reltimestr(reltime(time)) return '' endif unlet! l:env_names unlet! l:env_dict unlet! l:cenv_names unlet! l:pos unlet! l:pos_saved " if getline('.') =~ '^\s*$' " exec "normal dd" endif "}}}3 "{{{2 close math: texMathZoneV, texMathZoneW, texMathZoneX, texMathZoneY else "{{{3 Close math in the current line if !return_only if l:begin_line != line(".") echomsg "[ATP:] closing math from line " . l:begin_line endif endif if \ math_mode == 'texMathZoneV' && ( l:line !~ '^\s*\\(\s*$' || line(".") == l:begin_line ) || \ math_mode == 'texMathZoneW' && ( l:line !~ '^\s*\\\[\s*$' ) || \ math_mode == 'texMathZoneX' && ( l:line !~ '^\s*\$\s*$' || line(".") == l:begin_line ) || \ math_mode == 'texMathZoneY' && ( l:line !~ '^\s*\$\{2,2}\s*$' ) if g:atp_debugCloseLastEnvironment call atplib#Log('CloseLastEnvironment.log', 'inline math') endif if math_mode == "texMathZoneW" if !return_only if l:com == 'a' if getline(l:begin_line) =~ '^\s*\\\[\s*$' call append(line("."),atplib#complete#CopyIndentation(getline(l:begin_line)).'\]') else call setline(line("."), strpart(l:cline,0,getpos(".")[2]) . '\]'. strpart(l:cline,getpos(".")[2])) endif else if getline(l:begin_line) =~ '^\s*\\\[\s*$' call append(line("."),atplib#complete#CopyIndentation(getline(l:begin_line)).'\]') else call setline(line("."), strpart(l:cline,0,getpos(".")[2]-1) . '\]'. strpart(l:cline,getpos(".")[2]-1)) " TODO: This could be optional: (but the option rather " should be an argument of this function rather than " here! endif let l:pos=getpos(".") let l:pos[2]+=2 keepjumps call setpos(("."),l:pos) let b:cle_return="texMathZoneW" endif else let g:time_CloseLastEnvironment = reltimestr(reltime(time)) return '\]' endif elseif math_mode == "texMathZoneV" if !return_only if l:com == 'a' call setline(line("."), strpart(l:cline,0,getpos(".")[2]) . '\)'. strpart(l:cline,getpos(".")[2])) else call setline(line("."), strpart(l:cline,0,getpos(".")[2]-1) . '\)'. strpart(l:cline,getpos(".")[2]-1)) call cursor(line("."),col(".")+2) let b:cle_return="V" endif else let g:time_CloseLastEnvironment = reltimestr(reltime(time)) return '\)' endif elseif math_mode == "texMathZoneX" if !return_only call setline(line("."), strpart(l:cline,0,getpos(".")[2]-1) . '$'. strpart(l:cline,getpos(".")[2]-1)) call cursor(line("."),col(".")+1) else let g:time_CloseLastEnvironment = reltimestr(reltime(time)) return "$" endif elseif math_mode == "texMathZoneY" if !return_only call setline(line("."), strpart(l:cline,0,getpos(".")[2]-1) . '$$'. strpart(l:cline,getpos(".")[2]-1)) call cursor(line("."),col(".")+2) else let g:time_CloseLastEnvironment = reltimestr(reltime(time)) return '$$' endif endif " }}}3 "{{{3 Close math in a new line, preserv the indentation. else let l:eindent=atplib#complete#CopyIndentation(l:line) if math_mode == 'texMathZoneW' if !return_only let l:iline=line(".") " if the current line is empty append before it. if getline(".") =~ '^\s*$' && l:iline > 1 let l:iline-=1 endif call append(l:iline, l:eindent . '\]') echomsg "[ATP:] \[ closed in line " . l:iline else let g:time_CloseLastEnvironment = reltimestr(reltime(time)) return '\]' endif " let b:cle_return=2 . " dispalyed math " . l:iline . " indent " . len(l:eindent) " DEBUG elseif math_mode == 'texMathZoneV' if !return_only let l:iline=line(".") " if the current line is empty append before it. if getline(".") =~ '^\s*$' && l:iline > 1 let l:iline-=1 endif call append(l:iline, l:eindent . '\)') echomsg "[ATP:] \( closed in line " . l:iline else let g:time_CloseLastEnvironment = reltimestr(reltime(time)) return '\)' endif " let b:cle_return=2 . " inline math " . l:iline . " indent " .len(l:eindent) " DEBUG elseif math_mode == 'texMathZoneX' if !return_only let l:iline=line(".") " if the current line is empty append before it. if getline(".") =~ '^\s*$' && l:iline > 1 let l:iline-=1 endif let sindent=atplib#complete#CopyIndentation(getline(search('\$', 'bnW'))) call append(l:iline, sindent . '$') echomsg "[ATP:] $ closed in line " . l:iline else let g:time_CloseLastEnvironment = reltimestr(reltime(time)) return '$' endif elseif math_mode == 'texMathZoneY' if !return_only let l:iline=line(".") " if the current line is empty append before it. if getline(".") =~ '^\s*$' && l:iline > 1 let l:iline-=1 endif let sindent=atplib#complete#CopyIndentation(getline(search('\$\$', 'bnW'))) call append(l:iline, sindent . '$$') echomsg "[ATP:] $ closed in line " . l:iline else let g:time_CloseLastEnvironment = reltimestr(reltime(time)) return '$$' endif endif endif "}}3 endif if g:atp_debugCloseLastEnvironment silent echo "return G" redir END endif "}}}2 let g:time_CloseLastEnvironment = reltimestr(reltime(time)) return '' endfunction " imap :call atplib#CloseLastEnvironment() " }}}1 " {{{1 atplib#complete#CheckBracket " Returns a list [ l:open_line, l:open_col, l:open_bracket ] " l:open_col != 0 if any of brackets (in values(g:atp_bracket_dict) ) is " opened and not closed. l:open_bracket is the most recent such bracket " ([ l:open_line, l:open_col ] are its coordinates). " " a:bracket_dict is a dictionary of brackets to use: " { open_bracket : close_bracket } fun! atplib#complete#CheckBracket(bracket_dict) "{{{2 if has("python") return atplib#complete#CheckBracket_py(a:bracket_dict) else return atplib#complete#CheckBracket_vim(a:bracket_dict) endif endfun fun! atplib#complete#CheckBracket_py(bracket_dict) "{{{2 let time = reltime() let limit_line = max([1,(line(".")-g:atp_completion_limits[4])]) let pos = getpos(".") let begin_line = limit_line let end_line = min([line('$'), line(".")+g:atp_completion_limits[4]]) call cursor(pos[1:2]) let e_pos = [] if !has("python") echoh ErrorMsg echom "[ATP:] compile vim with python support for closing brackets" echohl Normal return [0, 0, ''] endif python << EOF import vim import atplib.check_bracket encoding = vim.eval('&enc') bracket_dict = {} for (key, val) in vim.eval("g:atp_bracket_dict").items(): bracket_dict[key.decode(encoding)] = val.decode(encoding) begin_line = int(vim.eval("begin_line")) end_line = int(vim.eval("end_line")) buf = vim.current.buffer text = ('\n'.join(buf[begin_line-1:end_line])).decode(encoding) bpos = map(lambda i: int(i), vim.eval('getpos(".")')[1:3]) r_idx = (bpos[0]-begin_line, bpos[1]-1) # r_idx line and column starts from 0 e_idx = atplib.check_bracket.check_bracket(text, r_idx[0], r_idx[1], bracket_dict) if hasattr(vim, 'bindeval'): e_pos = vim.bindeval("e_pos") else: e_pos = [] if (e_idx[0], e_idx[1]) != (-1, -1): e_pos.extend([e_idx[0]+begin_line, e_idx[1]+1, e_idx[2]]) else: e_pos.extend([0,0, e_idx[2]]) if not hasattr(vim, 'bindeval'): import json vim.command("let e_pos = %s" % json.dumps(e_pos)) EOF let g:time_CheckBracket = reltimestr(reltime(time)) let [ s:open_line, s:open_col, s:opening_bracket ] = e_pos if getline(e_pos[0]) =~ '\\begin\s*{\s*document\s*}' return [0, 0, ''] else return e_pos endif endfun fun! atplib#complete#CheckBracket_vim(bracket_dict) "{{{2 let time = reltime() let limit_line = max([1,(line(".")-g:atp_completion_limits[4])]) let pos = getpos(".") if pos[2] == 1 let check_pos = [0, pos[1], len(getline(line(".")-1)), 0] else let check_pos = copy(pos) let check_pos[2] -= 1 endif call search('\S', 'bW') if !atplib#IsInMath() let begin_line = max([search('\%(\\part\|\\chapter\|\\section\|\\subsection\|\\par\>\|^\s*$\|\\]\|\\end{\s*\%(equation\|align\|alignat\|flalign\|gather\|multline\)\*\=\s*}\)', 'bnW'), limit_line]) let end_line = min([search('\%(\\part\|\\chapter\|\\section\|\\subsection\|\\par\>\|^\s*$\|\\[\|\\begin{\s*\%(equation\|align\|alignat\|flalign\|gather\|multline\)\*\=\s*}\)', 'nW'), min([line('$'), line(".")+g:atp_completion_limits[4]])]) else let begin_line = max([search('\%(\\begin\s*{\s*\%(equation\|align\|alignat\|flalign\|gather\|multline\)\*\=\s*}\|\\(\|\$\$\|\\[\|\\par\>\|^\s*$\)', 'bnW'), limit_line]) let end_line = min([search('\%(\\end\s*{\s*\%(equation\|align\|alignat\|flalign\|gather\|multline\)\*\=\s*}\|\\)\|\$\$\|\\]\|\\par\>\|^\s*$\)', 'nW'), min([line('$'), line(".")+g:atp_completion_limits[4]])]) if end_line == begin_line let end_line += 1 endif endif call cursor(pos[1:2]) let length = end_line-begin_line if g:atp_debugCheckBracket let g:begin_line = begin_line let g:end_line = end_line let g:limit_line = limit_line let g:length = length endif let pos_saved = getpos(".") " Bracket sizes: let ket_pattern = '\%(' . join(values(filter(copy(g:atp_sizes_of_brackets), "v:val != '\\'")), '\|') . '\)' " But maybe we shouldn't check if the bracket is closed sometimes one can " want to close closed bracket and delete the old one. let check_list = [] if g:atp_debugCheckBracket call atplib#Log("CheckBracket.log","", "init") let g:check_list = check_list endif " change the position! and then: " check the flag 'r' in searchpair!!! "Note: this can be much faster to first to check if the line is matching " \({\|...\)[^}...]*, etc., but this would not " break which bracket to close. let i=0 let bracket_list= keys(a:bracket_dict) for ket in bracket_list let pos = deepcopy(pos_saved) let pos[2] -=1 let time_{i} = reltime() if ket != '{' && ket != '(' && ket != '[' if search('\\\@= 2 echomsg escape(ket,'\[]') . " pair_".i."=".string(pair_{i}) . " limit_line=" . limit_line endif if g:atp_debugCheckBracket >= 1 call atplib#Log("CheckBracket.log", ket." time_A_".i."=".string(g:time_A_{i})) call atplib#Log("CheckBracket.log", ket." pair_".i."=".string(pair_{i})) endif let pos[1] = pair_{i}[0] let pos[2] = pair_{i}[1] let no_backslash = ( i == 0 || i == 2 ? '\\\@= 1 call atplib#Log("CheckBracket.log", ket." check_".i."=".string(check_{i})) let g:check_{i} = check_{i} let g:arg_{i}=[escape(ket,'\[]'), '\%('.escape(a:bracket_dict[ket],'\[]').'\|\\\.\)', begin_line, 1, 2*g:atp_completion_limits[4],2] endif " check_dot_{i} is 1 if the bracket is closed with a dot (\right.) . " let check_dot_{i} = atplib#complete#CheckClosed('\\\@= 1 call atplib#Log("CheckBracket.log", ket." check_dot_".i."=".string(check_{i})) endif if g:atp_debugCheckBracket >= 2 echomsg escape(ket,'\[]') . " check_".i."=".string(check_{i}) . " check_dot_".i."=".string(check_dot_{i}) endif let check_{i} = min([check_{i}, check_dot_{i}]) call add(check_list, [ pair_{i}[0], ((check_{i})*pair_{i}[1]), i ] ) keepjumps call setpos(".",pos_saved) let g:time_B_{i} = reltimestr(reltime(time_{i})) call atplib#Log("CheckBracket.log", ket." time_B_".i."=".string(g:time_B_{i})) let i+=1 endfor " let g:time_CheckBracket_A=reltimestr(reltime(time)) keepjumps call setpos(".", pos_saved) " Find opening line and column numbers call sort(check_list, "atplib#CompareCoordinates") let g:check_list = check_list let [ open_line, open_col, open_bracket_nr ] = check_list[0] let [ s:open_line, s:open_col, s:opening_bracket ] = [ open_line, open_col, bracket_list[open_bracket_nr] ] if g:atp_debugCheckBracket let [ g:open_lineCB, g:open_colCB, g:opening_bracketCB ] = [ open_line, open_col, bracket_list[open_bracket_nr] ] call atplib#Log("CheckBracket.log", "return:") call atplib#Log("CheckBracket.log", "open_line=".open_line) call atplib#Log("CheckBracket.log", "open_col=".open_col) call atplib#Log("CheckBracket.log", "opening_bracketCB=".g:opening_bracketCB) endif let g:time_CheckBracket=reltimestr(reltime(time)) " let g:time=g:time+str2float(substitute(g:time_CheckBracket, '\.', ',', '')) return [ open_line, open_col, bracket_list[open_bracket_nr] ] endf " }}}1 " {{{1 atplib#complete#CloseLastBracket " " The second function closes the bracket if it was not closed. " (as returned by atplib#complete#CheckBracket or [ s:open_line, s:open_col, s:opening_bracket ]) " It is not used to close \(:\) and \[:\] as atplib#complete#CloseLastEnvironment has a better " way of doing that (preserving indentation) " a:bracket_dict is a dictionary of brackets to use: " { open_bracket : close_bracket } " a:1 = 1 just return the bracket " a:2 = 0 (default), 1 when used in atplib#complete#TabCompletion " then s:open_line, s:open_col and s:opening_bracket are " used to avoid running twice atplib#complete#CheckBracket(): " once in atplib#complete#TabCompletion and secondly in CloseLastBracket " function. function! atplib#complete#CloseLastBracket(bracket_dict, ...) let time = reltime() let only_return = ( a:0 >= 1 ? a:1 : 0 ) let tab_completion = ( a:0 >= 2 ? a:2 : 0 ) " {{{2 preambule let pattern = "" let size_patterns = [] for size in keys(g:atp_sizes_of_brackets) call add(size_patterns,escape(size,'\')) endfor let pattern_b = '\C\%('.join(size_patterns,'\|').'\)' let pattern_o = '\%('.join(map(keys(a:bracket_dict),'escape(v:val,"\\[]")'),'\|').'\)' if g:atp_debugCloseLastBracket call atplib#Log("CloseLastBracket.log","","init") let g:pattern_b = pattern_b let g:pattern_o = pattern_o call atplib#Log("CloseLastBracket.log", "pattern_b=".pattern_b) call atplib#Log("CloseLastBracket.log", "pattern_o=".pattern_o) endif let limit_line = max([1,(line(".")-g:atp_completion_limits[1])]) let pos_saved = getpos(".") " But maybe we shouldn't check if the bracket is closed sometimes one can " want to close closed bracket and delete the old one. call cursor(line("."), col(".")-1) let [ open_line, open_col, opening_bracket ] = ( tab_completion ? \ deepcopy([ s:open_line, s:open_col, s:opening_bracket ]) : atplib#complete#CheckBracket(a:bracket_dict) ) call cursor(line("."), pos_saved[2]) let g:time_CloseLastBracket_beforeEnv = reltimestr(reltime(time)) " Check and Close Environment: for env_name in g:atp_closebracket_checkenv " To Do: this should check for the most recent opened environment let limit_line = exists("open_line") ? open_line : search('\\\@=2 && a:2 != [] ? a:2 : atplib#complete#CheckBracket(a:bracket_dict) ) if begParen[2] == '\begin' && begParen[1] && (!atplib#complete#CheckSyntaxGroups(['texMathZoneX', 'texMathZoneY', 'texMathZoneV', 'texMathZoneW'])) call atplib#complete#CloseLastEnvironment(a:append, 'environment', matchstr(getline(begParen[0]), '.*\\begin{\s*\zs[^}]*\ze\s*}'), [begParen[0], begParen[1]-6]) return '' endif let g:time_GetBrackets_A=reltimestr(reltime(time)) if !has("python") call cursor(pos[1], pos[2]) if begParen[1] != 0 || atplib#complete#CheckSyntaxGroups(['texMathZoneX', 'texMathZoneY', 'texMathZoneV', 'texMathZoneW']) || ( a:0 >= 1 && a:1 ) if atplib#complete#CheckSyntaxGroups(['texMathZoneV']) let pattern = '\\\@ or (if g:atp_no_tab_map=1) " expert_mode = 0 (off) gives more matches but in some cases better ones, the " string has to match somewhare and is case in " sensitive, for example: " \arrow will show all the arrows definded in tex, " in expert mode there would be no match (as there is no " command in tex which begins with \arrow). " or (if g:atp_no_tab_map=1) " " Completion Modes: (this is not a complete list any more, see the " documentation of ATP) " documentclass (\documentclass) " labels (\ref,\eqref) " packages (\usepackage) " commands " environments (\begin,\(:\),\[:\]) " brackets ((:),[:],{:}) preserves the size operators! " Always: check first brackets then environments. Bracket " funnction can call function which closes environemnts but not " vice versa. " bibitems (\cite\|\citep\|citet) " bibfiles (\bibliography) " bibstyle (\bibliographystyle) " end (close \begin{env} with \end{env}) " font encoding " font family " font series " font shape " "ToDo: the completion should be only done if the completed text is different "from what it is. But it might be as it is, there are reasons to keep this. " try " Main tab completion function function! atplib#complete#TabCompletion(expert_mode,...) if g:atp_debugTabCompletion call atplib#Log("TabCompletion.log", "", "init") endif let time=reltime() let atp_MainFile = atplib#FullPath(b:atp_MainFile) " {{{2 Match the completed word let normal_mode=0 if a:0 >= 1 let normal_mode=a:1 endif " this specifies the default argument for atplib#complete#CloseLastEnvironment() " in some cases it is better to append after than before. let append='i' " Define string parts used in various completitons let pos = getpos(".") let pos_saved = deepcopy(pos) let line = join(getbufline("%",pos[1])) let nchar = strpart(line,pos[2]-1,1) " let rest = strpart(line,pos[2]-1) let l = strpart(line,0,pos[2]-1) let n = strridx(l,'{') let m = strridx(l,',') let o = strridx(l,'\') let s = strridx(l,' ') let p = strridx(l,'[') let r = strridx(l,'=') let c = match(l, '\\cite\>\(.*\\cite\>\)\@!') let a = len(l) - stridx(join(reverse(split(l, '\zs')), ''), "=") let nr=max([n,m,o,s,p]) let color_nr=max([nr, r]) " this matches for =... let abegin = strpart(l, a-1) " this matches for \... let begin = strpart(l,nr+1) let cmd_val_begin = strpart(l,max([nr+1,r+1])) let color_begin = strpart(l,color_nr+1) let cbegin = strpart(l,nr) " and this for '\<\w*$' (beginning of last started word) -- used in " tikzpicture completion method let tbegin = matchstr(l,'\zs\<\w*$') " start with last '\' let obegin = strpart(l,o) " start with last = let ebegin = strpart(l,max([r,m,n])+1) " what we are trying to complete: usepackage, environment. let pline = strpart(l, 0, nr) " \cite[Theorem~1]{Abcd -> \cite[Theorem~] let ppline = strpart(l, c) " \cite[Theorem~1]{Abcd -> \cite[Theorem~1]{ let limit_line=max([1,(pos[1]-g:atp_completion_limits[1])]) if g:atp_debugTabCompletion let g:nchar = nchar call atplib#Log("TabCompletion.log", "nchar=".nchar) let g:l = l call atplib#Log("TabCompletion.log", "l=".l) let g:n = n call atplib#Log("TabCompletion.log", "n=".n) let g:o = o call atplib#Log("TabCompletion.log", "o=".o) let g:s = s call atplib#Log("TabCompletion.log", "s=".s) let g:p = p call atplib#Log("TabCompletion.log", "p=".p) let g:a = a call atplib#Log("TabCompletion.log", "a=".a) let g:nr = nr call atplib#Log("TabCompletion.log", "nr=".nr) let g:line = line call atplib#Log("TabCompletion.log", "line=".line) let g:abegin = abegin call atplib#Log("TabCompletion.log", "abegin=".abegin) let g:cmd_val_begin = cmd_val_begin call atplib#Log("TabCompletion.log", "cmd_val_begin=".cmd_val_begin) let g:tbegin = tbegin call atplib#Log("TabCompletion.log", "tbegin=".tbegin) let g:cbegin = cbegin call atplib#Log("TabCompletion.log", "cbegin=".cbegin) let g:obegin = obegin call atplib#Log("TabCompletion.log", "obegin=".obegin) let g:begin = begin call atplib#Log("TabCompletion.log", "begin=".begin) let g:ebegin = ebegin call atplib#Log("TabCompletion.log", "ebegin=".ebegin) let g:pline = pline call atplib#Log("TabCompletion.log", "pline=".pline) let g:ppline = ppline call atplib#Log("TabCompletion.log", "ppline=".ppline) let g:color_begin = color_begin call atplib#Log("TabCompletion.log", "color_begin=".color_begin) let g:limit_line= limit_line call atplib#Log("TabCompletion.log", "limit_line=".limit_line) endif " {{{2 SET COMPLETION METHOD " {{{3 --------- command if o > n && o > s && \ pline !~ '\%(input\s*{[^}]*$\|include\%(only\)\=\s*{[^}]*$\|[^\\]\\\\[^\\]$\)' && \ pline !~ '\\\@.*\|\\\%(re\)\?newcommand\>.*\|%.*\)\@ search('[^%]*\\end{tikzpicture}','bnW') || \ !atplib#CompareCoordinates(searchpos('[^%]*\zs\\tikz{','bnw'),searchpos('}','bnw')) ) "{{{4 ----------- tikzpicture colors if begin =~ '^color=' " This is for tikz picture color completion. let completion_method='tikzpicture colors' let b:comp_method='tikzpicture colors' if g:atp_debugTabCompletion call atplib#Log("TabCompletion.log", "b:comp_method=".b:comp_method) endif "{{{4 ----------- tikzpicture keywords elseif l =~ '\%(\s\|\[\|{\|}\|,\|\.\|=\|:\)' . tbegin . '$' && \ !a:expert_mode let b:comp_method='tikzpicture keywords' if g:atp_debugTabCompletion call atplib#Log("TabCompletion.log", "b:comp_method=".b:comp_method) endif let completion_method="tikzpicture keywords" "{{{4 ----------- brackets else let begParen = atplib#complete#CheckBracket(g:atp_bracket_dict) let g:begParen = begParen if begParen[2] != '\begin' && ( begParen[1] != 0 || atplib#complete#CheckSyntaxGroups(['texMathZoneX', 'texMathZoneY']) && \ (!normal_mode && index(g:atp_completion_active_modes, 'brackets') != -1 ) || \ (normal_mode && index(g:atp_completion_active_modes_normal_mode, 'brackets') != -1 ) ) let b:comp_method='brackets tikzpicture' let completion_method = 'brackets' let bracket=atplib#complete#GetBracket(append, g:atp_bracket_dict, 0, begParen) let g:time_TabCompletion=reltimestr(reltime(time)) let move = ( !a:expert_mode ? join(map(range(len(bracket)), '"\"'), '') : '' ) return bracket.move "{{{4 ----------- close environments elseif (!normal_mode && index(g:atp_completion_active_modes, 'close environments') != '-1' ) || \ (normal_mode && index(g:atp_completion_active_modes_normal_mode, 'close environments') != '-1' ) let completion_method='close_env' " DEBUG: let b:comp_method='close_env tikzpicture' if g:atp_debugTabCompletion call atplib#Log("TabCompletion.log", "b:comp_method=".b:comp_method) endif else return '' endif endif "{{{3 --------- package options values elseif l =~ '\\\%(usepackage\|RequirePackage\)\[[^\]]*=\%([^\],]*\|{\([^}]\+,\)\?[^}]*\)$' && \ !( l =~ '\\\%(usepackage\|RequirePackage\)\[[^\]]*=\%(.*\]\|{.*}\),$' ) && \ !normal_mode && \ index(g:atp_completion_active_modes, 'package options values') != -1 let completion_method='package options values' let b:comp_method=completion_method "{{{3 --------- package options elseif l =~ '\\\%(usepackage\|RequirePackage\)\[[^\]]*$' && !normal_mode && \ index(g:atp_completion_active_modes, 'package options') != -1 let completion_method='package options' let b:comp_method=completion_method "{{{3 --------- package elseif pline =~ '\\\%(usepackage\|RequirePackage\)\%([.*]\)\?\s*' && !normal_mode && \ index(g:atp_completion_active_modes, 'package names') != -1 let completion_method='package' " DEBUG: let b:comp_method='package' if g:atp_debugTabCompletion call atplib#Log("TabCompletion.log", "b:comp_method=".b:comp_method) endif "{{{3 --------- tikz libraries elseif pline =~ '\\usetikzlibrary\%([.*]\)\?\s*' && !normal_mode && \ index(g:atp_completion_active_modes, 'tikz libraries') != -1 let completion_method='tikz libraries' " DEBUG: let b:comp_method='tikz libraries' if g:atp_debugTabCompletion call atplib#Log("TabCompletion.log", "b:comp_method=".b:comp_method) endif "{{{3 --------- inputfiles elseif (l =~ '\\input\%([^{}]*\|\s*{[^}]*\)$'|| \ l =~ '\\include\s*{[^}]*$') && !normal_mode && \ index(g:atp_completion_active_modes, 'input files') != -1 if begin =~ 'input' let begin=substitute(begin,'.*\%(input\|include\%(only\)\?\)\s\?','','') endif let completion_method='inputfiles' " DEBUG: let b:comp_method='inputfiles' if g:atp_debugTabCompletion call atplib#Log("TabCompletion.log", "b:comp_method=".b:comp_method) endif "{{{3 --------- includegraphics elseif (l =~ '\\includegraphics\s*\(\[[^\]]*\]\s*\)\?{[^}]*$') && \ index(g:atp_completion_active_modes, 'includegraphics') != -1 let completion_method='includegraphics' " DEBUG: let b:comp_method='includegraphics' if g:atp_debugTabCompletion call atplib#Log("TabCompletion.log", "b:comp_method=".b:comp_method) endif "{{{3 --------- bibfiles elseif pline =~ '\\\%(bibliography\%(style\)\@!\|addbibresource\|addglobalbib\)' && !normal_mode && \ index(g:atp_completion_active_modes, 'bibfiles') != -1 let completion_method='bibfiles' " DEBUG: let b:comp_method='bibfiles' if g:atp_debugTabCompletion call atplib#Log("TabCompletion.log", "b:comp_method=".b:comp_method) endif "{{{3 --------- bibstyles elseif pline =~ '\\bibliographystyle' && !normal_mode && \ index(g:atp_completion_active_modes, 'bibstyles') != -1 let completion_method='bibstyles' let b:comp_method='bibstyles' if g:atp_debugTabCompletion call atplib#Log("TabCompletion.log", "b:comp_method=".b:comp_method) endif "{{{3 --------- todo & missingfigure options elseif obegin =~ '\\todo\[[^\]]*$' && \ ( index(g:atp_completion_active_modes, 'todonotes') != -1 ) let completion_method='todo options' let b:comp_method='todo options' if g:atp_debugTabCompletion call atplib#Log("TabCompletion.log", "b:comp_method=".b:comp_method) endif elseif obegin =~ '\\missingfigure\[[^\]]*$' && \ ( index(g:atp_completion_active_modes, 'todonotes') != -1 ) let completion_method='missingfigure options' let b:comp_method='missingfigure options' if g:atp_debugTabCompletion call atplib#Log("TabCompletion.log", "b:comp_method=".b:comp_method) endif "{{{3 --------- documentclass options elseif l =~ '\\documentclass\s*\[[^\]]*$' && !normal_mode && \ index(g:atp_completion_active_modes, 'documentclass options') != -1 let completion_method='documentclass options' let b:comp_method=completion_method if g:atp_debugTabCompletion call atplib#Log("TabCompletion.log", "b:comp_method=".b:comp_method) endif "{{{3 --------- documentclass elseif pline =~ '\\documentclass\>' && !normal_mode && \ index(g:atp_completion_active_modes, 'documentclass') != -1 let completion_method='documentclass' let b:comp_method='documentclass' if g:atp_debugTabCompletion call atplib#Log("TabCompletion.log", "b:comp_method=".b:comp_method) endif "{{{3 --------- font family elseif l =~ '\%(\\renewcommand\s*{\s*\\\%(rm\|sf\|bf\|tt\|md\|it\|sl\|sc\|up\)default\s*}\s*{\|\\usefont\s*{[^}]*}{\|\\DeclareFixedFont\s*{[^}]*}{[^}]*}{\|\\fontfamily\s*{\)[^}]*$' && !normal_mode && \ index(g:atp_completion_active_modes, 'font family') != -1 let completion_method='font family' let b:comp_method='font family' if g:atp_debugTabCompletion call atplib#Log("TabCompletion.log", "b:comp_method=".b:comp_method) endif "{{{3 --------- font series elseif l =~ '\%(\\usefont{[^}]*}{[^}]*}{\|\\DeclareFixedFont{[^}]*}{[^}]*}{[^}]*}{\|\\fontseries{\)[^}]*$' && \ !normal_mode && \ index(g:atp_completion_active_modes, 'font series') != -1 let completion_method='font series' let b:comp_method='font series' if g:atp_debugTabCompletion call atplib#Log("TabCompletion.log", "b:comp_method=".b:comp_method) endif "{{{3 --------- font shape elseif l =~ '\%(\\usefont{[^}]*}{[^}]*}{[^}]*}{\|\\DeclareFixedFont{[^}]*}{[^}]*}{[^}]*}{[^}]*}{\|\\fontshape{\)[^}]*$' \ && !normal_mode && \ index(g:atp_completion_active_modes, 'font shape') != -1 let completion_method='font shape' let b:comp_method='font shape' if g:atp_debugTabCompletion call atplib#Log("TabCompletion.log", "b:comp_method=".b:comp_method) endif "{{{3 --------- font encoding elseif l =~ '\%(\\usefont{\|\\DeclareFixedFont{[^}]*}{\|\\fontencoding{\)[^}]*$' && !normal_mode && \ index(g:atp_completion_active_modes, 'font encoding') != -1 let completion_method='font encoding' let b:comp_method='font encoding' if g:atp_debugTabCompletion call atplib#Log("TabCompletion.log", "b:comp_method=".b:comp_method) endif "{{{3 --------- command values of values elseif l =~ '\\\w\+{\%([^}]*,\)\?[^,}=]*=[^,}]*$' && !normal_mode let completion_method='command values of values' let b:comp_method=completion_method if g:atp_debugTabCompletion call atplib#Log("TabCompletion.log", "b:comp_method=".b:comp_method) endif "{{{3 --------- command values " this is at the end because there are many command completions done " before - they would not work if this would be on the top. elseif (l =~ '\%(\\\w\+\%(\[\%([^\]]\|\[[^\]]*\]\)*\]\)\?\%({\%([^}]\|{\%([^}]\|{[^}]*}\)*}\)*}\)\?{\%([^}]\|{\%([^}]\|{[^}]*}\)*}\)*$\|\\renewcommand{[^}]*}{[^}]*$\)' && !normal_mode) && \ index(g:atp_completion_active_modes, 'environment names') != -1 let completion_method="command values" " DEBUG: let b:comp_method=completion_method if g:atp_debugTabCompletion call atplib#Log("TabCompletion.log", "b:comp_method=".b:comp_method) endif "{{{3 --------- brackets, algorithmic, abbreviations, close environments else let begParen = atplib#complete#CheckBracket(g:atp_bracket_dict) "{{{4 --------- abbreviations if l =~ '=[a-zA-Z]\+\*\=$' && \ index(g:atp_completion_active_modes, 'abbreviations') != -1 && \ !atplib#IsInMath() let completion_method='abbreviations' let b:comp_method='abbreviations' if g:atp_debugTabCompletion call atplib#Log("TabCompletion.log", "b:comp_method=".b:comp_method) endif "{{{4 --------- brackets elseif begParen[2] != '\begin' && ( begParen[1] != 0 || atplib#complete#CheckSyntaxGroups(['texMathZoneX', 'texMathZoneY']) && \ (!normal_mode && index(g:atp_completion_active_modes, 'brackets') != -1 ) || \ (normal_mode && index(g:atp_completion_active_modes_normal_mode, 'brackets') != -1 ) ) let completion_method = 'brackets' let b:comp_method='brackets' let bracket=atplib#complete#GetBracket(append, g:atp_bracket_dict, 0, begParen) let g:time_TabCompletion=reltimestr(reltime(time)) let move = ( !a:expert_mode ? join(map(range(len(bracket)), '"\"'), '') : '' ) return bracket.move "{{{4 --------- close environments elseif (!normal_mode && index(g:atp_completion_active_modes, 'close environments') != '-1' ) || \ (normal_mode && index(g:atp_completion_active_modes_normal_mode, 'close environments') != '-1' ) let completion_method='close_env' " DEBUG: let b:comp_method='close_env X' if g:atp_debugTabCompletion call atplib#Log("TabCompletion.log", "b:comp_method=".b:comp_method) endif "{{{4 --------- algorithmic elseif atplib#complete#CheckBracket(g:atp_algorithmic_dict)[0] != 0 && \ atplib#complete#CheckSyntaxGroups(['texMathZoneALG']) && \ ((!normal_mode && index(g:atp_completion_active_modes, 'algorithmic' ) != -1 ) || \ (normal_mode && index(g:atp_completion_active_modes_normal_mode, 'algorithmic') != -1 )) let b:comp_method='algorithmic' if g:atp_debugTabCompletion call atplib#Log("TabCompletion.log", "b:comp_method=".b:comp_method) endif call atplib#complete#CloseLastBracket(g:atp_algorithmic_dict, 0, 1) let g:time_TabCompletion=reltimestr(reltime(time)) return '' "}}}4 else let g:time_TabCompletion=reltimestr(reltime(time)) return '' endif let g:time_TabCompletion=reltimestr(reltime(time)) "}}}3 endif let b:completion_method = ( exists("completion_method") ? completion_method : 'completion_method does not exists' ) "}}}2 " {{{2 close environments if completion_method=='close_env' " Close one line math if !has("python") && (atplib#complete#CheckClosed_math('texMathZoneV') || \ atplib#complete#CheckClosed_math('texMathZoneW') || \ atplib#complete#CheckClosed_math('texMathZoneX') || \ b:atp_TexFlavor == 'plaintex' && atplib#complete#CheckClosed_math('texMathZoneY')) let b:tc_return = "close_env math" call atplib#complete#CloseLastEnvironment(append, 'math') " Close environments else let b:tc_return = "close_env environment" let stopline_forward = line(".") + g:atp_completion_limits[2] let stopline_backward = max([ 1, line(".") - g:atp_completion_limits[2]]) let line_nr=line(".") let pos_saved=getpos(".") while line_nr >= stopline_backward let [ line_nr, col_nr ] = searchpairpos('\\begin\s*{', '', '\\end\s*{', 'bW', 'strpart(getline("."), 0, col(".")-1) =~ "\\\\\\@= stopline_backward let env_name = matchstr(strpart(getline(line_nr), col_nr-1), '\\begin\s*{\zs[^}]*\ze}') if env_name =~# '^\s*document\s*$' break endif let line_forward = searchpair('\\begin\s*{'.env_name.'}', '', '\\end\s*{'.env_name.'}', \ 'nW', '', stopline_forward) if line_forward == 0 break endif else let line_nr = 0 break endif endwhile call cursor(pos_saved[1], pos_saved[2]) if line_nr " the env_name variable might have wrong value as it is " looking using '\\begin' and '\\end' this might be not enough, " however the function atplib#CloseLastEnv works perfectly and this " should be save: let g:time_TabCompletion=reltimestr(reltime(time)) if env_name !~# '^\s*document\s*$' call atplib#complete#CloseLastEnvironment(append, 'environment', '', [line_nr, 0]) return "" else return "" endif endif endif let g:time_TabCompletion=reltimestr(reltime(time)) return "" endif " {{{2 SET COMPLETION LIST " generate the completion names " {{{3 ------------ ENVIRONMENT NAMES if completion_method == 'environment_names' let end=strpart(line,pos[2]-1) keepjumps call setpos(".",[0,1,1,0]) let stop_line=search('\\begin\s*{document}','cnW') keepjumps call setpos(".",pos_saved) if end !~ '\s*}' let completion_list = [] " if atplib#search#DocumentClass(atplib#FullPath(b:atp_MainFile)) == 'beamer' " call extend(completion_list, g:atp_BeamerEnvironments) " endif call extend(completion_list,deepcopy(g:atp_Environments)) if g:atp_local_completion " Make a list of local envs and commands if !exists("s:atp_LocalEnvironments") LocalCommands let s:atp_LocalEnvironments=copy(b:atp_LocalEnvironments) elseif has("python") || has("python3") LocalCommands let s:atp_LocalEnvironments=copy(b:atp_LocalEnvironments) endif let completion_list=atplib#Extend(completion_list,s:atp_LocalEnvironments) endif let completion_list=atplib#Add(completion_list,'}') else let completion_list = [] " if atplib#search#DocumentClass(atplib#FullPath(b:atp_MainFile)) == 'beamer' " call extend(completion_list, g:atp_BeamerEnvironments) " endif call extend(completion_list,deepcopy(g:atp_Environments)) if g:atp_local_completion " Make a list of local envs and commands if !exists("s:atp_LocalEnvironments") LocalCommands let s:atp_LocalEnvironments=copy(b:atp_LocalEnvironments) elseif has("python") || has("python3") LocalCommands let s:atp_LocalEnvironments=copy(b:atp_LocalEnvironments) endif call atplib#Extend(completion_list,s:atp_LocalEnvironments) endif endif " TIKZ let in_tikz=searchpair('\\begin\s*{tikzpicture}','','\\end\s*{tikzpicture}','bnW',"", max([1,(line(".")-g:atp_completion_limits[2])])) || atplib#complete#CheckOpened('\\tikz{','}',line("."),g:atp_completion_limits[0]) if in_tikz if end !~ '\s*}' call extend(completion_list,atplib#Add(g:atp_tikz_environments,'}')) else call extend(completion_list,g:atp_tikz_environments) endif endif " AMSMATH if atplib#search#SearchPackage('amsmath', stop_line) || g:atp_amsmath != 0 || atplib#search#DocumentClass(atplib#FullPath(b:atp_MainFile)) =~ '^ams' if end !~ '\s*}' call extend(completion_list,atplib#Add(g:atp_amsmath_environments,'}'),0) else call extend(completion_list,g:atp_amsmath_environments,0) endif endif " MathTools " moved to packages/mathtools.vim " if atplib#search#SearchPackage('mathtools', stop_line) " if end !~ '\s*}' " call extend(completion_list,atplib#Add(g:atp_MathTools_environments,'}')) " else " call extend(completion_list,g:atp_MathTools_environments) " endif " endif " Packages for package in g:atp_packages if atplib#search#SearchPackage(package) && exists("g:atp_".package."_environments") if end !~ '\s*}' call extend(completion_list,atplib#Add({'g:atp_'.package.'_environments'},'}')) else call extend(completion_list,{'g:atp_'.package.'_environments'}) endif endif endfor " {{{3 ------------ ENVIRONMENT VALUES OF OPTIONS elseif completion_method == 'environment values of options' let env_name = matchstr(l, '.*\\begin{\s*\zs\w\+\ze\s*}') let [opt_name, opt_value] = matchlist(l, '\\begin\s*{[^}]*}\s*\[\%([^\]]*,\)\?\([^,\]]*\)=\([^\],]*\)$')[1:2] let completion_list=[] if a:expert_mode let filter_cond = 'v:val =~? "^".opt_value' else let filter_cond = 'v:val =~? opt_value' endif for package in g:atp_packages if exists("g:atp_".package."_environment_options_values") for env_key in keys(g:atp_{package}_environment_options_values) if env_name =~ env_key for opt_key in keys(g:atp_{package}_environment_options_values[env_key]) if opt_name =~ '^'.opt_key let obj = copy(g:atp_{package}_environment_options_values[env_key][opt_key]) if type(obj) == 3 let list = obj else let list = obj['matches'] endif call extend(completion_list, filter(list, filter_cond)) break " we can assume there is only one entry endif endfor endif endfor endif endfor " {{{3 ------------ ENVIRONMENT OPTIONS elseif completion_method == 'environment options' let env_name = matchstr(l, '.*\\begin{\s*\zs\w\+\ze\s*}') let completion_list=[] for package in g:atp_packages if exists("g:atp_".package."_environment_options") && \ (atplib#search#SearchPackage(package) || atplib#search#DocumentClass(atplib#FullPath(b:atp_MainFile)) == package) for key in keys({"g:atp_".package."_environment_options"}) if env_name =~ key call extend(completion_list, {"g:atp_".package."_environment_options"}[key]) endif endfor endif endfor "{{{3 ------------ PACKAGE OPTIONS VALUES elseif completion_method == 'package options values' let package = matchstr(line, '\\\%(usepackage\|RequirePackage\)\[.*{\zs[^}]*\ze}') let option = matchstr(l,'\zs\<\w\+\ze=[^=]*$') let completion_list=[] if exists("g:atp_".package."_options_values") for pat in keys({"g:atp_".package."_options_values"}) if (option =~ '^'.pat) let val={"g:atp_".package."_options_values"}[pat] if type(val) == 3 let completion_list={"g:atp_".package."_options_values"}[pat] elseif type(val) == 1 execute "let add=".val."()" call extend(completion_list, add) else let completion_list = [] endif break endif endfor else let g:time_TabCompletion=reltimestr(reltime(time)) if g:atp_debugTabCompletion call atplib#Log("TabCompletion.log", 'package options return') endif return "" endif "{{{3 ------------ PACKAGE OPTIONS elseif completion_method == 'package options' let package = matchstr(line, '\\\%(usepackage\|RequirePackage\).*{\zs[^}]*\ze}') let options = split(matchstr(line, '\\\%(usepackage\|RequirePackage\)\[\s*\zs[^\]{]*\ze\s*[\]{]'), '\s*,\s*') if has("python") || has("python3") let completion_list = get(get(g:atp_package_dict.ScanPackage(package.'.sty', ['options!']) ,package.'.sty',{}) , 'options', []) else let completion_list = [] endif if exists("g:atp_".package."_options") " Add options which are not already present: call extend(completion_list, filter(copy({"g:atp_".package."_options"}), 'index(completion_list, v:val) == -1')) endif " Note: if the completed phrase is in completion pool then we don't " want to remove it: let phrase = matchstr(l, '\\\%(usepackage\|RequirePackage\)\[\(.*,\)\?\zs.*') let g:phrase = phrase call filter(completion_list, 'index(options, v:val) == -1') "{{{3 ------------ PACKAGES elseif completion_method == 'package' if exists("g:atp_LatexPackages") let completion_list = copy(g:atp_LatexPackages) else echo "[ATP:] generating a list of packages (it might take a while) ... " if g:atp_debugTabCompletion let debugTabCompletion_LatexPackages_TimeStart=reltime() endif let g:atp_LatexPackages = atplib#search#KpsewhichGlobPath("tex", "", "*.sty") let completion_list = deepcopy(g:atp_LatexPackages) if g:atp_debugTabCompletion let g:debugTabCompletion_LatexPackages_Time=reltimestr(reltime(debugTabCompletion_LatexPackages_TimeStart)) call atplib#Log("TabCompletion.log", "LatexPackages Time: ".g:debugTabCompletion_LatexPackages_Time) endif redraw endif "{{{3 ------------ PAGESTYLE elseif completion_method == 'pagestyle' let completion_list=copy(g:atp_pagestyles) if atplib#search#SearchPackage('fancyhdr') call extend(completion_list, g:atp_fancyhdr_pagestyles) endif "{{{3 ------------ PAGENUMBERING elseif completion_method == 'pagenumbering' let completion_list=copy(g:atp_pagenumbering) " {{{3 ------------ TIKZ LIBRARIES elseif completion_method == 'tikz libraries' let completion_list=deepcopy(g:atp_tikz_libraries) " {{{3 ------------ TIKZ KEYWORDS elseif completion_method == 'tikzpicture keywords' let completion_list=[] " TODO: add support for all tikz libraries let tikz_libraries = atplib#search#GrepPackageList('\\use\%(tikz\|pgf\)library\s*{') call map(tikz_libraries, "substitute(v:val, '\\..*$', '', '')") for lib in tikz_libraries if exists("g:atp_tikz_library_".lib."_keywords") call extend(completion_list,g:atp_tikz_library_{lib}_keywords) endif endfor call extend(completion_list, deepcopy(g:atp_tikz_keywords)) " {{{3 ------------ TIKZ COMMANDS elseif completion_method == 'tikzpicture commands' let completion_list = [] " if tikz is declared and we are in tikz environment. let tikz_libraries = atplib#search#GrepPackageList('\\use\%(tikz\|pgf\)library\s*{') for lib in tikz_libraries if exists("g:atp_tikz_library_".lib."_commands") call extend(completion_list, g:atp_tikz_library_{lib}_commands) endif endfor " {{{3 ------------ TIKZ COLORS elseif completion_method == 'tikzpicture colors' let completion_list = copy(b:atp_LocalColors) " {{{3 ------------ COMMANDS elseif completion_method == 'command' "{{{4 let tbegin=strpart(l,o+1) let completion_list=[] " Find end of the preambule. if expand("%:p") == atp_MainFile " if the file is the main file let saved_pos=getpos(".") keepjumps call setpos(".", [0,1,1,0]) keepjumps let stop_line=search('\\begin\s*{document}','nW') keepjumps call setpos(".", saved_pos) else " if the file doesn't contain the preambule if &filetype == 'tex' let saved_loclist = getloclist(0) silent! execute '1lvimgrep /\\begin\s*{\s*document\s*}/j ' . fnameescape(atp_MainFile) let stop_line = get(get(getloclist(0), 0, {}), 'lnum', 0) call setloclist(0, saved_loclist) else let stop_line = 0 endif endif " Are we in the math mode? let math_is_opened = atplib#IsInMath() " -------------------- LOCAL commands {{{4 if g:atp_local_completion " make a list of local envs and commands: if !exists("b:atp_LocalCommands") " This saves the file. call LocalCommands(1, "", "") elseif has("python") || has("python3") " This will not save the file. call LocalCommands(0, "", "") endif call extend(completion_list, b:atp_LocalCommands) endif " {{{4 -------------------- MATH commands: amsmath, amssymb, mathtools, nicefrac, SIunits, math non expert mode. " if we are in math mode or if we do not check for it. if g:atp_no_math_command_completion != 1 && ( !g:atp_MathOpened || math_is_opened ) call extend(completion_list, g:atp_math_commands) " ----------------------- amsmath && amssymb {{{5 " if g:atp_amsmath is set or the document class is ams... if (g:atp_amsmath != 0 || atplib#search#DocumentClass(atplib#FullPath(b:atp_MainFile)) =~ '^ams') call extend(completion_list, g:atp_amsmath_commands) call extend(completion_list, g:atp_ams_negations) call extend(completion_list, g:atp_amsfonts) call extend(completion_list, g:atp_amsextra_commands) if a:expert_mode == 0 call extend(completion_list, g:atp_ams_negations_non_expert_mode) endif " else check if the packages are declared: else if atplib#search#SearchPackage('amsmath', stop_line) call extend(completion_list, g:atp_amsmath_commands,0) endif if atplib#search#SearchPackage('amssymb', stop_line) call extend(completion_list, g:atp_ams_negations) if a:expert_mode == 0 call extend(completion_list, g:atp_ams_negations_non_expert_mode) endif endif endif call extend(completion_list, g:atp_math_commands_PRE) " ----------------------- nicefrac {{{5 if atplib#search#SearchPackage('nicefrac', stop_line) call add(completion_list,"\\nicefrac{") endif " ----------------------- SIunits {{{5 if atplib#search#SearchPackage('SIunits', stop_line) && ( index(g:atp_completion_active_modes, 'SIunits') != -1 || index(g:atp_completion_active_modes, 'siunits') != -1 ) call extend(completion_list, g:atp_siuinits) endif for package in g:atp_packages if exists("g:atp_".package."_math_commands") call extend(completion_list, {"g:atp_".package."_math_commands"}) endif endfor " ----------------------- math non expert mode {{{5 if a:expert_mode == 0 call extend(completion_list, g:atp_math_commands_non_expert_mode) endif endif " {{{4 -------------------- BEAMER commands " if atplib#search#DocumentClass(atplib#FullPath(b:atp_MainFile)) == 'beamer' " call extend(completion_list, g:atp_BeamerCommands) " endif " {{{4 -------------------- TIKZ commands " if tikz is declared and we are in tikz environment. if atplib#search#SearchPackage('\(tikz\|pgf\)') let in_tikz=searchpair('\\begin\s*{tikzpicture}','','\\end\s*{tikzpicture}','bnW',"", max([1,(line(".")-g:atp_completion_limits[2])])) || atplib#complete#CheckOpened('\\tikz{','}',line("."),g:atp_completion_limits[0]) if in_tikz " find all tikz libraries at once: let tikz_libraries = atplib#search#GrepPackageList('\\use\%(tikz\|pgf\)library\s*{') " add every set of library commands: for lib in tikz_libraries if exists("g:atp_tikz_library_".lib."_commands") call extend(completion_list, g:atp_tikz_library_{lib}_commands) endif endfor " add common tikz commands: call extend(completion_list, g:atp_tikz_commands) " if in text mode add normal commands: if searchpair('\\\@ the pattern will not work and we do " not want env name. if env_name == pline let env_name='' endif if has_key(g:atp_shortname_dict,env_name) if g:atp_shortname_dict[env_name] != 'no_short_name' && g:atp_shortname_dict[env_name] != '' let short_env_name=g:atp_shortname_dict[env_name] let no_separator=0 else let short_env_name='' let no_separator=1 endif else let short_env_name='' let no_separator=1 endif " if index(g:atp_no_separator_list, env_name) != -1 " let no_separator = 1 " endif if g:atp_env_short_names == 1 if no_separator == 0 && g:atp_no_separator == 0 let short_env_name=short_env_name . g:atp_separator endif else let short_env_name='' endif call extend(completion_list, [ '\label{' . short_env_name ],0) " {{{3 ------------ COMMAND VALUES elseif completion_method == 'command values' if l !~ '\\renewcommand{[^}]*}{[^}]*$' " let command = matchstr(l, '.*\\\w\+\%(\[\%([^\]]\|\[[^\]]*\]\)*\]\)\?\%({\%([^}]\|{\%([^}]\|{[^}]*\)*}}\)*}\)*{\ze\%([^}]\|{\%([^}]\|{[^}]*}\)*}\)*$') let command = matchstr(l, '.*\\\w\+\%(\[\%([^\]]\|\[[^\]]*\]\)*\]\)\?\%({\%([^}]\|{\%([^}]\|{[^}]*\)*}}\)*}\)*{\ze\%([^}]\|{\%([^}]\|{[^}]*}\)*}\)*$') else let command = matchstr(l, '.*\\renewcommand{\s*\zs\\\?\w*\ze\s*}') endif let g:command = command let completion_list = [] let command_pat='\\\w\+[{\|\[]' for package in g:atp_packages let test = 0 if exists("g:atp_".package."_loading") for key in keys(g:atp_{package}_loading) let package_line_nr = atplib#search#SearchPackage(g:atp_{package}_loading[key]) if g:atp_{package}_loading[key] == "" || package_line_nr == 0 let test = package_line_nr else let package_line = getline(package_line_nr) let test = (package_line=~'\\\%(usepackage\|RequirePackage\)\[[^\]]*,\='.g:atp_{package}_loading[key].'[,\]]') endif if test break endif endfor endif if exists("g:atp_".package."_command_values") && \ ( \ atplib#search#SearchPackage(package) || test || \ atplib#search#DocumentClass(atplib#FullPath(b:atp_MainFile)) == package || package == "common" \ ) for key in keys({"g:atp_".package."_command_values"}) " uncomment this to debug in which package file there is a mistake. if command =~ key let command_pat = key let val={"g:atp_".package."_command_values"}[key] if g:atp_debugTabCompletion call atplib#Log("TabCompletion.log", 'command_pat='.command_pat." package=".package) call atplib#Log("TabCompletion.log", 'val='.string(val)) endif if type(val) == 3 call extend(completion_list, val) elseif type(val) == 1 && exists("*".val) execute "let add=".val."()" call extend(completion_list, add) else if g:atp_debugTabCompletion call atplib#Log("TabCompletion.log", "command values: wrong type error") endif endif endif endfor endif endfor " {{{3 ------------ COMMAND VALUES OF VALUES elseif completion_method == 'command values of values' let [ cmd_name, opt_name, opt_value ] = matchlist(l, '\(\\\w*\)\s*{\%([^}]*,\)\?\([^,}=]*\)=\([^,}]*\)$')[1:3] " let g:cmd_name = cmd_name " let g:opt_name = opt_name " let g:opt_value = opt_value let completion_list=[] if a:expert_mode let filter_cond = 'v:val =~? "^".opt_value' else let filter_cond = 'v:val =~? opt_value' endif let cvov_ignore_pattern = '' for package in g:atp_packages if exists("g:atp_".package."_command_values_dict") for cmd_key in keys(g:atp_{package}_command_values_dict) if cmd_name =~ cmd_key echomsg cmd_name for opt_key in keys(g:atp_{package}_command_values_dict[cmd_key]) echomsg opt_key if opt_name =~ '^'.opt_key echomsg opt_name if type(g:atp_{package}_command_values_dict[cmd_key][opt_key]) == 3 let matches = copy(g:atp_{package}_command_values_dict)[cmd_key][opt_key] else let matches = copy(g:atp_{package}_command_values_dict)[cmd_key][opt_key]['matches'] let cvov_ignore_pattern = get(g:atp_{package}_command_values_dict[cmd_key][opt_key], 'ignore_pattern', '') let match_l= matchlist(l, '\%(\\\w*\)\s*{\%([^}]*,\)\?\%([^,}=]*\)='.cvov_ignore_pattern.'\([^,}]*\)$') let opt_value = match_l[1] " let g:opt_value = opt_value if a:expert_mode let filter_cond = 'v:val =~? "^".opt_value' else let filter_cond = 'v:val =~? cvov_ignore_pattern_.opt_value' endif endif call extend(completion_list, filter(matches, filter_cond)) break " we can assume there is only one entry endif endfor endif endfor endif endfor " {{{3 ------------ ABBREVIATIONS elseif completion_method == 'abbreviations' let completion_list = sort(copy(b:atp_LocalEnvironments), "atplib#CompareStarAfter")+[ "document","description","letter","picture","list","minipage","titlepage","thebibliography","bibliography","center","flushright","flushleft","tikzpicture","frame","itemize","enumerate","quote","quotation","verse","abstract","verbatim","figure","array","table","tabular","equation","equation*","align","align*","alignat","alignat*","gather","gather*","multline","multline*","split","flalign","flalign*","corollary","theorem","proposition","lemma","definition","proof","remark","example","exercise","note","question","notation"] for package in g:atp_packages if exists("g:atp_".package."_environments") call extend(completion_list, {"g:atp_".package."_environments"}) endif endfor call map(completion_list, "g:atp_iabbrev_leader.v:val.g:atp_iabbrev_leader") " {{{3 ------------ LABELS /are done later/ elseif completion_method == 'labels' let completion_list = [] " {{{3 ------------ INPUTFILES elseif completion_method == 'inputfiles' let completion_list=[] call extend(completion_list, atplib#search#KpsewhichGlobPath('tex', expand(b:atp_OutDir) . ',' . g:atp_texinputs, '*.tex', ':t:r', '^\%(\/home\|\.\|.*users\)', '\%(^\\usr\|texlive\|miktex\|kpsewhich\|generic\)')) call sort(completion_list) " {{{3 ------------ TEX INCLUDEGRAPHICS elseif completion_method == 'includegraphics' " Search for \graphicspath but only in the preamble let matches=atplib#search#GrepPreambule('\\graphicspath') if len(matches) for match in matches let dirs = map(split(matchstr(match['text'], '\graphicspath\s*{\zs.*\ze}'), '}'), "substitute(v:val, '^\s*{', '', '')") call map(dirs, "substitute(v:val, '\/\/', '/**', 'g')") endfor else let dirs = [fnamemodify(atplib#FullPath(b:atp_MainFile), ":h")] endif let gr_dirs = join(dirs,',') let g:gr_dirs = gr_dirs if b:atp_TexCompiler == "latex" let gr = ["*.eps", "*.EPS"] else let gr = ["*.gif", "*jpeg", "*.jpg", "*.png", "*.pdf", "*.pdf_tex", "*.eps", \ "*.GIF", "*JPEG", "*.JPG", "*.PNG", "*.PDF", "*.PDF_TEX", "*.EPS"] endif let completion_list=[] if begin !~ '\.\(gif\|jpe\?g\|png\|pdf\|pdf_tex\|eps\)$' for ext in gr let completion_list+=split(globpath(gr_dirs, begin.ext), "\n") endfor else let completion_list+=split(globpath(gr_dirs, begin), "\n") endif call map(completion_list, "substitute(v:val, '^\s*\.\/', '', '')") " {{{3 ------------ BIBFILES elseif completion_method == 'bibfiles' let completion_list=[] call extend(completion_list, atplib#search#KpsewhichGlobPath('bib', expand(b:atp_OutDir) . ',' . g:atp_bibinputs, '*.bib', ':t:r', '^\%(\/home\|\.\|.*users\)', '\%(^\\usr\|texlive\|miktex\|kpsewhich\|generic\|miktex\)')) call sort(completion_list) " {{{3 ------------ BIBSTYLES elseif completion_method == 'bibstyles' let completion_list=atplib#search#KpsewhichGlobPath("bst", "", "*.bst") "{{{3 ------------ DOCUMENTCLASS OPTIONS elseif completion_method == 'documentclass options' let documentclass = matchstr(line, '\\documentclass\[[^{]*{\zs[^}]*\ze}') if has("python") || has("python3") let completion_list = get(get(g:atp_package_dict.ScanPackage(documentclass.'.cls', ['options!']) ,documentclass.'.cls',{}) , 'options', []) else let completion_list = [] endif if exists("g:atp_".documentclass."_options") if type({"g:atp_".documentclass."_options"}) == 3 " Add options whcih are not already present: call extend(completion_list, filter(copy({"g:atp_".documentclass."_options"}), 'index(completion_list, v:val) == -1')) else " it is a funcref. let c_list = {"g:atp_".documentclass."_options"}.GetOptions(begin) let g:c_list = c_list call extend(completion_list, filter(c_list, 'index(completion_list, v:val) == -1')) endif endif "{{{3 ------------ DOCUMENTCLASS elseif completion_method == 'documentclass' if exists("g:atp_LatexClasses") let completion_list = copy(g:atp_LatexClasses) else echo "[ATP:] generating a list of document classes (it might take a while) ... " if g:atp_debugTabCompletion let debugTabCompletion_LatexClasses_TimeStart=reltime() endif let g:atp_LatexClasses = atplib#search#KpsewhichGlobPath("tex", "", "*.cls") if g:atp_debugTabCompletion let g:debugTabCompletion_LatexClasses_Time=reltimestr(reltime(debugTabCompletion_LatexClasses_TimeStart)) call atplib#Log("TabCompletion.log", "LatexClasses Time: ".g:debugTabCompletion_LatexClasses_Time) endif redraw let completion_list = deepcopy(g:atp_LatexClasses) endif " \documentclass must be closed right after the name ends: if nchar != "}" call map(completion_list,'v:val."}"') endif "{{{3 ------------ FONT FAMILY elseif completion_method == 'font family' echo "[ATP:] searching through fd files ..." let time=reltime() let bpos=searchpos('\\selectfon\zst','bnW',line("."))[1] let epos=searchpos('\\selectfont','nW',line("."))[1]-1 if epos == -1 let epos=len(line) endif let fline=strpart(line,bpos,epos-bpos) let encoding=matchstr(fline,'\\\%(usefont\|DeclareFixedFont\s*{[^}]*}\|fontencoding\)\s*{\zs[^}]*\ze}') if encoding == "" let encoding=g:atp_font_encoding endif let completion_list=[] let fd_list=atplib#fontpreview#FdSearch('^'.encoding.begin) " The above function takes .5s to complete. The code below takes more 1s. for file in fd_list call extend(completion_list,map(atplib#fontpreview#ShowFonts(file),'matchstr(v:val,"usefont\\s*{[^}]*}\\s*{\\zs[^}]*\\ze}")')) endfor " call filter(completion_list,'count(completion_list,v:val) == 1 ') " This was taking another .8s. redraw if len(completion_list) == 0 echo "[ATP:] nothing found." endif let g:time_font_family=reltimestr(reltime(time)) "{{{3 ------------ FONT SERIES elseif completion_method == 'font series' let time=reltime() let bpos=searchpos('\\selectfon\zst','bnW',line("."))[1] let epos=searchpos('\\selectfont','nW',line("."))[1]-1 if epos == -1 let epos=len(line) endif let fline=strpart(line,bpos,epos-bpos) let encoding=matchstr(fline,'\\\%(usefont\|DeclareFixedFont\s*{[^}]*}\|fontencoding\)\s*{\zs[^}]*\ze}') if encoding == "" let encoding=g:atp_font_encoding endif let font_family=matchstr(fline,'\\\%(usefont\s*{[^}]*}\|DeclareFixedFont\s*{[^}]*}\s*{[^}]*}\|fontfamily\)\s*{\zs[^}]*\ze}') echo "[ATP:] searching through fd files ..." let completion_list=[] let fd_list=atplib#fontpreview#FdSearch(encoding.font_family) " The above function takes .5s to complete. for file in fd_list call extend(completion_list, map(atplib#fontpreview#ShowFonts(file),'matchstr(v:val,"usefont{[^}]*}{[^}]*}{\\zs[^}]*\\ze}")')) endfor call filter(completion_list,'count(completion_list,v:val) == 1 ') redraw "{{{3 ------------ FONT SHAPE elseif completion_method == 'font shape' let bpos=searchpos('\\selectfon\zst','bnW',line("."))[1] let epos=searchpos('\\selectfont','nW',line("."))[1]-1 if epos == -1 let epos=len(line) endif let fline=strpart(line,bpos,epos-bpos) let encoding=matchstr(fline,'\\\%(usefont\|DeclareFixedFont\s*{[^}]*}\|fontencoding\)\s*{\zs[^}]*\ze}') if encoding == "" let encoding=g:atp_font_encoding endif let font_family=matchstr(fline,'\\\%(usefont{[^}]*}\|DeclareFixedFont\s*{[^}]*}\s*{[^}]*}\|fontfamily\)\s*{\zs[^}]*\ze}') let font_series=matchstr(fline,'\\\%(usefont\s*{[^}]*}\s*{[^}]*}\|DeclareFixedFont\s*{[^}]*}\s*{[^}]*}\s*{[^}]*}\|fontseries\)\s*{\zs[^}]*\ze}') echo "[ATP:] searching through fd files ..." let completion_list=[] let fd_list=atplib#fontpreview#FdSearch('^'.encoding.font_family) for file in fd_list call extend(completion_list,map(atplib#fontpreview#ShowFonts(file),'matchstr(v:val,"usefont{[^}]*}{'.font_family.'}{'.font_series.'}{\\zs[^}]*\\ze}")')) endfor call filter(completion_list,'count(completion_list,v:val) == 1 ') redraw " {{{3 ------------ FONT ENCODING elseif completion_method == 'font encoding' let bpos=searchpos('\\selectfon\zst','bnW',line("."))[1] let epos=searchpos('\\selectfont','nW',line("."))[1]-1 if epos == -1 let epos=len(line) endif let fline=strpart(line,bpos,epos-bpos) let font_family=matchstr(fline,'\\\%(usefont\s*{[^}]*}\|DeclareFixedFont\s*{[^}]*}\s*{[^}]*}\|fontfamily\)\s*{\zs[^}]*\ze}') if font_family != "" echo "[ATP:] searching through fd files ..." let fd_list=atplib#fontpreview#FdSearch(font_family) let completion_list=map(copy(fd_list),'toupper(substitute(fnamemodify(v:val,":t"),"'.font_family.'.*$","",""))') redraw else " let completion_list=[] " for fd_file in fd_list " let enc=substitute(fnamemodify(fd_file,":t"),"\\d\\zs.*$","","") " if enc != fnamemodify(fd_file,":t") " call add(completion_list,toupper(enc)) " endif " endfor let completion_list=g:atp_completion_font_encodings endif " {{{3 ------------ BIBITEMS elseif completion_method == 'bibitems' let time_bibitems=reltime() let col = col('.') - 1 while col > 0 && line[col - 1] !~ '{\|,' let col -= 1 endwhile let pat = strpart(l,col) let searchbib_time=reltime() if len(filter(values(copy(b:TypeDict)), "v:val == 'bib'")) if !exists("b:ListOfFiles") && !exists("b:TypeDict") call TreeOfFiles(b:atp_MainFile) endif if has("python") || has("python3") && g:atp_bibsearch == "python" && pat != "" let bibfiles=[] for f in b:ListOfFiles let type = get(b:TypeDict, f, "NOTYPE") if type == 'bib' call add(bibfiles, f) elseif type == "NOTYPE" InputFiles let type = get(b:TypeDict, f, "NOTYPE") if type == "NOTYPE" echoerr "[ATP] error " endif endif endfor let bibitems_list=values(atplib#bibsearch#searchbib_py("", pat, bibfiles)) else let bibdict={} for f in b:ListOfFiles try let type = get(b:TypeDict, f, "NOTYPE") if type == 'bib' let bibdict[f]=readfile(f) elseif type == "NOTYPE" InputFiles let type = get(b:TypeDict, f, "NOTYPE") if type == "NOTYPE" echoerr "[ATP] error " endif endif catch /E716:/ echoerr "[ATP]: key ".f." not present in dictionary b:TypeDict. Try to run :InputFiles." return '' endtry endfor let bibitems_list=values(atplib#bibsearch#searchbib(pat, bibdict)) endif let g:time_searchbib_py=reltimestr(reltime(searchbib_time)) if g:atp_debugTabCompletion let g:pat = pat endif let pre_completion_list=[] let completion_dict=[] let completion_list=[] let time_bibitems_for=reltime() for dict in bibitems_list for key in keys(dict) " ToDo: change dict[key][...] to get() to not get errors " if it is not present or to handle situations when it is not " present! call add(pre_completion_list, dict[key]['bibfield_key']) let bibkey=dict[key]['bibfield_key'] if stridx(bibkey, '{') != -1 && stridx(bibkey, '(') != -1 let bibkey=substitute(strpart(bibkey,min([stridx(bibkey,'{'),stridx(bibkey,'(')])+1),',\s*','','') elseif stridx(bibkey, '(') == -1 let bibkey=substitute(strpart(bibkey,stridx(bibkey,'{')+1),',\s*','','') else let bibkey=substitute(strpart(bibkey,stridx(bibkey,'(')+1),',\s*','','') endif if nchar != ',' && nchar != '}' let bibkey.="}" endif let title=get(dict[key],'title', 'notitle') let title=substitute(matchstr(title,'^\s*\ctitle\s*=\s*\%("\|{\|(\)\zs.*\ze\%("\|}\|)\)\s*\%(,\|$\)'),'{\|}','','g') let year=get(dict[key],'year',"") let year=matchstr(year,'^\s*\cyear\s*=\s*\%("\|{\|(\)\zs.*\ze\%("\|}\|)\)\s*\%(,\|$\)') let abbr=get(dict[key],'author',"noauthor") let author = matchstr(abbr,'^\s*\cauthor\s*=\s*\%("\|{\|(\)\zs.*\ze\%("\|}\|)\)\s*,') if abbr=="noauthor" || abbr == "" let abbr=get(dict[key],'editor',"") let author = matchstr(abbr,'^\s*\ceditor\s*=\s*\%("\|{\|(\)\zs.*\ze\%("\|}\|)\)\s*,') endif if len(author) >= 40 if match(author,'\sand\s') let author=strpart(author,0,match(author,'\sand\s')) . ' et al.' else let author=strpart(author,0,40) endif endif let author=substitute(author,'{\|}','','g') if dict[key]['bibfield_key'] =~? '\' let type="[a]" elseif dict[key]['bibfield_key'] =~? '\' let type="[B]" elseif dict[key]['bibfield_key'] =~? '\' let type="[b]" elseif dict[key]['bibfield_key'] =~? '\<\%(proceedings\|conference\)\>' let type="[p]" elseif dict[key]['bibfield_key'] =~? '\' let type="[u]" elseif dict[key]['bibfield_key'] =~? '\' let type="[c]" elseif dict[key]['bibfield_key'] =~? '\' let type="[PhD]" elseif dict[key]['bibfield_key'] =~? '\' let type="[M]" elseif dict[key]['bibfield_key'] =~? '\' let type="[-]" elseif dict[key]['bibfield_key'] =~? '\' let type="[t]" elseif dict[key]['bibfield_key'] =~? '\' let type="[m]" else let type=" " endif let abbr=type." ".author." (".year.") " call add(completion_dict, { "word" : bibkey, "menu" : title, "abbr" : abbr }) endfor endfor let g:completion_dict=completion_dict for key in pre_completion_list call add(completion_list,substitute(strpart(key,max([stridx(key,'{'),stridx(key,'(')])+1),',\s*','','')) endfor else " add the \bibitems found in include files let time_bibitems_SearchBibItems=reltime() let completion_dict=[] let dict=atplib#bibsearch#SearchBibItems() let g:dict = copy(dict) for key in keys(dict) if a:expert_mode && ( key =~ '^'.begin || dict[key]['label'] =~ '^'.begin ) || \ !a:expert_mode && ( key =~ begin || dict[key]['label'] =~ begin ) call add(completion_dict, { "word" : key, "menu" : dict[key]['rest'], "abbrev" : dict[key]['label'] }) endif endfor let g:time_bibitems_SearchBibItems=reltimestr(reltime(time_bibitems_SearchBibItems)) endif let g:time_bibitems=reltimestr(reltime(time_bibitems)) " {{{3 ------------ TODONOTES TODO & MISSING FIGURE OPTIONS elseif completion_method == 'todo options' let completion_list = copy(g:atp_TodoNotes_todo_options) elseif completion_method == 'missingfigure options' let completion_list = copy(g:atp_TodoNotes_missingfigure_options) endif " }}}3 if exists("completion_list") let b:completion_list=completion_list " DEBUG if g:atp_debugTabCompletion call atplib#Log("TabCompletion.log", "completion_list=".string(completion_list)) endif endif let g:time_TabCompletion_CLset = reltimestr(reltime(time)) " {{{2 make the list of matching completions "{{{3 --------- completion_method = !close environments !env_close if completion_method != 'close environments' && completion_method != 'env_close' let completions=[] " {{{4 --------- packages, package options, bibstyles, font (family, series, shapre, encoding), document class, documentclass options, environment options if (completion_method == 'package' || \ completion_method == 'package options'|| \ completion_method == 'environment options'|| \ completion_method == 'documentclass options'|| \ completion_method == 'bibstyles' || \ completion_method =~ 'beamer\%(\|inner\|outer\|color\|font\)themes' || \ completion_method == 'font family' || \ completion_method == 'font series' || \ completion_method == 'font shape' || \ completion_method == 'font encoding'|| \ completion_method == 'pagestyle'|| \ completion_method == 'pagenumbering'|| \ completion_method == 'documentclass' ) if a:expert_mode let completions = filter(copy(completion_list),' v:val =~? "^".begin') else let completions = filter(copy(completion_list),' v:val =~? begin') endif " {{{4 --------- environment options values, command values of values elseif completion_method == 'environment values of options' || completion_method == 'command values of values' " This is essentialy done in previous step already let completions = completion_list " {{{4 --------- command values elseif completion_method == 'command values' if a:expert_mode let completions = filter(copy(completion_list),' v:val =~? "^".cmd_val_begin') else let completions = filter(copy(completion_list),' v:val =~? cmd_val_begin') endif " {{{4 --------- package options values elseif ( completion_method == 'package options values' ) if a:expert_mode let completions = filter(copy(completion_list),' v:val =~? "^".ebegin') else let completions = filter(copy(completion_list),' v:val =~? ebegin') endif " {{{4 --------- environment names, bibfiles elseif ( completion_method == 'environment_names' || \ completion_method == 'bibfiles' ) if a:expert_mode let completions = filter(copy(completion_list),' v:val =~# "^".begin') else let completions = filter(copy(completion_list),' v:val =~? begin') endif " {{{4 --------- colors elseif completion_method == 'tikzpicture colors' if a:expert_mode let completions = filter(copy(completion_list),' v:val =~# "^".color_begin') else let completions = filter(copy(completion_list),' v:val =~? color_begin') endif " {{{4 --------- tikzpicture libraries, inputfiles " match not only in the beginning elseif (completion_method == 'tikz libraries' || \ completion_method == 'inputfiles') let completions = filter(copy(completion_list),' v:val =~? begin') " if nchar != "}" && nchar != "," && completion_method != 'inputfiles' " call map(completions,'v:val') " endif " {{{4 --------- Commands " must match at the beginning (but in a different way) " (only in expert_mode). elseif completion_method == 'command' if a:expert_mode == 1 let completions = filter(copy(completion_list),'v:val =~# "\\\\".tbegin') elseif a:expert_mode != 1 let completions = filter(copy(completion_list),'v:val =~? tbegin') endif " {{{4 --------- Abbreviations elseif completion_method == 'abbreviations' let completions = filter(copy(completion_list), 'v:val =~# "^" . abegin') " {{{4 --------- Tikzpicture Keywords elseif completion_method == 'tikzpicture keywords' || \ completion_method == 'todo options' || \ completion_method == 'missingfigure options' if g:atp_completion_tikz_expertmode let completions = filter(copy(completion_list),'v:val =~# "^".tbegin') else let completions = filter(copy(completion_list),'v:val =~? tbegin') endif " {{{4 --------- Tikzpicture Commands elseif completion_method == 'tikzpicture commands' if a:expert_mode == 1 let completions = filter(copy(completion_list),'v:val =~# "^".tbegin') elseif a:expert_mode != 1 let completions = filter(copy(completion_list),'v:val =~? tbegin') endif " {{{4 --------- Labels elseif completion_method == 'labels' " Complete label by string or number: let aux_data = atplib#tools#GrepAuxFile() let completion_dict = [] let pattern = matchstr(l, '\\\%(eq\|page\|auto\|autopage\)\=ref\*\=\s*{\zs\S*$\|\\hyperref\s*\[\zs\S*$') for data in aux_data " match label by string or number if ( data[0] =~ '^' . pattern || data[1] =~ '^'. pattern ) && a:expert_mode || ( data[0] =~ pattern || data[1] =~ pattern ) && !a:expert_mode if l =~ '\\\%(eq\|page\|auto\|autopage\)\=ref\*\=\s*{\S*$' let close = ( nchar == '}' ? '' : '}' ) else let close = ( nchar == ']' ? '' : ']' ) endif call add(completion_dict, { "word" : data[0].close, "abbr" : data[0], "menu" : ( data[2] == 'equation' && data[1] != "" ? "(".data[1].")" : data[1] ) , "kind" : data[2][0] }) endif endfor " {{{4 --------- includegraphics elseif completion_method == 'includegraphics' let completions=copy(completion_list) endif "{{{3 --------- else: try to close environment else call atplib#complete#CloseLastEnvironment('a', 'environment') let b:tc_return="1" let g:time_TabCompletion=reltimestr(reltime(time)) return '' endif "{{{3 --------- SORTING and TRUNCATION " ToDo: we will not truncate if completion method is specific, this should be " made by a variable! Maybe better is to provide a positive list !!! if g:atp_completion_truncate && a:expert_mode && \ index(['bibfiles', 'bibitems', 'bibstyles', 'font family', \ 'environment_names', 'environment options', 'font series', \ 'font shape', 'font encoding', 'inputfiles', 'includefiles', \ 'labels', 'package options', 'package options values', \ 'documentclass options', 'documentclass options values', \ 'tikz libraries', 'command values', 'command values of values', \ 'environment values' ], completion_method) == -1 call filter(completions, 'len(substitute(v:val,"^\\","","")) >= g:atp_completion_truncate') endif " THINK: about this ... " if completion_method == "tikzpicture keywords" " let bracket = atplib#complete#CloseLastBracket(g:atp_bracket_dict, 1) " if bracket != "" " call add(completions, bracket) " endif " endif " if the list is long it is better if it is sorted, if it short it is " better if the more used things are at the beginning. if g:atp_sort_completion_list && len(completions) >= g:atp_sort_completion_list && completion_method != 'labels' if completion_method == 'abbreviations' let completions=sort(completions, "atplib#CompareStarAfter") else let completions=sort(completions) endif endif " DEBUG let b:completions=completions " {{{2 COMPLETE call cursor(pos_saved[1], pos_saved[2]) " {{{3 package, tikz libraries, environment_names, colors, bibfiles, bibstyles, documentclass, font family, font series, font shape font encoding, input files, includegraphics if \ completion_method == 'package' || \ completion_method == 'environment options' || \ completion_method == 'environment_names' || \ completion_method == 'tikz libraries' || \ completion_method == 'pagestyle' || \ completion_method == 'pagenumbering' || \ completion_method == 'bibfiles' || \ completion_method == 'bibstyles' || \ completion_method == 'documentclass' || \ completion_method == 'font family' || \ completion_method == 'font series' || \ completion_method == 'font shape' || \ completion_method == 'font encoding' || \ completion_method == 'todo options' || \ completion_method == 'missingfigure options' || \ completion_method == 'inputfiles' || \ completion_method == 'includegraphics' let column = nr+2 call complete(column,completions) "{{{3 abbreviations elseif completion_method == 'abbreviations' let col=match(l, '^.*\zs=')+1 call complete(col, completions) let column=col "{{{3 labels elseif completion_method == 'labels' let col=match(l, '\\\(eq\|page\|auto\|autopage\)\=ref\*\=\s*{\zs\S*$\|\\hyperref\s*\[\zs\S*$')+1 call complete(col, completion_dict) let column=col return '' " {{{3 bibitems elseif !normal_mode && completion_method == 'bibitems' if exists("completion_dict") " for bibtex, biblatex call complete(col+1,completion_dict) let column=col+1 else " for thebibliography environment call complete(col+1,completion_list) let column=col+1 endif " {{{3 commands, tikzcpicture commands elseif !normal_mode && (completion_method == 'command' || completion_method == 'tikzpicture commands') " We are not completing greek letters, but we add them if cbegin is " one. call extend(completion_list, g:atp_greek_letters) if count(completion_list, cbegin) >= 1 " Add here brackets - somebody might want to " close a bracket after \nu and not get \numberwithin{ (which is " rarely used). let b:comp_method = "brackets in commands" if (!normal_mode && index(g:atp_completion_active_modes, 'brackets') != -1 ) || \ (normal_mode && index(g:atp_completion_active_modes_normal_mode, 'brackets') != -1 ) let bracket=atplib#complete#GetBracket(append, g:atp_bracket_dict) if bracket != "0" && bracket != "" let completions = extend([cbegin.bracket], completions) endif endif call add(completions, cbegin) endif call complete(o+1,completions) let column=o+1 " {{{3 tikzpicture keywords elseif !normal_mode && (completion_method == 'tikzpicture keywords') let t=match(l,'\zs\<\w*$') " in case '\zs\<\w*$ is empty if t == -1 let t=col(".") endif call complete(t+1,completions) let column=t+1 let b:tc_return="tikzpicture keywords" " {{{3 tikzpicture colors elseif !normal_mode && (completion_method == 'tikzpicture colors') call complete(color_nr+2, completions) let column=color_nr+2 " {{{3 package and document class options elseif !normal_mode && ( completion_method == 'package options' || completion_method == 'documentclass options' \ || completion_method == 'environment options' ) let col=len(matchstr(l,'^.*\\\%(documentclass\|usepackage\)\[.*,\ze')) if col==0 let col=len(matchstr(l,'^.*\\\%(documentclass\|usepackage\)\[\ze')) endif call complete(col+1, completions) let column = col+1 " {{{3 command values elseif !normal_mode && ( completion_method == 'command values' ) let col = len(l)-len(cmd_val_begin) call complete(col+1, completions) let column = col+1 " {{{3 package and document class options values elseif !normal_mode && (completion_method == 'package options values') let col=len(matchstr(l,'\\\%(documentclass\|usepackage\)\[.*=\%({[^}]*,\|{\)\?\ze')) if col==0 let col=len(matchstr(l,'\\\%(documentclass\|usepackage\)\[\ze')) endif call complete(col+1, completions) let column = col+1 "{{{3 environment options values elseif !normal_mode && (completion_method == 'environment values of options') let col=len(matchstr(l, '.*\\begin\s*{[^}]*}\[.*=\%({[^}]*,\|{\)\?\ze')) let column = col+1 call complete(column, completions) elseif !normal_mode && (completion_method == 'command values of values') let col=len(matchstr(l, '.*\\\w\+{\%([^}]*,\)\?[^,}=]*='.cvov_ignore_pattern.'\ze')) let column = col+1 call complete(column, completions) else let column = col(".") endif " If the completion method was a command (probably in a math mode) and " there was no completion, check if environments are closed. " {{{3 Final call of CloseLastEnvrionment / CloseLastBracket let len=len(completions) let matched_word = strpart(getline(line(".")), column-1, pos_saved[2]-column) if len == 0 && (!count(['package', 'bibfiles', 'bibstyles', 'inputfiles'], completion_method) || a:expert_mode == 1 ) || len == 1 let b:comp_method .= " final" if count(['command', 'tikzpicture commands', 'tikzpicture keywords', 'command values'], completion_method) && \ (len == 0 || len == 1 && completions[0] =~ '^\\\='. begin . '$' ) let filter = 'strpart(getline("."), 0, col(".") - 1) =~ ''\\\@', 'bnW') " Check Brackets let b:comp_method .= " brackets: 1" let cl_return = atplib#complete#GetBracket(append, g:atp_bracket_dict) " If the bracket was closed return. if cl_return != "0" let g:time_TabCompletion=reltimestr(reltime(time)) return cl_return endif " Check inline math: if !has("python") && (atplib#complete#CheckClosed_math('texMathZoneV') || \ atplib#complete#CheckClosed_math('texMathZoneW') || \ atplib#complete#CheckClosed_math('texMathZoneX') || \ b:atp_TexFlavor == 'plaintex' && atplib#complete#CheckClosed_math('texMathZoneY')) let zone = 'texMathZoneVWXY' " DEBUG call atplib#complete#CloseLastEnvironment(append, 'math') " Check environments: else let env_opened= searchpairpos('\\begin','','\\end','bnW','searchpair("\\\\begin{".matchstr(getline("."),"\\\\begin{\\zs[^}]*\\ze}"),"","\\\\end{".matchstr(getline("."),"\\\\begin{\\zs[^}]*\\ze}"),"nW")',max([1,(line(".")-g:atp_completion_limits[2])])) let env_name = matchstr(strpart(getline(env_opened[0]), env_opened[1]-1), '\\begin\s*{\zs[^}]*\ze}') let zone = env_name " DEBUG if env_opened != [0, 0] call atplib#complete#CloseLastEnvironment('a', 'environment', env_name, env_opened) endif endif " DEBUG if exists("zone") let b:tc_return =" close_env end " . zone let b:comp_method.=' close_env end ' . zone if g:atp_debugTabCompletion call atplib#Log("TabCompletion.log", "b:comp_method.=".b:comp_method) endif else let b:tc_return=" close_env end" let b:comp_method.=' close_env end' if g:atp_debugTabCompletion call atplib#Log("TabCompletion.log", "b:comp_method=".b:comp_method) endif endif elseif len == 0 && \ completion_method != 'labels' && \ completion_method != 'bibitems' \ || len == 1 && get(completions, 0, "") == matched_word || \ completion_method != 'brackets' && \ completion_method != 'labels' && \ completion_method != 'bibitems' && \ completion_method != 'bibfiles' && \ completion_method != 'close environments' && \ completion_method != 'algorithmic' && \ completion_method != 'abbreviations' && \ completion_method != 'command' && \ completion_method != 'command values' && \ completion_method != 'tikzpicture' && \ completion_method != 'tikzpicture commands' && \ completion_method != 'tikzpicture keywords' && \ completion_method != 'package options' && \ completion_method != 'documentclass' && \ completion_method != 'documentclass options' && \ completion_method != 'environment_names' && \ completion_method != 'environment options' && \ completion_method != 'todo options' && \ completion_method != 'missingfigure options' " elseif completion_method == 'package' || " \ completion_method == 'environment_names' || " \ completion_method == 'font encoding' || " \ completion_method == 'font family' || " \ completion_method == 'font series' || " \ completion_method == 'font shape' || " \ completion_method == 'bibstyles' || " \ completion_method == 'bibfiles' let b:tc_return='close_bracket end' let b:comp_method .= " brackets: 2" let g:time_TabCompletion=reltimestr(reltime(time)) return atplib#complete#GetBracket(append, g:atp_bracket_dict) endif endif "}}}3 let g:time_TabCompletion=reltimestr(reltime(time)) return '' "}}}2 endfunction catch /E127:/ endtry " }}}1 " vim:fdm=marker:ff=unix:noet:ts=8:sw=4:fdc=1 autoload/atplib/fontpreview.vim [[[1 433 " Title: Vim library for ATP filetype plugin. " Author: Marcin Szamotulski " Email: mszamot [AT] gmail [DOT] com " Note: This file is a part of Automatic Tex Plugin for Vim. " URL: https://launchpad.net/automatictexplugin " Language: tex " Font Preview Functions: " These functions search for fd files and show them in a buffer with filetype " 'fd_atp'. There are additional function for this filetype written in " fd_atp.vim ftplugin. Distributed with atp. "{{{1 atplib#fontpreview#FdSearch "([,]) " There are two methods: " 0 - match fd file names ( ":t" filename modifier) <- the default one " 1 - match fd file path function! atplib#fontpreview#FdSearch(...) if a:0 == 0 let pattern = "" let method = 0 else let pattern = ( a:0 >= 1 ? a:1 : "" ) let method = ( a:0 >= 2 ? a:2 : 0 ) endif " let g:method = method " let g:pattern = pattern " Find fd file let path = substitute(substitute(system("kpsewhich -show-path tex"),'!!','','g'),'\/\/\+','\/','g') let path = substitute(path,':\|\n',',','g') let fd = split(globpath(path,"**/*.fd"),'\n') let g:fd = copy(fd) " Match for l:pattern let fd_matches=[] if method == 0 call filter(fd, 'fnamemodify(v:val, ":t") =~ pattern') else call filter(fd, 'v:val =~ pattern') endif return fd endfunction "{{{1 atplib#fontpreview#FontSearch " atplib#fontpreview#FontSearch(method,[]) " method = "" match for name of fd file " method = "!" match against whole path function! atplib#fontpreview#FontSearch(method,...) let l:method = ( a:method == "!" ? 1 : 0 ) let l:pattern = ( a:0 ? a:1 : "" ) let s:fd_matches=atplib#fontpreview#FdSearch(l:pattern, l:method) " Open Buffer and list fd files " set filetype to fd_atp let l:tmp_dir=tempname() call mkdir(l:tmp_dir) let l:fd_bufname="fd_list " . l:pattern let l:openbuffer="32vsplit! +setl\\ nospell\\ ft=fd_atp ". fnameescape(l:tmp_dir . "/" . l:fd_bufname ) let g:fd_matches=[] if len(s:fd_matches) > 0 echohl WarningMsg echomsg "[ATP:] found " . len(s:fd_matches) . " files." echohl None " wipe out the old buffer and open new one instead if buflisted(fnameescape(l:tmp_dir . "/" . l:fd_bufname)) silent exe "bd! " . bufnr(fnameescape(l:tmp_dir . "/" . l:fd_bufname)) endif silent exe l:openbuffer " make l:tmp_dir available for this buffer. " let b:tmp_dir=l:tmp_dir cd /tmp map q :bd " print the lines into the buffer let l:i=0 call setline(1,"FONT DEFINITION FILES:") for l:fd_file in s:fd_matches " we put in line the last directory/fd_filename: " this is what we cut: let l:path=fnamemodify(l:fd_file,":h:h") let l:fd_name=substitute(l:fd_file,"^" . l:path . '/\?','','') " call setline(line('$')+1,fnamemodify(l:fd_file,":t")) call setline(line('$')+1,l:fd_name) call add(g:fd_matches,l:fd_file) let l:i+=1 endfor call append('$', ['', 'maps:', \ 'p Preview font ', \ 'P Preview font+tex file', \ ' Show Fonts in fd file', \ ' Open fd file', \ 'q "bd!"', \ '', \ 'Note: p/P works in visual mode']) silent w setlocal nomodifiable setlocal ro else echohl WarningMsg if !l:method echomsg "[ATP:] no fd file found, try :FontSearch!" else echomsg "[ATP:] no fd file found." endif echohl None endif endfunction "{{{1 atplib#fontpreview#Fd_completion /not needed/ " if !exists("*atplib#Fd_completion") " function! atplib#fontpreview#Fd_completion(A,C,P) " " " Find all files " let l:path=substitute(substitute(system("kpsewhich -show-path tex"),'!!','','g'),'\/\/\+','\/','g') " let l:path=substitute(l:path,':\|\n',',','g') " let l:fd=split(globpath(l:path,"**/*.fd"),"\n") " let l:fd=map(l:fd,'fnamemodify(v:val,":t:r")') " " let l:matches=[] " for l:fd_file in l:fd " if l:fd_file =~ a:A " call add(l:matches,l:fd_file) " endif " endfor " return l:matches " endfunction " endif " {{{1 atplib#fontpreview#OpenFdFile /not working && not needed?/ " function! atplib#fontpreview#OpenFdFile(name) " let l:path=substitute(substitute(system("kpsewhich -show-path tex"),'!!','','g'),'\/\/\+','\/','g') " let l:path=substitute(l:path,':\|\n',',','g') " let b:path=l:path " let l:fd=split(globpath(l:path,"**/".a:name.".fd"),"\n") " let l:fd=map(l:fd,'fnamemodify(v:val,":t:r")') " let b:fd=l:fd " execute "split +setl\\ ft=fd_atp " . l:fd[0] " endfunction "{{{1 atplib#fontpreview#Preview " keep_tex=1 open the tex file of the sample file, otherwise it is deleted (at " least from the buffer list). " To Do: fd_file could be a list of fd_files which we would like to see, every " font should be done after \pagebreak[4] " if a:fd_files=['buffer'] it means read the current buffer (if one has opened " an fd file). function! atplib#fontpreview#Preview(fd_files,keep_tex) if a:fd_files != ["buffer"] let l:fd_files={} for l:fd_file in a:fd_files call extend(l:fd_files,{fd_file : readfile(l:fd_file)}) endfor else let l:fd_files={bufname("%"):getline(1,"$")} endif unlet l:fd_file let l:declare_command='\C\%(DeclareFontShape\%(WithSizes\)\?\|sauter@\%(tt\)\?family\|EC@\%(tt\)\?family\|krntstexmplfamily\|HFO@\%(tt\)\?family\)' let b:declare_command=l:declare_command let l:font_decl_dict={} for l:fd_file in a:fd_files call extend(l:font_decl_dict, {l:fd_file : [ ]}) for l:line in l:fd_files[l:fd_file] if l:line =~ '\\'.l:declare_command.'\s*{[^#}]*}\s*{[^#}]*}\s*{[^#}]*}\s*{[^#}]*}' call add(l:font_decl_dict[l:fd_file],l:line) endif endfor endfor let l:tmp_dir=tempname() call mkdir(expand(l:tmp_dir)) if a:fd_files == ["buffer"] " WINDOWS NOT COMPATIBLE let l:testfont_file=l:tmp_dir . "/" . fnamemodify(bufname("%"),":t:r") . ".tex" else " the name could be taken from the pattern " or join(map(keys(deepcopy(a:fd_files)),'substitute(fnamemodify(v:val,":t:r"),".fd$","","")'),'_') " though it can be quite a long name. let l:testfont_file=l:tmp_dir . "/" . fnamemodify(a:fd_files[0],":t:r") . ".tex" endif " WINDOWS NOT COMPATIBLE " call system("touch " . l:testfont_file) let l:fd_bufnr=bufnr("%") let s:text="On November 14, 1885, Senator \\& Mrs.~Leland Stanford called \ together at their San Francisco mansion the 24~prominent men who had \ been chosen as the first trustees of The Leland Stanford Junior University. \ They handed to the board the Founding Grant of the University, which they \ had executed three days before.\\\\ \ (!`THE DAZED BROWN FOX QUICKLY GAVE 12345--67890 JUMPS!)" " let l:text="On November 14, 1885, Senator \\& Mrs.~Leland Stanford called " \ together at their San Francisco mansion the 24~prominent men who had " \ been chosen as the first trustees of The Leland Stanford Junior University. " \ They handed to the board the Founding Grant of the University, which they " \ had executed three days before. This document---with various amendments, " \ legislative acts, and court decrees---remains as the University's charter. " \ In bold, sweeping language it stipulates that the objectives of the University " \ are ``to qualify students for personal success and direct usefulness in life; " \ and to promote the public welfare by exercising an influence in behalf of " \ humanity and civilization, teaching the blessings of liberty regulated by " \ law, and inculcating love and reverence for the great principles of " \ government as derived from the inalienable rights of man to life, liberty, " \ and the pursuit of happiness.''\\ " \ (!`THE DAZED BROWN FOX QUICKLY GAVE 12345--67890 JUMPS!)\\par}} " \ \\def\\\moretext{?`But aren't Kafka's Schlo{\\ss} and {\\AE}sop's {\\OE}uvres " \ often na{\\"\\i}ve vis-\\`a-vis the d{\\ae}monic ph{\\oe}nix's official r\\^ole " \ in fluffy souffl\\'es? } " \ \\moretext" if a:fd_files == ["buffer"] let l:openbuffer="edit " else let l:openbuffer="topleft split!" endif execute l:openbuffer . " +setlocal\\ ft=tex\\ modifiable\\ noro " . l:testfont_file " Clear the file (if one has a skeleton file it will be removed.) normal! ggdG let b:atp_ProjectScript = 0 map q :bd! call setline(1,'\documentclass{article}') call setline(2,'\oddsidemargin=0pt') call setline(3,'\textwidth=450pt') call setline(4,'\textheight=700pt') call setline(5,'\topmargin=-10pt') call setline(6,'\headsep=0pt') call setline(7,'\begin{document}') let l:i=8 let l:j=1 let l:len_font_decl_dict=len(l:font_decl_dict) let b:len_font_decl_dict=l:len_font_decl_dict for l:fd_file in keys(l:font_decl_dict) if l:j == 1 call setline(l:i,'\textsc\textbf{\Large Fonts from the file '.l:fd_file.'}\\[2em]') let l:i+=1 else " call setline(l:i,'\pagebreak[4]') call setline(l:i,'\vspace{4em}') call setline(l:i+1,'') call setline(l:i+2,'\textsc\textbf{\Large Fonts from the file '.l:fd_file.'}\\[2em]') let l:i+=3 endif let l:len_font_decl=len(l:font_decl_dict[l:fd_file]) let b:match=[] for l:font in l:font_decl_dict[l:fd_file] " SHOW THE FONT ENCODING, FAMILY, SERIES and SHAPE if matchstr(l:font,'\\'.l:declare_command.'\s*{[^#}]*}\s*{[^#}]*}\s*{\zs[^#}]*\ze}\s*{[^#}]*}') == "b" || \ matchstr(l:font,'\\'.l:declare_command.'\s*{[^#}]*}\s*{[^#}]*}\s*{\zs[^#}]*\ze}\s*{[^#}]*}') == "bx" let b:show_font='\noindent{\large \textit{Font Encoding}: \textsf{' . \ matchstr(l:font,'\\'.l:declare_command.'\s*{\zs[^#}]*\ze}\s*{[^#}]*}\s*{[^#}]*}\s*{[^#}]*}') . '}' . \ ' \textit{Font Family}: \textsf{' . \ matchstr(l:font,'\\'.l:declare_command.'\s*{[^}#]*}\s*{\zs[^#}]*\ze}\s*{[^#}]*}\s*{[^#}]*}') . '}' . \ ' \textit{Font Series}: \textsf{' . \ matchstr(l:font,'\\'.l:declare_command.'\s*{[^#}]*}\s*{[^#}]*}\s*{\zs[^#}]*\ze}\s*{[^#}]*}') . '}' . \ ' \textit{Font Shape}: \textsf{' . \ matchstr(l:font,'\\'.l:declare_command.'\s*{[^#}]*}\s*{[^#}]*}\s*{[^#}]*}\s*{\zs[^#}]*\ze}') . '}}\\[2pt]' else let b:show_font='\noindent{\large \textbf{Font Encoding}: \textsf{' . \ matchstr(l:font,'\\'.l:declare_command.'\s*{\zs[^#}]*\ze}\s*{[^#}]*}\s*{[^#}]*}\s*{[^#}]*}') . '}' . \ ' \textbf{Font Family}: \textsf{' . \ matchstr(l:font,'\\'.l:declare_command.'\s*{[^}#]*}\s*{\zs[^#}]*\ze}\s*{[^#}]*}\s*{[^#}]*}') . '}' . \ ' \textbf{Font Series}: \textsf{' . \ matchstr(l:font,'\\'.l:declare_command.'\s*{[^#}]*}\s*{[^#}]*}\s*{\zs[^#}]*\ze}\s*{[^#}]*}') . '}' . \ ' \textbf{Font Shape}: \textsf{' . \ matchstr(l:font,'\\'.l:declare_command.'\s*{[^#}]*}\s*{[^#}]*}\s*{[^#}]*}\s*{\zs[^#}]*\ze}') . '}}\\[2pt]' endif call setline(l:i,b:show_font) let l:i+=1 " CHANGE THE FONT call setline(l:i,'{' . substitute( \ matchstr(l:font,'\\'.l:declare_command.'\s*{[^#}]*}\s*{[^#}]*}\s*{[^#}]*}\s*{[^#}]*}'), \ l:declare_command,'usefont','') . \ '\selectfont') " WRITE SAMPLE TEXT call add(b:match,matchstr(l:font,'\\'.l:declare_command.'\s*{[^#}]*}\s*{[^#}]*}\s*{[^#}]*}\s*{[^#}]*}')) let l:i+=1 " END if l:j= 1 ? a:1 : "" ) let l:keep_tex = ( a:0 >= 2 ? a:2 : 0 ) if filereadable(a:fd_file) let l:fd_file=a:fd_file else " Find fd file if a:fd_file !~ '.fd\s*$' let l:fd_file=a:fd_file.".*.fd" else let l:fd_file=a:fd_file endif let l:fd=atplib#fontpreview#FdSearch(a:fd_file, l:method) let g:fd=l:fd if !empty(l:enc) call filter(l:fd, "fnamemodify(v:val, ':t') =~ '^' . l:enc") endif if len(l:fd) == 0 if !l:method echo "FD file not found. Try :FontPreview!" else echo "FD file not found." endif return elseif len(l:fd) == 1 let l:fd_file_list=l:fd else let l:i=1 for l:f in l:fd echo l:i." ".substitute(f,'^'.fnamemodify(f,":h:h").'/\?','','') let l:i+=1 endfor let l:choice=input('Which fd file? ') if l:choice == "" return endif let l:choice_list=split(l:choice,',') let b:choice_list=l:choice_list " if there is 1-4 --> a list of 1,2,3,4 let l:new_choice_list=[] for l:ch in l:choice_list if l:ch =~ '^\d\+$' call add(l:new_choice_list,l:ch) elseif l:ch =~ '^\d\+\s*-\s*\d\+$' let l:b=matchstr(l:ch,'^\d\+') let l:e=matchstr(l:ch,'\d\+$') let l:k=l:b while l:k<=l:e call add(l:new_choice_list,l:k) let l:k+=1 endwhile endif endfor let b:new_choice_list=l:new_choice_list let l:fd_file_list=map(copy(l:new_choice_list),'get(l:fd,(v:val-1),"")') let l:fd_file_list=filter(l:fd_file_list,'v:val != ""') " let l:fd_file=get(l:fd,l:choice-1,"return") if len(l:fd_file_list) == 0 return endif endif endif call atplib#fontpreview#Preview(l:fd_file_list,l:keep_tex) endfunction " {{{1 atplib#fontpreview#ShowFonts function! atplib#fontpreview#ShowFonts_vim(fd_file) let l:declare_command='\C\%(DeclareFontShape\%(WithSizes\)\?\|sauter@\%(tt\)\?family\|EC@\%(tt\)\?family\|krntstexmplfamily\|HFO@\%(tt\)\?family\)' let l:font_decl=[] for l:line in readfile(a:fd_file) if l:line =~ '\\'.l:declare_command.'\s*{[^#}]*}\s*{[^#}]*}\s*{[^#}]*}\s*{[^#}]*}' call add(l:font_decl,l:line) endif endfor let l:font_commands=[] for l:font in l:font_decl call add(l:font_commands,substitute( \ matchstr(l:font,'\\'.l:declare_command.'\s*{[^#}]*}\s*{[^#}]*}\s*{[^#}]*}\s*{[^#}]*}'), \ l:declare_command,'usefont','')) endfor return l:font_commands endfunction function! atplib#fontpreview#ShowFonts_py(fd_file) python << END import vim, re file=vim.eval("a:fd_file") try: file_o=open(file, "r") file_l=file_o.readlines() declare_pat=re.compile('(?:DeclareFontShape(?:WithSizes)?|sauter@(?:tt)?family|EC@(?:tt)?family|krntstexmplfamily|HFO@(?:tt)?family)') font_pat=re.compile('(\\\\(?:DeclareFontShape(?:WithSizes)?|sauter@(?:tt)?family|EC@(?:tt)?family|krntstexmplfamily|HFO@(?:tt)?family)\s*{[^#}]*}\s*{[^#}]*}\s*{[^#}]*}\s*{[^#}]*})') font_commands=[] for line in file_l: if re.search(declare_pat, line): font_cmd=re.search(font_pat, line) if font_cmd: font=font_cmd.group(0) font=re.sub(declare_pat, 'usefont', font) font_commands.append(font) vim.command("let s:return_ShowFonts_py="+str(font_commands)) except IOError: vim.command("let s:return_ShowFonts_py=[]") END return map(s:return_ShowFonts_py, "substitute(v:val, '^\\', '', '')") endfunction function! atplib#fontpreview#ShowFonts(fd_file) if has("python") return atplib#fontpreview#ShowFonts_py(a:fd_file) else return atplib#fontpreview#ShowFonts(a:fd_file) endif endfunction " }}}1 " vim:fdm=marker:ff=unix:noet:ts=8:sw=4:fdc=1 autoload/atplib/helpfunctions.vim [[[1 253 " Author: Marcin Szamotulski " Description: This file contains help commands and variables (for mappings used by ATP) " Note: This file is a part of Automatic Tex Plugin for Vim. " Language: tex " Last Change: " {{{1 Help Math IMAPS function! atplib#helpfunctions#HelpMathIMaps() if exists("g:no_plugin_maps") || exists("g:no_atp_maps") echomsg "[ATP:] ATP maps are turned off" return '' endif echohl Title echo "MATH IMAPS" echohl WarningMsg echo " has value g:atp_imap_leader_1" echohl Normal echohl Keyword|echo g:atp_imap_leader_1."a"|echohl Normal|echon " \\alpha " echohl Keyword|echon g:atp_imap_leader_1."b"|echohl Normal|echon " \\beta" " echo g:help_mathimaps echohl Keyword|echo g:atp_imap_leader_1."g"|echohl Normal|echon " \\gamma " echohl Keyword|echon g:atp_imap_leader_1."d"|echohl Normal|echon " \\delta" echohl Keyword|echo g:atp_imap_leader_1."e"|echohl Normal|echon " \\epsilon " echohl Keyword|echon g:atp_imap_leader_1."v"|echohl Normal|echon " \\varepsilon" echohl Keyword|echo g:atp_imap_leader_1."z"|echohl Normal|echon " \\zeta " echohl Keyword|echon g:atp_imap_leader_1."h"|echohl Normal|echon " \\eta" echohl Keyword|echo g:atp_imap_leader_1."o"|echohl Normal|echon " \\theta " echohl Keyword|echon g:atp_imap_leader_1."v"|echohl Normal|echon " \\vartheta" echohl Keyword|echo g:atp_imap_leader_1."i"|echohl Normal|echon " \\iota " echohl Keyword|echon g:atp_imap_leader_1."k"|echohl Normal|echon " \\kappa" echohl Keyword|echo g:atp_imap_leader_1."l"|echohl Normal|echon " \\lambda " echohl Keyword|echon g:atp_imap_leader_1."m"|echohl Normal|echon " \\mu" echohl Keyword|echo g:atp_imap_leader_1."n"|echohl Normal|echon " \\nu " echohl Keyword|echon g:atp_imap_leader_1."x"|echohl Normal|echon " \\xi" echohl Keyword|echo g:atp_imap_leader_1."p"|echohl Normal|echon " \\pi " echohl Keyword|echon g:atp_imap_leader_1."r"|echohl Normal|echon " \\rho" echohl Keyword|echo g:atp_imap_leader_1."s"|echohl Normal|echon " \\sigma " echohl Keyword|echon g:atp_imap_leader_1."v"|echohl Normal|echon " \\varsigma" echohl Keyword|echo g:atp_imap_leader_1."t"|echohl Normal|echon " \\tau " echohl Keyword|echon g:atp_imap_leader_1."u"|echohl Normal|echon " \\upsilon" echohl Keyword|echo g:atp_imap_leader_1."f"|echohl Normal|echon " \\phi " echohl Keyword|echon g:atp_imap_leader_1."c"|echohl Normal|echon " \\chi" echohl Keyword|echo g:atp_imap_leader_1."y"|echohl Normal|echon " \\psi " echohl Keyword|echon g:atp_imap_leader_1."w"|echohl Normal|echon " \\omega" echohl Keyword|echo g:atp_imap_leader_1."G"|echohl Normal|echon " \\Gamma " echohl Keyword|echon g:atp_imap_leader_1."D"|echohl Normal|echon " \\Delta" echohl Keyword|echo g:atp_imap_leader_1."Z"|echohl Normal|echon " \\mathrm{Z} " echohl Keyword|echon g:atp_imap_leader_1."O"|echohl Normal|echon " \\Theta" echohl Keyword|echo g:atp_imap_leader_1."L"|echohl Normal|echon " \\Lambda " echohl Keyword|echon g:atp_imap_leader_1."M"|echohl Normal|echon " \\Mu" echohl Keyword|echo g:atp_imap_leader_1."N"|echohl Normal|echon " \\Nu " echohl Keyword|echon g:atp_imap_leader_1."P"|echohl Normal|echon " \\Pi" echohl Keyword|echo g:atp_imap_leader_1."S"|echohl Normal|echon " \\Sigma " echohl Keyword|echon g:atp_imap_leader_1."U"|echohl Normal|echon " \\Upsilon" echohl Keyword|echo g:atp_imap_leader_1."F"|echohl Normal|echon " \\Phi " echohl Keyword|echon g:atp_imap_leader_1."Y"|echohl Normal|echon " \\Psi" echohl Keyword|echo g:atp_imap_leader_1."w"|echohl Normal|echon " \\Omega " echohl Keyword|echo g:atp_imap_leader_1."+"|echohl Normal|echon " \\bigcup " echohl Keyword|echon g:atp_imap_leader_1."-"|echohl Normal|echon " \\setminus" echohl Keyword|echo g:atp_imap_leader_1."8"|echohl Normal|echon " \\infty " echohl Keyword|echon g:atp_imap_leader_1."&"|echohl Normal|echon " \\wedge" echohl Keyword|echo g:atp_imap_leader_1."m"|echohl Normal|echon " \\(\\) " echohl Keyword|echon g:atp_imap_leader_1."M"|echohl Normal|echon " \\[\\] " echohl WarningMsg|echon " has value g:atp_imap_leader_3"|echohl Normal endfunction silent call atplib#helpfunctions#HelpMathIMaps() " {{{1 Help Environment IMAPS function! atplib#helpfunctions#HelpEnvIMaps() if exists("g:no_plugin_maps") || exists("g:no_atp_maps") echomsg "[ATP:] ATP maps are turned off" return '' endif let help_envimaps = '' \." ".(g:atp_imap_begin != "" ? g:atp_imap_leader_3.g:atp_imap_begin." \\begin{} " : "" ).(g:atp_imap_end != "" ? g:atp_imap_leader_3.g:atp_imap_end." \\end{}" : "") \."\n ".(g:atp_imap_theorem != "" ? g:atp_imap_leader_3.g:atp_imap_theorem." theorem " : "" ).(g:atp_imap_definition != "" ? g:atp_imap_leader_3.g:atp_imap_definition." definition" : "") \."\n ".(g:atp_imap_proposition != "" ? g:atp_imap_leader_3.g:atp_imap_proposition." proposition " : "").(g:atp_imap_lemma != "" ? g:atp_imap_leader_3.g:atp_imap_lemma." lemma" : "") \."\n ".(g:atp_imap_remark != "" ? g:atp_imap_leader_3.g:atp_imap_remark." remark " : "").(g:atp_imap_corollary != "" ? g:atp_imap_leader_3.g:atp_imap_corollary." corollary" : "") \."\n ".(g:atp_imap_proof != "" ? g:atp_imap_leader_3.g:atp_imap_proof." proof " : "").(g:atp_imap_example != "" ? g:atp_imap_leader_3.g:atp_imap_example." example" : "") \."\n ".(g:atp_imap_note != "" ? g:atp_imap_leader_3.g:atp_imap_note." note " : "") \."\n" \."\n ".(g:atp_imap_enumerate != "" ? g:atp_imap_leader_3.g:atp_imap_enumerate." enumerate " : "").(g:atp_imap_itemize != "" ? g:atp_imap_leader_3.g:atp_imap_itemize." itemize" : "") \."\n ".(g:atp_imap_item != "" ? g:atp_imap_leader_3.g:atp_imap_item." \\item" : "") \."\n" \.(g:atp_imap_align != "" ? "\n ".g:atp_imap_leader_3.g:atp_imap_align." align " : "").(g:atp_imap_equation != "" ? g:atp_imap_leader_3.g:atp_imap_equation." equation" : "") \.(g:atp_imap_gather != "" ? "\n ".g:atp_imap_leader_3.g:atp_imap_gather." gather " : "").(g:atp_imap_split != "" ? g:atp_imap_leader_3.g:atp_imap_split." split" : "") \."\n" \."\n ".(g:atp_imap_flushleft != "" ? g:atp_imap_leader_3.g:atp_imap_flushleft." flushleft " : "").(g:atp_imap_flushright != "" ? g:atp_imap_leader_3.g:atp_imap_flushright." flushright" : "") \."\n ".(g:atp_imap_center != "" ? g:atp_imap_leader_3.g:atp_imap_center." center" : "") \."\n" \.(g:atp_imap_tikzpicture != "" ? "\n ".g:atp_imap_leader_3.g:atp_imap_tikzpicture." tikzpicture " : "").(g:atp_imap_tabular != "" ? g:atp_imap_leader_3.g:atp_imap_tabular." tabular" : "") \."\n" \."\n ".(g:atp_imap_frame != "" ? g:atp_imap_leader_3.g:atp_imap_frame." frame " : "").(g:atp_imap_letter != "" ? g:atp_imap_leader_3.g:atp_imap_letter." letter" : "" ) echohl Title echo "ENVIRONMENT IMAPS" echohl WarningMsg echo " has value g:atp_imap_leader_3" echohl Normal echo help_envimaps endfunction " {{{1 Help VMaps function! atplib#helpfunctions#HelpVMaps() if exists("g:no_plugin_maps") || exists("g:no_atp_maps") echomsg "[ATP:] ATP maps are turned off" return '' endif let l:atp_vmap_text_font_leader = ( exists("maplocalleader") && g:atp_vmap_text_font_leader == "" ? maplocalleader : g:atp_vmap_text_font_leader ) let l:atp_vmap_environment_leader = ( exists("maplocalleader") && g:atp_vmap_environment_leader == "" ? maplocalleader : g:atp_vmap_environment_leader ) let l:atp_vmap_bracket_leader = ( exists("maplocalleader") && g:atp_vmap_bracket_leader == "" ? maplocalleader : g:atp_vmap_bracket_leader ) let l:atp_vmap_big_bracket_leader = ( exists("maplocalleader") && g:atp_vmap_big_bracket_leader =~ "" ? substitute(g:atp_vmap_big_bracket_leader, '', maplocalleader, '') : g:atp_vmap_big_bracket_leader ) let help_vmaps_1 = \ " ".l:atp_vmap_text_font_leader."rm \\textrm{} \\mathrm{}" \."\n ".l:atp_vmap_text_font_leader."em \\emph{} \\mathit{}" \."\n ".l:atp_vmap_text_font_leader."it \\textit{} \\mathit{}" \."\n ".l:atp_vmap_text_font_leader."sf \\textsf{} \\mathsf{}" \."\n ".l:atp_vmap_text_font_leader."tt \\texttt{} \\mathtt{}" \."\n ".l:atp_vmap_text_font_leader."bf \\textbf{} \\mathbf{}" \."\n ".l:atp_vmap_text_font_leader."bb \\textbf{} \\mathbb{}" \."\n ".l:atp_vmap_text_font_leader."bb \\textbf{} \\mathbb{}" \."\n ".l:atp_vmap_text_font_leader."sl \\textsl{}" \."\n ".l:atp_vmap_text_font_leader."sc \\textsc{}" \."\n ".l:atp_vmap_text_font_leader."up \\textup{}" \."\n ".l:atp_vmap_text_font_leader."md \\textmd{}" \."\n ".l:atp_vmap_text_font_leader."un \\underline{} \\underline{}" \."\n ".l:atp_vmap_text_font_leader."ov \\overline{} \\overline{}" \."\n ".l:atp_vmap_text_font_leader."no \\textnormal{} \\mathnormal{}" \."\n ".l:atp_vmap_text_font_leader."cal \\mathcal{}" let help_vmaps_2 = \ " ".l:atp_vmap_environment_leader."C wrap in center environment" \."\n ".l:atp_vmap_environment_leader."L wrap in flushleft environment" \."\n ".l:atp_vmap_environment_leader."R wrap in flushright environment" \."\n ".l:atp_vmap_environment_leader."E wrap in equation environment" \."\n ".l:atp_vmap_environment_leader."A wrap in align environment" let help_vmaps_3 = \ " ".l:atp_vmap_bracket_leader."( (:) ".l:atp_vmap_bracket_leader.") (:)" \."\n ".l:atp_vmap_bracket_leader."[ [:] ".l:atp_vmap_bracket_leader."] [:]" \."\n ".l:atp_vmap_bracket_leader."{ {:} ".l:atp_vmap_bracket_leader."} {:}" \."\n ".l:atp_vmap_bracket_leader."\\{ \\{:\\} ".l:atp_vmap_bracket_leader."\\} \\{:\\}" \."\n m ".repeat(" ",len(l:atp_vmap_bracket_leader))." \\(:\\) M ".repeat(" ",len(l:atp_vmap_bracket_leader))." \\[:\\]" let help_vmaps_4 = \ " ".l:atp_vmap_big_bracket_leader."( \\left(:\\right) ".l:atp_vmap_big_bracket_leader.") \\left(:\\right)" \."\n ".l:atp_vmap_big_bracket_leader."[ \\left[:\\right] ".l:atp_vmap_big_bracket_leader."] \\left[:\\right]" \."\n ".l:atp_vmap_big_bracket_leader."{ \\left{:\\right} ".l:atp_vmap_big_bracket_leader."} \\left{:\\right}" \."\n ".l:atp_vmap_big_bracket_leader."\\{ \\left\\{:\\right\\} ".l:atp_vmap_big_bracket_leader."\\} \\left\\{:\\right\\}" \."\n " \."\n ".l:atp_vmap_text_font_leader."f ".repeat(" ",len(l:atp_vmap_big_bracket_leader))." \\usefont{".g:atp_font_encoding."}{}{}{}\\selectfont" echohl WarningMsg echo " has value g:atp_vmap_text_font_leader" echohl Title echo " KEYMAP TEXT MODE MATH MODE" echohl Normal echo help_vmaps_1 echohl Title echo "MODE INDEPENDENT VMAPS:" echohl WarningMsg echo " has value g:atp_vmap_text_font_leader" echohl Normal echo help_vmaps_2 echohl WarningMsg echo " has value g:atp_vmap_bracket_leader" echohl Normal echo help_vmaps_3 echohl WarningMsg echo " has value g:atp_vmap_big_bracket_leader" echohl Normal echo help_vmaps_4 endfunction " {{{1 Help IMaps " function! atplib#helpfunctions#HelpIMaps() " let tc_imap = maparg(" ", 'i') =~# 'atplib#complete#TabCompletion' ? '' : " \ maparg(" ", 'i') =~# 'atplib#complete#TabCompletion' ? '' : "" " let netc_imap = tc_imap == "" ? "" : tc_imap == "" ? "" : "" " let g:help_imaps = '' " \."\n has value g:atp_vmap_text_font_leader" " \."\n ".tc_imap." "."Completion (expert mode)" " \."\n ".netc_imap." "."Completion (non-expert mode)" " endfunction " silent call atplib#helpfunctions#HelpIMaps() " command! -buffer HelpIMaps :echo atplib#helpfunctions#HelpIMaps() " }}}1 " {{{1 MapSearch function! atplib#helpfunctions#MapSearch(bang,rhs_pattern,...) let mode = ( a:0 >= 1 ? a:1 : '' ) let more = &more setl nomore redir => maps exe "silent ".mode."map" redir end let &l:more = more let list = split(maps, "\n") let pure_rhs_list = map(copy(list), 'matchstr(v:val, ''.\s\+\S\+\s\+\zs.*'')') let rhs_list = ( a:bang == "" ? copy(pure_rhs_list) : \ map(copy(list), 'matchstr(v:val, ''.\s\+\zs\S\+\s\+.*'')') ) if mode == 'i' let j=0 for entry in g:atp_imap_greek_letters \ +g:atp_imap_math_misc \ +g:atp_imap_diacritics \ +g:atp_imap_environments \ +g:atp_imap_math \ +g:atp_imap_fonts let entry_tab = substitute(entry[4], "\t", '', 'g') let entry_tab = substitute(entry_tab, "", '', 'g') if index(pure_rhs_list, entry_tab) == -1 && \ index(pure_rhs_list, "*".entry_tab) == -1 && \ index(pure_rhs_list, "@".entry_tab) == -1 && \ index(pure_rhs_list, "*@".entry_tab) == -1 " Debug: let j+=1 let space = join(map(range(max([12-len(entry[2].entry[3]),1])), "' '"), "") call add(list, 'i '.entry[2].entry[3].space.entry_tab) if a:bang == "" call add(rhs_list, entry_tab) else call add(rhs_list, 'i '.entry[2].entry[3].space.entry_tab) endif endif endfor endif let i = 0 let i_list = [] for rhs in rhs_list if rhs =~? a:rhs_pattern call add(i_list, i) endif let i+=1 endfor let found_maps = [] for i in i_list call add(found_maps, list[i]) endfor if len(found_maps) > 0 echo join(found_maps, "\n") else echohl WarningMsg echo "No matches found" echohl None endif endfunction " }}}1 " vim:fdm=marker:tw=85:ff=unix:noet:ts=8:sw=4:fdc=1 autoload/atplib/motion.vim [[[1 2392 " Author: Marcin Szamotulski " Description: This file contains motion and highlight functions of ATP. " Note: This file is a part of Automatic Tex Plugin for Vim. " Language: tex " Last Change: " All table of contents stuff: variables, functions and commands. " {{{1 __Table_of_Contents__ "--Make TOC ----------------------------- " This makes sense only for latex documents. " " Notes: Makeing toc from aux file: " + is fast " + one gets correct numbers " - one doesn't get line numbers " / the title might be modified thus one can not make a pattern " which works in all situations, while this is important for " :DeleteSection command / " " {{{2 atplib#motion#find_toc_lines function! atplib#motion#find_toc_lines() let toc_lines_nr=[] let toc_lines=[] let pos_saved=getpos(".") let pos=[0,1,1,0] keepjumps call setpos(".",pos) " Pattern: let j=0 for section in keys(g:atp_sections) if j == 0 let pattern=g:atp_sections[section][0] . '' else let pattern=pattern . '\|' . g:atp_sections[section][0] endif let j+=1 endfor " Searching Loop: let line=search(pattern, 'W') while line call add(toc_lines_nr, line) let line=search(pattern, 'W') endwhile keepjumps call setpos(".", pos_saved) for line in toc_lines_nr call add(toc_lines, getline(line)) endfor return toc_lines endfunction " {{{2 atplib#motion#maketoc " this will store information: " { 'linenumber' : ['chapter/section/..', 'sectionnumber', 'section title', '0/1=not starred/starred'] } " a:0 >= 1 avoid using atplib#search#SearchPackage('biblatex') (requires that b:atp_MainFile exists) function! atplib#motion#maketoc(filename,...) let toc={} let search_package = ( a:0 >= 1 ? a:1 : 1 ) " if the dictinary with labels is not defined, define it if !exists("t:atp_labels") let t:atp_labels = {} endif let texfile = [] " getbufline reads only loaded buffers, unloaded can be read from file. let bufname = fnamemodify(a:filename,":t") try let texfile = ( bufexists(bufname) ? getbufline("^" . bufname . "$","1","$") : readfile(a:filename) ) catch /E484:/ echohl Warning echo "File " . a:filename . " not readable." echohl None endtry let texfile_copy = deepcopy(texfile) let true = 1 let bline = 0 " We are not removing the preambule any more. let i = 1 " set variables for chapter/section numbers for section in keys(g:atp_sections) let ind{section} = 0 endfor " make a filter let j = 0 let biblatex = ( search_package ? atplib#search#SearchPackage("biblatex") : 0 ) " When \usepackge{biblatex} do not search for \bibliography{} commands -- they are placed in the preambule. let key_list = ( biblatex ? filter(keys(g:atp_sections), "v:val != 'bibliography'") : keys(g:atp_sections) ) for section in key_list let filter = ( j == 0 ? g:atp_sections[section][0] . '' : filter . '\|' . g:atp_sections[section][0] ) let j+=1 endfor let s:filtered = filter(deepcopy(texfile), 'v:val =~ filter') let line_number = -1 for line in s:filtered let line_number+=1 for section in keys(g:atp_sections) if line =~ g:atp_sections[section][0] if line !~ '^\s*\\\@ empty set, but with " \chapter{title} --> title, solution: the name of " 'Abstract' will be plased, as we know what we have " matched let title = line " This is an attempt to join consecutive lines iff the title is spanned " through more than one line. " s:filtered doesn't is not the same as texfile!!! " we should use texfile, but for this we need to know the true line numbers, " they should be around though. " let open=count(split(title, '\zs'), '{') " let closed=count(split(title, '\zs'), '}') " let i=0 " if open!=closed " echomsg "XXXXXXX" " echomsg title " endif " while open!=closed && line_number+i+2<=len(s:filtered) " echomsg i." ".s:filtered[line_number+i] " let i+=1 " let open+=count(split(s:filtered[line_number+i], '\zs'), '{') " let closed+=count(split(s:filtered[line_number+i], '\zs'), '}') " let title.=" ".substitute(s:filtered[line_number+i], '^\s*', '', '') " endwhile " test if it is a starred version. let star=0 if g:atp_sections[section][1] != 'nopattern' && line =~ g:atp_sections[section][1] let star=1 else let star=0 endif " Problem: If there are two sections with the same title, this " does't work: let idx = index(texfile,line) call remove(texfile, idx) let i = idx let tline = i+bline+1 let bline +=1 " Find Title: let start = stridx(title,'{')+1 let title = strpart(title,start) " we are looking for the maching '}' let l:count = 1 let i=-1 while i<=len(title) let i+=1 if strpart(title,i,1) == '{' let l:count+=1 elseif strpart(title,i,1) == '}' let l:count-=1 endif if l:count == 0 break endif endwhile let title = strpart(title,0,i) let title = substitute(title, '[{}]\|\\titlefont\|\\hfill\=\|\\hrule\|\\[vh]space\s*{[^}]\+}', '', 'g') " Section Number: " if it is not starred version add one to the section number " or it is not an abstract if star == 0 if !(section == 'chapter' && title =~ '^\cabstract$') let ind{section}+=1 endif endif if section == 'part' let indchapter = 0 let indsection = 0 let indsubsection = 0 let indsubsubsection = 0 elseif section == 'chapter' let indsection = 0 let indsubsection = 0 let indsubsubsection = 0 elseif section == 'section' || section == 'frame' let indsubsection = 0 let indsubsubsection = 0 elseif section == 'subsection' let indsubsubsection = 0 endif " Find Short Title: let shorttitle=line let start=stridx(shorttitle,'[')+1 if start == 0 let shorttitle='' else let shorttitle=strpart(shorttitle,start) " we are looking for the maching ']' let l:count=1 let i=-1 while i<=len(shorttitle) let i+=1 if strpart(shorttitle,i,1) == '[' let l:count+=1 elseif strpart(shorttitle,i,1) == ']' let l:count-=1 endif if l:count==0 break endif endwhile let shorttitle = strpart(shorttitle,0,i) endif "ToDo: if section is bibliography (using bib) then find the first " empty line: if section == "bibliography" && line !~ '\\begin\s*{\s*thebibliography\s*}' && !biblatex let idx = tline-1 while texfile_copy[idx] !~ '^\s*$' let idx-= 1 endwhile " " We add 1 as we want the first non blank line, and one more " " 1 as we want to know the line number not the list index " " number: let tline=idx+1 endif " Add results to the dictionary: if biblatex && section != "bibliography" || !biblatex call extend(toc, { tline : [ section, ind{section}, title, star, shorttitle] }) endif endif endif endfor endfor " if exists("t:atp_toc") " call extend(t:atp_toc, { a:filename : toc }, "force") " else " let t:atp_toc = { a:filename : toc } " endif " return t:atp_toc return { a:filename : toc } endfunction " " {{{2 atplib#motion#maketoc_py function! atplib#motion#maketoc_py(filename,...) " filename is supposed to be b:atp_MainFile let s:py_toc = [] python << END import vim import fileinput import sys import re import os import os.path from atplib.atpvim import readlines enc = vim.eval('&enc') # main file file_name = vim.eval("a:filename") # Change the directory to the main file main_dir = os.path.dirname(file_name) if main_dir != '': os.chdir(main_dir) section_pattern = re.compile(r'[^%]*\\(subsection|section|chapter|part)(\*)?\s*(?:\[|{)') shorttitle_pattern = re.compile(r'[^%]*\\(subsection|section|chapter|part)(\*)?\s*\[') subfile_pattern = re.compile(r'[^%]*\\(input|include|subfile)\s*{([^}]*)}') bib_pattern = re.compile(r'[^%]*\\bibliography\s*{([^}]*)}') # the toc list: toc = [] # toc = [ [file_name, line_nr, section_unit, title, short_title, star ], ... ] # after the section number will be computed (depending on section/parts/ ..., # or it might be taken from the aux file) # the list of files: file_list = [[file_name, 'root', 0]] # file_list = [ [ file, subfile, lnr ], ... ] def map_none(val): if val == None: return '' else: return val def file_path(fname): # add tex extension if the file has no extension, if not fname.endswith('.tex'): return os.path.join(main_dir,fname+".tex") else: return os.path.join(main_dir,fname) def find_in_brackets(string, bra='{', ket='}'): # find string in brackets {...}, if bra in string: match = string.split(bra, 1)[1] bopen = 1 for index in xrange(len(match)): if match[index] == bra: bopen += 1 elif match[index] == ket: bopen -= 1 if not bopen: return match[:index] def scan_project(fname): # scan file for section units starting after line start_line, try: flines = readlines(file_path(fname)) length = len(flines) for ind in xrange(length): line = flines[ind] secu = re.match(section_pattern, line) if secu: # Join lines (find titles if they are spread in more than one line): i = 1 while i+ind < length and i < 6: line += flines[ind+i] i+=1 if re.match(shorttitle_pattern, line): short_title = find_in_brackets(line, '[', ']') short_title = re.sub('\s*\n\s*', ' ', short_title) else: short_title = '' title = find_in_brackets(line, '{', '}') if title != None: title = re.sub('\s*\n\s*', ' ', title) else: title = '' # sec_nr is added afterwards. add = [ file_path(fname), ind+1, secu.group(1), title, short_title, secu.group(2)] toc.append(map(map_none,add)) else: subf = re.match(subfile_pattern, line) if subf: file_list.append(map(map_none,[file_path(fname), subf.group(2), ind+1])) scan_project(subf.group(2)) else: bibf = re.match(bib_pattern, line) if bibf: toc.append([file_path(fname), ind+1, 'bibliography', re.sub('\s*,\s*',' ',bibf.group(1)), '', '*']) except IOError: print("[ATP]: cannot open '%s' (cwd='%s')" % (file_path(fname), os.getcwd())) pass # add stuff to the toc list. scan_project(file_name) def check_sec(sec_name,toc): # Check if there is a section sec_name in toc def filter_toc(val): if val[2] == sec_name: return True else: return False return len(filter(filter_toc,toc)) > 0 has_part = check_sec('part', toc) has_chapter = check_sec('chapter', toc) has_section = check_sec('section', toc) if len(toc) > 0: p_nr = 0 c_nr = 0 s_nr = 0 ss_nr = 0 sss_nr = 0 for i in range(0,len(toc)): if toc[i][2] == 'part' and toc[i][5] == '': p_nr += 1 c_nr = 0 s_nr = 0 ss_nr = 0 sss_nr = 0 elif toc[i][2] == 'chapter' and toc[i][5] == '': c_nr += 1 s_nr = 0 ss_nr = 0 sss_nr = 0 elif toc[i][2] == 'section' and toc[i][5] == '': s_nr += 1 ss_nr = 0 sss_nr = 0 elif toc[i][2] == 'subsection' and toc[i][5] == '': ss_nr += 1 sss_nr = 0 elif toc[i][2] == 'subsubsection' and toc[i][5] == '': sss_nr += 1 if toc[i][5] == '*': sec_nr = "*" else: if has_part: if toc[i][2] == 'part': sec_nr = str(p_nr) elif toc[i][2] == 'chapter': sec_nr = str(p_nr)+"."+str(c_nr) elif toc[i][2] == 'section': sec_nr = str(p_nr)+"."+str(c_nr)+"."+str(s_nr) elif toc[i][2] == 'subsection': sec_nr = str(p_nr)+"."+str(c_nr)+"."+str(s_nr)+"."+str(ss_nr) elif toc[i][2] == 'subsubsection': sec_nr = str(p_nr)+"."+str(c_nr)+"."+str(s_nr)+"."+str(ss_nr)+"."+str(sss_nr) elif has_chapter: if toc[i][2] == 'chapter': sec_nr = str(c_nr) elif toc[i][2] == 'section': sec_nr = str(c_nr)+"."+str(s_nr) elif toc[i][2] == 'subsection': sec_nr = str(c_nr)+"."+str(s_nr)+"."+str(ss_nr) elif toc[i][2] == 'subsubsection': sec_nr = str(c_nr)+"."+str(s_nr)+"."+str(ss_nr)+"."+str(sss_nr) elif has_section: if toc[i][2] == 'section': sec_nr = str(s_nr) elif toc[i][2] == 'subsection': sec_nr = str(s_nr)+"."+str(ss_nr) elif toc[i][2] == 'subsubsection': sec_nr = str(s_nr)+"."+str(ss_nr)+"."+str(sss_nr) toc[i] = toc[i]+[sec_nr] if hasattr(vim, 'bindeval'): vtoc = vim.bindeval('s:py_toc') vtoc.extend(toc) else: import json vim.command("let s:py_toc=%s" % json.dumps(toc)) END return { a:filename : s:py_toc } endfunction " {{{2 atplib#motion#buflist function! atplib#motion#buflist() " this names are used in TOC and passed to atplib#motion#maketoc, which " makes a dictionary whose keys are the values of name defined " just below: if !exists("t:atp_toc_buflist") let t:atp_toc_buflist = [] endif if g:atp_python_toc let name = atplib#FullPath(b:atp_MainFile) else let name=resolve(fnamemodify(bufname("%"),":p")) " add an entry to the list t:atp_toc_buflist if it is not there. endif if bufname("") =~ ".tex" && index(t:atp_toc_buflist,name) == -1 if index(t:atp_toc_buflist,name) == -1 call add(t:atp_toc_buflist,name) endif endif return t:atp_toc_buflist endfunction " {{{2 tplib#motion#RemoveFromToC function! atplib#motion#RemoveFromToC(file) if a:file == "" if exists("b:atp_MainFile") let list = filter(copy(t:atp_toc_buflist), "v:val != fnamemodify(b:atp_MainFile, ':p')") else let list = copy(t:atp_toc_buflist) endif if len(list) >= 2 let i=1 for f in list echo "(" . i . ") " . f let i+=1 endfor let which=input("Which file to remove (press for none)") if which == "" return endif let which=t:atp_toc_buflist[which-1] elseif exists("b:atp_MainFile") && len(list) == 1 let which=get(list,0,"") else return endif else let which = fnamemodify(a:file, ":p") endif if which != "" silent! call remove(t:atp_toc_buflist,index(t:atp_toc_buflist, which)) silent! call remove(t:atp_toc,which) endif let winnr=winnr() if index(map(tabpagebuflist(), 'bufname(v:val)'), '__ToC__') != -1 call atplib#motion#TOC("!", 0, 0) endif exe winnr."wincmd w" endfunction function! atplib#motion#RemoveFromToCComp(A, B, C) return join(map(copy(t:atp_toc_buflist), 'fnamemodify(v:val, ":t")'),"\n") endfunction " {{{2 atplib#motion#showtoc function! atplib#motion#showtoc(toc) " this is a dictionary of line numbers where a new file begins. let cline=line(".") " " Open new window or jump to the existing one. " " Remember the place from which we are coming: let t:atp_bufname=atplib#FullPath(expand("%:t")) " let t:atp_winnr=winnr() these are already set by TOC() let bname="__ToC__" let tocwinnr=bufwinnr(bufnr("^".bname."$")) if tocwinnr != -1 " Jump to the existing window. exe tocwinnr . " wincmd w" setl modifiable noreadonly silent exe "%delete _" else " Open new window if its width is defined (if it is not the code below " will put toc in the current buffer so it is better to return. if !exists("t:toc_window_width") let t:toc_window_width = g:atp_toc_window_width endif let labels_winnr=bufwinnr(bufnr("__Labels__")) if labels_winnr != -1 exe labels_winnr."wincmd w" let split_cmd = "above split" else let split_cmd = "vsplit" endif let toc_winnr=bufwinnr(bufnr("__ToC__")) if toc_winnr == -1 let openbuffer="keepalt " . (labels_winnr == -1 ? t:toc_window_width : ''). split_cmd." +setl\\ buftype=nofile\\ modifiable\\ noreadonly\\ noswapfile\\ bufhidden=delete\\ nobuflisted\\ tabstop=1\\ filetype=toc_atp\\ nowrap\\ nonumber\\ norelativenumber\\ winfixwidth\\ nospell\\ cursorline __ToC__" let splitright = &splitright let &splitright = g:atp_splitright keepalt silent exe openbuffer let &splitright = splitright else exe toc_winnr."wincmd w" setl modifiable noreadonly endif endif let number=1 " this is the line number in ToC. " number is a line number relative to the file listed in ToC. " the current line number is linenumber+number " there are two loops: one over linenumber and the second over number. let numberdict = {} let s:numberdict = numberdict unlockvar b:atp_Toc let b:atp_Toc = {} " this variable will be used to set the cursor position in ToC. for openfile in keys(a:toc) call extend(numberdict, { openfile : number }) let part_on=0 let chap_on=0 let chnr=0 let secnr=0 let ssecnr=0 let sssecnr=0 for line in keys(a:toc[openfile]) if a:toc[openfile][line][0] == 'chapter' let chap_on=1 break elseif a:toc[openfile][line][0] == 'part' let part_on=1 endif endfor let sorted = sort(keys(a:toc[openfile]), "atplib#CompareNumbers") let len = len(sorted) " write the file name in ToC (with a full path in paranthesis) call setline(number, ">> ".fnamemodify(openfile,":t")." (".fnamemodify(openfile,":p:h").")") call extend(b:atp_Toc, { number : [ openfile, 1 ]}) let number+=1 let showline = " " for line in sorted call extend(b:atp_Toc, { number : [ openfile, line ] }) let lineidx=index(sorted,line) let nlineidx=lineidx+1 if nlineidx< len(sorted) let nline=sorted[nlineidx] else let nline=line("$") endif " Print ToC lines. if a:toc[openfile][line][0] == 'abstract' || a:toc[openfile][line][2] =~ '^\cabstract$' call setline(number, showline . "- " . "Abstract" ) elseif a:toc[openfile][line][0] =~ 'bibliography\|references' call setline(number, showline . "- " . a:toc[openfile][line][2]) elseif a:toc[openfile][line][0] == 'part' let partnr=a:toc[openfile][line][1] let nr=partnr if a:toc[openfile][line][3] "if it is stared version let nr=substitute(nr,'.',' ','') endif if a:toc[openfile][line][4] != '' call setline (number, " " . a:toc[openfile][line][4]) else call setline (number, " " . a:toc[openfile][line][2]) endif elseif a:toc[openfile][line][0] == 'chapter' let chnr=a:toc[openfile][line][1] let nr=chnr if a:toc[openfile][line][3] "if it is stared version let nr=substitute(nr,'.',' ','') endif if a:toc[openfile][line][4] != '' call setline (number, showline . nr . " " . a:toc[openfile][line][4]) else call setline (number, showline . nr . " " . a:toc[openfile][line][2]) endif elseif a:toc[openfile][line][0] == 'section' || a:toc[openfile][line][0] == 'frame' let secnr=a:toc[openfile][line][1] if chap_on let nr=chnr . "." . secnr if a:toc[openfile][line][3] "if it is stared version let nr=substitute(nr,'.',' ','g') endif if a:toc[openfile][line][4] != '' call setline (number, showline . nr . " " . a:toc[openfile][line][4]) else call setline (number, showline . nr . " " . a:toc[openfile][line][2]) endif else let nr=secnr if a:toc[openfile][line][3] "if it is stared version let nr=substitute(nr,'.',' ','g') endif if a:toc[openfile][line][4] != '' call setline (number, showline . nr . " " . a:toc[openfile][line][4]) else call setline (number, showline . nr . " " . a:toc[openfile][line][2]) endif endif elseif a:toc[openfile][line][0] == 'subsection' let ssecnr=a:toc[openfile][line][1] if chap_on let nr=chnr . "." . secnr . "." . ssecnr if a:toc[openfile][line][3] "if it is stared version let nr=substitute(nr,'.',' ','g') endif if a:toc[openfile][line][4] != '' call setline (number, showline . nr . " " . a:toc[openfile][line][4]) else call setline (number, showline . nr . " " . a:toc[openfile][line][2]) endif else let nr=secnr . "." . ssecnr if a:toc[openfile][line][3] "if it is stared version let nr=substitute(nr,'.',' ','g') endif if a:toc[openfile][line][4] != '' call setline (number, showline . nr . " " . a:toc[openfile][line][4]) else call setline (number, showline . nr . " " . a:toc[openfile][line][2]) endif endif elseif a:toc[openfile][line][0] == 'subsubsection' let sssecnr=a:toc[openfile][line][1] if chap_on let nr=chnr . "." . secnr . "." . sssecnr if a:toc[openfile][line][3] "if it is stared version let nr=substitute(nr,'.',' ','g') endif if a:toc[openfile][line][4] != '' call setline(number, showline . nr . " " . a:toc[openfile][line][4]) else call setline(number, showline . nr . " " . a:toc[openfile][line][2]) endif else let nr=secnr . "." . ssecnr . "." . sssecnr if a:toc[openfile][line][3] "if it is stared version let nr=substitute(nr,'.',' ','g') endif if a:toc[openfile][line][4] != '' call setline (number, showline . nr . " " . a:toc[openfile][line][4]) else call setline (number, showline . nr . " " . a:toc[openfile][line][2]) endif endif else let nr="" endif let number+=1 endfor endfor " set the cursor position on the correct line number. " first get the line number of the begging of the ToC of t:atp_bufname " (current buffer) " let t:numberdict=numberdict "DEBUG " t:atp_bufname is the full path to the current buffer. let num = get(numberdict, t:atp_bufname, 'no_number') if num == 'no_number' setl nomodifiable return endif let sorted = sort(keys(a:toc[t:atp_bufname]), "atplib#CompareNumbers") let t:sorted = sorted for line in sorted if cline>=line let num+=1 endif keepjumps call setpos('.',[bufnr(""),num,1,0]) endfor " Help Lines: if search('" jump and close', 'nW') == 0 call append('$', [ '', \ '" _ set', \ '" jump', \ '" jump and close', \ '" s jump and split', \ '" y or c yank label', \ '" p paste label', \ '" q close', \ '" zc fold section[s]', \ '" ^j go to next chapter', \ '" ^k go to previous chapter', \ '" J go to next project', \ '" K go to previous project', \ '" :[range]Fold', \ '" :YankSection', \ '" :DeleteSection', \ '" :PasteSection[!]', \ '" :SectionStack', \ '" :Undo' ]) endif setl nomodifiable lockvar 3 b:atp_Toc endfunction " {{{2 atplib#motion#show_pytoc function! atplib#motion#show_pytoc(toc) " this is a dictionary of line numbers where a new file begins. let cline=line(".") " " Open new window or jump to the existing one. " " Remember the place from which we are coming: let t:atp_bufname=atplib#FullPath(expand("%:t")) let bname="__ToC__" let tabpagebufdict = {} for bufnr in tabpagebuflist() if fnamemodify(bufname(bufnr), ":t") != "" let tabpagebufdict[fnamemodify(bufname(bufnr), ":t")]=bufnr endif endfor if index(keys(tabpagebufdict), "__ToC__") != -1 let tocwinnr = bufwinnr(tabpagebufdict["__ToC__"]) else let tocwinnr = -1 endif if tocwinnr != -1 " Jump to the existing window. exe tocwinnr . " wincmd w" setl modifiable noreadonly silent exe "%delete _" else " Open new window if its width is defined (if it is not the code below " will put toc in the current buffer so it is better to return. if !exists("t:toc_window_width") let t:toc_window_width = g:atp_toc_window_width endif let labels_winnr=bufwinnr(bufnr("__Labels__")) if labels_winnr != -1 exe labels_winnr."wincmd w" let split_cmd = "above split" else let split_cmd = "vsplit" endif let toc_winnr=bufwinnr(bufnr("__ToC__")) if toc_winnr == -1 let openbuffer="keepalt " . (labels_winnr == -1 ? t:toc_window_width : ''). split_cmd." +setl\\ buftype=nofile\\ modifiable\\ noreadonly\\ noswapfile\\ bufhidden=delete\\ nobuflisted\\ tabstop=1\\ filetype=toc_atp\\ nowrap\\ nonumber\\ norelativenumber\\ winfixwidth\\ nospell\\ cursorline __ToC__" let splitright = &splitright let &splitright = g:atp_splitright keepalt silent exe openbuffer let &splitright = splitright else exe toc_winnr."wincmd w" setl modifiable noreadonly endif endif let number=1 " this is the line number in ToC. " number is a line number relative to the file listed in ToC. " the current line number is linenumber+number " there are two loops: one over linenumber and the second over number. let numberdict = {} let s:numberdict = numberdict unlockvar b:atp_Toc let b:atp_Toc = {} " this variable will be used to set the cursor position in ToC. for openfile in keys(a:toc) call extend(numberdict, { openfile : number }) " write the file name in ToC (with a full path in paranthesis) call setline(number, ">> ".fnamemodify(openfile,":t")." (".fnamemodify(openfile,":p:h").")") " openfile is the project name call extend(b:atp_Toc, { number : [ openfile, 1, openfile ]}) let number+=1 let lineidx = -1 for line_list in a:toc[openfile] let line = line_list[1] call extend(b:atp_Toc, { number : [ line_list[0], line, openfile ] }) let lineidx+=1 let nlineidx=lineidx+1 if nlineidx < len(a:toc[openfile]) let nline=a:toc[openfile][nlineidx][1] else let nline=line("$") endif let showline = ' ' " Print ToC lines. if line_list[2] == 'abstract' || line_list[3] =~ '^\cabstract$' call setline(number, showline . "- " . "Abstract" ) elseif line_list[2] =~ 'bibliography\|references' call setline (number, showline . "- bib:" . line_list[3]) else let secnr=get(line_list,6,"XXX") " there might not bee section number in the line_list let nr=secnr if line_list[4] != '' call setline (number, showline . nr . " " . line_list[4]) else call setline (number, showline . nr . " " . line_list[3]) endif endif let number+=1 endfor endfor " set the cursor position on the correct line number. " first get the line number of the begging of the ToC of t:atp_bufname " (current buffer) let MainFile = atplib#FullPath(getbufvar(bufnr(t:atp_bufname), "atp_MainFile")) let num = get(s:numberdict, MainFile, 'no_number') if num == 'no_number' return endif let sorted = t:atp_pytoc[MainFile] let num_list=[0] let f_test = ( t:atp_bufname == atplib#FullPath(getbufvar(bufnr(t:atp_bufname), "atp_MainFile")) ) for ind in range(0,len(sorted)-1) let line_l = sorted[ind] if g:atp_python_toc " t:atp_bufname buffer from which :TOC was invoked. let f_test_p = f_test let f_test = ( !f_test && t:atp_bufname == line_l[0] ? 1 : f_test ) if f_test && !f_test_p call add(num_list, ind+1) endif if t:atp_bufname == line_l[0] && (str2nr(cline) >= str2nr(line_l[1])) call add(num_list, ind+1) endif else let line = line_l if cline>=line let num+=1 else break endif endif endfor if g:atp_python_toc let num = max(num_list)+1 keepjumps call setpos('.', [0,0,0,0]) keepjumps call search('^>> '.escape(fnamemodify(MainFile, ":t"), '.\/').'\s\+(.*)\s*$', 'cW') call cursor(line(".")+(num-1),1) else keepjumps call setpos('.',[bufnr(""),num,1,0]) endif " Help Lines: if search('" jump and close', 'nW') == 0 call append('$', [ '', \ '" _ set', \ '" jump', \ '" jump and close', \ '" s jump and split', \ '" y or c yank label', \ '" p paste label', \ '" q close', \ '" ^j go to next chapter', \ '" ^k go to previous chapter', \ '" J go to next project', \ '" K go to previous project', \ '" :YankSection', \ '" :DeleteSection', \ '" :PasteSection[!]', \ '" :SectionStack', \ '" :Undo' ]) " \ '" zc fold section[s]', " \ '" :[range]Fold', endif setl nomodifiable setl fdm=expr normal! zMzv lockvar 3 b:atp_Toc endfunction " {{{2 atplib#motion#ToCbufnr() " This function returns toc buffer number if toc window is not open returns -1. function! atplib#motion#ToCbufnr() let tabpagebufdict = {} for bufnr in tabpagebuflist() if fnamemodify(bufname(bufnr), ":t") != "" " For QuickFix bufname is an empty string: let tabpagebufdict[fnamemodify(bufname(bufnr), ":t")]=bufnr endif endfor if index(keys(tabpagebufdict), "__ToC__") != -1 return tabpagebufdict["__ToC__"] else let bufnames = [] for bufnr in range(1,bufnr('$')) if bufexists(bufnr) let bname = bufname(bufnr) if !empty(bname) call add(bufnames, [fnamemodify(bname, ":t"), bufnr]) endif endif endfor call filter(bufnames, 'v:val[0] == "__ToC__"') if !empty(bufnames) return bufnames[0][1] else return -1 endif endif endfunction " atplib#motion#UpdateToCLine {{{2 function! atplib#motion#UpdateToCLine(...) let time = reltime() if !g:atp_UpdateToCLine return endif let toc_bufnr = atplib#motion#ToCbufnr() if index(tabpagebuflist(), toc_bufnr) == -1 return endif let check_line = (a:0>=1 ? a:1 : -1) if toc_bufnr == -1 || check_line != -1 && \ getline(line(".")+check_line) !~# '\\\%(part\|chapter\|\%(sub\)\{0,2}section\)\s*{' return endif let cline = line(".") let cbufnr = bufnr("%") let cwinnr = winnr() exe "keepalt" bufwinnr(toc_bufnr)."wincmd w" let MainFile = atplib#FullPath(getbufvar(bufnr(t:atp_bufname), "atp_MainFile")) if g:atp_python_toc let num = get(s:numberdict, MainFile, 'no_number') else let num = get(s:numberdict, t:atp_bufname, 'no_number') endif if num == 'no_number' exe cwinnr."wincmd w" return endif let lazyredraw = &lazyredraw let eventignore=&eventignore set lazyredraw set eventignore=all if g:atp_python_toc let sorted = t:atp_pytoc[MainFile] else let sorted = sort(keys(t:atp_toc[t:atp_bufname]), "atplib#CompareNumbers") endif let num_list = [0] let f_test = ( t:atp_bufname == atplib#FullPath(getbufvar(bufnr(t:atp_bufname), "atp_MainFile")) ) for ind in range(0,len(sorted)-1) let line_l = sorted[ind] if g:atp_python_toc " t:atp_bufname buffer from which :TOC was invoked. let f_test_p = f_test let f_test = ( !f_test && t:atp_bufname == line_l[0] ? 1 : f_test ) if f_test && !f_test_p call add(num_list, ind+1) endif if t:atp_bufname == line_l[0] && (str2nr(cline) >= str2nr(line_l[1])) call add(num_list, ind+1) endif else let line = line_l if cline>=line let num+=1 else break endif endif endfor let savedview = winsaveview() if g:atp_python_toc let savedview = winsaveview() let num = max(num_list)+1 keepjumps call setpos('.', [0,0,0,0]) keepjumps call search('^'.escape(fnamemodify(MainFile, ":t"), '.\/').'\s\+(.*)\s*$', 'cW') call cursor(line(".")+(num-1),1) else keepjumps call setpos('.',[bufnr(""),num,1,0]) endif if line(".") == savedview['lnum'] call winrestview(savedview) endif call atplib#tools#CursorLine() exe cwinnr."wincmd w" let &eventignore = eventignore let &lazyredraw = lazyredraw let g:time_UpdateTocLine = reltimestr(reltime(time)) endfunction " This is User Front End Function " atplib#motion#TOC {{{2 function! atplib#motion#TOC(bang,...) let time = reltime() " skip generating t:atp_toc list if it exists and if a:0 != 0 if &l:filetype != 'tex' && &l:filetype != 'toc_atp' echoerr "Wrong 'filetype'. This command works only for latex documents." return endif if a:0 == 0 call atplib#motion#buflist() endif let search_package = ( a:0 >= 2 ? a:2 : 1 ) " avoid using atplib#search#SearchPackage() in atplib#motion#maketoc() " for each buffer in t:atp_toc_buflist (set by atplib#motion#buflist) if ( a:bang == "!" || !exists("t:atp_toc") || g:atp_python_toc ) if !g:atp_python_toc let t:atp_toc = {} else let t:atp_pytoc = {} endif for buffer in t:atp_toc_buflist if g:atp_python_toc update call extend(t:atp_pytoc, atplib#motion#maketoc_py(buffer,search_package)) else call extend(t:atp_toc, atplib#motion#maketoc(buffer,search_package)) endif endfor endif if g:atp_python_toc call atplib#motion#show_pytoc(t:atp_pytoc) else call atplib#motion#showtoc(t:atp_toc) endif let g:time_TOC = reltimestr(reltime(time)) endfunction nnoremap ATP_TOC :call atplib#motion#TOC("") " This finds the name of currently eddited section/chapter units. " {{{2 atplib#motion#NearestSection " This function finds the section name of the current section unit with " respect to the dictionary a:section={ 'line number' : 'section name', ... } " it returns the [ section_name, section line, next section line ] function! atplib#motion#NearestSection(section) let cline=line('.') let sorted=sort(keys(a:section), "atplib#CompareNumbers") let x=0 while x=1 && x < len(sorted) let section_name=a:section[sorted[x-1]] return [section_name, sorted[x-1], sorted[x]] elseif x>=1 && x >= len(sorted) let section_name=a:section[sorted[x-1]] return [section_name,sorted[x-1], line('$')] elseif x<1 && x < len(sorted) " if we are before the first section return the empty string return ['','0', sorted[x]] elseif x<1 && x >= len(sorted) return ['', '0', line('$')] endif endfunction " {{{2 atplib#motion#ctoc function! atplib#motion#ctoc() if &l:filetype != 'tex' || expand("%:e") != 'tex' return [] endif " resolve the full path: let t:atp_bufname = expand("%:p") " if t:atp_toc(t:atp_bufname) exists use it otherwise make it if !exists("t:atp_toc") || !has_key(t:atp_toc, t:atp_bufname) if !exists("t:atp_toc") let t:atp_toc = {} endif call extend(t:atp_toc, atplib#motion#maketoc(t:atp_bufname)) endif " l:count where the preambule ends let buffer=getbufline(bufname("%"),"1","$") let i=0 let line=buffer[0] while line !~ '\\begin\s*{document}' && i < len(buffer) let line=buffer[i] if line !~ '\\begin\s*{document}' let i+=1 endif endwhile " if we are before the '\\begin{document}' line: if line(".") <= i let return=['Preambule'] return return endif let chapter={} let section={} let subsection={} for key in keys(t:atp_toc[t:atp_bufname]) if t:atp_toc[t:atp_bufname][key][0] == 'chapter' " return the short title if it is provided if t:atp_toc[t:atp_bufname][key][4] != '' call extend(chapter, {key : t:atp_toc[t:atp_bufname][key][4]},'force') else call extend(chapter, {key : t:atp_toc[t:atp_bufname][key][2]},'force') endif elseif t:atp_toc[t:atp_bufname][key][0] == 'section' " return the short title if it is provided if t:atp_toc[t:atp_bufname][key][4] != '' call extend(section, {key : t:atp_toc[t:atp_bufname][key][4]},'force') else call extend(section, {key : t:atp_toc[t:atp_bufname][key][2]},'force') endif elseif t:atp_toc[t:atp_bufname][key][0] == 'subsection' " return the short title if it is provided if t:atp_toc[t:atp_bufname][key][4] != '' call extend(subsection, {key : t:atp_toc[t:atp_bufname][key][4]},'force') else call extend(subsection, {key : t:atp_toc[t:atp_bufname][key][2]},'force') endif endif endfor " Remove $ from chapter/section/subsection names to save the space. let chapter_name=substitute(atplib#motion#NearestSection(chapter)[0],'\$\|\\(\|\\)','','g') let chapter_line=atplib#motion#NearestSection(chapter)[1] let chapter_nline=atplib#motion#NearestSection(chapter)[2] let section_name=substitute(atplib#motion#NearestSection(section)[0],'\$\|\\(\|\\)','','g') let section_line=atplib#motion#NearestSection(section)[1] let section_nline=atplib#motion#NearestSection(section)[2] let subsection_name=substitute(atplib#motion#NearestSection(subsection)[0],'\$\|\\(\|\\)','','g') let subsection_line=atplib#motion#NearestSection(subsection)[1] let subsection_nline=atplib#motion#NearestSection(subsection)[2] let names = [ chapter_name ] if (section_line+0 >= chapter_line+0 && section_line+0 <= chapter_nline+0) call add(names, section_name) else call add(names, '') endif if subsection_line+0 >= section_line+0 && subsection_line+0 <= section_nline+0 call add(names, subsection_name) else call add(names, '') endif return names endfunction " Labels Front End Finction. The search engine/show function are in autoload/atplib.vim script " library. " }}}1 " {{{1 atplib#motion#Labels " a:bang = "!" do not regenerate labels if not necessary function! atplib#motion#Labels(bang) let t:atp_bufname = expand("%:p") let error = ( exists("b:atp_TexReturnCode") ? b:atp_TexReturnCode : 0 ) let atp_MainFile = atplib#FullPath(b:atp_MainFile) " Generate the dictionary with labels if a:bang == "" || ( a:bang == "!" && !exists("t:atp_labels") ) || \ ( a:bang == "!" && exists("t:atp_labels") && get(t:atp_labels, atp_MainFile, []) == [] ) let [ t:atp_labels, b:ListOfFiles ] = atplib#tools#generatelabels(atp_MainFile, 1) endif " Show the labels in seprate window call atplib#tools#showlabels([ t:atp_labels, map(extend([b:atp_MainFile], copy(b:ListOfFiles)), 'atplib#FullPath(v:val)')]) if error echohl WarningMsg redraw echomsg "[ATP:] the compelation contains errors, aux file might be not appriopriate for labels window." echohl None endif endfunction nnoremap ATP_Labels :call atplib#motion#Labels("") " atplib#motion#GotoLabel {{{1 " a:bang = "!" do not regenerate labels if not necessary " This is developed for one tex project in a vim. function! atplib#motion#GotoLabel(bang,...) let alabel = ( a:0 == 0 ? "" : a:1 ) let atp_MainFile = atplib#FullPath(b:atp_MainFile) " Generate the dictionary with labels if a:bang == "" || ( a:bang == "!" && ( !exists("b:ListOfFiles") || !exists("t:atp_labels") ) ) let [ t:atp_labels, b:ListOfFiles ] = atplib#tools#generatelabels(atp_MainFile, 1) endif let matches = [] for file in keys(t:atp_labels) if index(b:ListOfFiles, fnamemodify(file, ":t")) != -1 || index(b:ListOfFiles, file) != -1 || file == atplib#FullPath(b:atp_MainFile) for label in t:atp_labels[file] if label[1] =~ alabel || label[2] =~ '^'.alabel call add(matches, extend([file], label)) endif endfor endif endfor if len(matches) == 0 redraw echohl WarningMsg echomsg "[ATP:] no matching label" echohl None return 1 elseif len(matches) == 1 let file=matches[0][0] let line=matches[0][1] else " if len(keys(filter(copy(b:TypeDict), 'v:val == "input"'))) == 0 let mlabels=map(copy(matches), "[(index(matches, v:val)+1).'.', v:val[2],v:val[3]]") " else " Show File from which label comes " The reason to not use this is as follows: " it only matters for project files, which probably have many " labels, so it's better to make the list as concise as possible " let mlabels=map(copy(matches), "[(index(matches, v:val)+1).'.', v:val[2], v:val[3], fnamemodify(v:val[0], ':t')]") " let file=1 " endif echohl Title echo "Which label to choose?" echohl None " let mlabels= ( file ? extend([[' nr', 'LABEL', 'LABEL NR', 'FILE']], mlabels) : extend([[' nr', 'LABEL', 'LABEL NR']], mlabels) ) for row in atplib#FormatListinColumns(atplib#Table(mlabels, [1,2]),2) echo join(row) endfor let nr = input("Which label to choose? type number and press ")-1 if nr < 0 || nr >= len(matches) return endif let file=matches[nr][0] let line=matches[nr][1] endif " Check if the buffer is loaded. if bufloaded(file) execute "b " . file call cursor(line,1) else execute "edit " . file call cursor(line,1) endif endfunction " atplib#motion#GotoLabelCompletion {{{1 function! atplib#motion#GotoLabelCompletion(ArgLead, CmdLine, CursorPos) let atp_MainFile = atplib#FullPath(b:atp_MainFile) " Generate the dictionary with labels (only if it doesn't exist) if !exists("t:atp_labels") || t:atp_labels == {} || !exists("b:ListOfFiles") || a:CmdLine !~# '^GotoLabel!' let [ t:atp_labels, b:ListOfFiles ] = atplib#tools#generatelabels(atp_MainFile, 1) " It would be nice to delete the ! from the cmdline after this step. There are " only getcmdline(), getcmdpos() and setcmdpos() functions available. let cmd_line=substitute(getcmdline(), "GotoLabel!", "GotoLabel", "") endif let labels=[] for file in keys(t:atp_labels) if index(b:ListOfFiles, fnamemodify(file, ":t")) != -1 || index(b:ListOfFiles, file) != -1 || file == atplib#FullPath(b:atp_MainFile) call extend(labels, map(deepcopy(t:atp_labels)[file], 'v:val[1]')) call extend(labels, map(deepcopy(t:atp_labels)[file], 'v:val[2]')) endif endfor call filter(labels, "v:val !~ '^\s*$' && v:val =~ a:ArgLead ") return map(labels, "v:val.'\\>'") endfunction " atplib#motion#LatexTags {{{1 function! atplib#motion#LatexTags(bang,...) " a:1 == 1 : silent if stridx(expand("%"), 'fugitive://') == 0 return endif let silent = ( ( a:0 ? a:1 : 0 ) ? ' --silent ' : ' ' ) let hyperref_cmd = ( atplib#search#SearchPackage("hyperref") ? " --hyperref " : "" ) if has("clientserver") let servername = " --servername ".v:servername." " let progname = " --progname ".v:progname." " else let servername = "" let progname = "" endif let bibtags = ( a:bang == "" ? " --bibtags " : "" ) " Write file: call atplib#write('nobackup') let latextags=split(globpath(&rtp, "ftplugin/ATP_files/latextags.py"), "\n")[0] let files=join( \ map([b:atp_MainFile]+filter(copy(keys(b:TypeDict)), "b:TypeDict[v:val] == 'input'"), 'atplib#FullPath(v:val)') \ , ";") if len(filter(copy(keys(b:TypeDict)), "b:TypeDict[v:val] == 'bib'")) >= 1 let bibfiles=join(filter(copy(keys(b:TypeDict)), "b:TypeDict[v:val] == 'bib'"), ";") let bib= " --bibfiles ".shellescape(bibfiles) else let bib= " --bibtags_env " endif let dir = expand("%:p:h") if atplib#search#SearchPackage("biblatex") let cite = " --cite biblatex " elseif atplib#search#SearchPackage("natbib") let cite = " --cite natbib " else let cite = " " endif let cmd=g:atp_Python." ".shellescape(latextags). \ " --files ".shellescape(files). \ " --auxfile ".shellescape(atplib#joinpath(expand(b:atp_OutDir), fnamemodify(b:atp_MainFile, ":t:r").".aux")). \ " --dir ".shellescape(dir). \ bib . cite . silent . \ hyperref_cmd . servername . progname . bibtags . " &" if g:atp_debugLatexTags let g:cmd=cmd endif call system(cmd) endfunction "{{{1 atplib#motion#GotoDestination function! atplib#motion#GotoNamedDestination(destination) if b:atp_Viewer !~ '^\s*xpdf\>' echomsg "[ATP:] this only works with Xpdf viewer." return 0 endif let cmd='xpdf -remote '.b:atp_XpdfServer.' -exec gotoDest\("'.a:destination.'"\)' call system(cmd) endfunction function! atplib#motion#FindDestinations() let files = [ b:atp_MainFile ] if !exists("b:TypeDict") call TreeOfFiles(b:atp_MainFile) endif for file in keys(b:TypeDict) if b:TypeDict[file] == 'input' call add(files, file) endif endfor let saved_loclist = getloclist(0) exe 'lvimgrep /\\hypertarget\>/gj ' . join(map(files, 'fnameescape(v:val)'), ' ') let dests = [] let loclist = copy(getloclist(0)) call setloclist(0, saved_loclist) for loc in loclist let destname = matchstr(loc['text'], '\\hypertarget\s*{\s*\zs[^}]*\ze}') call add(dests, destname) endfor return dests endfunction function! atplib#motion#CompleteDestinations(ArgLead, CmdLine, CursorPos) let dests=atplib#motion#FindDestinations() return join(dests, "\n") endfunction " Motion functions through environments and sections. " atplib#motion#GotoEnvironment {{{1 " which name is given as the argument. Do not wrap " around the end of the file. function! atplib#motion#GotoEnvironment(flag,count,...) " Options : let env_name = ( a:0 >= 1 && a:1 != "" ? a:1 : '[^}]*' ) if env_name == 'part' if a:flag =~ 'b' exe a:count.'PPart' return else exe a:count.'NPart' return endif elseif env_name == 'chapter' if a:flag =~ 'b' exe a:count.'PChap' return else exe a:count.'NChap' return endif elseif env_name == 'section' if a:flag =~ 'b' exe a:count.'PSec' return else exe a:count.'NSec' return endif elseif env_name == 'subsection' if a:flag =~ 'b' exe a:count.'PSSec' return else exe a:count.'NSSec' return endif elseif env_name == 'subsubsection' if a:flag =~ 'b' exe a:count.'PSSSec' return else exe a:count.'NSSSec' return endif endif let flag = a:flag " Set the search tool : " Set the pattern : if env_name == 'math' let pattern = '\m\%(\(\\\@ 1 " the 's' flag should be used only in the first search. let flag=substitute(flag, 's', '', 'g') endif if g:atp_mapNn let search_cmd = "S /" let search_cmd_e= "/ " . flag else let search_cmd = "silent! call search('" let search_cmd_e= "','" . flag . "')" endif if a:flag !~# 'b' execute search_cmd . pattern . search_cmd_e if getline(".")[col(".")-1] == "$" if ( get(split(getline("."), '\zs'), col(".")-1, '') == "$" && get(split(getline("."), '\zs'), col("."), '') == "$" ) "check $$ let rerun = !atplib#complete#CheckSyntaxGroups(['texMathZoneY'], line("."), col(".")+1 ) elseif get(split(getline("."), '\zs'), col(".")-1, '') == "$" "check $ let rerun = !atplib#complete#CheckSyntaxGroups(['texMathZoneX', 'texMathZoneY'], line("."), col(".") ) endif if rerun silent! execute search_cmd . pattern . search_cmd_e endif endif else " a:flag =~# 'b' execute search_cmd . pattern_zs . search_cmd_e call search(pattern, 'bc', line(".")) if getline(".")[col(".")-1] == "$" if ( get(split(getline("."), '\zs'), col(".")-1, '') == "$" && get(split(getline("."), '\zs'), col(".")-2, '') == "$" ) "check $$ let rerun = atplib#complete#CheckSyntaxGroups(['texMathZoneY'], line("."), col(".")-3 ) elseif get(split(getline("."), '\zs'), col(".")-1, '') == "$" "check $ let rerun = atplib#complete#CheckSyntaxGroups(['texMathZoneX', 'texMathZoneY'], line("."), col(".")-2 ) endif if rerun silent! execute search_cmd . pattern_zs . search_cmd_e call search(pattern, 'bc', line(".")) endif endif endif endfor call atplib#motion#UpdateToCLine() silent! call histadd("search", pattern) silent! let @/ = pattern return "" endfunction " atplib#motion#GotoFrame {{{1 function! atplib#motion#GotoFrame(f, count) let lz=&lazyredraw set lazyredraw if a:f == "backward" call atplib#motion#GotoEnvironment('bsW', a:count, 'frame') else call atplib#motion#GotoEnvironment('sW', a:count, 'frame') endif normal! zt let &lz=lz endfunction nnoremap NextFrame :call atplib#motion#GotoFrame('forward', v:count1) nnoremap PreviousFrame :call atplib#motion#GotoFrame('backward', v:count1) " atplib#motion#JumptoEnvironment {{{1 " Good for going through all \begin:\end pairs in a given envionrment, without " visiting child nodes. function! atplib#motion#JumptoEnvironment(forward, ...) let cnt = (a:0>=1 ? a:1 : 1) k` call setpos("''", getpos(".")) let lazyredraw=&l:lazyredraw set lazyredraw if a:forward " let min = max([0, col(".")-6]) " let max = min([col(".")+5, len(getline(line(".")))]) " if getline(line("."))[(min):(max)] =~ '\\begin\>' " If on \begin moved to the start of it. call search('\\begin\>\(.*\\end\>\)\@!', 'b', line('.')) " endif for i in range(cnt) if !i && getline(".")[col(".")-1:] !~ '^\\begin\s*{' call search('^\%([^%]\|\\%\)*\zs\\begin\>', 'W') else call searchpair('\\begin\s*{\s*\%(document\>\)\@!', '', '\\end\s*{\s*\%(document\>\)\@!', 'W') call search('^\%([^%]\|\\%\)*\zs\\begin\>', 'W') endif endfor else " let min = max([0, col(".")-6]) " let max = min([col(".")+5, len(getline(line(".")))]) " if getline(line("."))[(min):(max)] =~ '\\begin\>' " If on \begin moved to the start of it. call search('\\begin\>\(.*\\end\>\)\@!', 'b', line('.')) " endif for i in range(cnt) call search('^\%([^%]\|\\%\)*\zs\\\%(begin\|end\)\>', 'Wb') if getline(".")[col(".")-1:] =~ '^\\end\s*{' call LaTeXBox_JumpToMatch('n', 0, 0) endif endfor endif let &l:lazyredraw=lazyredraw endfunction " atplib#motion#FastJumptoEnvironment {{{1 " Good for going up one level omittig current nodes. function! atplib#motion#FastJumptoEnvironment(forward, ...) let cnt = (a:0>=1 ? a:1 : 1) k` call setpos("''", getpos(".")) let lazyredraw=&l:lazyredraw set lazyredraw if a:forward call search('\\begin\>\(.*\\end\>\)\@!', 'b', line('.')) for i in range(cnt) let ppos = getpos(".")[1:2] call searchpair('\\begin\s*\zs{\s*\%(document\>\)\@!', '', '\\end\s*{\s*\%(document\>\)\@!', 'W') call search('\\begin\>\(.*\\end\>\)\@!', 'b', line('.')) let pos = getpos(".")[1:2] if pos == ppos call searchpair('\\begin\s*{\s*\%(document\>\)\@!', '', '\\end\s*{\s*\%(document\>\)\@!', 'W') endif call search('^\%([^%]\|\\%\)*\zs\\begin\>', 'W') endfor else call search('\\begin\>\(.*\\end\>\)\@!', 'b', line('.')) for i in range(cnt) let ppos = getpos(".")[1:2] call searchpair('\\begin\s*{\s*\zs\%(document\>\)\@!', '', '\\end\s*{\s*\%(document\>\)\@!', 'Wb') call search('\\begin', 'b', line('.')) let pos = getpos(".")[1:2] if ppos == pos call search('\\end\s*{\s*\%(document\>\)\@!', 'Wb') if pos != getpos(".")[1:2] call LaTeXBox_JumpToMatch('n', 0, 0) endif endif endfor endif let &l:lazyredraw=lazyredraw endfunction " atplib#motion#JumpOut {{{1 function! atplib#motion#JumpOut(forward,count) k` call setpos("''", getpos(".")) let lazyredraw=&l:lazyredraw set lazyredraw if a:forward let flags = 'W' " let limit = line(".")+g:atp_completion_limits[3] else let flags = 'Wb' " let limit = max([1, line(".")-g:atp_completion_limits[3]]) endif let ppos = getpos(".")[1:2] let pos = searchpairpos('\\begin\s*{\s*\%(document\>\)\@!', '', '\\end\s*{\s*\%(document\>\)\@!', flags) " , '', limit) for i in range(a:count-1) let ppos = pos if a:forward let limit = line(".")+g:atp_completion_limits[3] else let limit = max([1, line(".")-g:atp_completion_limits[3]]) endif let pos = searchpairpos('\\begin\s*{\s*\%(document\>\)\@!', '', '\\end\s*{\s*\%(document\>\)\@!', flags) " , '', limit) if pos == ppos break endif endfor let &l:lazyredraw=lazyredraw endfunction " atplib#motion#FastJumpOut {{{1 function! atplib#motion#FastJumpOut(forward) k` let s_pos = getpos(".")[1:2] let lazyredraw=&l:lazyredraw set lazyredraw if a:forward let flags = 'W' let limit = line(".")+g:atp_completion_limits[3] else let flags = 'Wb' let limit = max([1, line(".")-g:atp_completion_limits[3]]) endif let ppos = getpos(".")[1:2] let pos = searchpairpos('\\begin\s*{\s*\%(document\>\)\@!', '', '\\end\s*{\s*\%(document\>\)\@!', flags, '', limit) while pos != ppos let ppos = pos if a:forward let limit = line(".")+g:atp_completion_limits[3] else let limit = max([1, line(".")-g:atp_completion_limits[3]]) endif let pos = searchpairpos('\\begin\s*{\s*\%(document\>\)\@!', '', '\\end\s*{\s*\%(document\>\)\@!', flags, '', limit) endwhile if getpos(".")[1:2] == s_pos echohl ErrorMsg if a:forward echom '[ATP]: End not found within limits. Try ]o or enlarge g:atp_completion_limits[3]='.g:atp_completion_limits[3].'.' else echom '[ATP]: Begin not found within limits. Try [o or enlarge g:atp_completion_limits[3]='.g:atp_completion_limits[3].'.' endif echohl None endif let &l:lazyredraw=lazyredraw endfunction " atplib#motion#GotoSection {{{1 " The extra argument is a pattern to match for the " section title. The first, obsolete argument stands for: " part,chapter,section,subsection,etc. " This commands wrap around the end of the file. " with a:3 = 'vim' it uses vim search() function " with a:3 = 'atp' " the default is: " if g:atp_mapNn then use 'atp' " else use 'vim'. function! atplib#motion#GotoSection(bang, count, flag, secname, ...) let search_tool = ( a:0 >= 1 ? a:1 : ( g:atp_mapNn ? 'atp' : 'vim' ) ) let mode = ( a:0 >= 2 ? a:2 : 'n' ) let title_pattern = ( a:0 >= 3 ? a:3 : '' ) let pattern = ( empty(a:bang) ? '^\([^%]\|\\\@ 1 " the 's' flag should be used only in the first search. let flag=substitute(flag, 's', '', 'g') endif if search_tool == 'vim' call searchpos(bpat . pattern, flag) else execute "S /". bpat . pattern . "/ " . flag endif endfor call atplib#motion#UpdateToCLine() call histadd("search", pattern) let @/ = pattern endfunction function! atplib#motion#Env_compl(A,P,L) let envlist=sort(['algorithm', 'algorithmic', 'abstract', 'definition', 'equation', 'proposition', \ 'theorem', 'lemma', 'array', 'tikzpicture', \ 'tabular', 'table', 'align', 'alignat', 'proof', \ 'corollary', 'enumerate', 'examples\=', 'itemize', 'remark', \ 'notation', 'center', 'quotation', 'quote', 'tabbing', \ 'picture', 'math', 'displaymath', 'minipage', 'list', 'flushright', 'flushleft', \ 'frame', 'figure', 'eqnarray', 'thebibliography', 'titlepage', \ 'verbatim', 'verse', 'inlinemath', 'displayedmath', 'subequations', \ 'part', 'section', 'subsection', 'subsubsection' ]) let returnlist=[] for env in envlist if env =~ '^' . a:A call add(returnlist,env) endif endfor return returnlist endfunction function! atplib#motion#ggGotoSection(count,section) let mark = getpos("''") if a:section == "part" let secname = '\\part\>' call cursor(1,1) elseif a:section == "chapter" let secname = '\\\%(part\|chapter\)\>' if !search('\\part\>', 'bc') call cursor(1,1) endif elseif a:section == "section" let secname = '\\\%(part\|chapter\|section\)\>' if !search('\\chapter\>\|\\part\>', 'bc') call cursor(1,1) endif elseif a:section == "subsection" let secname = '\\\%(part\|chapter\|section\|subsection\)\>' if !search('\\section\>\|\\chapter\>\|\\part\>', 'bc') call cursor(1,1) endif elseif a:section == "subsubsection" let secname = '\\\%(part\|chapter\|section\|subsection\|subsubsection\)\>' if !search('\subsection\>\|\\section\>\|\\chapter\>\|\\part\>', 'bc') call cursor(1,1) endif endif call atplib#motion#UpdateToCLine() call atplib#motion#GotoSection("", a:count, 'Ws', secname) call setpos("''",mark) endfunction " atplib#motion#Input {{{1 function! atplib#motion#Input(flag, count) let pat = ( &l:filetype == "plaintex" ? '\\input\s*{' : '\%(\\input\s*{\=\>'.(atplib#search#SearchPackage('subfiles') ? '\|\\subfile\s*{' : '' ).'\|\\include\s*{\)' ) let @/ = '^\([^%]\|\\\@= 1 ? a:1 : strpart(getline("."), 0, col(".")) !~ '\(\\\@ method = "all" is used. let line = ( check_line ? getline(".") : "" ) if check_line let beg_line = strpart(line, 0,col(".")-1) " Find the begining column of the file name: let bcol = searchpos('\%({\|,\)', 'bn', line("."))[1] if bcol == 0 let bcol = searchpos('{', 'n', line("."))[1] endif " Find the end column of the file name let col = searchpos(',\|}', 'cn', line("."))[1] " Current column let cur_col = col(".") endif " This part will be omitted if check_line is 0 (see note above). " \usepackege{...,,...} if line =~ '\\usepackage' && g:atp_developer let method = "usepackage" let ext = '.sty' let fname = atplib#append_ext(strpart(getline("."), bcol, col-bcol-1), ext) let file = atplib#search#KpsewhichFindFile('tex', fname, '', 1) let file_l = [ file ] let message = "Pacakge: " let options = "" " \input{...}, \include{...} elseif line =~ '\\\(input\|include\|subfile\)\s*{' let method = "input{" let ext = '.tex' " \input{} doesn't allow for {...,...} many file path. let fname = atplib#append_ext(strpart(getline("."), bcol, col-bcol-1), '.tex') " The 'file . ext' might be already a full path. if fnamemodify(fname, ":p") != fname let file_l = atplib#search#KpsewhichFindFile('tex', fname, g:atp_texinputs, -1, ':p', '^\(\/home\|\.\)', '\%(^\/usr\|kpsewhich\|texlive\|miktex\)') let file = get(file_l, 0, 'file_missing') else let file_l = [ fname ] let file = fname endif let message = "File: " let options = "" " \input /without {/ elseif line =~ '\\input\s*{\@!' let method = "input" let fname = atplib#append_ext(matchstr(getline(line(".")), '\\input\s*\zs\f*\ze'), '.tex') let file_l = atplib#search#KpsewhichFindFile('tex', fname, g:atp_texinputs, -1, ':p', '^\(\/home\|\.\)', '\%(^\/usr\|kpsewhich\|texlive\)') let file = get(file_l, 0, "file_missing") let options = ' +setl\ ft=' . &l:filetype " \documentclass{...} elseif line =~ '\\documentclass' && g:atp_developer let method = "documentclass" let saved_pos = getpos(".") call cursor(line("."), 1) call search('\\documentclass\zs', 'cb', line(".")) let bcol = searchpos('{', 'c', line("."))[1] execute "normal %" let ecol = col(".") call cursor(saved_pos[0], saved_pos[1]) let classname = strpart(getline("."), bcol, ecol-bcol-1) let fname = atplib#append_ext(classname, '.cls') let file = atplib#search#KpsewhichFindFile('tex', fname, g:atp_texinputs, 1, ':p') let file_l = [ file ] let options = "" elseif line =~ '\\RequirePackage' && g:atp_developer let method = "requirepackage" let ext = '.sty' let fname = atplib#append_ext(strpart(getline("."), bcol, col-bcol-1), ext) let file = atplib#search#KpsewhichFindFile('tex', fname, g:atp_texinputs, 1, ':p') let file_l = [ file ] let options = ' +setl\ ft=' . &l:filetype elseif line =~ '\\bibliography\>' let method = "bibliography" setl iskeyword +=\ let fname = expand("") setl iskeyword -=\ if fname == "\\bibliography" let fname = matchstr(getline(line(".")), '\\bibliography{\zs[^},]*\ze\%(,\|}\)') endif let fname = atplib#append_ext(fname, '.bib') let file_l = atplib#search#KpsewhichFindFile('bib', fname, g:atp_bibinputs, -1, ':p', '^\(\/home\|\.\)', '\%(^\/usr\|kpsewhich\|texlive\)') let file = get(file_l, 0, "file_missing") let options = ' +setl\ ft=' . &l:filetype else " If not over any above give a list of input files to open, like " EditInputFile let method = "all" call extend(file_l, [ atp_MainFile ], 0) call extend(level_d, { atp_MainFile : 0 }) endif if len(file_l) > 1 && file =~ '^\s*$' if method == "all" let msg = "Which file to edit?" else let msg = "Found many files. Which file to use?" endif let mods = method == 'all' ? ":t" : ":p" " It is better to start numbering from 0, " then 0 - is the main file " 1 - is the first chapter, and so on. let i = 0 let input_l = [] for f in file_l if exists("level_d") let space = "" if g:atp_RelativePath exe "lcd " . fnameescape(b:atp_ProjectDir) let level = get(level_d,fnamemodify(f, ':.'), get(level_d, f, 1)) exe "lcd " . fnameescape(cwd) else exe "lcd " . fnameescape(b:atp_ProjectDir) let level = get(level_d,f, get(level_d,fnamemodify(f, ':.'), 1)) exe "lcd " . fnameescape(cwd) endif for j in range(level) let space .= " " endfor else space = "" endif call add(input_l, "(" . i . ") " . space . fnamemodify(f, mods)) let i+=1 endfor " Ask the user which file to edit: redraw if len([ msg ] + input_l) < &l:lines for f in [ msg ] + input_l " echo highlighted message if matchstr(f, '(\d\+)\s*\zs.*$') == expand("%:t") echohl CursorLine elseif f == msg echohl Title endif echo f if matchstr(f, '(\d\+)\s*\zs.*$') == expand("%:t") || f == msg echohl None endif endfor let choice = input("Type number and (empty cancels): ") if choice != "" let choice += 1 endif elseif for line in [ msg ] + input_l if line == msg echohl Title endif echo line echohl None endfor echohl MoreMsg let choice = input("Type number and (empty cancels): ") echohl None if choice != "" let choice += 1 endif endif " Remember: 0 == "" returns 1! " char2nr("") = 0 " nr2char(0) = "" if choice == "" exe "lcd " . fnameescape(cwd) return endif if choice < 1 || choice > len(file_l) if choice < 1 || choice > len(file_l) echo "\n" echoerr "Choice out of range." endif exe "lcd " . fnameescape(cwd) return endif let file = atplib#FullPath(file_l[choice-1]) let fname = file elseif file !~ '^\s*$' let file = atplib#FullPath(file) let fname = file endif if !exists("file") exe "lcd " . fnameescape(cwd) return endif if file != "file_missing" && filereadable(file) && ( !exists("choice") || exists("choice") && choice != 0 ) " Inherit tex flavour. " So that bib, cls, sty files will have their file type (bib/plaintex). let filetype = &l:filetype let old_file = expand("%:p") execute "edit ".edit_args." ".escape(find_args, '\')." ".fnameescape(file) call RestoreProjectVariables(projectVarDict) if &l:filetype =~ 'tex$' && file =~ '\.tex$' && &l:filetype != filetype let &l:filetype = filetype endif " Set the main file variable and pass the TreeOfFiles variables to the new " buffer. if exists("b:atp_ErrorFormat") unlockvar b:atp_ErrorFormat endif return file else echohl ErrorMsg redraw if file != "file_missing" && exists("fname") echo "File \'".fname."\' not found." else echo "Missing file." endif echohl None exe "lcd " . fnameescape(cwd) return file endif endfunction catch /E127:/ endtry function! atplib#motion#GotoFileComplete(ArgLead, CmdLine, CursorPos) let bang = ( a:CmdLine =~ '^\w*!' ? '!' : '') if bang == "!" || !exists("b:TreeOfFiles") || !exists("b:ListOfFiles") || !exists("b:TypeDict") || !exists("b:LevelDict") let [tree_d, file_l, type_d, level_d ] = TreeOfFiles(atp_MainFile) else let [tree_d, file_l, type_d, level_d ] = deepcopy([ b:TreeOfFiles, b:ListOfFiles, b:TypeDict, b:LevelDict ]) endif if index(file_l, b:atp_MainFile) == -1 || index(file_l, fnamemodify(b:atp_MailFile, ":p")) == -1 call add(file_l, b:atp_MainFile) endif return filter(file_l, "v:val =~ a:ArgLead") endfunction " atplib#motion#SkipComment {{{1 " a:flag=fb (f-forward, b-backward) " f works like ]* " b workd like [* " Note: the 's' search flag is passed by the associated commands. " This can be extended: " (1) skip empty lines between comments function! atplib#motion#SkipComment(flag, mode, count, ...) let flag = ( a:flag =~ 'b' ? 'b' : '' ) let nr = ( a:flag =~ 'b' ? -1 : 1 ) for c in range(1, a:count) let test = search('^\zs\s*%', flag) if !test return endif call cursor(line("."), ( nr == -1 ? 1 : len(getline(line("."))))) let line = getline(line(".")) " find previous line let pline_nr=min([line("$"), max([1,line(".")+nr])]) let pline = getline(pline_nr) while pline =~ '^\s*%' && line(".") != line("$") && line(".") != 1 call cursor(line(".")+nr, ( nr == -1 ? 1 : len(getline(line(".")+nr)))) let pline_nr=min([line("$"), max([1,line(".")+nr])]) let pline = getline(pline_nr) endwhile if a:mode == 'n' && ( !g:atp_VimCompatible || g:atp_VimCompatible =~? '\' ) if a:flag =~# 'b' call cursor(line(".")-1,1) else call cursor(line(".")+1,1) endif endif if a:mode == 'v' let end_pos = [ line("."), col(".") ] " Go where visual mode started exe "normal `" . ( nr == 1 ? '<' : '>' ) exe "normal " . visualmode() call cursor(end_pos) endif endfor endfunction " Syntax motion " {{{1 atplib#motion#TexSyntaxMotion function! atplib#motion#TexSyntaxMotion(forward, how, ...) " If the function is used in imap. let in_imap = ( a:0 >= 1 ? a:1 : 0 ) let whichwrap = split(&l:whichwrap, ',') if !count(whichwrap, 'l') setl ww+=l endif if !count(whichwrap, 'h') setl ww+=h endif " before we use let line=line(".") if in_imap && len(getline(".")) > col(".") let col = col(".")+1 else let col = col(".") endif " execute "normal l" let step = ( a:forward > 0 ? "l" : "h" ) let synstack = map(synstack(line, col), 'synIDattr( v:val, "name")') let synstackh = map(synstack(line, max([1, col-1])), 'synIDattr( v:val, "name")') let DelimiterCount = count(synstack, 'Delimiter') let ScriptCount = count(synstack, 'texSuperscript') + count(synstack, 'texSubscript') let ScriptsCount = count(synstack, 'texSuperscripts') + count(synstack, 'texSubscripts') let StatementCount = count(synstack, 'texStatement') let StatementCounth = count(synstackh, 'texStatement') && col(".") > 1 let SectionCount = count(synstack, 'texSection') let TypeStyleCount = count(synstack, 'texTypeStyle') let TypeStyleCounth = count(synstackh, 'texTypeStyle') && col(".") > 1 let MathTextCount = count(synstack, 'texMathText') let MathTextCounth = count(synstackh, 'texMathText') && col(".") > 1 let RefZoneCount = count(synstack, 'texRefZone') let RefZoneCounth = count(synstackh, 'texRefZone') && col(".") > 1 let RefOptionCount = count(synstack, 'texRefOption') let RefOptionCounth = count(synstackh, 'texRefOption') && !count(synstackh, 'Delimiter') && col(".") > 1 let CiteCount = count(synstack, 'texCite') let CiteCounth = count(synstackh, 'texCite') && !count(synstackh, 'Delimiter') && col(".") > 1 let MatcherCount = count(synstack, 'texMatcher') let MatcherCounth = count(synstackh, 'texMatcher') && !count(synstackh, 'Delimiter') && col(".") > 1 let MathMatcherCount = count(synstack, 'texMathMatcher') let MathMatcherCounth = count(synstackh, 'texMathMatcher') && !count(synstackh, 'Delimiter') && col(".") > 1 let SectionNameCount = count(synstack, 'texSectionName') let SectionNameCounth = count(synstackh, 'texSectionName') && !count(synstackh, 'Delimiter') && col(".") > 1 let SectionMarkerCount = count(synstack, 'texSectionMarker') let SectionModifierCount = count(synstack, 'texSectionModifier') let SectionModifierCounth = count(synstackh, 'texSectionModifier') && !count(synstackh, 'Delimiter') && col(".") > 1 " let MathZonesCount = len(filter(copy(synstack), 'v:val =~ ''^texMathZone[A-Z]''')) if DelimiterCount let syntax = [ 'Delimiter' ] elseif StatementCount && StatementCounth && step == "h" let syntax = [ 'texStatement' ] elseif StatementCount && step != "h" let syntax = [ 'texStatement' ] elseif SectionCount let syntax = [ 'texSection' ] elseif ScriptCount if a:how == 1 let syntax = [ 'texSuperscript', 'texSubscript'] else let syntax = [ 'texSuperscripts', 'texSubscripts'] endif elseif TypeStyleCount && TypeStyleCounth && step == "h" let syntax = [ 'texTypeStyle' ] elseif TypeStyleCount && step != "h" let syntax = [ 'texTypeStyle' ] elseif RefZoneCount && RefZoneCounth && step == "h" let syntax = [ 'texRefZone' ] elseif RefZoneCount && step != "h" let syntax = [ 'texRefZone' ] elseif RefOptionCount && RefOptionCounth && step == "h" let syntax = [ 'texRefOption' ] elseif RefOptionCount && step != "h" let syntax = [ 'texRefOption' ] elseif CiteCount && CiteCounth && step == "h" let syntax = [ 'texCite' ] elseif CiteCount && step != "h" let syntax = [ 'texCite' ] elseif MatcherCount && MatcherCounth && step == "h" let syntax = [ 'texMatcher' ] elseif MatcherCount && step != "h" let syntax = [ 'texMatcher' ] elseif MathMatcherCount && MathMatcherCounth && step == "h" let syntax = [ 'texMathMatcher' ] elseif MathMatcherCount && step != "h" let syntax = [ 'texMathMatcher' ] elseif SectionNameCount && SectionNameCounth && step == "h" let syntax = [ 'texSectionName' ] elseif SectionNameCount && step != "h" let syntax = [ 'texSectionName' ] elseif SectionMarkerCount let syntax = [ 'texSectionMarker' ] elseif SectionModifierCount && SectionModifierCounth && step == "h" let syntax = [ 'texSectionModifier' ] elseif SectionModifierCount && step != "h" let syntax = [ 'texSectionModifier' ] elseif MathTextCount && MathTextCounth && step == "h" let syntax = [ 'texMathText' ] elseif MathTextCount && step != "h" let syntax = [ 'texMathText' ] " elseif MathZonesCount " This might be slow " but we might change 'normal l' to 'normal w' " let syntax = [ 'texMathZoneA', 'texMathZoneB', 'texMathZoneC', 'texMathZoneD', 'texMathZoneE', 'texMathZoneF', 'texMathZoneG', 'texMathZoneH', 'texMathZoneI', 'texMathZoneJ', 'texMathZoneK', 'texMathZoneL', 'texMathZoneT', 'texMathZoneV', 'texMathZoneW', 'texMathZoneX', 'texMathZoneY' ] else " Go after first Delimiter let i=0 let DelimiterCount = count(synstack, 'Delimiter') while !DelimiterCount exe "normal " . step let synstack = map(synstack(line("."), col(".")), 'synIDattr( v:val, "name")') let DelimiterCount = count(synstack, 'Delimiter') if i == 1 let DelimiterCount = 0 endif let i+=1 endwhile if in_imap normal a endif return "Delimiter motion" endif let true = 0 for syn in syntax let true += count(synstack, syn) endfor let initial_count = true while true >= initial_count let true = 0 execute "normal " . step let synstack = map(synstack(line("."), col(".")), 'synIDattr( v:val, "name")') for syn in syntax let true += count(synstack, syn) endfor endwhile while getline(".")[col(".")] =~ '^{\|}\|(\|)\|\[\|\]$' exe "normal l" endwhile if getline(".")[col(".")-2] == "{" exe "normal h" endif let &l:whichwrap = join(whichwrap, ',') if in_imap normal a " else " normal l endif if step == "l" && syntax == [ 'Delimiter' ] normal h endif endfunction " ctrl-j motion " atplib#motion#JMotion {{{1 " New motion function! atplib#motion#JMotion(flag) " Note: pattern to match only commands which do not have any arguments: " '\(\\\w\+\>\s*{\)\@!\\\w\+\>' let line = getline(".") if a:flag !~# 'b' let pline = strpart(line, col(".")-1) if pline =~ '[{]*}{' call search('{.', 'e') return endif else let pline = strpart(line, 0, col(".")) if pline =~ '}{' call search('}{', 'b') normal! h return endif endif let lz = &lz set lz if a:flag !~# 'b' let pattern = '\%(\]\zs\|{\zs\|}\zs\|(\zs\|)\zs\|\[\zs\|\]\zs\|\$\zs\|^\zs\s*$\|\(\\\w\+\>\s*{\)\@!\\\w\+\>\zs\)' else let pattern = '\%(\]\|{\|}\|(\|)\|\[\|\]\|\$\|^\s*$\|\(\\\w\+\>\s*{\)\@!\\\w\+\>\)' endif if getline(line(".")) =~ '&' let pattern = '\%(&\s*\zs\|^\s*\zs\)\|' . pattern endif if getline(line("."))[col(".")-1] =~ '\%(\$\|{\|}\|(\|)\|\[\|\]\)' && a:flag !~# 'b' if col(".") == len(getline(line("."))) execute "normal a " else call cursor(line("."), col(".")+1) endif else call search(pattern, a:flag) " In the imaps we use 'a' for the backward move and 'i' for forward move! let condition = getline(line("."))[col(".")-1] =~ '\%(\$\|{\|}\|(\|)\|\[\|\]\)' if a:flag !~# 'b' && col(".") == len(getline(line("."))) && condition " Add a space at the end of line and move there execute "normal a" endif endif let &lz=lz endfunction " }}}1 " atplib#motion#ParagraphNormalMotion {{{1 function! atplib#motion#ParagraphNormalMotion(backward,count) normal! m` if a:backward != "b" for i in range(1,a:count) call search('\(^\(\n\|\s\)*\n\s*\zs\S\|\zs\\par\>\|\%'.line("$").'l$\)', 'W') endfor else for i in range(1,a:count) call search('\(^\(\n\|\s\)*\n\s*\zs\S\|\zs\\par\>\|^\%1l\)', 'Wb') endfor endif endfunction " atplib#motion#SentenceNormalMotion {{{1 fun! atplib#motion#SentenceNormalMotion(backward,count) normal! m` if a:backward != "b" for i in range(1,a:count) call search('\%(\.\|\\par\|\\]\|\\noindent\|\\\%(begin\|end\)\%(\s*{.*}\|\s*\[.*\]\)*\|\\\%(part\|chapter\|\%(sub\)\{0,2}section\|\%(sub\)\?paragraph\)\%(\s*[.\{-}]\)\?{.*}\)\_s\+\zs\%(\s*\\begin\|\s*\\end\)\@![A-Z]', 'W') endfor else for i in range(1,a:count) call search('\%(\.\|\\par\|\\]\|\\noindent\|\\\%(begin\|end\)\%(\s*{.*}\|\s*\[.*\]\)*\|\\\%(part\|chapter\|\%(sub\)\{0,2}section\|\%(sub\)\?paragraph\)\%(\s*[.\{-}]\)\?{.*}\)\_s\+\zs\%(\s*\\begin\|\s*\\end\)\@![A-Z]', 'Wb') endfor endif endfun " atplib#motion#StartVisualMode {{{1 function! atplib#motion#StartVisualMode(mode, count) let g:atp_visualstartpos = getpos(".") let l:count = ( a:count ? a:count : "" ) if a:mode ==# 'v' exe "normal! ".l:count."v" elseif a:mode ==# 'V' exe "normal! ".l:count."V" elseif a:mode ==# 'cv' exe "normal! ".l:count."\" endif endfunction " atplib#motion#ParagraphVisualMotion {{{1 function! atplib#motion#ParagraphVisualMotion(backward,count) let bpos = g:atp_visualstartpos normal! m` if a:backward != "b" let cond = (bpos[1] >= getpos("'>")[1]) if cond call cursor(getpos("'<")[1:2]) else call cursor(getpos("'>")[1:2]) endif for i in range(1,a:count) call search('.', 'cW') let epos = searchpos('\(^\(\n\|\s\)*\n\ze\|\(\_s*\)\=\\par\>\|\%'.line("$").'l$\)', 'W') if epos == [0, 0] let epos = getpos(".")[1:2] endif endfor else let cond = (bpos[1] < getpos("'>")[1]) if cond call cursor(getpos("'>")[1:2]) else call cursor(getpos("'<")[1:2]) endif for i in range(1,a:count) call search('.', 'cbW') let epos = searchpos('\(^\(\n\|\s\)*\n\ze\|\(\_s*\)\=\\par\>\|^\%1l\ze\)', 'Wb') if epos == [0, 0] let epos = getpos(".")[1:2] endif endfor endif call cursor(bpos[1:2]) exe "normal ".visualmode() call cursor(epos) endfunction fun! atplib#motion#TexKeywordObject() " {{{1 let line = getline(line(".")) let beg = len(matchstr(line[:(col(".")-1)], '\\\?\k*$')) let end = len(matchstr(line[col("."):], '^\k*')) if beg-1 >= 1 exe "normal! ".(beg-1)."h" endif normal v if end+beg-1 >= 1 exe "normal! ".(beg+end-1)."l" endif endfun " Modeliens: {{{1 " vim:fdm=marker:tw=85:ff=unix:noet:ts=8:sw=4:fdc=1 autoload/atplib/search.vim [[[1 2538 " Author: Marcin Szamotulski " Description: This file provides searching tools of ATP. " Note: This file is a part of Automatic Tex Plugin for Vim. " Language: tex " Last Change:Tue Sep 06, 2011 at 03:18 +0100 " Make a dictionary of definitions found in all input files. " {{{ atplib#search#make_defi_dict_vim " Comparing with ]D, ]d, ]i, ]I vim maps this function deals with multiline " definitions. " " The output dictionary is of the form: " { input_file : [ [begin_line, end_line], ... ] } " a:1 = buffer name to search in for input files " a:3 = 1 skip searching for the end_line " " ToDo: it is possible to check for the end using searchpairpos, but it " operates on a list not on a buffer. function! atplib#search#make_defi_dict_vim(bang,...) let atp_MainFile = atplib#FullPath(b:atp_MainFile) let bufname = a:0 >= 1 ? a:1 : atp_MainFile " pattern to match the definitions this function is also used to fine " \newtheorem, and \newenvironment commands let pattern = a:0 >= 2 ? a:2 : '\\def\|\\newcommand' let preambule_only = ( a:bang == "!" ? 0 : 1 ) " this is still to slow! let only_begining = ( a:0 >= 3 ? a:3 : 0 ) let defi_dict={} let inputfiles=atplib#search#FindInputFiles(bufname) let input_files=[] " TeX: How this work in TeX files. for inputfile in keys(inputfiles) if inputfiles[inputfile][0] != "bib" && ( !preambule_only || inputfiles[inputfile][0] == "preambule" ) call add(input_files, inputfiles[inputfile][2]) endif endfor let input_files=filter(input_files, 'v:val != ""') if !count(input_files, atp_MainFile) call extend(input_files,[ atp_MainFile ]) endif if len(input_files) > 0 for inputfile in input_files let defi_dict[inputfile]=[] " do not search for definitions in bib files "TODO: it skips lines somehow. let ifile=readfile(inputfile) " search for definitions let lnr=1 while (lnr <= len(ifile) && (!preambule_only || ifile[lnr-1] !~ '\\begin\s*{document}')) let match=0 let line=ifile[lnr-1] if substitute(line,'\\\@,) function! atplib#search#make_defi_dict_py(bang,...) let atp_MainFile = atplib#FullPath(b:atp_MainFile) let bufname = a:0 >= 1 ? a:1 : atp_MainFile " Not tested let pattern = a:0 >= 2 ? a:2 : '\\def\|\\newcommand' " Not implemeted let preambule_only= a:bang == "!" ? 0 : 1 let only_begining = a:0 >= 3 ? a:3 : "0" if a:bang == "!" || !exists("b:TreeOfFiles") " Update the cached values: let [ b:TreeOfFiles, b:ListOfFiles, b:TypeDict, b:LevelDict ] = TreeOfFiles(atp_MainFile) endif let [ Tree, List, Type_Dict, Level_Dict ] = deepcopy([ b:TreeOfFiles, b:ListOfFiles, b:TypeDict, b:LevelDict ]) let defi_dict = {} python << ENDPYTHON import re import subprocess import os import glob from atplib.atpvim import readlines from atplib.search import newcmd_pattern as pattern def preambule_end(file): """find linenr where preambule ends, file is list of lines""" nr=1 for line in file: if re.search(r'\\begin\s*{\s*document\s*}', line): return nr nr+=1 return 0 type_dict=vim.eval("b:TypeDict") main_file=vim.eval("atp_MainFile") if int(vim.eval("preambule_only")) != 0: preambule_only=True files=[main_file] for f in type_dict.keys(): if type_dict[f] == "preambule": files.append(f) with open(main_file) as sock: main_file_l=sock.read().splitlines() preambule_end=preambule_end(main_file_l) else: preambule_only=False files=[main_file] files.extend(vim.eval("b:ListOfFiles")) only_begining = (vim.eval("only_begining") != "0") if hasattr(vim, 'bindeval'): defi_dict = vim.bindeval("defi_dict") else: defi_dict = {} for fname in files: defi_dict[fname]=[] lnr=1 file_l = readlines(fname) while lnr <= len(file_l) and ( preambule_only and ( fname == main_file and lnr <= preambule_end or fname != main_file ) or not preambule_only): line=file_l[lnr-1] if re.search(pattern, line): # add: no search in comments. b_lnr = lnr if not only_begining: _open = len(re.findall("({)", line)) _close = len(re.findall("(})", line)) while _open != _close: lnr+=1 line = file_l[lnr-1] _open += len(re.findall("({)", line)) _close += len(re.findall("(})", line)) e_lnr = lnr defi_dict[fname].extend([[b_lnr, e_lnr ]]) else: defi_dict[fname].extend([[b_lnr, b_lnr ]]) lnr += 1 else: lnr += 1 if not hasattr(vim, 'bindeval'): # There is no need of using json.dumps() here since the defi_dict has str # type keys and list of intergers inside. import json vim.command("let defi_dict_py=%s" % json.dumps(defi_dict)) ENDPYTHON return defi_dict endfunction "}}} function! atplib#search#GlobalDefi(command) "{{{ " This function behaves like gD, but descends to included files. " a:cmd - cmd which definition we are searching for if !has("python") return endif python << EOF import vim import re import os from atplib.atpvim import readlines from atplib.search import scan_preambule from atplib.search import addext from atplib.search import kpsewhich_find from atplib.search import kpsewhich_path from atplib.search import newcmd_pattern as pattern cur_line = vim.eval('line(".")') cur_file = vim.eval('atplib#FullPath(expand("%"))') command = vim.eval('a:command') mainfile = vim.eval('atplib#FullPath(b:atp_MainFile)') if scan_preambule(mainfile, re.compile(r'\\usepackage{[^}]*\bsubfiles\b')): pat_str = r'^[^%]*(?:\\input\s+([\w_\-\.]*)|\\(?:input|include(?:only)?|subfile)\s*{([^}]*)})' inclpat = re.compile(pat_str) else: pat_str = r'^[^%]*(?:\\input\s+([\w_\-\.]*)|\\(?:input|include(?:only)?)\s*{([^}]*)})' inclpat = re.compile(pat_str) tex_path=kpsewhich_path('tex') relative_path = vim.eval('g:atp_RelativePath') project_dir = vim.eval('b:atp_ProjectDir') def scan_file(fname, command, pattern=pattern): linenr = 0 flines = readlines(fname) for line in flines: linenr += 1 matches = re.findall(inclpat, line) if len(matches) > 0: for match in matches: for m in match: if str(m) != "": m=addext(m, "tex") if not os.access(m, os.F_OK): try: m=kpsewhich_find(m, tex_path)[0] except IndexError: pass (ffile, linenr, col) = scan_file(m, command, pattern) if ffile: return (ffile, linenr, col) match = re.search(pattern, line) if match: if match.group(1) == command: col = match.start(1)+1 return (fname, linenr, col) else: return ("", 0, 0) if os.path.abspath(fname) == os.path.abspath(cur_file) and linenr > cur_line: return ("", 0, 0) (ffile, line, col) = scan_file(mainfile, command, pattern) vim.command("let ffile='%s'" % ffile) vim.command(" let line=%d" % line) vim.command(" let col=%d" % col) EOF if !empty(ffile) let bufnr = bufnr(ffile) if bufnr != -1 && buflisted(bufnr) exe "b ".bufnr call setpos(".", [0, line, col, 0]) else exe "edit +".line." ".ffile call setpos(".", [0, line, col, 0]) endif endif endfunction "}}} "{{{ atplib#search#LocalCommands_vim " a:1 = pattern " a:2 = "!" => renegenerate the input files. function! atplib#search#LocalCommands_vim(...) " let time = reltime() let pattern = a:0 >= 1 && a:1 != '' ? a:1 : '\\def\>\|\\newcommand\>\|\\newenvironment\|\\newtheorem\|\\definecolor\|' \ . '\\Declare\%(RobustCommand\|FixedFont\|TextFontCommand\|MathVersion\|SymbolFontAlphabet' \ . '\|MathSymbol\|MathDelimiter\|MathAccent\|MathRadical\|MathOperator\)' \ . '\|\\SetMathAlphabet\>' let bang = a:0 >= 2 ? a:2 : '' let atp_MainFile = atplib#FullPath(b:atp_MainFile) " Makeing lists of commands and environments found in input files if bang == "!" || !exists("b:TreeOfFiles") " Update the cached values: let [ b:TreeOfFiles, b:ListOfFiles, b:TypeDict, b:LevelDict ] = TreeOfFiles(atp_MainFile) endif let [ Tree, List, Type_Dict, Level_Dict ] = deepcopy([ b:TreeOfFiles, b:ListOfFiles, b:TypeDict, b:LevelDict ]) let saved_loclist = getloclist(0) " I should scan the preambule separately! " This will make the function twice as fast! silent! execute "lvimgrep /".pattern."/j " . fnameescape(atp_MainFile) for file in List if get(Type_Dict, file, 'no_file') == 'preambule' silent! execute "lvimgrepadd /".pattern."/j " . fnameescape(file) endif endfor let loclist = getloclist(0) call setloclist(0, saved_loclist) let atp_LocalCommands = [] let atp_LocalEnvironments = [] let atp_LocalColors = [] for line in loclist " the order of pattern is important if line['text'] =~ '^[^%]*\\definecolor' " color name let name=matchstr(line['text'], \ '\\definecolor\s*{\s*\zs[^}]*\ze\s*}') let type="Colors" elseif line['text'] =~ '^[^%]*\%(\\def\>\|\\newcommand\)' " definition name let name= '\' . matchstr(line['text'], '\\def\\\zs[^{]*\ze{\|\\newcommand{\?\\\zs[^\[{]*\ze}') let name=substitute(name, '\(#\d\+\)\+\s*$', '', '') let name.=(line['text'] =~ '\\def\\\w\+#[1-9]\|\\newcommand{[^}]*}\[[1-9]\]' ? '{' : '') if name =~ '#\d\+' echo line['text'] echo name endif let type="Commands" " definition " let def=matchstr(line['text'], " \ '^\%(\\def\\[^{]*{\zs.*\ze}\|\\newcommand\\[^{]*{\zs.*\ze}\)') elseif line['text'] =~ '^[^%]*\%(\\Declare\%(RobustCommand\|FixedFont\|TextFontCommand\|MathVersion\|SymbolFontAlphabet' \ . '\|MathSymbol\|MathDelimiter\|MathAccent\|MathRadical\|MathOperator\)\>\|\\SetMathAlphabet\)' let name=matchstr(line['text'], \ '\%(\\Declare\%(RobustCommand\|FixedFont\|TextFontCommand\|MathVersion\|SymbolFontAlphabet' \ . '\|MathSymbol\|MathDelimiter\|MathAccent\|MathRadical\|MathOperator\)\|\\SetMathAlphabet\)\s*{\s*\zs[^}]*\ze\s*}') let type="Commands" elseif line['text'] =~ '^[^%]*\%(\\newenvironment\|\\newtheorem\)' " environment name let name=matchstr(line['text'], \ '^[^%]*\\\%(newtheorem\*\?\|newenvironment\)\s*{\s*\zs[^}]*\ze\s*}') let type="Environments" endif if exists("name") && name != '' && name != '\' if count(atp_Local{type}, name) == 0 call add(atp_Local{type}, name) endif endif endfor let b:atp_LocalCommands = atp_LocalCommands let b:atp_LocalEnvironments = atp_LocalEnvironments let b:atp_LocalColors = atp_LocalColors return [ atp_LocalEnvironments, atp_LocalCommands, atp_LocalColors ] endfunction "}}} " {{{ atplib#search#LocalCommands_py function! atplib#search#LocalCommands_py(write, ...) let time=reltime() " The first argument pattern is not implemented " but it should be a python regular expression let bang = a:0 >= 2 ? a:2 : '' let atp_MainFile = atplib#FullPath(b:atp_MainFile) let pwd = getcwd() try exe "lcd ".fnameescape(b:atp_ProjectDir) catch /E344:/ return endtry " if a:write " call atplib#write("nobackup") " endif " Makeing lists of commands and environments found in input files if bang == "!" || !exists("b:TreeOfFiles") " Update the cached values: let [ b:TreeOfFiles, b:ListOfFiles, b:TypeDict, b:LevelDict ] = TreeOfFiles(atp_MainFile) endif let [ Tree, List, Type_Dict, Level_Dict ] = deepcopy([ b:TreeOfFiles, b:ListOfFiles, b:TypeDict, b:LevelDict ]) " Note: THIS CODE IS ONLY NEEDED WHEN PWD is different than the TreeOfFiles was " called! There is an option to store full path in ATP, then this is not needed. let files = [] for file in b:ListOfFiles if get(b:TypeDict, file, "") == "input" || get(b:TypeDict, file, "") == "preambule" if filereadable(file) call add(files, atplib#FullPath(file)) else " This makes it really slow when the files are missing. let file=atplib#search#KpsewhichFindFile("tex", file) if file != "" call add(files, file) endif endif endif endfor let atp_LocalCommands = [] let atp_LocalColors = [] let atp_LocalEnvironments = [] python << END import re import vim import os.path from atplib.atpvim import readlines pattern=re.compile(r'\s*(?:\\(?Pdef)(?P\\[^#{]*)|(?:\\(?Pnewcommand)|\\(?Pnewenvironment)|\\(?Pnewtheorem\*?)|\\(?Pdefinecolor)|\\(?PDeclare)(?:RobustCommand|FixedFont|TextFontCommand|MathVersion|SymbolFontAlphabet|MathSymbol|MathDelimiter|MathAccent|MathRadical|MathOperator)\s*{|\\(?PSetMathAlphabet))\s*{(?P[^}]*)})') files=[vim.eval("atp_MainFile")]+vim.eval("files") localcommands = [] localcolors = [] localenvs = [] for fname in files: lnr=1 file_l = readlines(fname) for line in file_l: m=re.match(pattern, line) if m: if m.group('def'): if re.search(r'\\def\\\w+#[1-9]', line): localcommands.append(m.group('def_c')+'{') else: localcommands.append(m.group('def_c')) elif m.group('nc') or m.group('dec') or m.group('sma'): if re.search(r'\\newcommand\s*{[^}]*}\s*\[[1-9]\]\s*{', line): localcommands.append(m.group('arg')+'{') else: localcommands.append(m.group('arg')) elif m.group('nt') or m.group('env'): localenvs.append(m.group('arg')) elif m.group('col'): localcolors.append(m.group('arg')) if hasattr(vim, 'bindeval'): cmds = vim.bindeval('atp_LocalCommands') cmds.extend(localcommands) envs = vim.bindeval('atp_LocalEnvironments') envs.extend(localenvs) cols = vim.bindeval('atp_LocalColors') cols.extend(localcolors) else: import json vim.command("let atp_LocalCommands=%s" % json.dumps(localcommands)) vim.command("let atp_LocalEnvironments=%s" % json.dumps(localenvs)) vim.command("let atp_LocalColors=%s" % json.dumps(localcolors)) END if exists("atp_LocalCommands") let b:atp_LocalCommands=map(atp_LocalCommands, 'substitute(v:val, ''\\\\'', ''\'', '''')') else let b:atp_LocalCommands=[] endif if exists("atp_LocalColors") let b:atp_LocalColors=map(atp_LocalColors, 'substitute(v:val, ''\\\\'', ''\'', '''')') else let b:atp_LocalColors=[] endif if exists("atp_LocalEnvironments") let b:atp_LocalEnvironments=map(atp_LocalEnvironments, 'substitute(v:val, ''\\\\'', ''\'', '''')') else let b:atp_LocalEnvironments=[] endif exe "lcd ".fnameescape(pwd) let g:time_LocalCommands_py=reltimestr(reltime(time)) return [ b:atp_LocalEnvironments, b:atp_LocalCommands, b:atp_LocalColors ] endfunction "}}} " atplib#search#LocalAbbreviations {{{ function! atplib#search#LocalAbbreviations() if !exists("b:atp_LocalEnvironments") let no_abbrev= ( exists('g:atp_no_local_abbreviations') ? g:atp_no_local_abbreviations : -1 ) let g:atp_no_local_abbreviations = 1 call LocalCommands(0) if no_abbrev == -1 unlet g:atp_no_local_abbreviations else let g:atp_no_local_abbreviations = no_abbrev endif endif if exists("b:atp_LocalEnvironments") for env in b:atp_LocalEnvironments if !empty(maparg(g:atp_iabbrev_leader.env.g:atp_iabbrev_leader, "i", 1)) " silent echomsg "abbreviation " . g:atp_iabbrev_leader.env.g:atp_iabbrev_leader . " exists." continue endif if exists("g:atp_abbreviate_".env) execute "iabbrev ".g:atp_iabbrev_leader.env.g:atp_iabbrev_leader." \\begin{".env."}".get(g:atp_abbreviate_{env}, 0, "")."\\end{".env."}".get(g:atp_abbreviate_{env}, 1, "O") else execute "iabbrev ".g:atp_iabbrev_leader.env.g:atp_iabbrev_leader." \\begin{".env."}\\end{".env."}O" endif endfor endif endfunction "}}} " Search for Definition in the definition dictionary (atplib#search#make_defi_dict). "{{{ atplib#search#Dsearch function! atplib#search#Dsearch(bang,...) call atplib#write("nobackup") let time = reltime() let o_pattern = a:0 >= 1 ? matchstr(a:1, '\/\=\zs.*[^\/]\ze\/\=') : '' let pattern = '\%(\\def\|\\\%(re\)\=newcommand\s*{\=\|\\providecommand\s*{\=\|\\\%(re\)\=newenvironment\s*{\|\\\%(re\)\=newtheorem\s*{\|\\definecolor\s*{\)\s*\\\=\w*\zs'.o_pattern let preambule_only = ( a:bang == "!" ? 0 : 1 ) let atp_MainFile = atplib#FullPath(b:atp_MainFile) if has("python") let defi_dict = atplib#search#make_defi_dict_py(a:bang, atp_MainFile, pattern) else let defi_dict = atplib#search#make_defi_dict_vim(a:bang, atp_MainFile, pattern) endif if len(defi_dict) > 0 " wipe out the old buffer and open new one instead if bufloaded("DefiSearch") exe "silent bw! " . bufnr("DefiSearch") endif if !exists("b:atp_MainFile") || !exists("b:atp_ProjectDir") " Note: I should write a function to read just one variable from " project file. LoadProjectScript endif setl syntax=tex let defi_list = [] let signs = [] for inputfile in keys(defi_dict) let ifile = readfile(inputfile) for l:range in defi_dict[inputfile] " This respects the options 'smartcase' and 'ignorecase'. let case = ( &l:smartcase && &l:ignorecase && pattern =~ '\u' ? 'noignorecase' : ( &l:ignorecase ? 'ignorecase' : 'noignorecase' )) let condition = ( case == "noignorecase" ? ifile[l:range[0]-1] =~# pattern : ifile[l:range[0]-1] =~? pattern ) if condition " print the lines into defi_list let i=0 let c=0 " add an empty line if the definition is longer than one line if l:range[0] != l:range[1] call add(defi_list, '') let i+=1 endif while c <= l:range[1]-l:range[0] let line=l:range[0]+c call add(defi_list, ifile[line-1]) if c == 0 let cmd = matchstr(ifile[line-1], '\\\%(def\|\%(re\)\?newcommand\s*{\|providecommand\s*{\|\%(re\)\?newenvironment\s*{\|\%(re\)\?newtheorem\s*{\|definecolor\s*{\)\zs[^ {}#]*\ze') call add(signs, [len(defi_list), cmd]) endif let i+=1 let c+=1 endwhile endif endfor endfor if len(defi_list) == 0 redraw echohl ErrorMsg if a:bang == "!" echomsg "[ATP:] definition not found." else echomsg "[ATP:] definition not found in the preambule, try [D or :Dsearch! to search beyond." endif echohl None return endif " open new buffer let window_height= min([g:atp_DsearchMaxWindowHeight, len(defi_list)]) let openbuffer=" +setl\\ buftype=nofile\\ nospell\\ nornu\\ nonu\\ mod\\ noswf\\ nobl\\ bh=wipe " . fnameescape("DefiSearch") if g:vertical == 1 let openbuffer="keepalt vsplit " . openbuffer else let openbuffer="keepalt rightbelow ".window_height."split " . openbuffer endif silent exe openbuffer let &l:statusline="Dsearch: ".o_pattern call setline(1, defi_list) if getline(line(".")) =~ '^\s*$' normal! dd call map(signs, '[v:val[0]-1,v:val[1]]') endif if o_pattern != "" call matchadd('Search', ( &l:ignorecase ? '\c' : '\C' ) .o_pattern) let @/=o_pattern endif setl syntax=tex setl readonly map q :bd " Place signs: if has("signs") && len(signs) > 1 sign unplace * for i in range(0,len(signs)-1) try exe 'sign define '.signs[i][1].' text=>>' exe 'sign place '.(i+1).' line='.signs[i][0].' name='.signs[i][1].' file='.expand('%:p') catch /E474/ if g:atp_devversion echoerr "[signs:] ".'sign place '.(i+1).' line='.signs[i][0].' name='.signs[i][1].' file='.expand('%:p') endif endtry endfor endif else redraw echohl ErrorMsg if a:bang == "!" echomsg "[ATP:] definition not found." else echomsg "[ATP:] definition not found in the preambule, try with a bang ! to search beyond." endif echohl None endif setl nomodifiable let g:source_time_DSEARCH=reltimestr(reltime(time)) endfunction function! atplib#search#DsearchComp(ArgLead, CmdLine, CursorPos) if !exists("b:atp_LocalCommands") LocalCommands endif let list=[] call extend(list, b:atp_LocalCommands) call extend(list, b:atp_LocalColors) call extend(list, b:atp_LocalEnvironments) call filter(list, 'v:val =~ a:ArgLead') call map(list, 'escape(v:val, ''\*'')') return sort(list) endfunction "}}} " Search in tree and return the one level up element and its line number. " {{{ atplib#search#SearchInTree " Before running this function one has to set the two variables " s:branch/s:branch_line to 0. " the a:tree variable should be something like: " a:tree = { b:atp_MainFile, [ TreeOfFiles(b:atp_MainFile)[0], 0 ] } " necessary a rooted tree! " This function remaps keys of dictionary. function! atplib#search#MapDict(dict) let new_dict = {} for key in keys(a:dict) let new_key = fnamemodify(key, ":p") let new_dict[new_key] = a:dict[key] endfor return new_dict endfunction function! atplib#search#SearchInTree(tree, branch, what) if g:atp_debugSIT exe "redir! > ".g:atp_TempDir."/SearchInTree.log" silent! echo "___SEARCH_IN_TREE___" silent! echo "a:branch=". a:branch silent! echo "a:what=" . a:what endif if g:atp_debugSIT >= 2 silent! echo "a:tree=" . string(a:tree) endif " let branch = a:tree[a:branch][0] if a:branch =~ '^\s*\/' let cwd = getcwd() exe "lcd " . fnameescape(b:atp_ProjectDir) let branchArg = ( g:atp_RelativePath ? fnamemodify(a:branch, ":.") : a:branch ) let branchArgN = ( !g:atp_RelativePath ? fnamemodify(a:branch, ":.") : a:branch ) let whatArg = ( g:atp_RelativePath ? fnamemodify(a:what, ":.") : a:what ) let whatArgN = ( !g:atp_RelativePath ? fnamemodify(a:what, ":.") : a:what ) if g:atp_debugSIT silent! echo "*** cwd=" . getcwd() . " b:atp_ProjectDir= " . b:atp_ProjectDir . " " . fnamemodify(a:branch, ":.") . " " . a:branch endif exe "lcd " . fnameescape(cwd) else let branchArg = ( g:atp_RelativePath ? a:branch : atplib#FullPath(a:branch) ) let branchArgN = ( !g:atp_RelativePath ? a:branch : atplib#FullPath(a:branch) ) let whatArg = ( g:atp_RelativePath ? a:what : atplib#FullPath(a:what) ) let whatArgN = ( !g:atp_RelativePath ? a:what : atplib#FullPath(a:what) ) endif if g:atp_debugSIT silent! echo "branchArg=" . branchArg . " branchArgN=" . branchArgN silent! echo "whatArg=" . whatArg . " whatArgN=" . whatArgN endif let branch = get(a:tree, branchArg , get(a:tree, branchArgN, ['NO_BRANCH']))[0] if count(keys(branch), whatArg) || count(keys(branch), whatArgN) " The following variable is used as a return value in " RecursiveSearch! let g:ATP_branch = branchArg let g:ATP_branch_line = get(branch, whatArg, get(branch, whatArgN, ['', 'ERROR']))[1] if g:atp_debugSIT silent! echo "g:ATP_branch=" . g:ATP_branch . " g:ATP_branch_line=" . g:ATP_branch_line redir END endif return branchArg else for new_branch in keys(branch) call atplib#search#SearchInTree(branch, new_branch, whatArg) endfor endif if g:atp_debugSIT redir END endif return endfunction " }}} " Search in all input files recursively. " {{{ __Recursive_Search__ " " Variables are used to pass them to next runs (this function calls it self) " a:main_file = b:atp_MainFile " a:start_file = expand("%:p") /this variable will not change untill the " last instance/ " a:tree = make_tree => make a tree " = any other value => use { a:main_file : [ b:TreeOfFiles, 0] } " a:cur_branch = expand("%") /this will change whenever we change a file/ " a:call_nr = number of the call " a:wrap_nr = if hit top/bottom a:call=0 but a:wrap_nr+=1 " a:winsaveview = winsaveview(0) to resotre the view if the pattern was not found " a:bufnr = bufnr("%") to come back to begining buffer if pattern not found " a:strftime = strftime(0) to compute the time " a:pattern = pattern to search " a:1 = flags: 'bcewWs' " a:2 is not not used: " a:2 = goto = DOWN_ACCEPT / Must not be used by the end user/ " 0/1 1=DOWN_ACCEPT " " g:atp_debugRS if 1 sets debugging messages which are appended to '/tmp/ATP_rs_debug' " you can :set errorfile=/tmp/ATP_rs_debug " and :set efm=.* " if 2 show time " log file : /tmp/ATP_rs_debug " {{{ atplib#search#RecursiveSearch function try function! atplib#search#RecursiveSearch(main_file, start_file, maketree, tree, cur_branch, call_nr, wrap_nr, winsaveview, bufnr, strftime, vim_options, cwd, pattern, subfiles, ... ) let main_file = g:atp_RelativePath ? atplib#RelativePath(a:main_file, b:atp_ProjectDir) : a:main_file let time0 = reltime() " set and restore some options: " foldenable (unset to prevent opening the folds :h winsaveview) " comeback to the starting buffer if a:call_nr == 1 && a:wrap_nr == 1 " Erease message 'search hit TOP, continuing at BOTTOM': if &shortmess =~# 's' echo "" endif if a:vim_options == { 'no_options' : 'no_options' } let vim_options = { 'hidden' : &l:hidden, \ 'foldenable' : &l:foldenable, \ 'autochdir' : &l:autochdir } else let vim_options = a:vim_options endif let &l:hidden = 1 let &l:foldenable = 0 let &l:autochdir = 0 if a:cwd == 'no_cwd' let cwd = getcwd() else let cwd = a:cwd endif exe "lcd " . fnameescape(b:atp_ProjectDir) " This makes it work faster when the input files were not yet opened by vim " some of them will not be shown to the user. " Note: but sometimes files are loaded without filetype what messes up " things. It is possible to make it work I think, but this might not " be needed (speed seems to be fine). " syntax off set eventignore+=Syntax " filetype off " there are many errors in /tmp/ATP_rs_debug file due to this which are not " important. else let vim_options = a:vim_options let cwd = a:cwd endif let subfiles = ( a:subfiles == "" ? atplib#search#SearchPackage('subfiles') : a:subfiles ) " Redirect debuggin messages: if g:atp_debugRS if a:wrap_nr == 1 && a:call_nr == 1 exe "redir! > ".g:atp_TempDir."/RecursiveSearch.log" else exe "redir! >> ".g:atp_TempDir."/RecursiveSearch.log" endif silent echo "________________" silent echo "Args: a:pattern:".a:pattern." call_nr:".a:call_nr. " wrap_nr:".a:wrap_nr . " cwd=" . getcwd() endif let flags_supplied = a:0 >= 1 ? a:1 : "" if flags_supplied =~# 'p' let flags_supplied = substitute(flags_supplied, 'p', '', 'g') echohl WarningMsg echomsg "[ATP:] searching flag 'p' is not supported, filtering it out." echohl None endif if a:maketree == 'make_tree' if g:atp_debugRS silent echo "*** Makeing Tree ***" endif let tree_of_files = TreeOfFiles(main_file)[0] else if g:atp_debugRS silent echo "*** Using Tree ***" endif let tree_of_files = a:tree endif let tree = { main_file : [ tree_of_files, 0 ] } if a:cur_branch != "no cur_branch " let cur_branch = a:cur_branch else let cur_branch = main_file endif if g:atp_debugRS > 1 silent echo "TIME0:" . reltimestr(reltime(time0)) endif let pattern = a:pattern let flags_supplied = substitute(flags_supplied, '[^bcenswWS]', '', 'g') " Add pattern to the search history if a:call_nr == 1 call histadd("search", a:pattern) let @/ = a:pattern endif " Set up searching flags let flag = flags_supplied if a:call_nr > 1 let flag = flags_supplied !~# 'c' ? flags_supplied . 'c' : flags_supplied endif let flag = substitute(flag, 'w', '', 'g') . 'W' let flag = flag !~# 'n' ? substitute(flag, 'n', '', 'g') . 'n' : flag let flag = substitute(flag, 's', '', 'g') if flags_supplied !~# 'b' " forward searching flag for input files: let flag_i = flags_supplied !~# 'c' ? flags_supplied . 'c' : flags_supplied else let flag_i = substitute(flags_supplied, 'c', '', 'g') endif let flag_i = flag_i !~# 'n' ? flag_i . 'n' : flag_i let flag_i = substitute(flag_i, 'w', '', 'g') . 'W' let flag_i = substitute(flag_i, 's', '', 'g') if g:atp_debugRS silent echo " flags_supplied:".flags_supplied." flag:".flag." flag_i:".flag_i." a:1=".(a:0 != 0 ? a:1 : "") endif " FIND PATTERN: let cur_pos = [line("."), col(".")] " We filter out the 's' flag which should be used only once " as the flags passed to next atplib#search#RecursiveSearch()es are based on flags_supplied variable " this will work. let s_flag = flags_supplied =~# 's' ? 1 : 0 let flags_supplied = substitute(flags_supplied, 's', '', 'g') if s_flag call setpos("''", getpos(".")) endif keepjumps let pat_pos = searchpos(pattern, flag) if g:atp_debugRS > 1 silent echo "TIME1:" . reltimestr(reltime(time0)) endif " FIND INPUT PATTERN: " (we do not need to search further than pat_pos) if pat_pos == [0, 0] let stop_line = flag !~# 'b' ? line("$") : 1 else let stop_line = pat_pos[0] endif if subfiles keepjumps let input_pos = searchpos('^[^%]*\\\(input\|include\|subfile\)\s*{', flag_i . 'n', stop_line ) else keepjumps let input_pos = searchpos('^[^%]*\\\(input\|include\)\s*{', flag_i . 'n', stop_line ) endif if g:atp_debugRS > 1 silent echo "TIME2:" . reltimestr(reltime(time0)) endif if g:atp_debugRS silent echo "Positions: ".string(cur_pos)." ".string(pat_pos)." ".string(input_pos)." in branch: ".cur_branch."#".expand("%:p") . " stop_line: " . stop_line endif " Down Accept: " the current value of down_accept let DOWN_ACCEPT = a:0 >= 2 ? a:2 : 0 " the value of down_accept in next turn let down_accept = getline(input_pos[0]) =~ pattern || input_pos == [0, 0] ? 1 : 0 " if g:atp_debugRS " silent echo "DOWN_ACCEPT=" . DOWN_ACCEPT . " down_accept=" . down_accept " endif " Decide what to do: accept the pattern, go to higher branch, go to lower " branch or say Pattern not found if flags_supplied !~# 'b' " FORWARD " cur < pat <= input if atplib#CompareCoordinates(cur_pos,pat_pos) && atplib#CompareCoordinates_leq(pat_pos, input_pos) let goto_s = 'ACCEPT' " cur == pat <= input elseif cur_pos == pat_pos && atplib#CompareCoordinates_leq(pat_pos, input_pos) " this means that the 'flag' variable has to contain 'c' or the " wrapscan is on " ACCEPT if 'c' and wrapscan is off or there is another match below, " if there is not go UP. let wrapscan = ( flags_supplied =~# 'w' || &l:wrapscan && flags_supplied !~# 'W' ) if flag =~# 'c' let goto_s = 'ACCEPT' elseif wrapscan " if in wrapscan and without 'c' flag let goto_s = 'UP' else " this should not happen: cur == put can hold only in two cases: " wrapscan is on or 'c' is used. let goto_s = 'ERROR' endif " pat < cur <= input elseif atplib#CompareCoordinates(pat_pos, cur_pos) && atplib#CompareCoordinates_leq(cur_pos, input_pos) let goto_s = 'UP' " cur < input < pat elseif atplib#CompareCoordinates(cur_pos, input_pos) && atplib#CompareCoordinates(input_pos, pat_pos) let goto_s = 'UP' " cur < input == pat /we are looking for '\\input'/ elseif atplib#CompareCoordinates(cur_pos, input_pos) && input_pos == pat_pos let goto_s = 'ACCEPT' " input < cur <= pat (includes input = 0]) elseif atplib#CompareCoordinates(input_pos, cur_pos) && atplib#CompareCoordinates_leq(cur_pos, pat_pos) " cur == pat thus 'flag' contains 'c'. let goto_s = 'ACCEPT' " cur == input elseif cur_pos == input_pos let goto_s = 'UP' " cur < input < pat " input == 0 /there is no 'input' ahead - flag_i contains 'W'/ " /but there is no 'pattern ahead as well/ " at this stage: pat < cur (if not then input = 0 < cur <= pat was done above). elseif input_pos == [0, 0] if expand("%:p") == fnamemodify(main_file, ":p") " wrapscan if ( flags_supplied =~# 'w' || &l:wrapscan && flags_supplied !~# 'W' ) let new_flags = substitute(flags_supplied, 'w', '', 'g') . 'W' if a:wrap_nr <= 2 call cursor(1,1) if g:atp_debugRS silent echo " END 1 new_flags:" . new_flags redir END endif keepjumps call atplib#search#RecursiveSearch(main_file, a:start_file, "", tree_of_files, a:cur_branch, 1, a:wrap_nr+1, a:winsaveview, a:bufnr, a:strftime, vim_options, cwd, pattern, subfiles, new_flags) return else let goto_s = "REJECT" " echohl ErrorMsg " echomsg 'Pattern not found: ' . a:pattern " echohl None endif else let goto_s = "REJECT" " echohl ErrorMsg " echomsg 'Pattern not found: ' . a:pattern " echohl None endif " if we are not in the main file go up. else let goto_s = "DOWN" endif else let goto_s = 'ERROR' endif else " BACKWARD " input <= pat < cur (pat != 0) if atplib#CompareCoordinates(pat_pos, cur_pos) && atplib#CompareCoordinates_leq(input_pos, pat_pos) && pat_pos != [0, 0] " input < pat if input_pos != pat_pos let goto_s = 'ACCEPT' " input == pat else let goto_s = 'UP' endif " input <= pat == cur (input != 0) /pat == cur => pat != 0/ elseif cur_pos == pat_pos && atplib#CompareCoordinates_leq(input_pos, pat_pos) && input_pos != [0, 0] " this means that the 'flag' variable has to contain 'c' or the " wrapscan is on let wrapscan = ( flags_supplied =~# 'w' || &l:wrapscan && flags_supplied !~# 'W' ) if flag =~# 'c' let goto_s = 'ACCEPT' elseif wrapscan " if in wrapscan and without 'c' flag let goto_s = 'UP' else " this should not happen: cur == put can hold only in two cases: " wrapscan is on or 'c' is used. let goto_s = 'ERROR' endif " input <= cur < pat (input != 0) elseif atplib#CompareCoordinates(cur_pos, pat_pos) && atplib#CompareCoordinates_leq(input_pos, cur_pos) && input_pos != [0, 0] let goto_s = 'UP' " pat < input <= cur (input != 0) elseif atplib#CompareCoordinates_leq(input_pos, cur_pos) && atplib#CompareCoordinates(pat_pos, input_pos) && input_pos != [0, 0] let goto_s = 'UP' " input == pat < cur (pat != 0) /we are looking for '\\input'/ elseif atplib#CompareCoordinates(input_pos, cur_pos) && input_pos == pat_pos && pat_pos != [0, 0] let goto_s = 'ACCEPT' " pat <= cur < input (pat != 0) elseif atplib#CompareCoordinates(cur_pos, input_pos) && atplib#CompareCoordinates_leq(pat_pos, cur_pos) && input_pos != [0, 0] " cur == pat thus 'flag' contains 'c'. let goto_s = 'ACCEPT' " cur == input elseif cur_pos == input_pos let goto_s = 'UP' " input == 0 /there is no 'input' ahead - flag_i contains 'W'/ " /but there is no 'pattern ahead as well/ " at this stage: cur < pat || pat=input=0 (if not then pat <= cur was done above, input=pat=0 is the " only posibility to be passed by the above filter). elseif input_pos == [0, 0] " I claim that then cur < pat or pat=0 if expand("%:p") == fnamemodify(main_file, ":p") " wrapscan if ( flags_supplied =~# 'w' || &l:wrapscan && flags_supplied !~# 'W' ) let new_flags = substitute(flags_supplied, 'w', '', 'g') . 'W' if a:wrap_nr <= 2 call cursor(line("$"), col("$")) if g:atp_debugRS silent echo " END 2 new_flags:".new_flags redir END endif keepjumps call atplib#search#RecursiveSearch(main_file, a:start_file, "", tree_of_files, a:cur_branch, 1, a:wrap_nr+1, a:winsaveview, a:bufnr, a:strftime, vim_options, cwd, pattern, subfiles, new_flags) if g:atp_debugRS > 1 silent echo "TIME_END:" . reltimestr(reltime(time0)) endif return else let goto_s = "REJECT" " echohl ErrorMsg " echomsg 'Pattern not found: ' . a:pattern " echohl None endif else let goto_s = "REJECT" endif " if we are not in the main file go up. else let goto_s = "DOWN" " If using the following line DOWN_ACCEPT and down_accept " variables are not needed. This seems to be the best way. " There is no need to use this feature for " \input files. if pattern =~ '\\\\input' || pattern =~ '\\\\include' || pattern =~ '\\\\subfile' " if getline(input_pos[0]) =~ pattern || getline(".") =~ pattern let goto_s = "DOWN_ACCEPT" endif endif else let goto_s = 'ERROR' endif endif if g:atp_debugRS silent echo "goto_s:".goto_s endif if g:atp_debugRS >= 2 silent echo "TIME ***goto*** " . reltimestr(reltime(time0)) endif " When ACCEPTING the line: if goto_s == 'ACCEPT' keepjumps call setpos(".", [ 0, pat_pos[0], pat_pos[1], 0]) if flags_supplied =~# 'e' keepjumps call search(pattern, 'e', line(".")) endif "A Better solution must be found. " if &l:hlsearch " execute '2match Search /'.pattern.'/' " endif let time = matchstr(reltimestr(reltime(a:strftime)), '\d\+\.\d\d\d') . "sec." if &shortmess =~# 's' if a:wrap_nr == 2 && flags_supplied =~# 'b' redraw echohl WarningMsg echo "search hit TOP, continuing at BOTTOM " echohl None elseif a:wrap_nr == 2 redraw echohl WarningMsg echo "search hit BOTTOM, continuing at TOP " echohl None endif endif if g:atp_debugRS silent echo "FOUND PATTERN: " . a:pattern . " time " . time silent echo "" redir END endif " restore vim options if a:vim_options != { 'no_options' : 'no_options' } for option in keys(a:vim_options) execute "let &l:".option."=".a:vim_options[option] endfor endif exe "lcd " . fnameescape(cwd) set eventignore-=Syntax syntax enable " filetype on " filetype detect return " when going UP elseif goto_s == 'UP' call setpos(".", [ 0, input_pos[0], input_pos[1], 0]) " Open file and Search in it" " This should be done by kpsewhich: if subfiles let file = matchstr(getline(input_pos[0]), '\\\(input\|subfile\|include\)\s*{\zs[^}]*\ze}') else let file = matchstr(getline(input_pos[0]), '\\\(input\|include\)\s*{\zs[^}]*\ze}') endif if g:atp_debugRS silent echo " ------ file=".file." ".getline(input_pos[0]) silent echo " ------ input_pos=".string(input_pos) endif let file = atplib#append_ext(file, '.tex') let keepalt = ( @# == '' || expand("%:p") == a:start_file ? '' : 'keepalt' ) let open = flags_supplied =~ 'b' ? keepalt . ' edit + ' : keepalt.' edit +1 ' let swapfile = globpath(fnamemodify(file, ":h"), ( has("unix") ? "." : "" ) . fnamemodify(file, ":t") . ".swp") if !( a:call_nr == 1 && a:wrap_nr == 1 ) let open = "silent keepjumps " . open endif let projectVarDict = SaveProjectVariables() if g:atp_debugRS >= 3 silent echo "projectVarDict : " . string(projectVarDict) let g:projectVarDict = projectVarDict elseif g:atp_debugRS >= 2 let g:projectVarDict = projectVarDict endif if g:atp_debugRS >= 2 silent echo "TIME ***goto UP before open*** " . reltimestr(reltime(time0)) endif " ERROR: When opening for the first time there are two errors which " I cannot figure out. " OPEN: if empty(swapfile) || bufexists(file) if g:atp_debugRS >= 2 silent echo "Alternate (before open) " . bufname("#") silent echo " XXXXXXXX file=".file endif " silent should not have bang, which prevents E325 to be shown. silent execute open . fnameescape(file) if g:atp_mapNn call atplib#search#ATP_ToggleNn(1,"on") else call atplib#search#ATP_ToggleNn(1,"off") endif " if &l:filetype != "tex" " setl filetype=tex " endif else echoerr "Recursive Search: swap file: " . swapfile . " exists. Aborting." set eventignore-=Syntax syntax enable return endif if g:atp_debugRS >= 2 exe "redir! >> ".g:atp_TempDir."/RecursiveSearch.log" silent echo "TIME ***goto UP after open*** " . reltimestr(reltime(time0)) endif call RestoreProjectVariables(projectVarDict) if g:atp_debugRS >= 2 silent echo "TIME ***goto UP restore variables *** " . reltimestr(reltime(time0)) endif if flags_supplied =~# 'b' call cursor(line("$"), col("$")) else call cursor(1,1) endif if g:atp_debugRS silent echo "In higher branch: " . file . " POS " line(".").":".col(".") silent echo "Open Command: '" . open . file . "'" silent echo "exist b:TreeOfFiles " . exists("b:TreeOfFiles") silent echo "flags_supplied: " . flags_supplied endif if g:atp_debugRS >= 2 silent echo "Alternate (after open) " . bufname("#") endif if g:atp_debugRS >= 2 silent echo "TIME_END: " . reltimestr(reltime(time0)) endif let flag = flags_supplied =~ 'W' ? flags_supplied : flags_supplied . 'W' if @# == '' keepjumps call atplib#search#RecursiveSearch(main_file, a:start_file, "", tree_of_files, expand("%:p"), a:call_nr+1, a:wrap_nr, a:winsaveview, a:bufnr, a:strftime, vim_options, cwd, pattern, subfiles, flags_supplied, down_accept) else keepalt keepjumps call atplib#search#RecursiveSearch(main_file, a:start_file, "", tree_of_files, expand("%:p"), a:call_nr+1, a:wrap_nr, a:winsaveview, a:bufnr, a:strftime, vim_options, cwd, pattern, subfiles, flags_supplied, down_accept) endif if g:atp_debugRS redir END endif return " when going DOWN elseif goto_s == 'DOWN' || goto_s == 'DOWN_ACCEPT' " We have to get the element in the tree one level up + line number let g:ATP_branch = "nobranch" let g:ATP_branch_line = "nobranch_line" if g:atp_debugRS silent echo " SearchInTree Args " . expand("%:p") endif if g:atp_RelativePath call atplib#search#SearchInTree(l:tree, main_file, atplib#RelativePath(expand("%:p"), resolve(b:atp_ProjectDir))) else call atplib#search#SearchInTree(l:tree, main_file, expand("%:p")) endif if g:atp_debugRS silent echo " SearchInTree found " . g:ATP_branch . " g:ATP_branch_line=" . g:ATP_branch_line endif if g:ATP_branch == "nobranch" echohl ErrorMsg echomsg "[ATP:] Error. Try to run :S! or :InputFiles command." echohl None silent! echomsg "Tree=" . string(l:tree) silent! echomsg "MainFile " . main_file . " current_file=" . expand("%:p") silent! echomsg "Going to file : " . g:ATP_branch . " ( g:ATP_branch ) " " restore the window and buffer! let keepalt = ( @# == '' || expand("%:p") == a:start_file ? '' : 'keepalt' ) silent execute keepalt. " keepjumps edit #" . a:bufnr if g:atp_mapNn call atplib#search#ATP_ToggleNn(1,"on") else call atplib#search#ATP_ToggleNn(1,"off") endif call winrestview(a:winsaveview) if g:atp_debugRS redir END endif set eventignore-=Syntax syntax enable return endif let next_branch = atplib#FullPath(g:ATP_branch) let swapfile = globpath(fnamemodify(next_branch, ":h"), ( has("unix") ? "." : "" ) . fnamemodify(next_branch, ":t") . ".swp") let keepalt = ( @# == '' || expand("%:p") == a:start_file ? '' : 'keepalt' ) if a:call_nr == 1 && a:wrap_nr == 1 let open = 'silent '.keepalt.' edit +'.g:ATP_branch_line." ".fnameescape(next_branch) else let open = 'silent keepjumps '.keepalt.' edit +'.g:ATP_branch_line." ".fnameescape(next_branch) endif if g:atp_debugRS >= 2 silent echo "TIME ***goto DOWN before open*** " . reltimestr(reltime(time0)) endif let projectVarDict = SaveProjectVariables() if empty(swapfile) || bufexists(next_branch) if g:atp_debugRS >= 2 silent echo "Alternate (before open) " . bufname("#") endif " silent should not have bang, which prevents E325 to be shown. silent execute open if g:atp_mapNn call atplib#search#ATP_ToggleNn(1,"on") else call atplib#search#ATP_ToggleNn(1,"off") endif " if &l:filetype != "tex" " setl filetype=tex " endif else echoerr "Recursive Search: swap file: " . swapfile . " exists. Aborting." set eventignore-=Syntax syntax enable return endif if g:atp_debugRS >= 2 silent echo "TIME ***goto DOWN after open*** " . reltimestr(reltime(time0)) endif call RestoreProjectVariables(projectVarDict) if g:atp_debugRS >= 2 silent echo "TIME ***goto DOWN restore project variables *** " . reltimestr(reltime(time0)) endif " call cursor(g:ATP_branch_line, 1) if flags_supplied !~# 'b' if subfiles keepjumps call search('\m\\\(input\|\include\|subfile\)\s*{[^}]*}', 'e', line(".")) else keepjumps call search('\m\\\(input\|\include\)\s*{[^}]*}', 'e', line(".")) endif endif if g:atp_debugRS silent echo "In lower branch: " . g:ATP_branch . " branch_line=" . g:ATP_branch_line. " POS " . line(".") . ":" . col(".") silent echo "Open Command '" . open . "'" silent echo "exist b:TreeOfFiles " . exists("b:TreeOfFiles") silent echo "flags_supplied: " . flags_supplied endif if g:atp_debugRS >= 2 silent echo "Alternate (after open) " . bufname("#") endif if g:atp_debugRS > 1 silent echo "TIME_END: " . reltimestr(reltime(time0)) endif unlet g:ATP_branch unlet g:ATP_branch_line " let flag = flags_supplied =~ 'W' ? flags_supplied : flags_supplied . 'W' if goto_s == 'DOWN' if @# == '' keepjumps call atplib#search#RecursiveSearch(main_file, a:start_file, "", tree_of_files, expand("%:p"), a:call_nr+1, a:wrap_nr, a:winsaveview, a:bufnr, a:strftime, vim_options, cwd, pattern, subfiles, flags_supplied) else keepalt keepjumps call atplib#search#RecursiveSearch(main_file, a:start_file, "", tree_of_files, expand("%:p"), a:call_nr+1, a:wrap_nr, a:winsaveview, a:bufnr, a:strftime, vim_options, cwd, pattern, subfiles, flags_supplied) endif endif " when REJECT elseif goto_s == 'REJECT' echohl ErrorMsg echomsg "[ATP:] pattern not found" echohl None if g:atp_debugRS > 1 silent echo "TIME_END:" . reltimestr(reltime(time0)) endif " restore the window and buffer! " it is better to remember bufnumber let keepalt = ( @# == '' || expand("%:p") == a:start_file ? '' : 'keepalt' ) silent execute "keepjumps ".keepalt." edit #" . a:bufnr if g:atp_mapNn call atplib#search#ATP_ToggleNn(1,"on") else call atplib#search#ATP_ToggleNn(1,"off") endif call winrestview(a:winsaveview) if g:atp_debugRS silent echo "" redir END endif " restore vim options if a:vim_options != { 'no_options' : 'no_options' } for option in keys(a:vim_options) execute "let &l:".option."=".a:vim_options[option] endfor endif exe "lcd " . fnameescape(cwd) set eventignore-=Syntax syntax enable " filetype on " filetype detect return " when ERROR elseif echohl ErrorMsg echomsg "[ATP:] this is a bug in ATP." echohl None " restore vim options if a:vim_options != { 'no_options' : 'no_options' } for option in keys(a:vim_options) execute "let &l:".option."=".a:vim_options[option] endfor endif exe "lcd " . fnameescape(cwd) set eventignore-=Syntax " filetype on " filetype detect " restore the window and buffer! let keepalt = ( @# == '' || expand("%:p") == a:start_file ? '' : 'keepalt' ) silent execute "keepjumps ".keepalt." edit #" . a:bufnr if g:atp_mapNn call atplib#search#ATP_ToggleNn(1,"on") else call atplib#search#ATP_ToggleNn(1,"off") endif call winrestview(a:winsaveview) return endif endfunction catch /E127:/ endtry " }}} " User interface to atplib#search#RecursiveSearch function. " atplib#search#GetSearchArgs {{{ " This functionn returns arguments from - a list [ pattern, flag ] " It allows to pass arguments to atplib#search#Search in a similar way to :vimgrep, :ijump, ... function! atplib#search#GetSearchArgs(Arg,flags) let g:Arg = a:Arg if a:Arg =~ '^\/' let pattern = matchstr(a:Arg, '^\/\zs.*\ze\/') let flag = matchstr(a:Arg, '\/.*\/\s*\zs['.a:flags.']*\ze\s*$') elseif a:Arg =~ '^\i' && a:Arg !~ '^\w' let pattern = matchstr(a:Arg, '^\(\i\)\zs.*\ze\1') let flag = matchstr(a:Arg, '\(\i\).*\1\s*\zs['.a:flags.']*\ze\s*$') else let pattern = matchstr(a:Arg, '^\zs\S*\ze') let flag = matchstr(a:Arg, '^\S*\s*\zs['.a:flags.']*\ze\s*$') endif return [ pattern, flag ] endfunction "}}} " {{{ atplib#search#Search() try function! atplib#search#Search(Bang, Arg) "Like :s, :S should be a jump-motion (see :help jump-motions) normal! m` let atp_MainFile = atplib#FullPath(b:atp_MainFile) let [ pattern, flag ] = atplib#search#GetSearchArgs(a:Arg, 'bceswWx') if pattern == "" echohl ErrorMsg echomsg "[ATP:] enclose the pattern with /.../" echohl None return endif let subfiles = atplib#search#SearchPackage('subfiles') if a:Bang == "!" || !exists("b:TreeOfFiles") call atplib#search#RecursiveSearch(atp_MainFile, expand("%:p"), 'make_tree', '', expand("%:p"), 1, 1, winsaveview(), bufnr("%"), reltime(), { 'no_options' : 'no_options' }, 'no_cwd', pattern, subfiles, flag) else call atplib#search#RecursiveSearch(atp_MainFile, expand("%:p"), '', deepcopy(b:TreeOfFiles), expand("%:p"), 1, 1, winsaveview(), bufnr("%"), reltime(), { 'no_options' : 'no_options' }, 'no_cwd', pattern, subfiles, flag) endif endfunction catch /E127: Cannot redefine function/ endtry " }}} function! atplib#search#ATP_ToggleNn(silent,...) " {{{ " With bang it is only used in RecursiveSearch function (where it is used " twice in a row). let on = ( a:0 ? ( a:1 == 'on' || string(a:1) == '1' ? 1 : 0 ) : !g:atp_mapNn ) if !on silent! nunmap n silent! nunmap N silent! aunmenu LaTeX.Toggle\ Nn\ [on] let g:atp_mapNn = 0 nmenu 550.79 &LaTeX.Toggle\ &Nn\ [off]:ToggleNn :ToggleNn imenu 550.79 &LaTeX.Toggle\ &Nn\ [off]:ToggleNn :ToggleNna tmenu LaTeX.Toggle\ Nn\ [off] atp maps to n,N. if !a:silent echomsg "[ATP:] vim nN maps" endif else silent! nmap n RecursiveSearchn silent! nmap N RecursiveSearchN silent! aunmenu LaTeX.Toggle\ Nn\ [off] let g:atp_mapNn = 1 nmenu 550.79 &LaTeX.Toggle\ &Nn\ [on]:ToggleNn :ToggleNn imenu 550.79 &LaTeX.Toggle\ &Nn\ [on]:ToggleNn :ToggleNna tmenu LaTeX.Toggle\ Nn\ [on] n,N vim normal commands. if !a:silent echomsg "[ATP:] atp nN maps" endif endif endfunction function! atplib#search#SearchHistCompletion(ArgLead, CmdLine, CursorPos) let search_history=[] let hist_entry = histget("search") let nr = 0 while hist_entry != "" call add(search_history, hist_entry) let nr -= 1 let hist_entry = histget("search", nr) endwhile return filter(search_history, "v:val =~# '^'.a:ArgLead") endfunction "}}} "}}} " These are only variables and front end functions for Bib Search Engine of ATP. " Search engine is define in autoload/atplib.vim script library. "{{{ Bibliography Search "-------------SEARCH IN BIBFILES ---------------------- " This function counts accurence of a:keyword in string a:line, " there are two methods keyword is a string to find (a:1=0)or a pattern to " match, the pattern used to is a:keyword\zs.* to find the place where to cut. " DEBUG: " command -buffer -nargs=* Count :echo atplib#count() " Front End Function " {{{ BibSearch " There are three arguments: {pattern}, [flags, [choose]] function! atplib#search#BibSearch(bang,...) " let pattern = a:0 >= 1 ? a:1 : "" " let flag = a:0 >= 2 ? a:2 : "" let time=reltime() let Arg = ( a:0 >= 1 ? a:1 : "" ) if Arg != "" let [ pattern, flag ] = atplib#search#GetSearchArgs(Arg, 'aetbjsynvpPNShouH@BcpmMtTulL') else let [ pattern, flag ] = [ "", ""] endif let b:atp_LastBibPattern = pattern " This cannot be set here. It is set later by atplib#bibsearch#showresults function. " let b:atp_LastBibFlags = flag let @/ = pattern if g:atp_debugBS exe "redir! > ".g:atp_TempDir."/Bibsearch.log" silent! echo "==========BibSearch==========================" silent! echo "b:BibSearch_pattern=" . pattern silent! echo "b:BibSearch bang=" . a:bang silent! echo "b:BibSearch flag=" . flag let g:BibSearch_pattern = pattern let g:BibSearch_bang = a:bang let g:BibSearch_flag = flag redir END endif if !exists("s:bibdict") let s:bibdict={} if !exists("b:ListOfFiles") || !exists("b:TypeDict") || a:bang == "!" call TreeOfFiles(b:atp_MainFile) endif for file in b:ListOfFiles if b:TypeDict[file] == "bib" if atplib#FullPath(file) != file let s:bibdict[file]=readfile(atplib#search#KpsewhichFindFile('bib', file)) else let s:bibdict[file]=readfile(file) endif endif endfor endif let b:atp_BibFiles=keys(s:bibdict) if has("python") && g:atp_bibsearch == "python" call atplib#bibsearch#showresults(a:bang, atplib#bibsearch#searchbib_py(a:bang, pattern, keys(s:bibdict)), flag, pattern, s:bibdict) else call atplib#bibsearch#showresults("", atplib#bibsearch#searchbib(pattern, s:bibdict), flag, pattern, s:bibdict) endif let g:time_BibSearch=reltimestr(reltime(time)) endfunction " }}} "}}} " Other Searching Tools: " {{{1 atplib#search#KpsewhichGlobPath " a:format is the format as reported by kpsewhich --help " a:path path if set to "", then kpsewhich will find the path. " The default is what 'kpsewhich -show-path tex' returns " with "**" appended. " a:name can be "*" then finds all files with the given extension " or "*.cls" to find all files with a given extension. " a:1 modifiers (the default is ":t:r") " a:2 filters path names matching the pattern a:1 " a:3 filters out path names not matching the pattern a:2 " " Argument a:path was added because it takes time for kpsewhich to return the " path (usually ~0.5sec). ATP asks kpsewhich on start up " (g:atp_kpsewhich_tex) and then locks the variable (this will work " unless sb is reinstalling tex (with different personal settings, " changing $LOCALTEXMF) during vim session - not that often). " " Example: call atplib#search#KpsewhichGlobPath('tex', '', '*', ':p', '^\(\/home\|\.\)','\%(texlive\|kpsewhich\|generic\)') " gives on my system only the path of current dir (/.) and my localtexmf. " this is done in 0.13s. The long pattern is to " " atplib#search#KpsewhichGlobPath({format}, {path}, {expr=name}, [ {mods}, {pattern_1}, {pattern_2}]) function! atplib#search#KpsewhichGlobPath(format, path, name, ...) let time = reltime() let modifiers = a:0 == 0 ? ":t:r" : a:1 if a:path == "" let path = substitute(substitute(system("kpsewhich -show-path ".a:format ),'!!','','g'),'\/\/\+','\/','g') let path = substitute(path,':\|\n',',','g') let path_list = split(path, ',') let idx = index(path_list, '.') if idx != -1 let dot = remove(path_list, index(path_list,'.')) . "," else let dot = "" endif call map(path_list, 'v:val . "**"') let path_list = ['.']+path_list let path = join(path_list, ',') else let path = a:path endif " If a:2 is non zero (if not given it is assumed to be 0 for compatibility " reasons) if get(a:000, 1, 0) != "0" if !exists("path_list") let path_list = split(path, ',') endif call filter(path_list, 'v:val =~ a:2') let path = join(path_list, ',') endif if get(a:000, 2, 0) != "0" if !exists("path_list") let path_list = split(path, ',') endif call filter(path_list, 'v:val !~ a:3') let path = join(path_list, ',') endif let list = split(globpath(path, a:name),"\n") if modifiers != ":p" call map(list, 'fnamemodify(v:val, modifiers)') endif let g:time_KpsewhichGlobPath=reltimestr(reltime(time)) return list endfunction " }}}1 " {{{1 atplib#search#KpsewhichFindFile " the arguments are similar to atplib#KpsewhichGlob except that the a:000 list " is shifted: " a:1 = path " if set to "" then kpsewhich will find the path. " a:2 = count (as for findfile()) " when count < 0 returns a list of all files found " a:3 = modifiers " a:4 = positive filter for path (see KpsewhichGLob a:1) " a:5 = negative filter for path (see KpsewhichFind a:2) " " needs +path_extra vim feature " " atp#KpsewhichFindFile({format}, {expr=name}, [{path}, {count}, {mods}, {pattern_1}, {pattern_2}]) function! atplib#search#KpsewhichFindFile(format, name, ...) " Unset the suffixadd option let saved_sua = &l:suffixesadd let &l:sua = "" " let time = reltime() let path = a:0 >= 1 ? a:1 : "" let l:count = a:0 >= 2 ? a:2 : 0 let modifiers = a:0 >= 3 ? a:3 : "" " This takes most of the time! if !path let path = substitute(substitute(system("kpsewhich -show-path ".a:format ),'!!','','g'),'\/\/\+','\/','g') let path = substitute(path,':\|\n',',','g') let path_list = split(path, ',') let idx = index(path_list, '.') if idx != -1 let dot = remove(path_list, index(path_list,'.')) . "," else let dot = "" endif call map(path_list, 'v:val . "**"') let path = dot . join(path_list, ',') unlet path_list endif " If a:2 is non zero (if not given it is assumed to be 0 for compatibility " reasons) if get(a:000, 3, 0) != 0 let path_list = split(path, ',') call filter(path_list, 'v:val =~ a:4') let path = join(path_list, ',') endif if get(a:000, 4, 0) != 0 let path_list = split(path, ',') call filter(path_list, 'v:val !~ a:5') let path = join(path_list, ',') endif let g:name = a:name let g:path = path let g:count = l:count if l:count >= 1 if has("python") let result = atplib#search#findfile(a:name, path, l:count) else let result = findfile(a:name, path, l:count) endif elseif l:count == 0 if has("python") let result = atplib#search#findfile(a:name, path) else let result = findfile(a:name, path) endif elseif l:count < 0 if has("python") let result = atplib#search#findfile(a:name, path, -1) else let result = findfile(a:name, path, -1) endif endif if l:count >= 0 && modifiers != "" let result = fnamemodify(result, modifiers) elseif l:count < 0 && modifiers != "" call map(result, 'fnamemodify(v:val, modifiers)') endif let &l:sua = saved_sua return result endfunction " }}}1 " {{{1 atplib#search#findfile function! atplib#search#findfile(fname, ...) " Python implementation of the vim findfile() function. let time = reltime() let path = ( a:0 >= 1 ? a:1 : &l:path ) let l:count = ( a:0 >= 2 ? a:2 : 1 ) python << EOF import vim import os.path import glob import json path=vim.eval("path") fname=vim.eval("a:fname") file_list = [] for p in path.split(","): if len(p) >= 2 and p[-2:] == "**": file_list.extend(glob.glob(os.path.join( p[:-2], fname ))) file_list.extend(glob.glob(os.path.join( p, fname ))) vim.command("let file_list=%s" % json.dumps(file_list)) EOF if l:count == -1 return file_list elseif l:count <= len(file_list) return file_list[l:count-1] else return "" endif endfunction "}}}1 " atplib#search#SearchPackage {{{1 " " This function searches if the package in question is declared or not. " Returns the line number of the declaration or 0 if it was not found. " " It was inspired by autex function written by Carl Mueller, math at carlm e4ward c o m " and made work for project files using lvimgrep. " " This function doesn't support plaintex files (\\input{}) " ATP support plaintex input lines in a different way (but not that flexible " as this: for plaintex I use atplib#GrepPackageList on startup (only!) and " then match input name with the list). " " name = package name (tikz library name) " a:1 = stop line (number of the line \\begin{document} " a:2 = pattern matching the command (without '^[^%]*\\', just the name) " to match \usetikzlibrary{...,..., - function! atplib#search#SearchPackage(name,...) let atp_MainFile = atplib#FullPath(b:atp_MainFile) if !filereadable(atp_MainFile) silent echomsg "[ATP:] atp_MainFile : " . atp_MainFile . " is not readable " return endif let cwd = getcwd() if exists("b:atp_ProjectDir") && getcwd() != b:atp_ProjectDir try exe "lcd " . fnameescape(b:atp_ProjectDir) catch /E344/ endtry endif if getbufvar("%", "atp_MainFile") == "" call SetProjectName() endif let com = a:0 >= 2 ? a:2 : 'usepackage\s*\%(\[[^\]]*\]\)\?' " If the current file is the atp_MainFile if expand("%:p") == atp_MainFile if !exists("saved_pos") let saved_pos=getpos(".") endif keepjumps call setpos(".",[0,1,1,0]) let stop_line = search('^\([^%]\|\\%]\)*\\begin\s*{\s*document\s*}', 'ncW') if stop_line != 0 keepjumps let ret = search('\C^[^%]*\\'.com.'\s*{[^}]*'.a:name,'ncW', stop_line) keepjump call setpos(".",saved_pos) exe "lcd " . fnameescape(cwd) return ret else keepjumps let ret = search('\C^[^%]*\\'.com.'\s*{[^}]*'.a:name,'ncW') keepjump call setpos(".", saved_pos) exe "lcd " . fnameescape(cwd) return ret endif " If the current file is not the mainfile else " Cache the Preambule / it is not changing so this is completely safe / if !exists("s:Preambule") let s:Preambule = readfile(atp_MainFile) endif let lnum = 1 for line in s:Preambule if line =~ '^[^%]*\\'.com.'\s*{[^}]*\C'.a:name exe "lcd " . fnameescape(cwd) return lnum endif if line =~ '^\([^%]\|\\%\)*\\begin\s*{\s*document\s*}' if lnum < len(s:Preambule) call remove(s:Preambule, lnum-1, -1) endif exe "lcd " . fnameescape(cwd) return 0 endif let lnum += 1 endfor endif " echo reltimestr(reltime(time)) " If the package was not found return 0 exe "lcd " . fnameescape(cwd) return 0 endfunction " }}}1 "{{{1 atplib#search#GrepPackageList " This function returns list of packages declared in the b:atp_MainFile (or " a:2). If the filetype is plaintex it returns list of all \input{} files in " the b:atp_MainFile. " I'm not shure if this will be OK for project files written in plaintex: Can " one declare a package in the middle of document? probably yes. So it might " be better to use TreeOfFiles in that case. " This takes =~ 0.02 s. This is too long to call it in complete#TabCompletion. function! atplib#search#GrepPackageList(...) " let time = reltime() let file = a:0 >= 2 ? a:2 : getbufvar("%", "atp_MainFile") let pat = a:0 >= 1 ? a:1 : '' if file == "" return [] endif let ftype = getbufvar(file, "&filetype") if pat == '' if ftype =~ '^\(ams\)\=tex$' let pat = '\\usepackage\s*\(\[[^]]*\]\)\=\s*{' elseif ftype == 'plaintex' let pat = '\\input\s*{' else " echoerr "ATP doesn't recognize the filetype " . &l:filetype . ". Using empty list of packages." return [] endif endif let saved_loclist = getloclist(0) try silent execute 'lvimgrep /^[^%]*'.pat.'/j ' . fnameescape(file) catch /E480:/ call setloclist(0, [{'text' : 'empty' }]) endtry let loclist = getloclist(0) call setloclist(0, saved_loclist) let pre = map(loclist, 'v:val["text"]') let pre_l = [] for line in pre let package_l = matchstr(line, pat.'\zs[^}]*\ze}') call add(pre_l, package_l) endfor " We make a string of packages separeted by commas and the split it " (compatibility with \usepackage{package_1,package_2,...}) let pre_string = join(pre_l, ',') let pre_list = split(pre_string, ',') call filter(pre_list, "v:val !~ '^\s*$'") " echo reltimestr(reltime(time)) return pre_list endfunction "{{{1 atplib#search#GrepPreambule function! atplib#search#GrepPreambule(pattern, ...) let saved_loclist = getloclist(0) let atp_MainFile = ( a:0 >= 1 ? a:1 : atplib#FullPath(b:atp_MainFile) ) let winview = winsaveview() exe 'silent! 1lvimgrep /^[^%]*\\begin\s*{\s*document\s*}/j ' . fnameescape(atp_MainFile) let linenr = get(get(getloclist(0), 0, {}), 'lnum', 'nomatch') if linenr == "nomatch" call setloclist(0, saved_loclist) return endif exe 'silent! lvimgrep /'.a:pattern.'\%<'.linenr.'l/jg ' . fnameescape(atp_MainFile) let matches = getloclist(0) call setloclist(0, saved_loclist) return matches endfunction " atplib#search#DocumentClass {{{1 function! atplib#search#DocumentClass(file) if bufloaded(a:file) let bufnr = bufnr(a:file) let file = getbufline(bufnr, 1, 50) elseif filereadable(a:file) let file = readfile(a:file, 50) else return '' endif let lnr = -1 let documentclass = '' for line in file let lnr += 1 if line =~ '^[^%]*\\documentclass' let stream = matchstr(line, '^[^%]*\\documentclass\zs.*').join(file[(lnr+1):], "\n") let idx = -1 while idx < len(stream) let idx += 1 let chr = stream[idx] if chr == '[' " jump to ']' while idx < len(stream) let idx += 1 let chr = stream[idx] if chr == ']' break endif endwhile elseif chr == '%' while idx < len(stream) let idx += 1 let chr = stream[idx] if chr == "\n" break endif endwhile elseif chr == '{' while idx < len(stream) let idx += 1 let chr = stream[idx] if chr == '}' return matchstr(documentclass, '\s*\zs\S*') else let documentclass .= chr endif endwhile endif endwhile endif endfor return 0 endfunction " }}}1 " Make a tree of input files. " {{{ atplib#search#TreeOfFiles_vim " this is needed to make backward searching. " It returns: " [ {tree}, {list}, {type_dict}, {level_dict} ] " where {tree}: " is a tree of files of the form " { file : [ subtree, linenr ] } " where the linenr is the linenr of \input{file} iline the one level up " file. " {list}: " is just list of all found input files (except the main file!). " {type_dict}: " is a dictionary of types for files in {list} " type is one of: preambule, input, bib. " " {flat} = 1 do not be recursive " {flat} = 0 the deflaut be recursive for input files (not bib and not preambule) " bib and preambule files are not added to the tree " {flat} = -1 include input and premabule files into the tree " " TreeOfFiles({main_file}, [{pattern}, {flat}, {run_nr}]) " debug file - /tmp/tof_log " a:main_file is the main file to start with function! atplib#search#TreeOfFiles_vim(main_file,...) " let time = reltime() let atp_MainFile = atplib#FullPath(b:atp_MainFile) if !exists("b:atp_OutDir") call atplib#common#SetOutDir(0, 1) endif let tree = {} " flat = do a flat search, i.e. fo not search in input files at all. let flat = a:0 >= 2 ? a:2 : 0 " This prevents from long runs on package files " for example babel.sty has lots of input files. if expand("%:e") != 'tex' return [ {}, [], {}, {} ] endif let run_nr = a:0 >= 3 ? a:3 : 1 let biblatex = 0 " Adjust g:atp_inputfile_pattern if it is not set right if run_nr == 1 let pattern = '^[^%]*\\\%(input\s*{\=\|include\s*{' if '\subfile{' !~ g:atp_inputfile_pattern && atplib#search#SearchPackage('subfiles') let pattern .= '\|subfile\s*{' endif let biblatex = atplib#search#SearchPackage('biblatex') if biblatex " If biblatex is present, search for bibliography files only in the " preambule. if '\addbibresource' =~ g:atp_inputfile_pattern || '\addglobalbib' =~ g:atp_inputfile_pattern || '\addsectionbib' =~ g:atp_inputfile_pattern || '\bibliography' =~ g:atp_inputfile_pattern echo "[ATP:] You might remove biblatex patterns from g:atp_inputfile_pattern if you use biblatex package." endif let biblatex_pattern = '^[^%]*\\\%(bibliography\s*{\|addbibresource\s*\%(\[[^]]*\]\)\?\s*{\|addglobalbib\s*\%(\[[^]]*\]\)\?\s*{\|addsectionbib\s*\%(\[[^]]*\]\)\?\s*{\)' else let pattern .= '\|bibliography\s*{' endif let pattern .= '\)' endif let pattern = a:0 >= 1 ? a:1 : g:atp_inputfile_pattern if g:atp_debugToF if exists("g:atp_TempDir") if run_nr == 1 exe "redir! > ".g:atp_TempDir."/TreeOfFiles.log" else exe "redir! >> ".g:atp_TempDir."/TreeOfFiles.log" endif endif endif if g:atp_debugToF silent echo run_nr . ") |".a:main_file."| expand=".expand("%:p") endif if run_nr == 1 let cwd = getcwd() exe "lcd " . fnameescape(b:atp_ProjectDir) endif let line_nr = 1 let ifiles = [] let list = [] let type_dict = {} let level_dict = {} let saved_llist = getloclist(0) if run_nr == 1 && &l:filetype =~ '^\(ams\)\=tex$' try silent execute 'lvimgrep /\\begin\s*{\s*document\s*}/j ' . fnameescape(a:main_file) catch /E480:/ endtry let end_preamb = get(get(getloclist(0), 0, {}), 'lnum', 0) call setloclist(0,[]) if biblatex try silent execute 'lvimgrep /'.biblatex_pattern.'\%<'.end_preamb.'l/j ' . fnameescape(a:main_file) catch /E480:/ endtry endif else let end_preamb = 0 call setloclist(0,[]) endif try silent execute "lvimgrepadd /".pattern."/jg " . fnameescape(a:main_file) catch /E480:/ " catch /E683:/ " let g:pattern = pattern " let g:filename = fnameescape(a:main_file) endtry let loclist = getloclist(0) call setloclist(0, saved_llist) let lines = map(loclist, "[ v:val['text'], v:val['lnum'], v:val['col'] ]") if g:atp_debugToF silent echo run_nr . ") Lines: " .string(lines) endif for entry in lines let [ line, lnum, cnum ] = entry " input name (iname) as appeared in the source file let iname = substitute(matchstr(line, pattern . '\(''\|"\)\=\zs\f\%(\f\|\s\)*\ze\1\='), '\s*$', '', '') if iname == "" && biblatex let iname = substitute(matchstr(line, biblatex_pattern . '\(''\|"\)\=\zs\f\%(\f\|\s\)*\ze\1\='), '\s*$', '', '') endif if g:atp_debugToF silent echo run_nr . ") iname=".iname endif if line =~ '{\s*' . iname let iname = substitute(iname, '\\\@\|\\addglobalbib\>\|\\addsectionbib\>\|\\addbibresource\>\)' let type = "bib" elseif lnum < end_preamb && run_nr == 1 let type = "preambule" else let type = "input" endif if g:atp_debugToF silent echo run_nr . ") type=" . type endif let inames = [] if type != "bib" let inames = [ atplib#append_ext(iname, '.tex') ] else let inames = map(split(iname, ','), "atplib#append_ext(v:val, '.bib')") endif if g:atp_debugToF silent echo run_nr . ") inames " . string(inames) endif " Find the full path only if it is not already given. for iname in inames let saved_iname = iname if iname != fnamemodify(iname, ":p") if type != "bib" let iname = atplib#search#KpsewhichFindFile('tex', iname, expand(b:atp_OutDir) . "," . g:atp_texinputs , 1, ':p', '^\%(\/home\|\.\)', '\(^\/usr\|texlive\|kpsewhich\|generic\|miktex\)') else let iname = atplib#search#KpsewhichFindFile('bib', iname, expand(b:atp_OutDir) . "," . g:atp_bibinputs , 1, ':p') endif endif if fnamemodify(iname, ":t") == "" let iname = expand(saved_iname, ":p") endif if g:atp_debugToF silent echo run_nr . ") iname " . string(iname) endif if g:atp_RelativePath let iname = atplib#RelativePath(iname, (fnamemodify(resolve(b:atp_MainFile), ":h"))) endif call add(ifiles, [ iname, lnum] ) call add(list, iname) call extend(type_dict, { iname : type } ) call extend(level_dict, { iname : run_nr } ) endfor endfor if g:atp_debugToF silent echo run_nr . ") list=".string(list) endif " Be recursive if: flat is off, file is of input type. if !flat || flat <= -1 for [ifile, line] in ifiles if type_dict[ifile] == "input" && flat <= 0 || ( type_dict[ifile] == "preambule" && flat <= -1 ) let [ ntree, nlist, ntype_dict, nlevel_dict ] = atplib#search#TreeOfFiles_vim(ifile, pattern, flat, run_nr+1) call extend(tree, { ifile : [ ntree, line ] } ) call extend(list, nlist, index(list, ifile)+1) call extend(type_dict, ntype_dict) call extend(level_dict, nlevel_dict) endif endfor else " Make the flat tree for [ ifile, line ] in ifiles call extend(tree, { ifile : [ {}, line ] }) endfor endif " Showing time takes ~ 0.013sec. " if run_nr == 1 " echomsg "TIME:" . join(reltime(time), ".") . " main_file:" . a:main_file " endif let [ b:TreeOfFiles, b:ListOfFiles, b:TypeDict, b:LevelDict ] = deepcopy([ tree, list, type_dict, level_dict]) " restore current working directory if run_nr == 1 exe "lcd " . fnameescape(cwd) endif if g:atp_debugToF && run_nr == 1 silent! echo "========TreeOfFiles========================" silent! echo "TreeOfFiles b:ListOfFiles=" . string(b:ListOfFiles) redir END endif return [ tree, list, type_dict, level_dict ] endfunction "}}} " atplib#search#TreeOfFiles_py "{{{ function! atplib#search#TreeOfFiles_py(main_file) let b:TreeOfFiles = {} let b:ListOfFiles = [] let b:TypeDict = {} let b:LevelDict = {} let time=reltime() python << END_PYTHON import vim import re import subprocess import os import glob import json from atplib.search import scan_preambule from atplib.search import addext from atplib.search import kpsewhich_find from atplib.search import kpsewhich_path filename = vim.eval('a:main_file') relative_path = vim.eval('g:atp_RelativePath') project_dir = vim.eval('b:atp_ProjectDir') def vim_remote_expr(servername, expr): """Send to vim server, expr must be well quoted: vim_remote_expr('GVIM', "atplib#callback#TexReturnCode()")""" cmd=[options.progname, '--servername', servername, '--remote-expr', expr] subprocess.Popen(cmd, stdout=subprocess.PIPE).wait() def preambule_end(file): """Find linenr where preambule ends, file is list of lines.""" nr=1 for line in file: if re.search(r'\\begin\s*{\s*document\s*}', line): return nr nr+=1 return 0 def bufnumber(file): cdir = os.path.abspath(os.curdir) try: os.chdir(project_dir) except OSError: return 0 for buf in vim.buffers: # This requires that we are in the directory of the main tex file: if buf.name == os.path.abspath(file): os.chdir(cdir) return buf.number for buf in vim.buffers: if not buf.name is None and os.path.basename(buf.name) == file: os.chdir(cdir) return buf.number os.chdir(cdir) return 0 def scan_file(file, fname, pattern, bibpattern): """Scan file for a pattern, return all groups, file is a list of lines.""" matches_d={} matches_l=[] nr = 0 for line in file: nr+=1 match_all=re.findall(pattern, line) if len(match_all) > 0: for match in match_all: for m in match: if str(m) != "": m=addext(m, "tex") if not os.access(m, os.F_OK): try: m=kpsewhich_find(m, tex_path)[0] except IndexError: pass elif relative_path == "0": m=os.path.join(project_dir,m) if fname == filename and nr < preambule_end: matches_d[m]=[m, fname, nr, 'preambule'] matches_l.append(m) else: matches_d[m]=[m, fname, nr, 'input'] matches_l.append(m) match_all=re.findall(bibpattern, line) if len(match_all) > 0: for match in match_all: if str(match) != "": for m in match.split(','): m=addext(m, "bib") if not os.access(m, os.F_OK): try: m=kpsewhich_find(m, bib_path)[0] except IndexError: pass matches_d[m]=[m, fname, nr, 'bib'] matches_l.append(m) return [ matches_d, matches_l ] def tree(file, level, pattern, bibpattern): """files - list of file names to scan,""" bufnr = bufnumber(file) if bufnr in vim.buffers: file_l = vim.buffers[bufnr] else: try: with open(file) as fo: file_l = fo.read().splitlines(False) except IOError: if file.endswith('.bib'): path=bib_path else: path=tex_path try: k_list = kpsewhich_find(file, path) if k_list: file = k_list[0] else: file = None if file: with open(file) as fo: file_l = fo.read().splitlines(False) else: return [ {}, [], {}, {} ] except IOError: return [ {}, [], {}, {} ] except IndexError: return [ {}, [], {}, {} ] [found, found_l] = scan_file(file_l, file, pattern, bibpattern) t_list=[] t_level={} t_type={} t_tree={} for item in found_l: t_list.append(item) t_level[item]=level t_type[item]=(found[item][3]) # t_type values are ASCII i_list=[] for file in t_list: if found[file][3] == "input": i_list.append(file) for file in i_list: [ n_tree, n_list, n_type, n_level ] = tree(file, level+1, pattern, bibpattern) for f in n_list: t_list.append(f) t_type[f] = (n_type[f]) t_level[f] = n_level[f] t_tree[file] = [ n_tree, found[file][2] ] return [ t_tree, t_list, t_type, t_level ] try: with open(filename) as sock: mainfile = sock.read().splitlines(False) except IOError: [ tree_of_files, list_of_files, type_dict, level_dict]= [ {}, [], {}, {} ] else: if scan_preambule(mainfile, re.compile(r'\\usepackage{[^}]*\bsubfiles\b')): pat_str = r'^[^%]*(?:\\input\s+([\w_\-\.]*)|\\(?:input|include(?:only)?|subfile)\s*{([^}]*)})' pattern = re.compile(pat_str) else: pat_str = r'^[^%]*(?:\\input\s+([\w_\-\.]*)|\\(?:input|include(?:only)?)\s*{([^}]*)})' pattern = re.compile(pat_str) bibpattern=re.compile(r'^[^%]*\\(?:bibliography|addbibresource|addsectionbib(?:\s*\[.*\])?|addglobalbib(?:\s*\[.*\])?)\s*{([^}]*)}') bib_path=kpsewhich_path('bib') tex_path=kpsewhich_path('tex') preambule_end=preambule_end(mainfile) [ tree_of_files, list_of_files, type_dict, level_dict] = tree(filename, 1, pattern, bibpattern) if hasattr(vim, 'bindeval'): def copy_dict(from_dict, to_dict): for key in from_dict.iterkeys(): to_dict[str(key)] = from_dict[key] TreeOfFiles = vim.bindeval('b:TreeOfFiles') copy_dict(tree_of_files, TreeOfFiles) ListOfFiles = vim.bindeval('b:ListOfFiles') ListOfFiles.extend(list_of_files) TypeDict = vim.bindeval('b:TypeDict') copy_dict(type_dict, TypeDict) LevelDict = vim.bindeval('b:LevelDict') copy_dict(level_dict, LevelDict) else: vim.command("let b:TreeOfFiles=%s" % json.dumps(tree_of_files)) vim.command("let b:ListOfFiles=%s" % json.dumps(list_of_files)) vim.command("let b:TypeDict=%s" % json.dumps(type_dict)) vim.command("let b:LevelDict=%s" % json.dumps(level_dict)) END_PYTHON let g:time_TreeOfFiles_py=reltimestr(reltime(time)) return [ b:TreeOfFiles, b:ListOfFiles, b:TypeDict, b:LevelDict ] endfunction "}}} " This function finds all the input and bibliography files declared in the source files (recursive). " {{{ atplib#search#FindInputFiles " Returns a dictionary: " { : [ 'bib', 'main file', 'full path' ] } " with the same format as the output of FindInputFiles " a:MainFile - main file (b:atp_MainFile) " a:1 = 0 [1] - use cached values of tree of files. function! atplib#search#FindInputFiles(MainFile,...) " let time=reltime() call atplib#write("nobackup") let cached_Tree = a:0 >= 1 ? a:1 : 0 let saved_llist = getloclist(0) call setloclist(0, []) if cached_Tree && exists("b:TreeOfFiles") let [ TreeOfFiles, ListOfFiles, DictOfFiles, LevelDict ]= deepcopy([ b:TreeOfFiles, b:ListOfFiles, b:TypeDict, b:LevelDict ]) else if &filetype == "plaintex" let flat = 1 else let flat = 0 endif let [ TreeOfFiles, ListOfFiles, DictOfFiles, LevelDict ]= TreeOfFiles(fnamemodify(a:MainFile, ":p"), g:atp_inputfile_pattern, flat) " Update the cached values: let [ b:TreeOfFiles, b:ListOfFiles, b:TypeDict, b:LevelDict ] = deepcopy([ TreeOfFiles, ListOfFiles, DictOfFiles, LevelDict ]) endif let AllInputFiles = keys(filter(copy(DictOfFiles), " v:val == 'input' || v:val == 'preambule' ")) let AllBibFiles = keys(filter(copy(DictOfFiles), " v:val == 'bib' ")) let b:AllInputFiles = deepcopy(AllInputFiles) let b:AllBibFiles = deepcopy(AllBibFiles) let b:atp_BibFiles = copy(b:AllBibFiles) " this variable will store unreadable bibfiles: let NotReadableInputFiles=[] " this variable will store the final result: let Files = {} for File in ListOfFiles let File_Path = atplib#FullPath(File) if filereadable(File) call extend(Files, \ { fnamemodify(File_Path,":t:r") : [ DictOfFiles[File] , fnamemodify(a:MainFile, ":p"), File_Path ] }) else " echo warning if a bibfile is not readable " echohl WarningMsg | echomsg "File " . File . " not found." | echohl None if count(NotReadableInputFiles, File_Path) == 0 call add(NotReadableInputFiles, File_Path) endif endif endfor let g:NotReadableInputFiles = NotReadableInputFiles " return the list of readable bibfiles " let g:time_FindInputFiles=reltimestr(reltime(time)) return Files endfunction function! atplib#search#UpdateMainFile() if b:atp_MainFile =~ '^\s*\/' let cwd = getcwd() exe "lcd " . fnameescape(b:atp_ProjectDir) let b:atp_MainFile = ( g:atp_RelativePath ? fnamemodify(b:atp_MainFile, ":.") : b:atp_MainFile ) exe "lcd " . fnameescape(cwd) else let b:atp_MainFile = ( g:atp_RelativePath ? b:atp_MainFile : atplib#FullPath(b:atp_MainFile) ) endif return endfunction "}}} " vim:fdm=marker:tw=85:ff=unix:noet:ts=8:sw=4:fdc=1 autoload/atplib/tools.vim [[[1 595 " Title: Vim library for ATP filetype plugin. " Author: Marcin Szamotulski " Email: mszamot [AT] gmail [DOT] com " Note: This file is a part of Automatic Tex Plugin for Vim. " URL: https://launchpad.net/automatictexplugin " Language: tex " Open Function: "{{{1 atplib#tools#Open " a:1 - pattern or a file name " a:1 is regarded as a filename if filereadable(pattern) is non " zero. function! atplib#tools#Open(bang, dir, TypeDict, ...) if a:dir == "0" echohl WarningMsg echomsg "You have to set g:atp_LibraryPath in your vimrc or atprc file." echohl None return endif let pattern = ( a:0 >= 1 ? a:1 : "") let file = filereadable(pattern) ? pattern : "" if file == "" if a:bang == "!" || !exists("g:atp_Library") let g:atp_Library = filter(split(globpath(a:dir, "*"), "\n"), 'count(keys(a:TypeDict), fnamemodify(v:val, ":e"))') let found = deepcopy(g:atp_Library) else let found = deepcopy(g:atp_Library) endif call filter(found, "fnamemodify(v:val, ':t') =~ pattern") " Resolve symlinks: call map(found, "resolve(v:val)") " Remove double entries: call filter(found, "count(found, v:val) == 1") if len(found) > 1 echohl Title echo "Found files:" echohl None let i = 1 for file in found if len(map(copy(found), "v:val =~ escape(fnamemodify(file, ':t'), '~') . '$'")) == 1 echo i . ") " . fnamemodify(file, ":t") else echo i . ") " . pathshorten(fnamemodify(file, ":p")) endif let i+=1 endfor let choice = input("Which file to open? ")-1 if choice == -1 return endif let file = found[choice] elseif len(found) == 1 let file = found[0] else echohl WarningMsg echomsg "[ATP:] Nothing found." echohl None return endif endif let ext = fnamemodify(file, ":e") let viewer = get(a:TypeDict, ext, 0) if viewer == '0' echomsg "\n" echomsg "[ATP:] filetype: " . ext . " is not supported, add an entry to g:atp_OpenTypeDict" return endif if viewer !~ '^\s*cat\s*$' && viewer !~ '^\s*g\=vim\s*$' && viewer !~ '^\s*edit\s*$' && viewer !~ '^\s*tabe\s*$' && viewer !~ '^\s*split\s*$' call system(viewer . " '" . file . "' &") elseif viewer =~ '^\s*g\=vim\s*$' || viewer =~ '^\s*tabe\s*$' exe "tabe " . fnameescape(file) setl nospell elseif viewer =~ '^\s*edit\s*$' || viewer =~ '^\s*split\s*$' exe viewer . " " . fnameescape(file) setl nospell elseif viewer == '^\s*cat\s*' redraw! echohl Title echo "cat '" . file . "'" echohl None echo system(viewer . " '" . file . "' &") endif endfunction "}}}1 " Labels Tools: GrepAuxFile, SrotLabels, generatelabels and showlabes. " {{{1 LABELS " {{{2 --------------- atplib#tools#GrepAuxFile " This function searches in aux file (actually it tries first ._aux file, " made by compile.py - this is because compile.py is copying aux file only if " there are no errors (to not affect :Labels command) " The argument should be: resolved full path to the file: " resove(fnamemodify(bufname("%"),":p")) function! atplib#tools#GrepAuxFile(...) " Aux file to read: let base = ( a:0 >= 1 ? fnamemodify(a:1, ":r") : atplib#joinpath(expand(b:atp_OutDir), fnamemodify(b:atp_MainFile, ":t:r"))) let aux_filename = base . "._aux" if !filereadable(aux_filename) let aux_filename = base . ".aux" if !filereadable(aux_filename) let base = fnamemodify(atplib#FullPath(b:atp_MainFile), ":r") let aux_filename = base . "._aux" if !filereadable(aux_filename) let aux_filename = base . ".aux" else echohl WarningMsg echom "[ATP] aux file not found (atplib#tools#GrepAuxFile)." echohl Normal endif endif endif let tex_filename = fnamemodify(aux_filename, ":r") . ".tex" if !filereadable(aux_filename) " We should worn the user that there is no aux file " /this is not visible ! only after using the command 'mes'/ echohl WarningMsg if exists("b:atp_TexCompiler") echomsg "[ATP:] there is no aux file. Run ".b:atp_TexCompiler." first." else echomsg "[ATP:] there is no aux file. " endif echohl None return [] " CALL BACK is not working " I can not get output of: vim --servername v:servername --remote-expr v:servername " for v:servername " Here we should run latex to produce auxfile " echomsg "Running " . b:atp_TexCompiler . " to get aux file." " let labels = system(b:atp_TexCompiler . " -interaction nonstopmode " . atp_MainFile . " 1&>/dev/null 2>1 ; " . " vim --servername ".v:servername." --remote-expr 'atplib#tools#GrepAuxFile()'") " return labels endif " let aux_file = readfile(aux_filename) let saved_llist = getloclist(0) if bufloaded(aux_filename) exe "silent! bd! " . bufnr(aux_filename) endif try silent execute 'lvimgrep /\\newlabel\s*{/j ' . fnameescape(aux_filename) catch /E480:/ endtry if atplib#FullPath(b:atp_MainFile) != expand("%:p") " if we are in the project file and one is useing the subfiles package " search the 'local' aux file as well, but only if its time stamp is " newer than the time stamp of the aux_filename let local_base = expand("%:r") let local_aux = filereadable(local_base."._aux") ? local_base."._aux" : local_base.".aux" if filereadable(local_aux) && getftime(local_aux) > getftime(aux_filename) try silent execute 'lvimgrepadd /\\newlabel\s*{/j ' . fnameescape(local_aux) catch /E480:/ endtry endif endif let loc_list = getloclist(0) call setloclist(0, saved_llist) call map(loc_list, ' v:val["text"]') let labels = [] if g:atp_debugGAF let g:gaf_debug = {} endif " Equation counter depedns on the option \numberwithin{equation}{section} " /now this only supports article class. let equation = len(atplib#search#GrepPreambule('^\s*\\numberwithin{\s*equation\s*}{\s*section\s*}', tex_filename)) " for line in aux_file for line in loc_list if line =~ '\\newlabel\>' let line = substitute(line, '\\GenericError\s*\%({[^}]*}\)\{4}', '', 'g') " line is of the form: " \newlabel{