Initial Commit
This commit is contained in:
commit
2ecf8bd5db
6 changed files with 178 additions and 0 deletions
2
.cargo/config.toml
Normal file
2
.cargo/config.toml
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
[build]
|
||||||
|
target = "wasm32-wasi"
|
||||||
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
target/
|
||||||
|
Cargo.lock
|
||||||
13
Cargo.toml
Normal file
13
Cargo.toml
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
[package]
|
||||||
|
name = "module"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Brooks J Rady <b.j.rady@gmail.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
description = "A small client-side library for writing mosaic plugins (tiles)"
|
||||||
|
repository = "https://github.com/mosaic-org/strider"
|
||||||
|
license = "MIT"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
colored = "2"
|
||||||
|
mosaic-tile = "0.1"
|
||||||
|
pretty-bytes = "0.2"
|
||||||
21
LICENSE.md
Normal file
21
LICENSE.md
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2020 Mosaic contributors
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
85
src/main.rs
Normal file
85
src/main.rs
Normal file
|
|
@ -0,0 +1,85 @@
|
||||||
|
mod state;
|
||||||
|
|
||||||
|
use colored::*;
|
||||||
|
use mosaic_tile::register_tile;
|
||||||
|
use state::{FsEntry, State};
|
||||||
|
use std::{cmp::min, fs::read_dir};
|
||||||
|
|
||||||
|
register_tile!(State);
|
||||||
|
|
||||||
|
impl MosaicTile for State {
|
||||||
|
fn init(&mut self) {
|
||||||
|
refresh_directory(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw(&mut self, rows: usize, cols: usize) {
|
||||||
|
for i in 0..rows - 1 {
|
||||||
|
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 handle_key(&mut self, key: KeyEvent) {
|
||||||
|
match key.code {
|
||||||
|
KeyCode::Up => {
|
||||||
|
*self.selected_mut() = self.selected().saturating_sub(1);
|
||||||
|
}
|
||||||
|
KeyCode::Down => {
|
||||||
|
let next = self.selected().saturating_add(1);
|
||||||
|
*self.selected_mut() = min(self.files.len() - 1, next);
|
||||||
|
}
|
||||||
|
KeyCode::Right | KeyCode::Enter => match self.files[self.selected()].clone() {
|
||||||
|
FsEntry::Dir(p, _) => {
|
||||||
|
self.path = p;
|
||||||
|
refresh_directory(self);
|
||||||
|
}
|
||||||
|
FsEntry::File(p, _) => open_file(&p),
|
||||||
|
},
|
||||||
|
KeyCode::Left => {
|
||||||
|
self.path.pop();
|
||||||
|
refresh_directory(self);
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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()
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
state.files.sort_unstable();
|
||||||
|
}
|
||||||
55
src/state.rs
Normal file
55
src/state.rs
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
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)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue