passing arguments to @command

56 views
Skip to first unread message

jkn

unread,
Dec 9, 2024, 4:36:37 PM12/9/24
to leo-editor
I've been meaning to ask this for ever...Is there a way to pass argument(s) to leo @command-s?

If I have a node like

@command test_args
        import sys
        g.es(sys.argv))

and run "test_args 1 2 abcd"

none of "1 2 abcd" get printed - only sys.argv from the initial invocation of Leo.

is there a way for something like this to work? Apologies if it is already documented, I cannot find it.

    Thanks
    Jon N

Thomas Passin

unread,
Dec 9, 2024, 4:58:06 PM12/9/24
to leo-editor
There's a node in LeoDocs about getting arguments.  Look for the headline "Getting interactive input in scripts and commands".

sys.argv will give you the arguments that the Python interpreter received at startup.

Another way I've passed arguments to a script is via the clipboard, but of course you have to get them into the clipboard first.

jkn

unread,
Dec 9, 2024, 5:38:01 PM12/9/24
to leo-editor
Thanks for the pointer Thomas.

That looks like not exactly what I am thinking of - it seems to be oriented towards "command<return>argument1<return>argument2<return>" in the minibuffer. I confess I have never used a Leo command that operates in that way! my loss, I am sure.

I am thinking more of "command arg1 arg2 arg3<return>" - so 'non-interactive', perhaps. But perhaps the available mechanisms will provide that, Ii will have a read.

    Regards
    J^n

Thomas Passin

unread,
Dec 9, 2024, 6:02:21 PM12/9/24
to leo-editor
If you use Find/Replace, it picks up the arguments from the minibuffer the same way.  There's nothing to stop you from asking for an argument, inputting all of them, and having your command extract them all.

Hmm, I tried a command and added some text after its name in the minibuffer after the command's name (I used vr3-show).  The command executed.  Maybe your script could read the contents of the minibuffer, move past the its own name, and get the args from the rest of the input. You would have to find the widget name of the minibuffer single line edit.  I don't happen to know it.

Thomas Passin

unread,
Dec 9, 2024, 6:31:11 PM12/9/24
to leo-editor
I found it.  Here's how you can get the text of the minibuffer's line editor.  What I don't know is whether it will still  be there once your command starts executing.  You can try that for yourself.

# type some text into the minibuffer before executing the following
le = c.frame.top.lineEdit
g.es(le.text())

jkn

unread,
Dec 10, 2024, 3:43:48 AM12/10/24
to leo-editor
Thanks Thomas, I will take a look at this.

My original motivation for this is that I have a small script which could benefit from exhibiting 'variant behaviour'. I was thinking of either invoking via the minibuffer: "mycommand parm", or via a set of custom menu entries, each of which invoked the command with a different parameter. I guess the latter is not going to work via parsing the minibuffer.

    Regards
    J^n

jkn

unread,
Dec 10, 2024, 4:45:30 AM12/10/24
to leo-editor
PS: doesn't look like c.frame.top.lineEdit.text() gives anything useful from within a command ;-(

Edward K. Ream

unread,
Dec 11, 2024, 11:23:09 AM12/11/24
to leo-editor
On Monday, December 9, 2024 at 3:36:37 PM UTC-6 jkn wrote:

I've been meaning to ask this for ever...Is there a way to pass argument(s) to leo @command-s?

Hi Jon,

Good question. The short answer is "no", but there are workarounds.

I often use bespoke scripts that I customize by hand. For example, here is a script that I use to import multiple files:

@language python
"""Recursively import all python files in a directory and clean the result."""
@tabwidth -4 # For a better match.
g.cls()
dir_ = r'<<path to a folder>>  # <--- customize as needed
c.recursiveImport(
    dir_=dir_,
    kind = '@clean', # '@auto', '@clean', '@nosent','@file',
    recursive = True,
    safe_at_file = True,
    theTypes = ['.py',],
    verbose = True,
)
if 1:
    last = c.lastTopLevel()
    last.expand()
    if last.hasChildren():
        last.firstChild().expand()
    c.redraw(last)
print('Done')

I will typically execute this script several times, so it would be less convenient to "generalize" it by asking for a path.

Other workarounds

It's almost always simplest to write your own scripts. But if you really want to write a general command, Leo provides ways to do that.

The big hint: look for code in Leo's codebase that does something similar to what you want. For example, Leo's find commands prompt for one or more arguments. The code isn't pretty. find.find-next and find.change-all show how to set up the required state machines.

The node c.interactive* in leoCommands.py contains helpers that set up state machines.

Summary

Writing bespoke scripts is almost always the simplest solution.

Other solutions involve state machines. I would only consider such approaches in extraordinary circumstances.

HTH.

Edward

jkn

unread,
Dec 11, 2024, 12:03:30 PM12/11/24
to leo-editor
Thanks for the comments/encouragement Edward

    I too have a few scripts such as the above, which I customise on an ad hoc basis. I'm not trying to eliminate that kind of fun ;-). This is for the situation when I have a few fixed variants of operation.

I am making progress my following Thomas' pointer to the use of k.get1arg, to prompt and get a return parameter from the minibuffer. As mentioned this is not my favourite approach, but it will do as a start.

Thanks for the pointer to the use of c.interactive.* . I enjoy wandering down these little passages of Leo's design...

PS: TIL about g.cls(), used in your script above! ;-)

    Regards
    Jon N

Thomas Passin

unread,
Dec 11, 2024, 12:51:57 PM12/11/24
to leo-editor
You could also have your script pop up a dialog to type the args into.

jkn

unread,
Dec 11, 2024, 5:39:55 PM12/11/24
to leo-editor
agreed - I already have some scripts like that. In fact I have occasionally wondered about suggesting a simple 'dialog description language' to allow more complicated dialogs than are currently available to be created.

Still not quite what I want on this occasion though ;-)
Reply all
Reply to author
Forward
0 new messages