+" Tools for use with the mkbuild build environment.
+
+" Return the results of a command without the ending newline
+function! s:chompsys(cmd)
+ 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 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 . "/|')"
+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)
+ else
+ call add(dirs, topdir)
+ let extrefs = topdir . '/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)
+ endif
+ endfor
+ endif
+ endif
+ return dirs
+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()
+ let tags = []
+ for t in split(&tags, ',')
+ if filereadable(t)
+ call add(tags, t)
+ endif
+ endfor
+ 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)"
+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()
+ let files = []
+ for t in s:tagfiles()
+ let f = substitute(t, '\c\(\.\/\)*tags.*$', 'filelist', '')
+ if filereadable(f)
+ call add(files, f)
+ endif
+ endfor
+ 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 . ")"
+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"
+ else
+ 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
+ let fname = s:chompsys(sourcecmd . ' | dmenu -i -l 20 -p "' . source . '(' .
+ \ a:cmd . ')"')
+ if empty(fname)
+ return
+ endif
+ execute a:cmd . " " . fname
+ endif
+endfunction