I broke up with neovim....vim is my best friend now

This commit is contained in:
LinlyBoi
2023-04-30 08:14:07 +03:00
parent 0d185449c5
commit 4a4a6b1e81
5245 changed files with 468325 additions and 25 deletions

View File

@@ -0,0 +1,321 @@
" ==============================================================================
" File: syntaxFolds.vim
" Authors: Srinath Avadhanula, Gerd Wachsmuth
" ( srinath@fastmail.fm )
" Description: Emulation of the syntax folding capability of vim using manual
" folding
"
" This script provides an emulation of the syntax folding of vim using manual
" folding. Just as in syntax folding, the folds are defined by regions. Each
" region is specified by a call to AddSyntaxFoldItem() which accepts either 4
" or 6 parameters. When it is called with 4 arguments, it is equivalent to
" calling it with 6 arguments with the last two left blank (i.e as empty
" strings).
" The folds are actually created when calling MakeSyntaxFolds().
"
" call AddSyntaxFoldItem(startpat, endpat, startoff, endoff [, skipStart, skipEnd])
"
" startpat: a line matching this pattern defines the beginning of a fold.
" endpat : a line matching this pattern defines the end of a fold.
" startoff: this is the offset from the starting line at which folding will
" actually start
" endoff : like startoff, but gives the offset of the actual fold end from
" the line satisfying endpat.
" startoff and endoff are necessary when the folding region does
" not have a specific end pattern corresponding to a start
" pattern. for example in latex,
" \begin{section}
" defines the beginning of a section, but its not necessary to
" have a corresponding
" \end{section}
" the section is assumed to end 1 line _before_ another section
" starts.
" startskip: a pattern which defines the beginning of a "skipped" region.
"
" For example, suppose we define a \itemize fold as follows:
" startpat = '^\s*\\item',
" endpat = '^\s*\\item\|^\s*\\end{\(enumerate\|itemize\|description\)}',
" startoff = 0,
" endoff = -1
"
" This defines a fold which starts with a line beginning with an
" \item and ending one line before a line beginning with an
" \item or \end{enumerate} etc.
"
" Then, as long as \item's are not nested things are fine.
" However, once items begin to nest, the fold started by one
" \item can end because of an \item in an \itemize
" environment within this \item. i.e, the following can happen:
"
" \begin{itemize}
" \item Some text <------- fold will start here
" This item will contain a nested item
" \begin{itemize} <----- fold will end here because next line contains \item...
" \item Hello
" \end{itemize} <----- ... instead of here.
" \item Next item of the parent itemize
" \end{itemize}
"
" Therefore, in order to completely define a folding item which
" allows nesting, we need to also define a "skip" pattern.
" startskip and end skip do that.
" Leave '' when there is no nesting.
" endskip: the pattern which defines the end of the "skip" pattern for
" nested folds.
"
" Example:
" 1. A syntax fold region for a latex section is
" startpat = "\\section{"
" endpat = "\\section{"
" startoff = 0
" endoff = -1
" startskip = ''
" endskip = ''
" Note that the start and end patterns are thus the same and endoff has a
" negative value to capture the effect of a section ending one line before
" the next starts.
" 2. A syntax fold region for the \itemize environment is:
" startpat = '^\s*\\item',
" endpat = '^\s*\\item\|^\s*\\end{\(enumerate\|itemize\|description\)}',
" startoff = 0,
" endoff = -1,
" startskip = '^\s*\\begin{\(enumerate\|itemize\|description\)}',
" endskip = '^\s*\\end{\(enumerate\|itemize\|description\)}'
" Note the use of startskip and endskip to allow nesting.
"
"
" Each time a call is made to FoldRegionWith[No]Skip(), all the regions are folded up.
" Nested folds can be created by successive calls to AddSyntaxFoldItem(). See
" MakeTexFolds() for an idea of how this works for latex files.
if exists('b:suppress_latex_suite') && b:suppress_latex_suite == 1
finish
endif
" Function: AddSyntaxFoldItem (start, end, startoff, endoff [, skipStart, skipEnd]) {{{
function! AddSyntaxFoldItem(start, end, startoff, endoff, ...)
if a:0 > 0
let skipStart = a:1
let skipEnd = a:2
else
let skipStart = ''
let skipEnd = ''
end
if !exists('b:numFoldItems')
let b:numFoldItems = 0
end
let b:numFoldItems = b:numFoldItems + 1
exe 'let b:startPat_'.b:numFoldItems.' = a:start'
exe 'let b:endPat_'.b:numFoldItems.' = a:end'
exe 'let b:startOff_'.b:numFoldItems.' = a:startoff'
exe 'let b:endOff_'.b:numFoldItems.' = a:endoff'
exe 'let b:skipStartPat_'.b:numFoldItems.' = skipStart'
exe 'let b:skipEndPat_'.b:numFoldItems.' = skipEnd'
endfunction
" }}}
" Function: MakeSyntaxFolds (force) {{{
" Description: This function calls FoldRegionsWith[No]Skip() several times with the
" parameters specifying various regions resulting in a nested fold
" structure for the file.
function! MakeSyntaxFolds(force)
if exists('b:doneFolding') && a:force == 0
return
end
let start = reltime()
" Save cursor position
if exists('*getcurpos')
let curpos = getcurpos()
else
let curpos = getpos('.')
endif
setlocal fdm=manual
normal! zE
if !exists('b:numFoldItems')
echohl ErrorMsg
echomsg 'Error in MakeSyntaxFolds: You have to call AddSyntaxFoldItem() first!'
echohl None
return
end
for i in range(1, b:numFoldItems)
exe 'let startPat = b:startPat_'.i
exe 'let endPat = b:endPat_'.i
exe 'let startOff = b:startOff_'.i
exe 'let endOff = b:endOff_'.i
exe 'let skipStart = b:skipStartPat_'.i
exe 'let skipEnd = b:skipEndPat_'.i
if skipStart != ''
call s:FoldRegionsWithSkip(startPat, endPat, startOff, endOff, skipStart, skipEnd, 1, line('$'))
else
call s:FoldRegionsWithNoSkip(startPat, endPat, startOff, endOff, 1, line('$'), [])
end
call s:Debug('done folding ['.startPat.']')
endfor
" Close all folds.
normal! zM
call setpos('.', curpos)
if foldlevel(curpos[1]) > 1
exe "normal! ".(foldlevel(curpos[1]) - 1)."zo"
end
let b:doneFolding = 0
" Report a folding performance.
if exists('*Tex_Debug')
call Tex_Debug('Finished folding in ' . reltimestr(reltime(start)) . ' seconds.', 'SyntaxFolds')
end
endfunction
" }}}
" Local Helper Functions
" Function: s:FoldRegionsWithSkip: folding things such as \item's which can be nested. {{{
function! s:FoldRegionsWithSkip(startpat, endpat, startoff, endoff, startskip, endskip, line1, line2)
" Move cursor to (begin of) line1
call setpos('.', [0, a:line1, 1, 0])
" count the regions which have been skipped as we go along. do not want to
" create a fold which with a beginning or end line in one of the skipped
" regions.
let skippedRegions = []
let BeginSkipArray = []
" start searching for either the starting pattern or the end pattern.
while search(a:startskip.'\|'.a:endskip, 'Wc')
if getline('.') =~ a:endskip
if len(BeginSkipArray) > 0
" Pop last elements:
let lastBegin = remove(BeginSkipArray, -1)
let lastRegions = remove(skippedRegions, -1)
call s:Debug('popping '.lastBegin.' from stack and folding until '.line('.'))
call s:FoldRegionsWithNoSkip(a:startpat, a:endpat, a:startoff, a:endoff, lastBegin, line('.'), lastRegions)
" The found region should be skipped on higher levels:
if len(skippedRegions) > 0
call add(skippedRegions[-1], [lastBegin, line('.')])
end
else
call s:Debug('Found [' . a:endskip . '] on line ' . line('.') . ', but nothing is in BeginSkipArray. Something is wrong here.')
end
elseif getline('.') =~ a:startskip
" if this is the beginning of a skip region, then, push this line as
" the beginning of a skipped region.
call s:Debug('pushing '.line('.').' ['.getline('.').'] into stack')
call add(BeginSkipArray, line('.'))
call add(skippedRegions, [])
end
if line('.') == line('$')
break
endif
" Move one line down
normal! j0
endwhile
if len(BeginSkipArray) > 0
call s:Debug('Finished FoldRegionsWithSkip, but BeginSkipArray is not empty, something is wrong here')
for i in range(0,len(BeginSkipArray)-1)
call s:Debug('BeginSkipArray[' . i . '] = ' . BeginSkipArray[i] )
endfor
end
call s:Debug('FoldRegionsWithSkip finished')
endfunction
" }}}
" Function: s:FoldRegionsWithNoSkip: folding things such as \sections which do not nest. {{{
function! s:FoldRegionsWithNoSkip(startpat, endpat, startoff, endoff, line1, line2, skippedRegions)
call s:Debug('line1 = '.a:line1.', line2 = ' . a:line2 . ', skippedRegions = ' . string(a:skippedRegions))
" Move cursor to (begin of) line1
call setpos('.', [0, a:line1, 1, 0])
call s:Debug('searching for ['.a:startpat.']')
let lineBegin = s:MySearch(a:startpat, 'in')
call s:Debug('... and finding it at '.lineBegin)
while lineBegin <= a:line2
if s:IsInSkippedRegion(lineBegin, a:skippedRegions)
let lineBegin = s:MySearch(a:startpat, 'out')
call s:Debug(lineBegin.' is being skipped')
continue
end
" Move to end of start pattern:
normal! 0
call search(a:startpat, 'cWe')
let lineEnd = s:MySearch(a:endpat, 'out')
while s:IsInSkippedRegion(lineEnd, a:skippedRegions) && lineEnd <= a:line2
let lineEnd = s:MySearch(a:endpat, 'out')
endwhile
if lineEnd > a:line2
exe (lineBegin + a:startoff).','.a:line2.' fold'
" Open all folds:
normal! zR
break
else
call s:Debug ('for ['.a:startpat.'] '.(lineBegin + a:startoff).','.(lineEnd + a:endoff).' fold')
exe (lineBegin + a:startoff).','.(lineEnd + a:endoff).' fold'
" Open all folds:
normal! zR
end
call s:Debug('line1 = '.a:line1.', searching from '.line('.').'... for ['.a:startpat.']')
let lineBegin = s:MySearch(a:startpat, 'in')
call s:Debug('... and finding it at '.lineBegin)
endwhile
" Move cursor to (end of) line2
exe a:line2
normal! $
return
endfunction
" }}}
" Function: s:MySearch: just like search(), but returns large number on failure {{{
function! s:MySearch(pat, opt)
if a:opt == 'in'
normal! 0
let ret = search(a:pat, 'cW')
else
normal! $
let ret = search(a:pat, 'W')
end
if ret == 0
let ret = line('$') + 1
end
return ret
endfunction
" }}}
" Function: s:IsInSkippedRegion (lnum, regions) {{{
" Description: finds whether a given line number is within one of the regions
" skipped.
function! s:IsInSkippedRegion(lnum, regions)
for region in a:regions
if a:lnum >= region[0] && a:lnum <= region[1]
return 1
end
endfor
return 0
endfunction
" }}}
" Function: s:Debug: A wrapper for Tex_Debug, if it exists and if g:SyntaxFolds_Debug == 1 {{{
function! s:Debug(string)
if exists('g:SyntaxFolds_Debug') && g:SyntaxFolds_Debug == 1 && exists('*Tex_Debug')
call Tex_Debug(a:string,'SyntaxFolds')
end
endfunction
" }}}
" vim600:fdm=marker

View File

@@ -0,0 +1,249 @@
" filebrowser.vim: utility file for vim 6.2+
"
" Copyright: Srinath Avadhanula <srinath AT fastmail DOT fm>
" Parts of this file are taken from explorer.vim which is a plugin file
" distributed with vim under the Vim charityware license.
" License: distributed under the Vim charityware license.
"
" Settings:
" FB_CallBackFunction: the function name which gets called when the user
" presses <cr> on a file-name in the file browser.
" FB_AllowRegexp: A filename has to match this regexp to be displayed.
" FB_RejectRegexp: If a filename matches this regexp, then its not displayed.
" (Both these regexps are '' by default which means no filtering is
" done).
if exists('b:suppress_latex_suite') && b:suppress_latex_suite == 1
finish
endif
" line continuation used here.
let s:save_cpo = &cpo
set cpo&vim
"======================================================================
" Globally visible functions (API)
"======================================================================
" FB_OpenFileBrowser: opens a new buffer and displays the file list {{{
" Description:
function! FB_OpenFileBrowser(dir)
if !isdirectory(a:dir)
return
endif
if exists('s:FB_BufferNumber')
if bufwinnr(s:FB_BufferNumber) != -1
execute bufwinnr(s:FB_BufferNumber).' wincmd w'
return
endif
execute 'aboveleft split #'.s:FB_BufferNumber
else
aboveleft split __Choose_File__
let s:FB_BufferNumber = bufnr('%')
endif
call FB_DisplayFiles(a:dir)
endfunction " }}}
" FB_DisplayFiles: displays the files in a given directory {{{
" Description:
" Call this function only when the cursor is in a temporary buffer
function! FB_DisplayFiles(dir)
if !isdirectory(a:dir)
return
endif
call s:FB_SetSilentSettings()
" make this a "scratch" buffer
call s:FB_SetScratchSettings()
let allowRegexp = s:FB_GetVar('FB_AllowRegexp', '')
let rejectRegexp = s:FB_GetVar('FB_RejectRegexp', '')
" change to the directory to make processing simpler.
try
execute "lcd ".fnameescape(a:dir)
catch
echohl ErrorMsg
unsilent echomsg 'Cannot enter directory "' . fnamemodify(a:dir, ':p') . '"'
echohl None
return
endtry
" delete everything in the buffer.
" IMPORTANT: we need to be in a scratch buffer
0,$ d_
let allFilenames = glob('*')
let dispFiles = ""
let subDirs = "../\n"
let start = 0
for filename in split(allFilenames, "\n")
if isdirectory(filename)
let subDirs = subDirs.filename."/\n"
else
if allowRegexp != '' && filename !~ allowRegexp
elseif rejectRegexp != '' && filename =~ rejectRegexp
else
let dispFiles = dispFiles.filename."\n"
endif
endif
endfor
0put!=dispFiles
0put!=subDirs
" delte the last empty line resulting from the put
$ d_
call s:FB_SetHighlighting()
call s:FB_DisplayHelp()
call s:FB_SetMaps()
" goto the first file/directory
0
call search('^"=', 'w')
normal! j:<bs>
set nomodified nomodifiable
call s:FB_ResetSilentSettings()
endfunction " }}}
" FB_SetVar: sets script local variables from outside this script {{{
" Description:
function! FB_SetVar(varname, value)
let s:{a:varname} = a:value
endfunction " }}}
" ==============================================================================
" Script local functions below this
" ==============================================================================
" FB_SetHighlighting: sets syntax highlighting for the buffer {{{
" Description:
" Origin: from explorer.vim in vim
function! <SID>FB_SetHighlighting()
" Set up syntax highlighting
" Something wrong with the evaluation of the conditional though...
if has("syntax") && exists("g:syntax_on") && !has("syntax_items")
syn match browseSynopsis "^\"[ -].*"
syn match browseDirectory "[^\"].*/ "
syn match browseDirectory "[^\"].*/$"
syn match browseCurDir "^\"= .*$"
"hi def link browseSynopsis PreProc
hi def link browseSynopsis Special
hi def link browseDirectory Directory
hi def link browseCurDir Statement
hi def link browseSuffixes Type
endif
endfunction " }}}
" FB_SetMaps: sets buffer local maps {{{
" Description:
function! <SID>FB_SetMaps()
nnoremap <buffer> <silent> q :bdelete<cr>
nnoremap <buffer> <silent> <esc> :bdelete<cr>
nnoremap <buffer> <silent> <CR> :call <SID>FB_EditEntry()<CR>
nnoremap <buffer> <silent> ? :call <SID>FB_ToggleHelp()<CR>
nnoremap <buffer> C :CD<space>
command! -nargs=1 -buffer -complete=dir CD :silent call FB_DisplayFiles('<args>')
" lock the user in this window
nnoremap <buffer> <C-w> <nop>
endfunction " }}}
" FB_SetSilentSettings: some settings which make things silent {{{
" Description:
" Origin: from explorer.vim distributed with vim.
function! <SID>FB_SetSilentSettings()
let s:save_report=&report
let s:save_showcmd = &sc
set report=10000 noshowcmd
endfunction
" FB_ResetSilentSettings: reset settings set by FB_SetSilentSettings
" Description:
function! <SID>FB_ResetSilentSettings()
let &report=s:save_report
let &showcmd = s:save_showcmd
endfunction " }}}
" FB_SetScratchSettings: makes the present buffer a scratch buffer {{{
" Description:
function! <SID>FB_SetScratchSettings()
" Turn off the swapfile, set the buffer type so that it won't get
" written, and so that it will get deleted when it gets hidden.
setlocal noreadonly modifiable
setlocal noswapfile
setlocal buftype=nowrite
setlocal bufhidden=delete
" Don't wrap around long lines
setlocal nowrap
endfunction
" }}}
" FB_ToggleHelp: toggles verbosity of help {{{
" Description:
function! <SID>FB_ToggleHelp()
let s:FB_VerboseHelp = 1 - s:FB_GetVar('FB_VerboseHelp', 0)
call FB_DisplayFiles('.')
endfunction " }}}
" FB_DisplayHelp: displays a helpful header {{{
" Description:
function! <SID>FB_DisplayHelp()
let verboseHelp = s:FB_GetVar('FB_VerboseHelp', 0)
if verboseHelp
let txt =
\ "\" <cr> on file: choose the file and quit\n"
\ ."\" <cr> on dir : enter directory\n"
\ ."\" q/<esc> : quit without choosing\n"
\ ."\" C/:CD : change directory\n"
\ ."\" ? : toggle help verbosity\n"
\ ."\"= ".getcwd()
else
let txt = "\" ?: toggle help verbosity\n"
\ ."\"= ".getcwd()
endif
0put!=txt
endfunction " }}}
" FB_EditEntry: handles the user pressing <enter> on a line {{{
" Description:
function! <SID>FB_EditEntry()
let line = getline('.')
if isdirectory(line)
call FB_DisplayFiles(line)
endif
" If the user has a call back function defined on choosing a file, handle
" it.
let cbf = s:FB_GetVar('FB_CallBackFunction', '')
if cbf != '' && line !~ '^" ' && filereadable(line)
let fname = fnamemodify(line, ':p')
bdelete
let arguments = s:FB_GetVar('FB_CallBackFunctionArgs', '')
if arguments != ''
let arguments = ','.arguments
endif
if exists('*Tex_Debug')
call Tex_Debug('arguments = '.arguments, 'fb')
call Tex_Debug("call ".cbf."('".fname."'".arguments.')', 'fb')
endif
exec "call ".cbf."('".fname."'".arguments.')'
endif
endfunction " }}}
" FB_GetVar: gets the most local value of a variable {{{
function! <SID>FB_GetVar(name, default)
if exists('s:'.a:name)
return s:{a:name}
elseif exists('w:'.a:name)
return w:{a:name}
elseif exists('b:'.a:name)
return b:{a:name}
elseif exists('g:'.a:name)
return g:{a:name}
else
return a:default
endif
endfunction
" }}}
let &cpo = s:save_cpo
" vim:fdm=marker:ff=unix:noet:ts=4:sw=4:nowrap

View File

@@ -0,0 +1,766 @@
" File: imaps.vim
" Authors: Srinath Avadhanula <srinath AT fastmail.fm>
" Benji Fisher <benji AT member.AMS.org>
"
" Description: insert mode template expander with cursor placement
" while preserving filetype indentation.
"
"
" Documentation: {{{
"
" Motivation:
" this script provides a way to generate insert mode mappings which do not
" suffer from some of the problem of mappings and abbreviations while allowing
" cursor placement after the expansion. It can alternatively be thought of as
" a template expander.
"
" Consider an example. If you do
"
" imap lhs something
"
" then a mapping is set up. However, there will be the following problems:
" 1. the 'ttimeout' option will generally limit how easily you can type the
" lhs. if you type the left hand side too slowly, then the mapping will not
" be activated.
" 2. if you mistype one of the letters of the lhs, then the mapping is
" deactivated as soon as you backspace to correct the mistake.
"
" If, in order to take care of the above problems, you do instead
"
" iab lhs something
"
" then the timeout problem is solved and so is the problem of mistyping.
" however, abbreviations are only expanded after typing a non-word character.
" which causes problems of cursor placement after the expansion and invariably
" spurious spaces are inserted.
"
" Usage Example:
" this script attempts to solve all these problems by providing an emulation
" of imaps wchich does not suffer from its attendant problems. Because maps
" are activated without having to press additional characters, therefore
" cursor placement is possible. furthermore, file-type specific indentation is
" preserved, because the rhs is expanded as if the rhs is typed in literally
" by the user.
"
" Each "mapping" is of the form:
"
" call IMAP (lhs, rhs, ft)
"
" Some characters in the RHS have special meaning which help in cursor
" placement.
"
" Example One:
"
" call IMAP ("bit`", "\\begin{itemize}\<cr>\\item <++>\<cr>\\end{itemize}<++>", "tex")
"
" This effectively sets up the map for "bit`" whenever you edit a latex file.
" When you type in this sequence of letters, the following text is inserted:
"
" \begin{itemize}
" \item *
" \end{itemize}<++>
"
" where * shows the cursor position. The cursor position after inserting the
" text is decided by the position of the first "place-holder". Place holders
" are special characters which decide cursor placement and movement. In the
" example above, the place holder characters are <+ and +>. After you have typed
" in the item, press <C-j> and you will be taken to the next set of <++>'s.
" Therefore by placing the <++> characters appropriately, you can minimize the
" use of movement keys.
"
" NOTE: Set g:Imap_UsePlaceHolders to 0 to disable placeholders altogether.
" Set
" g:Imap_PlaceHolderStart and g:Imap_PlaceHolderEnd
" to something else if you want different place holder characters.
" Also, b:Imap_PlaceHolderStart and b:Imap_PlaceHolderEnd override the values
" of g:Imap_PlaceHolderStart and g:Imap_PlaceHolderEnd respectively. This is
" useful for setting buffer specific place hoders.
"
" Example Two:
" You can use the <C-r> command to insert dynamic elements such as dates.
" call IMAP ('date`', "\<c-r>=strftime('%b %d %Y')\<cr>", '')
"
" sets up the map for date` to insert the current date.
" }}}
if exists('b:suppress_latex_suite') && b:suppress_latex_suite == 1
finish
endif
" line continuation used here.
let s:save_cpo = &cpo
set cpo&vim
" ==============================================================================
" Script Options / Variables
" ==============================================================================
" Options {{{
if !exists('g:Imap_StickyPlaceHolders')
let g:Imap_StickyPlaceHolders = 1
endif
if !exists('g:Imap_DeleteEmptyPlaceHolders')
let g:Imap_DeleteEmptyPlaceHolders = 1
endif
if !exists('g:Imap_GoToSelectMode')
let g:Imap_GoToSelectMode = 1
endif
" }}}
" Variables {{{
" s:LHS_{ft}_{char} will be generated automatically. It will look like
" s:LHS_tex_o = 'fo\|foo\|boo' and contain all mapped sequences ending in "o".
"
" s:Map_{ft}_{lhs} will be generated automatically. It will look like
" s:Map_c_foo = 'for(<++>; <++>; <++>)', the mapping for "foo".
"
" s:LHS_{ft} will be generated automatically. It contains all chars for which
" s:LHS_{ft}_{char} is not empty.
"
" b:IMAP_imaps will be generated automatically. It contains all chars which
" were mapped in the current buffer.
"
" }}}
" ==============================================================================
" functions for easy insert mode mappings.
" ==============================================================================
" IMAP: Adds a "fake" insert mode mapping. {{{
" For example, doing
" IMAP('abc', 'def' ft)
" will mean that if the letters abc are pressed in insert mode, then
" they will be replaced by def. If ft != '', then the "mapping" will be
" buffer local. You have to call IMAP_infect() on new buffers of type ft.
"
" Using IMAP has a few advantages over simply doing:
" imap abc def
" 1. with imap, if you begin typing abc, the cursor will not advance and
" long as there is a possible completion, the letters a, b, c will be
" displayed on on top of the other. using this function avoids that.
" 2. with imap, if a backspace or arrow key is pressed before completing
" the word, then the mapping is lost. this function allows movement.
" (this ofcourse means that this function is only limited to
" left-hand-sides which do not have movement keys or unprintable
" characters)
" It works by only mapping the last character of the left-hand side.
" when this character is typed in, then a reverse lookup is done and if
" the previous characters consititute the left hand side of the mapping,
" the previously typed characters and erased and the right hand side is
" inserted
" IMAP: set up a filetype specific mapping.
" Description:
" "maps" the lhs to rhs in files of type 'ft'. If supplied with 2
" additional arguments, then those are assumed to be the placeholder
" characters in rhs. If unspecified, then the placeholder characters
" are assumed to be '<+' and '+>' These placeholder characters in
" a:rhs are replaced with the users setting of
" [bg]:Imap_PlaceHolderStart and [bg]:Imap_PlaceHolderEnd settings.
"
function! IMAP(lhs, rhs, ft, ...)
" Find the place holders to save for IMAP_PutTextWithMovement() .
if a:0 < 2
let phs = '<+'
let phe = '+>'
else
let phs = a:1
let phe = a:2
endif
let hash = s:Hash(a:lhs)
let s:Map_{a:ft}_{hash} = a:rhs
let s:phs_{a:ft}_{hash} = phs
let s:phe_{a:ft}_{hash} = phe
" Add a:lhs to the list of left-hand sides that end with lastLHSChar:
let lastLHSChar = s:MultiByteLastCharacter(a:lhs)
let hash = s:Hash(lastLHSChar)
if !exists("s:LHS_" . a:ft . "_" . hash)
let s:LHS_{a:ft}_{hash} = escape(a:lhs, '\')
else
" Check whether this lhs is already mapped.
if a:lhs !~# '\V\^\%(' . s:LHS_{a:ft}_{hash} . '\)\$'
let s:LHS_{a:ft}_{hash} = escape(a:lhs, '\') .'\|'. s:LHS_{a:ft}_{hash}
endif
endif
" Add lastLHSChar to s:LHS_{ft}
if a:ft != ''
if !exists('s:LHS_'.a:ft)
let s:LHS_{a:ft} = []
endif
if index(s:LHS_{a:ft}, lastLHSChar) < 0
call add(s:LHS_{a:ft}, lastLHSChar )
endif
endif
" Only add a imap if it is a global IMAP or we are in the correct filetype
" (then, we add a <buffer>-local imap, other buffers have to be infected
" with IMAP_infect).
if a:ft != ''
if &ft == a:ft
let buffer = '<buffer>'
else
return
endif
else
let buffer = ''
endif
" map only the last character of the left-hand side.
call s:IMAP_add_imap( lastLHSChar, buffer )
endfunction
" }}}
" IUNMAP: Removes a "fake" insert mode mapping. {{{
function! IUNMAP(lhs, ft)
let lastLHSChar = s:MultiByteLastCharacter(a:lhs)
let charHash = s:Hash(lastLHSChar)
" Check whether the mapping exists
if exists("s:LHS_" . a:ft . "_" . charHash)
\ && a:lhs =~# '\V\^\%(' . s:LHS_{a:ft}_{charHash} . '\)\$'
" Remove lhs from the list of mappings
let s:LHS_{a:ft}_{charHash} = substitute(s:LHS_{a:ft}_{charHash},
\ '\V\(\^\|\\|\)' . escape(escape(a:lhs, '\'), '\') . '\(\$\|\\|\)',
\ '\\|', '')
" Remove leading/trailing '\|'
let s:LHS_{a:ft}_{charHash} = substitute(s:LHS_{a:ft}_{charHash}, '^\\|\|\\|$', '', '')
let hash = s:Hash(a:lhs)
unlet s:Map_{a:ft}_{hash}
unlet s:phs_{a:ft}_{hash}
unlet s:phe_{a:ft}_{hash}
if strlen(s:LHS_{a:ft}_{charHash}) == 0
" No more mappings left for this lastLHSChar.
let idx = index(s:LHS_{a:ft}, lastLHSChar)
if idx >= 0
call remove(s:LHS_{a:ft}, idx )
endif
" Check for ft and unmap the last character of the left-hand side.
" (if ft is set, other buffers with the same ft have to be updated with
" IMAP_desinfect() and IMAP_infect()).
if a:ft != ''
if &ft == a:ft
call s:IMAP_rm_imap( lastLHSChar, '<buffer>' )
endif
else
call s:IMAP_rm_imap( lastLHSChar, '' )
endif
endif
else
" a:lhs is not mapped!
" Do nothing.
endif
endfunction
" }}}
" IMAP_infect: Infect the current buffer with ft IMAPS. {{{
function! IMAP_infect()
if &ft != '' && exists('s:LHS_'.&ft)
for lastLHSChar in s:LHS_{&ft}
call s:IMAP_add_imap( lastLHSChar, '<buffer>' )
endfor
endif
endfunction
" }}}
" IMAP_desinfect: Desinfect the current buffer with ft IMAPS. {{{
function! IMAP_desinfect()
if exists('b:IMAP_imaps')
for lastLHSChar in copy(b:IMAP_imaps)
call s:IMAP_rm_imap( lastLHSChar, '<buffer>' )
endfor
endif
endfunction
" }}}
" IMAP_list: list the rhs and place holders corresponding to a:lhs {{{
"
" Added mainly for debugging purposes, but maybe worth keeping.
function! IMAP_list(lhs)
let char = s:MultiByteLastCharacter(a:lhs)
let charHash = s:Hash(char)
if exists("s:LHS_" . &ft ."_". charHash)
\ && a:lhs =~# '\V\^\%(' . s:LHS_{&ft}_{charHash} . '\)\$'
let ft = &ft
elseif exists("s:LHS__" . charHash)
\ && a:lhs =~# '\V\^\%(' . s:LHS__{charHash} . '\)\$'
let ft = ""
else
return ""
endif
let hash = s:Hash(a:lhs)
return "rhs = " . strtrans( s:Map_{ft}_{hash} ) . " place holders = " .
\ s:phs_{ft}_{hash} . " and " . s:phe_{ft}_{hash}
endfunction
" }}}
" IMAP_list_all: list all the rhs and place holders with lhs ending in a:char {{{
function! IMAP_list_all(char)
let result = ''
let charHash = s:Hash(a:char)
if &ft == ''
let ft_list = ['']
else
let ft_list = [&ft, '']
endif
" Loop over current file type and global IMAPs
for ft in ft_list
if ft == ''
let ft_display = 'global: '
else
let ft_display = ft . ': '
endif
if exists("s:LHS_" . ft ."_". charHash)
for lhs in split( s:LHS_{ft}_{charHash}, '\\|' )
" Undo the escaping of backslashes in lhs
let lhs = substitute(lhs, '\\\\', '\', 'g')
let hash = s:Hash(lhs)
let result .= ft_display . lhs . " => " . strtrans( s:Map_{ft}_{hash} ) . "\n"
endfor
endif
endfor
return result
endfunction
" }}}
" LookupCharacter: inserts mapping corresponding to this character {{{
"
" This function extracts from s:LHS_{&ft}_{a:char} or s:LHS__{a:char}
" the longest lhs matching the current text. Then it replaces lhs with the
" corresponding rhs saved in s:Map_{ft}_{lhs} .
" The place-holder variables are passed to IMAP_PutTextWithMovement() .
function! s:LookupCharacter(char)
if IMAP_GetVal('Imap_FreezeImap', 0) == 1
return a:char
endif
let charHash = s:Hash(a:char)
" The line so far, including the character that triggered this function:
let linestart = strpart(getline("."), 0, col(".")-1)
let text = linestart . a:char
" Prefer a local map to a global one, even if the local map is shorter.
" Is this what we want? Do we care?
" Use '\V' (very no-magic) so that only '\' is special, and it was already
" escaped when building up s:LHS_{&ft}_{charHash} .
if exists("s:LHS_" . &ft . "_" . charHash)
\ && text =~ "\\C\\V\\%(" . s:LHS_{&ft}_{charHash} . "\\)\\$"
let ft = &ft
elseif exists("s:LHS__" . charHash)
\ && text =~ "\\C\\V\\%(" . s:LHS__{charHash} . "\\)\\$"
let ft = ""
else
" If this is a character which could have been used to trigger an
" abbreviation, check if an abbreviation exists.
if a:char !~ '\k'
let lastword = matchstr(linestart, '\k\+$', '')
call IMAP_Debug('getting lastword = ['.lastword.']', 'imap')
if lastword != ''
let abbreviationRHS = maparg( lastword, 'i', 1 )
call IMAP_Debug('getting abbreviationRHS = ['.abbreviationRHS.']', 'imap')
if abbreviationRHS == ''
return a:char
endif
let abbreviationRHS = escape(abbreviationRHS, '\<"')
exec 'let abbreviationRHS = "'.abbreviationRHS.'"'
let lhs = lastword.a:char
let rhs = abbreviationRHS.a:char
let phs = IMAP_GetPlaceHolderStart()
let phe = IMAP_GetPlaceHolderEnd()
else
return a:char
endif
else
return a:char
endif
endif
" Find the longest left-hand side that matches the line so far.
" matchstr() returns the match that starts first. This automatically
" ensures that the longest LHS is used for the mapping.
if !exists('lhs') || !exists('rhs')
let lhs = matchstr(text, "\\C\\V\\%(" . s:LHS_{ft}_{charHash} . "\\)\\$")
let hash = s:Hash(lhs)
let rhs = s:Map_{ft}_{hash}
let phs = s:phs_{ft}_{hash}
let phe = s:phe_{ft}_{hash}
endif
if strlen(lhs) == 0
return a:char
endif
" enough back-spaces to erase the left-hand side
let bs = repeat("\<bs>", s:MultiByteStrlen(lhs))
" \<c-g>u inserts an undo point
let result = a:char . "\<c-g>u" . bs . IMAP_PutTextWithMovement(rhs, phs, phe)
if a:char !~? '[a-z0-9]'
" If 'a:char' is not a letter or number, insert it literally.
let result = "\<c-v>" . result
endif
return result
endfunction
" }}}
" IMAP_PutTextWithMovement: returns the string with movement appended {{{
" Description:
" If a:str contains "placeholders", then appends movement commands to
" str in a way that the user moves to the first placeholder and enters
" insert or select mode. If supplied with 2 additional arguments, then
" they are assumed to be the placeholder specs. Otherwise, they are
" assumed to be '<+' and '+>'. These placeholder chars are replaced
" with the users settings of [bg]:Imap_PlaceHolderStart and
" [bg]:Imap_PlaceHolderEnd.
function! IMAP_PutTextWithMovement(str, ...)
" The placeholders used in the particular input string. These can be
" different from what the user wants to use.
if a:0 < 2
let phs = '<+'
let phe = '+>'
else
let phs = escape(a:1, '\')
let phe = escape(a:2, '\')
endif
let text = a:str
" The user's placeholder settings.
let phsUser = IMAP_GetPlaceHolderStart()
let pheUser = IMAP_GetPlaceHolderEnd()
let pattern = '\V\(\.\{-}\)' .phs. '\(\.\{-}\)' .phe. '\(\.\*\)'
" If there are no placeholders, just return the text.
if text !~ pattern
call IMAP_Debug('Not getting '.phs.' and '.phe.' in '.text, 'imap')
return text
endif
" Break text up into "initial <+template+> final"; any piece may be empty.
let initial = substitute(text, pattern, '\1', '')
let template = substitute(text, pattern, '\2', '')
let final = substitute(text, pattern, '\3', '')
" If the user does not want to use placeholders, then remove all but the
" first placeholder.
" Otherwise, replace all occurences of the placeholders here with the
" user's choice of placeholder settings.
if exists('g:Imap_UsePlaceHolders') && !g:Imap_UsePlaceHolders
let final = substitute(final, '\V'.phs.'\.\{-}'.phe, '', 'g')
else
let final = substitute(final, '\V'.phs.'\(\.\{-}\)'.phe,
\ phsUser.'\1'.pheUser, 'g')
endif
" Build up the text to insert:
" 1. the initial text plus an extra character;
" 2. go to Normal mode with <C-\><C-N>, so it works even if 'insertmode'
" is set, and mark the position;
" 3. replace the extra character with tamplate and final;
" 4. back to Normal mode and restore the cursor position;
" 5. call IMAP_Jumpfunc().
let template = phsUser . template . pheUser
" Old trick: insert and delete a character to get the same behavior at
" start, middle, or end of line and on empty lines.
let text = initial . "X\<C-\>\<C-N>:call IMAP_Mark('set')\<CR>\"_s"
let text = text . template . final
let text = text . "\<C-\>\<C-N>:call IMAP_Mark('go')\<CR>"
let text = text . ":call IMAP_Jumpfunc('', 1)\<CR>"
call IMAP_Debug('IMAP_PutTextWithMovement: text = ['.text.']', 'imap')
return text
endfunction
" }}}
" IMAP_Jumpfunc: takes user to next <+place-holder+> {{{
" Author: Luc Hermitte
" Arguments:
" direction: flag for the search() function. If set to '', search forwards,
" if 'b', then search backwards. See the {flags} argument of the
" |search()| function for valid values.
" inclusive: In vim, the search() function is 'exclusive', i.e we always goto
" next cursor match even if there is a match starting from the
" current cursor position. Setting this argument to 1 makes
" IMAP_Jumpfunc() also respect a match at the current cursor
" position. 'inclusive'ness is necessary for IMAP() because a
" placeholder string can occur at the very beginning of a map which
" we want to select.
" We use a non-zero value only in special conditions. Most mappings
" should use a zero value.
function! IMAP_Jumpfunc(direction, inclusive)
" The user's placeholder settings.
let phsUser = IMAP_GetPlaceHolderStart()
let pheUser = IMAP_GetPlaceHolderEnd()
" Set up flags for the search() function
let flags = a:direction
if a:inclusive
let flags .= 'c'
end
let searchString = '\V'.phsUser.'\_.\{-}'.pheUser
" If we didn't find any placeholders return quietly.
if !search(searchString, flags)
return
endif
" Open any closed folds and make this part of the text visible.
normal! zv
" We are at the starting placeholder. Start visual mode.
normal! v
" Calculate if we have an empty placeholder. It is empty if both
" placeholders appear one after the other.
" Check also whether the empty placeholder ends at the end of the line.
let curline = strpart(getline('.'), col('.')-1)
let phUser = phsUser.pheUser
let placeHolderEmpty = (strpart(curline,0,strlen(phUser)) ==# phUser)
let placeHolderEOL = (curline ==# phUser)
" Search for the end placeholder and position the cursor.
call search(searchString, 'ce')
" If we are selecting in exclusive mode, then we need to move one step to
" the right
if &selection == 'exclusive'
normal! l
endif
" Now either goto insert mode, visual mode or select mode.
if placeHolderEmpty && g:Imap_DeleteEmptyPlaceHolders
" Delete the empty placeholder into the blackhole.
normal! "_d
" Start insert mode. If the placeholder was at the end of the line, use
" startinsert! (equivalent to 'A'), otherwise startinsert (equiv. 'i')
if placeHolderEOL
startinsert!
else
startinsert
endif
else
if g:Imap_GoToSelectMode
" Go to select mode
execute "normal! \<C-g>"
else
" Do not go to select mode
endif
endif
endfunction
" }}}
" Maps for IMAP_Jumpfunc {{{
"
" These mappings use <Plug> and thus provide for easy user customization. When
" the user wants to map some other key to jump forward, he can do for
" instance:
" nmap ,f <plug>IMAP_JumpForward
" etc.
" jumping forward and back in insert mode.
inoremap <silent> <Plug>IMAP_JumpForward <C-\><C-N>:call IMAP_Jumpfunc('', 0)<CR>
inoremap <silent> <Plug>IMAP_JumpBack <C-\><C-N>:call IMAP_Jumpfunc('b', 0)<CR>
" jumping in normal mode
nnoremap <silent> <Plug>IMAP_JumpForward :call IMAP_Jumpfunc('', 0)<CR>
nnoremap <silent> <Plug>IMAP_JumpBack :call IMAP_Jumpfunc('b', 0)<CR>
" deleting the present selection and then jumping forward.
vnoremap <silent> <Plug>IMAP_DeleteAndJumpForward "_<Del>:call IMAP_Jumpfunc('', 0)<CR>
vnoremap <silent> <Plug>IMAP_DeleteAndJumpBack "_<Del>:call IMAP_Jumpfunc('b', 0)<CR>
" jumping forward without deleting present selection.
vnoremap <silent> <Plug>IMAP_JumpForward <C-\><C-N>:call IMAP_Jumpfunc('', 0)<CR>
vnoremap <silent> <Plug>IMAP_JumpBack <C-\><C-N>`<:call IMAP_Jumpfunc('b', 0)<CR>
" }}}
" Default maps for IMAP_Jumpfunc {{{
" map only if there is no mapping already. allows for user customization.
" NOTE: Default mappings for jumping to the previous placeholder are not
" provided. It is assumed that if the user will create such mappings
" hself if e so desires.
if !hasmapto('<Plug>IMAP_JumpForward', 'i')
imap <C-J> <Plug>IMAP_JumpForward
endif
if !hasmapto('<Plug>IMAP_JumpForward', 'n')
nmap <C-J> <Plug>IMAP_JumpForward
endif
if exists('g:Imap_StickyPlaceHolders') && g:Imap_StickyPlaceHolders
if !hasmapto('<Plug>IMAP_JumpForward', 'v')
vmap <C-J> <Plug>IMAP_JumpForward
endif
else
if !hasmapto('<Plug>IMAP_DeleteAndJumpForward', 'v')
vmap <C-J> <Plug>IMAP_DeleteAndJumpForward
endif
endif
" }}}
" ==============================================================================
" helper functions
" ==============================================================================
" s:Hash: Return a version of a string that can be used as part of a variable" {{{
" name.
" Converts every non alphanumeric character into _{ascii}_ where {ascii} is
" the ASCII code for that character...
fun! s:Hash(text)
return substitute(a:text, '\([^[:alnum:]]\)',
\ '\="_".char2nr(submatch(1))."_"', 'g')
endfun
"" }}}
" s:IMAP_add_imap() Adds the imap for IMAP {{{
function! s:IMAP_add_imap( lastLHSChar, buffer )
if a:lastLHSChar == ' '
for lastLHSChar in ['<space>', '<s-space>', '<c-space>', '<cs-space>']
call s:IMAP_add_imap( lastLHSChar, a:buffer )
endfor
else
if a:buffer =~# '<buffer>'
if !exists('b:IMAP_imaps')
let b:IMAP_imaps = []
endif
if index(b:IMAP_imaps, a:lastLHSChar) < 0
call add(b:IMAP_imaps, a:lastLHSChar )
endif
endif
exe 'inoremap <silent>' . a:buffer
\ escape(a:lastLHSChar, '|')
\ '<C-r>=<SID>LookupCharacter("' .
\ escape(a:lastLHSChar, '\|"') .
\ '")<CR>'
endif
endfunction
" }}}
" s:IMAP_rm_imap() Removes the imap for IMAP {{{
function! s:IMAP_rm_imap( lastLHSChar, buffer )
if a:lastLHSChar == ' '
for lastLHSChar in ['<space>', '<s-space>', '<c-space>', '<cs-space>']
call s:IMAP_rm_imap( lastLHSChar, a:buffer )
endfor
else
if a:buffer =~# '<buffer>' && exists('b:IMAP_imaps')
let idx = index(b:IMAP_imaps, a:lastLHSChar)
if idx >= 0
call remove(b:IMAP_imaps, idx)
endif
endif
exe 'iunmap <silent>' . a:buffer escape(a:lastLHSChar, '|')
endif
endfunction
" }}}
" IMAP_GetPlaceHolderStart and IMAP_GetPlaceHolderEnd: "{{{
" return the buffer local placeholder variables, or the global one, or the default.
function! IMAP_GetPlaceHolderStart()
if exists("b:Imap_PlaceHolderStart") && strlen(b:Imap_PlaceHolderEnd)
return b:Imap_PlaceHolderStart
elseif exists("g:Imap_PlaceHolderStart") && strlen(g:Imap_PlaceHolderEnd)
return g:Imap_PlaceHolderStart
else
return "<+"
endfun
function! IMAP_GetPlaceHolderEnd()
if exists("b:Imap_PlaceHolderEnd") && strlen(b:Imap_PlaceHolderEnd)
return b:Imap_PlaceHolderEnd
elseif exists("g:Imap_PlaceHolderEnd") && strlen(g:Imap_PlaceHolderEnd)
return g:Imap_PlaceHolderEnd
else
return "+>"
endfun
" }}}
" IMAP_Debug: interface to Tex_Debug if available, otherwise emulate it {{{
" Description:
" Do not want a memory leak! Set this to zero so that imaps always
" starts out in a non-debugging mode.
if !exists('g:Imap_Debug')
let g:Imap_Debug = 0
endif
function! IMAP_Debug(string, pattern)
if !g:Imap_Debug
return
endif
if exists('*Tex_Debug')
call Tex_Debug(a:string, a:pattern)
else
if !exists('s:debug_'.a:pattern)
let s:debug_{a:pattern} = a:string
else
let s:debug_{a:pattern} = s:debug_{a:pattern}.a:string
endif
endif
endfunction " }}}
" IMAP_DebugClear: interface to Tex_DebugClear if avaialable, otherwise emulate it {{{
" Description:
function! IMAP_DebugClear(pattern)
if exists('*Tex_DebugClear')
call Tex_DebugClear(a:pattern)
else
let s:debug_{a:pattern} = ''
endif
endfunction " }}}
" IMAP_PrintDebug: interface to Tex_DebugPrint if avaialable, otherwise emulate it {{{
" Description:
function! IMAP_PrintDebug(pattern)
if exists('*Tex_PrintDebug')
call Tex_PrintDebug(a:pattern)
else
if exists('s:debug_'.a:pattern)
echo s:debug_{a:pattern}
endif
endif
endfunction " }}}
" IMAP_Mark: Save the cursor position (if a:action == 'set') in a" {{{
" script-local variable; restore this position if a:action == 'go'.
let s:Mark = "(0,0)"
let s:initBlanks = ''
function! IMAP_Mark(action)
if a:action == 'set'
let s:Mark = "(" . line(".") . "," . col(".") . ")"
let s:initBlanks = matchstr(getline('.'), '^\s*')
elseif a:action == 'go'
execute "call cursor" s:Mark
let blanksNow = matchstr(getline('.'), '^\s*')
if strlen(blanksNow) > strlen(s:initBlanks)
execute 'silent! normal! '.(strlen(blanksNow) - strlen(s:initBlanks)).'l'
elseif strlen(blanksNow) < strlen(s:initBlanks)
execute 'silent! normal! '.(strlen(s:initBlanks) - strlen(blanksNow)).'h'
endif
endif
endfunction "" }}}
" IMAP_GetVal: gets the value of a variable {{{
" Description: first checks window local, then buffer local etc.
function! IMAP_GetVal(name, ...)
if a:0 > 0
let default = a:1
else
let default = ''
endif
if exists('w:'.a:name)
return w:{a:name}
elseif exists('b:'.a:name)
return b:{a:name}
elseif exists('g:'.a:name)
return g:{a:name}
else
return default
endif
endfunction " }}}
" s:MultiByteStrlen: Same as strlen() but counts multibyte characters {{{
" instead of bytes.
function! s:MultiByteStrlen(str)
return strlen(substitute(a:str, ".", "x", "g"))
endfunction " }}}
" s:MultiByteLastCharacter: Return last multibyte characters {{{
function! s:MultiByteLastCharacter(str)
return matchstr(a:str, ".$")
endfunction " }}}
let &cpo = s:save_cpo
" vim:ft=vim:ts=4:sw=4:noet:fdm=marker:commentstring=\"\ %s:nowrap

View File

@@ -0,0 +1,154 @@
" File: remoteOpen.vim
" Author: Srinath Avadhanula <srinath AT fastmail DOT fm>
"
" Description:
" Often times, an external program needs to open a file in gvim from the
" command line. However, it will not know if the file is already opened in a
" previous vim session. It is not sufficient to simply specify
"
" gvim --remote-silent <filename>
"
" because this simply opens up <filename> in the first remote gvim session it
" sees. This script provides a command RemoteOpen which is meant to be used
" from the command line as follows:
"
" gvim -c ":RemoteOpen +<lnum> <filename>"
"
" where <lnum> is the line-number you wish <filename> to open to. What will
" happen is that a new gvim will start up and enquire from all previous
" sessions if <filename> is already open in any of them. If it is, then it
" will edit the file in that session and bring it to the foreground and itself
" quit. Otherwise, it will not quit and instead open up the file for editing
" at <lnum>.
"
" This was mainly created to be used with Yap (the dvi previewer in miktex),
" so you can specify the program for "inverse search" as specified above.
" This ensures that the inverse search uses the correct gvim each time.
"
" Ofcourse, this requires vim with +clientserver. If not, then RemoteOpen just
" opens in the present session.
if exists('b:suppress_latex_suite') && b:suppress_latex_suite == 1
finish
endif
" Enclose <args> in single quotes so it can be passed as a function argument.
com! -nargs=1 RemoteOpen :call RemoteOpen('<args>')
com! -nargs=? RemoteInsert :call RemoteInsert('<args>')
" RemoteOpen: open a file remotely (if possible) {{{
" Description: checks all open vim windows to see if this file has been opened
" anywhere and if so, opens it there instead of in this session.
function! RemoteOpen(arglist)
" First construct line number and filename from argument. a:arglist is of
" the form:
" +10 c:\path\to\file
" or just
" c:\path\to\file
if a:arglist =~ '^\s*+\d\+'
let linenum = matchstr(a:arglist, '^\s*+\zs\d\+\ze')
let filename = matchstr(a:arglist, '^\s*+\d\+\s*\zs.*\ze')
else
let linenum = 1
let filename = matchstr(a:arglist, '^\s*\zs.*\ze')
endif
let filename = escape(filename, ' ')
if exists('*Tex_Debug')
call Tex_Debug("linenum = ".linenum.', filename = '.filename, "RemoteOpen")
endif
" If there is no clientserver functionality, then just open in the present
" session and return
if !has('clientserver')
if exists('*Tex_Debug')
call Tex_Debug("-clientserver, opening locally and returning", "RemoteOpen")
endif
exec "e ".filename
exec linenum
normal! zv
return
endif
" Otherwise, loop through all available servers
let servers = split(serverlist(), '\n')
let targetServer = ''
for server in servers
" Find out if there was any server which was used by remoteOpen before
" this. If a new gvim session was ever started via remoteOpen, then
" g:Remote_Server will be set.
if remote_expr(server, 'exists("g:Remote_Server")')
let targetServer = server
endif
" Ask each server if that file is being edited by them.
let bufnum = remote_expr(server, "bufnr('".filename."')")
" If it is...
if bufnum != -1
" ask the server to edit that file and come to the foreground.
" set a variable g:Remote_Server to indicate that this server
" session has at least one file opened via RemoteOpen
let targetServer = server
break
end
endfor
" If there are no servers, open file locally.
if targetServer == ''
if exists('*Tex_Debug')
call Tex_Debug("no open servers, opening locally", "RemoteOpen")
endif
exec "e ".filename
exec linenum
let g:Remote_Server = 1
normal! zv
return
endif
" If none of the servers have the file open, then open this file in the
" first server. This has the advantage if yap tries to make vim open
" multiple vims, then at least they will all be opened by the same gvim
" server.
call remote_send(targetServer,
\ "\<C-\>\<C-n>".
\ ":let g:Remote_Server = 1\<CR>".
\ ":drop ".filename."\<CR>".
\ ":".linenum."\<CR>zv"
\ )
call remote_foreground(targetServer)
" quit this vim session
if v:servername != targetServer
q
endif
endfunction " }}}
" RemoteInsert: inserts a \cite'ation remotely (if possible) {{{
" Description:
function! RemoteInsert(...)
let citation = matchstr(argv(0), "\\[InsText('.cite{\\zs.\\{-}\\ze}');\\]")
if citation == ""
q
endif
" Otherwise, loop through all available servers
let servers = split(serverlist(), '\n')
let targetServer = v:servername
for server in servers
if remote_expr(server, 'exists("g:Remote_WaitingForCite")')
call remote_send(server, citation . "\<CR>")
call remote_foreground(server)
if v:servername != server
q
else
return
endif
endif
endfor
q
endfunction " }}}
" vim:ft=vim:ts=4:sw=4:noet:fdm=marker:commentstring=\"\ %s:nowrap