Hacker News new | ask | show | jobs
by 414owen 1719 days ago
So, what's the plan? Reimplement every popular extension that doesn't have good performance?

> the asynchronous communication between the renderer and the extension-host severely limits how fast bracket pair colorization can be when implemented as an extension. This limit cannot be overcome

Nope, I'm not convinced. If it can be done internally, then you should expose more internals until it's possible to do it with the public API.

I bet this could be made really performant if vscode had incremental parsing, like tree-sitter+Atom.

3 comments

There were additional issues too, like access to token information discussed here

> This is another challenge of the Bracket Pair Colorization extension that affects performance negatively: it does not have access to these tokens and has to recompute them on its own. We thought long about how we could efficiently and reliably expose token information to extensions, but came to the conclusion that we cannot do this without a lot of implementation details leaking into the extension API. Because the extension still has to send over a list of color decorations for each bracket in the document, such an API alone would not even solve the performance problem.

> access to token information

This is perhaps the core difference between VS Code and Emacs (which a lot of people believe is being superseded by VS Code as the "extensible editor") - in Emacs, there is no such thing as limiting access to information. Outside of things that get hidden accidentally[0], any bit of elisp code can access everything.

It's not just a practical difference, but also a philosophical one: Emacs plugins are not designed to expose a narrow API, because it's impossible to enforce anyway. There's a structure to it, so nothing prevents one from creating good abstractions - those abstractions just have to be designed with extensibility and interoperability in mind[1], because the users (including other package developers) always have an option to just hook into, advise, override or replace any piece of code in your package.

Performance-wise, the impact of it varies. On the one hand, this level of flexibility prevents Emacs from making important breaking changes[2]. On the other hand, nothing ever has to wait for a better API design - if there's a way to make a feature faster by hooking to a dependency's internal, people will do just that, and keep doing that until the API blesses the use case.

--

[0] - Like state the C core doesn't expose, or some implicit state shared by a bunch of closures - though you can get at the latter if you override whatever is hiding the state.

[1] - E.g. by offering hooks as a blessed, well-defined and stable way to interact with internals to cover 90% of interoperability needs.

[2] - Like doing proper multithreading, or replacing Emacs Lisp with a more polished Lisp - though myself I feel ELisp is good enough as a language.

This is, in part, because VS Code plugins run in a separate process. Each extension API needs corresponding IPC code on both the extension host process and the renderer process.

This means that plugins which work great in Emacs, where there's no IPC overhead, might be pitifully slow in VS Code. Alternatively, plugins that work great in VS Code might bog down Emacs (yes, the Emacs plugin can spawn a new thread and work there, but I don't think that's the typical approach of plugin authors)

Note that Extensions are able to directly manipulate the main application bundle a la Emacs (this is what https://marketplace.visualstudio.com/items?itemName=be5invis... does, for instance), but that is discouraged by way of a checksum failure putting "Unsupported" in the title bar. Of course, that checksum code could be removed by the extension too, but doing so without informing the user would be considered in bad taste.

This makes some sense, but I'm a bit confused on why it was so slow, to be honest. Seems that running emacs against the checker.ts example they gave, with rainbow-delimiters-mode is instant. Am I just comparing against a different type of mode?

That said, I do get the point on wanting things to be IPC based, but that feels like a large jump in complexity for most items. I'm very grateful for the model of extension in emacs, where you do have to learn complexities if you are building a complex plugin, but you can go very far before you get into the realm of complex plugin.

Idea is that in emacs the procedure is a simple function call, so if the "business" logic isn't too expensive (and I presume the Emacs folks have done a good job of ensuring this is true), it will run pretty darn quick. On VS Code it's a whole IPC maneuver, so even if the "business" is fast, there can still be a lot of overhead that bites you when calls happen frequently.

The extension model is the same in VS Code, all the author needs to do is write basic JS (or TS). VS Code core does the heavy lifting of creating the extension host process to run that code and exposing the `vscode` proxy object to the extension's code, which enables communication between the extension and the renderer in a manner that appears identical to as if the `vscode` were a simple object. See the minimal hello world sample [0] for the basic case.

End of the day it's a tradeoff between latency and throughput, emacs chooses latency, vs code chooses throughput. Both have their ups and downs, largely dependent on the size and frequency of the task at hand.

[0] https://github.com/microsoft/vscode-extension-samples/blob/m...

I don't think that is quite right, actually. There are facilities in emacs to do async things. Such that you can make a similar latency trade-off.

I agree the difference is emacs is done such that it is all exposed to all developers. There are no special parts, as it were. Such that a hello world looks like (defun my-ext () (message "hello, world")). If binding this to a key, you simply need to add (interactive) after the argument list.

Obviously, things ramp up quickly, but the point is it isn't some special framework to make extensions. It is just a function.

I am also in the camp that thinks elisp is fine.
> So, what's the plan? Reimplement every popular extension that doesn't have good performance?

Why not? If the extension is popular that suggests the functionality is something people want, and surely if you're working on the next version of something you'd be interested in things people want?

One hopes that they wouldn't unilaterally do this to things that are monetized, but otherwise it's hard not to see how it would be a win for everybody.

The problem is that now the core is more complex, and it still won't help if someone else wants to implement a slightly different feature.
I suppose that's how people ended up with Linux. A mish-mash of incoherent UX executions where each app uses a GUI that doesn't quite match your OS and the whole experience is subpar because no boundaries are ever enforced. Likewise, let's cram every popular extension into VS Code! It's what the users want!
> A mish-mash of incoherent UX executions where each app uses a GUI that doesn't quite match your OS and the whole experience is subpar because no boundaries are ever enforced.

This has nothing to do with, and isn't even exclusive to Linux. If you have an axe to grind, at least grind it well.

Sounds like somebody's stuck using Ubuntu 4.10
I've been using a TreeSitter-powered colouriser in Vim, it's fantastic and, like with everything TreeSitter related, extremely fast.

https://github.com/p00f/nvim-ts-rainbow

Hah, I just wondered how easy it would be to implement it using treesitter, thanks for the link!
As far as I know though, tree sitter has problems with really long lists and even incremental parsing gets slower linearly when extending the list.

Also, to my knowledge, tree sitter cannot move nodes around (which is also very hard for languages that are not as simple as the Dyck language [1]).

For bracket pairs, you can easily reuse all (...)-pairs in the following example, even though their height in the AST changes significantly: old text: (...)[(...)] new text: {{(...)}(...)}

[1] https://en.wikipedia.org/wiki/Dyck_language