eugen0329/vim-esearch

View on GitHub
autoload/esearch/xargs.vim

Summary

Maintainability
Test Coverage
let s:Filepath = vital#esearch#import('System.Filepath')

fu! esearch#xargs#git_log(...) abort
  let options = get(a:, 1, '')
  return {
        \ 'repr': function('s:repr', ['git-log']),
        \ 'command': function('s:git_log'),
        \ 'options': get(a:, 1, ''),
        \ 'adapters': ['git'],
        \ 'pathspec': get(a:, 2, esearch#shell#argv([])),
        \}
endfu

fu! esearch#xargs#git_stash(...) abort
  return {
        \ 'repr': function('s:repr', ['git-stash']),
        \ 'command': function('s:git_stash'),
        \ 'options': get(a:, 1, ''),
        \ 'adapters': ['git'],
        \ 'pathspec': get(a:, 2, esearch#shell#argv([])),
        \}
endfu

fu! s:repr(name, ...) abort dict " python __repr__-like method
  return '<'
        \ . a:name
        \ . (empty(self.options) ? '' : ' ' . self.options)
        \ . (empty(self.pathspec) ? '' : ' ' . esearch#shell#join(self.pathspec))
        \ . '>'
endfu

let s:hold_revision = '1{h;d;}; /^$/{n;h;d;};'
let s:prefix_filenames_with_revision = '/./{G;s/(.*)\n(.*)/\2:\1/g;};'
let s:q = "'\\''" " single quote to pass into sed
let s:shell_quote = 's/'.s:q.'/'.s:q.'\\'.s:q.s:q.'/g; s/.*/'.s:q.'&'.s:q.'/g;'
let s:prepend_filenames_with_revisions_fmt =
      \  "|sed -nE '"
      \. s:hold_revision.' '
      \. s:prefix_filenames_with_revision.' '
      \. '%s '
      \. s:shell_quote
      \. " p;'"
let s:xargs_batched = '| xargs -n127' " bigger n means higher latency, but lower overhead
let s:prepend_filenames_with_revisions = printf(s:prepend_filenames_with_revisions_fmt, '')

fu! s:git_log(adapter, esearch) abort dict
  let pipe = join([
        \ a:adapter.bin,
        \ 'log --oneline --pretty=format:%H --name-only --diff-filter=d --ignore-submodules=all',
        \ a:esearch.regex ==# 'literal' ? '' : '--pickaxe-regex',
        \ a:esearch.case ==# 'ignore' ?  '--regexp-ignore-case' : '',
        \ self.options,
        \ join(map(copy(a:esearch.pattern._arg), '"-S". v:val[1]')),
        \ '--',
        \ esearch#shell#join_pathspec(self.pathspec),
        \ s:prepend_filenames_with_revisions,
        \ s:xargs_batched,
        \], ' ')
  return [pipe, '']
endfu

fu! s:git_stash(adapter, esearch) abort dict
  if empty(self.pathspec) || !g:esearch#has#posix_shell
    let filter_paths = ''
  else
    let relative_paths = filter(copy(self.pathspec), 's:Filepath.is_relative(v:val.str)')
    if empty(relative_paths)
      let filter_paths = ''
    else
      " https://www.gnu.org/software/sed/manual/html_node/Regular-Expressions.html
      " https://www.gnu.org/software/sed/manual/html_node/BRE-vs-ERE.html
      let filter_paths = join(map(relative_paths, "escape(v:val.str, '/?+{}|()*.^[]$\')"), '|')
      let filter_paths = '/^stash@[{][[:digit:]]+[}]:(' . filter_paths . ')/!d;'
    endif
  endif

  " -S is claimed to work the same as in git-log, but it doesn't
  let pipe = join([
        \ a:adapter.bin,
        \ 'stash list --oneline --pretty=format:%gd --name-only --diff-filter=d',
        \ self.options,
        \ printf(s:prepend_filenames_with_revisions_fmt, filter_paths),
        \ s:xargs_batched,
        \], ' ')
  return [pipe, '']
endfu