90

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

Matthias Braun
  • 7,797
  • 7
  • 45
  • 54
xzhu
  • 1,272
  • 2
  • 11
  • 8
  • It's also worth mentioning that this is *not* the same question as [Writing a vim function to insert a block of static text](http://stackoverflow.com/questions/690386/writing-a-vim-function-to-insert-a-block-of-static-text), however some of the answers still apply. – Alastair Irvine Jan 19 '15 at 10:27
  • See also redirecting into a register: https://stackoverflow.com/questions/2573021/how-to-redirect-ex-command-output-into-current-buffer-or-file/4283053#4283053 – NeilG Oct 02 '19 at 02:04

9 Answers9

104

:r!date +\%c

see :help :r!

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

trusktr
  • 4,035
  • 7
  • 29
  • 34
glenn jackman
  • 84,176
  • 15
  • 116
  • 168
  • 5
    `date` is an external command and `!` calls external commands while OP asks for vim commands. – Eelvex Feb 25 '11 at 08: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 '11 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 '11 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## ` – Matthias Braun Jun 21 '20 at 17:39
  • @Keith No they **did not**. OP clearly gave an example of a vim command, not a shell command. – adamency Mar 02 '23 at 15:29
78

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>
Chris Johnsen
  • 19,790
  • 8
  • 63
  • 52
  • 3
    +1 Off course! The `"=` register. :-/ – Eelvex Feb 25 '11 at 07:42
  • 3
    to get the value of a vim variable (for example, sessionoptions): `=&sessionoptions` -- it even does wildmode tab-completion! – Justin M. Keyes Oct 25 '12 at 18:22
  • 6
    :put =strftime('%c') – brunch875 Aug 13 '15 at 19:23
  • In insert mode, using `=` 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, `=execute('nmap')`, the output will be written line by line, which is very slow. – jdhao Apr 24 '19 at 08:51
  • For some reason, this just doesn't work for me. Any ideas why it wouldn't work? – trusktr Dec 28 '20 at 22:48
  • Here is now to insert from normal mode without creating a new line: `:nmap F2 a=strftime('%c')` (For visual mode, use `vmap` and `c` instead of `a`) – Martin Braun Sep 30 '22 at 18:32
18

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.

Good Pen
  • 175
  • 5
intuited
  • 3,488
  • 3
  • 25
  • 36
  • 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 05 '15 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. – Evgeni Sergeev Apr 23 '15 at 04:57
  • `Instead of i^R=Exec('ls')`, try `:put =Exec('ls')`. That should avoid the need to for setpaste. – idbrii Apr 26 '20 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

Eelvex
  • 676
  • 5
  • 13
5
: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.

Mikel
  • 56,387
  • 13
  • 130
  • 149
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.

ruohola
  • 242
  • 2
  • 16
Evgeni Sergeev
  • 1,361
  • 3
  • 10
  • 9
4

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
idbrii
  • 221
  • 1
  • 5
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').

AdminBee
  • 21,637
  • 21
  • 47
  • 71
wos
  • 71
  • 6