100

For instance, :echo strftime(%c) will show the current time on the bottom, but how to insert this time string into the text (right after the cursor)?

2

9 Answers 9

122

:r!date +\%c

see :help :r!

Note, this is for external commands (they run in your shell), not vim commands.

5
  • 5
    date is an external command and ! calls external commands while OP asks for vim commands.
    – Eelvex
    Feb 25, 2011 at 8:51
  • 3
    @eelvex no he didn't. and the ! is a vim, and vi, command. This is the canonical method. Works for many other things as well.
    – Keith
    Feb 25, 2011 at 11:29
  • 6
    @Keith: yes ! is a vi(m) command that calls external commands. You may be right OP not wanting to output only vim commands but if (s)he does, ! will not do.
    – Eelvex
    Feb 25, 2011 at 17:19
  • 2
    You can combine the output of the external command with text you define. For example, the following adds two pound signs and the date of next Tuesday ("## Tuesday, 2020-06-23"): :exe 'r!date --date="next Tuesday" "+\%A, \%Y-\%m-\%d"' | normal I## Jun 21, 2020 at 17:39
  • @Keith No they did not. OP clearly gave an example of a vim command, not a shell command.
    – adamency
    Mar 2, 2023 at 15:29
81

You can use the expression register, "=, with p (or P) in normal mode or <C-R> in insert mode:

In normal mode:
(<C-M> here means Control+M, or just press Enter/Return)

"=strftime('%c')<C-M>p

In insert mode:
(<C-M> has the same meaning as above, <C-R> means Control+R)

<C-R>=strftime('%c')<C-M>

If you want to insert the result of the same expression many times, then you might want to map them onto keys in your .vimrc:
(here the <C-M> and <C-R> should be typed literally (a sequence of five printable characters—Vim will translate them internally))

:nmap <F2> "=strftime('%c')<C-M>p
:imap <F2> <C-R>=strftime('%c')<C-M>
6
  • 3
    +1 Off course! The "= register. :-/
    – Eelvex
    Feb 25, 2011 at 7:42
  • 3
    to get the value of a vim variable (for example, sessionoptions): <C-R>=&sessionoptions -- it even does wildmode tab-completion! Oct 25, 2012 at 18:22
  • 6
    :put =strftime('%c')<C-M>
    – brunch875
    Aug 13, 2015 at 19:23
  • In insert mode, using <c-r>= is slow for command which may have a lot of output and also may break indent so that the output text is unreadable. For example, <c-r>=execute('nmap'), the output will be written line by line, which is very slow.
    – jdhao
    Apr 24, 2019 at 8:51
  • For some reason, this just doesn't work for me. Any ideas why it wouldn't work?
    – trusktr
    Dec 28, 2020 at 22:48
19

If you want to insert the output of a vim command (just like stdout in shell, and as opposed to the return value of a function call or an expression), you have to capture it. This is accomplished via the :redir command, which allows you to redirect vim's equivalent of standard output into a variable, file, register, or other target.

:redir is sort of painfully inconvenient to use; I would write a function to encapsulate its functionality in a more convenient way, something like

funct! Exec(command)
    redir =>output
    silent exec a:command
    redir END
    return output
endfunct!

Once you've declared such a function, you can use the expression register (as explained by Chris Johnsen) to insert the output of a command at the cursor position. So, from normal mode, hit :put =Exec('ls') to insert the list of vim's current buffers.

Be aware that the command will execute in the function namespace, so if you use a global variable you will have to explicitly namespace it by prefixing it with g:. Also note that Exec(), as written above, will append a terminating newline to even one-line output. You might want to add a call to substitute() into the function to avoid this.

Also see https://stackoverflow.com/questions/2573021/vim-how-to-redirect-ex-command-output-into-current-buffer-or-file/2573054#2573054 for more blathering on about redir and a link to a related command.

3
  • 2
    This works great. I added a set paste command before returning the output and a set nopaste after, to avoid the staircase indent when the lines start with blanks. Actually, I wanted to save the value of the current paste option and to return it but I was unable to do it so.
    – Juan Lanus
    Jan 5, 2015 at 21:17
  • 1
    @JuanLanus The set nopaste shouldn't work after return output, because the return statement is an exit point out of the function. I've put my solution to this problem as a separate answer on this page. Apr 23, 2015 at 4:57
  • Instead of i^R=Exec('ls'), try :put =Exec('ls'). That should avoid the need to for setpaste.
    – idbrii
    Apr 26, 2020 at 20:29
12

These commands will insert the output of strftime("%c") right where your cursor is:

:exe ":normal i" . strftime("%c")

and

:call feedkeys("i". strftime("%c"))

There are other ways to do what you want (like, for example, those on Mikel's answer).

Edit: Even better, for in-place insert, use the = register as Chris Johnsen describes

2
  • How can we pipe vim command output (f.e. output of echo "foo", instead of strftime("%c")) to the buffer?
    – trusktr
    Dec 28, 2020 at 22:47
  • @trusktr feedkeys("i"."foo")
    – Eelvex
    Dec 29, 2020 at 20:00
6
:call append(line('.'), strftime("%c"))

Will put it on the next line, then you could press J (Shift+J)to join it up to the current position.

Or if you need it all in one command, you could do

:call setline(line('.'), getline(line('.')) . strftime("%c"))

or

:call setline(line('.'), getline(line('.')) . " " . strftime("%c"))

depending on whether you want a space inserted before the date or not.

5

You can use :put with the expression register =:

:put =strftime('%c')

This method allows you to make an alternative command to :echo called :InsertExpr that would insert your expression:

command! -nargs=* InsertExpr put =<args>

Or to insert commands like :ls:

command! -nargs=* InsertCmd put =execute('<args>')

(Not sure why I can't get q-args to work.)

Usage:

:InsertExpr strftime('%c')
:InsertCmd ls
4

Improving @intuited answer to avoid the problem with leading whitespace and growing indent:

"Examples:
":call Exec('buffers')
"This will include the output of :buffers into the current buffer.
"
"Also try:
":call Exec('ls')
":call Exec('autocmd')
"
funct! Exec(command)
    redir =>output
    silent exec a:command
    redir END
    let @o = output
    execute "put o"
    return ''
endfunct!

This will simply insert at the current location in the file when you :call Exec('command') from normal mode. As noted in the comment, the original (insert-mode) Ctrl+R =Exec('command') approach with Exec(..) returning a string could be partially corrected by using set paste, but doesn't offer an opportunity to put the set nopaste anywhere.

The let @o = output syntax sets the register o to the contents of the variable output, as explained here: https://stackoverflow.com/a/22738310/1143274

The return '' line is so that the default return value of 0 doesn't get inserted to the buffer.

2

This is how I do it. It puts it right after the cursor because it uses p.

" save previous yank
let reg_save = @@

" save your text to the '@' register
let @@ = strftime('%c')
" paste it after the cursor
exec "normal! p"

" restore previous yank
let @@ = reg_save
1

If you end up mapping it at the end then there is a nicer way.

inoremap <expr> <C-f> strftime('%c')

This is quite general, just substitude your binding for Ctrl-F and your function for strftime('%c').

You must log in to answer this question.

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