From 878c9b1f80d06e1e221b0e6b7a71c51edf5f3eac Mon Sep 17 00:00:00 2001 From: JEEVITHA KANNAN K S Date: Sat, 7 Sep 2024 22:38:57 +0530 Subject: [PATCH 1/3] Add multi selection --- src/running_command.rs | 34 ++++++++++++-------- src/state.rs | 72 +++++++++++++++++++++++++++++++++++------- 2 files changed, 80 insertions(+), 26 deletions(-) diff --git a/src/running_command.rs b/src/running_command.rs index f5041ee48..f8b2e236e 100644 --- a/src/running_command.rs +++ b/src/running_command.rs @@ -126,24 +126,30 @@ impl FloatContent for RunningCommand { } impl RunningCommand { - pub fn new(command: Command) -> Self { + pub fn new(commands: Vec) -> Self { let pty_system = NativePtySystem::default(); - // Build the command based on the provided Command enum variant - let mut cmd = CommandBuilder::new("sh"); - match command { - Command::Raw(prompt) => { - cmd.arg("-c"); - cmd.arg(prompt); - } - Command::LocalFile(file) => { - cmd.arg(&file); - if let Some(parent) = file.parent() { - cmd.cwd(parent); + // Create a command to execute all the selected commands + let mut cmd: CommandBuilder = CommandBuilder::new("sh"); + cmd.arg("-c"); + + // Initialize an empty string to hold the merged commands + // All the merged commands are passed as a single argument to reduce the overhead of rebuilding the command arguments for each and every command + let mut script = String::new(); + for command in commands { + match command { + Command::Raw(prompt) => script.push_str(&format!("{}\n", prompt)), // Merge raw commands + Command::LocalFile(file) => { + if let Some(parent) = file.parent() { + script.push_str(&format!("cd {}\n", parent.display())); + // Merge local file path + } + script.push_str(&format!("sh {}\n", file.display())); } + Command::None => panic!("Command::None was treated as a command"), } - Command::None => panic!("Command::None was treated as a command"), } + cmd.arg(script); // Open a pseudo-terminal with initial size let pair = pty_system @@ -164,7 +170,7 @@ impl RunningCommand { child.wait().unwrap() }); - let mut reader = pair.master.try_clone_reader().unwrap(); // This is a reader, this is where we + let mut reader = pair.master.try_clone_reader().unwrap(); // A buffer, shared between the thread that reads the command output, and the main tread. // The main thread only reads the contents diff --git a/src/state.rs b/src/state.rs index 432a5af25..dd8182ded 100644 --- a/src/state.rs +++ b/src/state.rs @@ -33,6 +33,8 @@ pub struct AppState { /// widget selection: ListState, filter: Filter, + multi_select: bool, // This keeps track of Multi select toggle + selected_commands: Vec, // This field is to store selected commands } pub enum Focus { @@ -60,6 +62,8 @@ impl AppState { visit_stack: vec![root_id], selection: ListState::default().with_selected(Some(0)), filter: Filter::new(), + multi_select: false, + selected_commands: Vec::new(), // Initialize with an empty vector }; state.update_items(); state @@ -120,12 +124,24 @@ impl AppState { |ListEntry { node, has_children, .. }| { + let is_selected = self.selected_commands.contains(&node.command); // Add * if command is selected + let indicator = if is_selected { "*" } else { "" }; if *has_children { - Line::from(format!("{} {}", self.theme.dir_icon(), node.name)) - .style(self.theme.dir_color()) + Line::from(format!( + "{} {} {}", + self.theme.dir_icon(), + node.name, + indicator + )) + .style(self.theme.dir_color()) } else { - Line::from(format!("{} {}", self.theme.cmd_icon(), node.name)) - .style(self.theme.cmd_color()) + Line::from(format!( + "{} {} {}", + self.theme.cmd_icon(), + node.name, + indicator + )) + .style(self.theme.cmd_color()) } }, )); @@ -137,11 +153,15 @@ impl AppState { } else { Style::new() }) - .block( - Block::default() - .borders(Borders::ALL) - .title(format!("Linux Toolbox - {}", env!("BUILD_DATE"))), - ) + .block(Block::default().borders(Borders::ALL).title(format!( + "Linux Toolbox - {} {}", + env!("BUILD_DATE"), + if self.multi_select { + "[Multi-Select]" + } else { + "" + } + ))) .scroll_padding(1); frame.render_stateful_widget(list, chunks[1], &mut self.selection); @@ -197,12 +217,34 @@ impl AppState { KeyCode::Tab => self.focus = Focus::TabList, KeyCode::Char('t') => self.theme.next(), KeyCode::Char('T') => self.theme.prev(), + KeyCode::Char('v') => self.toggle_multi_select(), + KeyCode::Char('V') => self.toggle_multi_select(), + KeyCode::Char(' ') if self.multi_select => self.toggle_selection(), // Add space key to toggle selection + _ => {} }, _ => {} }; true } + + fn toggle_multi_select(&mut self) { + self.multi_select = !self.multi_select; + if !self.multi_select { + self.selected_commands.clear(); + } + } + + fn toggle_selection(&mut self) { + if let Some(command) = self.get_selected_command(false) { + if self.selected_commands.contains(&command) { + self.selected_commands.retain(|c| c != &command); + } else { + self.selected_commands.push(command); + } + } + } + fn update_items(&mut self) { self.filter.update_items( &self.tabs, @@ -253,10 +295,16 @@ impl AppState { } } fn handle_enter(&mut self) { - if let Some(cmd) = self.get_selected_command(true) { - let command = RunningCommand::new(cmd); - self.spawn_float(command, 80, 80); + if self.selected_commands.is_empty() { + // If no commands are selected, run the currently highlighted command + if let Some(cmd) = self.get_selected_command(true) { + self.selected_commands.push(cmd); + } } + + let command = RunningCommand::new(self.selected_commands.clone()); + self.spawn_float(command, 80, 80); + self.selected_commands.clear(); } fn spawn_float(&mut self, float: T, width: u16, height: u16) { self.focus = Focus::FloatingWindow(Float::new(Box::new(float), width, height)); From c7ae60787514d8fc3fc9b9451e330d1a6f6a71cc Mon Sep 17 00:00:00 2001 From: JEEVITHA KANNAN K S Date: Tue, 10 Sep 2024 10:12:36 +0530 Subject: [PATCH 2/3] Add toml based multi-select implementation --- src/commands/utils/tab_data.toml | 1 + src/state.rs | 37 ++++++++++++++++++++++--------- src/tabs.rs | 38 ++++++++++++++++++++++++-------- 3 files changed, 57 insertions(+), 19 deletions(-) diff --git a/src/commands/utils/tab_data.toml b/src/commands/utils/tab_data.toml index 67ba893fd..72be5a4e9 100644 --- a/src/commands/utils/tab_data.toml +++ b/src/commands/utils/tab_data.toml @@ -1,4 +1,5 @@ name = "Utilities" +multi_selectable = false [[data]] name = "WiFi Manager" diff --git a/src/state.rs b/src/state.rs index dd8182ded..11e7685b4 100644 --- a/src/state.rs +++ b/src/state.rs @@ -217,9 +217,8 @@ impl AppState { KeyCode::Tab => self.focus = Focus::TabList, KeyCode::Char('t') => self.theme.next(), KeyCode::Char('T') => self.theme.prev(), - KeyCode::Char('v') => self.toggle_multi_select(), - KeyCode::Char('V') => self.toggle_multi_select(), - KeyCode::Char(' ') if self.multi_select => self.toggle_selection(), // Add space key to toggle selection + KeyCode::Char('v') | KeyCode::Char('V') => self.toggle_multi_select(), + KeyCode::Char(' ') if self.multi_select => self.toggle_selection(), _ => {} }, @@ -229,9 +228,11 @@ impl AppState { } fn toggle_multi_select(&mut self) { - self.multi_select = !self.multi_select; - if !self.multi_select { - self.selected_commands.clear(); + if self.is_current_tab_multi_selectable() { + self.multi_select = !self.multi_select; + if !self.multi_select { + self.selected_commands.clear(); + } } } @@ -245,12 +246,24 @@ impl AppState { } } + fn is_current_tab_multi_selectable(&self) -> bool { + let index = self.current_tab.selected().unwrap_or(0); + self.tabs + .get(index) + .map_or(false, |tab| tab.multi_selectable) + } + fn update_items(&mut self) { self.filter.update_items( &self.tabs, self.current_tab.selected().unwrap(), *self.visit_stack.last().unwrap(), ); + + if !self.is_current_tab_multi_selectable() { + self.multi_select = false; + self.selected_commands.clear(); + } } /// Checks ehther the current tree node is the root node (can we go up the tree or no) /// Returns `true` if we can't go up the tree (we are at the tree root) @@ -296,15 +309,19 @@ impl AppState { } fn handle_enter(&mut self) { if self.selected_commands.is_empty() { - // If no commands are selected, run the currently highlighted command + // If no commands are selected, run the currently highlighted command by pushing them into vector if let Some(cmd) = self.get_selected_command(true) { self.selected_commands.push(cmd); } } - let command = RunningCommand::new(self.selected_commands.clone()); - self.spawn_float(command, 80, 80); - self.selected_commands.clear(); + // Only spawn the floating window if there are selected commands + // This prevents the floating window when changing directories + if !self.selected_commands.is_empty() { + let command = RunningCommand::new(self.selected_commands.clone()); + self.spawn_float(command, 80, 80); + self.selected_commands.clear(); + } } fn spawn_float(&mut self, float: T, width: u16, height: u16) { self.focus = Focus::FloatingWindow(Float::new(Box::new(float), width, height)); diff --git a/src/tabs.rs b/src/tabs.rs index 979693262..970884a0e 100644 --- a/src/tabs.rs +++ b/src/tabs.rs @@ -12,6 +12,12 @@ struct TabList { struct TabEntry { name: String, data: Vec, + #[serde(default = "default_multi_selectable")] + multi_selectable: bool, +} + +fn default_multi_selectable() -> bool { + true } #[derive(Deserialize)] @@ -83,6 +89,7 @@ enum SystemDataType { pub struct Tab { pub name: String, pub tree: Tree, + pub multi_selectable: bool, } #[derive(Clone, Hash, Eq, PartialEq)] @@ -105,15 +112,28 @@ pub fn get_tabs(command_dir: &Path, validate: bool) -> Vec { }); let tabs: Vec = tabs - .map(|(TabEntry { name, data }, directory)| { - let mut tree = Tree::new(ListNode { - name: "root".to_string(), - command: Command::None, - }); - let mut root = tree.root_mut(); - create_directory(data, &mut root, &directory); - Tab { name, tree } - }) + .map( + |( + TabEntry { + name, + data, + multi_selectable, + }, + directory, + )| { + let mut tree = Tree::new(ListNode { + name: "root".to_string(), + command: Command::None, + }); + let mut root = tree.root_mut(); + create_directory(data, &mut root, &directory); + Tab { + name, + tree, + multi_selectable, + } + }, + ) .collect(); if tabs.is_empty() { From ae1fece1dfac0e3b00729e5590c7a0737b11c6ea Mon Sep 17 00:00:00 2001 From: JEEVITHA KANNAN K S Date: Wed, 11 Sep 2024 09:25:10 +0530 Subject: [PATCH 3/3] Add hints Single command execution bug fix --- Cargo.lock | 162 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/hint.rs | 165 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/state.rs | 9 +-- 3 files changed, 330 insertions(+), 6 deletions(-) create mode 100644 src/hint.rs diff --git a/Cargo.lock b/Cargo.lock index a87ca14f7..c8e2b954e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -20,6 +20,21 @@ version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "anstream" version = "0.6.14" @@ -99,6 +114,12 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + [[package]] name = "cassowary" version = "0.3.0" @@ -114,12 +135,35 @@ dependencies = [ "rustversion", ] +[[package]] +name = "cc" +version = "1.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b62ac837cdb5cb22e10a256099b4fc502b1dfe560cb282963a974d7abd80e476" +dependencies = [ + "shlex", +] + [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chrono" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-targets 0.52.5", +] + [[package]] name = "clap" version = "4.5.16" @@ -179,6 +223,12 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + [[package]] name = "crossterm" version = "0.27.0" @@ -280,6 +330,29 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "iana-time-zone" +version = "0.1.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + [[package]] name = "include_dir" version = "0.7.4" @@ -339,6 +412,15 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +[[package]] +name = "js-sys" +version = "0.3.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" +dependencies = [ + "wasm-bindgen", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -423,6 +505,15 @@ dependencies = [ "pin-utils", ] +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + [[package]] name = "once_cell" version = "1.19.0" @@ -703,6 +794,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signal-hook" version = "0.3.17" @@ -871,6 +968,7 @@ dependencies = [ name = "tui" version = "0.1.0" dependencies = [ + "chrono", "clap", "crossterm", "ego-tree", @@ -976,6 +1074,61 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasm-bindgen" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +dependencies = [ + "cfg-if", + "once_cell", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" + [[package]] name = "which" version = "6.0.3" @@ -1010,6 +1163,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.5", +] + [[package]] name = "windows-sys" version = "0.48.0" diff --git a/src/hint.rs b/src/hint.rs new file mode 100644 index 000000000..76e2e9eab --- /dev/null +++ b/src/hint.rs @@ -0,0 +1,165 @@ +use ratatui::{ + layout::{Margin, Rect}, + style::{Style, Stylize}, + text::{Line, Span}, + widgets::{Block, Borders, Paragraph}, + Frame, +}; + +use crate::state::{AppState, Focus}; + +pub const SHORTCUT_LINES: usize = 2; + +pub struct ShortcutList { + pub scope_name: &'static str, + pub hints: Vec, +} + +pub struct Shortcut { + pub key_sequenses: Vec>, + pub desc: &'static str, +} + +pub fn span_vec_len(span_vec: &[Span]) -> usize { + span_vec.iter().rfold(0, |init, s| init + s.width()) +} +impl ShortcutList { + pub fn draw(&self, frame: &mut Frame, area: Rect) { + let block = Block::default() + .title(self.scope_name) + .borders(Borders::all()); + let inner_area = area.inner(Margin::new(1, 1)); + let mut shortcut_list: Vec> = self.hints.iter().map(|h| h.to_spans()).collect(); + + let mut lines = vec![Line::default(); SHORTCUT_LINES]; + let mut idx = 0; + + while idx < SHORTCUT_LINES - 1 { + let split_idx = shortcut_list + .iter() + .scan(0usize, |total_len, s| { + *total_len += span_vec_len(s); + if *total_len > inner_area.width as usize { + None + } else { + *total_len += 4; + Some(1) + } + }) + .count(); + let new_shortcut_list = shortcut_list.split_off(split_idx); + let line: Vec<_> = shortcut_list + .into_iter() + .flat_map(|mut s| { + s.push(Span::default().content(" ")); + s + }) + .collect(); + shortcut_list = new_shortcut_list; + lines[idx] = line.into(); + idx += 1; + } + lines[idx] = shortcut_list + .into_iter() + .flat_map(|mut s| { + s.push(Span::default().content(" ")); + s + }) + .collect(); + + let p = Paragraph::new(lines).block(block); + frame.render_widget(p, area); + } +} + +impl Shortcut { + pub fn new(key_sequences: Vec<&'static str>, desc: &'static str) -> Self { + Self { + key_sequenses: key_sequences + .iter() + .map(|s| Span::styled(*s, Style::default().bold())) + .collect(), + desc, + } + } + + fn to_spans(&self) -> Vec { + let mut ret: Vec<_> = self + .key_sequenses + .iter() + .flat_map(|seq| { + [ + Span::default().content("["), + seq.clone(), + Span::default().content("] "), + ] + }) + .collect(); + ret.push(Span::styled(self.desc, Style::default().italic())); + ret + } +} + +fn get_list_item_shortcut(state: &AppState) -> Shortcut { + if state.selected_item_is_dir() { + Shortcut::new(vec!["l", "Right", "Enter"], "Go to selected dir") + } else { + Shortcut::new(vec!["l", "Right", "Enter"], "Run selected command") + } +} + +pub fn draw_shortcuts(state: &AppState, frame: &mut Frame, area: Rect) { + match state.focus { + Focus::Search => ShortcutList { + scope_name: "Search bar", + hints: vec![Shortcut::new(vec!["Enter"], "Finish search")], + }, + Focus::List => { + let mut hints = Vec::new(); + hints.push(Shortcut::new(vec!["q", "CTRL-c"], "Exit linutil")); + if state.at_root() { + hints.push(Shortcut::new(vec!["h", "Left", "Tab"], "Focus tab list")); + hints.push(get_list_item_shortcut(state)); + } else { + if state.selected_item_is_up_dir() { + hints.push(Shortcut::new( + vec!["l", "Right", "Enter", "h", "Left"], + "Go to parrent directory", + )); + } else { + hints.push(Shortcut::new(vec!["h", "Left"], "Go to parrent directory")); + hints.push(get_list_item_shortcut(state)); + if state.selected_item_is_cmd() { + hints.push(Shortcut::new(vec!["p"], "Enable preview")); + } + } + hints.push(Shortcut::new(vec!["Tab"], "Focus tab list")); + }; + hints.push(Shortcut::new(vec!["k", "Up"], "Select item above")); + hints.push(Shortcut::new(vec!["j", "Down"], "Select item below")); + hints.push(Shortcut::new(vec!["t"], "Next theme")); + hints.push(Shortcut::new(vec!["T"], "Previous theme")); + if state.is_current_tab_multi_selectable() { + hints.push(Shortcut::new(vec!["v"], "Toggle Multi selection")); + hints.push(Shortcut::new(vec!["Space"], "Multi select commands")); + } + ShortcutList { + scope_name: "Item list", + hints, + } + } + Focus::TabList => ShortcutList { + scope_name: "Tab list", + hints: vec![ + Shortcut::new(vec!["q", "CTRL-c"], "Exit linutil"), + Shortcut::new(vec!["l", "Right", "Tab", "Enter"], "Focus action list"), + Shortcut::new(vec!["k", "Up"], "Select item above"), + Shortcut::new(vec!["j", "Down"], "Select item below"), + Shortcut::new(vec!["t"], "Next theme"), + Shortcut::new(vec!["T"], "Previous theme"), + ], + }, + Focus::FloatingWindow(ref float) => float.get_shortcut_list(), + } + .draw(frame, area); +} diff --git a/src/state.rs b/src/state.rs index 11e7685b4..ab7256fe4 100644 --- a/src/state.rs +++ b/src/state.rs @@ -246,7 +246,7 @@ impl AppState { } } - fn is_current_tab_multi_selectable(&self) -> bool { + pub fn is_current_tab_multi_selectable(&self) -> bool { let index = self.current_tab.selected().unwrap_or(0); self.tabs .get(index) @@ -313,14 +313,11 @@ impl AppState { if let Some(cmd) = self.get_selected_command(true) { self.selected_commands.push(cmd); } - } - - // Only spawn the floating window if there are selected commands - // This prevents the floating window when changing directories - if !self.selected_commands.is_empty() { let command = RunningCommand::new(self.selected_commands.clone()); self.spawn_float(command, 80, 80); self.selected_commands.clear(); + } else { + self.go_to_selected_dir(); } } fn spawn_float(&mut self, float: T, width: u16, height: u16) {