aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJonah Caplan <jonahcaplan@gmail.com>2021-03-08 04:06:23 -0500
committerGitHub <noreply@github.com>2021-03-08 10:06:23 +0100
commit44b0246e91ae65b09f3e2d9b111772a6b093135b (patch)
treec1a422e0f9ffb02cb978ae4d5bb68018deb2a998
parentNew tab styling (#216) (diff)
downloadsl0ppij-44b0246e91ae65b09f3e2d9b111772a6b093135b.tar.gz
sl0ppij-44b0246e91ae65b09f3e2d9b111772a6b093135b.tar.xz
sl0ppij-44b0246e91ae65b09f3e2d9b111772a6b093135b.zip
feat(tabs): add ability to set tab name (#212)
* send all tabs in vec * works but no input filtering * add event types * add event handler for tab events * fmt fixups * update tab name in place, and escape rename works * rename handle_tab_event handle_tab_rename_keypress * handle empty new_name when renaming * fix(tabs): pad active tab name too * fix(tabs): report proper length * fix(tabs): always render active tab * style(fmt): rustfmt Co-authored-by: Aram Drevekenin <aram@poor.dev>
Diffstat (limited to '')
-rw-r--r--assets/layouts/default.yaml2
-rw-r--r--default-tiles/status-bar/src/main.rs2
-rw-r--r--default-tiles/tab-bar/src/line.rs4
-rw-r--r--default-tiles/tab-bar/src/main.rs58
-rw-r--r--default-tiles/tab-bar/src/tab.rs25
-rw-r--r--src/client/layout.rs3
-rw-r--r--src/client/tab.rs26
-rw-r--r--src/common/errors.rs2
-rw-r--r--src/common/input/actions.rs2
-rw-r--r--src/common/input/handler.rs29
-rw-r--r--src/common/input/keybinds.rs25
-rw-r--r--src/common/mod.rs81
-rw-r--r--src/common/screen.rs45
-rw-r--r--src/common/wasm_vm.rs21
-rw-r--r--zellij-tile/src/lib.rs14
-rw-r--r--zellij-tile/src/shim.rs13
16 files changed, 285 insertions, 67 deletions
diff --git a/assets/layouts/default.yaml b/assets/layouts/default.yaml
index f06bab17..463c5e2d 100644
--- a/assets/layouts/default.yaml
+++ b/assets/layouts/default.yaml
@@ -5,6 +5,8 @@ parts:
split_size:
Fixed: 1
plugin: tab-bar
+ events:
+ - Tab
- direction: Vertical
expansion_boundary: true
- direction: Vertical
diff --git a/default-tiles/status-bar/src/main.rs b/default-tiles/status-bar/src/main.rs
index e5de067d..1b64a304 100644
--- a/default-tiles/status-bar/src/main.rs
+++ b/default-tiles/status-bar/src/main.rs
@@ -104,7 +104,7 @@ fn key_path(help: &Help) -> LinePart {
len,
)
}
- InputMode::Tab => {
+ InputMode::Tab | InputMode::RenameTab => {
let mode_shortcut_text = "t ";
let superkey = superkey_text.bold().on_magenta();
let first_superkey_separator = ARROW_SEPARATOR.magenta().on_black();
diff --git a/default-tiles/tab-bar/src/line.rs b/default-tiles/tab-bar/src/line.rs
index f28fab3f..306c0281 100644
--- a/default-tiles/tab-bar/src/line.rs
+++ b/default-tiles/tab-bar/src/line.rs
@@ -115,9 +115,7 @@ fn add_next_tabs_msg(
title_bar: &mut Vec<LinePart>,
cols: usize,
) {
- while get_current_title_len(&title_bar) +
- // get_tabs_after_len(tabs_after_active.len()) >= cols {
- right_more_message(tabs_after_active.len()).len
+ while get_current_title_len(&title_bar) + right_more_message(tabs_after_active.len()).len
>= cols
{
tabs_after_active.insert(0, title_bar.pop().unwrap());
diff --git a/default-tiles/tab-bar/src/main.rs b/default-tiles/tab-bar/src/main.rs
index 8a334334..9f1c10ea 100644
--- a/default-tiles/tab-bar/src/main.rs
+++ b/default-tiles/tab-bar/src/main.rs
@@ -4,7 +4,7 @@ mod tab;
use zellij_tile::*;
use crate::line::tab_line;
-use crate::tab::nameless_tab;
+use crate::tab::tab_style;
#[derive(Debug)]
pub struct LinePart {
@@ -12,10 +12,25 @@ pub struct LinePart {
len: usize,
}
+#[derive(PartialEq)]
+enum BarMode {
+ Normal,
+ Rename,
+}
+
+impl Default for BarMode {
+ fn default() -> Self {
+ BarMode::Normal
+ }
+}
+
#[derive(Default)]
struct State {
active_tab_index: usize,
num_tabs: usize,
+ tabs: Vec<TabData>,
+ mode: BarMode,
+ new_name: String,
}
static ARROW_SEPARATOR: &str = "";
@@ -29,20 +44,32 @@ impl ZellijTile for State {
set_max_height(1);
self.active_tab_index = 0;
self.num_tabs = 0;
+ self.mode = BarMode::Normal;
+ self.new_name = String::new();
}
fn draw(&mut self, _rows: usize, cols: usize) {
- if self.num_tabs == 0 {
+ if self.tabs.is_empty() {
return;
}
let mut all_tabs: Vec<LinePart> = vec![];
- for i in 0..self.num_tabs {
- let tab = nameless_tab(i, i == self.active_tab_index);
+ let mut active_tab_index = 0;
+ for t in self.tabs.iter_mut() {
+ let mut tabname = t.name.clone();
+ if t.active && self.mode == BarMode::Rename {
+ if self.new_name.is_empty() {
+ tabname = String::from("Enter name...");
+ } else {
+ tabname = self.new_name.clone();
+ }
+ active_tab_index = t.position;
+ } else if t.active {
+ active_tab_index = t.position;
+ }
+ let tab = tab_style(tabname, t.active, t.position);
all_tabs.push(tab);
}
-
- let tab_line = tab_line(all_tabs, self.active_tab_index, cols);
-
+ let tab_line = tab_line(all_tabs, active_tab_index, cols);
let mut s = String::new();
for bar_part in tab_line {
s = format!("{}{}", s, bar_part.part);
@@ -50,8 +77,19 @@ impl ZellijTile for State {
println!("{}\u{1b}[40m\u{1b}[0K", s);
}
- fn update_tabs(&mut self, active_tab_index: usize, num_tabs: usize) {
- self.active_tab_index = active_tab_index;
- self.num_tabs = num_tabs;
+ fn update_tabs(&mut self) {
+ self.tabs = get_tabs();
+ }
+
+ fn handle_tab_rename_keypress(&mut self, key: Key) {
+ self.mode = BarMode::Rename;
+ match key {
+ Key::Char('\n') | Key::Esc => {
+ self.mode = BarMode::Normal;
+ self.new_name.clear();
+ }
+ Key::Char(c) => self.new_name = format!("{}{}", self.new_name, c),
+ _ => {}
+ }
}
}
diff --git a/default-tiles/tab-bar/src/tab.rs b/default-tiles/tab-bar/src/tab.rs
index 78a9ba0b..fa345ba0 100644
--- a/default-tiles/tab-bar/src/tab.rs
+++ b/default-tiles/tab-bar/src/tab.rs
@@ -9,11 +9,11 @@ pub fn active_tab(text: String, is_furthest_to_the_left: bool) -> LinePart {
ARROW_SEPARATOR.black().on_magenta()
};
let right_separator = ARROW_SEPARATOR.magenta().on_black();
- let tab_styled_text = format!("{}{}{}", left_separator, text, right_separator)
+ let tab_styled_text = format!("{} {} {}", left_separator, text, right_separator)
.black()
.bold()
.on_magenta();
- let tab_text_len = text.chars().count() + 2; // 2 for left and right separators
+ let tab_text_len = text.chars().count() + 4; // 2 for left and right separators, 2 for the text padding
LinePart {
part: format!("{}", tab_styled_text),
len: tab_text_len,
@@ -27,26 +27,27 @@ pub fn non_active_tab(text: String, is_furthest_to_the_left: bool) -> LinePart {
ARROW_SEPARATOR.black().on_green()
};
let right_separator = ARROW_SEPARATOR.green().on_black();
- let tab_styled_text = format!("{}{}{}", left_separator, text, right_separator)
+ let tab_styled_text = format!("{} {} {}", left_separator, text, right_separator)
.black()
.bold()
.on_green();
- let tab_text_len = text.chars().count() + 2; // 2 for the left and right separators
+ let tab_text_len = text.chars().count() + 4; // 2 for the left and right separators, 2 for the text padding
LinePart {
part: format!("{}", tab_styled_text),
len: tab_text_len,
}
}
-pub fn tab(text: String, is_active_tab: bool, is_furthest_to_the_left: bool) -> LinePart {
+pub fn tab_style(text: String, is_active_tab: bool, position: usize) -> LinePart {
+ let tab_text;
+ if text.is_empty() {
+ tab_text = format!("Tab #{}", position + 1);
+ } else {
+ tab_text = text;
+ }
if is_active_tab {
- active_tab(text, is_furthest_to_the_left)
+ active_tab(tab_text, position == 0)
} else {
- non_active_tab(text, is_furthest_to_the_left)
+ non_active_tab(tab_text, position == 0)
}
}
-
-pub fn nameless_tab(index: usize, is_active_tab: bool) -> LinePart {
- let tab_text = format!(" Tab #{} ", index + 1);
- tab(tab_text, is_active_tab, index == 0)
-}
diff --git a/src/client/layout.rs b/src/client/layout.rs
index c032be38..1b383540 100644
--- a/src/client/layout.rs
+++ b/src/client/layout.rs
@@ -4,6 +4,7 @@ use serde::{Deserialize, Serialize};
use std::path::{Path, PathBuf};
use std::{fs::File, io::prelude::*};
+use crate::common::wasm_vm::EventType;
use crate::panes::PositionAndSize;
fn split_space_to_parts_vertically(
@@ -180,6 +181,8 @@ pub struct Layout {
pub plugin: Option<PathBuf>,
#[serde(default)]
pub expansion_boundary: bool,
+ #[serde(default, skip_serializing_if = "Vec::is_empty")]
+ pub events: Vec<EventType>,
}
impl Layout {
diff --git a/src/client/tab.rs b/src/client/tab.rs
index bf096367..1ef0b720 100644
--- a/src/client/tab.rs
+++ b/src/client/tab.rs
@@ -2,11 +2,13 @@
//! as well as how they should be resized
use crate::common::{AppInstruction, SenderWithContext};
+use crate::layout::Layout;
use crate::panes::{PaneId, PositionAndSize, TerminalPane};
use crate::pty_bus::{PtyInstruction, VteEvent};
+use crate::wasm_vm::{PluginInputType, PluginInstruction};
use crate::{boundaries::Boundaries, panes::PluginPane};
-use crate::{layout::Layout, wasm_vm::PluginInstruction};
use crate::{os_input_output::OsApi, utils::shared::pad_to_size};
+use serde::{Deserialize, Serialize};
use std::os::unix::io::RawFd;
use std::{
cmp::Reverse,
@@ -51,6 +53,7 @@ fn split_horizontally_with_gap(rect: &PositionAndSize) -> (PositionAndSize, Posi
pub struct Tab {
pub index: usize,
pub position: usize,
+ pub name: String,
panes: BTreeMap<PaneId, Box<dyn Pane>>,
panes_to_hide: HashSet<PaneId>,
active_terminal: Option<PaneId>,
@@ -64,6 +67,14 @@ pub struct Tab {
expansion_boundary: Option<PositionAndSize>,
}
+#[derive(Clone, Debug, Default, Serialize, Deserialize)]
+pub struct TabData {
+ /* subset of fields to publish to plugins */
+ pub position: usize,
+ pub name: String,
+ pub active: bool,
+}
+
// FIXME: Use a struct that has a pane_type enum, to reduce all of the duplication
pub trait Pane {
fn x(&self) -> usize;
@@ -170,6 +181,7 @@ impl Tab {
pub fn new(
index: usize,
position: usize,
+ name: String,
full_screen_ws: &PositionAndSize,
mut os_api: Box<dyn OsApi>,
send_pty_instructions: SenderWithContext<PtyInstruction>,
@@ -195,6 +207,7 @@ impl Tab {
index,
position,
panes,
+ name,
max_panes,
panes_to_hide: HashSet::new(),
active_terminal: pane_id,
@@ -249,7 +262,11 @@ impl Tab {
if let Some(plugin) = &layout.plugin {
let (pid_tx, pid_rx) = channel();
self.send_plugin_instructions
- .send(PluginInstruction::Load(pid_tx, plugin.clone()))
+ .send(PluginInstruction::Load(
+ pid_tx,
+ plugin.clone(),
+ layout.events.clone(),
+ ))
.unwrap();
let pid = pid_rx.recv().unwrap();
let new_plugin = PluginPane::new(
@@ -546,7 +563,10 @@ impl Tab {
}
Some(PaneId::Plugin(pid)) => {
self.send_plugin_instructions
- .send(PluginInstruction::Input(pid, input_bytes))
+ .send(PluginInstruction::Input(
+ PluginInputType::Normal(pid),
+ input_bytes,
+ ))
.unwrap();
}
_ => {}
diff --git a/src/common/errors.rs b/src/common/errors.rs
index 03aec714..df741629 100644
--- a/src/common/errors.rs
+++ b/src/common/errors.rs
@@ -198,6 +198,7 @@ pub enum ScreenContext {
SwitchTabPrev,
CloseTab,
GoToTab,
+ UpdateTabName,
}
impl From<&ScreenInstruction> for ScreenContext {
@@ -236,6 +237,7 @@ impl From<&ScreenInstruction> for ScreenContext {
ScreenInstruction::SwitchTabPrev => ScreenContext::SwitchTabPrev,
ScreenInstruction::CloseTab => ScreenContext::CloseTab,
ScreenInstruction::GoToTab(_) => ScreenContext::GoToTab,
+ ScreenInstruction::UpdateTabName(_) => ScreenContext::UpdateTabName,
}
}
}
diff --git a/src/common/input/actions.rs b/src/common/input/actions.rs
index fe5e2dad..88a7036f 100644
--- a/src/common/input/actions.rs
+++ b/src/common/input/actions.rs
@@ -48,4 +48,6 @@ pub enum Action {
/// Close the current tab.
CloseTab,
GoToTab(u32),
+ TabNameInput(Vec<u8>),
+ SaveTabName,
}
diff --git a/src/common/input/handler.rs b/src/common/input/handler.rs
index 5c4f1971..52db9b4f 100644
--- a/src/common/input/handler.rs
+++ b/src/common/input/handler.rs
@@ -7,7 +7,7 @@ use crate::errors::ContextType;
use crate::os_input_output::OsApi;
use crate::pty_bus::PtyInstruction;
use crate::screen::ScreenInstruction;
-use crate::wasm_vm::PluginInstruction;
+use crate::wasm_vm::{EventType, PluginInputType, PluginInstruction};
use crate::CommandIsExecuting;
use serde::{Deserialize, Serialize};
@@ -232,6 +232,28 @@ impl InputHandler {
.send(ScreenInstruction::GoToTab(i))
.unwrap();
}
+ Action::TabNameInput(c) => {
+ self.send_plugin_instructions
+ .send(PluginInstruction::Input(
+ PluginInputType::Event(EventType::Tab),
+ c.clone(),
+ ))
+ .unwrap();
+ self.send_screen_instructions
+ .send(ScreenInstruction::UpdateTabName(c))
+ .unwrap();
+ }
+ Action::SaveTabName => {
+ self.send_plugin_instructions
+ .send(PluginInstruction::Input(
+ PluginInputType::Event(EventType::Tab),
+ vec![b'\n'],
+ ))
+ .unwrap();
+ self.send_screen_instructions
+ .send(ScreenInstruction::UpdateTabName(vec![b'\n']))
+ .unwrap();
+ }
Action::NoOp => {}
}
@@ -265,6 +287,7 @@ pub enum InputMode {
Tab,
/// `Scroll` mode allows scrolling up and down within a pane.
Scroll,
+ RenameTab,
}
/// Represents the contents of the help message that is printed in the status bar,
@@ -310,10 +333,14 @@ pub fn get_help(mode: InputMode) -> Help {
keybinds.push(("←↓↑→".to_string(), "Move focus".to_string()));
keybinds.push(("n".to_string(), "New".to_string()));
keybinds.push(("x".to_string(), "Close".to_string()));
+ keybinds.push(("r".to_string(), "Rename".to_string()));
}
InputMode::Scroll => {
keybinds.push(("↓↑".to_string(), "Scroll".to_string()));
}
+ InputMode::RenameTab => {
+ keybinds.push(("Enter".to_string(), "when done".to_string()));
+ }
}
keybinds.push(("ESC".to_string(), "BACK".to_string()));
keybinds.push(("q".to_string(), "QUIT".to_string()));
diff --git a/src/common/input/keybinds.rs b/src/common/input/keybinds.rs
index e56488b4..46abf4ab 100644
--- a/src/common/input/keybinds.rs
+++ b/src/common/input/keybinds.rs
@@ -128,6 +128,13 @@ fn get_defaults_for_mode(mode: &InputMode) -> Result<ModeKeybinds, String> {
defaults.insert(Key::Char('n'), vec![Action::NewTab]);
defaults.insert(Key::Char('x'), vec![Action::CloseTab]);
+ defaults.insert(
+ Key::Char('r'),
+ vec![
+ Action::SwitchToMode(InputMode::RenameTab),
+ Action::TabNameInput(vec![0]),
+ ],
+ );
defaults.insert(Key::Char('q'), vec![Action::Quit]);
defaults.insert(
Key::Ctrl('g'),
@@ -155,6 +162,23 @@ fn get_defaults_for_mode(mode: &InputMode) -> Result<ModeKeybinds, String> {
);
defaults.insert(Key::Esc, vec![Action::SwitchToMode(InputMode::Command)]);
}
+ InputMode::RenameTab => {
+ defaults.insert(
+ Key::Char('\n'),
+ vec![Action::SaveTabName, Action::SwitchToMode(InputMode::Tab)],
+ );
+ defaults.insert(
+ Key::Ctrl('g'),
+ vec![Action::SwitchToMode(InputMode::Normal)],
+ );
+ defaults.insert(
+ Key::Esc,
+ vec![
+ Action::TabNameInput(vec![0x1b]),
+ Action::SwitchToMode(InputMode::Tab),
+ ],
+ );
+ }
}
Ok(defaults)
@@ -178,6 +202,7 @@ pub fn key_to_actions(
};
match *mode {
InputMode::Normal => mode_keybind_or_action(Action::Write(input)),
+ InputMode::RenameTab => mode_keybind_or_action(Action::TabNameInput(input)),
_ => mode_keybind_or_action(Action::NoOp),
}
}
diff --git a/src/common/mod.rs b/src/common/mod.rs
index f78303ea..7b19bcef 100644
--- a/src/common/mod.rs
+++ b/src/common/mod.rs
@@ -34,7 +34,9 @@ use os_input_output::OsApi;
use pty_bus::{PtyBus, PtyInstruction};
use screen::{Screen, ScreenInstruction};
use utils::consts::{ZELLIJ_IPC_PIPE, ZELLIJ_ROOT_PLUGIN_DIR};
-use wasm_vm::{wasi_stdout, wasi_write_string, zellij_imports, PluginInstruction};
+use wasm_vm::{
+ wasi_stdout, wasi_write_string, zellij_imports, EventType, PluginInputType, PluginInstruction,
+};
#[derive(Serialize, Deserialize, Debug)]
pub enum ApiCommand {
@@ -419,6 +421,9 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) {
ScreenInstruction::GoToTab(tab_index) => {
screen.go_to_tab(tab_index as usize)
}
+ ScreenInstruction::UpdateTabName(c) => {
+ screen.update_active_tab_name(c);
+ }
ScreenInstruction::Quit => {
break;
}
@@ -438,6 +443,11 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) {
let store = Store::default();
let mut plugin_id = 0;
let mut plugin_map = HashMap::new();
+ let handler_map: HashMap<EventType, String> =
+ [(EventType::Tab, "handle_tab_rename_keypress".to_string())]
+ .iter()
+ .cloned()
+ .collect();
move || loop {
let (event, mut err_ctx) = receive_plugin_instructions
@@ -448,7 +458,7 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) {
send_pty_instructions.update(err_ctx);
send_app_instructions.update(err_ctx);
match event {
- PluginInstruction::Load(pid_tx, path) => {
+ PluginInstruction::Load(pid_tx, path, events) => {
let project_dirs =
ProjectDirs::from("org", "Zellij Contributors", "Zellij").unwrap();
let plugin_dir = project_dirs.data_dir().join("plugins/");
@@ -490,6 +500,7 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) {
send_screen_instructions: send_screen_instructions.clone(),
send_app_instructions: send_app_instructions.clone(),
wasi_env,
+ events,
};
let zellij = zellij_imports(&store, &plugin_env);
@@ -514,32 +525,58 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) {
buf_tx.send(wasi_stdout(&plugin_env.wasi_env)).unwrap();
}
- PluginInstruction::UpdateTabs(active_tab_index, num_tabs) => {
- for (instance, _) in plugin_map.values() {
+ PluginInstruction::UpdateTabs(mut tabs) => {
+ for (instance, plugin_env) in plugin_map.values() {
+ if !plugin_env.events.contains(&EventType::Tab) {
+ continue;
+ }
let handler = instance.exports.get_function("update_tabs").unwrap();
- handler
- .call(&[
- Value::I32(active_tab_index as i32),
- Value::I32(num_tabs as i32),
- ])
- .unwrap();
+ tabs.sort_by(|a, b| a.position.cmp(&b.position));
+ wasi_write_string(
+ &plugin_env.wasi_env,
+ &serde_json::to_string(&tabs).unwrap(),
+ );
+ handler.call(&[]).unwrap();
}
}
// FIXME: Deduplicate this with the callback below!
- PluginInstruction::Input(pid, input_bytes) => {
- let (instance, plugin_env) = plugin_map.get(&pid).unwrap();
-
- let handle_key = instance.exports.get_function("handle_key").unwrap();
- for key in input_bytes.keys() {
- if let Ok(key) = key {
- wasi_write_string(
- &plugin_env.wasi_env,
- &serde_json::to_string(&key).unwrap(),
- );
- handle_key.call(&[]).unwrap();
+ PluginInstruction::Input(input_type, input_bytes) => {
+ match input_type {
+ PluginInputType::Normal(pid) => {
+ let (instance, plugin_env) = plugin_map.get(&pid).unwrap();
+ let handle_key =
+ instance.exports.get_function("handle_key").unwrap();
+ for key in input_bytes.keys() {
+ if let Ok(key) = key {
+ wasi_write_string(
+ &plugin_env.wasi_env,
+ &serde_json::to_string(&key).unwrap(),
+ );
+ handle_key.call(&[]).unwrap();
+ }
+ }
+ }
+ PluginInputType::Event(event) => {
+ for (instance, plugin_env) in plugin_map.values() {
+ if !plugin_env.events.contains(&event) {
+ continue;
+ }
+ let handle_key = instance
+ .exports
+ .get_function(handler_map.get(&event).unwrap())
+ .unwrap();
+ for key in input_bytes.keys() {
+ if let Ok(key) = key {
+ wasi_write_string(
+ &plugin_env.wasi_env,
+ &serde_json::to_string(&key).unwrap(),
+ );
+ handle_key.call(&[]).unwrap();
+ }
+ }
+ }
}
}
-
drop(send_screen_instructions.send(ScreenInstruction::Render));
}
PluginInstruction::GlobalInput(input_bytes) => {
diff --git a/src/common/screen.rs b/src/common/screen.rs
index 7747b43b..199a1223 100644
--- a/src/common/screen.rs
+++ b/src/common/screen.rs
@@ -2,13 +2,14 @@
use std::collections::BTreeMap;
use std::os::unix::io::RawFd;
+use std::str;
use std::sync::mpsc::Receiver;
use super::{AppInstruction, SenderWithContext};
use crate::os_input_output::OsApi;
use crate::panes::PositionAndSize;
use crate::pty_bus::{PtyInstruction, VteEvent};
-use crate::tab::Tab;
+use crate::tab::{Tab, TabData};
use crate::{errors::ErrorContext, wasm_vm::PluginInstruction};
use crate::{layout::Layout, panes::PaneId};
@@ -46,6 +47,7 @@ pub enum ScreenInstruction {
SwitchTabPrev,
CloseTab,
GoToTab(u32),
+ UpdateTabName(Vec<u8>),
}
/// A [`Screen`] holds multiple [`Tab`]s, each one holding multiple [`panes`](crate::client::panes).
@@ -69,6 +71,7 @@ pub struct Screen {
active_tab_index: Option<usize>,
/// The [`OsApi`] this [`Screen`] uses.
os_api: Box<dyn OsApi>,
+ tabname_buf: String,
}
impl Screen {
@@ -92,6 +95,7 @@ impl Screen {
active_tab_index: None,
tabs: BTreeMap::new(),
os_api,
+ tabname_buf: String::new(),
}
}
@@ -103,6 +107,7 @@ impl Screen {
let tab = Tab::new(
tab_index,
position,
+ String::new(),
&self.full_screen_ws,
self.os_api.clone(),
self.send_pty_instructions.clone(),
@@ -246,6 +251,7 @@ impl Screen {
let mut tab = Tab::new(
tab_index,
position,
+ String::new(),
&self.full_screen_ws,
self.os_api.clone(),
self.send_pty_instructions.clone(),
@@ -261,13 +267,36 @@ impl Screen {
}
fn update_tabs(&self) {
- if let Some(active_tab) = self.get_active_tab() {
- self.send_plugin_instructions
- .send(PluginInstruction::UpdateTabs(
- active_tab.position,
- self.tabs.len(),
- ))
- .unwrap();
+ let mut tab_data = vec![];
+ let active_tab_index = self.active_tab_index.unwrap();
+ for tab in self.tabs.values() {
+ tab_data.push(TabData {
+ position: tab.position,
+ name: tab.name.clone(),
+ active: active_tab_index == tab.index,
+ });
+ }
+ self.send_plugin_instructions
+ .send(PluginInstruction::UpdateTabs(tab_data))
+ .unwrap();
+ }
+
+ pub fn update_active_tab_name(&mut self, buf: Vec<u8>) {
+ let s = str::from_utf8(&buf).unwrap();
+ match s {
+ "\0" => {
+ self.tabname_buf = String::new();
+ }
+ "\n" => {
+ let new_name = self.tabname_buf.clone();
+ let active_tab = self.get_active_tab_mut().unwrap();
+ active_tab.name = new_name;
+ self.update_tabs();
+ self.render();
+ }
+ c => {
+ self.tabname_buf.push_str(c);
+ }
}
}
}
diff --git a/src/common/wasm_vm.rs b/src/common/wasm_vm.rs
index 5d4b1e30..15b920ad 100644
--- a/src/common/wasm_vm.rs
+++ b/src/common/wasm_vm.rs
@@ -1,24 +1,36 @@
+use crate::tab::TabData;
+use serde::{Deserialize, Serialize};
use std::{
path::PathBuf,
sync::mpsc::{channel, Sender},
};
use wasmer::{imports, Function, ImportObject, Store, WasmerEnv};
use wasmer_wasi::WasiEnv;
-// use crate::utils::logging::debug_log_to_file;
use super::{
input::handler::get_help, pty_bus::PtyInstruction, screen::ScreenInstruction, AppInstruction,
PaneId, SenderWithContext,
};
+#[derive(Clone, Debug, PartialEq, Hash, Eq, Serialize, Deserialize)]
+pub enum EventType {
+ Tab,
+}
+
+#[derive(Clone, Debug)]
+pub enum PluginInputType {
+ Normal(u32),
+ Event(EventType),
+}
+
#[derive(Clone, Debug)]
pub enum PluginInstruction {
- Load(Sender<u32>, PathBuf),
+ Load(Sender<u32>, PathBuf, Vec<EventType>),
Draw(Sender<String>, u32, usize, usize), // String buffer, plugin id, rows, cols
- Input(u32, Vec<u8>), // plugin id, input bytes
+ Input(PluginInputType, Vec<u8>), // plugin id, input bytes
GlobalInput(Vec<u8>), // input bytes
Unload(u32),
- UpdateTabs(usize, usize), // num tabs, active tab
+ UpdateTabs(Vec<TabData>), // num tabs, active tab
Quit,
}
@@ -29,6 +41,7 @@ pub struct PluginEnv {
pub send_app_instructions: SenderWithContext<AppInstruction>,
pub send_pty_instructions: SenderWithContext<PtyInstruction>, // FIXME: This should be a big bundle of all of the channels
pub wasi_env: WasiEnv,
+ pub events: Vec<EventType>,
}
// Plugin API ---------------------------------------------------------------------------------------------------------
diff --git a/zellij-tile/src/lib.rs b/zellij-tile/src/lib.rs
index b5ba63fe..de87ee9c 100644
--- a/zellij-tile/src/lib.rs
+++ b/zellij-tile/src/lib.rs
@@ -7,7 +7,8 @@ pub trait ZellijTile {
fn draw(&mut self, rows: usize, cols: usize) {}
fn handle_key(&mut self, key: Key) {}
fn handle_global_key(&mut self, key: Key) {}
- fn update_tabs(&mut self, active_tab_index: usize, num_active_tabs: usize) {}
+ fn update_tabs(&mut self) {}
+ fn handle_tab_rename_keypress(&mut self, key: Key) {}
}
#[macro_export]
@@ -45,11 +46,18 @@ macro_rules! register_tile {
}
#[no_mangle]
- pub fn update_tabs(active_tab_index: i32, num_active_tabs: i32) {
+ pub fn update_tabs() {
+ STATE.with(|state| {
+ state.borrow_mut().update_tabs();
+ })
+ }
+
+ #[no_mangle]
+ pub fn handle_tab_rename_keypress() {
STATE.with(|state| {
state
.borrow_mut()
- .update_tabs(active_tab_index as usize, num_active_tabs as usize);
+ .handle_tab_rename_keypress($crate::get_key());
})
}
};
diff --git a/zellij-tile/src/shim.rs b/zellij-tile/src/shim.rs
index 52740472..20185c72 100644
--- a/zellij-tile/src/shim.rs
+++ b/zellij-tile/src/shim.rs
@@ -38,10 +38,19 @@ pub enum InputMode {
Resize,
Pane,
Tab,
+ RenameTab,
Scroll,
Exiting,
}
+#[derive(Debug, Clone, Deserialize, Serialize)]
+pub struct TabData {
+ /* subset of fields to publish to plugins */
+ pub position: usize,
+ pub name: String,
+ pub active: bool,
+}
+
impl Default for InputMode {
fn default() -> InputMode {
InputMode::Normal
@@ -76,6 +85,10 @@ pub fn get_help() -> Help {
deserialize_from_stdin().unwrap_or_default()
}
+pub fn get_tabs() -> Vec<TabData> {
+ deserialize_from_stdin().unwrap_or_default()
+}
+
fn deserialize_from_stdin<T: DeserializeOwned>() -> Option<T> {
let mut json = String::new();
io::stdin().read_line(&mut json).unwrap();