summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorqkzk <qu3nt1n@gmail.com>2022-10-09 15:07:28 +0200
committerqkzk <qu3nt1n@gmail.com>2022-10-09 15:07:28 +0200
commit7657cdfc065b5efbab75295192a367447507e7d2 (patch)
tree0c6ae04981eca270295cd4465f3a23d651dffda7 /src
parent394a37f8d00e0234d387f2c721149547c783f0fa (diff)
simple tabs, can switch. Can't communicate
Diffstat (limited to 'src')
-rw-r--r--src/actioner.rs211
-rw-r--r--src/completion.rs1
-rw-r--r--src/content_window.rs2
-rw-r--r--src/display.rs35
-rw-r--r--src/input.rs1
-rw-r--r--src/last_edition.rs2
-rw-r--r--src/lib.rs1
-rw-r--r--src/main.rs12
-rw-r--r--src/preview.rs5
-rw-r--r--src/status.rs1
-rw-r--r--src/tabs.rs47
-rw-r--r--src/visited.rs2
12 files changed, 191 insertions, 129 deletions
diff --git a/src/actioner.rs b/src/actioner.rs
index 5db9dd3..4edec7d 100644
--- a/src/actioner.rs
+++ b/src/actioner.rs
@@ -4,11 +4,11 @@ use tuikit::prelude::{Event, Key, MouseButton};
use crate::config::Keybindings;
use crate::event_char::EventChar;
use crate::mode::Mode;
-use crate::status::Status;
+use crate::tabs::Tabs;
-/// Struct which mutates `Status`.
+/// Struct which mutates `tabs.selected()..
/// Holds a mapping which can't be static since it's read from a config file.
-/// All keys are mapped to relevent events on status.
+/// All keys are mapped to relevent events on tabs.selected().
/// Keybindings are read from `Config`.
pub struct Actioner {
binds: HashMap<char, EventChar>,
@@ -16,7 +16,7 @@ pub struct Actioner {
impl Actioner {
/// Creates a map of configurable keybindings to `EventChar`
- /// The `EventChar` is then associated to a `Status` method.
+ /// The `EventChar` is then associated to a `tabs.selected(). method.
pub fn new(keybindings: &Keybindings) -> Self {
let binds = HashMap::from([
(keybindings.toggle_hidden, EventChar::ToggleHidden),
@@ -50,224 +50,227 @@ impl Actioner {
Self { binds }
}
/// Reaction to received events.
- pub fn read_event(&self, status: &mut Status, ev: Event) {
+ pub fn read_event(&self, tabs: &mut Tabs, ev: Event) {
match ev {
- Event::Key(Key::ESC) => self.escape(status),
- Event::Key(Key::Up) => self.up(status),
- Event::Key(Key::Down) => self.down(status),
- Event::Key(Key::Left) => self.left(status),
- Event::Key(Key::Right) => self.right(status),
- Event::Key(Key::Backspace) => self.backspace(status),
- Event::Key(Key::Ctrl('d')) => self.delete(status),
- Event::Key(Key::Ctrl('q')) => self.escape(status),
- Event::Key(Key::Delete) => self.delete(status),
- Event::Key(Key::Char(c)) => self.char(status, c),
- Event::Key(Key::Home) => self.home(status),
- Event::Key(Key::End) => self.end(status),
- Event::Key(Key::PageDown) => self.page_down(status),
- Event::Key(Key::PageUp) => self.page_up(status),
- Event::Key(Key::Enter) => self.enter(status),
- Event::Key(Key::Tab) => self.tab(status),
- Event::Key(Key::WheelUp(_, _, _)) => self.up(status),
- Event::Key(Key::WheelDown(_, _, _)) => self.down(status),
- Event::Key(Key::SingleClick(MouseButton::Left, row, _)) => self.left_click(status, row),
- Event::Key(Key::SingleClick(MouseButton::Right, row, _)) => {
- self.right_click(status, row)
- }
+ Event::Key(Key::ESC) => self.escape(tabs),
+ Event::Key(Key::Up) => self.up(tabs),
+ Event::Key(Key::Down) => self.down(tabs),
+ Event::Key(Key::Left) => self.left(tabs),
+ Event::Key(Key::Right) => self.right(tabs),
+ Event::Key(Key::Backspace) => self.backspace(tabs),
+ Event::Key(Key::Ctrl('d')) => self.delete(tabs),
+ Event::Key(Key::Ctrl('q')) => self.escape(tabs),
+ Event::Key(Key::Delete) => self.delete(tabs),
+ Event::Key(Key::Char(c)) => self.char(tabs, c),
+ Event::Key(Key::Home) => self.home(tabs),
+ Event::Key(Key::End) => self.end(tabs),
+ Event::Key(Key::PageDown) => self.page_down(tabs),
+ Event::Key(Key::PageUp) => self.page_up(tabs),
+ Event::Key(Key::Enter) => self.enter(tabs),
+ Event::Key(Key::Tab) => self.tab(tabs),
+ Event::Key(Key::WheelUp(_, _, _)) => self.up(tabs),
+ Event::Key(Key::WheelDown(_, _, _)) => self.down(tabs),
+ Event::Key(Key::SingleClick(MouseButton::Left, row, _)) => self.left_click(tabs, row),
+ Event::Key(Key::SingleClick(MouseButton::Right, row, _)) => self.right_click(tabs, row),
_ => {}
}
}
/// Leaving a mode reset the window
- fn escape(&self, status: &mut Status) {
- status.event_normal()
+ fn escape(&self, tabs: &mut Tabs) {
+ tabs.selected().event_normal()
}
/// Move one line up
- fn up(&self, status: &mut Status) {
- match status.mode {
- Mode::Normal | Mode::Preview => status.event_up_one_row(),
- Mode::Jump => status.event_jumplist_prev(),
- Mode::History => status.event_history_prev(),
- Mode::Shortcut => status.event_shortcut_prev(),
+ fn up(&self, tabs: &mut Tabs) {
+ match tabs.selected().mode {
+ Mode::Normal | Mode::Preview => tabs.selected().event_up_one_row(),
+ Mode::Jump => tabs.selected().event_jumplist_prev(),
+ Mode::History => tabs.selected().event_history_prev(),
+ Mode::Shortcut => tabs.selected().event_shortcut_prev(),
Mode::Goto | Mode::Exec | Mode::Search => {
- status.completion.prev();
+ tabs.selected().completion.prev();
}
_ => (),
}
}
/// Move one line down
- fn down(&self, status: &mut Status) {
- match status.mode {
- Mode::Normal | Mode::Preview => status.event_down_one_row(),
- Mode::Jump => status.event_jumplist_next(),
- Mode::History => status.event_history_next(),
- Mode::Shortcut => status.event_shortcut_next(),
+ fn down(&self, tabs: &mut Tabs) {
+ match tabs.selected().mode {
+ Mode::Normal | Mode::Preview => tabs.selected().event_down_one_row(),
+ Mode::Jump => tabs.selected().event_jumplist_next(),
+ Mode::History => tabs.selected().event_history_next(),
+ Mode::Shortcut => tabs.selected().event_shortcut_next(),
Mode::Goto | Mode::Exec | Mode::Search => {
- status.completion.next();
+ tabs.selected().completion.next();
}
_ => (),
}
}
/// Move left in a string, move to parent in normal mode
- fn left(&self, status: &mut Status) {
- match status.mode {
- Mode::Normal => status.event_move_to_parent(),
+ fn left(&self, tabs: &mut Tabs) {
+ match tabs.selected().mode {
+ Mode::Normal => tabs.selected().event_move_to_parent(),
Mode::Rename
| Mode::Chmod
| Mode::Newdir
| Mode::Newfile
| Mode::Exec
| Mode::Search
- | Mode::Goto => status.event_move_cursor_left(),
+ | Mode::Goto => tabs.selected().event_move_cursor_left(),
_ => (),
}
}
/// Move right in a string, move to children in normal mode.
- fn right(&self, status: &mut Status) {
- match status.mode {
- Mode::Normal => status.event_go_to_child(),
+ fn right(&self, tabs: &mut Tabs) {
+ match tabs.selected().mode {
+ Mode::Normal => tabs.selected().event_go_to_child(),
Mode::Rename
| Mode::Chmod
| Mode::Newdir
| Mode::Newfile
| Mode::Exec
| Mode::Search
- | Mode::Goto => status.event_move_cursor_right(),
+ | Mode::Goto => tabs.selected().event_move_cursor_right(),
_ => (),
}
}
/// Deletes a char in input string
- fn backspace(&self, status: &mut Status) {
- match status.mode {
+ fn backspace(&self, tabs: &mut Tabs) {
+ match tabs.selected().mode {
Mode::Rename
| Mode::Newdir
| Mode::Chmod
| Mode::Newfile
| Mode::Exec
| Mode::Search
- | Mode::Goto => status.event_delete_char_left(),
+ | Mode::Goto => tabs.selected().event_delete_char_left(),
Mode::Normal => (),
_ => (),
}
}
/// Deletes chars right of cursor in input string.
- fn delete(&self, status: &mut Status) {
- match status.mode {
+ fn delete(&self, tabs: &mut Tabs) {
+ match tabs.selected().mode {
Mode::Rename
| Mode::Newdir
| Mode::Chmod
| Mode::Newfile
| Mode::Exec
| Mode::Search
- | Mode::Goto => status.event_delete_chars_right(),
+ | Mode::Goto => tabs.selected().event_delete_chars_right(),
Mode::Normal => (),
_ => (),
}
}
/// Move to top or beggining of line.
- fn home(&self, status: &mut Status) {
- match status.mode {
- Mode::Normal | Mode::Preview => status.event_go_top(),
- _ => status.event_cursor_home(),
+ fn home(&self, tabs: &mut Tabs) {
+ match tabs.selected().mode {
+ Mode::Normal | Mode::Preview => tabs.selected().event_go_top(),
+ _ => tabs.selected().event_cursor_home(),
}
}
/// Move to end or end of line.
- fn end(&self, status: &mut Status) {
- match status.mode {
- Mode::Normal | Mode::Preview => status.event_go_bottom(),
- _ => status.event_cursor_end(),
+ fn end(&self, tabs: &mut Tabs) {
+ match tabs.selected().mode {
+ Mode::Normal | Mode::Preview => tabs.selected().event_go_bottom(),
+ _ => tabs.selected().event_cursor_end(),
}
}
/// Move down 10 rows
- fn page_down(&self, status: &mut Status) {
- match status.mode {
- Mode::Normal | Mode::Preview => status.event_page_down(),
+ fn page_down(&self, tabs: &mut Tabs) {
+ match tabs.selected().mode {
+ Mode::Normal | Mode::Preview => tabs.selected().event_page_down(),
_ => (),
}
}
/// Move up 10 rows
- fn page_up(&self, status: &mut Status) {
- match status.mode {
- Mode::Normal | Mode::Preview => status.event_page_up(),
+ fn page_up(&self, tabs: &mut Tabs) {
+ match tabs.selected().mode {
+ Mode::Normal | Mode::Preview => tabs.selected().event_page_up(),
_ => (),
}
}
/// Execute a command
- fn enter(&self, status: &mut Status) {
- match status.mode {
- Mode::Rename => status.exec_rename(),
- Mode::Newfile => status.exec_newfile(),
- Mode::Newdir => status.exec_newdir(),
- Mode::Chmod => status.exec_chmod(),
- Mode::Exec => status.exec_exec(),
- Mode::Search => status.exec_search(),
- Mode::Goto => status.exec_goto(),
- Mode::RegexMatch => status.exec_regex(),
- Mode::Jump => status.exec_jump(),
- Mode::History => status.exec_history(),
- Mode::Shortcut => status.exec_shortcut(),
+ fn enter(&self, tabs: &mut Tabs) {
+ match tabs.selected().mode {
+ Mode::Rename => tabs.selected().exec_rename(),
+ Mode::Newfile => tabs.selected().exec_newfile(),
+ Mode::Newdir => tabs.selected().exec_newdir(),
+ Mode::Chmod => tabs.selected().exec_chmod(),
+ Mode::Exec => tabs.selected().exec_exec(),
+ Mode::Search => tabs.selected().exec_search(),
+ Mode::Goto => tabs.selected().exec_goto(),
+ Mode::RegexMatch => tabs.selected().exec_regex(),
+ Mode::Jump => tabs.selected().exec_jump(),
+ Mode::History => tabs.selected().exec_history(),
+ Mode::Shortcut => tabs.selected().exec_shortcut(),
Mode::Normal | Mode::NeedConfirmation | Mode::Help | Mode::Sort | Mode::Preview => (),
}
- status.input.reset();
- status.mode = Mode::Normal;
+ tabs.selected().input.reset();
+ tabs.selected().mode = Mode::Normal;
}
/// Select this file
- fn left_click(&self, status: &mut Status, row: u16) {
- if let Mode::Normal = status.mode {
- status.event_select_row(row)
+ fn left_click(&self, tabs: &mut Tabs, row: u16) {
+ if let Mode::Normal = tabs.selected().mode {
+ tabs.selected().event_select_row(row)
}
}
/// Open a directory or a file
- fn right_click(&self, status: &mut Status, row: u16) {
- if let Mode::Normal = status.mode {
- status.event_right_click(row)
+ fn right_click(&self, tabs: &mut Tabs, row: u16) {
+ if let Mode::Normal = tabs.selected().mode {
+ tabs.selected().event_right_click(row)
}
}
/// Select next completion and insert it
- fn tab(&self, status: &mut Status) {
- match status.mode {
- Mode::Goto | Mode::Exec | Mode::Search => status.event_replace_input_with_completion(),
+ fn tab(&self, tabs: &mut Tabs) {
+ match tabs.selected().mode {
+ Mode::Goto | Mode::Exec | Mode::Search => {
+ tabs.selected().event_replace_input_with_completion()
+ }
+ Mode::Normal => tabs.next(),
_ => (),
}
}
/// Match read key to a relevent event, depending on keybindings.
/// Keybindings are read from `Config`.
- fn char(&self, status: &mut Status, c: char) {
- match status.mode {
+ fn char(&self, tabs: &mut Tabs, c: char) {
+ match tabs.selected().mode {
Mode::Newfile | Mode::Newdir | Mode::Chmod | Mode::Rename | Mode::RegexMatch => {
- status.event_text_insertion(c)
+ tabs.selected().event_text_insertion(c)
+ }
+ Mode::Goto | Mode::Exec | Mode::Search => {
+ tabs.selected().event_text_insert_and_complete(c)
}
- Mode::Goto | Mode::Exec | Mode::Search => status.event_text_insert_and_complete(c),
Mode::Normal => match self.binds.get(&c) {
- Some(event_char) => event_char.match_char(status),
+ Some(event_char) => event_char.match_char(tabs.selected()),
None => (),
},
- Mode::Help | Mode::Preview | Mode::Shortcut => status.event_normal(),
+ Mode::Help | Mode::Preview | Mode::Shortcut => tabs.selected().event_normal(),
Mode::Jump => (),
Mode::History => (),
Mode::NeedConfirmation => {
if c == 'y' {
- status.exec_last_edition()
+ tabs.selected().exec_last_edition()
}
- status.event_leave_need_confirmation()
+ tabs.selected().event_leave_need_confirmation()
}
- Mode::Sort => status.event_leave_sort(c),
+ Mode::Sort => tabs.selected().event_leave_sort(c),
}
}
}
diff --git a/src/completion.rs b/src/completion.rs
index 2ca8c1b..1af4ac3 100644
--- a/src/completion.rs
+++ b/src/completion.rs
@@ -4,6 +4,7 @@ use crate::fileinfo::PathContent;
/// Holds a `Vec<String>` of possible completions and an `usize` index
/// showing where the user is in the vec.
+#[derive(Clone)]
pub struct Completion {
pub proposals: Vec<String>,
pub index: usize,
diff --git a/src/content_window.rs b/src/content_window.rs
index 3054040..484b51d 100644
--- a/src/content_window.rs
+++ b/src/content_window.rs
@@ -5,7 +5,7 @@ use std::cmp::{max, min};
/// and this struct is responsible for that.
/// Scrolling is done with `scroll_to`, `scroll_up_one`, `scroll_down_one`
/// methods.
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub struct ContentWindow {
/// The index of the first displayed file.
pub top: usize,
diff --git a/src/display.rs b/src/display.rs
index fa91c60..d0dfda2 100644
--- a/src/display.rs
+++ b/src/display.rs
@@ -10,6 +10,7 @@ use crate::help::HELP_LINES;
use crate::mode::Mode;
use crate::preview::Preview;
use crate::status::Status;
+use crate::tabs::Tabs;
/// Is responsible for displaying content in the terminal.
/// It uses an already created terminal.
@@ -49,16 +50,17 @@ impl Display {
/// The completion list if any.
///
/// The preview in preview mode.
- pub fn display_all(&mut self, status: &Status) {
- self.first_line(status);
- self.files(status);
- self.cursor(status);
- self.help(status);
- self.jump_list(status);
- self.history(status);
- self.completion(status);
- self.preview(status);
- self.shortcuts(status);
+ pub fn display_all(&mut self, tabs: &mut Tabs) {
+ let index = tabs.index;
+ self.first_line(tabs.selected(), index);
+ self.files(tabs.selected());
+ self.cursor(tabs.selected());
+ self.help(tabs.selected());
+ self.jump_list(tabs.selected());
+ self.history(tabs.selected());
+ self.completion(tabs.selected(), index);
+ self.preview(tabs.selected(), index);
+ self.shortcuts(tabs.selected());
}
/// Reads and returns the `tuikit::term::Term` height.
@@ -72,11 +74,12 @@ impl Display {
/// In normal mode we display the path and number of files.
/// When a confirmation is needed we ask the user to input `'y'` or
/// something else.
- fn first_line(&mut self, status: &Status) {
+ fn first_line(&mut self, status: &Status, index: usize) {
let first_row: String = match status.mode {
Mode::Normal => {
format!(
- "Path: {} -- {} files",
+ "Tab: {} - Path: {} -- {} files",
+ index,
status.path_content.path.to_str().unwrap(),
status.path_content.files.len(),
)
@@ -206,11 +209,11 @@ impl Display {
/// Display the possible completion items. The currently selected one is
/// reversed.
- fn completion(&mut self, status: &Status) {
+ fn completion(&mut self, status: &Status, index: usize) {
match status.mode {
Mode::Goto | Mode::Exec | Mode::Search => {
let _ = self.term.clear();
- self.first_line(status);
+ self.first_line(status, index);
let _ = self
.term
.set_cursor(0, status.input.cursor_index + Self::EDIT_BOX_OFFSET);
@@ -233,10 +236,10 @@ impl Display {
/// else the content is supposed to be text and shown as such.
/// It may fail to recognize some usual extensions, notably `.toml`.
/// It may fail to recognize small files (< 1024 bytes).
- fn preview(&mut self, status: &Status) {
+ fn preview(&mut self, status: &Status, index: usize) {
if let Mode::Preview = status.mode {
let _ = self.term.clear();
- self.first_line(status);
+ self.first_line(status, index);
let length = status.preview.len();
let line_number_width = length.to_string().len();
diff --git a/src/input.rs b/src/input.rs
index 17896bc..d99e7cb 100644
--- a/src/input.rs
+++ b/src/input.rs
@@ -1,5 +1,6 @@
/// Holds a string typed by the user and the cursor position.
/// Methods allow mutation of this string and movement of the cursor.
+#[derive(Clone)]
pub struct Input {
pub string: String,
pub cursor_index: usize,
diff --git a/src/last_edition.rs b/src/last_edition.rs
index 026bce0..bb77e3f 100644
--- a/src/last_edition.rs
+++ b/src/last_edition.rs
@@ -1,7 +1,7 @@
use std::fmt;
/// Different kind of last edition command received.
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub enum LastEdition {
/// No edition command
Nothing,
diff --git a/src/lib.rs b/src/lib.rs
index e9ea95d..d2a330b 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -13,4 +13,5 @@ pub mod mode;
pub mod preview;
pub mod shortcut;
pub mod status;
+pub mod tabs;
pub mod visited;
diff --git a/src/main.rs b/src/main.rs
index b48e4c0..2fc3258 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -6,7 +6,7 @@ use fm::args::Args;
use fm::config::load_config;
use fm::config::Colors;
use fm::display::Display;
-use fm::status::Status;
+use fm::tabs::Tabs;
static CONFIG_PATH: &str = "~/.config/fm/config.yaml";
@@ -29,21 +29,21 @@ fn main() {
let config = load_config(CONFIG_PATH);
let actioner = Actioner::new(&config.keybindings);
let mut display = init_display(config.colors.clone());
- let mut status = Status::new(Args::parse(), config, display.height());
+ let mut tabs = Tabs::new(Args::parse(), config, display.height());
while let Ok(event) = display.term.poll_event() {
let _ = display.term.clear();
let (_width, height) = display.term.term_size().unwrap();
- status.set_height(height);
+ tabs.selected().set_height(height);
- actioner.read_event(&mut status, event);
+ actioner.read_event(&mut tabs, event);
- display.display_all(&status);
+ display.display_all(&mut tabs);
let _ = display.term.present();
- if status.must_quit() {
+ if tabs.selected().must_quit() {
reset_cursor(&display);
break;
};
diff --git a/src/preview.rs b/src/preview.rs
index b76fb3d..169850c 100644
--- a/src/preview.rs
+++ b/src/preview.rs
@@ -11,6 +11,7 @@ use tuikit::term::Term;
use crate::fileinfo::PathContent;
+#[derive(Clone)]
pub enum Preview {
Syntaxed(SyntaxedContent),
Text(TextContent),
@@ -105,6 +106,7 @@ impl TextContent {
}
}
+#[derive(Clone)]
pub struct SyntaxedContent {
pub highlighted_content: Box<Vec<Vec<SyntaxedString>>>,
length: usize,
@@ -161,6 +163,7 @@ impl SyntaxedContent {
}
}
+#[derive(Clone)]
pub struct SyntaxedString {
// row: usize,
col: usize,
@@ -188,6 +191,7 @@ impl SyntaxedString {
}
}
+#[derive(Clone)]
pub struct BinaryContent {
pub path: PathBuf,
length: u64,
@@ -233,6 +237,7 @@ impl BinaryContent {
/// Holds a `Vec` of "bytes" (`u8`).
/// It's mostly used to implement a `print` method.
+#[derive(Clone)]
pub struct Line {
line: Vec<u8>,
}
diff --git a/src/status.rs b/src/status.rs
index 0ee00bd..08bcd6e 100644
--- a/src/status.rs
+++ b/src/status.rs
@@ -24,6 +24,7 @@ use crate::visited::History;
/// Is responsible to execute commands depending on received events, mutating
/// the status of the application.
/// Every change on the application comes here.
+#[derive(Clone)]
pub struct Status {
/// The mode the application is currenty in
pub mode: Mode,
diff --git a/src/tabs.rs b/src/tabs.rs
new file mode 100644
index 0000000..c8671e0
--- /dev/null
+++ b/src/tabs.rs
@@ -0,0 +1,47 @@
+use crate::{args::Args, config::Config, status::Status};
+
+pub struct Tabs {
+ pub statuses: Vec<Status>,
+ pub index: usize,
+}
+
+impl Tabs {
+ pub fn new(args: Args, config: Config, height: usize) -> Self {
+ let status = Status::new(args, config, height);
+
+ Self {
+ statuses: vec![status.clone(), status],
+ index: 0,
+ }
+ }
+
+ pub fn is_empty(&self) -> bool {
+ self.statuses.is_empty()
+ }
+
+ pub fn len(&self) -> usize {
+ self.statuses.len()
+ }
+
+ pub fn next(&mut self) {
+ if self.is_empty() {
+ self.index = 0;
+ } else {
+ self.index = (self.index + 1) % self.len()
+ }
+ }
+
+ pub fn prev(&mut self) {
+ if self.is_empty() {
+ self.index = 0
+ } else if self.index > 0 {
+ self.index -= 1;
+ } else {
+ self.index = self.len() - 1
+ }
+ }
+
+ pub fn selected(&mut self) -> &mut Status {
+ &mut self.statuses[self.index]
+ }
+}
diff --git a/src/visited.rs b/src/visited.rs
index 178bfe1..b488f0e 100644
--- a/src/visited.rs
+++ b/src/visited.rs
@@ -1,6 +1,6 @@
use std::path::PathBuf;
-#[derive(Default)]
+#[derive(Default, Clone)]
pub struct History {
pub visited: Vec<PathBuf>,
pub index: usize,