Initial import of my home directory
[home/.git] / .vim / ftplugin / latex-suite / compiler.vim
1 "=============================================================================
2 "            File: compiler.vim
3 "      Author: Srinath Avadhanula
4 "     Created: Tue Apr 23 05:00 PM 2002 PST
5
6 "  Description: functions for compiling/viewing/searching latex documents
7 "          CVS: $Id: compiler.vim 997 2006-03-20 09:45:45Z srinathava $
8 "=============================================================================
9
10 " Tex_SetTeXCompilerTarget: sets the 'target' for the next call to Tex_RunLaTeX() {{{
11 function! Tex_SetTeXCompilerTarget(type, target)
12         call Tex_Debug("+Tex_SetTeXCompilerTarget: setting target to [".a:target."] for ".a:type."r", "comp")
13
14         if a:target == ''
15                 let target = Tex_GetVarValue('Tex_DefaultTargetFormat')
16                 let target = input('Enter the target format for '.a:type.'r: ', target)
17         else
18                 let target = a:target
19         endif
20         if target == ''
21                 let target = 'dvi'
22         endif
23
24         let targetRule = Tex_GetVarValue('Tex_'.a:type.'Rule_'.target)
25
26         if targetRule != ''
27                 if a:type == 'Compile'
28                         let &l:makeprg = escape(targetRule, Tex_GetVarValue('Tex_EscapeChars'))
29                 elseif a:type == 'View'
30                         let s:viewer = targetRule
31                 endif
32                 let s:target = target
33
34         elseif Tex_GetVarValue('Tex_'.a:type.'RuleComplete_'.target) != ''
35                 let s:target = target
36
37         else
38                 let curd = getcwd()
39                 exe 'cd '.expand('%:p:h')
40                 if !Tex_GetVarValue('Tex_UseMakefile') || (glob('makefile*') == '' && glob('Makefile*') == '')
41                         if has('gui_running')
42                                 call confirm(
43                                         \'No '.a:type.' rule defined for target '.target."\n".
44                                         \'Please specify a rule in $VIMRUNTIME/ftplugin/tex/texrc'."\n".
45                                         \'     :help Tex_'.a:type.'Rule_format'."\n".
46                                         \'for more information',
47                                         \"&ok", 1, 'Warning')
48                         else
49                                 call input( 
50                                         \'No '.a:type.' rule defined for target '.target."\n".
51                                         \'Please specify a rule in $VIMRUNTIME/ftplugin/tex/texrc'."\n".
52                                         \'     :help Tex_'.a:type.'Rule_format'."\n".
53                                         \'for more information'
54                                         \)
55                         endif
56                 else
57                         echomsg 'Assuming target is for makefile'
58                         let s:target = target
59                 endif
60                 exe 'cd '.curd
61         endif
62 endfunction 
63
64 function! SetTeXTarget(...)
65         if a:0 < 1
66                 let target = Tex_GetVarValue('Tex_DefaultTargetFormat')
67                 let target = input('Enter the target format for compiler and viewer: ', target)
68         else
69                 let target = a:1
70         endif
71         if target == ''
72                 let target = 'dvi'
73         endif
74
75         call Tex_SetTeXCompilerTarget('Compile', target)
76         call Tex_SetTeXCompilerTarget('View', target)
77 endfunction
78
79 com! -nargs=1 TCTarget :call Tex_SetTeXCompilerTarget('Compile', <f-args>)
80 com! -nargs=1 TVTarget :call Tex_SetTeXCompilerTarget('View', <f-args>)
81 com! -nargs=? TTarget :call SetTeXTarget(<f-args>)
82
83 " }}}
84 " Tex_CompileLatex: compiles the present file. {{{
85 " Description: 
86 function! Tex_CompileLatex()
87         if &ft != 'tex'
88                 echo "calling Tex_RunLaTeX from a non-tex file"
89                 return
90         end
91
92         " close any preview windows left open.
93         pclose!
94
95         let curd = getcwd()
96
97         " Find the main file corresponding to this file. Always cd to the
98         " directory containing the file to avoid problems with the directory
99         " containing spaces.
100         " Latex on linux seems to be unable to handle file names with spaces at
101         " all! Therefore for the moment, do not attempt to handle spaces in the
102         " file name.
103         if exists('b:fragmentFile')
104                 let mainfname = expand('%:p:t')
105                 call Tex_CD(expand('%:p:h'))
106         else
107                 let mainfname = Tex_GetMainFileName(':p:t')
108                 call Tex_CD(Tex_GetMainFileName(':p:h'))
109         end
110
111         call Tex_Debug('Tex_CompileLatex: getting mainfname = ['.mainfname.'] from Tex_GetMainFileName', 'comp')
112
113         " if a makefile exists and the user wants to use it, then use that
114         " irrespective of whether *.latexmain exists or not. mainfname is still
115         " extracted from *.latexmain (if possible) log file name depends on the
116         " main file which will be compiled.
117         if Tex_GetVarValue('Tex_UseMakefile') && (glob('makefile') != '' || glob('Makefile') != '')
118                 let _makeprg = &l:makeprg
119                 call Tex_Debug("Tex_CompileLatex: using the makefile in the current directory", "comp")
120                 let &l:makeprg = 'make $*'
121                 if exists('s:target')
122                         call Tex_Debug('Tex_CompileLatex: execing [make! '.s:target.']', 'comp')
123                         exec 'make! '.s:target
124                 else
125                         call Tex_Debug('Tex_CompileLatex: execing [make!]', 'comp')
126                         exec 'make!'
127                 endif
128                 let &l:makeprg = _makeprg
129         else
130                 " If &makeprg has something like "$*.ps", it means that it wants the
131                 " file-name without the extension... Therefore remove it.
132                 if &makeprg =~ '\$\*\.\w\+'
133                         let mainfname = fnamemodify(mainfname, ':r')
134                 endif
135                 call Tex_Debug('Tex_CompileLatex: execing [make! '.mainfname.']', 'comp')
136                 exec 'make! '.mainfname
137         endif
138         redraw!
139
140         call Tex_CD(curd)
141 endfunction " }}}
142 " Tex_RunLaTeX: compilation function {{{
143 " this function runs the latex command on the currently open file. often times
144 " the file being currently edited is only a fragment being \input'ed into some
145 " master tex file. in this case, make a file called mainfile.latexmain in the
146 " directory containig the file. in other words, if the current file is
147 " ~/thesis/chapter.tex
148 " so that doing "latex chapter.tex" doesnt make sense, then make a file called 
149 " main.tex.latexmain 
150 " in the ~/thesis directory. this will then run "latex main.tex" when
151 " Tex_RunLaTeX() is called.
152 function! Tex_RunLaTeX()
153         call Tex_Debug('+Tex_RunLaTeX, b:fragmentFile = '.exists('b:fragmentFile'), 'comp')
154
155         let dir = expand("%:p:h").'/'
156         let curd = getcwd()
157         call Tex_CD(expand("%:p:h"))
158
159         let initTarget = s:target
160
161         " first get the dependency chain of this format.
162         call Tex_Debug("Tex_RunLaTeX: compiling to target [".s:target."]", "comp")
163
164         if Tex_GetVarValue('Tex_FormatDependency_'.s:target) != ''
165                 let dependency = Tex_GetVarValue('Tex_FormatDependency_'.s:target)
166                 if dependency !~ ','.s:target.'$'
167                         let dependency = dependency.','.s:target
168                 endif
169         else
170                 let dependency = s:target
171         endif
172
173         call Tex_Debug('Tex_RunLaTeX: getting dependency chain = ['.dependency.']', 'comp')
174
175         " now compile to the final target format via each dependency.
176         let i = 1
177         while Tex_Strntok(dependency, ',', i) != ''
178                 let s:target = Tex_Strntok(dependency, ',', i)
179
180                 call Tex_SetTeXCompilerTarget('Compile', s:target)
181                 call Tex_Debug('Tex_RunLaTeX: setting target to '.s:target, 'comp')
182
183                 if Tex_GetVarValue('Tex_MultipleCompileFormats') =~ '\<'.s:target.'\>'
184                         call Tex_Debug("Tex_RunLaTeX: compiling file multiple times via Tex_CompileMultipleTimes", "comp")
185                         call Tex_CompileMultipleTimes()
186                 else
187                         call Tex_Debug("Tex_RunLaTeX: compiling file once via Tex_CompileLatex", "comp")
188                         call Tex_CompileLatex()
189                 endif
190
191                 let errlist = Tex_GetErrorList()
192                 call Tex_Debug("Tex_RunLaTeX: errlist = [".errlist."]", "comp")
193
194                 " If there are any errors, then break from the rest of the steps
195                 if errlist =~  '\v(error|warning)'
196                         call Tex_Debug('Tex_RunLaTeX: There were errors in compiling, breaking chain...', 'comp')
197                         break
198                 endif
199
200                 let i = i + 1
201         endwhile
202         
203         let s:target = initTarget
204         let s:origwinnum = winnr()
205         call Tex_SetupErrorWindow()
206
207         call Tex_CD(curd)
208         call Tex_Debug("-Tex_RunLaTeX", "comp")
209 endfunction
210
211 " }}}
212 " Tex_ViewLaTeX: opens viewer {{{
213 " Description: opens the DVI viewer for the file being currently edited.
214 " Again, if the current file is a \input in a master file, see text above
215 " Tex_RunLaTeX() to see how to set this information.
216 function! Tex_ViewLaTeX()
217         if &ft != 'tex'
218                 echo "calling Tex_ViewLaTeX from a non-tex file"
219                 return
220         end
221         
222         let curd = getcwd()
223         
224         " If b:fragmentFile is set, it means this file was compiled as a fragment
225         " using Tex_PartCompile, which means that we want to ignore any
226         " *.latexmain or makefile's.
227         if !exists('b:fragmentFile')
228                 " cd to the location of the file to avoid having to deal with spaces
229                 " in the directory name.
230                 let mainfname = Tex_GetMainFileName(':p:t:r')
231                 call Tex_CD(Tex_GetMainFileName(':p:h'))
232         else
233                 let mainfname = expand("%:p:t:r")
234                 call Tex_CD(expand("%:p:h"))
235         endif
236
237         if Tex_GetVarValue('Tex_ViewRuleComplete_'.s:target) != ''
238
239                 let execString = Tex_GetVarValue('Tex_ViewRuleComplete_'.s:target)
240                 let execString = substitute(execString, '{v:servername}', v:servername, 'g')
241
242         elseif has('win32')
243                 " unfortunately, yap does not allow the specification of an external
244                 " editor from the command line. that would have really helped ensure
245                 " that this particular vim and yap are connected.
246                 let execString = 'start '.s:viewer.' "$*.'.s:target.'"'
247
248         elseif has('macunix')
249                 if strlen(s:viewer)
250                         let s:viewer = '-a '.s:viewer
251                 endif
252                 let execString = 'open '.s:viewer.' $*.'.s:target
253
254         else
255                 " taken from Dimitri Antoniou's tip on vim.sf.net (tip #225).
256                 " slight change to actually use the current servername instead of
257                 " hardcoding it as xdvi.
258                 " Using an option for specifying the editor in the command line
259                 " because that seems to not work on older bash'es.
260                 if s:target == 'dvi'
261
262                         if Tex_GetVarValue('Tex_UseEditorSettingInDVIViewer') == 1 &&
263                                                 \ v:servername != '' &&
264                                                 \ (s:viewer == "xdvi" || s:viewer == "xdvik")
265
266                                 let execString = s:viewer.' -editor "gvim --servername '.v:servername.
267                                                         \ ' --remote-silent +\%l \%f" $*.dvi &'
268
269                         elseif Tex_GetVarValue('Tex_UseEditorSettingInDVIViewer') == 1 &&
270                                                 \ s:viewer == "kdvi"
271
272                                 let execString = 'kdvi --unique $*.dvi &'
273
274                         else
275
276                                 let execString = s:viewer.' $*.dvi &'
277
278                         endif
279
280                 else
281
282                         let execString = s:viewer.' $*.'.s:target.' &'
283
284                 endif
285         end
286
287         let execString = substitute(execString, '\V$*', mainfname, 'g')
288         call Tex_Debug("Tex_ViewLaTeX: execString = ".execString, "comp")
289
290         exec 'silent! !'.execString
291
292         if !has('gui_running')
293                 redraw!
294         endif
295
296         call Tex_CD(curd)
297 endfunction
298
299 " }}}
300 " Tex_ForwardSearchLaTeX: searches for current location in dvi file. {{{
301 " Description: if the DVI viewr is compatible, then take the viewer to that
302 "              position in the dvi file. see docs for Tex_RunLaTeX() to set a
303 "              master file if this is an \input'ed file. 
304 " Tip: With YAP on Windows, it is possible to do forward and inverse searches
305 "      on DVI files. to do forward search, you'll have to compile the file
306 "      with the --src-specials option. then set the following as the command
307 "      line in the 'view/options/inverse search' dialog box:
308 "           gvim --servername LATEX --remote-silent +%l "%f"
309 "      For inverse search, if you are reading this, then just pressing \ls
310 "      will work.
311 function! Tex_ForwardSearchLaTeX()
312         if &ft != 'tex'
313                 echo "calling Tex_ViewLaTeX from a non-tex file"
314                 return
315         end
316
317         " only know how to do forward search for yap on windows and xdvik (and
318         " some newer versions of xdvi) on unices. Therefore forward searching will
319         " automatically open the DVI viewer irrespective of what the user chose as
320         " the default view format.
321         if Tex_GetVarValue('Tex_ViewRule_dvi') == ''
322                 return
323         endif
324         let viewer = Tex_GetVarValue('Tex_ViewRule_dvi')
325         
326         let curd = getcwd()
327
328         let mainfname = Tex_GetMainFileName(':t')
329         let mainfnameRoot = fnamemodify(Tex_GetMainFileName(), ':t:r')
330         " cd to the location of the file to avoid problems with directory name
331         " containing spaces.
332         call Tex_CD(Tex_GetMainFileName(':p:h'))
333         
334         " inverse search tips taken from Dimitri Antoniou's tip and Benji Fisher's
335         " tips on vim.sf.net (vim.sf.net tip #225)
336         if has('win32')
337
338                 let execString = 'silent! !start '. viewer.' -s '.line('.').expand('%').' '.mainfnameRoot
339
340         else
341                 if Tex_GetVarValue('Tex_UseEditorSettingInDVIViewer') == 1 &&
342                                         \ exists('v:servername') &&
343                                         \ (viewer == "xdvi" || viewer == "xdvik") 
344
345                         let execString = 'silent! !'.viewer.' -name xdvi -sourceposition '.line('.').expand("%").
346                                                 \ ' -editor "gvim --servername '.v:servername.' --remote-silent +\%l \%f" '.
347                                                 \ mainfnameRoot.'.dvi &'
348
349                 elseif Tex_GetVarValue('Tex_UseEditorSettingInDVIViewer') == 1 && viewer == "kdvi"
350
351                         let execString = 'silent! !kdvi --unique file:'.mainfnameRoot.'.dvi\#src:'.line('.').expand("%").' &'
352
353                 else
354
355                         let execString = 'silent! !'.viewer.' -name xdvi -sourceposition '.line('.').expand("%").' '.mainfnameRoot.'.dvi &'
356
357                 endif
358         end
359
360         call Tex_Debug("Tex_ForwardSearchLaTeX: execString = ".execString, "comp")
361         execute execString
362         if !has('gui_running')
363                 redraw!
364         endif
365
366         call Tex_CD(curd)
367 endfunction
368
369 " }}}
370
371 " ==============================================================================
372 " Functions for compiling parts of a file. 
373 " ============================================================================== 
374 " Tex_PartCompile: compiles selected fragment {{{
375 " Description: creates a temporary file from the selected fragment of text
376 "       prepending the preamble and \end{document} and then asks Tex_RunLaTeX() to
377 "       compile it.
378 function! Tex_PartCompile() range
379         call Tex_Debug('+Tex_PartCompile', 'comp')
380         " Save position
381         let pos = line('.').' | normal! '.virtcol('.').'|'
382
383         " Get a temporary file in the same directory as the file from which
384         " fragment is being extracted. This is to enable the use of relative path
385         " names in the fragment.
386         let tmpfile = Tex_GetTempName(expand('%:p:h'))
387
388         " Remember all the temp files and for each temp file created, remember
389         " where the temp file came from.
390         let s:Tex_NumTempFiles = (exists('s:Tex_NumTempFiles') ? s:Tex_NumTempFiles + 1 : 1)
391         let s:Tex_TempFiles = (exists('s:Tex_TempFiles') ? s:Tex_TempFiles : '')
392                 \ . tmpfile."\n"
393         let s:Tex_TempFile_{s:Tex_NumTempFiles} = tmpfile
394         " TODO: For a function Tex_RestoreFragment which restores a temp file to
395         "       its original location.
396         let s:Tex_TempFileOrig_{s:Tex_NumTempFiles} = expand('%:p')
397         let s:Tex_TempFileRange_{s:Tex_NumTempFiles} = a:firstline.','.a:lastline
398
399         " Set up an autocmd to clean up the temp files when Vim exits.
400         if Tex_GetVarValue('Tex_RemoveTempFiles')
401                 augroup RemoveTmpFiles
402                         au!
403                         au VimLeave * :call Tex_RemoveTempFiles()
404                 augroup END
405         endif
406
407         " If mainfile exists open it in tiny window and extract preamble there,
408         " otherwise do it from current file
409         let mainfile = Tex_GetMainFileName(":p")
410         exe 'bot 1 split '.escape(mainfile, ' ')
411         exe '1,/\s*\\begin{document}/w '.tmpfile
412         wincmd q
413
414         exe a:firstline.','.a:lastline."w! >> ".tmpfile
415
416         " edit the temporary file
417         exec 'drop '.tmpfile
418
419         " append the \end{document} line.
420         $ put ='\end{document}'
421         w
422         
423         " set this as a fragment file.
424         let b:fragmentFile = 1
425
426         silent! call Tex_RunLaTeX()
427 endfunction " }}}
428 " Tex_RemoveTempFiles: cleans up temporary files created during part compilation {{{
429 " Description: During part compilation, temporary files containing the
430 "              visually selected text are created. These files need to be
431 "              removed when Vim exits to avoid "file leakage".
432 function! Tex_RemoveTempFiles()
433         if !exists('s:Tex_NumTempFiles') || !Tex_GetVarValue('Tex_RemoveTempFiles')
434                 return
435         endif
436         let i = 1
437         while i <= s:Tex_NumTempFiles
438                 let tmpfile = s:Tex_TempFile_{i}
439                 " Remove the tmp file and all other associated files such as the
440                 " .log files etc.
441                 call Tex_DeleteFile(fnamemodify(tmpfile, ':p:r').'.*')
442                 let i = i + 1
443         endwhile
444 endfunction " }}}
445
446 " ==============================================================================
447 " Compiling a file multiple times to resolve references/citations etc.
448 " ============================================================================== 
449 " Tex_CompileMultipleTimes: The main function {{{
450 " Description: compiles a file multiple times to get cross-references right.
451 function! Tex_CompileMultipleTimes()
452         " Just extract the root without any extension because we want to construct
453         " the log file names etc from it.
454         let curd = getcwd()
455         let mainFileName_root = Tex_GetMainFileName(':p:t:r')
456         call Tex_CD(Tex_GetMainFileName(':p:h'))
457
458         " First ignore undefined references and the 
459         " "rerun to get cross-references right" message from 
460         " the compiler output.
461         let origlevel = Tex_GetVarValue('Tex_IgnoreLevel')
462         let origpats = Tex_GetVarValue('Tex_IgnoredWarnings')
463
464         let g:Tex_IgnoredWarnings = g:Tex_IgnoredWarnings."\n"
465                 \ . 'Reference %.%# undefined'."\n"
466                 \ . 'Rerun to get cross-references right'
467         TCLevel 1000
468
469         let idxFileName = mainFileName_root.'.idx'
470         let auxFileName = mainFileName_root.'.aux'
471
472         let runCount = 0
473         let needToRerun = 1
474         while needToRerun == 1 && runCount < 5
475                 " assume we need to run only once.
476                 let needToRerun = 0
477
478                 let idxlinesBefore = Tex_CatFile(idxFileName)
479                 let auxlinesBefore = Tex_GetAuxFile(auxFileName)
480
481                 " first run latex.
482                 echomsg "latex run number : ".(runCount+1)
483                 call Tex_Debug("Tex_CompileMultipleTimes: latex run number : ".(runCount+1), "comp") 
484                 silent! call Tex_CompileLatex()
485                 
486                 " If there are errors in any latex compilation step, immediately
487                 " return. For now, do not bother with warnings because those might go
488                 " away after compiling again or after bibtex is run etc.
489                 let errlist = Tex_GetErrorList()
490                 call Tex_Debug("Tex_CompileMultipleTimes: errors = [".errlist."]", "comp")
491
492                 if errlist =~ 'error'
493                         let g:Tex_IgnoredWarnings = origpats
494                         exec 'TCLevel '.origlevel
495
496                         return
497                 endif
498
499                 let idxlinesAfter = Tex_CatFile(idxFileName)
500
501                 " If .idx file changed, then run makeindex to generate the new .ind
502                 " file and remember to rerun latex.
503                 if runCount == 0 && glob(idxFileName) != '' && idxlinesBefore != idxlinesAfter
504                         echomsg "Running makeindex..."
505                         let temp_mp = &mp | let &mp = Tex_GetVarValue('Tex_MakeIndexFlavor')
506                         exec 'silent! make '.mainFileName_root
507                         let &mp = temp_mp
508
509                         let needToRerun = 1
510                 endif
511
512                 " The first time we see if we need to run bibtex and if the .bbl file
513                 " changes, we will rerun latex.
514                 if runCount == 0 && Tex_IsPresentInFile('\\bibdata', mainFileName_root.'.aux')
515                         let bibFileName = mainFileName_root.'.bbl'
516
517                         let biblinesBefore = Tex_CatFile(bibFileName)
518
519                         echomsg "Running '".Tex_GetVarValue('Tex_BibtexFlavor')."' ..."
520                         let temp_mp = &mp | let &mp = Tex_GetVarValue('Tex_BibtexFlavor')
521                         exec 'silent! make '.mainFileName_root
522                         let &mp = temp_mp
523
524                         let biblinesAfter = Tex_CatFile(bibFileName)
525
526                         " If the .bbl file changed after running bibtex, we need to
527                         " latex again.
528                         if biblinesAfter != biblinesBefore
529                                 echomsg 'Need to rerun because bibliography file changed...'
530                                 call Tex_Debug('Tex_CompileMultipleTimes: Need to rerun because bibliography file changed...', 'comp')
531                                 let needToRerun = 1
532                         endif
533                 endif
534
535                 " check if latex asks us to rerun
536                 let auxlinesAfter = Tex_GetAuxFile(auxFileName)
537                 if auxlinesAfter != auxlinesBefore
538                         echomsg "Need to rerun because the AUX file changed..."
539                         call Tex_Debug("Tex_CompileMultipleTimes: Need to rerun to get cross-references right...", 'comp')
540                         let needToRerun = 1
541                 endif
542
543                 let runCount = runCount + 1
544         endwhile
545
546         call Tex_Debug("Tex_CompileMultipleTimes: Ran latex ".runCount." time(s)", "comp")
547         echomsg "Ran latex ".runCount." time(s)"
548
549         let g:Tex_IgnoredWarnings = origpats
550         exec 'TCLevel '.origlevel
551         " After all compiler calls are done, reparse the .log file for
552         " errors/warnings to handle the situation where the clist might have been
553         " emptied because of bibtex/makeindex being run as the last step.
554         exec 'silent! cfile '.mainFileName_root.'.log'
555
556         call Tex_CD(curd)
557 endfunction " }}}
558 " Tex_GetAuxFile: get the contents of the AUX file {{{
559 " Description: get the contents of the AUX file recursively including any
560 " @\input'ted AUX files.
561 function! Tex_GetAuxFile(auxFile)
562         if !filereadable(a:auxFile)
563                 return ''
564         endif
565
566         let auxContents = Tex_CatFile(a:auxFile)
567         let pattern = '@\input{\(.\{-}\)}'
568
569         let auxContents = substitute(auxContents, pattern, '\=Tex_GetAuxFile(submatch(1))', 'g')
570
571         return auxContents
572 endfunction " }}}
573
574 " ==============================================================================
575 " Helper functions for 
576 " . viewing the log file in preview mode.
577 " . syncing the display between the quickfix window and preview window
578 " . going to the correct line _and column_ number from from the quick fix
579 "   window.
580 " ============================================================================== 
581 " Tex_SetupErrorWindow: sets up the cwindow and preview of the .log file {{{
582 " Description: 
583 function! Tex_SetupErrorWindow()
584         let mainfname = Tex_GetMainFileName()
585
586         let winnum = winnr()
587
588         " close the quickfix window before trying to open it again, otherwise
589         " whether or not we end up in the quickfix window after the :cwindow
590         " command is not fixed.
591         cclose
592         cwindow
593         " create log file name from mainfname
594         let mfnlog = fnamemodify(mainfname, ":t:r").'.log'
595         call Tex_Debug('Tex_SetupErrorWindow: mfnlog = '.mfnlog, 'comp')
596         " if we moved to a different window, then it means we had some errors.
597         if winnum != winnr()
598                 if Tex_GetVarValue('Tex_ShowErrorContext')
599                         call Tex_UpdatePreviewWindow(mfnlog)
600                         exe 'nnoremap <buffer> <silent> j j:call Tex_UpdatePreviewWindow("'.mfnlog.'")<CR>'
601                         exe 'nnoremap <buffer> <silent> k k:call Tex_UpdatePreviewWindow("'.mfnlog.'")<CR>'
602                         exe 'nnoremap <buffer> <silent> <up> <up>:call Tex_UpdatePreviewWindow("'.mfnlog.'")<CR>'
603                         exe 'nnoremap <buffer> <silent> <down> <down>:call Tex_UpdatePreviewWindow("'.mfnlog.'")<CR>'
604                 endif
605                 exe 'nnoremap <buffer> <silent> <enter> :call Tex_GotoErrorLocation("'.mfnlog.'")<CR>'
606
607                 setlocal nowrap
608
609                 " resize the window to just fit in with the number of lines.
610                 exec ( line('$') < 4 ? line('$') : 4 ).' wincmd _'
611         if Tex_GetVarValue('Tex_GotoError') == 1
612                 call Tex_GotoErrorLocation(mfnlog)
613         else
614                         exec s:origwinnum.' wincmd w'
615         endif
616         endif
617
618 endfunction " }}}
619 " Tex_PositionPreviewWindow: positions the preview window correctly. {{{
620 " Description: 
621 "       The purpose of this function is to count the number of times an error
622 "       occurs on the same line. or in other words, if the current line is
623 "       something like |10 error|, then we want to count the number of
624 "       lines in the quickfix window before this line which also contain lines
625 "       like |10 error|. 
626 "
627 function! Tex_PositionPreviewWindow(filename)
628
629         if getline('.') !~ '|\d\+ \(error\|warning\)|'
630                 if !search('|\d\+ \(error\|warning\)|')
631                         call Tex_Debug("not finding error pattern anywhere in quickfix window :".bufname(bufnr('%')),
632                                                 \ 'comp')
633                         pclose!
634                         return
635                 endif
636         endif
637
638         " extract the error pattern (something like 'file.tex|10 error|') on the
639         " current line.
640         let errpat = matchstr(getline('.'), '^\f*|\d\+ \(error\|warning\)|\ze')
641         let errfile = matchstr(getline('.'), '^\f*\ze|\d\+ \(error\|warning\)|')
642         " extract the line number from the error pattern.
643         let linenum = matchstr(getline('.'), '|\zs\d\+\ze \(error\|warning\)|')
644
645         " if we are on an error, then count the number of lines before this in the
646         " quickfix window with an error on the same line.
647         if errpat =~ 'error|$'
648                 " our location in the quick fix window.
649                 let errline = line('.')
650
651                 " goto the beginning of the quickfix window and begin counting the lines
652                 " which show an error on the same line.
653                 0
654                 let numrep = 0
655                 while 1
656                         " if we are on the same kind of error line, then means we have another
657                         " line containing the same error pattern.
658                         if getline('.') =~ errpat
659                                 let numrep = numrep + 1
660                                 normal! 0
661                         endif
662                         " if we have reached the original location in the quick fix window,
663                         " then break.
664                         if line('.') == errline
665                                 break
666                         else
667                                 " otherwise, search for the next line which contains the same
668                                 " error pattern again. goto the end of the current line so we
669                                 " dont count this line again.
670                                 normal! $
671                                 call search(errpat, 'W')
672                         endif
673                 endwhile
674         else
675                 let numrep = 1
676         endif
677
678         if getline('.') =~ '|\d\+ warning|'
679                 let searchpat = escape(matchstr(getline('.'), '|\d\+ warning|\s*\zs.*'), '\ ')
680         else
681                 let searchpat = 'l\.'.linenum
682         endif
683
684         " We first need to be in the scope of the correct file in the .log file.
685         " This is important for example, when a.tex and b.tex both have errors on
686         " line 9 of the file and we want to go to the error of b.tex. Merely
687         " searching forward from the beginning of the log file for l.9 will always
688         " land us on the error in a.tex.
689         if errfile != ''
690                 exec 'silent! bot pedit +/(\\(\\f\\|\\[\\|\]\\|\\s\\)*'.errfile.'/ '.a:filename
691         else
692                 exec 'bot pedit +0 '.a:filename
693         endif
694         " Goto the preview window
695         " TODO: This is not robust enough. Check that a wincmd j actually takes
696         " us to the preview window.
697         wincmd j
698         " now search forward from this position in the preview window for the
699         " numrep^th error of the current line in the quickfix window.
700         while numrep > 0
701                 call search(searchpat, 'W')
702                 let numrep = numrep - 1
703         endwhile
704         normal! z.
705
706 endfunction " }}}
707 " Tex_UpdatePreviewWindow: updates the view of the log file {{{
708 " Description: 
709 "       This function should be called when focus is in a quickfix window.
710 "       It opens the log file in a preview window and makes it display that
711 "       part of the log file which corresponds to the error which the user is
712 "       currently on in the quickfix window. Control returns to the quickfix
713 "       window when the function returns. 
714 "
715 function! Tex_UpdatePreviewWindow(filename)
716         call Tex_PositionPreviewWindow(a:filename)
717
718         if &previewwindow
719                 6 wincmd _
720                 wincmd p
721         endif
722 endfunction " }}}
723 " Tex_GotoErrorLocation: goes to the correct location of error in the tex file {{{
724 " Description: 
725 "   This function should be called when focus is in a quickfix window. This
726 "   function will first open the preview window of the log file (if it is not
727 "   already open), position the display of the preview to coincide with the
728 "   current error under the cursor and then take the user to the file in
729 "   which this error has occured. 
730 "
731 "   The position is both the correct line number and the column number.
732 function! Tex_GotoErrorLocation(filename)
733
734         " first use vim's functionality to take us to the location of the error
735         " accurate to the line (not column). This lets us go to the correct file
736         " without applying any logic.
737         exec "normal! \<enter>"
738         " If the log file is not found, then going to the correct line number is
739         " all we can do.
740         if glob(a:filename) == ''
741                 return
742         endif
743
744         let winnum = winnr()
745         " then come back to the quickfix window
746         wincmd w
747
748         " find out where in the file we had the error.
749         let linenum = matchstr(getline('.'), '|\zs\d\+\ze \(warning\|error\)|')
750         call Tex_PositionPreviewWindow(a:filename)
751
752         if getline('.') =~ 'l.\d\+'
753
754                 let brokenline = matchstr(getline('.'), 'l.'.linenum.' \zs.*\ze')
755                 " If the line is of the form
756                 "       l.10 ...and then there was some error
757                 " it means (most probably) that only part of the erroneous line is
758                 " shown. In this case, finding the length of the broken line is not
759                 " correct.  Instead goto the beginning of the line and search forward
760                 " for the part which is displayed and then go to its end.
761                 if brokenline =~ '^\M...'
762                         let partline = matchstr(brokenline, '^\M...\m\zs.*')
763                         let normcmd = "0/\\V".escape(partline, "\\")."/e+1\<CR>"
764                 else
765                         let column = strlen(brokenline) + 1
766                         let normcmd = column.'|'
767                 endif
768
769         elseif getline('.') =~ 'LaTeX Warning: \(Citation\|Reference\) `.*'
770
771                 let ref = matchstr(getline('.'), "LaTeX Warning: \\(Citation\\|Reference\\) `\\zs[^']\\+\\ze'")
772                 let normcmd = '0/'.ref."\<CR>"
773
774         else
775
776                 let normcmd = '0'
777
778         endif
779
780         " go back to the window where we came from.
781         exec winnum.' wincmd w'
782         exec 'silent! '.linenum.' | normal! '.normcmd
783
784         if !Tex_GetVarValue('Tex_ShowErrorContext')
785                 pclose!
786         endif
787 endfunction " }}}
788 " Tex_SetCompilerMaps: sets maps for compiling/viewing/searching {{{
789 " Description: 
790 function! <SID>Tex_SetCompilerMaps()
791         if exists('b:Tex_doneCompilerMaps')
792                 return
793         endif
794         let s:ml = exists('g:mapleader') ? g:mapleader : "\\"
795
796         nnoremap <buffer> <Plug>Tex_Compile :call Tex_RunLaTeX()<cr>
797         vnoremap <buffer> <Plug>Tex_Compile :call Tex_PartCompile()<cr>
798         nnoremap <buffer> <Plug>Tex_View :call Tex_ViewLaTeX()<cr>
799         nnoremap <buffer> <Plug>Tex_ForwardSearch :call Tex_ForwardSearchLaTeX()<cr>
800
801         call Tex_MakeMap(s:ml."ll", "<Plug>Tex_Compile", 'n', '<buffer>')
802         call Tex_MakeMap(s:ml."ll", "<Plug>Tex_Compile", 'v', '<buffer>')
803         call Tex_MakeMap(s:ml."lv", "<Plug>Tex_View", 'n', '<buffer>')
804         call Tex_MakeMap(s:ml."ls", "<Plug>Tex_ForwardSearch", 'n', '<buffer>')
805 endfunction 
806 " }}}
807
808 augroup LatexSuite
809         au LatexSuite User LatexSuiteFileType 
810                 \ call Tex_Debug('compiler.vim: Catching LatexSuiteFileType event', 'comp') | 
811                 \ call <SID>Tex_SetCompilerMaps()
812 augroup END
813
814 command! -nargs=0 -range=% TPartCompile :<line1>, <line2> silent! call Tex_PartCompile()
815 " Setting b:fragmentFile = 1 makes Tex_CompileLatex consider the present file
816 " the _main_ file irrespective of the presence of a .latexmain file.
817 command! -nargs=0 TCompileThis let b:fragmentFile = 1
818 command! -nargs=0 TCompileMainFile let b:fragmentFile = 0
819
820 " vim:fdm=marker:ff=unix:noet:ts=4:sw=4