return substitute(system(a:cmd), '\n$', '', '')
endfunction
-" Return the top level working directory in a git checkout. If dir is '',
-" start from the current directory, else start from dir.
-function! s:gittop(dir)
- if empty(a:dir)
- return s:chompsys('git rev-parse --show-toplevel 2>/dev/null')
- else
+" Return a list directories contained within an extrefs file at 'dir'. Use
+" '.' as dir if wanting to find extrefs in the current directory. The
+" returned list may be empty. Directories returned are not validated.
+function! s:extrefs(dir)
+ let extdirs = []
+ let extrefs = a:dir . '/extrefs'
+ if filereadable(extrefs)
+ for e in split(s:chompsys(
+ \ "grep ^git " . extrefs . "| awk '{ print $3 }'"))
+ if !empty(e)
+ call add(extdirs, a:dir . '/' . e)
+ endif
+ endfor
+ endif
+ return extdirs
+endfunction
+
+" Return a list of files found using 'find', recursively, starting at 'dir'
+function s:filesFromFind(dir)
+ return split(s:chompsys("cd " . a:dir . " 2>/dev/null && find . -type f"),
+ \ '\n')
+endfunction
+
+" If 'dir' is empty, assume the current directory. Assume 'dir' is within a
+" Git checkout. If true, return a list of tracked files from the Get
+" repository. Otherwise, return an empty string.
+function! s:gitTopLevel(dir)
return s:chompsys("cd " . a:dir .
\ " && git rev-parse --show-toplevel 2>/dev/null")
endfunction
-" Return a shell segment that will output a list of files with full paths
-" parsed from working directory's tracked files.
-function! s:gitls(workdir)
- return "(git --git-dir=" . a:workdir . "/.git ls-files | sed -e s'|^|" .
- \ a:workdir . "/|')"
+" 'dir' must either be an empty string or a directory within a Git checkout,
+" generally its top level directory. Return a list of all tracked files
+" within the repository starting at 'dir'.
+function! s:filesFromGit(dir)
+ if empty(a:dir)
+ return []
+ else
+ return split(s:chompsys("git --git-dir=" . a:dir . "/.git ls-files | "
+ \ . "sed -e s'|^|" . a:dir . "/|'"), '\n')
+ endif
endfunction
-" Return a list of git directories. If the current directory is in a git
-" working directory, at least this one will be returned. If the top level of
-" this directory has an extrefs file, then the valid git directories listed
-" therein are also added to the list.
-function! s:gitdirs()
- let dirs = []
- let topdir = s:gittop('')
- if empty(topdir)
+" Return a list of files contained within the directory 'dir'. If 'dir'
+" belongs to a Git working directory, return all tracked files in the
+" repository. Otherwise, use find to return the files at the filesystem
+" subtree starting at 'dir'.
+"
+" Additionally, if 'dir' (or instead the Git top-level working directory),
+" contains an extrefs file, recursively include files from each of its listed
+" directories.
+function! s:filesFromDir(dir)
+ let dir = s:gitTopLevel(a:dir)
+ if !empty(dir)
+ let files = s:filesFromGit(dir)
else
- call add(dirs, topdir)
- let extrefs = topdir . '/extrefs'
+ let dir = a:dir
+ let files = s:filesFromFind(dir)
+ endif
+ if !empty(files)
+ let extrefs = dir . '/extrefs'
if filereadable(extrefs)
for e in split(s:chompsys(
\ "grep ^git " . extrefs . "| awk '{ print $3 }'"))
- let dir = s:gittop(topdir . '/' . e)
- if empty(dir)
- else
- call add(dirs, dir)
+ if !empty(e)
+ call extend(files, s:filesFromDir(dir . '/' . e))
endif
endfor
endif
endif
- return dirs
+ return files
endfunction
+
" Return a list of readable tag files, as present in &tags. This function
" doesn't handle the sometimes-default 'tags:/' value I've seen.
function! s:tagfiles()
return tags
endfunction
-" Return a shell segment that will output a list of files with full paths
-" parsed from the named tags (ctags) file.
-function! s:tagls(tagfile)
- return "(grep -v \"!\" " . a:tagfile . " | awk -F\\\t '{ print $2 }' | " .
- \ "sort -u)"
+" Return a list of files with full paths, parsed from the named tags (ctags)
+" file.
+function! s:filesFromTagsFile(tagfile)
+ return split(s:chompsys("grep -v \"!\" " . a:tagfile .
+ \ " | awk -F\\\t '{ print $2 }' | sort -u"), '\n')
endfunction
" Return a list of readable filelist files, which are looked for in the same
" directories where &tags has vim looking for tags files.
-function! s:filelists()
+function! s:filelistfiles()
let files = []
for t in s:tagfiles()
let f = substitute(t, '\c\(\.\/\)*tags.*$', 'filelist', '')
return files
endfunction
-" Return a shell segment that will output a list of files with full paths
-" parsed from the named filelist file.
-function! s:filels(filelist)
- return "(cat " . a:filelist . ")"
+" Return a list of files with full paths, parsed from the named filelist file.
+function! s:filesFromFilelistFile(filelist)
+ return split(s:chompsys("cat " . a:filelist), '\n')
endfunction
-" Generate a command to generate a list of files. Return a dictionary
-" containing two entries:
-" source - The source of the files (generated by executing the sourcecmd)
-" sourcecmd - The system command to use to generate the list of files
-"
-" The source command returned will output files from one of 4 locations,
-" searched in priority order:
-" 1. All filelist files found in the same directory(ies) vim looks for tags
-" files. Files are extracted from the contents of these files.
-" 2. Any tags files found in &tags. The file is parsed to get filenames.
-" 3. The tracked files in the current git repository, and/or the tracked files
-" in those valid git repositories named in the 'extrefs' file, if present.
-" 4. Perform a 'find . -type f' in the current directory.
-function! mkbuild#flcmd()
- let files = s:filelists()
- if empty(files)
- let tags = s:tagfiles()
- if empty(tags)
- let gitdirs = s:gitdirs()
- if empty(gitdirs)
- let source = 'find'
- let sourcecmd = 'find . -type f'
- else " gitdirs
- let source = 'git|extrefs'
- let sourcecmd = '(true'
- for g in gitdirs
- let sourcecmd = sourcecmd . '; ' . s:gitls(g)
- endfor
- let sourcecmd = sourcecmd . ')'
- endif
- else " tags
- let source = 'tags'
- let sourcecmd = '(true'
- for t in tags
- let sourcecmd = sourcecmd . '; ' . s:tagls(t)
- endfor
- let sourcecmd = sourcecmd . ')'
- endif
- else " filelists
- let source = 'filelists'
- let sourcecmd = '(true'
- for f in files
- let sourcecmd = sourcecmd . '; ' . s:filels(f)
- endfor
- let sourcecmd = sourcecmd . ')'
- endif
- return { 'source': source, 'sourcecmd': sourcecmd }
+" Return a list of all project files. Where possible, use tracked files from
+" the project Git repository, else collect all files. Also follow 'extrefs'
+" files to additional, external sources.
+function! mkbuild#allFiles()
+ return s:filesFromDir('.')
endfunction
-" Generate a list of files using mkbuild#flcmd()
-function! mkbuild#filelist()
- let flcmdres = mkbuild#flcmd()
- return s:chompsys(flcmdres['sourcecmd'] . ' | cat')
-endfunction
-
-" Use dmenu to select a file to execute with command 'cmd'. If no file is
-" selected, no action is taken. The list of files presented to dmenu comes
-" from one of four places, in the following priority order:
-" 1. All filelist files found in the same directory(ies) vim looks for tags
-" files.
-" 2. Any tags files found in &tags. The file is parsed to get filenames.
-" 3. The tracked files in the current git repository, and/or the tracked files
-" in those valid git repositories named in the 'extrefs' file, if present.
-" 3. Perform a 'find . -type f' in the current directory.
-function! mkbuild#DmenuOpen(cmd)
- if empty(system('which dmenu'))
- echo "Dmenu is not installed"
+" Return the subset of project files used in the build referenced by the
+" directory defined in the 'tags' variable. Use the mkbuild filelist, if
+" available, or fall back to extracting files from the tags file. If no
+" source of filelist or tags files are available, revert to returning all
+" proejct files.
+function! mkbuild#buildFiles()
+ let files = []
+ let flfiles = s:filelistfiles()
+ if !empty(flfiles)
+ for f in flfiles
+ call extend(files, s:filesFromFilelistFile(f))
+ endfor
else
- let flcmdres = mkbuild#flcmd()
- let source = flcmdres['source']
- let sourcecmd = flcmdres['sourcecmd']
- let fname = s:chompsys(sourcecmd . ' | dmenu -i -l 20 -p "' . source . '(' .
- \ a:cmd . ')"')
- if empty(fname)
- return
+ let tagfiles = s:tagfiles()
+ if !empty(tagfiles)
+ for t in tags
+ call extend(files, s:filesFromTagsFile(t))
+ endfor
+ else
+ call extend(files, s:filesFromDir('.'))
endif
- execute a:cmd . " " . fname
endif
+ return files
endfunction