Flow uses actor model to offer an snappy experience when working with projects that have tens of thousands of source files, also features async communication with the threads that are working in independent tasks supporting git interface, lsp and tree-sitter integration, apart from the directory introspection to make available all the files of the project, all of them expected s from an IDE. The command arguments travel to the target command and are en/decoded powered by cbor, the same as the parameters that are sent from one thread to another. The process management is provided by thespian.
This chapter describes the mechanisms that flow has to pass arguments between components.
thespian.message values, which are strongly typed, but schema free CBOR encoded structures. It supports spawning, linking, killing, etc., of lightweight processes (aka the “Actor Model” with “Green Threads”) and provides async file and network IO and child process management.cbor.write* functions. These are wrapped by command.fmt and thespian.message.fmt which provide fast allocation free encoding to a thread local buffer. Note that the CBOR data encoded via the *.fmt functions will only survive until another message is encoded and must be copied somewhere for more permanent storage, or possibly sent somewhere via thespian.cbor.match, cbor.extract and cbor.extractAlloc group of functions. cbor.extract functions do not allocate and cannot be used to extract some types that require allocation. cbor.extractAlloc functions do allocate and can extract arrays and structures that require allocation. Both cbor.extract and cbor.extractAlloc produce strings that reference the original CBOR data buffer. thespian.message.match and thespian.extract functions are fairly simple wrappers.The most basic example on deserialization of an integer value is shown in commands.
Cbor features en/decoding arrays, json and compounds of basic types and the only requirement is to decode in the same order as encoding the data, more samples on using cbor can be seen in cbor tests.
For example, when interacting with the clipboard, the messages sent are multiple chunks of information,
CBOR structures are mostly stored in a way that avoids allocation entirely. This is really fast, but requires that you always know where the CBOR data you are working with is stored.
thespian.message.fmt encoded messages are stored in the thread local thespian.message_buffer and remain in scope only until the next thespian.message.fmt call on the same threadthespian.exit_message encoded message are stored in the thread local thespian.error_message_buffer and remain in scope only until the next thespian.exit_message call on the same threadcommand.fmt encoded messages are stored in the thread local command.context_buffer and remain in scope only until the next command.fmt call on the same threadAll of this implies several things worth keeping in mind:
thespian.pid.send will encode it’s parameters to thespian.message_buffer and then send them to the destination actor’s receive buffer. This will invalidate the contents of thespian.message_buffer and destroy any message previously encoded with thespian.message.fmt (on the same thread).command.fmt inside a command that uses command.Context.args will possibly invalidate the command’s own arguments. I say possibly because the ctx.arg may come from somewhere else entirely, like the actor’s receive buffer if the command was called remotely, or some other explicitly allocated buffer.*.fmtbuf to encode to different buffer if there may be scoping issues. You can allocate and scope this buffer any way you want.thespian.exit_message while propagating an error up the stack that was previously created with thespian.exit_message will overwrite the original error