-
-
Notifications
You must be signed in to change notification settings - Fork 670
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
feat: Add a plugins manifest to allow for more configuration of plugins #660
Conversation
b907afb
to
62d7b35
Compare
Hey @spacemaison ! Sorry for letting this sit around for so long! This looks like a quite promising PR, but, as you point out in your issue on the topic, there are a lot of design decisions to be made here! For example, @imsnif @a-kenji and I have recently come to the decision that we want to somewhat unify the config and layout files (so layouts should be able to contain configuration like keybindings and also this sort of plugin configuration). How exactly this all happens, however, is a bit up in the air still. I agree also that plugins really need a better way to have a default configuration. We've tossed around the idea of making plugins ZIP files with the WASM and a manifest within them (a bit like a Java Overall, there is a lot to talk about here! If possible, I'd love to have you join us for tomorrow's maintainer meeting to chat about it over a video call, but I'd also understand if that's not something you're comfortable with. If you can make the meeting (18:00-19:00 BST), then just ping either myself or @imsnif probably on the Discord! Hopefully chat soon, otherwise we can do some writing to think about an ideal configuration API! |
Sure I'll try and make it tomorrow. I'll ping you in the morning before the meeting. |
Hi @spacemaison ! It was nice chatting! As discussed offline, if you're up for removing the Default config stuff that might be best for the moment, and does this new system require every plugin to be listed in the config file before use in a layout? If I understand correctly, this would break layouts like this? Looking forward to getting this merged soon! |
It was nice chatting with you as well. From what I recall, I thought I added a way to load plugins directly from the layout files as well, but maybe I'm misremembering that here. I'm busy for the rest of the day but I'll try and look into it tonight and work on it then. |
Hey @TheLostLambda, you're right I did just abstract away looking up plugins to using a tag name. Speaking with you all about it really helped clarify how handy it might be to have the ability to load and configure plugins directly from the layout files, and as it stands this PR breaks that workflow. @imsnif suggested that we use URL's for plugin lookup and that seems like a good way to support both. For the plugin template we can just use a file URL like so: ---
direction: Horizontal
parts:
- direction: Vertical
split_size:
Fixed: 1
plugin: tab-bar
- direction: Vertical
plugin: "file:target/wasm32-wasi/debug/{{project-name}}.wasm"
- direction: Vertical
split_size:
Fixed: 2
plugin: status-bar For plugin lookup from the manifest I suggest we just add a custom |
I should also add that we don't have to use URL's here. I could just use the tag lookup and then fallback to trying to directly looking up the PathBuf as well. URL's just seemed like an elegant way to support standalone plugin lookup in layout files. |
Hi @spacemaison ! I personally like the idea of starting to use URLs. With the changes you are proposing, using the default plugins could still just be something like |
Just to add, since I don't know how involved it would be.
|
Absolutely @a-kenji, I was going to back out of adding the config field to this PR and then start a separate issue for it so we can be sure to get it right. @TheLostLambda I've refactored everything to use URL's so the plugin templates will work again. I've just about finished rebasing the recent permissions changes into this PR as well, but it's super late for me now so I'm going to finish it off in the morning. |
@spacemaison |
@spacemaison Thanks for keeping at this! Once you feel it's all ready for review, feel free to ping me on Discord! |
4b1a37e
to
6db5c0f
Compare
Hey @TheLostLambda, apparently I am the midnight coder here. I've finished rebasing main on top of this PR. I'll try and ping you in the morning on Discord to let you know as well. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall looks great! I left a couple of nitpicks if you are interested, but I'm happy to merge this whenever you'd like me to!
zellij-server/src/wasm_vm.rs
Outdated
@@ -50,77 +54,48 @@ impl From<&PluginInstruction> for PluginContext { | |||
#[derive(WasmerEnv, Clone)] | |||
pub(crate) struct PluginEnv { | |||
pub plugin_id: u32, | |||
pub tab_index: usize, | |||
pub plugin: Plugin, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As an extraordinarily small nitpick, I might change the name of the Plugin struct to something like PluginConfig
? What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, you're right it's confusing.
let mut plugin_map = HashMap::new(); | ||
let mut plugin_map = HashMap::<u32, (Instance, PluginEnv)>::new(); | ||
|
||
for plugin in plugins.iter() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd personally prefer if this loading was also done through the Load
call, but if that's too tricky of a change, it's something I'm happy merging now and cleaning up later :)
zellij-server/src/wasm_vm.rs
Outdated
if _allow_exec_host_cmd { | ||
info!("Plugin({:?}) is able to run any host command, this may lead to some security issues!", path); | ||
PluginInstruction::Load(pid_tx, run, tab_index) => { | ||
if run._allow_exec_host_cmd { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Especially because I don't think this logging would be printed if the Headless plugins were loaded with permissions? Again, if loading headless plugins through this code-path is too much work, we could just move this if
to start_plugin()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah the "when" and "where" of starting headless plugins was something I took into consideration. Starting them right after the wasm thread is forked was just the simplest and most obvious choice for a first pass at it. I absolutely could start them via PluginInstruction::Load
message, but I'm worried it might just obfuscate what's happening. Right after the call to init_session
in zellij-server/src/lib.rs
maybe? Is there a reason you want it changed aside from the aesthetics of it being a bit ugly?
In any event I moved the security warning into the call to start_plugin
so that headless plugins get the warning as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mostly just aesthetics to be honest :) Always nice to have one clear code-path as well, so if someone needs to change the loading of plugins in the future, they only have to do so in one place. With that being said, this is certainly something that can wait until a different PR!
zellij-server/src/wasm_vm.rs
Outdated
)) | ||
.unwrap() | ||
match plugin_env.plugin.run { | ||
PluginType::OncePerPane(Some(tab_index)) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another minor nitpick, would you be up for calling this something like PluginType::Pane
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure thing
zellij-server/src/wasm_vm.rs
Outdated
} | ||
_ => { | ||
debug!( | ||
"{} - Calling method 'host_set_selectable' does nothing for service plugins", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would probably be good to standardise on either "Headless" or "Service" plugins – I'd be happy with either!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for catching this, it was a hold over from the first pass at this when I still called them service plugins
zellij-utils/src/input/layout.rs
Outdated
run: tab | ||
.run | ||
.map(Run::try_from) | ||
// FIXME: This is just Result::transpose but that method is unstable, when it |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it not already stable? Not sure if this is the one you were talking about: https://doc.rust-lang.org/std/result/enum.Result.html#method.transpose
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup, it is. I think I was thinking of Result::flatten
or something. I changed it, thanks
zellij-utils/src/input/plugins.rs
Outdated
|
||
/// Used in the config struct for plugin metadata | ||
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] | ||
pub struct Plugins(HashMap<PluginTag, Plugin>); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Like mentioned before, I'd probably rename this to PluginConfig
or PluginMetadata
:)
pub struct Plugins(HashMap<PluginTag, Plugin>); | ||
|
||
impl Plugins { | ||
pub fn new() -> Self { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could derive Default
if you'd like :)
zellij-utils/src/input/plugins.rs
Outdated
pub fn get(&self, run: impl Borrow<RunPlugin>) -> Option<Plugin> { | ||
let run = run.borrow(); | ||
match &run.location { | ||
// FIXME |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume the // FIXME
is about eventually allowing file:...
with Headless
plugins, but that might be worth writing for whomever stumbles across this in the future!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah more or less. That's where the run configuration from the layout files meets the plugins configuration, the FIXME tag was more of a general reminder to not screw up merging configuration metadata from the layout files, which i promptly ignored when merging in the command execution permission. I added documentation on what the method does at the top to clarify it. Hopefully it will help when extending the layouts API to accept headless plugins among other things.
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] | ||
#[serde(rename_all = "kebab-case")] | ||
pub enum PluginType { | ||
// TODO: A plugin with output thats cloned across every pane in a tab, or across the entire |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed! I think this might be helpful as another type of Pane
as opposed to just a plugin type :) Happy to chat about it down the line!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup! Someone in the Discord was doing a pomodoro timer the other day, and they we're asking for what was essentially a "static" plugin pane, or a plugin that runs once and mirrors itself to every pane. I'll open an issue to discuss it after this gets merged.
@spacemaison Oh, actually, could we fix this? The pane frames get their names from the plugin URL, it might be worth stripping away the |
I didn't test things quite enough...
I fixed displaying the full URL in the pane frames by just displaying the paths of the URL's. The permission for executing commands should be fixed as well. I wasn't copying over the permission from the layout config when generating the plugin config for plugins with the |
Thanks for all of the swift and excellent changes! I'll do a bit of testing now and hopefully we can merge things today! (I'm happy to resolve the merge conflicts if you'd like me to as well!) |
@spacemaison I'm happy to merge things when you are ready! It actually looks like resolving those conflicts was slightly more complex than I thought (something I probably shouldn't try in the Github web editor 😅), so it would be great if you could take a swing at them! Otherwise I can do so tonight or tomorrow :) |
Hey, sure I'll get to it over the next few hours. |
- The Plugins/Plugin structs had "Config" appended to them to clarify that they're metadata about plugins, and not the plugins themselves. - The PluginType::OncePerPane variant was renamed to be just PluginType::Pane, and the documentation clarified to explain what it is. - The "service" nomenclature was completely removed in favor of "headless".
The only time that a plugin location is displayed in Zellij is the border of the pane. Having `zellij:strider` display instead of just `strider` was a little annoying, so we're stripping out the scheme information from a locations display.
74297dc
to
975cbb9
Compare
Hey @TheLostLambda, I rebased main back into the PR. In doing so I actually found a bug in the wasm_vm's handling of data directories for plugins. We were taking just the filename of each plugin to create data directories. That means that two different plugins with separate paths but the same filename would share a data directory. For instance, |
@spacemaison Thanks for the fixes! I actually wanted to change those data directories to be the full paths, but I must have missed that in my earlier reviewing! Thanks for tweaking that! I'll add some info to the changelog :) Thank you for all of your hard work here! |
… how many hidden panes are (#450) * fix(ui): offset content after viewport construction * Added the feature to display fullscreen information on the second line of the status-bar. * fix(strider): update host mount-point * fix(plugin): create missing data directories as needed * feat(layout): specify only tab name in `tabs` section (#722) Allow specifying only the tab name in the `tabs` section - For example this is now possible: ``` tabs: - name: first parts: - direction: Vertical - direction: Vertical - name: second - name: third ``` For that the tab section defaults the direction to `direction::Horizontal` - Adds an error upon specifying a tab name inside the `parts` section of the tab-layout * docs(changelog): Solely name tab in `tabs` section * feature(release): Copy default config to the examples folder on release (#736) fixes #733 * docs(changelog): Copy example config on release * Update default config (#737) * feat(plugin): add manifest to allow for plugin configuration (#660) * feat(plugins-manifest): Add a plugins manifest to allow for more configuration of plugins * refactor(plugins-manifest): Better storage of plugin metadata in wasm_vm * fix(plugins-manifest): Inherit permissions from run configuration * refactor(plugins-manifest): Rename things for more clarity - The Plugins/Plugin structs had "Config" appended to them to clarify that they're metadata about plugins, and not the plugins themselves. - The PluginType::OncePerPane variant was renamed to be just PluginType::Pane, and the documentation clarified to explain what it is. - The "service" nomenclature was completely removed in favor of "headless". * refactor(plugins-manifest): Move security warning into start plugin * refactor(plugins-manifest): Remove hack in favor of standard method * refactor(plugins-manifest): Change display of plugin location The only time that a plugin location is displayed in Zellij is the border of the pane. Having `zellij:strider` display instead of just `strider` was a little annoying, so we're stripping out the scheme information from a locations display. * refactor(plugins-manifest): Add a little more documentation * fix(plugins-manifest): Formatting Co-authored-by: Jesse Tuchsen <not@disclosing> * chore(docs): update changelog * feat(sessions): mirrored sessions (#740) * feat(sessions): mirrored sessions * fix(tests): input units * style(fmt): make rustfmt happy * fix(tests): make mirrored sessions e2e test more robust * refactor(sessions): remove force attach * style(fmt): rustfmtify * docs(changelog): update change * fix(e2e): retry on all errors Co-authored-by: Brooks J Rady <b.j.rady@gmail.com> Co-authored-by: a-kenji <aks.kenji@protonmail.com> Co-authored-by: spacemaison <tuchsen@protonmail.com> Co-authored-by: Jesse Tuchsen <not@disclosing> Co-authored-by: Aram Drevekenin <aram@poor.dev>
feat: Plugins can now be instantiated as headless (paneless)
feat: Config field is passed through from manifest into plugins