0

How can I set a variable that only the current command line sees?

So that

:let s:one = 1 | echo s:one prints 1

but running two commands

:let s:one = 1
:echo s:one

errors E121: Undefined variable: s:one.

In the end I would like to remap to a command line that uses a temporary variable, without overriding or polluting any potential other user variables.

5
  • Could you explain why the first solution is not good enough? Where will the script will be defined: 1. in a one line mapping, 2. in a script file? How much persistent must the variable be: 1. in the call, 2. in the buffer lifetime, 3. in the Vim lifetime Apr 21, 2023 at 14:13
  • 1
    @VivianDeSmedt I get Illegal variable name: s:one when I try the first solution. The variable should only be as persistent as the call. I'm just defining a mapping like this in my vimrc xnoremap <silent> il :<C-u>let s:one ...
    – minseong
    Apr 21, 2023 at 14:27
  • Do we need a gensym ?? Typically you use a unique prefix based on the plugin name or your initials or something.
    – D. Ben Knoble
    Apr 21, 2023 at 15:39
  • @D.BenKnoble I don't know what gensym is
    – minseong
    Apr 21, 2023 at 17:14
  • In Lisps and Schemes it gives you a guaranteed unique symbol
    – D. Ben Knoble
    Apr 22, 2023 at 1:47

2 Answers 2

1

Here is what I could propose:

function! Variable(...)
  if a:0
    let x = a:1
  else
    let x = 0
  endif
  function! Set(...) closure
    if a:0
      let x = a:1
    endif
    return x
  endfunction
  return funcref('Set')
endfunction

With this Variable function you can create a variable that don't clutter the global workspace:

let X=Variable(4) " Initialize X to 4
call X(7) " Change X to 7
echo X() " Get the value of X
2
  • 1
    If "X" exists and is a variable then it will get overwritten by a funcref. So it is not a valid solution, I think.
    – Matt
    Apr 21, 2023 at 15:19
  • 1
    You are right :-) I move the problem from variables to functions but the clutter problem remains :-| Apr 21, 2023 at 15:23
1

I am guessing that a simple "echo" is not the extent of what you want to do with the assigned value.

But addressing only what is in your question... why not go to the shell for this?

:!one=1; echo $one

If your larger plan can still work in the shell, then you simply capture it right below the current line with a leading :r :

:r !one1; echo $one
If on windows...

OS limitations here require delayed variable expansion
(which is the /v:on option to cmd.exe):

:r !cmd /v:on /c "set one=1 & echo \!one\!"

(escaping to prevent previous-command-substitution, see :h :!)

If you add the cmd option to your 'shellcmdflag' setting, then it's just:

:r !set one=1 & echo \!one\!

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.