1294 lines
56 KiB
VimL
1294 lines
56 KiB
VimL
"=============================================================================
|
|
" File: project.vim
|
|
" Author: Aric Blumer (Aric.Blumer at aricvim@charter.net)
|
|
" Last Change: Fri 13 Oct 2006 09:47:08 AM EDT
|
|
" Version: 1.4.1
|
|
"=============================================================================
|
|
" See documentation in accompanying help file
|
|
" You may use this code in whatever way you see fit.
|
|
|
|
if exists('loaded_project') || &cp
|
|
finish
|
|
endif
|
|
let loaded_project=1
|
|
|
|
function! s:Project(filename) " <<<
|
|
" Initialization <<<
|
|
if exists("g:proj_running")
|
|
if strlen(a:filename) != 0
|
|
call confirm('Project already loaded; ignoring filename "'.a:filename."\".\n".'See ":help project-invoking" for information about changing project files.', "&OK", 1)
|
|
endif
|
|
let filename=bufname(g:proj_running)
|
|
else
|
|
if strlen(a:filename) == 0
|
|
let filename ='~/.vimprojects' " Default project filename
|
|
else
|
|
let filename = a:filename
|
|
endif
|
|
endif
|
|
if !exists('g:proj_window_width')
|
|
let g:proj_window_width=24 " Default project window width
|
|
endif
|
|
if !exists('g:proj_window_increment')
|
|
let g:proj_window_increment=100 " Project Window width increment
|
|
endif
|
|
if !exists('g:proj_flags')
|
|
if has("win32") || has("mac")
|
|
let g:proj_flags='imst' " Project default flags for windows/mac
|
|
else
|
|
let g:proj_flags='imstb' " Project default flags for everything else
|
|
endif
|
|
endif
|
|
if !exists("g:proj_running") || (bufwinnr(g:proj_running) == -1) " Open the Project Window
|
|
exec 'silent vertical new '.filename
|
|
if match(g:proj_flags, '\CF') == -1 " We're floating
|
|
silent! wincmd H
|
|
exec 'vertical resize '.g:proj_window_width
|
|
endif
|
|
setlocal nomodeline
|
|
else
|
|
silent! 99wincmd h
|
|
if bufwinnr(g:proj_running) == -1
|
|
vertical split
|
|
let v:errmsg="nothing"
|
|
silent! bnext
|
|
if 'nothing' != v:errmsg
|
|
enew
|
|
endif
|
|
endif
|
|
return
|
|
endif
|
|
" Process the flags
|
|
let b:proj_cd_cmd='cd'
|
|
if match(g:proj_flags, '\Cl') != -1
|
|
let b:proj_cd_cmd = 'lcd'
|
|
endif
|
|
|
|
let b:proj_locate_command='silent! wincmd H'
|
|
let b:proj_resize_command='exec ''vertical resize ''.g:proj_window_width'
|
|
if match(g:proj_flags, '\CF') != -1 " Set the resize commands to nothing
|
|
let b:proj_locate_command=''
|
|
let b:proj_resize_command=''
|
|
endif
|
|
|
|
let g:proj_last_buffer = -1
|
|
">>>
|
|
" ProjFoldText() <<<
|
|
" The foldtext function for displaying just the description.
|
|
function! ProjFoldText()
|
|
let line=substitute(getline(v:foldstart),'^[ \t#]*\([^=]*\).*', '\1', '')
|
|
let line=strpart(' ', 0, (v:foldlevel - 1)).substitute(line,'\s*{\+\s*', '', '')
|
|
return line
|
|
endfunction ">>>
|
|
" s:DoSetup() <<<
|
|
" Ensure everything is set up
|
|
function! s:DoSetup()
|
|
setlocal foldenable foldmethod=marker foldmarker={,} commentstring=%s foldcolumn=0 nonumber noswapfile shiftwidth=1
|
|
setlocal foldtext=ProjFoldText() nobuflisted nowrap
|
|
setlocal winwidth=1
|
|
if match(g:proj_flags, '\Cn') != -1
|
|
setlocal number
|
|
endif
|
|
endfunction ">>>
|
|
call s:DoSetup()
|
|
" Syntax Stuff <<<
|
|
if match(g:proj_flags, '\Cs')!=-1 && has('syntax') && exists('g:syntax_on') && !has('syntax_items')
|
|
syntax match projectDescriptionDir '^\s*.\{-}=\s*\(\\ \|\f\|:\|"\)\+' contains=projectDescription,projectWhiteError
|
|
syntax match projectDescription '\<.\{-}='he=e-1,me=e-1 contained nextgroup=projectDirectory contains=projectWhiteError
|
|
syntax match projectDescription '{\|}'
|
|
syntax match projectDirectory '=\(\\ \|\f\|:\)\+' contained
|
|
syntax match projectDirectory '=".\{-}"' contained
|
|
syntax match projectScriptinout '\<in\s*=\s*\(\\ \|\f\|:\|"\)\+' contains=projectDescription,projectWhiteError
|
|
syntax match projectScriptinout '\<out\s*=\s*\(\\ \|\f\|:\|"\)\+' contains=projectDescription,projectWhiteError
|
|
syntax match projectComment '#.*'
|
|
syntax match projectCD '\<CD\s*=\s*\(\\ \|\f\|:\|"\)\+' contains=projectDescription,projectWhiteError
|
|
syntax match projectFilterEntry '\<filter\s*=.*"' contains=projectWhiteError,projectFilterError,projectFilter,projectFilterRegexp
|
|
syntax match projectFilter '\<filter='he=e-1,me=e-1 contained nextgroup=projectFilterRegexp,projectFilterError,projectWhiteError
|
|
syntax match projectFlagsEntry '\<flags\s*=\( \|[^ ]*\)' contains=projectFlags,projectWhiteError
|
|
syntax match projectFlags '\<flags' contained nextgroup=projectFlagsValues,projectWhiteError
|
|
syntax match projectFlagsValues '=[^ ]* 'hs=s+1,me=e-1 contained contains=projectFlagsError
|
|
syntax match projectFlagsError '[^rtTsSwl= ]\+' contained
|
|
syntax match projectWhiteError '=\s\+'hs=s+1 contained
|
|
syntax match projectWhiteError '\s\+='he=e-1 contained
|
|
syntax match projectFilterError '=[^"]'hs=s+1 contained
|
|
syntax match projectFilterRegexp '=".*"'hs=s+1 contained
|
|
syntax match projectFoldText '^[^=]\+{'
|
|
|
|
highlight def link projectDescription Identifier
|
|
highlight def link projectScriptinout Identifier
|
|
highlight def link projectFoldText Identifier
|
|
highlight def link projectComment Comment
|
|
highlight def link projectFilter Identifier
|
|
highlight def link projectFlags Identifier
|
|
highlight def link projectDirectory Constant
|
|
highlight def link projectFilterRegexp String
|
|
highlight def link projectFlagsValues String
|
|
highlight def link projectWhiteError Error
|
|
highlight def link projectFlagsError Error
|
|
highlight def link projectFilterError Error
|
|
endif ">>>
|
|
" s:SortR(start, end) <<<
|
|
" Sort lines. SortR() is called recursively.
|
|
" from ":help eval-examples" by Robert Webb, slightly modified
|
|
function! s:SortR(start, end)
|
|
if (a:start >= a:end)
|
|
return
|
|
endif
|
|
let partition = a:start - 1
|
|
let middle = partition
|
|
let partStr = getline((a:start + a:end) / 2)
|
|
let i = a:start
|
|
while (i <= a:end)
|
|
let str = getline(i)
|
|
if str < partStr
|
|
let result = -1
|
|
elseif str > partStr
|
|
let result = 1
|
|
else
|
|
let result = 0
|
|
endif
|
|
if (result <= 0)
|
|
let partition = partition + 1
|
|
if (result == 0)
|
|
let middle = partition
|
|
endif
|
|
if (i != partition)
|
|
let str2 = getline(partition)
|
|
call setline(i, str2)
|
|
call setline(partition, str)
|
|
endif
|
|
endif
|
|
let i = i + 1
|
|
endwhile
|
|
if (middle != partition)
|
|
let str = getline(middle)
|
|
let str2 = getline(partition)
|
|
call setline(middle, str2)
|
|
call setline(partition, str)
|
|
endif
|
|
call s:SortR(a:start, partition - 1)
|
|
call s:SortR(partition + 1, a:end)
|
|
endfunc ">>>
|
|
" s:IsAbsolutePath(path) <<<
|
|
" Returns true if filename has an absolute path.
|
|
function! s:IsAbsolutePath(path)
|
|
if a:path =~ '^ftp:' || a:path =~ '^rcp:' || a:path =~ '^scp:' || a:path =~ '^http:'
|
|
return 2
|
|
endif
|
|
if a:path =~ '\$'
|
|
let path=expand(a:path) " Expand any environment variables that might be in the path
|
|
else
|
|
let path=a:path
|
|
endif
|
|
if path[0] == '/' || path[0] == '~' || path[0] == '\\' || path[1] == ':'
|
|
return 1
|
|
endif
|
|
return 0
|
|
endfunction " >>>
|
|
" s:DoSetupAndSplit() <<<
|
|
" Call DoSetup to ensure the settings are correct. Split to the next
|
|
" file.
|
|
function! s:DoSetupAndSplit()
|
|
call s:DoSetup() " Ensure that all the settings are right
|
|
let n = winnr() " Determine if there is a CTRL_W-p window
|
|
silent! wincmd p
|
|
if n == winnr()
|
|
silent! wincmd l
|
|
endif
|
|
if n == winnr()
|
|
" If n == winnr(), then there is no CTRL_W-p window
|
|
" So we have to create a new one
|
|
if bufnr('%') == g:proj_running
|
|
exec 'silent vertical new'
|
|
else
|
|
exec 'silent vertical split | silent! bnext'
|
|
endif
|
|
wincmd p " Go back to the Project Window and ensure it is the right width
|
|
exec b:proj_locate_command
|
|
exec b:proj_resize_command
|
|
wincmd p
|
|
endif
|
|
endfunction ">>>
|
|
" s:DoSetupAndSplit_au() <<<
|
|
" Same as above but ensure that the Project window is the current
|
|
" window. Only called from an autocommand
|
|
function! s:DoSetupAndSplit_au()
|
|
if winbufnr(0) != g:proj_running
|
|
return
|
|
endif
|
|
call s:DoSetup() " Ensure that all the settings are right
|
|
if winbufnr(2) == -1 " We're the only window right now.
|
|
exec 'silent vertical split | bnext'
|
|
if bufnr('%') == g:proj_running
|
|
enew
|
|
endif
|
|
if bufnr('%') == g:proj_last_buffer | bnext | bprev | bnext | endif
|
|
wincmd p " Go back to the Project Window and ensure it is the right width
|
|
exec b:proj_locate_command
|
|
exec b:proj_resize_command
|
|
elseif(winnr() != 1)
|
|
exec b:proj_locate_command
|
|
exec b:proj_resize_command
|
|
endif
|
|
endfunction
|
|
function! s:RecordPrevBuffer_au()
|
|
let g:proj_last_buffer = bufnr('%')
|
|
endfunction ">>>
|
|
" s:RecursivelyConstructDirectives(lineno) <<<
|
|
" Construct the inherited directives
|
|
function! s:RecursivelyConstructDirectives(lineno)
|
|
let lineno=s:FindFoldTop(a:lineno)
|
|
let foldlineno = lineno
|
|
let foldlev=foldlevel(lineno)
|
|
let parent_infoline = ''
|
|
if foldlev > 1
|
|
while foldlevel(lineno) >= foldlev " Go to parent fold
|
|
if lineno < 1
|
|
echoerr 'Some kind of fold error. Check your syntax.'
|
|
return
|
|
endif
|
|
let lineno = lineno - 1
|
|
endwhile
|
|
let parent_infoline = s:RecursivelyConstructDirectives(lineno)
|
|
endif
|
|
let parent_home = s:GetHome(parent_infoline, '')
|
|
let parent_c_d = s:GetCd(parent_infoline, parent_home)
|
|
let parent_scriptin = s:GetScriptin(parent_infoline, parent_home)
|
|
let parent_scriptout = s:GetScriptout(parent_infoline, parent_home)
|
|
let parent_filter = s:GetFilter(parent_infoline, '*')
|
|
let infoline = getline(foldlineno)
|
|
" Extract the home directory of this fold
|
|
let home=s:GetHome(infoline, parent_home)
|
|
if home != ''
|
|
if (foldlevel(foldlineno) == 1) && !s:IsAbsolutePath(home)
|
|
call confirm('Outermost Project Fold must have absolute path! Or perhaps the path does not exist.', "&OK", 1)
|
|
let home = '~' " Some 'reasonable' value
|
|
endif
|
|
endif
|
|
" Extract any CD information
|
|
let c_d = s:GetCd(infoline, home)
|
|
if c_d != ''
|
|
if (foldlevel(foldlineno) == 1) && !s:IsAbsolutePath(c_d)
|
|
call confirm('Outermost Project Fold must have absolute CD path! Or perhaps the path does not exist.', "&OK", 1)
|
|
let c_d = '.' " Some 'reasonable' value
|
|
endif
|
|
else
|
|
let c_d=parent_c_d
|
|
endif
|
|
" Extract scriptin
|
|
let scriptin = s:GetScriptin(infoline, home)
|
|
if scriptin == ''
|
|
let scriptin = parent_scriptin
|
|
endif
|
|
" Extract scriptout
|
|
let scriptout = s:GetScriptout(infoline, home)
|
|
if scriptout == ''
|
|
let scriptout = parent_scriptout
|
|
endif
|
|
" Extract filter
|
|
let filter = s:GetFilter(infoline, parent_filter)
|
|
if filter == '' | let filter = parent_filter | endif
|
|
return s:ConstructInfo(home, c_d, scriptin, scriptout, '', filter)
|
|
endfunction ">>>
|
|
" s:ConstructInfo(home, c_d, scriptin, scriptout, flags, filter) <<<
|
|
function! s:ConstructInfo(home, c_d, scriptin, scriptout, flags, filter)
|
|
let retval='Directory='.a:home
|
|
if a:c_d[0] != ''
|
|
let retval=retval.' CD='.a:c_d
|
|
endif
|
|
if a:scriptin[0] != ''
|
|
let retval=retval.' in='.a:scriptin
|
|
endif
|
|
if a:scriptout[0] != ''
|
|
let retval=retval.' out='.a:scriptout
|
|
endif
|
|
if a:filter[0] != ''
|
|
let retval=retval.' filter="'.a:filter.'"'
|
|
endif
|
|
return retval
|
|
endfunction ">>>
|
|
" s:OpenEntry(line, precmd, editcmd) <<<
|
|
" Get the filename under the cursor, and open a window with it.
|
|
function! s:OpenEntry(line, precmd, editcmd, dir)
|
|
silent exec a:precmd
|
|
if (a:editcmd[0] != '')
|
|
if a:dir
|
|
let fname='.'
|
|
else
|
|
if (foldlevel(a:line) == 0) && (a:editcmd[0] != '')
|
|
return 0 " If we're outside a fold, do nothing
|
|
endif
|
|
let fname=substitute(getline(a:line), '\s*#.*', '', '') " Get rid of comments and whitespace before comment
|
|
let fname=substitute(fname, '^\s*\(.*\)', '\1', '') " Get rid of leading whitespace
|
|
if strlen(fname) == 0
|
|
return 0 " The line is blank. Do nothing.
|
|
endif
|
|
endif
|
|
else
|
|
let fname='.'
|
|
endif
|
|
let infoline = s:RecursivelyConstructDirectives(a:line)
|
|
let retval=s:OpenEntry2(a:line, infoline, fname, a:editcmd)
|
|
call s:DisplayInfo()
|
|
return retval
|
|
endfunction
|
|
">>>
|
|
" s:OpenEntry2(line, infoline, precmd, editcmd) <<<
|
|
" Get the filename under the cursor, and open a window with it.
|
|
function! s:OpenEntry2(line, infoline, fname, editcmd)
|
|
let fname=escape(a:fname, ' %#') " Thanks to Thomas Link for cluing me in on % and #
|
|
let home=s:GetHome(a:infoline, '').'/'
|
|
if home=='/'
|
|
echoerr 'Project structure error. Check your syntax.'
|
|
return
|
|
endif
|
|
"Save the cd command
|
|
let cd_cmd = b:proj_cd_cmd
|
|
if a:editcmd[0] != '' " If editcmd is '', then just set up the environment in the Project Window
|
|
call s:DoSetupAndSplit()
|
|
" If it is an absolute path, don't prepend home
|
|
if !s:IsAbsolutePath(fname)
|
|
let fname=home.fname
|
|
endif
|
|
if s:IsAbsolutePath(fname) == 2
|
|
exec a:editcmd.' '.fname
|
|
else
|
|
silent exec 'silent '.a:editcmd.' '.fname
|
|
endif
|
|
else " only happens in the Project File
|
|
exec 'au! BufEnter,BufLeave '.expand('%:p')
|
|
endif
|
|
" Extract any CD information
|
|
let c_d = s:GetCd(a:infoline, home)
|
|
if c_d != '' && (s:IsAbsolutePath(home) != 2)
|
|
if match(g:proj_flags, '\CL') != -1
|
|
call s:SetupAutoCommand(c_d)
|
|
endif
|
|
if !isdirectory(glob(c_d))
|
|
call confirm("From this fold's entry,\nCD=".'"'.c_d.'" is not a valid directory.', "&OK", 1)
|
|
else
|
|
silent exec cd_cmd.' '.c_d
|
|
endif
|
|
endif
|
|
" Extract any scriptin information
|
|
let scriptin = s:GetScriptin(a:infoline, home)
|
|
if scriptin != ''
|
|
if !filereadable(glob(scriptin))
|
|
call confirm('"'.scriptin.'" not found. Ignoring.', "&OK", 1)
|
|
else
|
|
call s:SetupScriptAutoCommand('BufEnter', scriptin)
|
|
exec 'source '.scriptin
|
|
endif
|
|
endif
|
|
let scriptout = s:GetScriptout(a:infoline, home)
|
|
if scriptout != ''
|
|
if !filereadable(glob(scriptout))
|
|
call confirm('"'.scriptout.'" not found. Ignoring.', "&OK", 1)
|
|
else
|
|
call s:SetupScriptAutoCommand('BufLeave', scriptout)
|
|
endif
|
|
endif
|
|
return 1
|
|
endfunction
|
|
">>>
|
|
" s:DoFoldOrOpenEntry(cmd0, cmd1) <<<
|
|
" Used for double clicking. If the mouse is on a fold, open/close it. If
|
|
" not, try to open the file.
|
|
function! s:DoFoldOrOpenEntry(cmd0, cmd1)
|
|
if getline('.')=~'{\|}' || foldclosed('.') != -1
|
|
normal! za
|
|
else
|
|
call s:DoEnsurePlacementSize_au()
|
|
call s:OpenEntry(line('.'), a:cmd0, a:cmd1, 0)
|
|
if (match(g:proj_flags, '\Cc') != -1)
|
|
let g:proj_mywinnumber = winbufnr(0)
|
|
Project
|
|
hide
|
|
if(g:proj_mywinnumber != winbufnr(0))
|
|
wincmd p
|
|
endif
|
|
wincmd =
|
|
endif
|
|
endif
|
|
endfunction ">>>
|
|
" s:VimDirListing(filter, padding, separator, filevariable, filecount, dirvariable, dircount) <<<
|
|
function! s:VimDirListing(filter, padding, separator, filevariable, filecount, dirvariable, dircount)
|
|
let end = 0
|
|
let files=''
|
|
let filter = a:filter
|
|
" Chop up the filter
|
|
" Apparently glob() cannot take something like this: glob('*.c *.h')
|
|
let while_var = 1
|
|
while while_var
|
|
let end = stridx(filter, ' ')
|
|
if end == -1
|
|
let end = strlen(filter)
|
|
let while_var = 0
|
|
endif
|
|
let single=glob(strpart(filter, 0, end))
|
|
if strlen(single) != 0
|
|
let files = files.single."\010"
|
|
endif
|
|
let filter = strpart(filter, end + 1)
|
|
endwhile
|
|
" files now contains a list of everything in the directory. We need to
|
|
" weed out the directories.
|
|
let fnames=files
|
|
let {a:filevariable}=''
|
|
let {a:dirvariable}=''
|
|
let {a:filecount}=0
|
|
let {a:dircount}=0
|
|
while strlen(fnames) > 0
|
|
let fname = substitute(fnames, '\(\(\f\|[ :\[\]]\)*\).*', '\1', '')
|
|
let fnames = substitute(fnames, '\(\f\|[ :\[\]]\)*.\(.*\)', '\2', '')
|
|
if isdirectory(glob(fname))
|
|
let {a:dirvariable}={a:dirvariable}.a:padding.fname.a:separator
|
|
let {a:dircount}={a:dircount} + 1
|
|
else
|
|
let {a:filevariable}={a:filevariable}.a:padding.fname.a:separator
|
|
let {a:filecount}={a:filecount} + 1
|
|
endif
|
|
endwhile
|
|
endfunction ">>>
|
|
" s:GenerateEntry(recursive, name, absolute_dir, dir, c_d, filter_directive, filter, foldlev, sort) <<<
|
|
function! s:GenerateEntry(recursive, line, name, absolute_dir, dir, c_d, filter_directive, filter, foldlev, sort)
|
|
let line=a:line
|
|
if a:dir =~ '\\ '
|
|
let dir='"'.substitute(a:dir, '\\ ', ' ', 'g').'"'
|
|
else
|
|
let dir=a:dir
|
|
endif
|
|
let spaces=strpart(' ', 0, a:foldlev)
|
|
let c_d=(strlen(a:c_d) > 0) ? 'CD='.a:c_d.' ' : ''
|
|
let c_d=(strlen(a:filter_directive) > 0) ? c_d.'filter="'.a:filter_directive.'" ': c_d
|
|
call append(line, spaces.'}')
|
|
call append(line, spaces.a:name.'='.dir.' '.c_d.'{')
|
|
if a:recursive
|
|
exec 'cd '.a:absolute_dir
|
|
call s:VimDirListing("*", '', "\010", 'b:files', 'b:filecount', 'b:dirs', 'b:dircount')
|
|
cd -
|
|
let dirs=b:dirs
|
|
let dcount=b:dircount
|
|
unlet b:files b:filecount b:dirs b:dircount
|
|
while dcount > 0
|
|
let dname = substitute(dirs, '\(\( \|\f\|:\)*\).*', '\1', '')
|
|
let edname = escape(dname, ' ')
|
|
let dirs = substitute(dirs, '\( \|\f\|:\)*.\(.*\)', '\2', '')
|
|
let line=s:GenerateEntry(1, line + 1, dname, a:absolute_dir.'/'.edname, edname, '', '', a:filter, a:foldlev+1, a:sort)
|
|
let dcount=dcount-1
|
|
endwhile
|
|
endif
|
|
return line+1
|
|
endfunction " >>>
|
|
" s:DoEntryFromDir(line, name, absolute_dir, dir, c_d, filter_directive, filter, foldlev, sort) <<<
|
|
" Generate the fold from the directory hierarchy (if recursive), then
|
|
" fill it in with RefreshEntriesFromDir()
|
|
function! s:DoEntryFromDir(recursive, line, name, absolute_dir, dir, c_d, filter_directive, filter, foldlev, sort)
|
|
call s:GenerateEntry(a:recursive, a:line, a:name, escape(a:absolute_dir, ' '), escape(a:dir, ' '), escape(a:c_d, ' '), a:filter_directive, a:filter, a:foldlev, a:sort)
|
|
normal! j
|
|
call s:RefreshEntriesFromDir(1)
|
|
endfunction ">>>
|
|
" s:CreateEntriesFromDir(recursive) <<<
|
|
" Prompts user for information and then calls s:DoEntryFromDir()
|
|
function! s:CreateEntriesFromDir(recursive)
|
|
" Save a mark for the current cursor position
|
|
normal! mk
|
|
let line=line('.')
|
|
let name = inputdialog('Enter the Name of the Entry: ')
|
|
if strlen(name) == 0
|
|
return
|
|
endif
|
|
let foldlev=foldlevel(line)
|
|
if (foldclosed(line) != -1) || (getline(line) =~ '}')
|
|
let foldlev=foldlev - 1
|
|
endif
|
|
let absolute = (foldlev <= 0)?'Absolute ': ''
|
|
let home=''
|
|
let filter='*'
|
|
if (match(g:proj_flags, '\Cb') != -1) && has('browse')
|
|
" Note that browse() is inconsistent: On Win32 you can't select a
|
|
" directory, and it gives you a relative path.
|
|
let dir = browse(0, 'Enter the '.absolute.'Directory to Load: ', '', '')
|
|
let dir = fnamemodify(dir, ':p')
|
|
else
|
|
let dir = inputdialog('Enter the '.absolute.'Directory to Load: ', '')
|
|
endif
|
|
if (dir[strlen(dir)-1] == '/') || (dir[strlen(dir)-1] == '\\')
|
|
let dir=strpart(dir, 0, strlen(dir)-1) " Remove trailing / or \
|
|
endif
|
|
let dir = substitute(dir, '^\~', $HOME, 'g')
|
|
if (foldlev > 0)
|
|
let parent_directive=s:RecursivelyConstructDirectives(line)
|
|
let filter = s:GetFilter(parent_directive, '*')
|
|
let home=s:GetHome(parent_directive, '')
|
|
if home[strlen(home)-1] != '/' && home[strlen(home)-1] != '\\'
|
|
let home=home.'/'
|
|
endif
|
|
unlet parent_directive
|
|
if s:IsAbsolutePath(dir)
|
|
" It is not a relative path Try to make it relative
|
|
let hend=matchend(dir, '\C'.glob(home))
|
|
if hend != -1
|
|
let dir=strpart(dir, hend) " The directory can be a relative path
|
|
else
|
|
let home=""
|
|
endif
|
|
endif
|
|
endif
|
|
if strlen(home.dir) == 0
|
|
return
|
|
endif
|
|
if !isdirectory(home.dir)
|
|
if has("unix")
|
|
silent exec '!mkdir '.home.dir.' > /dev/null'
|
|
else
|
|
call confirm('"'.home.dir.'" is not a valid directory.', "&OK", 1)
|
|
return
|
|
endif
|
|
endif
|
|
let c_d = inputdialog('Enter the CD parameter: ', '')
|
|
let filter_directive = inputdialog('Enter the File Filter: ', '')
|
|
if strlen(filter_directive) != 0
|
|
let filter = filter_directive
|
|
endif
|
|
" If I'm on a closed fold, go to the bottom of it
|
|
if foldclosedend(line) != -1
|
|
let line = foldclosedend(line)
|
|
endif
|
|
let foldlev = foldlevel(line)
|
|
" If we're at the end of a fold . . .
|
|
if getline(line) =~ '}'
|
|
let foldlev = foldlev - 1 " . . . decrease the indentation by 1.
|
|
endif
|
|
" Do the work
|
|
call s:DoEntryFromDir(a:recursive, line, name, home.dir, dir, c_d, filter_directive, filter, foldlev, 0)
|
|
" Restore the cursor position
|
|
normal! `k
|
|
endfunction ">>>
|
|
" s:RefreshEntriesFromDir(recursive) <<<
|
|
" Finds metadata at the top of the fold, and then replaces all files
|
|
" with the contents of the directory. Works recursively if recursive is 1.
|
|
function! s:RefreshEntriesFromDir(recursive)
|
|
if foldlevel('.') == 0
|
|
echo 'Nothing to refresh.'
|
|
return
|
|
endif
|
|
" Open the fold.
|
|
if getline('.') =~ '}'
|
|
normal! zo[z
|
|
else
|
|
normal! zo]z[z
|
|
endif
|
|
let just_a_fold=0
|
|
let infoline = s:RecursivelyConstructDirectives(line('.'))
|
|
let immediate_infoline = getline('.')
|
|
if strlen(substitute(immediate_infoline, '[^=]*=\(\(\f\|:\|\\ \)*\).*', '\1', '')) == strlen(immediate_infoline)
|
|
let just_a_fold = 1
|
|
endif
|
|
" Extract the home directory of the fold
|
|
let home = s:GetHome(infoline, '')
|
|
if home == ''
|
|
" No Match. This means that this is just a label with no
|
|
" directory entry.
|
|
if a:recursive == 0
|
|
return " We're done--nothing to do
|
|
endif
|
|
" Mark that it is just a fold, so later we don't delete filenames
|
|
" that aren't there.
|
|
let just_a_fold = 1
|
|
endif
|
|
if just_a_fold == 0
|
|
" Extract the filter between quotes (we don't care what CD is).
|
|
let filter = s:GetFilter(infoline, '*')
|
|
" Extract the description (name) of the fold
|
|
let name = substitute(infoline, '^[#\t ]*\([^=]*\)=.*', '\1', '')
|
|
if strlen(name) == strlen(infoline)
|
|
return " If there's no name, we're done.
|
|
endif
|
|
if (home == '') || (name == '')
|
|
return
|
|
endif
|
|
" Extract the flags
|
|
let flags = s:GetFlags(immediate_infoline)
|
|
let sort = (match(g:proj_flags, '\CS') != -1)
|
|
if flags != ''
|
|
if match(flags, '\Cr') != -1
|
|
" If the flags do not contain r (refresh), then treat it just
|
|
" like a fold
|
|
let just_a_fold = 1
|
|
endif
|
|
if match(flags, '\CS') != -1
|
|
let sort = 1
|
|
endif
|
|
if match(flags, '\Cs') != -1
|
|
let sort = 0
|
|
endif
|
|
else
|
|
let flags=''
|
|
endif
|
|
endif
|
|
" Move to the first non-fold boundary line
|
|
normal! j
|
|
" Delete filenames until we reach the end of the fold
|
|
while getline('.') !~ '}'
|
|
if line('.') == line('$')
|
|
break
|
|
endif
|
|
if getline('.') !~ '{'
|
|
" We haven't reached a sub-fold, so delete what's there.
|
|
if (just_a_fold == 0) && (getline('.') !~ '^\s*#') && (getline('.') !~ '#.*pragma keep')
|
|
d _
|
|
else
|
|
" Skip lines only in a fold and comment lines
|
|
normal! j
|
|
endif
|
|
else
|
|
" We have reached a sub-fold. If we're doing recursive, then
|
|
" call this function again. If not, find the end of the fold.
|
|
if a:recursive == 1
|
|
call s:RefreshEntriesFromDir(1)
|
|
normal! ]zj
|
|
else
|
|
if foldclosed('.') == -1
|
|
normal! zc
|
|
endif
|
|
normal! j
|
|
endif
|
|
endif
|
|
endwhile
|
|
if just_a_fold == 0
|
|
" We're not just in a fold, and we have deleted all the filenames.
|
|
" Now it is time to regenerate what is in the directory.
|
|
if !isdirectory(glob(home))
|
|
call confirm('"'.home.'" is not a valid directory.', "&OK", 1)
|
|
else
|
|
let foldlev=foldlevel('.')
|
|
" T flag. Thanks Tomas Z.
|
|
if (match(flags, '\Ct') != -1) || ((match(g:proj_flags, '\CT') == -1) && (match(flags, '\CT') == -1))
|
|
" Go to the top of the fold (force other folds to the
|
|
" bottom)
|
|
normal! [z
|
|
normal! j
|
|
" Skip any comments
|
|
while getline('.') =~ '^\s*#'
|
|
normal! j
|
|
endwhile
|
|
endif
|
|
normal! k
|
|
let cwd=getcwd()
|
|
let spaces=strpart(' ', 0, foldlev)
|
|
exec 'cd '.home
|
|
if match(g:proj_flags, '\Ci') != -1
|
|
echon home."\r"
|
|
endif
|
|
call s:VimDirListing(filter, spaces, "\n", 'b:files', 'b:filecount', 'b:dirs', 'b:dircount')
|
|
if b:filecount > 0
|
|
normal! mk
|
|
silent! put =b:files
|
|
normal! `kj
|
|
if sort
|
|
call s:SortR(line('.'), line('.') + b:filecount - 1)
|
|
endif
|
|
else
|
|
normal! j
|
|
endif
|
|
unlet b:files b:filecount b:dirs b:dircount
|
|
exec 'cd '.cwd
|
|
endif
|
|
endif
|
|
" Go to the top of the refreshed fold.
|
|
normal! [z
|
|
endfunction ">>>
|
|
" s:MoveUp() <<<
|
|
" Moves the entity under the cursor up a line.
|
|
function! s:MoveUp()
|
|
let lineno=line('.')
|
|
if lineno == 1
|
|
return
|
|
endif
|
|
let fc=foldclosed('.')
|
|
let a_reg=@a
|
|
if lineno == line('$')
|
|
normal! "add"aP
|
|
else
|
|
normal! "addk"aP
|
|
endif
|
|
let @a=a_reg
|
|
if fc != -1
|
|
normal! zc
|
|
endif
|
|
endfunction ">>>
|
|
" s:MoveDown() <<<
|
|
" Moves the entity under the cursor down a line.
|
|
function! s:MoveDown()
|
|
let fc=foldclosed('.')
|
|
let a_reg=@a
|
|
normal! "add"ap
|
|
let @a=a_reg
|
|
if (fc != -1) && (foldclosed('.') == -1)
|
|
normal! zc
|
|
endif
|
|
endfunction " >>>
|
|
" s:DisplayInfo() <<<
|
|
" Displays filename and current working directory when i (info) is in
|
|
" the flags.
|
|
function! s:DisplayInfo()
|
|
if match(g:proj_flags, '\Ci') != -1
|
|
echo 'file: '.expand('%').', cwd: '.getcwd().', lines: '.line('$')
|
|
endif
|
|
endfunction ">>>
|
|
" s:SetupAutoCommand(cwd) <<<
|
|
" Sets up an autocommand to ensure that the cwd is set to the one
|
|
" desired for the fold regardless. :lcd only does this on a per-window
|
|
" basis, not a per-buffer basis.
|
|
function! s:SetupAutoCommand(cwd)
|
|
if !exists("b:proj_has_autocommand")
|
|
let b:proj_cwd_save = escape(getcwd(), ' ')
|
|
let b:proj_has_autocommand = 1
|
|
let bufname=escape(substitute(expand('%:p', 0), '\\', '/', 'g'), ' ')
|
|
exec 'au BufEnter '.bufname." let b:proj_cwd_save=escape(getcwd(), ' ') | cd ".a:cwd
|
|
exec 'au BufLeave '.bufname.' exec "cd ".b:proj_cwd_save'
|
|
exec 'au BufWipeout '.bufname.' au! * '.bufname
|
|
endif
|
|
endfunction ">>>
|
|
" s:SetupScriptAutoCommand(bufcmd, script) <<<
|
|
" Sets up an autocommand to run the scriptin script.
|
|
function! s:SetupScriptAutoCommand(bufcmd, script)
|
|
if !exists("b:proj_has_".a:bufcmd)
|
|
let b:proj_has_{a:bufcmd} = 1
|
|
exec 'au '.a:bufcmd.' '.escape(substitute(expand('%:p', 0), '\\', '/', 'g'), ' ').' source '.a:script
|
|
endif
|
|
endfunction " >>>
|
|
" s:DoEnsurePlacementSize_au() <<<
|
|
" Ensure that the Project window is on the left of the window and has
|
|
" the correct size. Only called from an autocommand
|
|
function! s:DoEnsurePlacementSize_au()
|
|
if (winbufnr(0) != g:proj_running) || (winnr() != 1)
|
|
if exists("g:proj_doinghelp")
|
|
if g:proj_doinghelp > 0
|
|
let g:proj_doinghelp = g:proj_doinghelp - 1
|
|
return
|
|
endif
|
|
unlet g:proj_doinghelp
|
|
return
|
|
endif
|
|
exec b:proj_locate_command
|
|
endif
|
|
exec b:proj_resize_command
|
|
endfunction ">>>
|
|
" s:Spawn(number) <<<
|
|
" Spawn an external command on the file
|
|
function! s:Spawn(number)
|
|
echo | if exists("g:proj_run".a:number)
|
|
let fname=getline('.')
|
|
if fname!~'{\|}'
|
|
let fname=substitute(fname, '\s*#.*', '', '')
|
|
let fname=substitute(fname, '^\s*\(.*\)\s*', '\1', '')
|
|
if fname == '' | return | endif
|
|
let parent_infoline = s:RecursivelyConstructDirectives(line('.'))
|
|
let home=expand(s:GetHome(parent_infoline, ''))
|
|
let c_d=expand(s:GetCd(parent_infoline, ''))
|
|
let command=substitute(g:proj_run{a:number}, '%%', "\010", 'g')
|
|
let command=substitute(command, '%f', escape(home.'/'.fname, '\'), 'g')
|
|
let command=substitute(command, '%F', substitute(escape(home.'/'.fname, '\'), ' ', '\\\\ ', 'g'), 'g')
|
|
let command=substitute(command, '%s', escape(home.'/'.fname, '\'), 'g')
|
|
let command=substitute(command, '%n', escape(fname, '\'), 'g')
|
|
let command=substitute(command, '%N', substitute(fname, ' ', '\\\\ ', 'g'), 'g')
|
|
let command=substitute(command, '%h', escape(home, '\'), 'g')
|
|
let command=substitute(command, '%H', substitute(escape(home, '\'), ' ', '\\\\ ', 'g'), 'g')
|
|
if c_d != ''
|
|
if c_d == home
|
|
let percent_r='.'
|
|
else
|
|
let percent_r=substitute(home, escape(c_d.'/', '\'), '', 'g')
|
|
endif
|
|
else
|
|
let percent_r=home
|
|
endif
|
|
let command=substitute(command, '%r', percent_r, 'g')
|
|
let command=substitute(command, '%R', substitute(percent_r, ' ', '\\\\ ', 'g'), 'g')
|
|
let command=substitute(command, '%d', escape(c_d, '\'), 'g')
|
|
let command=substitute(command, '%D', substitute(escape(c_d, '\'), ' ', '\\\\ ', 'g'), 'g')
|
|
let command=substitute(command, "\010", '%', 'g')
|
|
exec command
|
|
endif
|
|
endif
|
|
endfunction ">>>
|
|
" s:ListSpawn(varnamesegment) <<<
|
|
" List external commands
|
|
function! s:ListSpawn(varnamesegment)
|
|
let number = 1
|
|
while number < 10
|
|
if exists("g:proj_run".a:varnamesegment.number)
|
|
echohl LineNr | echo number.':' | echohl None | echon ' '.substitute(escape(g:proj_run{a:varnamesegment}{number}, '\'), "\n", '\\n', 'g')
|
|
else
|
|
echohl LineNr | echo number.':' | echohl None
|
|
endif
|
|
let number=number + 1
|
|
endwhile
|
|
endfunction ">>>
|
|
" s:FindFoldTop(line) <<<
|
|
" Return the line number of the directive line
|
|
function! s:FindFoldTop(line)
|
|
let lineno=a:line
|
|
if getline(lineno) =~ '}'
|
|
let lineno = lineno - 1
|
|
endif
|
|
while getline(lineno) !~ '{' && lineno > 1
|
|
if getline(lineno) =~ '}'
|
|
let lineno=s:FindFoldTop(lineno)
|
|
endif
|
|
let lineno = lineno - 1
|
|
endwhile
|
|
return lineno
|
|
endfunction ">>>
|
|
" s:FindFoldBottom(line) <<<
|
|
" Return the line number of the directive line
|
|
function! s:FindFoldBottom(line)
|
|
let lineno=a:line
|
|
if getline(lineno) =~ '{'
|
|
let lineno=lineno + 1
|
|
endif
|
|
while getline(lineno) !~ '}' && lineno < line('$')
|
|
if getline(lineno) =~ '{'
|
|
let lineno=s:FindFoldBottom(lineno)
|
|
endif
|
|
let lineno = lineno + 1
|
|
endwhile
|
|
return lineno
|
|
endfunction ">>>
|
|
" s:LoadAll(recurse, line) <<<
|
|
" Load all files in a project
|
|
function! s:LoadAll(recurse, line)
|
|
let b:loadcount=0
|
|
function! s:SpawnExec(infoline, fname, lineno, data)
|
|
if s:OpenEntry2(a:lineno, a:infoline, a:fname, 'e')
|
|
wincmd p
|
|
let b:loadcount=b:loadcount+1
|
|
echon b:loadcount."\r"
|
|
if getchar(0) != 0
|
|
let b:stop_everything=1
|
|
endif
|
|
endif
|
|
endfunction
|
|
call Project_ForEach(a:recurse, line('.'), "*<SID>SpawnExec", 0, '^\(.*l\)\@!')
|
|
delfunction s:SpawnExec
|
|
echon b:loadcount." Files Loaded\r"
|
|
unlet b:loadcount
|
|
if exists("b:stop_everything") | unlet b:stop_everything | endif
|
|
endfunction ">>>
|
|
" s:WipeAll(recurse, line) <<<
|
|
" Wipe all files in a project
|
|
function! s:WipeAll(recurse, line)
|
|
let b:wipecount=0
|
|
let b:totalcount=0
|
|
function! s:SpawnExec(home, c_d, fname, lineno, data)
|
|
let fname=escape(a:fname, ' ')
|
|
if s:IsAbsolutePath(fname)
|
|
let fname=fnamemodify(fname, ':n') " :n is coming, won't break anything now
|
|
else
|
|
let fname=fnamemodify(a:home.'/'.fname, ':n') " :n is coming, won't break anything now
|
|
endif
|
|
let b:totalcount=b:totalcount+1
|
|
let fname=substitute(fname, '^\~', $HOME, 'g')
|
|
if bufloaded(substitute(fname, '\\ ', ' ', 'g'))
|
|
if getbufvar(fname.'\>', '&modified') == 1
|
|
exec 'sb '.fname
|
|
wincmd L
|
|
w
|
|
wincmd p
|
|
endif
|
|
let b:wipecount=b:wipecount+1
|
|
exec 'bwipe! '.fname
|
|
endif
|
|
if b:totalcount % 5 == 0
|
|
echon b:wipecount.' of '.b:totalcount."\r"
|
|
redraw
|
|
endif
|
|
if getchar(0) != 0
|
|
let b:stop_everything=1
|
|
endif
|
|
endfunction
|
|
call Project_ForEach(a:recurse, line('.'), "<SID>SpawnExec", 0, '^\(.*w\)\@!')
|
|
delfunction s:SpawnExec
|
|
echon b:wipecount.' of '.b:totalcount." Files Wiped\r"
|
|
unlet b:wipecount b:totalcount
|
|
if exists("b:stop_everything") | unlet b:stop_everything | endif
|
|
endfunction ">>>
|
|
" s:LoadAllSplit(recurse, line) <<<
|
|
" Load all files in a project using split windows.
|
|
" Contributed by A. Harrison
|
|
function! s:LoadAllSplit(recurse, line)
|
|
let b:loadcount=0
|
|
function! s:SpawnExec(infoline, fname, lineno, data)
|
|
let winNr = winnr() "get ProjectWindow number
|
|
if s:OpenEntry2(a:lineno, a:infoline, a:fname, 'sp')
|
|
exec winNr."wincmd w"
|
|
let b:loadcount=b:loadcount+1
|
|
echon b:loadcount."\r"
|
|
if getchar(0) != 0
|
|
let b:stop_everything=1
|
|
endif
|
|
endif
|
|
endfunction
|
|
call Project_ForEach(a:recurse, line('.'), "*<SID>SpawnExec", 0, '^\(.*l\)\@!')
|
|
delfunction s:SpawnExec
|
|
echon b:loadcount." Files Loaded\r"
|
|
unlet b:loadcount
|
|
if exists("b:stop_everything") | unlet b:stop_everything | endif
|
|
endfunction ">>>
|
|
" s:GrepAll(recurse, lineno, pattern) <<<
|
|
" Grep all files in a project, optionally recursively
|
|
function! s:GrepAll(recurse, lineno, pattern)
|
|
cunmap <buffer> help
|
|
let pattern=(a:pattern[0] == '')?input("GREP options and pattern: "):a:pattern
|
|
cnoremap <buffer> help let g:proj_doinghelp = 1<CR>:help
|
|
if pattern[0] == ''
|
|
return
|
|
endif
|
|
let b:escape_spaces=1
|
|
let fnames=Project_GetAllFnames(a:recurse, a:lineno, ' ')
|
|
unlet b:escape_spaces
|
|
cclose " Make sure grep window is closed
|
|
call s:DoSetupAndSplit()
|
|
if match(g:proj_flags, '\Cv') == -1
|
|
silent! exec 'silent! grep '.pattern.' '.fnames
|
|
if v:shell_error != 0
|
|
echo 'GREP error. Perhaps there are too many filenames.'
|
|
else
|
|
copen
|
|
endif
|
|
else
|
|
silent! exec 'silent! vimgrep '.pattern.' '.fnames
|
|
copen
|
|
endif
|
|
endfunction ">>>
|
|
" GetXXX Functions <<<
|
|
function! s:GetHome(info, parent_home)
|
|
" Thanks to Adam Montague for pointing out the need for @ in urls.
|
|
let home=substitute(a:info, '^[^=]*=\(\(\\ \|\f\|:\|@\)\+\).*', '\1', '')
|
|
if strlen(home) == strlen(a:info)
|
|
let home=substitute(a:info, '.\{-}"\(.\{-}\)".*', '\1', '')
|
|
if strlen(home) != strlen(a:info) | let home=escape(home, ' ') | endif
|
|
endif
|
|
if strlen(home) == strlen(a:info)
|
|
let home=a:parent_home
|
|
elseif home=='.'
|
|
let home=a:parent_home
|
|
elseif !s:IsAbsolutePath(home)
|
|
let home=a:parent_home.'/'.home
|
|
endif
|
|
return home
|
|
endfunction
|
|
function! s:GetFilter(info, parent_filter)
|
|
let filter = substitute(a:info, '.*\<filter="\([^"]*\).*', '\1', '')
|
|
if strlen(filter) == strlen(a:info) | let filter = a:parent_filter | endif
|
|
return filter
|
|
endfunction
|
|
function! s:GetCd(info, home)
|
|
let c_d=substitute(a:info, '.*\<CD=\(\(\\ \|\f\|:\)\+\).*', '\1', '')
|
|
if strlen(c_d) == strlen(a:info)
|
|
let c_d=substitute(a:info, '.*\<CD="\(.\{-}\)".*', '\1', '')
|
|
if strlen(c_d) != strlen(a:info) | let c_d=escape(c_d, ' ') | endif
|
|
endif
|
|
if strlen(c_d) == strlen(a:info)
|
|
let c_d=''
|
|
elseif c_d == '.'
|
|
let c_d = a:home
|
|
elseif !s:IsAbsolutePath(c_d)
|
|
let c_d = a:home.'/'.c_d
|
|
endif
|
|
return c_d
|
|
endfunction
|
|
function! s:GetScriptin(info, home)
|
|
let scriptin = substitute(a:info, '.*\<in=\(\(\\ \|\f\|:\)\+\).*', '\1', '')
|
|
if strlen(scriptin) == strlen(a:info)
|
|
let scriptin=substitute(a:info, '.*\<in="\(.\{-}\)".*', '\1', '')
|
|
if strlen(scriptin) != strlen(a:info) | let scriptin=escape(scriptin, ' ') | endif
|
|
endif
|
|
if strlen(scriptin) == strlen(a:info) | let scriptin='' | else
|
|
if !s:IsAbsolutePath(scriptin) | let scriptin=a:home.'/'.scriptin | endif | endif
|
|
return scriptin
|
|
endfunction
|
|
function! s:GetScriptout(info, home)
|
|
let scriptout = substitute(a:info, '.*\<out=\(\(\\ \|\f\|:\)\+\).*', '\1', '')
|
|
if strlen(scriptout) == strlen(a:info)
|
|
let scriptout=substitute(a:info, '.*\<out="\(.\{-}\)".*', '\1', '')
|
|
if strlen(scriptout) != strlen(a:info) | let scriptout=escape(scriptout, ' ') | endif
|
|
endif
|
|
if strlen(scriptout) == strlen(a:info) | let scriptout='' | else
|
|
if !s:IsAbsolutePath(scriptout) | let scriptout=a:home.'/'.scriptout | endif | endif
|
|
return scriptout
|
|
endfunction
|
|
function! s:GetFlags(info)
|
|
let flags=substitute(a:info, '.*\<flags=\([^ {]*\).*', '\1', '')
|
|
if (strlen(flags) == strlen(a:info))
|
|
let flags=''
|
|
endif
|
|
return flags
|
|
endfunction ">>>
|
|
" Project_GetAllFnames(recurse, lineno, separator) <<<
|
|
" Grep all files in a project, optionally recursively
|
|
function! Project_GetAllFnames(recurse, lineno, separator)
|
|
let b:fnamelist=''
|
|
function! s:SpawnExec(home, c_d, fname, lineno, data)
|
|
if exists('b:escape_spaces')
|
|
let fname=escape(a:fname, ' ')
|
|
else
|
|
let fname=a:fname
|
|
endif
|
|
if !s:IsAbsolutePath(a:fname)
|
|
let fname=a:home.'/'.fname
|
|
endif
|
|
let b:fnamelist=b:fnamelist.a:data.fname
|
|
endfunction
|
|
call Project_ForEach(a:recurse, line('.'), "<SID>SpawnExec", a:separator, '')
|
|
delfunction s:SpawnExec
|
|
let retval=b:fnamelist
|
|
unlet b:fnamelist
|
|
return retval
|
|
endfunction ">>>
|
|
" Project_GetAllFnames(recurse, lineno, separator) <<<
|
|
" Grep all files in a project, optionally recursively
|
|
function! Project_GetFname(line)
|
|
if (foldlevel(a:line) == 0)
|
|
return ''
|
|
endif
|
|
let fname=substitute(getline(a:line), '\s*#.*', '', '') " Get rid of comments and whitespace before comment
|
|
let fname=substitute(fname, '^\s*\(.*\)', '\1', '') " Get rid of leading whitespace
|
|
if strlen(fname) == 0
|
|
return '' " The line is blank. Do nothing.
|
|
endif
|
|
if s:IsAbsolutePath(fname)
|
|
return fname
|
|
endif
|
|
let infoline = s:RecursivelyConstructDirectives(a:line)
|
|
return s:GetHome(infoline, '').'/'.fname
|
|
endfunction ">>>
|
|
" Project_ForEach(recurse, lineno, cmd, data, match) <<<
|
|
" Grep all files in a project, optionally recursively
|
|
function! Project_ForEach(recurse, lineno, cmd, data, match)
|
|
let info=s:RecursivelyConstructDirectives(a:lineno)
|
|
let lineno=s:FindFoldTop(a:lineno) + 1
|
|
let flags=s:GetFlags(getline(lineno - 1))
|
|
if (flags == '') || (a:match=='') || (match(flags, a:match) != -1)
|
|
call s:Project_ForEachR(a:recurse, lineno, info, a:cmd, a:data, a:match)
|
|
endif
|
|
endfunction
|
|
function! s:Project_ForEachR(recurse, lineno, info, cmd, data, match)
|
|
let home=s:GetHome(a:info, '')
|
|
let c_d=s:GetCd(a:info, home)
|
|
let scriptin = s:GetScriptin(a:info, home)
|
|
let scriptout = s:GetScriptout(a:info, home)
|
|
let filter = s:GetFilter(a:info, '')
|
|
let lineno = a:lineno
|
|
let curline=getline(lineno)
|
|
while (curline !~ '}') && (curline < line('$'))
|
|
if exists("b:stop_everything") && b:stop_everything | return 0 | endif
|
|
if curline =~ '{'
|
|
if a:recurse
|
|
let flags=s:GetFlags(curline)
|
|
if (flags == '') || (a:match=='') || (match(flags, a:match) != -1)
|
|
let this_home=s:GetHome(curline, home)
|
|
let this_cd=s:GetCd(curline, this_home)
|
|
if this_cd=='' | let this_cd=c_d | endif
|
|
let this_scriptin=s:GetScriptin(curline, this_home)
|
|
if this_scriptin == '' | let this_scriptin=scriptin | endif
|
|
let this_scriptout=s:GetScriptin(curline, this_home)
|
|
if this_scriptout == '' | let this_scriptout=scriptout | endif
|
|
let this_filter=s:GetFilter(curline, filter)
|
|
let lineno=s:Project_ForEachR(1, lineno+1,
|
|
\s:ConstructInfo(this_home, this_cd, this_scriptin, this_scriptout, flags, this_filter), a:cmd, a:data, a:match)
|
|
else
|
|
let lineno=s:FindFoldBottom(lineno)
|
|
endif
|
|
else
|
|
let lineno=s:FindFoldBottom(lineno)
|
|
endif
|
|
else
|
|
let fname=substitute(curline, '\s*#.*', '', '')
|
|
let fname=substitute(fname, '^\s*\(.*\)', '\1', '')
|
|
if (strlen(fname) != strlen(curline)) && (fname[0] != '')
|
|
if a:cmd[0] == '*'
|
|
call {strpart(a:cmd, 1)}(a:info, fname, lineno, a:data)
|
|
else
|
|
call {a:cmd}(home, c_d, fname, lineno, a:data)
|
|
endif
|
|
endif
|
|
endif
|
|
let lineno=lineno + 1
|
|
let curline=getline(lineno)
|
|
endwhile
|
|
return lineno
|
|
endfunction ">>>
|
|
" s:SpawnAll(recurse, number) <<<
|
|
" Spawn an external command on the files of a project
|
|
function! s:SpawnAll(recurse, number)
|
|
echo | if exists("g:proj_run_fold".a:number)
|
|
if g:proj_run_fold{a:number}[0] == '*'
|
|
function! s:SpawnExec(home, c_d, fname, lineno, data)
|
|
let command=substitute(strpart(g:proj_run_fold{a:data}, 1), '%s', escape(a:fname, ' \'), 'g')
|
|
let command=substitute(command, '%f', escape(a:fname, '\'), 'g')
|
|
let command=substitute(command, '%h', escape(a:home, '\'), 'g')
|
|
let command=substitute(command, '%d', escape(a:c_d, '\'), 'g')
|
|
let command=substitute(command, '%F', substitute(escape(a:fname, '\'), ' ', '\\\\ ', 'g'), 'g')
|
|
exec command
|
|
endfunction
|
|
call Project_ForEach(a:recurse, line('.'), "<SID>SpawnExec", a:number, '.')
|
|
delfunction s:SpawnExec
|
|
else
|
|
let info=s:RecursivelyConstructDirectives(line('.'))
|
|
let home=s:GetHome(info, '')
|
|
let c_d=s:GetCd(info, '')
|
|
let b:escape_spaces=1
|
|
let fnames=Project_GetAllFnames(a:recurse, line('.'), ' ')
|
|
unlet b:escape_spaces
|
|
let command=substitute(g:proj_run_fold{a:number}, '%f', substitute(escape(fnames, '\'), '\\ ', ' ', 'g'), 'g')
|
|
let command=substitute(command, '%s', escape(fnames, '\'), 'g')
|
|
let command=substitute(command, '%h', escape(home, '\'), 'g')
|
|
let command=substitute(command, '%d', escape(c_d, '\'), 'g')
|
|
let command=substitute(command, '%F', escape(fnames, '\'), 'g')
|
|
exec command
|
|
if v:shell_error != 0
|
|
echo 'Shell error. Perhaps there are too many filenames.'
|
|
endif
|
|
endif
|
|
endif
|
|
endfunction ">>>
|
|
if !exists("g:proj_running")
|
|
" s:DoProjectOnly(void) <<<
|
|
" Make the file window the only one.
|
|
function! s:DoProjectOnly()
|
|
if winbufnr(0) != g:proj_running
|
|
let lzsave=&lz
|
|
set lz
|
|
only
|
|
Project
|
|
silent! wincmd p
|
|
let &lz=lzsave
|
|
unlet lzsave
|
|
endif
|
|
endfunction
|
|
" >>>
|
|
|
|
" Mappings <<<
|
|
nnoremap <buffer> <silent> <Return> \|:call <SID>DoFoldOrOpenEntry('', 'e')<CR>
|
|
nnoremap <buffer> <silent> <S-Return> \|:call <SID>DoFoldOrOpenEntry('', 'sp')<CR>
|
|
nnoremap <buffer> <silent> <C-Return> \|:call <SID>DoFoldOrOpenEntry('silent! only', 'e')<CR>
|
|
nnoremap <buffer> <silent> <LocalLeader>T \|:call <SID>DoFoldOrOpenEntry('', 'tabe')<CR>
|
|
nmap <buffer> <silent> <LocalLeader>s <S-Return>
|
|
nnoremap <buffer> <silent> <LocalLeader>S \|:call <SID>LoadAllSplit(0, line('.'))<CR>
|
|
nmap <buffer> <silent> <LocalLeader>o <C-Return>
|
|
nnoremap <buffer> <silent> <LocalLeader>i :echo <SID>RecursivelyConstructDirectives(line('.'))<CR>
|
|
nnoremap <buffer> <silent> <LocalLeader>I :echo Project_GetFname(line('.'))<CR>
|
|
nmap <buffer> <silent> <M-CR> <Return><C-W>p
|
|
nmap <buffer> <silent> <LocalLeader>v <M-CR>
|
|
nnoremap <buffer> <silent> <LocalLeader>l \|:call <SID>LoadAll(0, line('.'))<CR>
|
|
nnoremap <buffer> <silent> <LocalLeader>L \|:call <SID>LoadAll(1, line('.'))<CR>
|
|
nnoremap <buffer> <silent> <LocalLeader>w \|:call <SID>WipeAll(0, line('.'))<CR>
|
|
nnoremap <buffer> <silent> <LocalLeader>W \|:call <SID>WipeAll(1, line('.'))<CR>
|
|
nnoremap <buffer> <silent> <LocalLeader>W \|:call <SID>WipeAll(1, line('.'))<CR>
|
|
nnoremap <buffer> <silent> <LocalLeader>g \|:call <SID>GrepAll(0, line('.'), "")<CR>
|
|
nnoremap <buffer> <silent> <LocalLeader>G \|:call <SID>GrepAll(1, line('.'), "")<CR>
|
|
nnoremap <buffer> <silent> <2-LeftMouse> \|:call <SID>DoFoldOrOpenEntry('', 'e')<CR>
|
|
nnoremap <buffer> <silent> <S-2-LeftMouse> \|:call <SID>DoFoldOrOpenEntry('', 'sp')<CR>
|
|
nnoremap <buffer> <silent> <M-2-LeftMouse> <M-CR>
|
|
nnoremap <buffer> <silent> <S-LeftMouse> <LeftMouse>
|
|
nmap <buffer> <silent> <C-2-LeftMouse> <C-Return>
|
|
nnoremap <buffer> <silent> <C-LeftMouse> <LeftMouse>
|
|
nnoremap <buffer> <silent> <3-LeftMouse> <Nop>
|
|
nmap <buffer> <silent> <RightMouse> <space>
|
|
nmap <buffer> <silent> <2-RightMouse> <space>
|
|
nmap <buffer> <silent> <3-RightMouse> <space>
|
|
nmap <buffer> <silent> <4-RightMouse> <space>
|
|
nnoremap <buffer> <silent> <space> \|:silent exec 'vertical resize '.(match(g:proj_flags, '\Ct')!=-1 && winwidth('.') > g:proj_window_width?(g:proj_window_width):(winwidth('.') + g:proj_window_increment))<CR>
|
|
nnoremap <buffer> <silent> <C-Up> \|:silent call <SID>MoveUp()<CR>
|
|
nnoremap <buffer> <silent> <C-Down> \|:silent call <SID>MoveDown()<CR>
|
|
nmap <buffer> <silent> <LocalLeader><Up> <C-Up>
|
|
nmap <buffer> <silent> <LocalLeader><Down> <C-Down>
|
|
let k=1
|
|
while k < 10
|
|
exec 'nnoremap <buffer> <LocalLeader>'.k.' \|:call <SID>Spawn('.k.')<CR>'
|
|
exec 'nnoremap <buffer> <LocalLeader>f'.k.' \|:call <SID>SpawnAll(0, '.k.')<CR>'
|
|
exec 'nnoremap <buffer> <LocalLeader>F'.k.' \|:call <SID>SpawnAll(1, '.k.')<CR>'
|
|
let k=k+1
|
|
endwhile
|
|
nnoremap <buffer> <LocalLeader>0 \|:call <SID>ListSpawn("")<CR>
|
|
nnoremap <buffer> <LocalLeader>f0 \|:call <SID>ListSpawn("_fold")<CR>
|
|
nnoremap <buffer> <LocalLeader>F0 \|:call <SID>ListSpawn("_fold")<CR>
|
|
nnoremap <buffer> <silent> <LocalLeader>c :call <SID>CreateEntriesFromDir(0)<CR>
|
|
nnoremap <buffer> <silent> <LocalLeader>C :call <SID>CreateEntriesFromDir(1)<CR>
|
|
nnoremap <buffer> <silent> <LocalLeader>r :call <SID>RefreshEntriesFromDir(0)<CR>
|
|
nnoremap <buffer> <silent> <LocalLeader>R :call <SID>RefreshEntriesFromDir(1)<CR>
|
|
" For Windows users: same as \R
|
|
nnoremap <buffer> <silent> <F5> :call <SID>RefreshEntriesFromDir(1)<CR>
|
|
nnoremap <buffer> <silent> <LocalLeader>e :call <SID>OpenEntry(line('.'), '', '', 0)<CR>
|
|
nnoremap <buffer> <silent> <LocalLeader>E :call <SID>OpenEntry(line('.'), '', 'e', 1)<CR>
|
|
" The :help command stomps on the Project Window. Try to avoid that.
|
|
" This is not perfect, but it is alot better than without the mappings.
|
|
cnoremap <buffer> help let g:proj_doinghelp = 1<CR>:help
|
|
nnoremap <buffer> <F1> :let g:proj_doinghelp = 1<CR><F1>
|
|
" This is to avoid changing the buffer, but it is not fool-proof.
|
|
nnoremap <buffer> <silent> <C-^> <Nop>
|
|
"nnoremap <script> <Plug>ProjectOnly :let lzsave=&lz<CR>:set lz<CR><C-W>o:Project<CR>:silent! wincmd p<CR>:let &lz=lzsave<CR>:unlet lzsave<CR>
|
|
nnoremap <script> <Plug>ProjectOnly :call <SID>DoProjectOnly()<CR>
|
|
if match(g:proj_flags, '\Cm') != -1
|
|
if !hasmapto('<Plug>ProjectOnly')
|
|
nmap <silent> <unique> <C-W>o <Plug>ProjectOnly
|
|
nmap <silent> <unique> <C-W><C-O> <C-W>o
|
|
endif
|
|
endif " >>>
|
|
if filereadable(glob('~/.vimproject_mappings')) | source ~/.vimproject_mappings | endif
|
|
" Autocommands <<<
|
|
" Autocommands to clean up if we do a buffer wipe
|
|
" These don't work unless we substitute \ for / for Windows
|
|
let bufname=escape(substitute(expand('%:p', 0), '\\', '/', 'g'), ' ')
|
|
exec 'au BufWipeout '.bufname.' au! * '.bufname
|
|
exec 'au BufWipeout '.bufname.' unlet g:proj_running'
|
|
exec 'au BufWipeout '.bufname.' nunmap <C-W>o'
|
|
exec 'au BufWipeout '.bufname.' nunmap <C-W><C-O>'
|
|
" Autocommands to keep the window the specified size
|
|
exec 'au WinLeave '.bufname.' call s:DoEnsurePlacementSize_au()'
|
|
exec 'au BufEnter '.bufname.' call s:DoSetupAndSplit_au()'
|
|
au WinLeave * call s:RecordPrevBuffer_au()
|
|
" >>>
|
|
setlocal buflisted
|
|
let g:proj_running = bufnr(bufname.'\>')
|
|
if g:proj_running == -1
|
|
call confirm('Project/Vim error. Please Enter :Project again and report this bug.', "&OK", 1)
|
|
unlet g:proj_running
|
|
endif
|
|
setlocal nobuflisted
|
|
endif
|
|
endfunction " >>>
|
|
|
|
if exists(':Project') != 2
|
|
command -nargs=? -complete=file Project call <SID>Project('<args>')
|
|
endif
|
|
" Toggle Mapping
|
|
if !exists("*<SID>DoToggleProject()") "<<<
|
|
function! s:DoToggleProject()
|
|
if !exists('g:proj_running') || bufwinnr(g:proj_running) == -1
|
|
Project
|
|
else
|
|
let g:proj_mywindow = winnr()
|
|
Project
|
|
hide
|
|
if(winnr() != g:proj_mywindow)
|
|
wincmd p
|
|
endif
|
|
unlet g:proj_mywindow
|
|
endif
|
|
endfunction
|
|
endif ">>>
|
|
nnoremap <script> <Plug>ToggleProject :call <SID>DoToggleProject()<CR>
|
|
if exists('g:proj_flags') && (match(g:proj_flags, '\Cg') != -1)
|
|
if !hasmapto('<Plug>ToggleProject')
|
|
nmap <silent> <F12> <Plug>ToggleProject
|
|
endif
|
|
endif
|
|
|
|
finish
|
|
|
|
" vim600: set foldmethod=marker foldmarker=<<<,>>> foldlevel=1:
|