As Ingo Karkat wrote, a solution can be found using c_CTRL-\_e
. Here's the version I'm using, which is identical to the original solution except for the regex pattern. (Since this is really just Ingo Karkat's answer with a modest improvement suggested by Ingo Karkat, I don't think it actually deserves its own answer, but I guess I'm outvoted: http://chat.stackexchange.com/transcript/message/15021397#15021397)
function! TranslateBackslashN()
if getcmdtype() ==# ':' && getcmdline() =~#
\ '[%>]s\([um]\w*\)\?\(.\).\{-}\(\\\)\@<!\2.*\\$'
return getcmdline() . 'r'
endif
return getcmdline() . 'n'
endfunction
cnoremap n <C-\>eTranslateBackslashN()<CR>
Explanation of the regex pattern:
[%>]s
ensures that the replacement only occurs when s
comes immediately after a range
\([um]\w*\)\?
matches variations of the s
command, such as smagic
.
\(.\)
will be the first non-word character, since all word characters will already be eaten by \w
in the optional group. Note that this is group 2
. This is the separator character, which is usually /
. Note that _
, which is a word character, is also a valid separator, so the pattern won't work correctly if _
is used that way. I don't ever use _
as a separator, though, so I'm not going to worry about it. Similarly, there are some characters that are not word characters but which shouldn't be used as separators, but I'm not worried about that here because in that case the command should fail anyway. I wanted to use \W
here, but for some reason that didn't work when I tested it.
.\{-}
should match the pattern (\{-}
is like Perl's *?
).
\(\\\)\@<!\2
matches the next instance of the separator character not preceded by a back-slash. The Perl equivalent would be (?<!\\)\2
.
.*
matches whatever is in the replacement string so far.
\\$
matches only if the command so far ends with a backslash.
c_CTRL-\_e
withgetcmdline() =~#
, not the details of the regex used, I don't think it deserves its own answer.