elves / elvish

Powerful scripting language & versatile interactive shell
https://elv.sh/
BSD 2-Clause "Simplified" License
5.64k stars 299 forks source link

Parser and interpreter API for implementing own editor as separate process #746

Open notramo opened 6 years ago

notramo commented 6 years ago

I thought a lot about making extensions for the shell. I think, one of the most powerful things would be to simply expose a JSON API for the editor. This could make possible to implement a fully custom editor. There are languages that are more powerful than Go. For example, I want to develop an editor in Crystal or D.
It should be able to:

It would manage on its own how to:

It could also implement completion in a compiled language, which is faster, and is more comfortable to write than Elvish in most cases when dealing with completion processes. For example, I want completion mode to open automatically, and typing would automatically filter the candidates (see how the command line works of the Kakoune editor). This would only be possible in a compiled language.

It could implement custom modes. For example, it would only query the directory history for the histlist mode, and use its own matching and sorting engine (even very complex ones) with blazing speed.

It could simply query the command history and give autosuggestions based on it; using its own, complex, and fast matching engine.

How it would work?
When the command exits, and the shell's editor activates, it wouldn't draw anything to the screen, instead it would launch a new process (the custom editor), and use its input/output for communication. (The editor could open /dev/tty for drawing to the terminal.)
It would send the command to the shell (using the API), and exit, when the command line is ready for evaluation.
If the editor process exits with nonzero, the shell's built-in editor would take the control over the drawing.

This would be a very big step forwards. I think it is easier to implement (a JSON conversion tool is available in the shell), than all the proposed editor features. These features then could be implemented in another language which is easier to write and runs faster than Go.

What do you think about it?
(I know I can't describe my ideas in the most easily understandable way, so ask me if you don't understand something.)

xiaq commented 6 years ago

Correct me if I am wrong, but you are essentially proposing:

While this can definitely work (it is similar to how Emacs's C/S mode works, for instance), the primary problem is that the API surface area will be very large. Large API surface area makes changes more costly and limits the development of both producer (Elvish) and consumer (the external editor).

It is much simpler if Elvish simply exposes the interpreter via an API. The basic API of an interpreter is very simple; written in Go:

interface Interpreter {
  interprete(code string) error
}

This definition is schematic because Go interfaces are not suitable for defining IPC API, and the return value should probably be more sophisticated; but it illustrates the point. If you wrap Elvish's interpreter in an IPC API, you can start implementing an external editor right away. In fact, this is exactly what elvish -web does: it exposes an interpreter API on an HTTP path /execute:

https://github.com/elves/elvish/blob/a8d8e6405eb14891c6b1e5d8aa44a1d0ca61b25d/program/web/web.go#L48

The implementation of that handler is essentially "eval the HTTP request body and return results in the HTTP response body":

https://github.com/elves/elvish/blob/a8d8e6405eb14891c6b1e5d8aa44a1d0ca61b25d/program/web/web.go#L64-L87

notramo commented 6 years ago

@xiaq The shell would not use the editor core, so it wouldn't need to expose anything from the build-in editor. The buffer, cursor movement, insert/delete, modes, history, etc. is handled by the external editor process.

What the shell would expose:

The editor could:

What it would simplify:

The web editor could also use this API.

xiaq commented 6 years ago

OK, I see what you mean now; your proposal is kind of complementary to the interpreter API I formulated. You are basically saying that Elvish should expose something like the language server protocol (in addition to the interpreter API). If you have not heard of LSP, you should visit that website now.

I don't think that Go is fundamentally a bad language for implementing editors, especially for implementing a terminal-oriented one; I am interested in this "external editor" approach, although I don't yet see how any editor feature can be dramatically simplified by switching to another language. However, this point is not very important. Exposing an LSP API from Elvish has wider benefits than just enabling an alternative terminal-based editor: it also enables integration with other editors like Vim, VS Code.