7

I'm trying to make a key mapping in vim that (a) saves current file (b) performs a git action, using shell (c) quits current vim editor.

I've tried the following methods but still can't figure it out.

Method 1 - in Vim command line

:w | !git commit -am "auto" | q

Method 2 - in .vimrc

map :W :w \| !git commit -am "auto"

map :L :Wq

Problem

The problem is that the pipe | can only be used to append shell commands. How do I do 'a Vim command' + 'a shell command' + 'a Vim command'? How to pipe a vim command after a shell command?

6
  • This is absolutely not duplicate of the problem @Barmar marked! I have described it very clearly. The problem is that the pipe | can only be used to append shell commands. The problem mentioned by Barmar is only for pure shell commands piping. In contrast, my problem asks to combine a shell command and then a vim command! Commented May 18, 2017 at 23:19
  • The other question is about running two vim commands. One of the commands happens to be a ! command that executes a shell command, but the two commands can be anything. Commented May 18, 2017 at 23:21
  • pdflatex and git are not vim commands, they are shell commands. You have to use ! to execute them inside vim. In my question, the q would be translated to !q which is q (in bash) and produce error. Commented May 18, 2017 at 23:25
  • 1
    As an aside, the phrase vim commands is not code, and should not be quoted in backticks. Consider italicising for emphasis. BTW, would y'all mind linking to the proposed dupe so others have context to build an informed decision on the matter? Commented May 18, 2017 at 23:31
  • 1
    You can't use a pipe after :!, according to the docs. Commented May 18, 2017 at 23:48

7 Answers 7

4

You need to execute those three commands separately. This is what <CR> is for:

nnoremap <key> :w<CR>:!git commit -am "auto"<CR>:qa<CR> 
Sign up to request clarification or add additional context in comments.

1 Comment

figured it out!
1

Have you tried vim-fugitive?

You can git commit -am using that plugin and then add your git command.

So you would write something like:

Gcommit -am "auto"

I tested it briefly. I've put this into my .vimrc:

function! CommitAndQuit() execute "Gcommit -am 'auto'" execute "q" endfunction 

Then type :call CommitAndQuit() and it will do what you want.

Comments

1

This feels related as I ended up here!

So if you want to bind this in a command you won't be able to use <cr> and pipe also won't work.

In that case the right thing to do is use a function and just call the function from that command.

In this example I had a shell script to grep some log files for errors and output the result into .errors, which then gets opened in the quickfix. The redraw is because silent messes your screen up with external commands!

function! ReadErrors() silent !read-errors redraw! cfile .errors endfunction command! ReadErrors call ReadErrors() 

Comments

1

There are 3 scenarios I see here:

Adding a vim command

If you want to add a new vim command, so that typing :W would write the buffer, do git commit and quit vim, you'll need to follow JonnyRaa's answer. Namely, define a function, and then define a command that executes that function:

function! WriteCommitAndQuit() w silent !git commit -am "auto" q endfunction command! W call WriteCommitAndQuit() 

Notes:

  1. These lines can be put into ~/.vimrc, or executed directly after hitting : to go into command line mode.
  2. I used silent to avoid getting the "Press ENTER or type command to continue" prompt.
  3. You might want to use write and quit instead of w and q, for nicer-looking code. (Conversely, silent can be shortened to sil if you're in a hurry...)

Adding a keyboard mapping

If you want to just be able to hit a single key to run these commands, you'll need to add a mapping, and the trick for putting a shell command in the middle is to use <CR> to simulate hitting ENTER:

map <F10> :w<CR>:silent !git commit -am "auto"<CR>:q<CR> 

Notes:

  1. Once again, this can go in ~/.vimrc or execute by hitting : and typing it directly.
  2. Instead of silent, you can just add an extra <CR> after the shell command.

Executing directly

Sometimes there's a sequence of commands you want to run repeatedly, but they're not worth bothering to persist into vimrc, since they are ad-hoc and won't be useful in the future. In this case, I just execute the line and then rely on the up arrow to bring the line again from history and execute it. In this case, the trick is to add an escaped LF character in the middle of the command, using Ctrl-V, Ctrl-J:

:w | silent !git commit -am "auto" ^@ q 

Notes:

  1. The ^@ in the command is what gets shown when I hit Ctrl-V, Ctrl-J. It won't work if you hit Shift-6, Shift-2. However, it does seem to work if I hit Ctrl-Shift-2.
  2. You can also replace the first pipe character with LF, but you don't have to.
  3. In case you're curious, Ctrl-J is LF because LF is ASCII 10, and J is the 10th letter of the ABC. Similarly, Ctrl-I is Tab, Ctrl-M is CR, and Ctrl-] is Escape, since Escape is ASCII 27, and if you look at an ASCII table, you'll realize that ] is the 27th letter of the ABC.

Comments

0

i use this command to copy current file path to system clipboard.

map <silent> <leader>vv :echo expand('%:p') \| !syscopy.sh <cr> 

Comments

0

simple why for me is:

  • Work
:echo expand('ls') | echomsg 'test' 
  • Not work
:!ls | echomsg 'test' 

Comments

-1

You can't:

A '|' in {cmd} is passed to the shell, you cannot use it to append a Vim command. See |:bar|.

1 Comment

Yes, this fact has already been stated in the problem, as in this sentence, The problem is that the pipe | can only be used to append shell commands.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.