Command To Run External File

110 views
Skip to first unread message

Thomas Passin

unread,
Feb 6, 2023, 1:18:42 AM2/6/23
to leo-editor
I've been working on a command to run an external file (@file, @clean ...).  I think it is ready, and I'd appreciate it if other folks could test it for me.  The idea is that you select a node in the external file tree and launch the command.  It works on Windows and Linux but not Mac (I need more information about the Mac, and I don't have one for testing).

As long as the processing program such as Ruby, Python, Julia, is on the path (and the file is a known file type) - or you specify it in a @data setting node - a new terminal will open, run your GUI or console program, and wait for you to close it.

The new command is the @button node in the attached Leo outline.  I suggest copying in into the @buttons tree in your myLeoSettings.leo outline and restarting Leo.

The languages it can handle without adding an @data node - it's documented in the command's docstring - are python, shell, batch (for Windows), ruby, lua, and julia.

Here are some technical details -

This command was hard to get working right on Linux (and I can't swear that it will work on Linux if the external file name has spaces), and the reason was my requirement to open a new terminal and keep it open after the external program finishes.  I want that so that any output can be seen and studied.  

It's easy to launch a program and have it write to Leo's own console, but that is not ideal, because 1) other Leo output may get mixed in with the external program's or the output may get scrolled offscreen; 2) if the external program crashes, it may leave your Leo console running a secondary shell; and 3) if you launch a GUI program that lasts a long time your output may get very confusing.

It turns out that to reliably keep the new terminal open on Linux, you have to open a terminal and use that to run the shell, not just launch the shell.  This is a problem because there are a lot of Linux distros and they don't all have the same terminal.  In particular, the different terminals don't always use the same options to run a shell with its command line.  The shell may also differ.  Almost all desktops use bash, usually at /usr/bin/bash, but a user can change that and some do.

So we can't assume that the shell will be bash, nor what the terminal may be.  x-terminal-emulator does not give you the same options across distros, either.  $TERM doesn't actually give you the terminal either, just a logical terminal so the right colors can be set up. 

To keep the terminal open after the command runs, some terminals have an option for that, some have the option but it doesn't work, and some don't have the option. Also, the option name is subject to change (I found at least one distro that issued a deprecation warning) So we need another solution.  My solution is to have the shell wait for user input after the main command finishes.  After a long time running queries on the Internet I have not found a more workable way.

So how do we find the terminal and shell?  By running pstree -s $$ and parsing its output.  Then we run that terminal with --help and try to parse the help message to find the right option.  This works on all cases I've tried, but it's probably a little fragile.

If the shell isn't bash, or we can't figure it out, we use the $SHELL variable.

Then we use the command's internal table, or the system file association, to find the right processor to run.  We also check to make sure it can actually be found.

Finally we can construct the command and run it.  Whew, that was tricky!  It's easier on Windows because we don't have to discover the terminal and shell, and the launch options are always the same.

For the Mac, I don't know the terminal or shell names nor the right options to invoke.  I'm pretty sure that if I learn them this command will work on a Mac too.

x-run-ext-file.zip

jkn

unread,
Feb 6, 2023, 4:15:40 AM2/6/23
to leo-editor
I'll give it a try (kubuntu linux, mainly) and let you know what I find...

Thomas Passin

unread,
Feb 18, 2023, 9:27:15 PM2/18/23
to leo-editor
If nobody complains about it in another week, I'll package it up as a new Leo command.

jkn

unread,
Feb 19, 2023, 12:38:04 PM2/19/23
to leo-editor
sorry, I have installed it but not tried it. I'll give it a go this week

Thomas Passin

unread,
Feb 19, 2023, 1:01:56 PM2/19/23
to leo-editor
Thanks, I'd appreciate it.

SegundoBob

unread,
Feb 19, 2023, 7:02:19 PM2/19/23
to leo-editor
Your "Execute script" code works well for me when I use it from a Leo-Editor file that I open from a terminal, but it does not work when I use the file browser Thunar to open the Leo-editor file.

When I invoke your script from a Leo-Editor file opened by Thunar, I get this error message even when the script is not a Bash script:

```
exception executing script
Traceback (most recent call last):
  File "/pri/git/leo-editor/leo/core/leoCommands.py", line 732, in executeScript
    c.executeScriptHelper(args, define_g, define_name, namespace, script)
  File "/pri/git/leo-editor/leo/core/leoCommands.py", line 771, in executeScriptHelper
    exec(compile(script, scriptFile, 'exec'), d)
  File "/sec/tmp/leoScript.py", line 327, in <module>
    runfile(path, processor)
  File "/sec/tmp/leoScript.py", line 298, in runfile
    term = getTerminal()
  File "/sec/tmp/leoScript.py", line 215, in getTerminal
    shell_index = words.index(shell_name)
ValueError: 'bash' is not in list
only 8 lines
--------------------
  line 214:
* line 215:     shell_index = words.index(shell_name)
  line 216:     term = words[shell_index - 1]
  line 217:     return term
```

Test System:
```
Ubuntu 20.04
Leo Log Window
Leo 6.6.3-devel, devel branch, build 4eaacdf7e5
2022-06-29 04:10:01 -0500
Python 3.8.10, PyQt version 5.12.8
linux
```
Regards,
SegundoBob

Mike Hodson

unread,
Feb 19, 2023, 8:02:47 PM2/19/23
to leo-e...@googlegroups.com


On Sun, Feb 19, 2023, 17:02 SegundoBob <segun...@gmail.com> wrote:
Your "Execute script" code works well for me when I use it from a Leo-Editor file that I open from a terminal, but it does not work when I use the file browser Thunar to open the Leo-editor file.

When I invoke your script from a Leo-Editor file opened by Thunar, I get this error message even when the script is not a Bash script:

My first feeling here is that there are some commands or variables that would be populated in an interactive shell session's environment but do not exist in a non-interactive shell session.

I will take time tonight to try this out myself. I haven't had a need to use Leo in a long time but to help debug this issue I will make that change.   I'm not great at Python, but I do understand some of the complexities of making things work on Linux. 

Mike

Thomas Passin

unread,
Feb 19, 2023, 9:25:25 PM2/19/23
to leo-editor
" but it does not work when I use the file browser Thunar to open the Leo-editor file".  I don't understand what you mean here, @SegundoBob.  The intended use is to select  - within Leo -  a node in an external file, and have it run in (or get launched by) a terminal.   How does the file browser fit into this?  Would you explain it for me with some more detail? 

To launch a file with some processor like say Ruby or Python, and have the terminal stay open after the program finishes, the only reliable way I have found so in Linux far is to open a terminal with a command that will open a shell which in turn will launch the program and wait for user input (so the terminal will stay open).  If you are trying to include a third program (the file browser) in that chain, I suppose I'm not surprised if it won't work.  The command line to be passed to the terminal would probably need to be pretty complicated (with respect to quoting especially.



Segundo Bob

unread,
Feb 20, 2023, 8:09:22 AM2/20/23
to leo-e...@googlegroups.com
On 2/19/23 18:25, Thomas Passin wrote:
> " but it does not work when I use the file browser Thunar to open the
> Leo-editor file".  I don't understand what you mean here, @SegundoBob.

Your "execute external script" is invoked while running Leo-Editor. If
you start Leo-Editor from a terminal command line, your "execute
external script" works as intended. If you start Leo-Editor by
selecting a Leo-Editor file with a browser, then your "execute external
script" does NOT work as intended. The difference is probably that
Leo-Editor does NOT have a terminal in the non-working case.
--
Segundo Bob
Segun...@gmail.com

jkn

unread,
Feb 20, 2023, 11:49:19 AM2/20/23
to leo-editor
I am seeing something similar to SegundoBob. I also tried it with a trivial python script. To spell out the details:

(I run Kubuntu Linux)

Leo Log Window
Leo 6.7.2-devel, devel branch, build 4e9b1569de
2023-01-25 08:35:46 -0600
Python 3.10.6, PyQt version 5.15.3
linux


1) I make a node

    @clean {{g.app.homeDir}}{{sep}}tmp{{sep}}test_leo.py

2) the contents of that node are:

