(The future of) Scripting in Haiku

I agree, maybe because Haiku’s scripting system might look a bit convoluted. I mean the whole set of commands, properties, specifiers and suites.
One could argue that it can be simply achieved with accepting well defined and documented messages in BApplication. So probably this has to do with the lack of a built-in “standard” scripting language as opposed to AmigaOS with ARexx and MorphOS with Lua.
We do have BRexx which supports Haiku scripting and ports but it’s not a great language. IMHO. We also do have Lua but no bindings to BMessenger and BMessage. There was an attempt to bring these to Lua which came to naught.
But now we have PyAPI and Python looks a good language to script applications. I think it’s time to give it a try.

1 Like

It doesn’t, it implements its own thing that’s more similar to how AREXX works on Amiga systems.

No, not really. The idea of scripting (the initial idea, not the hacky way it ends up being used currently) is that each application defines custom properties that are related to whatever the application is doing. If done correctly, the interface that each application exposes would be what you need for a script using this application, and things would be a lot simpler.

Currently, very few applications do this, and people will abuse hey to just send normal BMessage, or use the default scripting that allows to locate a specific button in a window and click it. Of course, when doing it this way, things are a bit obscure and complicated, because this interface was not designed for that usage.

The very idea of scripting is that applications provide non-standard, custom and specific things. All the scripting system provides is a framework that should make these things self-documenting (thanks to the “getsuites” request). So, at the low level, this is already a set of well defined and documented messages. But, it provides a framework to expose so much more, in a very expressive and flexible way.

Now the responsibility is on the side of C++ application developers to expose more things through scripting. This doesn’t really happen because few people use scripting, and those who do, got used to the hacky way of looking at the app sourcecode to figure out which view to target and which message to send. So, an application not using scripting has become “acceptable” to them, and as a result, application developers don’t get much requests to develop a proper scripting interface. And there are also not many examples to get inspiration from.

If this was done correctly, simple commands like “hey MediaPlayer NextTrack” would work (useful to wire some shortcut key to that). Or “hey MediaPlayer GET Title OF CurrentSong” (probably useful for sending it over IRC with a special command in Vision, I guess? Or showing it in some replicant, or LCD display attached to the machine or whatever).

4 Likes

Thanks just wanted to say that scripting is actually very natural and powerful the way BeOS implemented it, and actually similar to the tell command on MacOS.

I’ll need to patch some apps to make them behave correctly😏 so they can be integrated better with SEN. Sadly, even the standard apps are not really following the suites approach, and e.g. BePDF ignores the command line parameter page and doesn’t provide a way to navigate via scripting.

Just compare the line

hey sen_server ‘SCra’ …

to the much more natural

hey sen_server ADD RELATION …

1 Like

I think there is a misunderstanding here. BeBRexx does support Haiku scripting. For example:
rx - "address 'Terminal' 'get Title of Window 0'; say result"
will return the title of the first window, “Terminal: home: --” in my case.
In addition to that, it also supports the typical “port” concept (just like AmigaOS) via PortManager
Am I missing something?

I mean that it is technically possible but not ideal probably. However, the way scripting support was designed in BeOS, which we have inherited, is slighly more convoluted than OSA (Open Scripting Architecture in MacOS) in my opinion.

We also need to make a distinction between UI scripting and application scripting.
Haiku does not draw a distinct line between the two. To implement application scripting it is indeed sufficient to “expose” a message and document the behaviour (like the old AmigaOS+ARexx fashion) without actually requiring much more than that. However, I’m inclined to favour a well structured approach in the style of Haiku.

1 Like

Ah, yes, I forgot thatthe rx interpreter can actually access both.

From the scripted application side, however, they are quite different, and require separate implementations, that’s what I was thinking about.

Not sure how relevant that is, is there anything except ACE exposing BRexx scripting? I did it there only to stay as close as possible to the MorphOS version, but I’m not sure we should go further inthat direction, and eventually I should add BeOS-style scripting to ACE.

1 Like

No, not that I recall. Probably changing it is fine but people used to the REXX way might be a bit lost without it? If I may suggest and given you have time for it, you may add BeOS-style to the existing REXX-style and let people choose.
It’s a shame it wasn’t developed further in Haiku. Although I don’t like REXX as a language that much, the concept was brilliant back in the Amiga days.

yes, I said “add” not “replace”. In theory the existing brexx scripting should allow to share rexx (or lua/python if we get the needed interfacing) scripts between the MorphOS and Haiku versions of ACE.

