13
12
Fork
You've already forked volute
0

Plugin system proposal (spellbook) #2

Open
opened 2026年07月10日 21:30:55 +02:00 by CenTdemeern1 · 2 comments

This is a proposal to replace Helix's upcoming Steel/Scheme-based plugin system with our own Rust-focused one, codenamed Spellbook.

Why?

After internal discussion on Zulip, it seems pretty clear that we want Volute (or whatever its name ends up being) to have a working plugin system.

Helix has an upcoming system (which has been in development hell for ages now) which uses Steel, a Scheme (lisp) dialect.

I would personally prefer to write plugins in Rust.

Key points

  • A while ago I designed a plugin system for Rust projects which has the concept of "adapter plugins"; plugins with the capability to load and manage other plugins, possibly written in different languages.
  • It loads cdylibs and uses symbol lookup to call a plugin's functions.
    • There is a predefined API which follows semantic versioning
    • Plugins are able to decide whether they're compatible with the version of the loader/API that is loading them before initialization
      • This should help prevent undefined behavior between incompatible API versions
    • The public API is defined in a single place, in a single crate shared by both the loader and plugins
      • This helps avoid discrepancies and thus UB ("oops I forgot to edit this on the loader side and now everything is broken")
      • This crate exposes a macro for automatically generating this interface in the plugin crate
        • This is convenient and helps quickly bootstrap projects
    • You can theoretically write plugins in anything that can expose a C interface, not just Rust
      • Rust is what it's designed for though, with stuff like the aforementioned macro
  • Adapter plugins are used to add compatibility with other systems or programming language
    • We could make an official neovim adapter plugin to allow for loading neovim plugins
    • We could be backward compatible with Helix's Steel plugins via an adapter plugin, if that ecosystem ever takes off.
      • It might very well not take off, so the need may not arise
    • If we ever have a major version bump that makes all previous plugins incompatible, an adapter plugin to load older plugins could be developed
    • If anyone wants to write plugins in their favorite programming language, they can make an adapter plugin without having to fork the editor

Unresolved questions

  • If we're using native cdylibs, this would require compiling a plugin from source if it's not normally distributed for the architecture you need.
    • Should all plugins be compiled for a specific shared architecture, like WASM/WASI? Should we support both WASM/WASI and native?
  • Will having too many languages and adapter plugins fragment the plugin ecosystem?
This is a proposal to replace Helix's upcoming Steel/Scheme-based plugin system with our own Rust-focused one, codenamed Spellbook. # Why? After internal discussion on Zulip, it seems pretty clear that we want Volute (or whatever its name ends up being) to have a working plugin system. Helix has an upcoming system (which has been in development hell for ages now) which uses Steel, a Scheme (lisp) dialect. I would personally prefer to write plugins in Rust. # Key points - A while ago I designed [a plugin system for Rust projects](https://codeberg.org/CenTdemeern1/plugin-loader) which has the concept of "adapter plugins"; plugins with the capability to load and manage other plugins, possibly written in different languages. - It loads cdylibs and uses symbol lookup to call a plugin's functions. - There is a predefined API which follows semantic versioning - Plugins are able to decide whether they're compatible with the version of the loader/API that is loading them before initialization - This should help prevent undefined behavior between incompatible API versions - The public API is defined in a single place, in a single crate shared by both the loader and plugins - This helps avoid discrepancies and thus UB ("oops I forgot to edit this on the loader side and now everything is broken") - This crate exposes a macro for automatically generating this interface in the plugin crate - This is convenient and helps quickly bootstrap projects - You can theoretically write plugins in anything that can expose a C interface, not just Rust - Rust is what it's designed for though, with stuff like the aforementioned macro - Adapter plugins are used to add compatibility with other systems or programming language - We could make an official neovim adapter plugin to allow for loading neovim plugins - We could be backward compatible with Helix's Steel plugins via an adapter plugin, if that ecosystem ever takes off. - It might very well not take off, so the need may not arise - If we ever have a major version bump that makes all previous plugins incompatible, an adapter plugin to load older plugins could be developed - If anyone wants to write plugins in their favorite programming language, they can make an adapter plugin without having to fork the editor # Unresolved questions - [ ] If we're using native cdylibs, this would require compiling a plugin from source if it's not normally distributed for the architecture you need. - Should all plugins be compiled for a specific shared architecture, like WASM/WASI? Should we support *both* WASM/WASI and native? - [ ] Will having too many languages and adapter plugins fragment the plugin ecosystem?
Owner
Copy link

