6

I am writing a vim script, and I need to insert the contents of a string variable at the current cursor position. What is an appropriate way to do this?

let text = "Lorem ipsum sit dolor amet ..."
" How to insert text at current cursor position?

I know that :read can do something like this, but it is only applicable for inserting text that come from files, not text stored in variables.

3 Answers 3

10

You can do a literal insert of register contents through :help i_CTRL-R_CTRL-R, combined with the expression register (:help quote=) to reference the variable:

execute "normal! i\<C-r>\<C-r>=text\<CR>\<Esc>"

Note that newlines will appear as ^@; if the variable does not contain any other special characters, you could switch to :help i_CTRL-R, which does interpret the variable contents as types (and therefore inserts a newline, but would also interpret stuff like Home etc.)

If you know that the variable contents are just plain text (without any special control characters), you could also just append the variable contents as-is and conclude with <Esc>:

execute "normal! i" . text . "\<Esc>"

Or use the low-level setline(), splicing in the text at the cursor column via string manipulation:

let line = getline('.')
call setline('.', strpart(line, 0, col('.') - 1) . text . strpart(line, col('.') - 1))
8
  • 1
    @MaximKim: You can get away without it, but I prefer to be fully correct. This matters if, for example, you add another :normal later in that function. Commented Nov 8, 2019 at 8:04
  • 1
    It still works without explicit Esc though. fun! Test() let text = "Lorem ipsum sit dolor amet ..." exe 'normal a' . text normal gg endfun
    – Maxim Kim
    Commented Nov 8, 2019 at 8:11
  • 1
    But the help shows example with \<Esc>, so consider me convinced :)
    – Maxim Kim
    Commented Nov 8, 2019 at 8:13
  • 1
    @D.BenKnoble: For the double-quoting and special \<CR> notation. Yes, you could type \<C-r> as ^R instead, but the Enter would be difficult I think. Commented Nov 8, 2019 at 12:55
  • 1
    Ah, for some reason I was thinking normal would interpret <C-r> like a mapping. Ofc. The enter would be done the same way, no problem. But this is cleaner.
    – D. Ben Knoble
    Commented Nov 8, 2019 at 13:03
5

You might go with setline function or simple:

let text = "Lorem ipsum sit dolor amet ..."
exe "normal! a" . text . "\<Esc>"
  • exe (:execute) is to execute vimscript
  • normal! a executes a command as you type in vim (append after cursor)
  • . text then you concatenate your text with normal a. As you would type this text in vim after a.
  • and '\<Esc> to exit insert mode.
2

The following function emulates the behaviour of: i + insert text + Esc.

" Insert text at the current cursor position.
function! InsertText(text)
    let cur_line_num = line('.')
    let cur_col_num = col('.')
    let orig_line = getline('.')
    let modified_line =
        \ strpart(orig_line, 0, cur_col_num - 1)
        \ . a:text
        \ . strpart(orig_line, cur_col_num - 1)
    " Replace the current line with the modified line.
    call setline(cur_line_num, modified_line)
    " Place cursor on the last character of the inserted text.
    call cursor(cur_line_num, cur_col_num + strlen(a:text))
endfunction

Usage:

let text = "Lorem ipsum sit dolor amet ..."
call InsertText(text)

Documentation:

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.