sxyazi / yazi

💥 Blazing fast terminal file manager written in Rust, based on async I/O.
https://yazi-rs.github.io
MIT License
11.95k stars 276 forks source link

Increase possibilities for yazi<->embedding editor integration #989

Open mikavilpas opened 2 months ago

mikavilpas commented 2 months ago

Please describe the problem you're trying to solve

In https://github.com/mikavilpas/yazi.nvim, I have ideas for some features that I think might require allowing a deeper level of interaction with editors that want to embed yazi:

Would you be willing to contribute this feature?

Describe the solution you'd like

Suggestions

Suggestion 1: programmatic access to yazi actions

The api could be disabled by default, and enabled with a command line flag such as yazi --enable-rpc-api, maybe even enabled in the user's configuration.

Currently, yazi can send events via the data distribution service (dds), and the editor integrations can listen to these events. Events can also be sent to yazi via ya pub and ya pub-static.

Even though the communication is now bidirectional, there are some difficulties with this approach:

Suggestion 2: allow loading additional plugins from the command line

With deeper integration between yazi and neovim, some features only make sense when both yazi and neovim are running. I love the fact that yazi is a very composable tool and I can run it from the terminal as well as in my editor.

I want myself and other users to have a good experience in both environments. I think the best way to do this would be adding a new flag such as yazi --load-plugin='~/.local/share/nvim/lazy/yazi.nvim/bundled-yazi-plugin/' which would load this additional plugin that provides yazi.nvim specific functionality. When running yazi in the terminal environment, the plugin would not get loaded.

Additional context

Benefits and ideas

Finally, I want to list some ideas and benefits that I think would come from these changes:

sxyazi commented 2 months ago

but currently due to neovim limitations, I cannot read live events from yazi. The apis seem to only allow reading stdout + stderr as a combined stream while the application (yazi) is running, so right now I can only read the events after yazi has been closed

If Neovim doesn't provide an API for reading stdout from a running process, you can start another Yazi process in the background as a server using yazi --remote-event, and the process with which the user interacts will automatically become the client.

which would load this additional plugin that provides yazi.nvim specific functionality. When running yazi in the terminal environment, the plugin would not get loaded.

I'm not quite sure what you mean by "loading" plugins. Normally, Yazi plugins don't need to be manually loaded; they are lazily loaded automatically after user actions (such as pressing a key). Are you referring to the initialization process of plugins? If so, that would involve loading an init.lua rather than specific plugins.

mikavilpas commented 2 months ago

If Neovim doesn't provide an API for reading stdout from a running process, you can start another Yazi process in the background as a server using yazi --remote-event, and the process with which the user interacts will automatically become the client.

I love this idea. I think I will try it out soon.

I'm not quite sure what you mean by "loading" plugins.

I'm not sure if "plugin" is the correct term to use here. I'm looking for a way to

mikavilpas commented 2 months ago

If Neovim doesn't provide an API for reading stdout from a running process, you can start another Yazi process in the background as a server using yazi --remote-event, and the process with which the user interacts will automatically become the client.

Tried this approach, but I quickly found out yazi could not be started when it's "hidden", possibly because it cannot draw to a screen.

Opened #1004 which could be used to work around this limitation - the idea is to start ya sub-static in addition to the already running yazi instance, and listen to incoming events without displaying a TUI.

mikavilpas commented 1 month ago