#! /bin/env python3

print("Hello Leo shell world")

3) I save my Leo file and get the .py file created (I checked)

4) when I have tree focus on that node and press the x-run-ext button, I see in the log:

exception executing script


ValueError: 'bash' is not in list

only 6 lines

--------------------
  line 214:
* line 215:     shell_index = words.index(shell_name)
  line 216:     term = words[shell_index - 1]
  line 217:     return term


This is with Leo invoked via a desktop shortcut

HTH, Jon N

Thomas Passin

unread,
Feb 20, 2023, 11:50:19 AM2/20/23
to leo-editor
Oh, I understand now.  Thank you.  I'll see what can be done.

Thomas Passin

unread,
Feb 20, 2023, 5:58:11 PM2/20/23
to leo-editor
@mike, that was a good diagnosis.  When Leo is not run from a terminal (in Linux), the process space does not include a terminal and the shell may not even be the same shell (e.g., sh instead of bash) as one might expect.

I have revised the terminal-finding code for Linux to try several heuristics, starting with the same one as @SegundoBob tried.  After failing that, it looks in /usr/bin and /bin for a name starting with either *-terminal or *term.  That will find, e.g., gnome-terminal, xfce-terminal, or uxterm. Failing that, it looks for xterm using shutil.which().  If none of them can be found, the script exits with an error message.

