Re: [code] Textadept: preliminary question to the better-experienced about best-practice(s) for: event-handlers waiting for external command response

From: Phil S. <>
Date: Sat, 10 Nov 2018 10:44:31 +0100

Thanks for clarifying and illuminating, Mitchell! Exactly the puzzle
piece I wasn't seeing before, this support for the coexistence of
callback-reads and direct, blocking reads. Will come in handy.

On 11/9/18 11:35 PM, Mitchell wrote:
> Hi Phil,
> On Fri, 9 Nov 2018, Phil S. wrote:
>> This is a thing that will come up repeatedly for other scenarios as
>> well, but
>> for now just consider this simple scenario: format-on-save.
>> Now if your formatter logic is inside your local Lua scripts, this is
>> straightforward with FILE_BEFORE_SAVE. Even if invoking a command from
>> scratch, this would be equally straightforward with io.popen which isn't
>> callback-based or on a separate thread.
>> BUT if your script is "perma-connected" (eg. via stdout/stdin IPC
>> pipes) to
>> your long-running backend program (kinda like a 'language server'
>> perhaps,
>> started via os.spawn), then you're going to post your request to its
>> stdin
>> and some time later your `stdout_cb` callback handler receives a message
>> containing some indication that it is the response to your earlier fmt
>> request via some request-ID. Other messages might occur prior while
>> waiting
>> for the fmt-response.
>> (Nevermind that this takes mere milliseconds in practice, it's still
>> cross-process IO.)
>> In other environments like Node, you wouldn't
>> noop-loop-until-response-received in your FILE_BEFORE_SAVE handler
>> because
>> that would be blocking the whole single-threaded process and prevent your
>> `stdout_cb` from ever being called. (In the very old VisualBasic days,
>> you
>> could put a DoEvents call inside your waiting/noop loop and done ;)
> Instead of waiting for a message in `stdout_cb`, you would use
> `proc:read()` when you are expecting something. My Language Server
> Protocol (LSP) module does this[1].
>> Now normally (ignoring Windows-terminal-version special case) Textadept
>> manages its `os.spawn`ed processes in (a) separate thread(s) so I
>> guess those
>> pipes aren't blocked from my wait-loop, if I were to go try that
>> route. But
>> in Textadept Lua, are your `os.spawn` callbacks in that separate
>> thread too,
>> or in the same one as other userland script code? Docs say "Stdout is
>> read
>> asynchronously" but that doesn't tell me about where my callback is
>> invoked.
> Textadept is actually a single-threaded application. When the GUI event
> loop is empty (e.g. waiting for a keypress), Textadept will poll for
> output from spawned processes, but while Lua is doing something (e.g.
> running a CPU-intensive function, blocking for something like I/O,
> etc.), Textadept will not do anything that appears asynchronous (e.g.
> read stdout from a spawned process, process functions passed to
> `_G.timeout()`, etc.).
>> How would a more seasoned than me Lua scripter approach this scenario
>> when
>> scripting within the Textadept environment and API context? Wait-loops
>> are a
>> bit ugly in general and won't occur often, usually there's no point
>> for them
>> but in a few select scenarios such as fmt-on-save it'd be nice if one
>> could
>> stick to the existing FILE_BEFORE_SAVE event-handling infra (rather
>> than say
>> re-route all-user-interactions-for-Save to some handcrafted custom
>> replacement scaffolding --- but maybe that would be the recommended
>> approach
>> in the end, I don't know, hence my asking =)
> As I mentioned a couple paragraphs above, use a blocking read when you
> know you are expecting something. Otherwise, you'll have to program
> around callbacks.
> I hope this helps.
> Cheers,
> Mitchell
> [1]:

You are subscribed to
To change subscription settings, send an e-mail to
To unsubscribe, send an e-mail to
Received on Sat 10 Nov 2018 - 04:44:31 EST

This archive was generated by hypermail 2.2.0 : Sat 10 Nov 2018 - 06:45:02 EST