aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJonah Caplan <jonahcaplan@gmail.com>2021-02-20 18:19:05 -0500
committerJonah Caplan <jonahcaplan@gmail.com>2021-02-25 01:44:10 -0500
commitce54127d7de314e683ed0fefd8be987bbc47e369 (patch)
tree0fd91434af3477f9b7c16a61b822537a18abcca2 /src
parentMake fullscreen panes not override the status bar and strider (#209) (diff)
downloadsl0ppij-ce54127d7de314e683ed0fefd8be987bbc47e369.tar.gz
sl0ppij-ce54127d7de314e683ed0fefd8be987bbc47e369.tar.xz
sl0ppij-ce54127d7de314e683ed0fefd8be987bbc47e369.zip
add basic tab bar #166
Diffstat (limited to 'src')
-rw-r--r--src/client/tab.rs3
-rw-r--r--src/common/errors.rs4
-rw-r--r--src/common/input/actions.rs1
-rw-r--r--src/common/input/handler.rs5
-rw-r--r--src/common/input/keybinds.rs3
-rw-r--r--src/common/mod.rs14
-rw-r--r--src/common/screen.rs79
-rw-r--r--src/common/wasm_vm.rs1
-rw-r--r--src/main.rs1
9 files changed, 93 insertions, 18 deletions
diff --git a/src/client/tab.rs b/src/client/tab.rs
index bdbf7db1..bf096367 100644
--- a/src/client/tab.rs
+++ b/src/client/tab.rs
@@ -50,6 +50,7 @@ fn split_horizontally_with_gap(rect: &PositionAndSize) -> (PositionAndSize, Posi
pub struct Tab {
pub index: usize,
+ pub position: usize,
panes: BTreeMap<PaneId, Box<dyn Pane>>,
panes_to_hide: HashSet<PaneId>,
active_terminal: Option<PaneId>,
@@ -168,6 +169,7 @@ impl Tab {
// FIXME: Too many arguments here! Maybe bundle all of the senders for the whole program in a struct?
pub fn new(
index: usize,
+ position: usize,
full_screen_ws: &PositionAndSize,
mut os_api: Box<dyn OsApi>,
send_pty_instructions: SenderWithContext<PtyInstruction>,
@@ -191,6 +193,7 @@ impl Tab {
};
Tab {
index,
+ position,
panes,
max_panes,
panes_to_hide: HashSet::new(),
diff --git a/src/common/errors.rs b/src/common/errors.rs
index 3d105dbc..03aec714 100644
--- a/src/common/errors.rs
+++ b/src/common/errors.rs
@@ -197,6 +197,7 @@ pub enum ScreenContext {
SwitchTabNext,
SwitchTabPrev,
CloseTab,
+ GoToTab,
}
impl From<&ScreenInstruction> for ScreenContext {
@@ -234,6 +235,7 @@ impl From<&ScreenInstruction> for ScreenContext {
ScreenInstruction::SwitchTabNext => ScreenContext::SwitchTabNext,
ScreenInstruction::SwitchTabPrev => ScreenContext::SwitchTabPrev,
ScreenInstruction::CloseTab => ScreenContext::CloseTab,
+ ScreenInstruction::GoToTab(_) => ScreenContext::GoToTab,
}
}
}
@@ -277,6 +279,7 @@ pub enum PluginContext {
GlobalInput,
Unload,
Quit,
+ Tabs,
}
impl From<&PluginInstruction> for PluginContext {
@@ -288,6 +291,7 @@ impl From<&PluginInstruction> for PluginContext {
PluginInstruction::GlobalInput(_) => PluginContext::GlobalInput,
PluginInstruction::Unload(_) => PluginContext::Unload,
PluginInstruction::Quit => PluginContext::Quit,
+ PluginInstruction::UpdateTabs(..) => PluginContext::Tabs,
}
}
}
diff --git a/src/common/input/actions.rs b/src/common/input/actions.rs
index eee8b1b6..fe5e2dad 100644
--- a/src/common/input/actions.rs
+++ b/src/common/input/actions.rs
@@ -47,4 +47,5 @@ pub enum Action {
GoToPreviousTab,
/// Close the current tab.
CloseTab,
+ GoToTab(u32),
}
diff --git a/src/common/input/handler.rs b/src/common/input/handler.rs
index 2a8c3bfa..5c4f1971 100644
--- a/src/common/input/handler.rs
+++ b/src/common/input/handler.rs
@@ -227,6 +227,11 @@ impl InputHandler {
.unwrap();
self.command_is_executing.wait_until_pane_is_closed();
}
+ Action::GoToTab(i) => {
+ self.send_screen_instructions
+ .send(ScreenInstruction::GoToTab(i))
+ .unwrap();
+ }
Action::NoOp => {}
}
diff --git a/src/common/input/keybinds.rs b/src/common/input/keybinds.rs
index c573a557..e56488b4 100644
--- a/src/common/input/keybinds.rs
+++ b/src/common/input/keybinds.rs
@@ -133,6 +133,9 @@ fn get_defaults_for_mode(mode: &InputMode) -> Result<ModeKeybinds, String> {
Key::Ctrl('g'),
vec![Action::SwitchToMode(InputMode::Normal)],
);
+ for i in '1'..='9' {
+ defaults.insert(Key::Char(i), vec![Action::GoToTab(i.to_digit(10).unwrap())]);
+ }
defaults.insert(Key::Esc, vec![Action::SwitchToMode(InputMode::Command)]);
}
InputMode::Scroll => {
diff --git a/src/common/mod.rs b/src/common/mod.rs
index 8f37994f..f78303ea 100644
--- a/src/common/mod.rs
+++ b/src/common/mod.rs
@@ -416,6 +416,9 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) {
screen.apply_layout(layout, new_pane_pids);
command_is_executing.done_opening_new_pane();
}
+ ScreenInstruction::GoToTab(tab_index) => {
+ screen.go_to_tab(tab_index as usize)
+ }
ScreenInstruction::Quit => {
break;
}
@@ -511,6 +514,17 @@ 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() {
+ 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();
+ }
+ }
// FIXME: Deduplicate this with the callback below!
PluginInstruction::Input(pid, input_bytes) => {
let (instance, plugin_env) = plugin_map.get(&pid).unwrap();
diff --git a/src/common/screen.rs b/src/common/screen.rs
index 1e04e231..7747b43b 100644
--- a/src/common/screen.rs
+++ b/src/common/screen.rs
@@ -45,6 +45,7 @@ pub enum ScreenInstruction {
SwitchTabNext,
SwitchTabPrev,
CloseTab,
+ GoToTab(u32),
}
/// A [`Screen`] holds multiple [`Tab`]s, each one holding multiple [`panes`](crate::client::panes).
@@ -98,8 +99,10 @@ impl Screen {
/// [pane](crate::client::panes) with PTY file descriptor `pane_id`.
pub fn new_tab(&mut self, pane_id: RawFd) {
let tab_index = self.get_new_tab_index();
+ let position = self.tabs.len();
let tab = Tab::new(
tab_index,
+ position,
&self.full_screen_ws,
self.os_api.clone(),
self.send_pty_instructions.clone(),
@@ -110,6 +113,7 @@ impl Screen {
);
self.active_tab_index = Some(tab_index);
self.tabs.insert(tab_index, tab);
+ self.update_tabs();
self.render();
}
@@ -126,34 +130,52 @@ impl Screen {
/// Sets this [`Screen`]'s active [`Tab`] to the next tab.
pub fn switch_tab_next(&mut self) {
- let active_tab_id = self.get_active_tab().unwrap().index;
- let tab_ids: Vec<usize> = self.tabs.keys().copied().collect();
- let first_tab = tab_ids.get(0).unwrap();
- let active_tab_id_position = tab_ids.iter().position(|id| id == &active_tab_id).unwrap();
- if let Some(next_tab) = tab_ids.get(active_tab_id_position + 1) {
- self.active_tab_index = Some(*next_tab);
- } else {
- self.active_tab_index = Some(*first_tab);
+ let active_tab_pos = self.get_active_tab().unwrap().position;
+ let new_tab_pos = (active_tab_pos + 1) % self.tabs.len();
+
+ for tab in self.tabs.values() {
+ if tab.position == new_tab_pos {
+ self.active_tab_index = Some(tab.index);
+ break;
+ }
}
+ self.update_tabs();
self.render();
}
/// Sets this [`Screen`]'s active [`Tab`] to the previous tab.
pub fn switch_tab_prev(&mut self) {
- let active_tab_id = self.get_active_tab().unwrap().index;
- let tab_ids: Vec<usize> = self.tabs.keys().copied().collect();
- let first_tab = tab_ids.get(0).unwrap();
- let last_tab = tab_ids.last().unwrap();
-
- let active_tab_id_position = tab_ids.iter().position(|id| id == &active_tab_id).unwrap();
- if active_tab_id == *first_tab {
- self.active_tab_index = Some(*last_tab)
- } else if let Some(prev_tab) = tab_ids.get(active_tab_id_position - 1) {
- self.active_tab_index = Some(*prev_tab)
+ let active_tab_pos = self.get_active_tab().unwrap().position;
+ let new_tab_pos = if active_tab_pos == 0 {
+ self.tabs.len() - 1
+ } else {
+ active_tab_pos - 1
+ };
+ for tab in self.tabs.values() {
+ if tab.position == new_tab_pos {
+ self.active_tab_index = Some(tab.index);
+ break;
+ }
}
+ self.update_tabs();
self.render();
}
+ pub fn go_to_tab(&mut self, mut tab_index: usize) {
+ tab_index -= 1;
+ let active_tab = self.get_active_tab().unwrap();
+ match self.tabs.values().find(|t| t.position == tab_index) {
+ Some(t) => {
+ if t.index != active_tab.index {
+ self.active_tab_index = Some(t.index);
+ self.update_tabs();
+ self.render();
+ }
+ }
+ None => {}
+ }
+ }
+
/// Closes this [`Screen`]'s active [`Tab`], exiting the application if it happens
/// to be the last tab.
pub fn close_tab(&mut self) {
@@ -174,6 +196,13 @@ impl Screen {
self.send_app_instructions
.send(AppInstruction::Exit)
.unwrap();
+ } else {
+ for t in self.tabs.values_mut() {
+ if t.position > active_tab.position {
+ t.position -= 1;
+ }
+ }
+ self.update_tabs();
}
}
@@ -213,8 +242,10 @@ impl Screen {
/// and switching to it.
pub fn apply_layout(&mut self, layout: Layout, new_pids: Vec<RawFd>) {
let tab_index = self.get_new_tab_index();
+ let position = self.tabs.len();
let mut tab = Tab::new(
tab_index,
+ position,
&self.full_screen_ws,
self.os_api.clone(),
self.send_pty_instructions.clone(),
@@ -226,5 +257,17 @@ impl Screen {
tab.apply_layout(layout, new_pids);
self.active_tab_index = Some(tab_index);
self.tabs.insert(tab_index, tab);
+ self.update_tabs();
+ }
+
+ 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();
+ }
}
}
diff --git a/src/common/wasm_vm.rs b/src/common/wasm_vm.rs
index 70808b5d..5d4b1e30 100644
--- a/src/common/wasm_vm.rs
+++ b/src/common/wasm_vm.rs
@@ -18,6 +18,7 @@ pub enum PluginInstruction {
Input(u32, Vec<u8>), // plugin id, input bytes
GlobalInput(Vec<u8>), // input bytes
Unload(u32),
+ UpdateTabs(usize, usize), // num tabs, active tab
Quit,
}
diff --git a/src/main.rs b/src/main.rs
index 91a7b422..c4123e55 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -33,6 +33,7 @@ pub fn main() {
let data_dir = project_dirs.data_dir();
let assets = asset_map! {
"target/status-bar.wasm" => "plugins/status-bar.wasm",
+ "target/tab-bar.wasm" => "plugins/tab-bar.wasm",
"target/strider.wasm" => "plugins/strider.wasm",
"assets/layouts/default.yaml" => "layouts/default.yaml",
"assets/layouts/strider.yaml" => "layouts/strider.yaml",