In comparison to the LSP (language server protocol) which uses json RPC (https://microsoft.github.io/language-server-protocol/overviews/lsp/overview/), several types of messages are supported:

  1. request (editor -> server -> editor): editor asks the server, and the server responds with data
  2. notice (editor -> server): the editor notifies the server but doesn't need a response
  3. notice (server -> editor): the server notifies the editor but doesn't need a response

Right now, the ya sub implementation that's ongoing in #1004 should allow for type 3 (notice from server -> editor). I'm curious how you might feel about types 1 and 2.

Is this a direction you could see yazi going?

sxyazi commented 1 month ago

It sounds like the three modes you mentioned are already covered by the current DDS, but it's based on an asynchronous publish-subscribe model rather than a synchronous request-response model.

For example, for the first mode, editor -> server -> editor, you can use the Lua API to call ya.pub_to to send a message to the server, which then forwards the message to the corresponding Yazi instance. The instance then executes the event, and you receive the result through ya.sub_remote.

mikavilpas commented 1 month ago

Message passing with the DDS itself should not be an issue. My issue is that there is no known real time communication channel that I could use from neovim.

It's becoming clearer and clearer to me that at some point yazi.nvim might need its own plugin for various features. I will think about this idea more.

Maybe there's something that could be done on the plugin level to make the communication possible.

sxyazi commented 1 month ago

My issue is that there is no known real time communication channel that I could use from neovim.

I think adding a new ya sub to the CLI (as in the content of this PR https://github.com/sxyazi/yazi/pull/1004) to workaround the current limitations of nvim is the right direction. But since it's closed, I'm wondering if there's something specific that it couldn't cover in this way?

It's becoming clearer and clearer to me that at some point yazi.nvim might need its own plugin for various features.

Could you describe your needs? What are the things that DDS currently can't provide directly and must be done through plugins?

mikavilpas commented 1 month ago

Actually, I'm coming around to #1004 being a good approach. Let's reopen it and see if we can finish it.

Previously I was confused about a few things, but I think this approach can work for me:

I will think about what the best way to include the plugin would be.. For example, when running yazi inside neovim, some keybindings should probably run plugin specific functionality, but when running outside of neovim they should use the default functionality instead.

Have you thought about this kind of an approach?

39555 commented 1 month ago

I've also played with this issue because I'm using Nushell, but yazi.nvim depends on the posix shell when running --local-events with redirection to a temp file to read events. Without the redirection, the stdout prints all stuff to the screen and breaks the UI

Starting the second process with yazi --remote-events is not possible. All of termopen jobstart, vim.uv.spawn exit with Device is not configured because yazi tries to draw the UI. --remote-events becomes useless without a --headless flag or something similar.

sxyazi commented 4 weeks ago

I've also played with this issue because I'm using Nushell, but yazi.nvim depends on the posix shell when running --local-events with redirection to a temp file to read events. Without the redirection, the stdout prints all stuff to the screen and breaks the UI

Starting the second process with yazi --remote-events is not possible. All of termopen jobstart, vim.uv.spawn exit with Device is not configured because yazi tries to draw the UI. --remote-events becomes useless without a --headless flag or something similar.

Please try https://github.com/sxyazi/yazi/pull/1004 to see if it meets your needs.

sxyazi commented 3 weeks ago

some keybindings should probably run plugin specific functionality

Could you give me an example - which keys need to trigger a specific plugin inside Neovim and when?

mikavilpas commented 3 weeks ago

Sure, I was thinking good use cases might be to

Other use cases for this type of integration are also possible (when yazi is open in neovim):

There's lots of cool ideas that I think this could help with!

sxyazi commented 3 weeks ago

I need to think more about an elegant way for the plugin to take over these keybindings. Do you have any ideas on this?

mikavilpas commented 3 weeks ago

Yes, I have a couple of ideas 🙂

  1. Idea: what about an approach like #1148 where I could make neovim open yazi with an additional configuration file? We could merge the two files together in yazi when it's starting, for example.
  2. Idea: Plugins could be allowed to create their own keybindings too. That way I could have the plugin only activate when $NVIM is set, indicating the session is happening inside of neovim's embedded terminal.

Neovim is a special case though, because I control both the (future) plugin as well as the invocation of yazi itself. Maybe idea 2 could be more useful to the yazi community. I think it might allow some plugins to provide a more "batteries included" type of experience (reducing the amount of manual configuration).

daUnknownCoder commented 3 weeks ago

Idea: Plugins could be allowed to create their own keybindings too. That way I could have the plugin only activate when $NVIM is set, indicating the session is happening inside of neovim's embedded terminal.

this feels like an on_attach function i wonder if yazi's lua format supports it?

sxyazi commented 1 week ago

Outside of neovim, bulk renaming works fine, but when using yazi.nvim, the experience is not consistent and a few assumptions have to be made

I tried this yesterday and found that the issue isn't due to nested Neovim instances (as I mentioned here). Instead, it's because yazi.nvim starts Yazi with yazi --local-events > /tmp/xxx, which causes Neovim invoked by Yazi during bulk renaming to be unable to render the TUI to stdout, making it invisible to the user.

Do you think this could be solved using the existing ya sub? This might also address the issue you mentioned earlier about not being able to listen to Yazi events in real-time.

the same thing could be done for the yazi.nvim default keymappings (open in vsplit, etc) to make them more robust - currently they depend on some yazi keybindings being their defaults

Can you elaborate on this? I don't quite understand why splits in Neovim would be related to Yazi's default key bindings. From what I understand, you want to add a new --config or Lua API to override Yazi's default keybindings, but I don't get why it would be related to solving the split issue. Are you mean configuring two different key mappings for yazi.nvim and Yazi at the same time, like this?

require("yazi").setup {
  yazi_ctrl_s = "none"  -- <C-s> in Yazi, do nothing
  yazi_nvim_ctrl_s = "vsplit"  -- <C-s> in Nvim, vsplit
}

add more robust support for bulk renaming files with yazi.nvim

the same thing could be done for the yazi.nvim default keymappings

I'm not too satisfied with these two ideas (I'll explain why later), so I want to see if we can solve these issues using existing solutions first. If they don't work, we can look for other ways.

daUnknownCoder commented 1 week ago

Do you think this could be solved using the existing ya sub:

error: unrecognized subcommand 'sub'

  tip: a similar subcommand exists: 'pub'

Usage: ya <COMMAND>

For more information, try '--help'.

version:

Yazi 0.2.5 (Arch Linux 2024-04-27)
sxyazi commented 1 week ago

add more robust support for bulk renaming files with yazi.nvim

Even though I think it's doable, there are still some concerns:

the same thing could be done for the yazi.nvim default keymappings

It's simply not feasible: To achieve the highest performance, Yazi's configurations are designed to be immutable. They are parsed and initialized only once at startup. So dynamically registering new content into the configuration via the Lua API isn't feasible. To achieve this, we would need to change the immutable configuration and event dispatch design, introduce more locks and memory clones, which would increase code complexity and decrease performance.

sxyazi commented 1 week ago

Do you think this could be solved using the existing ya sub:

error: unrecognized subcommand 'sub'

  tip: a similar subcommand exists: 'pub'

Usage: ya <COMMAND>

For more information, try '--help'.

version:

Yazi 0.2.5 (Arch Linux 2024-04-27)

It was added two weeks ago in https://github.com/sxyazi/yazi/pull/1004 and will soon be released as part of Yazi v0.3.

mikavilpas commented 1 week ago

I tried this yesterday and found that the issue isn't due to nested Neovim instances (as I mentioned https://github.com/mikavilpas/yazi.nvim/issues/137#issuecomment-2196017681). Instead, it's because yazi.nvim starts Yazi with yazi --local-events > /tmp/xxx, which causes Neovim invoked by Yazi during bulk renaming to be unable to render the TUI to stdout, making it invisible to the user.

Do you think this could be solved using the existing ya sub? This might also address the issue you mentioned earlier about not being able to listen to Yazi events in real-time.

I think this sounds like a really good idea. I will have to do some experiments but I think this can probably work as long as plugins such as https://github.com/willothy/flatten.nvim are disabled e.g. when $YAZI_ID is set, indicating a nested session.

mikavilpas commented 1 week ago

Unclear definition: What exactly does it refer to? yazi.toml or keymap.toml? If I got it right, you want to override some of the user's key bindings, so it's probably keymap.toml. Then how do yazi.toml and theme.toml get specified?

Yeah I think I meant a merging of additional yazi.nvim settings with the ones that are used in the terminal yazi. I'm not really sure what exactly would be required, but since there are 3 configuration files it would perhaps add quite a bit of complexity.

I think you laid out the challenges in yazi related to this level of configuration quite well; perhaps it's better to abandon this idea. Maybe it would be possible to do overriding or configuration merging in yazi.nvim though.