summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authora-kenji <aks.kenji@protonmail.com>2021-08-01 20:25:33 +0200
committera-kenji <aks.kenji@protonmail.com>2021-08-01 20:25:33 +0200
commitfc7bc3cc8b8b6e6c652e85bb47424338e7038cbe (patch)
treeeb43e2b04ebe0c26e286bab77d842304ddae596d
parent806ffad5539c99380e7c0e423f4c864d8db431e2 (diff)
parent309f4a62bfd11bd1c311d833343625f9bc476114 (diff)
Merge branch 'main' of https://github.com/zellij-org/zellij into tab-layout
-rw-r--r--CHANGELOG.md4
-rw-r--r--GOVERNANCE.md1
-rw-r--r--src/main.rs49
-rw-r--r--zellij-server/src/route.rs6
-rw-r--r--zellij-server/src/screen.rs93
-rw-r--r--zellij-server/src/tab.rs14
-rw-r--r--zellij-server/src/wasm_vm.rs12
-rw-r--r--zellij-utils/assets/config/default.yaml2
-rw-r--r--zellij-utils/src/errors.rs1
-rw-r--r--zellij-utils/src/input/actions.rs2
-rw-r--r--zellij-utils/src/input/layout.rs22
-rw-r--r--zellij-utils/src/input/unit/layout_test.rs5
-rw-r--r--zellij-utils/src/setup.rs80
13 files changed, 199 insertions, 92 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ad53c6c99..97f68875b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -12,6 +12,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
* Add displaying of the `session-name` to the `tab-bar` (https://github.com/zellij-org/zellij/pull/608)
* Add command to dump `layouts` to stdout (https://github.com/zellij-org/zellij/pull/623)
* `zellij setup --dump-layout [LAYOUT]` [default, strider, disable-status]
+* Add `action`: `ScrollToBottom` (https://github.com/zellij-org/zellij/pull/626)
+ * Bound by default to `^c` in `scroll` mode, scrolls to bottom and exists the scroll mode
+* Simplify deserialization slightly (https://github.com/zellij-org/zellij/pull/633)
+* Fix update plugin attributes on inactive tab (https://github.com/zellij-org/zellij/pull/634)
## [0.15.0] - 2021-07-19
* Kill children properly (https://github.com/zellij-org/zellij/pull/601)
diff --git a/GOVERNANCE.md b/GOVERNANCE.md
index b405d29db..698630697 100644
--- a/GOVERNANCE.md
+++ b/GOVERNANCE.md
@@ -29,3 +29,4 @@ Once the organization reaches 10 members, a reasonable and achievable process mu
* Roee Shapira <ro33.sha@gmail.com>
* Alex Kenji Berthold <aks.kenji@protonmail.com>
* Kyle Sutherland-Cash <kyle.sutherlandcash@gmail.com>
+* Dante Pippi <dante.dpf@gmail.com> \ No newline at end of file
diff --git a/src/main.rs b/src/main.rs
index 76a44d750..f0d00f77a 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -5,16 +5,14 @@ mod tests;
use crate::install::populate_data_dir;
use sessions::{assert_session, assert_session_ne, get_active_session, list_sessions};
-use std::convert::TryFrom;
use std::process;
use zellij_client::{os_input_output::get_client_os_input, start_client, ClientInfo};
use zellij_server::{os_input_output::get_server_os_input, start_server};
use zellij_utils::{
cli::{CliArgs, Command, Sessions},
consts::{ZELLIJ_TMP_DIR, ZELLIJ_TMP_LOG_DIR},
- input::{config::Config, layout::Layout, options::Options},
logging::*,
- setup::{find_default_config_dir, get_default_data_dir, get_layout_dir, Setup},
+ setup::{get_default_data_dir, Setup},
structopt::StructOpt,
};
@@ -26,25 +24,6 @@ pub fn main() {
list_sessions();
}
- let config = match Config::try_from(&opts) {
- Ok(config) => config,
- Err(e) => {
- eprintln!("There was an error in the config file:\n{}", e);
- process::exit(1);
- }
- };
- let config_options = Options::from_cli(&config.options, opts.command.clone());
-
- if let Some(Command::Setup(ref setup)) = opts.command {
- Setup::from_cli(setup, &opts, &config_options).map_or_else(
- |e| {
- eprintln!("{:?}", e);
- process::exit(1);
- },
- |_| {},
- );
- };
-
atomic_create_dir(&*ZELLIJ_TMP_DIR).unwrap();
atomic_create_dir(&*ZELLIJ_TMP_LOG_DIR).unwrap();
if let Some(path) = opts.server {
@@ -75,6 +54,14 @@ pub fn main() {
session_name = Some(get_active_session());
}
+ let (config, _, config_options) = match Setup::from_options(&opts) {
+ Ok(results) => results,
+ Err(e) => {
+ eprintln!("{}", e);
+ process::exit(1);
+ }
+ };
+
start_client(
Box::new(os_input),
opts,
@@ -83,6 +70,14 @@ pub fn main() {
None,
);
} else {
+ let (config, layout, _) = match Setup::from_options(&opts) {
+ Ok(results) => results,
+ Err(e) => {
+ eprintln!("{}", e);
+ process::exit(1);
+ }
+ };
+
let session_name = opts
.session
.clone()
@@ -94,16 +89,6 @@ pub fn main() {
#[cfg(not(disable_automatic_asset_installation))]
populate_data_dir(&data_dir);
- let layout_dir = config_options.layout_dir.or_else(|| {
- get_layout_dir(opts.config_dir.clone().or_else(find_default_config_dir))
- });
- let layout = Layout::from_path_or_default(
- opts.layout.as_ref(),
- opts.layout_path.as_ref(),
- layout_dir,
- )
- .map(|layout| layout.construct_main_layout());
-
start_client(
Box::new(os_input),
opts,
diff --git a/zellij-server/src/route.rs b/zellij-server/src/route.rs
index 47eeabad1..7dbf09a7f 100644
--- a/zellij-server/src/route.rs
+++ b/zellij-server/src/route.rs
@@ -127,6 +127,12 @@ fn route_action(
.send_to_screen(ScreenInstruction::ScrollDownAt(point))
.unwrap();
}
+ Action::ScrollToBottom => {
+ session
+ .senders
+ .send_to_screen(ScreenInstruction::ScrollToBottom)
+ .unwrap();
+ }
Action::PageScrollUp => {
session
.senders
diff --git a/zellij-server/src/screen.rs b/zellij-server/src/screen.rs
index 86ecd6888..b348540fb 100644
--- a/zellij-server/src/screen.rs
+++ b/zellij-server/src/screen.rs
@@ -50,15 +50,16 @@ pub(crate) enum ScreenInstruction {
ScrollUpAt(Position),
ScrollDown,
ScrollDownAt(Position),
+ ScrollToBottom,
PageScrollUp,
PageScrollDown,
ClearScroll,
CloseFocusedPane,
ToggleActiveTerminalFullscreen,
- SetSelectable(PaneId, bool),
- SetFixedHeight(PaneId, usize),
- SetFixedWidth(PaneId, usize),
- SetInvisibleBorders(PaneId, bool),
+ SetSelectable(PaneId, bool, usize),
+ SetFixedHeight(PaneId, usize, usize),
+ SetFixedWidth(PaneId, usize, usize),
+ SetInvisibleBorders(PaneId, bool, usize),
ClosePane(PaneId),
ApplyLayout(Layout, Vec<RawFd>),
NewTab(RawFd),
@@ -103,6 +104,7 @@ impl From<&ScreenInstruction> for ScreenContext {
ScreenInstruction::Exit => ScreenContext::Exit,
ScreenInstruction::ScrollUp => ScreenContext::ScrollUp,
ScreenInstruction::ScrollDown => ScreenContext::ScrollDown,
+ ScreenInstruction::ScrollToBottom => ScreenContext::ScrollToBottom,
ScreenInstruction::PageScrollUp => ScreenContext::PageScrollUp,
ScreenInstruction::PageScrollDown => ScreenContext::PageScrollDown,
ScreenInstruction::ClearScroll => ScreenContext::ClearScroll,
@@ -335,6 +337,11 @@ impl Screen {
}
}
+ /// Returns a mutable reference to this [`Screen`]'s indexed [`Tab`].
+ pub fn get_indexed_tab_mut(&mut self, tab_index: usize) -> Option<&mut Tab> {
+ self.get_tabs_mut().get_mut(&tab_index)
+ }
+
/// Creates a new [`Tab`] in this [`Screen`], applying the specified [`Layout`]
/// and switching to it.
pub fn apply_layout(&mut self, layout: Layout, new_pids: Vec<RawFd>) {
@@ -353,7 +360,7 @@ impl Screen {
self.colors,
self.session_state.clone(),
);
- tab.apply_layout(layout, new_pids);
+ tab.apply_layout(layout, new_pids, tab_index);
self.active_tab_index = Some(tab_index);
self.tabs.insert(tab_index, tab);
self.update_tabs();
@@ -569,6 +576,12 @@ pub(crate) fn screen_thread_main(
.unwrap()
.scroll_terminal_down(&point, 3);
}
+ ScreenInstruction::ScrollToBottom => {
+ screen
+ .get_active_tab_mut()
+ .unwrap()
+ .scroll_active_terminal_to_bottom();
+ }
ScreenInstruction::PageScrollUp => {
screen
.get_active_tab_mut()
@@ -591,29 +604,53 @@ pub(crate) fn screen_thread_main(
screen.get_active_tab_mut().unwrap().close_focused_pane();
screen.render();
}
- ScreenInstruction::SetSelectable(id, selectable) => {
- screen
- .get_active_tab_mut()
- .unwrap()
- .set_pane_selectable(id, selectable);
- }
- ScreenInstruction::SetFixedHeight(id, fixed_height) => {
- screen
- .get_active_tab_mut()
- .unwrap()
- .set_pane_fixed_height(id, fixed_height);
- }
- ScreenInstruction::SetFixedWidth(id, fixed_width) => {
- screen
- .get_active_tab_mut()
- .unwrap()
- .set_pane_fixed_width(id, fixed_width);
- }
- ScreenInstruction::SetInvisibleBorders(id, invisible_borders) => {
- screen
- .get_active_tab_mut()
- .unwrap()
- .set_pane_invisible_borders(id, invisible_borders);
+ ScreenInstruction::SetSelectable(id, selectable, tab_index) => {
+ screen.get_indexed_tab_mut(tab_index).map_or_else(
+ || {
+ log::warn!(
+ "Tab index #{} not found, could not set selectable for plugin #{:?}.",
+ tab_index,
+ id
+ )
+ },
+ |tab| tab.set_pane_selectable(id, selectable),
+ );
+ }
+ ScreenInstruction::SetFixedHeight(id, fixed_height, tab_index) => {
+ screen.get_indexed_tab_mut(tab_index).map_or_else(
+ || {
+ log::warn!(
+ "Tab index #{} not found, could not set fixed height for plugin #{:?}.",
+ tab_index,
+ id
+ )
+ },
+ |tab| tab.set_pane_fixed_height(id, fixed_height),
+ );
+ }
+ ScreenInstruction::SetFixedWidth(id, fixed_width, tab_index) => {
+ screen.get_indexed_tab_mut(tab_index).map_or_else(
+ || {
+ log::warn!(
+ "Tab index #{} not found, could not set fixed width for plugin #{:?}.",
+ tab_index,
+ id
+ )
+ },
+ |tab| tab.set_pane_fixed_width(id, fixed_width),
+ );
+ }
+ ScreenInstruction::SetInvisibleBorders(id, invisible_borders, tab_index) => {
+ screen.get_indexed_tab_mut(tab_index).map_or_else(
+ || {
+ log::warn!(
+ r#"Tab index #{} not found, could not set invisible borders for plugin #{:?}."#,
+ tab_index,
+ id
+ )
+ },
+ |tab| tab.set_pane_invisible_borders(id, invisible_borders),
+ );
screen.render();
}
ScreenInstruction::ClosePane(id) => {
diff --git a/zellij-server/src/tab.rs b/zellij-server/src/tab.rs
index f3b30fe3a..0662be225 100644
--- a/zellij-server/src/tab.rs
+++ b/zellij-server/src/tab.rs
@@ -301,7 +301,7 @@ impl Tab {
}
}
- pub fn apply_layout(&mut self, layout: Layout, new_pids: Vec<RawFd>) {
+ pub fn apply_layout(&mut self, layout: Layout, new_pids: Vec<RawFd>, tab_index: usize) {
// TODO: this should be an attribute on Screen instead of full_screen_ws
let free_space = PositionAndSize {
x: 0,
@@ -340,7 +340,7 @@ impl Tab {
if let Some(Run::Plugin(Some(plugin))) = &layout.run {
let (pid_tx, pid_rx) = channel();
self.senders
- .send_to_plugin(PluginInstruction::Load(pid_tx, plugin.clone()))
+ .send_to_plugin(PluginInstruction::Load(pid_tx, plugin.clone(), tab_index))
.unwrap();
let pid = pid_rx.recv().unwrap();
let new_plugin = PluginPane::new(
@@ -2280,6 +2280,16 @@ impl Tab {
self.render();
}
}
+ pub fn scroll_active_terminal_to_bottom(&mut self) {
+ if let Some(active_terminal_id) = self.get_active_terminal_id() {
+ let active_terminal = self
+ .panes
+ .get_mut(&PaneId::Terminal(active_terminal_id))
+ .unwrap();
+ active_terminal.clear_scroll();
+ self.render();
+ }
+ }
pub fn clear_active_terminal_scroll(&mut self) {
if let Some(active_terminal_id) = self.get_active_terminal_id() {
let active_terminal = self
diff --git a/zellij-server/src/wasm_vm.rs b/zellij-server/src/wasm_vm.rs
index f3e4a115b..41a468ee2 100644
--- a/zellij-server/src/wasm_vm.rs
+++ b/zellij-server/src/wasm_vm.rs
@@ -28,8 +28,8 @@ use zellij_utils::{input::command::TerminalAction, serde, zellij_tile};
#[derive(Clone, Debug)]
pub(crate) enum PluginInstruction {
- Load(Sender<u32>, PathBuf),
- Update(Option<u32>, Event), // Focused plugin / broadcast, event data
+ Load(Sender<u32>, PathBuf, usize), // tx_pid, path_of_plugin , tab_index
+ Update(Option<u32>, Event), // Focused plugin / broadcast, event data
Render(Sender<String>, u32, usize, usize), // String buffer, plugin id, rows, cols
Unload(u32),
Exit,
@@ -50,6 +50,7 @@ impl From<&PluginInstruction> for PluginContext {
#[derive(WasmerEnv, Clone)]
pub(crate) struct PluginEnv {
pub plugin_id: u32,
+ pub tab_index: usize,
pub senders: ThreadSenders,
pub wasi_env: WasiEnv,
pub subscriptions: Arc<Mutex<HashSet<EventType>>>,
@@ -64,7 +65,7 @@ pub(crate) fn wasm_thread_main(bus: Bus<PluginInstruction>, store: Store, data_d
let (event, mut err_ctx) = bus.recv().expect("failed to receive event on channel");
err_ctx.add_call(ContextType::Plugin((&event).into()));
match event {
- PluginInstruction::Load(pid_tx, path) => {
+ PluginInstruction::Load(pid_tx, path, tab_index) => {
let plugin_dir = data_dir.join("plugins/");
let wasm_bytes = fs::read(&path)
.or_else(|_| fs::read(&path.with_extension("wasm")))
@@ -100,6 +101,7 @@ pub(crate) fn wasm_thread_main(bus: Bus<PluginInstruction>, store: Store, data_d
let plugin_env = PluginEnv {
plugin_id,
+ tab_index,
senders: bus.senders.clone(),
wasi_env,
subscriptions: Arc::new(Mutex::new(HashSet::new())),
@@ -193,6 +195,7 @@ fn host_set_selectable(plugin_env: &PluginEnv, selectable: i32) {
.send_to_screen(ScreenInstruction::SetSelectable(
PaneId::Plugin(plugin_env.plugin_id),
selectable,
+ plugin_env.tab_index,
))
.unwrap()
}
@@ -204,6 +207,7 @@ fn host_set_fixed_height(plugin_env: &PluginEnv, fixed_height: i32) {
.send_to_screen(ScreenInstruction::SetFixedHeight(
PaneId::Plugin(plugin_env.plugin_id),
fixed_height,
+ plugin_env.tab_index,
))
.unwrap()
}
@@ -215,6 +219,7 @@ fn host_set_fixed_width(plugin_env: &PluginEnv, fixed_width: i32) {
.send_to_screen(ScreenInstruction::SetFixedWidth(
PaneId::Plugin(plugin_env.plugin_id),
fixed_width,
+ plugin_env.tab_index,
))
.unwrap()
}
@@ -226,6 +231,7 @@ fn host_set_invisible_borders(plugin_env: &PluginEnv, invisible_borders: i32) {
.send_to_screen(ScreenInstruction::SetInvisibleBorders(
PaneId::Plugin(plugin_env.plugin_id),
invisible_borders,
+ plugin_env.tab_index,
))
.unwrap()
}
diff --git a/zellij-utils/assets/config/default.yaml b/zellij-utils/assets/config/default.yaml
index e90b60a18..13c8efcae 100644
--- a/zellij-utils/assets/config/default.yaml
+++ b/zellij-utils/assets/config/default.yaml
@@ -178,6 +178,8 @@ keybinds:
key: [Ctrl: 'p',]
- action: [SwitchToMode: Session,]
key: [Ctrl: 'o',]
+ - action: [ScrollToBottom, SwitchToMode: Normal,]
+ key: [Ctrl: 'c',]
- action: [Quit,]
key: [Ctrl: 'q',]
- action: [ScrollDown,]
diff --git a/zellij-utils/src/errors.rs b/zellij-utils/src/errors.rs
index b32dd337d..6a053038a 100644
--- a/zellij-utils/src/errors.rs
+++ b/zellij-utils/src/errors.rs
@@ -202,6 +202,7 @@ pub enum ScreenContext {
ScrollUpAt,
ScrollDown,
ScrollDownAt,
+ ScrollToBottom,
PageScrollUp,
PageScrollDown,
ClearScroll,
diff --git a/zellij-utils/src/input/actions.rs b/zellij-utils/src/input/actions.rs
index ab711c75c..dbced56df 100644
--- a/zellij-utils/src/input/actions.rs
+++ b/zellij-utils/src/input/actions.rs
@@ -49,6 +49,8 @@ pub enum Action {
ScrollDown,
/// Scroll down at point
ScrollDownAt(Position),
+ /// Scroll down to bottom in focus pane.
+ ScrollToBottom,
/// Scroll up one page in focus pane.
PageScrollUp,
/// Scroll down one page in focus pane.
diff --git a/zellij-utils/src/input/layout.rs b/zellij-utils/src/input/layout.rs
index 26d967646..887350fb0 100644
--- a/zellij-utils/src/input/layout.rs
+++ b/zellij-utils/src/input/layout.rs
@@ -123,8 +123,8 @@ impl Layout {
layout: Option<&PathBuf>,
layout_path: Option<&PathBuf>,
layout_dir: Option<PathBuf>,
- ) -> Option<Layout> {
- let layout_result = layout
+ ) -> Option<Result<Layout, ConfigError>> {
+ layout
.map(|p| Layout::from_dir(p, layout_dir.as_ref()))
.or_else(|| layout_path.map(|p| Layout::new(p)))
.or_else(|| {
@@ -132,16 +132,7 @@ impl Layout {
&std::path::PathBuf::from("default"),
layout_dir.as_ref(),
))
- });
-
- match layout_result {
- None => None,
- Some(Ok(layout)) => Some(layout),
- Some(Err(e)) => {
- eprintln!("There was an error in the layout file:\n{}", e);
- std::process::exit(1);
- }
- }
+ })
}
// Currently still needed but on nightly
@@ -297,12 +288,9 @@ impl Layout {
pub fn construct_main_layout(&self) -> MainLayout {
let (pre_tab, post_tab, tabs) = self.split_main_and_tab_layout();
+ // Todo: A proper LayoutError
if tabs.is_empty() {
- panic!("The layout file should have a `tabs` section specified");
- }
-
- if tabs.len() > 1 {
- panic!("The layout file should have one single tab in the `tabs` section specified");
+ panic!("The layout file should have a [`tabs`] section specified");
}
MainLayout {
diff --git a/zellij-utils/src/input/unit/layout_test.rs b/zellij-utils/src/input/unit/layout_test.rs
index 89217e04e..5d9fda35a 100644
--- a/zellij-utils/src/input/unit/layout_test.rs
+++ b/zellij-utils/src/input/unit/layout_test.rs
@@ -528,10 +528,7 @@ fn no_tabs_specified_should_panic() {
}
#[test]
-#[should_panic]
-// TODO Make error out of this
-// Only untill #631 is fixed
-fn multiple_tabs_specified_should_panic() {
+fn multiple_tabs_specified_should_not_panic() {
let path = layout_test_dir("multiple-tabs-should-panic.yaml".into());
let layout = Layout::new(&path);
let _main_layout = layout.unwrap().construct_main_layout();
diff --git a/zellij-utils/src/setup.rs b/zellij-utils/src/setup.rs
index aa0bb642b..e00eb7aea 100644
--- a/zellij-utils/src/setup.rs
+++ b/zellij-utils/src/setup.rs
@@ -1,11 +1,18 @@
-use crate::cli::CliArgs;
-use crate::consts::{
- FEATURES, SYSTEM_DEFAULT_CONFIG_DIR, SYSTEM_DEFAULT_DATA_DIR_PREFIX, VERSION, ZELLIJ_PROJ_DIR,
+use crate::{
+ cli::{CliArgs, Command},
+ consts::{
+ FEATURES, SYSTEM_DEFAULT_CONFIG_DIR, SYSTEM_DEFAULT_DATA_DIR_PREFIX, VERSION,
+ ZELLIJ_PROJ_DIR,
+ },
+ input::{
+ config::{Config, ConfigError},
+ layout::{Layout, MainLayout},
+ options::Options,
+ },
};
-use crate::input::options::Options;
use directories_next::BaseDirs;
use serde::{Deserialize, Serialize};
-use std::{io::Write, path::Path, path::PathBuf};
+use std::{convert::TryFrom, io::Write, path::Path, path::PathBuf, process};
use structopt::StructOpt;
const CONFIG_LOCATION: &str = ".config/zellij";
@@ -139,6 +146,68 @@ pub struct Setup {
impl Setup {
/// Entrypoint from main
+ /// Merges options from the config file and the command line options
+ /// into `[Options]`, the command line options superceding the config
+ /// file options:
+ /// 1. command line options (`zellij options`)
+ /// 2. config options (`config.yaml`)
+ pub fn from_options(
+ opts: &CliArgs,
+ ) -> Result<(Config, Option<MainLayout>, Options), ConfigError> {
+ let clean = match &opts.command {
+ Some(Command::Setup(ref setup)) => setup.clean,
+ _ => false,
+ };
+
+ log::info!("{:?}", clean);
+
+ let config = if !clean {
+ match Config::try_from(opts) {
+ Ok(config) => config,
+ Err(e) => {
+ eprintln!("There was an error in the config file:");
+ return Err(e);
+ }
+ }
+ } else {
+ Config::default()
+ };
+
+ let config_options = Options::from_cli(&config.options, opts.command.clone());
+
+ let layout_dir = config_options
+ .layout_dir
+ .clone()
+ .or_else(|| get_layout_dir(opts.config_dir.clone().or_else(find_default_config_dir)));
+ let layout_result = Layout::from_path_or_default(
+ opts.layout.as_ref(),
+ opts.layout_path.as_ref(),
+ layout_dir,
+ );
+ let layout = match layout_result {
+ None => None,
+ Some(Ok(layout)) => Some(layout),
+ Some(Err(e)) => {
+ eprintln!("There was an error in the layout file:");
+ return Err(e);
+ }
+ }
+ .map(|layout| layout.construct_main_layout());
+
+ if let Some(Command::Setup(ref setup)) = &opts.command {
+ setup.from_cli(opts, &config_options).map_or_else(
+ |e| {
+ eprintln!("{:?}", e);
+ process::exit(1);
+ },
+ |_| {},
+ );
+ };
+
+ Ok((config, layout, config_options))
+ }
+
+ /// General setup helpers
pub fn from_cli(&self, opts: &CliArgs, config_options: &Options) -> std::io::Result<()> {
if self.clean {
return Ok(());