2

In a Vim function, I want to append \ and carriage return after AND.

I modify the line using the following expression:

let new_line = substitute(new_line, ") AND (", ") AND \\\n (", "g")

Now new_line contains multiple lines.

How to swap the current line with the content of new_line?

Currently I have to run the below commands to output multiple lines:

let new_line = substitute(new_line, ") AND (", ") AND \\\\r (", "g")
:call setline(".", new_line)
:s/\\r/\\\r/g

2 Answers 2

1

You might know; but always remember that when operating on strings in VIM script most (all?) functions do not know or care about what a line is.

https://vimhelp.org/builtin.txt.html#string-match

There is a layer between buffer and file written to disk. When a file is read into a buffer VIM detects line-endings, fileformat, and replaces them internally; As to mean a buffer is end-of-line byte(s) agnostic. Look at it as a list. When writing to disk the lines are joined by <EOL> according to fileformat.

When one are working with string functions like substitute() etc. VIM does not know (or try to detect) what line endings are, e.g. \n vs \r\n. This is also why one typically use lists instead of strings when working with multiple lines in buffers from scripts. This way one do not need to worry about fileformat. One typically get multiple lines as a list and put multiple lines using lists. This is also why for example $ does not mean end-of-line in a string, but end-of-string, \n means literal LF / 0x0a and not end-of-line etc.

Also note for example :h substitute()

[…] the matching with {pat} is always done like the 'magic' option is set and 'cpoptions' is empty (to make scripts portable).

You have some options e.g. append() and setline(). Both can take a list as input. For example by using append() you can do something like:

"" Get line, substitue and split to list
let list = getline('.')
    \ ->substitute(') AND (', ') AND \\\n(', 'g')
    \ ->split('\n')
"" Delete current line
delete _
"" Append
call append(line('.') - 1, list)

Note that if you use setline() you would first have to make room for the new lines as it replaces (set) lines.

2
  • Apology my fault, I want a single '\'. Question updated.
    – Fisher
    Commented Dec 22, 2023 at 9:53
  • @Fisher No worries. Updated. Only sample code anyway. Hope my ramblings are readable ;), - my phrasings could have been better. Commented Dec 22, 2023 at 20:35
1

I would do:

let n = line('.')
let new_lines = split(new_line, ') AND \zs\ze(')
for i in range(len(new_lines) - 1)
    let new_lines[i] = new_lines[i] . '\'
endfor

call deletebufline('%', n)
call appendbufline('%', n - 1, new_lines)

Here is some explanation about the steps:

  1. The split call split your line into subline with ) AND ( as separator.
  2. The \zs makes that the separator stay with the previous line.
  3. The deletebufline deletes the current line.
  4. The appendbufline insert the new lines.

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.