Describe the bug
In Vim9 script, we cannot use a backtick expansion in a :folddoopen command, nor in a :folddoclosed command.
To Reproduce
Run this shell command:
vim -Nu NONE -S <(cat <<'EOF'
vim9
def Func()
var name = 'test'
folddoopen echo '`=name`'
enddef
Func()
EOF
)
This is echo'ed:
`=name`
Expected behavior
test is echo'ed.
Environment
Additional context
The same backtick expansion works fine in a global command:
vim9 def Func() var name = 'test' g/^/echo '`=name`' enddef Func()
test
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub, or unsubscribe.![]()
I don't think
=expris evaluated for an :echo command.
Yes, in Vim script legacy, I think a backtick expansion is only evaluated for a command which expects a filename, like :edit and :vimgrep. :echo does not expect a filename but an expression, therefore a backtick expansion should not work after :echo.
Nevertheless, I still thought it would work for several reasons.
First, it already works in a global command:
vim9 def Func() var name = 'test' g/^/echo '`=name`' enddef Func()
test
Second, it was mentioned in this comment:
The value of the variable is inserted in place, thus if you want to use
it as a string you need to add quotes:
def Func()
var name = 'test'
g/^/echo "=name"
enddef
Third, it is documented as working in the replacement field of a substitution command:
And indeed, it works as documented:
vim9 def Replace() setline(1, 'pattern') var newText = 'blah' g/pattern/s/^/`=newText`/ enddef Replace() echo getline(1)
blahpattern
But this doesn't work in Vim script legacy:
fu Replace() call setline(1, 'pattern') let newText = 'blah' g/pattern/s/^/`=newText`/ endfu call Replace() echo getline(1)
`=newText`pattern
Which means that the syntax has been made valid in more contexts than it was initially designed for. As I didn't know which contexts it was valid in, I assumed it was valid everywhere.
Fourth, we can no longer access a function-local variable in a command which is executed in the global context like :g or :s. For those cases, the backtick expansion could be useful.
That being said, I can understand that we don't allow the syntax to work in too many places, to avoid unexpected expansions. And I don't mind if it's limited to commands expecting filenames as arguments and the replacement field of :s. That's because it doesn't always work anyway. For example, the last time I was tempted to use it, I had to execute an assignment in a :folddoclosed and a :folddoopen command; but the assignment involved a function-local dictionary variable:
" inside a function
let state = {'open': [], 'closed': []}
folddoclosed let state.closed += s:get_state('closed')
folddoopen let state.open += s:get_state('open')
The code worked fine in Vim script legacy, but not in Vim9. I wasn't able to use a backtick expansion either. So, in the end, I moved the function-local variable to the script-local namespace:
# at the script level
var state: dict<list<number>>
# inside a function
...
state = {open: [], closed: []}
folddoclosed state.closed += GetState('closed')
folddoopen state.open += GetState('open')
...
I think this is the general solution for this kind of issue. I have yet to find a single case where it didn't work.