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? :)

4
  • 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?) Commented Feb 19, 2016 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). Commented Feb 19, 2016 at 16:27
  • 1
    Maybe you could use getline() and join() like this: let s:msg = join(getline(a:l1,a:l2), "\n") Commented Feb 19, 2016 at 16:36
  • @saginaw: That approach worked to get s:msg. Commented Feb 19, 2016 at 17:09

1 Answer 1

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
  • 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). Commented Feb 19, 2016 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. Commented Feb 19, 2016 at 17:39

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.