98

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

xzhu
  • 1,362

9 Answers9

117

:r!date +\%c

see :help :r!

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

trusktr
  • 4,165
glenn jackman
  • 85,964
  • 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
80

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
  • 20,101
  • 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): <C-R>=&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 <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 '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<C-r>=strftime('%c')<C-m><C-c> (For visual mode, use vmap and c instead of a) – Martin Braun Sep 30 '22 at 18:32
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.

Good Pen
  • 205
intuited
  • 3,538
  • 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
  • 686
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.

Mikel
  • 57,299
  • 15
  • 134
  • 153
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
idbrii
  • 231
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
  • 282
Evgeni Sergeev
  • 1,371
  • 3
  • 10
  • 9
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
  • 22,803
wos
  • 181