I have a user command that grep-replaces files recursively using vimgrep
and cfdo
:
-- Grep
vim.api.nvim_create_user_command(
'Grep',
function(opts)
if #opts.fargs < 1 then
print("Usage: :Grep(!) <pattern> <filter?>, i.e. :Grep /my_string/g **/*, or :Grep! /my_string/my_replacement/g **/*")
return
end
local pattern = opts.fargs[1]
local filter = opts.fargs[2] or "**/*"
local segmno = 1
local searchpatt = nil
local replpatt = nil
local flags = nil
for pattsegm in string.gmatch(pattern, "([^/]+)") do
if segmno == 1 then
searchpatt = pattsegm
elseif segmno == 2 then
if not opts.bang then
flags = pattsegm
else
replpatt = pattsegm
end
elseif segmno == 3 then
flags = pattsegm
else
break
end
segmno = segmno + 1
end
if searchpatt and flags and filter then
vim.cmd(":vimgrep /" .. searchpatt .. "/" .. flags .. "j " .. filter)
vim.cmd(":cw")
vim.cmd(":.cc")
if opts.bang and replpatt then
vim.cmd(":cfdo %s/" .. searchpatt .. "/" .. replpatt .. "/" .. flags .. "e")
end
end
end,
{ nargs = '*', bang = true }
)
This works all fine until I want to replace a pattern with something that has a space in it, because it will shift my arguments, such as:
:Grep! /my\_s*string/my replacement/g **/*
Obviously, opts.fargs[1]
is only /my\_s*string/my
instead of /my\_s*string/my replacement/g
.
I tried wrapping the first argument into '...'
without success. How can I pass an argument that contains spaces to the user command?
<f-args>
or<q-args>
/my\_s*string/my\ replacement/g **/*
:Grep! '/dotenv\.env\['REQUEST_TIMEOUT'\]/\0\ ??\ "30"/g' **/*.dart
, but it messed up complaining aboutTrailing characters: \0 ?? "30"e
. I'm not very sure why.opts.args
are all args as one string, so I can find the right split, but it seems not as trivial giving the fact that the substitute delimiter can vary.