Branching on a boolean option -- without calling the shell

Mnah, I’m thinking further ahead, not just if-then-else: going full Lisp / lambda. A string that can be passed to eval is a lambda expression. Except you can’t return values from def, so you have to pass continuations (i.e. other strings to be eval’d).

This works:

def cps-angle-quote-str -params 2 -override %{
  # continuation in %arg{1}, str in %arg{2}
  eval %arg{1} "<%arg{2}>"
}
cps-angle-quote-str echo 42  # <42>
cps-angle-quote-str 'cps-angle-quote-str echo' 42  # <<42>

… but of course you need to do quoting in general. One can probably build R5RS scheme on top of kakscript.

Ah, I see, sorry, didn’t thought in that direction. Yeah, this might need escaping.

eval does three things:

  • it recombines its arguments into a single string
  • it re-splits them into words according to the regular Kakoune quoting rules
  • it takes the first word as the name of a Kakoune command, and invokes it, passing the rest of the words as arguments.

For example, take a command like:

eval 'echo %{hello' 'world}'
  • eval joins its arguments with spaces:
    • echo %{hello world}
  • eval splits according to the regular quoting rules:
    • echo
    • hello world
  • eval executes the command echo with the argument hello world

eval -verbatim is different; it skips the first two steps entirely, and just invokes the first word as a command. For example, this command:

eval -verbatim 'echo %{hello' 'world}'

…produces this error:

'eval' no such command: 'echo %{hello'

As such, no extra quoting is needed. I modified your example to use eval -verbatim:

def -override -params .. echo-args %{ nop -- %sh{
  env printf '- |%s|\n' "$@" 1>&2
}}

eval -verbatim echo-args 'a ''b'
echo-args 'a ''b'

When I save that to a file and source it, I get the following in the *debug* buffer:

shell stderr: <<<
- |a 'b|
>>>
shell stderr: <<<
- |a 'b|
>>>

Both with eval -verbatim and without give the same result.

1 Like

Yes, yes, eval -verbatim is quite clear. However, for my purposes I need something like

eval -evaled %arg{1} -verbatim "processed-%arg{2}"

(because %arg{1} will contain the continuation, telling the lambda where to pass the processed %arg{2}; this continuation is a string containing multiple commands, see the cps-angle-quote-str example above).

So one argument needs to be evaled, the other not. Thus, presumably, use eval (non-verbatim) and pass %arg{1} but escape the processed %arg{2}.

But once this is done, there will be few limits to what can be expressed in kakscript (unnaturally as CPS is). I’m working on getting a command to reverse the arglist as a first milestone, for example. Anything the basic data-types support should be expressible (i.e. I’m not sure if kakscript has int addition, and if no hack for that can be found, no amount of continuation-style passing will change it)

… actually, that’s not how it seems to work. In reality, just like sh

  • eval splits each of its arguments on (un-quoted, un-escaped) whitespace
  • there is no recombining
  • the first word is taken as the command, the rest as arguments.
def defp -params .. %{ def -override -params .. %arg{@} } -override
defp echo-dbg %{ echo -debug -quoting shell -- %arg{@} }
eval echo-dbg '1st str' '1st\ str' "2nd str" "2nd\ str" %{3d str} %{3rd\ str}

The problem with anything but "" is that it’s impossible to interpolate into them; so for building up commands to be eval’d, only "" can be used. For example:

defp cat %{ eval echo-dbg "%%file{%arg{1}}" }
cat "%val{client_env_HOME}/.bashrc"

Try defining cat without double-quotes. Or calling it as above, for that matter.

**Phew**