I love the idea, thanks for the write-up! The plugin loader system you've created is very cool.

Using native cdylibs may have some performance advantages, but I think it will have more issues than it's worth, so I would err on the side of WASM or similar with this.

I would like to add something else to think about: the plugin system supporting many languages will mean that plugins will be in many languages, and will cause the plugin ecosystem to be very heterogeneous. Settling on one language has the benefit of avoiding this situation.

My own view on plugins is also that I would like for the core editor to support most things people want, and that plugins are mostly just some glue over existing things.

I love the idea, thanks for the write-up! The plugin loader system you've created is very cool. Using native cdylibs may have some performance advantages, but I think it will have more issues than it's worth, so I would err on the side of WASM or similar with this. I would like to add something else to think about: the plugin system supporting many languages will mean that plugins will be in many languages, and will cause the plugin ecosystem to be very heterogeneous. Settling on one language has the benefit of avoiding this situation. My own view on plugins is also that I would like for the core editor to support most things people want, and that plugins are mostly just some glue over existing things.

@lumi wrote in #2 (comment):

I love the idea, thanks for the write-up! The plugin loader system you've created is very cool.

Thank you <3

Using native cdylibs may have some performance advantages, but I think it will have more issues than it's worth, so I would err on the side of WASM or similar with this.

The problem with WASM is that it doesn't have access to stuff like the filesystem. We would either need to require our users to write #[no_std] and then provide our own extensive API for access to OS features like the filesystem or shell, or use something like WASI, which isn't stable yet, and rather limited.
WASM or WASI would be really great for portability but not as good for performance or for operations that require nontrivial integration with other programs or the OS.

I would like to add something else to think about: the plugin system supporting many languages will mean that plugins will be in many languages, and will cause the plugin ecosystem to be very heterogeneous. Settling on one language has the benefit of avoiding this situation.

I've added this to the unresolved questions!

My own view on plugins is also that I would like for the core editor to support most things people want, and that plugins are mostly just some glue over existing things.

I agree; a user shouldn't have to go out of their way to find and install plugins to get basic features, but for some really niche situations or integrations with other software that doesn't fit into the main project having a plugin system is nice.

