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

Support ctrl+hjkl in more apps and command history search #16

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,17 @@ Available commands:
- `move_focus` with payload `up`, `down`, `left`, `right` to move the focus in the corresponding direction.
- `move_focus_or_tab` with payload `up`, `down`, `left`, `right` to move the focus in the corresponding direction or switch to the next tab if the focus is already at the edge.
- `resize` with payload `up`, `down`, `left`, `right` to resize the pane in the corresponding direction.
- `enable`/`disable` or `toggle` as the payload to control if the plugin is active.

If you use configuration for the plugin it must be added to every command in order to function consistently.
This is because the plugin is loaded with the configuration of the first command executed.

Available configuration options:
- `move_mod`: The modifier key passed to Neovim with `move_focus` or `move_focus_or_tab`. Default: `ctrl`. Options: `ctrl`, `alt`.
- `resize_mod`: The modifier key passed to Neovim with the `resize` command. Default: `alt`. Options: `ctrl`, `alt`.
- `disable_for_apps`: The list of apps to automatically disable this plugin for so the shortcuts work as they would normally. Default: `"vim,nvim,fzf"`.

Example keybindings:

```javascript
keybinds {
Expand Down Expand Up @@ -120,3 +124,48 @@ keybinds {
}
```

If other applications use the same keybindings, like fzf in combination with Shell forward/backward command history search, you can configure these keybindings to first disable this plugin's keybindings and reenable them another keybindings was pressed. For example, press `Ctrl+r` to disable the plugin but still start command history search. Then on `ESC`/`Enter` or `Ctrl+c`, reenable the plugin again.

```javascript
keybindings {
shared_except "locked" {
bind "Ctrl r" { // Backward shell history
WriteChars "\u{0012}"; // Passthrough `Ctrl+r`
MessagePlugin "https://github.com/hiasr/vim-zellij-navigator/releases/download/0.2.1/vim-zellij-navigator.wasm" {
payload "disable";
};
}
bind "Ctrl s" { // Forward shell history
WriteChars "\u{0013}"; // Passthrough `Ctrl+s`
MessagePlugin "https://github.com/hiasr/vim-zellij-navigator/releases/download/0.2.1/vim-zellij-navigator.wasm" {
payload "disable";
};
}
bind "ESC" {
WriteChars "\u{001B}"; // Passthrough `ESC`
MessagePlugin "https://github.com/hiasr/vim-zellij-navigator/releases/download/0.2.1/vim-zellij-navigator.wasm" {
payload "enable";
};
}
bind "Enter" {
WriteChars "\u{000D}"; // Passthrough `Enter`
MessagePlugin "zellij-move" {
payload "enable";
};
}
bind "Ctrl c" {
WriteChars "\u{0003}"; // Passthrough `Ctrl+c`
MessagePlugin "https://github.com/hiasr/vim-zellij-navigator/releases/download/0.2.1/vim-zellij-navigator.wasm" {
payload "enable";
};
}

// Toggle the plugin on or off manually
bind "Ctrl Alt a" {
MessagePlugin "https://github.com/hiasr/vim-zellij-navigator/releases/download/0.2.1/vim-zellij-navigator.wasm" {
payload "toggle";
};
}
}
}
```
42 changes: 30 additions & 12 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,18 @@ use zellij_tile::prelude::*;

use std::collections::{BTreeMap, VecDeque};

const DEFAULT_DISABLED_APPS: &[&str; 3] = &["vim", "nvim", "fzf"];

struct State {
permissions_granted: bool,
current_term_command: Option<String>,
command_queue: VecDeque<Command>,

// Configuration
enabled: bool,
move_mod: Mod,
resize_mod: Mod,
disable_for_apps: Vec<String>,
}

enum Command {
Expand Down Expand Up @@ -74,7 +78,7 @@ impl ZellijPlugin for State {
fn render(&mut self, _rows: usize, _cols: usize) {}

fn pipe(&mut self, pipe_message: PipeMessage) -> bool {
if let Some(command) = parse_command(pipe_message) {
if let Some(command) = self.handle_message(pipe_message) {
self.handle_command(command);
}
true
Expand All @@ -88,20 +92,35 @@ impl Default for State {
current_term_command: None,
command_queue: VecDeque::new(),

enabled: true,
move_mod: Mod::Ctrl,
resize_mod: Mod::Alt,
disable_for_apps: DEFAULT_DISABLED_APPS.map(ToString::to_string).to_vec(),
}
}
}

impl State {
fn handle_message(&mut self, pipe_message: PipeMessage) -> Option<Command> {
let payload = pipe_message.payload?;
match payload.as_str() {
"enable" => self.enabled = true,
"disable" => self.enabled = false,
"toggle" => self.enabled = !self.enabled,
value => {
return parse_command(&pipe_message.name, value);
}
}
None
}

fn handle_command(&mut self, command: Command) {
self.command_queue.push_back(command);
run_command(&["zellij", "action", "list-clients"], BTreeMap::new());
}

fn execute_command(&mut self, command: Command) {
if self.current_pane_is_vim() {
if !self.enabled || self.current_pane_is_disabled_app() {
write_chars(&self.command_to_keybind(&command));
return;
}
Expand All @@ -115,11 +134,9 @@ impl State {
}
}

fn current_pane_is_vim(&self) -> bool {
fn current_pane_is_disabled_app(&self) -> bool {
if let Some(current_command) = &self.current_term_command {
if current_command == "nvim" || current_command == "vim" {
return true;
}
return self.disable_for_apps.contains(current_command);
}
false
}
Expand All @@ -131,6 +148,10 @@ impl State {
self.resize_mod = configuration.get("resize_mod").map_or(Mod::Alt, |f| {
string_to_mod(f).expect("Illegal modifier for resize_mod")
});
self.disable_for_apps = configuration.get("disable_for_apps").map_or(
DEFAULT_DISABLED_APPS.map(ToString::to_string).to_vec(),
|f| f.split(",").map(|s| s.trim().to_string()).collect(),
);
}

fn command_to_keybind(&mut self, command: &Command) -> String {
Expand Down Expand Up @@ -212,13 +233,10 @@ fn string_to_mod(s: &str) -> Option<Mod> {
}
}

fn parse_command(pipe_message: PipeMessage) -> Option<Command> {
let payload = pipe_message.payload?;
let command = pipe_message.name;

let direction = string_to_direction(payload.as_str())?;
fn parse_command(command: &str, payload: &str) -> Option<Command> {
let direction = string_to_direction(payload)?;

match command.as_str() {
match command {
"move_focus" => Some(Command::MoveFocus(direction)),
"move_focus_or_tab" => Some(Command::MoveFocusOrTab(direction)),
"resize" => Some(Command::Resize(direction)),
Expand Down