11

I have the following in my vimrc:

func! AddSpaceBeforeEqual()
  s/\([a-z)_0-9"'\[\]]\)=/\1 =/ge
endfunc

I'm using vint to lint my vimrc, and got the following warning :

ProhibitCommandWithUnintendedSideEffect Avoid commands with unintended side effects. Avoid using :s[ubstitute] as it moves the cursor and prints error messages. Prefer functions (such as search()) better suited to scripts. For many vim commands, functions exist that do the same thing with fewer side effects. See :help functions() for a list of built-in functions. Google Vimscript Style Guide

However, I do not think that they is a way to do the substitution without using the :s command.

For example, the search() function gives the lines matching a pattern, but there is no way to do substitution. The substitute() function operates on a string, and doesn't substitute on a whole file.

Should I implement a substitute method myself, or is they a smarter way to rewrite my function ?

10

The reason it is warning you about unintended side effects is because :substitute does move the cursor and overwrite the previous search (if used outside of a function). However, this does not mean you shouldn't use it, as you can reverse the side effects of :substitute. For example, here is a function I made that uses the substitute command to strip trailing whitespace:

function! StripTrailingWhitespace()
    " Save cursor position
    let l:save = winsaveview()
    " Remove trailing whitespace
    %s/\s\+$//e
    " Move cursor to original position
    call winrestview(l:save)
    echo "Stripped trailing whitespace"
endfunction

Note that you could also use the :mark command to save the cursor position, but that also means you will be overwriting the mark you decide to use. I haven't used vint before, but one tip on linters is that you can take their warnings with a grain of salt. In this case, it is true that :substitute does have side effects, but they are side effects that can be prevented. Plus, there really is no better way of doing a search and replace in a file anyway.

  • 6
    The last-used search term is automatically restored after leaving a function, so saving & restoring that shouldn't be required when using it inside a function. See :help function-search-undo – Martin Tournoij Dec 24 '15 at 17:30
  • 1
    rather use winsaveview()/winrestview() instead of cursor() – Christian Brabandt Dec 25 '15 at 15:16
5

Here is a simplistic implementation of your function, written with substitute():

function! AddSpaceBeforeEqualInWholeBuffer()
    let l = 1
    for line in getline(1,"$")
        call setline(l, substitute(line, '\([^= ]\)=', '\1 =', "g"))
        let l = l + 1
    endfor
endfunction

Adjust the search pattern to taste.

2

The :s command is a pure Vimscript approach.

My guess is the warning only means, that the cursor will most likely be mispositioned after its useage (which you can circumvent by using the winsaveview() function before and the winrestview() commmand after its usage). Also you need to take care of possible errors that might occur. This is usually handled by using the e flag. Also one needs to take care of some settings like the gdefault setting, which inverts the meaning of the g flag.

One needs to take care of those specifics and that is probably the root cause of those warnings. But that does not mean to avoid the use of the :s command. It is perfectly okay to use :s command, if you want to replace something in the current buffer.

(Note, one could of course loop through all lines and use an search()/getline()/setline() approach. But that is usually slower.)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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