-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Steel as an optional plugin system #8675
base: master
Are you sure you want to change the base?
Conversation
This thread is really long, so I haven't checked the history. Who's working on plugins? Maybe we could make an awesome-helix repository that links Helix distributions & plugins. Would also be nice to have it on the website |
I think people are waiting until release to start working on plugins, since there may be breaking changes |
I would absolutely adore that. |
Not to put the horse before the cart too much, but I do wonder about the distribution mechanism for packages. Other editors have entire package managers just for plugins. I can’t say I miss the days of deciding which Neovim plugin manager to use. It would be cool if there was a sensible default. |
I have a functioning package manager working on a branch for steel, which will work for helix as well. Trying to dog food it a bit and iron out some details before releasing. At the moment the distribution mechanism is just git urls, which will probably work to start. |
I think it shouldn't be bundled by default, as people might want to use other package managers. I'm going to use home-manager for example and a builtin But a recommended plugin would be great, for people who want the default experience |
That’s a good point. I would use home-manager too. |
I think it's fine if it's bundled by default, but not enabled by default(maybe you meant it that way, and I misread). Besides there are plenty of things in home-manager that do ship with a package manager, like Node or even Emacs comes with |
As a happy (lurking) user I'd like to throw in vote on the package manager discussion... IMO it should be installed and enabled by default but easy to disable. I don't think standalone environment managers like home-manager are that pervasive and most users would benefit from having package management be a solved issue that they didn't have to consider. Thanks. |
Including modules in steel is really quite simple; just tell steel where to look for them. Given that flexibility (for better or for worse), it means that no one package management solution will be the only way to do things. I'm hoping to provide a very sensible and functional default, but if you'd like to use another solution you should be more than welcome to. I myself don't use nix, so rest assured we'll have something that works for non nix users |
I guess that straight.el's comparison to use-package might come useful when discussing what's needed from the plugin management system, but starting from reading a single directory configured at startup seems flexible enough for plugin systems to proliferate and explore a common plugin definition, config, and versioning system. Being able to configure that single directory is important, on Emacs trying out different configs or patches/fixes to existing ones and such was painful enough that chemacs and chemacs2 came out to help define what configuration and set of plugins should be used. |
Having a default package manager is one of the greatest feature in new language in my opinion, it standardize and regulate stuffs. It's good to have different possibility but it should be an option and you shouldn't have to make a choice in the first place to try stuff. Having a lot of possibility when it comes to plugin management in neovim is, in my opinion, a weakness concerning beginner as every plugin will have different instruction of installation and it's a real pain when you start your nvim journey |
Will steel allow something like this ?
|
I was thinking what kind of plugins would be really nice to have when Helix has a plugin system. So I browsed Dotfyle Neovim Plugins for quite a while. Most of the features I'd want Helix either already has, PRs already exist to add those features, or doesn't make sense to be in core. But those that don't make sense in core would still be nice features that could exist as plugins. So I feel like plugins which target specific tooling or languages and don't make an overall impact on the editor are the perfect example of what Helix plugins could be used for. For example, it would be nice to have an SQL query builder within Helix. But it doesn't make sense for that to be anything but a plugin, for example Once this PR drops, I may wish to develop a plugin so I'm putting this list I've compiled of nice-to-have plugins down here. Feel free to add to it or use it for inspiration.
|
The two plugins I would really like to see is something like hardtime.nvim and precognition.nvim. These would really help beginners learn commands |
More ideas of plugins that would be very nice:
|
As far as I'm aware, helix has the most sophisticated text-selection management system. I would like to play around with leaning on it to support arbitrary highlighting. We're all familiar with rules-driven highlighting, where language keywords might appear in one color and variable names might appear in another. By "arbitrary" I mean that you'd press some key while text is selected, and the selected text would turn green and stay green even after you've gone on to select something else. Presumably it would be a plugin which is remembering which text is painted in which colors, and then you could extract it as metadata later. Characters 0-47 were painted red, 500-505 were blue, etc. This would be a precursor towards tooling that thinks in terms of text selections rather than indicating a row and line numbers (Imagine receiving advice from an LLM where substrings like Does anyone have any tips about where I'd go looking to see if such functionality is accessible from within a plugin? |
Two plugins I've made the last few days are a quick and dirty OpenAI hinting plugin, and a steel "evaluate all top level forms" plugin. Note that both require the Source and demo vids here: AI Hint suggestionsai-hints.movEvaluating top level expressions and displaying them as ghost hints with steelScreen.Recording.2024-12-26.at.20.54.03.mov |
What is the progress, Whether you can publish a preview version |
@ofzo you can test it now by your self. just check how to integrate steel with helix from this pr post and comments. And checkout steel repo |
Just curious why Scheme instead of writing packages in Rust itself? Part of the reason I use Helix is because everything is in Rust and can be very performant. I worry if people start writing many popular plugins in Steel that we might get a situation like neovim which is slowed down by package loading and general performance speed, as it seems like Steel can be as slow as Python, even Lua which is neovim's plug-in language is faster than that. |
I don't see what needs to be particularly performant about helix, apart from opening large files in a timely manner, which happens regardless of the plugin system. Compiled plugins are not cross compatible between all the architectures that helix can run on, and it's also much less approachable. rust is from what I've seen not an easy language to grasp, even if you have programming experience. Its syntax and concepts can be hard to understand. A plugin system making use of scheme makes all of this much easier. The plugins are cross-compatible since the plugin-system is part of the editor itself, and the language is very simplistic (which doesn't have to be a bad thing, and emacs is proof for that. scheme is merely a lisp dialect) |
@satvikpendem I'm sharing this explanation here for you, and for anyone else reviewing this PR, who may wonder why your comment was downvoted so quickly. It’s generally expected—out of courtesy for everyone involved—that before asking a question, you take a moment to see if the answer is readily available. More than 50 people are subscribed to the updates on this PR, and many of them may be feeling fatigued by having to re-answer questions that have already been addressed multiple times. In this case, the answer to your question can be found by searching for “plugin” in the Helix discussions, specifically looking at the top-rated thread (#3806). You can also Google it... there are Reddit threads and other sources that cover this topic thoroughly. |
@lcpichette I see, thank you, I didn't think to look in the discussions tab (truthfully I personally never use the discussions tab myself for my own projects and those I contribute to so that's probably why), I just searched the issues tab. I appreciate the response. |
If at some point there's going to be an LSP for Steel as well as a formatter, would it make sense to ship those with the editor so that users don't even need to configure it? |
There is an LSP for steel already. For formatting, I don't have one specifically for steel, but have been using |
Notes:
Opening this just to track progress on the effort and gather some feedback. There is still work to be done but I would like to gather some opinions on the direction before I continue more.
You can see my currently functioning helix config here and there are instructions listed in the
STEEL.md
file. The main repo for steel lives here, however much documentation is in works and will be added soon.The bulk of the implementation lies in the
engine.rs
andscheme.rs
files.Design
Given prior conversation about developing a custom language implementation, I attempted to make the integration with Steel as agnostic of the engine as possible to keep that door open.
The interface I ended up with (which is subject to change and would love feedback on) is the following:
If you can implement this, the engine should be able to be embedded within Helix. On top of that, I believe what I have allows the coexistence of multiple scripting engines, with a built in priority for resolving commands / configurations / etc.
As a result, Steel here is entirely optional and also remains completely backwards compatible with the existing toml configuration. Steel is just another layer on the existing configuration chain, and as such will be applied last. This applies to both the
config.toml
and thelanguages.toml
. Keybindings can be defined via Steel as well, and these can be buffer specific, language specific, or global. Themes can also be defined from Steel code and enabled, although this is not as rigorously tested and is a relatively recent addition. Otherwise, I have been using this as my daily driver to develop for the last few months.I opted for a two tiered approach, centered around a handful of design ideas that I'd like feedback on:
The first, there is a
init.scm
and ahelix.scm
file - thehelix.scm
module is where you define any commands that you would like to use at all. Any function exposed via that module is eligible to be used as a typed command or via a keybinding. For example:This would then make the command
:shell
available, and it will just replace the%
with the current file. The documentation listed in the@doc
doc comment will also pop up explaining what the command does:Once the
helix.scm
module isrequire
'd - then theinit.scm
file is run. One thing to note is that thehelix.scm
module does not have direct access to a running helix context. It must act entirely stateless of anything related to the helix context object. Runninginit.scm
gives access to a helix object, currently defined as*helix.cx*
. This is something I'm not sure I particularly love, as it makes async function calls a bit odd - I think it might make more sense to make the helix context just a global inside of a module. This would also save the hassle that every function exposed has to accept acx
parameter - this ends up with a great deal of boilerplate that I don't love. Consider the following:Every function call to helix built ins requires passing in the
cx
object - I think just having them be able to reference the global behind the scenes would make this a bit ergonomic. The integration with the helix runtime would make sure whether that variable actually points to a legal context, since we pass this in via reference, so it is only alive for the duration of the call to the engine.Async functions
Steel has support for async functions, and has successfully been integrated with the tokio runtime used within helix, however it requires constructing manually the callback function yourself, rather than elegantly being able to use something like
await
. More to come on this, since the eventual design will depend on the decision to use a local context variable vs a global one.Built in functions
The basic built in functions are first all of the function that are typed and static - i.e. everything here:
However, these functions don't return values so aren't particularly useful for anything but their side effects to the editor state. As a result, I've taken the liberty of defining functions as I've needed/wanted them. Some care will need to be decided what those functions actually exposed are.
Examples
Here are some examples of plugins that I have developed using Steel:
File tree
Source can be found here
filetree.webm
Recent file picker
Source can be found here
recent-files.webm
This persists your recent files between sessions.
Scheme indent
Since steel is a scheme, there is a relatively okay scheme indent mode that only applied on
.scm
files, which can be found here. The implementation requires a little love, but worked enough for me to use helix to write scheme code 😄Terminal emulator
I did manage to whip up a terminal emulator, however paused the development of it while focusing on other things. When I get it back into working shape, I will post a video of it here. I am not sure what the status is with respect to a built in terminal emulator, but the one I got working did not attempt to do complete emulation, but rather just maintained a shell to interact with non-interactively (e.g. don't try to launch helix in it, you'll have a bad time 😄 )
Steel as a choice for a language
I understand that there is skepticism around something like Steel, however I have been working diligently on improving it. My current projects include shoring up the documentation, and working on an LSP for it to make development easier - but I will do that in parallel with maintaining this PR. If Steel is not chosen and a different language is picked, in theory the API I've exposed should do the trick at least with matching the implementation behavior that I've outlined here.
Pure rust plugins
As part of this, I spent some time trying to expose a C ABI from helix to do rust to rust plugins directly in helix without a scripting engine, with little success. Steel supports loading dylibs over a stable abi (will link to documentation once I've written it). I used this to develop the proof of concept terminal emulator. So, you might not be a huge fan of scheme code, but in theory you can write mostly Rust and use Steel as glue if you'd like - you would just be limited to the abi compatible types.
System compatibility
I develop off of Linux and Mac - but have not tested on windows. I have access to a windows system, and will get around to testing on that when the time comes.