The reason for all this is that 1) a distro might not even have xterm (I've seen it), x-terminal-emulator,  or xdg-terminal (or if it has them, they don't always open right), and 2) the terminal program or link might not be in /usr/bin or /bin.

This is still not guaranteed to succeed, since it won't find, e.g., konsole.  I may hard-code a few more well-known names but there are so many possibilities that you can't be sure you can handle every variation out there.  I haven't so far found a more general solution on the internet.  There ought to be a way because the OS knows what terminal to launch by default.  There just doesn't seem to be a standardized way to find out from Python - as opposed to clicking on "About" in a terminal.

The attached outline has the new version, which succeeds on all the several distros I've tried even when Leo is not launched from a terminal.  Please try it out!

On Sunday, February 19, 2023 at 8:02:47 PM UTC-5 mys...@gmail.com wrote:
get-ext-file.leo

SegundoBob

unread,
Feb 20, 2023, 7:06:26 PM2/20/23
to leo-editor
Thomas Passin,

Your fix passes all my tests.

You say that you may not always be able to find the terminal program the user wants you to use.  Maybe when you fail to find any suitable terminal program, you should report this to the user and ask him to enter the pathname to the terminal program he wants you to use always.  You should save it so he only has to do this once.  Maybe even when you can find a suitable terminal program, there should be a way for the user to tell you to use the terminal program he wants you to use.

Regards,
SegundoBob

Thomas Passin

unread,
Feb 20, 2023, 7:30:14 PM2/20/23
to leo-editor
That's a good idea!  I think a setting would be the Leonine way to do it.  When I convert this into a Leo command, I'll look at making it happen.

jkn

unread,
Feb 21, 2023, 4:58:47 AM2/21/23
to leo-editor
The updated scripts seems to be working for me as well. It uses 'uxterm',
which I never even knew I had installed!

I agree that an optional setting for the terminal would be a good idea.

J^n

Edward K. Ream

unread,
Feb 21, 2023, 5:45:44 AM2/21/23
to leo-editor
On Monday, February 6, 2023 at 12:18:42 AM UTC-6 tbp wrote:

I've been working on a command to run an external file (@file, @clean ...).  I think it is ready, and I'd appreciate it if other folks could test it for me. 

Thanks to all who have commented. This has been an excellent group collaboration.

Edward

Thomas Passin

unread,
Feb 21, 2023, 8:38:13 AM2/21/23
to leo-editor
Thanks for testing! I was surprised by all the terminals available, too.  On my Mint virtual machine ( I have lightly annotated the responses):
tom@tom-VirtualBox:~$ find /usr/bin -name *term -type f
/usr/bin/setterm          # Not a terminal - controls terminal properties
/usr/bin/xterm
/usr/bin/lxterm
/usr/bin/uxterm
/usr/bin/koi8rxterm       # Apparently a Russian language one

tom@tom-VirtualBox:~$ find /usr/bin -name *-terminal -type f
/usr/bin/xfce4-terminal
/usr/bin/gnome-terminal
/usr/bin/mate-terminal


Reply all
Reply to author
Forward
0 new messages