! in specific, you're mixing up the
append() function (which you can use with
:call) with the Ex command
:append. While they have the same name, they're pretty different things (as in general, in Vimscript, with functions and Ex commands.)
Functions such as
setline() will typically not preserve indentation. For one thing, since they can append or modify an arbitrary line of the buffer, which indentation to copy might be a hard question to answer... Also, Vimscript functions typically try to depend less on the behavior of options such as
'autoindent' and friends.
So, if you want to use the
append() function and preserve indentation of the current line, you have to do that yourself. You can, for instance, use the
indent() function, which will return the number of spaces that are equivalent to the indentation of the current line, together with the
repeat() function to prepend those spaces into the appended string:
:call append(repeat(' ', indent('.')) . 'string_output')
There are quite a few limitations to this approach. For one, this will always indent using spaces and not tabs (regardless of the
'expandtab' setting), it will also indent unconditionally regardless of the
'autoindent' setting and will also only copy indentation of the current line and not respect
'indentexpr' which might decide on a different indentation for the next line...
For those reasons, it's often more productive to use an Ex command or a normal mode command (such as
i or, in this case,
o) to append or modify lines, when you want to preserve indentation and other features of the text that Vim typically managed during normal text editing.
The interface for
:append is a little awkward (entering multiple lines ending on a line with just a dot), but it's still possible to use it from a mapping:
nnoremap <silent> xx :append<CR>string_output<CR>.<CR>
It might be easier to use the
o Normal mode command though:
nnoremap xx ostring_output<Esc>
You also mentioned the
:append, but note that
:append will by default do whatever the current
'autoindent' setting is set to do (either preserve or ignore indentation), so typically that's what you want... The
:append! command will do the opposite of the current
'autoindent' setting, but in a sense it still depends on it.
I also imagine that the
string_output in your question is just an example. Using the result of a function or an expression is much easier in a function call such as
append(), but still can be done in
o by using the
<C-R> shortcut to recall the contents of a register, possibly combined with the expression register
= which allows you to enter an expression.
nnoremap <silent> xx :append<CR><C-R>='string_output'<CR><CR>.<CR>
(Note you need two
<CR>s in a row, one to finish entering the expression for the expression register, and another to finish entering the line in
nnoremap xx o<C-R>='string_output'<CR><Esc>
In these examples, I still used
'string_output', but hopefully it's clear that any other valid Vimscript expression would be also possible here.