28

with vim, if I use

:r!date

vim insert the date in the next line, similar with

:r!pwd

how I can insert the output command under cursor position and no in a new line ?

1

5 Answers 5

24

With ":read" Vim will always insert the output on a new line. The solution is unfortunately not simple.

You may insert the output of a command at the current cursor position when you are in insert mode by pressing ControlR then typing =system('command')Enter. Unfortunately, if the command's output has a trailing newline (as most will) that will also be inserted, so your line will be broken.

That can be fixed by adding a substitute() call to strip trailing newlines, but that makes the command more trouble than it is worth to type out by hand.

The ultimate solution is to create some sort of mapping, but that gets even more complex due to how Vim handles what it calls "type ahead"; while you can do something like:

:nmap \e i<c-r>=substitute(system('date'),'[\r\n]*$','','')<cr><esc>

Where the command is "hard wired" in the mapping, you cannot do something like:

:nmap \e i<c-r>=substitute(system(input('Command: ')),'[\r\n]*$','','')<cr><esc>

Where you try to prompt the user for the command to run, because Vim will just get confused, beep, and enter insert mode.

So you have to prompt for the command to run first, store it in a variable, and then insert the processed output. At this point a helper function is probably needed to keep the mapping itself from becoming unmanageably messy, so we end up with something like this:

function InlineCommand()
    let l:cmd = input('Command: ')
    let l:output = system(l:cmd)
    let l:output = substitute(l:output, '[\r\n]*$', '', '')
    execute 'normal i' . l:output
endfunction

nmap <silent> \e :call InlineCommand()<CR>

Note that nmap creates mappings that only execute when typed in normal mode.

Incidentally, if you only wanted to insert the date or the current working directory, the initial answer I gave is feasible. Just enter insert mode and type ControlR=strftime('%c')Enter or ControlR=getcwd()Enter.

1
  • Would it be possible to chain commands to solve this. :r !date | :- | J or i\n\n^[ -:.!date\n -JJ Jul 17, 2017 at 16:52
5

If you want it in the current line you try just, but have in mind the old content of the line will be erased:

:.!date

If you want the exact cursor position you can:

:let a=system("date") | let b=substitute(a,"[\r\n]*$","","g") | exec 'normal i'.b

Long story short: you need to substitute cause you want to get rid of ^@ (null characters) which you can also can replace with .s/\%x00//g. This is a shorter version with less pipes:

:exec 'normal i'.substitute(system("date"),"[\n]*$","","")

And you can also set tags if you want to replace in various points at the same line:

Given this Line 1:

1 Date: <datehere> and also <datehere>

Execute:

:let a=system("date") | exec ".s/<datehere>/".a."/g" | .s/\%x00//g

After Replacement:

1 Date: jue ago 9 02:34:52 ART 2012 and also jue ago 9 02:34:52 ART 2012

Tested on Vim 7.2

1

You can add this kind of thing in your .vimrc:

" Insert the date in YYYY-MM-DD format inline just before cursor position (normal mode)
nnoremap <Leader>di me:r !date +\%F<CR>A <Esc>0D`ePJx
  • me marks the current position.
  • :r !date +\%F<CR> puts the date on the next line in YYYY-MM-DD format (you can change this however you like, just escape each % with \).
  • A <Esc> appends a space to the end of the date output.
  • 0D deletes the date, `e takes you back to the marked position, and PJx puts the date before the cursor, joins the lines (to get rid of the empty one below) and kills the trailing space. Modify the mapping as you see fit.

If you want to do it from insert mode, I read this gem today on https://vimways.org/2018/the-mapping-business/

inoremap <C-g><C-t> <C-r>=strftime("%F")<CR>

You can modify the date output to suit your needs (man date can help with this).

0

In normal mode (escape/bleep mode) paste in

:exec 'normal i'.system("date \| tr '\n' ' '")

to get the date inserted at the current position. If you copy that line with a carriage-return then Shift+Insert becomes your DateTime-Here command.

Additionally you can bind F12 to a command with

:inoremap <F12> <C-r>=system("date \| tr '\n' ' '")<CR>

then you can insert the date with Function-key-12 while insert mode is active. I use

:inoremap DHRE <C-r>=system("date \| tr '\n' ' '")<CR>

(I changed from DHERE after finding that pasting ADHERE triggered) because I already use F12 for other things.

I use

grep -iE "dhere" /usr/share/dict/words

to check for obvious clashes with existing words, which suggest that you are relatively safe to use:

:inoremap PWD <C-r>=system("pwd \| tr '\n' ' '")<CR>

(unless you are writing certain documentation.)

0

If you want to insert above the current line, run:

:-1 read !date

or

:-r!date

See :help [range] and :help :range-offset for more information. The commands were tested on Vim v9.0.1736 .

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .