summaryrefslogtreecommitdiffstats
path: root/default-plugins/strider
diff options
context:
space:
mode:
authorBrooks J Rady <b.j.rady@gmail.com>2021-04-19 23:37:47 +0100
committerBrooks J Rady <b.j.rady@gmail.com>2021-04-19 23:37:47 +0100
commitfee999ec40b469564e65c8c551f463805003ba6d (patch)
treee66c4f4bce0d22aa22de4408b4e0c9db5b71b0fa /default-plugins/strider
parent996c197fcf9fbc655e7cf7e741c62ad71970c322 (diff)
fix(naming): made plugin terminology more consistent
Diffstat (limited to 'default-plugins/strider')
-rw-r--r--default-plugins/strider/.cargo/config.toml2
-rw-r--r--default-plugins/strider/Cargo.toml12
l---------default-plugins/strider/LICENSE.md1
-rw-r--r--default-plugins/strider/src/main.rs97
-rw-r--r--default-plugins/strider/src/state.rs63
5 files changed, 175 insertions, 0 deletions
diff --git a/default-plugins/strider/.cargo/config.toml b/default-plugins/strider/.cargo/config.toml
new file mode 100644
index 000000000..bc255e30b
--- /dev/null
+++ b/default-plugins/strider/.cargo/config.toml
@@ -0,0 +1,2 @@
+[build]
+target = "wasm32-wasi" \ No newline at end of file
diff --git a/default-plugins/strider/Cargo.toml b/default-plugins/strider/Cargo.toml
new file mode 100644
index 000000000..d10598512
--- /dev/null
+++ b/default-plugins/strider/Cargo.toml
@@ -0,0 +1,12 @@
+[package]
+name = "strider"
+version = "0.2.0"
+authors = ["Brooks J Rady <b.j.rady@gmail.com>"]
+edition = "2018"
+description = "A simplified ranger clone written as a Zellij plugin"
+license = "MIT"
+
+[dependencies]
+colored = "2"
+zellij-tile = { path = "../../zellij-tile" }
+pretty-bytes = "0.2" \ No newline at end of file
diff --git a/default-plugins/strider/LICENSE.md b/default-plugins/strider/LICENSE.md
new file mode 120000
index 000000000..f0608a63a
--- /dev/null
+++ b/default-plugins/strider/LICENSE.md
@@ -0,0 +1 @@
+../../LICENSE.md \ No newline at end of file
diff --git a/default-plugins/strider/src/main.rs b/default-plugins/strider/src/main.rs
new file mode 100644
index 000000000..8edc1e197
--- /dev/null
+++ b/default-plugins/strider/src/main.rs
@@ -0,0 +1,97 @@
+mod state;
+
+use colored::*;
+use state::{FsEntry, State};
+use std::{cmp::min, fs::read_dir};
+use zellij_tile::prelude::*;
+
+register_plugin!(State);
+
+impl ZellijPlugin for State {
+ fn load(&mut self) {
+ refresh_directory(self);
+ subscribe(&[EventType::KeyPress]);
+ }
+
+ fn update(&mut self, event: Event) {
+ if let Event::KeyPress(key) = event {
+ match key {
+ Key::Up | Key::Char('k') => {
+ *self.selected_mut() = self.selected().saturating_sub(1);
+ }
+ Key::Down | Key::Char('j') => {
+ let next = self.selected().saturating_add(1);
+ *self.selected_mut() = min(self.files.len() - 1, next);
+ }
+ Key::Right | Key::Char('\n') | Key::Char('l') if !self.files.is_empty() => {
+ match self.files[self.selected()].clone() {
+ FsEntry::Dir(p, _) => {
+ self.path = p;
+ refresh_directory(self);
+ }
+ FsEntry::File(p, _) => open_file(&p),
+ }
+ }
+ Key::Left | Key::Char('h') => {
+ self.path.pop();
+ refresh_directory(self);
+ }
+
+ Key::Char('.') => {
+ self.toggle_hidden_files();
+ refresh_directory(self);
+ }
+
+ _ => (),
+ };
+ }
+ }
+
+ fn render(&mut self, rows: usize, cols: usize) {
+ for i in 0..rows {
+ if self.selected() < self.scroll() {
+ *self.scroll_mut() = self.selected();
+ }
+ if self.selected() - self.scroll() + 2 > rows {
+ *self.scroll_mut() = self.selected() + 2 - rows;
+ }
+ let i = self.scroll() + i;
+ if let Some(entry) = self.files.get(i) {
+ let mut path = entry.as_line(cols).normal();
+
+ if let FsEntry::Dir(..) = entry {
+ path = path.dimmed().bold();
+ }
+
+ if i == self.selected() {
+ println!("{}", path.reversed());
+ } else {
+ println!("{}", path);
+ }
+ } else {
+ println!();
+ }
+ }
+ }
+}
+
+fn refresh_directory(state: &mut State) {
+ state.files = read_dir(&state.path)
+ .unwrap()
+ .filter_map(|res| {
+ res.and_then(|d| {
+ if d.metadata()?.is_dir() {
+ let children = read_dir(d.path())?.count();
+ Ok(FsEntry::Dir(d.path(), children))
+ } else {
+ let size = d.metadata()?.len();
+ Ok(FsEntry::File(d.path(), size))
+ }
+ })
+ .ok()
+ .filter(|d| !d.is_hidden_file() || !state.hide_hidden_files)
+ })
+ .collect();
+
+ state.files.sort_unstable();
+}
diff --git a/default-plugins/strider/src/state.rs b/default-plugins/strider/src/state.rs
new file mode 100644
index 000000000..0d96ae0b9
--- /dev/null
+++ b/default-plugins/strider/src/state.rs
@@ -0,0 +1,63 @@
+use pretty_bytes::converter as pb;
+use std::{collections::HashMap, path::PathBuf};
+
+#[derive(Default)]
+pub struct State {
+ pub path: PathBuf,
+ pub files: Vec<FsEntry>,
+ pub cursor_hist: HashMap<PathBuf, (usize, usize)>,
+ pub hide_hidden_files: bool,
+}
+
+impl State {
+ pub fn selected_mut(&mut self) -> &mut usize {
+ &mut self.cursor_hist.entry(self.path.clone()).or_default().0
+ }
+ pub fn selected(&self) -> usize {
+ self.cursor_hist.get(&self.path).unwrap_or(&(0, 0)).0
+ }
+ pub fn scroll_mut(&mut self) -> &mut usize {
+ &mut self.cursor_hist.entry(self.path.clone()).or_default().1
+ }
+ pub fn scroll(&self) -> usize {
+ self.cursor_hist.get(&self.path).unwrap_or(&(0, 0)).1
+ }
+ pub fn toggle_hidden_files(&mut self) {
+ self.hide_hidden_files = !self.hide_hidden_files;
+ }
+}
+
+#[derive(PartialEq, Eq, PartialOrd, Ord, Clone)]
+pub enum FsEntry {
+ Dir(PathBuf, usize),
+ File(PathBuf, u64),
+}
+
+impl FsEntry {
+ pub fn name(&self) -> String {
+ let path = match self {
+ FsEntry::Dir(p, _) => p,
+ FsEntry::File(p, _) => p,
+ };
+ path.file_name().unwrap().to_string_lossy().into_owned()
+ }
+
+ pub fn as_line(&self, width: usize) -> String {
+ let info = match self {
+ FsEntry::Dir(_, s) => s.to_string(),
+ FsEntry::File(_, s) => pb::convert(*s as f64),
+ };
+ let space = width - info.len();
+ let name = self.name();
+ if space - 1 < name.len() {
+ [&name[..space - 2], &info].join("~ ")
+ } else {
+ let padding = " ".repeat(space - name.len());
+ [name, padding, info].concat()
+ }
+ }
+
+ pub fn is_hidden_file(&self) -> bool {
+ self.name().starts_with('.')
+ }
+}