@lumi wrote in https://codeberg.org/polyphony/volute/issues/2#issuecomment-18968519: > I love the idea, thanks for the write-up! The plugin loader system you've created is very cool. Thank you <3 > Using native cdylibs may have some performance advantages, but I think it will have more issues than it's worth, so I would err on the side of WASM or similar with this. The problem with WASM is that it doesn't have access to stuff like the filesystem. We would either need to require our users to write `#[no_std]` and then provide our own extensive API for access to OS features like the filesystem or shell, or use something like WASI, which isn't stable yet, and rather limited. WASM or WASI would be really great for portability but not as good for performance or for operations that require nontrivial integration with other programs or the OS. > I would like to add something else to think about: the plugin system supporting many languages will mean that plugins will be in many languages, and will cause the plugin ecosystem to be very heterogeneous. Settling on one language has the benefit of avoiding this situation. I've added this to the unresolved questions! > My own view on plugins is also that I would like for the core editor to support most things people want, and that plugins are mostly just some glue over existing things. I agree; a user shouldn't have to go out of their way to find and install plugins to get basic features, but for some really niche situations or integrations with other software that doesn't fit into the main project having a plugin system is nice.
Sign in to join this conversation.
No Branch/Tag specified
main
master
dependabot/cargo/sha2-0.11.0
gh-pages
spellbook-2
filesentry
syntax-gd-gr
ropey-2
config_refactor_v2
spellbook
foreground-rulers
25.07.x
diagnostic-severity-glyphs
ropey2
inlay-hints-on-event-system
batteries
helix_syntax
register-history
append-changes-ensure-cursor-automatically
allowlist
config_refactor
get-lang-config-by-injection-layer
md-compositor-key-remapping-idea
fix-yaml-indents-debug
help-command
gui
termwiz
set-title
25.07.1
25.07
25.01.1
25.01
24.07
24.03
23.10
23.05
23.03
22.12
22.08.1
22.08
22.05
22.03
v0.6.0
v0.5.0
v0.4.1
v0.4.0
v0.3.0
v0.2.1
v0.2.0
v0.0.10
v0.0.9
v0.0.8
v0.0.7
v0.0.6
v0.0.5
v0.0.4
v0.0.3
v0.0.2
Labels
Clear labels
⚠️Priority
A (Highest)
Highest priority issue
⚠️Priority
C (High)
High priority issue
⚠️Priority
D (Medium-High)
Medium to high priority issue
⚠️Priority
E (Medium)
Medium priority issue
⚠️Priority
G (Low)
Low priority issue
⚠️Priority
H (Lowest)
Lowest priority issue
🏷️Kind
Bug
Something is not as expected. For specifications or guidelines, an under-/overspecification is also considered a bug.
🏷️Kind
Chore
Regular maintainance tasks, version bumps, lint fixes
🏷️Kind
Documentation
Documentation changes
🏷️Kind
Epic
This issue is a collection of other, related issues.
🏷️Kind
Feature
New functionality
🏷️Kind
Improvement
Improve existing functionality
🏷️Kind
Task
A specific work item. Can be part of an epic
🏷️Kind
Testing and CI
Change related to CI or testing
👁️Reviewed
Duplicate
This issue or pull request already exists
👁️Reviewed
Invalid
Invalid issue
👁️Reviewed
Valid
This issue has been reviewed and a resolution is desired
👁️Reviewed
Won't Fix
This issue won't be fixed
📋️Kind/Security
This is security issue

Archived

📋️Status
Abandoned
Somebody has started to work on this but abandoned work
📋️Status
Blocked
Something is blocking this issue or pull request

Archived

📋️Status
In Progress
This label is intended to be used when an outside collaborator is pursuing the completion of this issue, since they cannot be directly assigned to the task.
📋️Status
Need More Info
Feedback is required to reproduce issue or to continue work
🔧Difficulty
A (Very hard)
Measure of time-to-implement and cognitive complexity of the task. "Hard" tasks usually take >15h to complete. Extremely unlikely to be suitable for first-time-contributors.
🔧Difficulty
B (Hard)
Measure of time-to-implement and cognitive complexity of the task. "Hard" tasks usually take 3h-15h to complete. Very likely not suitable for first-time-contributors.
🔧Difficulty
C (Medium)
Measure of time-to-implement and cognitive complexity of the task. "Medium" tasks usually take 30min-3h to complete. Likely not suitable for first-time-contributors.
🔧Difficulty
D (Easy)
Measure of time-to-implement and cognitive complexity of the task. "Easy" tasks usually take 15-30min to complete. Likely suitable for first-time-contributors.
🔧Difficulty
E (Trivial)
Measure of time-to-implement and cognitive complexity of the task. "Trivial" tasks usually take 1-15min to complete. Very likely suitable for first-time-contributors.
Compat
Breaking
Breaking change that won't be backward compatible
Good First Issue
This issue is a good task to take on if you are new to the project or the repository and looking to contribute.
Milestone
Clear milestone
No items
No milestone
Projects
Clear projects
No items
No project
Assignees
Clear assignees
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
polyphony/volute#2
Reference in a new issue
polyphony/volute
No description provided.
Delete branch "%!s()"

Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?