Skip to content

Generalize sync repl - #60

Closed
leiradel wants to merge 6 commits into
hoelzro:masterfrom
leiradel:Generalize_sync_REPL
Closed

leiradel wants to merge 6 commits into
hoelzro:masterfrom
leiradel:Generalize_sync_REPL

Conversation

@leiradel

Copy link
Copy Markdown

No description provided.

@hoelzro

hoelzro commented Feb 25, 2020

Copy link
Copy Markdown
Owner

Hi, and thanks for the PR! Could you tell me a little bit about your changes? What kinds of things are you trying to do with lua-repl that weren't possible or easy with the previous API?

@leiradel

Copy link
Copy Markdown
Author

Hi,

I'm using Lua REPL to implement a embedded Lua console accessible over a socket. It seemed natural to derive the console from repl.console, but it used print and I needed to implement my own method to write out the results.

I've however changed my console to derive from repl.sync, which not only seems the correct thing to do, but also renders this PR useless, unlike #59 which is necessary to have pretty printing over the socket.

Sorry for the noise, and thanks for this module. I'm using it together with lua-term and luasockets, and it's making my life a lot easier. I also wanted to use lua-linenoise, but it seems to be tied to stdin and stdout.

@leiradel leiradel closed this Feb 25, 2020
@hoelzro

hoelzro commented Feb 25, 2020

Copy link
Copy Markdown
Owner

No need to apologize - I'm glad Lua REPL is working for you! You're right about deriving from repl.sync vs repl.console - the latter is poorly named, in retrospect, and is mostly intended for a REPL on a TTY the user is talking to directly.

As far as prettyprint is concerned, I agree - it needs a change to work properly with what you have in mind (which, by the way, is a really good idea - I've been meaning to embed Lua REPL into AwesomeWM for...some time now, but awesome-client has always been just good enough). I'm not sure if leveraging the underlying displayresults method is the right way to go about this - I'm thinking maybe your idea of adding a write method might be a good way forward. I'll have to think about it a bit!

As far using lua-linenoise goes, what does your socket client look like? Maybe I could help you get linenoise working there!

@leiradel

Copy link
Copy Markdown
Author

I'm not sure if leveraging the underlying displayresults method is the right way to go about this

The other PR only uses around instead of override to make it possible for the pretty print plugin to use the original REPL's displayresults code. It worked like a charm and seemed like a very natural way to do it given the design of the module. As the author you will now much better than I do of course.

I'm thinking maybe your idea of adding a write method might be a good way forward

Yeah I think an easy way to have a reusable REPL is to have it take a function to read lines from, and another to write strings to, and maybe another one to report errors. With that design you can leverage the module to work with all scenarios I can think of. You module sort of works like that though, but it needs more tweaking i.e. override the showprompt method.

As far using lua-linenoise goes, what does your socket client look like?

I simply override repl.sync's methods: lines to get the lines from the socket, and showprompt, displayresults, and displayerror, to write characters to it. The functions to read from and write to the socket yield when they would block, so I can run the REPL in a coroutine in the main thread, which simplified the design of my application.

With lua-term embedded and that change to the pretty print plugin, everything worked like a charm.

Maybe I could help you get linenoise working there!

Thank you!

When I added the plugin, I could only issue commands on the terminal where the server was running, because linenoise reads from stdin and writes to stdout as far as I could see. Ideally, linenoise should allow the user to provide functions to read keys from and to write characters to, so I could make it work with the socket.

I know it's perfectly possible to do that kind of line editing over a socket, but I have no idea of the amount of work involved in that.

@hoelzro

hoelzro commented Mar 3, 2020

Copy link
Copy Markdown
Owner

So I had a long think about this a day or two ago, and I came up with a design that I think will be more flexible going forward. I have to experiment with this design in code to feel more certain, but I have a good feeling. The summary is roughly this:

  • We add repl:write() as a method, which will be used by displayresults
  • write can take a string as an argument, which does the simple and correct thing, but it can also take a "token value", which will symbolize things like a color change or an interactive element. This will allow plugins like the pretty printer to work outside of ANSI terminals
  • displayresults and other methods will have a notion of "reply context", so you can have multiple sources of input (whether that's a user, a socket, a GUI widget) talking to a single REPL object, if that makes sense for the underlying application. I'm not 100% how this will fit in just yet

I'm not sure how prompting will work with this - I'm going to try making this change and seeing if plugins break in interesting ways, or if writing other REPL embeddings break in interesting ways as well.

I don't have time for this this week, but I'll try to do it next week!

@hoelzro

hoelzro commented Mar 3, 2020

Copy link
Copy Markdown
Owner

@leiradel

The functions to read from and write to the socket yield when they would block, so I can run the REPL in a coroutine in the main thread, which simplified the design of my application.

Out of curiosity, do you have a single REPL object per socket, or are all of the sockets talking to a single REPL object?

@hoelzro

hoelzro commented Mar 3, 2020

Copy link
Copy Markdown
Owner

@leiradel As far as linenoise over a socket goes, one option would be to have the client itself embed a line editor like linenoise. I might be wrong on this, but I don't think the server process will be able to configure the client's terminal properly to let something like linenoise do its job if the client is just something like netcat.

@leiradel

leiradel commented Mar 4, 2020

Copy link
Copy Markdown
Author

I'm not sold on the reply context, I think it's easy enough to create multiple REPLs, each one talking to its own connection, and avoids having to maintain per-connection state in the REPL.

Out of curiosity, do you have a single REPL object per socket

For now I only support one connection, but if I need to support multiple connections I'll create a REPL per socket. It feels like the right thing to do instead of trying to make the same REPL talk to every socket.

As far as linenoise over a socket goes, one option would be to have the client itself embed a line editor like linenoise.

My client is telnet :)

@hoelzro

hoelzro commented Mar 5, 2020

Copy link
Copy Markdown
Owner

@leiradel That's a good point - I think I'll hold off on the "reply context" idea, then!

As far as the linenoise over network thing goes - if your client is telnet, I don't think there's a way to get it working, at least not to my knowledge :(

@leiradel

leiradel commented Mar 5, 2020

Copy link
Copy Markdown
Author

Yeah I think I'll try to write something similar to linenoise and then a Lua REPL plugin for it. Command history and line editing would be already life savers!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants