Skip to content
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

Plugin API Requests #280

Open
5 of 12 tasks
TheLostLambda opened this issue Apr 20, 2021 · 32 comments
Open
5 of 12 tasks

Plugin API Requests #280

TheLostLambda opened this issue Apr 20, 2021 · 32 comments
Labels
plugin system Enhancement or fixes related to plugin system

Comments

@TheLostLambda
Copy link
Member

TheLostLambda commented Apr 20, 2021

This issue is meant to be a thread for suggesting / requesting new features in the plugin API. Early plugins will likely require new API to be added, but we'll do our best to be responsive and help add the new API where needed!

Some current things on the docket:

@TheLostLambda TheLostLambda pinned this issue Apr 20, 2021
@a-kenji a-kenji added the plugin system Enhancement or fixes related to plugin system label Apr 20, 2021
@horasal
Copy link
Contributor

horasal commented Apr 22, 2021

Request: logging api

  • Background

Current zellij does not provide any logging method (nor for zellij itself except a function for dumping terminal content). As plugin can not simply use println(or simple_log, etc) for logging, debug may be challenging.
Providing a log api will be helpful for debugging plugin as well as reporting issues. Furthermore, this will also be useful for zellij itself.

  • Plugin Side Design

Rust already have many good logging library, such as log and tracing. Plugin can just import them and use warn!, debug! etc to log.

  • plugin library side design

register_plugin! macro should also generate some codes to catch messages from log, and send them to zellij.
For example, it can be

lazy_static! {
    static ref LOGGER: ZellijPluginLogger = ZellijPluginLogger::default();
}

// ... many codes

impl Log for ZellijPluginLogger {
    fn enabled(&self, _: &Metadata) -> bool { 
        check_zellij_availabre() 
    }
    fn log(&self, record: &Record) {
        if self.enabled() { send_log(record) } 
        // .... many codes
    }
}

fn send_log_to_zellij() {
    let _ = log::set_logger(&*LOGGER);
}
  • Zellij Side

zellij-tile should provide an API for send log, e.g. send_log. Furthermore, zellij should also provide a way to check these logs. Here are several approaches:

  1. provide a special tab for logging. This tab can be toggled by a command or option.
  2. write all logs to a file

Remaining Problems

  • Logging library for other languages
  • Performance issues

@a-kenji
Copy link
Contributor

a-kenji commented Apr 22, 2021

Make Plugins Configurable #317.

@TheLostLambda
Copy link
Member Author

@horasal Thanks for the suggestion! I think this is certainly a feature I'd like to have in the API eventually! I do have a currently implemented alternative if you're looking for something simple though 🙂

This section of the "Writing a Plugin" guide shows off how simple Rust debugging is possible with the dbg!() macro and shell redirection of stderr. Though it's obviously not a robust solution, and I've only coded some simple plugins, cargo make run 2> dbg.log, tail -f dbg.log, and some dbg!() statements in Rust work like a charm (in both plugins and the main program). This is also nice because every language can print to stderr somehow.

Let me know what you think!

@horasal
Copy link
Contributor

horasal commented Apr 23, 2021

@TheLostLambda
I tried dbg! during working on #319 , it works and is useful for debugging. However, I think there are still some issues remaining:

  • developers have to remove all dbg macros before publish
  • there's no way to collect those info for bug report
  • it's difficult to handle complex scene (for example, bugs that only appear with another specific plugin)

@TheLostLambda
Copy link
Member Author

@horasal
Those are some quite good points! I would agree that this sort of logging capability would be really nice to have! I do think that Zellij itself will likely need logging added before the same can be done with plugins, but what do you think about changing Zellij to capture output over stderr when Zellij is run with --debug? Using stderr is rather language agnostic and can be totally tossed out when not running in --debug, so plugins can keep debug messages in the code. Any messages from the plugins can then be timestamped and marked with their plugin of origin on the Zellij side.

Let me know what you think about that!

Obviously it would be ideal if plugins could also detect flags, but I think that should come with #317 :)

@5c077m4n
Copy link
Contributor

@TheLostLambda Maybe some sort of message bus/event listener could help (and maybe even remove the need for the timeout and logging)?

@TheLostLambda
Copy link
Member Author

@TheLostLambda Maybe some sort of message bus/event listener could help (and maybe even remove the need for the timeout and logging)?

How exactly do you mean? We currently have a sort of event bus system that allows Zellij to send events to plugins, but I suppose that doesn't go both ways yet? For plugins to talk to Zellij, there are just dedicated functions.

@5c077m4n
Copy link
Contributor

@TheLostLambda I meant something more generic, that can send/receive serializable objects that can be used to pass any data that it may need (other than ModeInfo, Vec<TabInfo> and Key)

@TheLostLambda
Copy link
Member Author

@5c077m4n What new abilities would that give us? Currently things are just sent as JSON over the interface. It's already decently generic I think?

@horasal
Copy link
Contributor

horasal commented Apr 26, 2021

what do you think about changing Zellij to capture output over stderr when Zellij is run with --debug?
Any messages from the plugins can then be timestamped and marked with their plugin of origin on the Zellij side.

It sounds great!
I really like to see this land to zellij so we can add debug trace for grid/cursor calculation etc.

BTW, I found that json can not serialize things like HashMap<Key, _>. When I change ModeInfo to a hashmap, zellij will lose response because of this failure. Logging will be useful to detect exceptions like this :)

@a-kenji
Copy link
Contributor

a-kenji commented Jul 7, 2021

Allow plugins to react to mouse events #607.

@spacemaison
Copy link
Contributor

Hey, how do you all feel about metaprogramming Zellij with plugins? Right now the API for plugins seems focused on just getting visual elements painted to the screen to be interacted with. The things I'm interested in doing with plugins involve changing the way Zellij works, rather than presenting information.

For instance, I recently wrote a plugin that keeps the current working directory of the focused pane when splitting into a new one. A lot of additions to the core plugin API were needed to make it work though. Basically, the keybinds API was modified to allow for registering actions to be dispatched into plugins instead of being handled by Zellij. Other changes include adding a "PaneUpdate" event that's supposed to function similarly to the TabUpdate event, a plugins manifest in the core config file was added to help with configuring plugins, and an open_terminal method was also introduced. It's quite a lot of changes, and it's pretty hacky and unfinished, but if someone wants to take a look at my fork I can split it into multiple pull requests.

As an aside though, can I just say thanks to everyone who contributed to Zellij! I used Tmux for years, but tried Zellij a few weeks ago and now I'm never going back.

@TheLostLambda
Copy link
Member Author

@spacemaison I think adding this sort of "metaprogramming" ability to Zellij plugins is essential! It's actually something that's been on our radar for a little while now but that we've not gotten around to. Things like plugin configuration have been particularly tricky UI problems (would plugin configuration be more at home in the layout or config files, for example?)

I'm happy to break things into smaller PRs and merge them in gradually! Is there a particular place that you'd like to start?

I've added "Implement Headless Plugins" to the task list at the top of this issue which I think maps to your concept of a "service" plugin :)

@imsnif
Copy link
Member

imsnif commented Aug 23, 2021

Just a note @spacemaison - while I would totally welcome these changes, IMO the sticky-cwd needs to be the default behaviour of Zellij. There's an open PR for it here: #277 - I think you can pick it up if you like, or start a new one?

@spacemaison
Copy link
Contributor

Hey thanks for being receptive to the changes @TheLostLambda. I've opened an issue to add a plugins manifest to Zellij as a place to start.

Also thanks for letting me know @imsnif, I'll take a look at that PR and work from there on the issue.

@a-kenji
Copy link
Contributor

a-kenji commented Aug 30, 2021

Dispatching keybound actions into plugins #662 .

@prscoelho
Copy link
Contributor

Thoughts on plugins being able to send instructions to zellij? There's already subscribe, but I think going the other way around would be important too. Once mouse events are added, tab bar would have to send an instruction to zellij to change the active tab, right?

@TheLostLambda
Copy link
Member Author

@prscoelho

I agree that's a pretty essential feature to have! Currently the way that plugins talk back to Zellij is by calling certain API functions that we expose. Adding one for switching the tab should be relatively simple I think!

@spacemaison
Copy link
Contributor

@TheLostLambda

Has any thought been given to dispatching actions back into Zellij from plugins rather than exposing API methods piecemeal? You could just give plugins a dispatch_action/dispatch_actions method that'd work like this:

impl ZellijPlugin for Whatever {
    fn load(&mut self) {
        // Creates a new tab and renames it
        dispatch_actions(&[
            Action::NewTab(None),
            Action::TabNameInput("Generated tab".as_bytes().to_vec())
        ]);
    }
}

Personally, I don't know if that's kinda ugly or elegant. I already have an open issue for dispatching actions into plugins at #662, and I get the sense @a-kenji thinks it's kinda ugly, so maybe I'm the nutty one here. It'd simplify documentation around what you can do with plugins by quite a bit though, and expand what they can do by a lot.

... A permissions system would absolutely need to be done before this because a plugin author could arbitrarily write whatever they want to the console using Action::Write.

@prscoelho
Copy link
Contributor

It seems like sending actions would scale better than having to add functions for each action. I'm not too familiar with how wasm and rust interoperate, but could update and load have a Sender in their parameters?

@TheLostLambda
Copy link
Member Author

@prscoelho @spacemaison
Ah! I misunderstood your original message! I think a function like dispatch_actions is an excellent idea – certainly better than a separate function for every action. I think a permissions system is on the way somewhat soon and it seems (to me) quite reasonable to pass actions through a firewall-style filter in the plugin thread before forwarding them to the rest of Zellij!

I've added this to the official list above!

@a-kenji
Copy link
Contributor

a-kenji commented Sep 14, 2021

Make PluginPanes copyable #721 .

@TheLostLambda
Copy link
Member Author

TheLostLambda commented Sep 28, 2021

As a tentative roadmap:

  1. Move Zellij configuration over from YAML to KDL
  2. Implement plugin manifests in KDL (starting as just a headless vs pane-bound and name thing)
  3. Expand plugin manifests to determine if a pane if globally, per-user, or pane-unique (fixes the 10 tabs, 20 plugins problem)
  4. Add a permission system for Events and Actions
  5. Allow plugins to request permissions via the manifest
  6. Allow plugins to dispatch arbitrary actions and convert most host-functions to actions

How do people feel about this overall? I should get a chance to give these a swing soon (obviously happy to accept help from others as well)!

@arefem-project
Copy link

Hey @TheLostLambda, that sounds like a good course of action. How far along are you? I'd be happy to help if you can find a way to divide the work. Every item on that list kinda hangs on the manifest being implemented first though.

How are you planning on implementing the manifest? I vaguely recall that we talked about rolling manifest information into the wasm binary somehow, but I can't remember the specifics of what was discussed...

@spacemaison
Copy link
Contributor

Ah Firefox wants to randomly log me into the wrong account when I'm not paying attention. For clarities sake that was me @TheLostLambda.

@TheLostLambda
Copy link
Member Author

@spacemaison I'm looking to take a swipe at the manifest this week! It's been a while since I've actually done some coding and I'm eager to give it a go. My plan is to kinda incorporate it with the template plugin repo we have so that the manifest can be maintained as a separate text file (YAML, I suppose) and include_bytes! would be used to bake it into the WASM blob. Calling the manifest() function in the WASM would simply return this internal string :)

@a-kenji
Copy link
Contributor

a-kenji commented Nov 16, 2021

Add action that can send data to a plugin #874

@a-kenji
Copy link
Contributor

a-kenji commented Nov 23, 2021

Give plugins version information on load #888

@a-kenji
Copy link
Contributor

a-kenji commented Nov 25, 2021

Feature: add plugin API for File IO #896

@ahirner
Copy link

ahirner commented Feb 27, 2022

Reading current directory and command: #1133

@a-kenji a-kenji unpinned this issue Jul 7, 2022
@abhijeetbhagat
Copy link

abhijeetbhagat commented Jul 14, 2022

i want to create a headless plugin that gets details about the layout in a current session. i want to then save this info in a file and load the saved layout the next time zellij is launched if the user wants to.

@mdrssv
Copy link

mdrssv commented Jul 15, 2024

Request:

allow plugins to aid Zellij to resurrect certain panes. By allowing an plugin to generate the command which shall be used to recreate the pane.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
plugin system Enhancement or fixes related to plugin system
Projects
None yet
Development

No branches or pull requests