My question was more in terms of other applications: since the current scripting system is not very succesful, should we promote it anyways? Should we make something simpler? In that case, would Amiga-style scripting be a good choice? Or should we just improve “hey” and expose things with a simpler interface? I have no idea, really. But maybe adding BeOS style scripting to ACE will at least allow to compare the two systems

My apologies, I misread it.

I’m truly interested in this topic as I’m tinkering with adding scripting capabilities to Genio (aka “extensions”). Shall we move to a separate thread?
I’ve done some succesful experiments with Python with PyAPI and I also considered Lua, tbh.

On the “script” side, the rexx way seems a lot easier to use. Provided that we promote the PortManager or equivalent to a system component.
Either way, Haiku or REXX style, I think we also need to provide a plain C standard library to interface with it as it would allow almost every scripting language to access this capabaility, including Python and Lua for example. Once upon a time there was Heymodule, just as an example.
On the “application” side, I need to look at how brexx handles it to be honest so I can’t really comment on that.

Whatever route we take it needs to be as much simple as possible, both for application and script developers or power users to get more traction.

Just a side note, Python with PyAPI looks promising as we can use the Haiku API for file panels, alerts or even more complex UI.

1 Like

I‘m currently working partly on a scripting system for Haiku to replace the argc/argv based posix scripting interface

3 Likes

By the way, about scripting. Command line tools should support outputting structured data. This allows to easily extract data instead of silosing it.

For example, right now there’s no easy way to get data from the package manager.

Some linux commands provide --json for for that. But CBOR would be a more adequate format.

1 Like

@suhr
The Haiku serializer used by the “flatten” subroutine would be more native than JSON or CBOR. Otherwise that would be a good idea.

If it provides a sufficiently expressive and stable representation, then sure, why not.

I was just now inspired to add a scripting feature to the email application I use for my recreaational coding. After brief perusal of the Be Developer’s Guide discussion of scripting … I’m not sure this is very useful.

I read a lot about reading and writing “properties”, but what I will want to do has little to with with changing state like that, it’s more like “run this.” To implement, I just need to be able to post a message to the application, “run this”, and for my case I don’t see any use for the scripting features here.

I guess they’d be needed for some more complex applications, though. Say a web browser that can fill out forms; there could be multiple pages up, multiple forms on a single page, and then there are the form fields. How would ARexx do that?

Check out the freely available BeOS scripting bible by Scott Hacker, it’s all in there:

Pages 60ff explain how commands work (it’s an execute property) and how to use them together with properties and specifiers.

Since BeOS and consequently Haiku build heavily on messaging, using this feature also for scripting is logical, consistent and very powerful.
If only more devs would follow that paradigm and make their applications scriptable, we could do lots of cool things and build flexible connected workflows across app boundaries, just like UNIX pipes but more advanced and intuitive.

7 Likes

Tbanks, that’s interesting - the BeOS Developer’s Guide doesn’t mention B_EXECUTE_PROPERTY. And as Hacker writes, hey doesn’t support it. … “that’s not a problem, though - you can do a lot of useful things without it!”

What I’m talking about doing is, more abstractly, supporting an application command domain that is parallel to the GUI, not dangling off the GUI’s end points, and for that I really don’t need any execute properties etc. I wouldn’t be at all surprised if this describes a lot of applications with a potential to support scripting, but is it the common case? That’s why I ask about the web browser form, which is tied to the GUI in some sense (albeit not guaranteed to be using Interface Kit.)

  • Can the BeOS system provide somewhat painless access to a form on a page?
  • How would ARexx handle it?
  • For applications that support an independent scripting command set, is there anything about the typical application ARexx interface that I’ll wish I had implemented from the start?

I had an Amiga, but sadly did not use ARexx scripting enough to remember anything.

An application that exposes an ARexx port, needs to declare an array of commands and the hook functions that get executed, at least on the Amiga but I think that BeBRexx does roughly the same.
When it receives a command from an ARexx script this must be parsed (it’s a string) so the application does the heavy lifting.
On Haiku, a stack of specifiers are sent with a BMessage along with any relevant additional fields (indexes, names, values, and more).
So everything is a bit more structured and no parsing is needed but the target of the message must overrides ResolveSpeficier(), GetSupportedSuites() and MessageReceived().

The ARexx model gives the developer more freedom but also more responsibilities, the Haiku model is more structured but it’s a bit more complex to master, in my opinion.

1 Like

Yes, I see the BMessage interface as “already parsed”, wihch is a good thing. Past that, though - like I say, if it’s just about “execute property”, then we’re talking about starting from scratch, no inherited functionality, and the BeOS scripting support adds nothing?

