5

Problem:

Suppose I have the following text in my vim buffer:

This is a commit msg.

Suppose further I have a git repo located at ~/my_repo.

Goal: Make a vim script so that I can highlight the text above, and have it sent as a git commit message within ~/my_repo. It would look something like

:'<,'>Commit ~/my_repo

It would also have auto-complete on its repo argument.

Attempted Solution:

First, the autocomplete function (AFAIK I think this is OK?):

function! GitLocations()
  return find $HOME -name '.git' -printf '%h\n' "generates a list of all folders which contain a .git dir
endfunction 

Next, the actual git commit function, which is incomplete:

function! CommitTextGitRepo(l1, l2, loc)
  let s:msg = ??? " how do I make this the highlighted text from line l1 to line l2?
  execute '!cd ' . a:loc . '&& git commit --allow-empty -m \"' . s:msg '\"'
endfunction

Assuming I can figure out how to get CommitTextGitRepo() working above, the final thing I would need is this (I think):

command! -nargs=* -complete=custom,GitLocations -range Commit call CommitToGitRepo(<line1>, <line2>, <q-args>)

I'm so close. How do I finish this up? :)

  • 1
    GitLocations won't work as expected, since you'll be calling Vim's :find, not the find command. Might try something like return system('find $HOME ...') (and add a -type d to it to skip submodules, perhaps?) – muru Feb 19 '16 at 16:19
  • Good idea. With that, all I need is a way to bind s:msg to the contents of the line range (within CommitTextGitRepo above). – user1770201 Feb 19 '16 at 16:27
  • 1
    Maybe you could use getline() and join() like this: let s:msg = join(getline(a:l1,a:l2), "\n") – saginaw Feb 19 '16 at 16:36
  • @saginaw: That approach worked to get s:msg. – user1770201 Feb 19 '16 at 17:09
5

GitLocations won't work as expected, since you'll be calling Vim's :find, not the find command. You might try something like:

return system('find $HOME -name ".git" -printf "%h\n"')

And you could add a -type d to it to skip submodules.

To get visually selected text, you can use getline():

let s:msg = join(getline("'<", "'>"), "\n") . "\n"

However, it will be easier if you took advantage of git commit's ability to read the commit message from standard input. From man git commit:

-F <file>, --file=<file>
   Take the commit message from the given file. Use - to read the
   message from the standard input.

With w !, you can write a set of lines to the standard input of a shell command:

:[range]w[rite] [++opt] !{cmd}
                        Execute {cmd} with [range] lines as standard input
                        (note the space in front of the '!').  {cmd} is
                        executed like with ":!{cmd}", any '!' is replaced with
                        the previous command :!.

You could do something like:

function! CommitToGitRepo(l1, l2, loc) range
    exec a:l1 . ',' . a:l2 'w !cd' shellescape(a:loc) '; git commit --allow-empty -F -'
endfunction

command! -nargs=1 -range -complete=custom,GitLocations Commit call CommitToGitRepo(<line1>, <line2>, <args>)

Sources:

  • 2
    -printf isn't available in my OSX version of find but you can get something similar using internal Vim functions anyway: return fnamemodify(finddir('.git', $HOME), ":h"). I always work with my current directory inside the repo though so it's even easier since I don't need to get the git dir, I could just use let l:rootdir = fnamemodify(finddir('.git', getcwd().';/'), ":h") directly in the commit function (this uses upward as opposed to downward searching because of the semicolon). – dash-tom-bang Feb 19 '16 at 17:28
  • 2
    @dash-tom-bang ah, well, if you're already in the required git repo, you can run git commit directly. :) Even so, the pure Vimscript way might be more efficient than calling system('find ...'), so that's something OP should look into. I assume OP is using GNU find, since they came up with that part themselves. – muru Feb 19 '16 at 17:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.