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

From: Mitchell <m.att.foicica.com>
Date: Fri, 9 Nov 2018 17:35:22 -0500 (EST)

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]: https://foicica.com/hg/.textadept/file/f050fbdaf1ab/modules/lsp/init.lua#l238

-- 
You are subscribed to code.att.foicica.com.
To change subscription settings, send an e-mail to code+help.att.foicica.com.
To unsubscribe, send an e-mail to code+unsubscribe.att.foicica.com.
Received on Fri 09 Nov 2018 - 17:35:22 EST

This archive was generated by hypermail 2.2.0 : Sat 10 Nov 2018 - 06:44:58 EST