My application is an IMAP client, so my priority in the scripting interface will be to execute IMAP comments in the context of the current session. That might mean a message like [ (“request”, “FETCH 1922 (BODYSTRUCTURE)”) ], and a reply message like [ [(“response”, string, maybe_tag), …], (“bodystructure”, string) ], and it’s between the two parties just how to encode all that data.

(There’s the advantage of a structured interface - the application has already done a fair amount to parse out that IMAP protocol, which will have to be marshaled back into a transmissible package, so if BMessage marshaling doesn’t have too much overhead, I can just send BMessages within BMessages.)

I guess in terms of some standard protocol elements, some success/error conventions could be nice. Like a standardized error field, to indicate whether the requested action came about. (OK for any request that yielded data that might be of interest, whether success or failure from the IMAP protocol perspective; FAIL for a request where there isn’t, because the request wasn’t understood by the application, there wasn’t an active IMAP service connection, etc.) That level of interaction could be a scripting standard, but again if it comes with the BeOS scripting interface I didn’t notice it.

A web browser, for another example, might support interaction with an HTML form on a page. After some interaction loading and identifying the page, you send a message describing the forms, like [ (“internal ID”, string), ([ (“element type”, (input|label), … various attributes or text. ]), … ]

The script rummages around in there, and sends back something like ((“submit”, id-string), [(“element”, element-id), …]) (Right off hand I don’t know how submit works with HTTP service protocol.)

You render pages however you want, the BRadioButtons and whatnot are for GUI users. The script refers to the underlying structure, not its rendition. Could even work the same with different browsers.

So I built an application scripting interface into my email client, and tried it out with a project. My post-mortem reaction: I should have done this a long time ago!

What it does, basically, is allow a script to run random IMAP requests in the current open session, and receive the complete reply and do stuff with it. I reckon some client developers would be horrified, but I’d argue that this is an essential feature.

On the (Ocaml language) client:

  • a standard message ID that the application recognizes and forwards to the IMAP service thread, with a simple protocol - string attributes “command” and “file”, and a return BMessenger.
  • service thread unwraps the command and executes it, and packs the responses into a BMessage. As luck would have it, my client has a maybe unique feature where a file may be specified for direct download of a mail body, so the big payloads aren’t going into the message - that’s the “file” parameter in the script requrest message.
  • Script cilent (in C++) receives the message, and unpacks it. Optionally, PrintToStream, Flatten to file, and/or convert to Python source notation text.

My productive use was a prototype of archiving emails. I’d set up a volume of old emails from an old service on a USB disk, with Email attributes, and it seemed like a good enough idea to start doing it for my current service. The script interaction was super simple, just "FETCH %d (UID BODY[])" somefile, grub through the output with sed to find the reported UID value, and the rest is about what to do with the email. (UID is a semi-permanent ID number for each email.)

I didn’t need any Python for this, but if you wanted to look harder at for example a BODYSTRUCTURE response, you’d need Python or something like it. It can ‘eval’ the Python code text, so the interface is simple enough.

What I might have done differently …

  • I used the BMessage “what” tags to convey information, but then I had to prefix each message with a header table defining the tag meanings. The typical script cilent is going to be text based and it’s unnecessry trouble all the way around. I’d probably change this to use 2 or something for all data values, and add string items to convey any necessary information.
  • CS types would probably like to see a sequence ID and an error field.

Aside from my recent prototyping exercise, I have also used it to download a bunch of PDF attachments in a message, probably did some other things I’ve forgotten. If I had to deal with unfortunate users of my application, I could foresee requiring them to execute this or that command via the scripting interface, in cases where some email is causing troubles.

Obviously, none of this has anything at all to do with scripting in the Interface kit.

1 Like

So, if I’m understanding correctly, this is blending commands either from the command line or from other applications to interact with a program that provides some mechanism to receive those messages.

That’s great!

@PulkoMandy, is there a list of those very few applications that allow such interaction and their allowed messages?

Already read a bit about Rexx in the past, but went a bit deeper this time.

(…) shifts the burden of programming from programmer to machine to the greatest degree possible. The result is a comparatively easy language to learn, code, remember, and maintain. Rexx is intended as a human-oriented language.

Rexx implements the principle of least astonishment, the idea that systems should work in ways that people assume or expect. For example, Rexx’s default decimal arithmetic—with precision you control—means you aren’t surprised by rounding errors.

I came to appreciate very much simplicity and simple languages.