mirror of
https://codeberg.org/unspeaker/perch.git
synced 2025-12-06 09:36:42 +01:00
wip: basic editing
This commit is contained in:
parent
b13ce4f0d0
commit
5336ee358a
4 changed files with 90 additions and 57 deletions
32
src/keys.rs
32
src/keys.rs
|
|
@ -2,6 +2,14 @@ use crate::*;
|
||||||
use opener::open;
|
use opener::open;
|
||||||
|
|
||||||
macro_rules! press {
|
macro_rules! press {
|
||||||
|
(Shift-$($key:tt)+) => {
|
||||||
|
Event::Key(KeyEvent {
|
||||||
|
code: KeyCode::$($key)+,
|
||||||
|
kind: KeyEventKind::Press,
|
||||||
|
modifiers: KeyModifiers::SHIFT,
|
||||||
|
state: KeyEventState::NONE
|
||||||
|
})
|
||||||
|
};
|
||||||
($($key:tt)+) => {
|
($($key:tt)+) => {
|
||||||
Event::Key(KeyEvent {
|
Event::Key(KeyEvent {
|
||||||
code: KeyCode::$($key)+,
|
code: KeyCode::$($key)+,
|
||||||
|
|
@ -9,7 +17,7 @@ macro_rules! press {
|
||||||
modifiers: KeyModifiers::NONE,
|
modifiers: KeyModifiers::NONE,
|
||||||
state: KeyEventState::NONE
|
state: KeyEventState::NONE
|
||||||
})
|
})
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Handle<TuiIn> for Taggart {
|
impl Handle<TuiIn> for Taggart {
|
||||||
|
|
@ -17,7 +25,17 @@ impl Handle<TuiIn> for Taggart {
|
||||||
let x_min = self.offset;
|
let x_min = self.offset;
|
||||||
let x_max = self.offset + self.size.h().saturating_sub(1);
|
let x_max = self.offset + self.size.h().saturating_sub(1);
|
||||||
let event = &*input.event();
|
let event = &*input.event();
|
||||||
match event {
|
match &self.editing {
|
||||||
|
Some(_value) => match event {
|
||||||
|
press!(Char(c)) => self.edit_insert(*c),
|
||||||
|
press!(Shift-Char(c)) => self.edit_insert(c.to_uppercase().next().unwrap()),
|
||||||
|
press!(Backspace) => self.edit_backspace(),
|
||||||
|
press!(Delete) => self.edit_delete(),
|
||||||
|
press!(Enter) => self.edit_cancel(),
|
||||||
|
press!(Esc) => self.edit_confirm(),
|
||||||
|
_ => {}
|
||||||
|
},
|
||||||
|
None => match event {
|
||||||
press!(Up) => { self.cursor = self.cursor.saturating_sub(1); },
|
press!(Up) => { self.cursor = self.cursor.saturating_sub(1); },
|
||||||
press!(Down) => { self.cursor = self.cursor + 1; },
|
press!(Down) => { self.cursor = self.cursor + 1; },
|
||||||
press!(PageUp) => { self.cursor = self.cursor.saturating_sub(PAGE_SIZE); },
|
press!(PageUp) => { self.cursor = self.cursor.saturating_sub(PAGE_SIZE); },
|
||||||
|
|
@ -25,16 +43,8 @@ impl Handle<TuiIn> for Taggart {
|
||||||
press!(Left) => { self.column = self.column.saturating_sub(1); },
|
press!(Left) => { self.column = self.column.saturating_sub(1); },
|
||||||
press!(Right) => { self.column = self.column + 1; },
|
press!(Right) => { self.column = self.column + 1; },
|
||||||
press!(Char(' ')) => { open(&self.paths[self.cursor].path)?; }
|
press!(Char(' ')) => { open(&self.paths[self.cursor].path)?; }
|
||||||
_ => match &self.editing {
|
press!(Enter) => self.edit_begin(),
|
||||||
Some(_value) => match event {
|
|
||||||
press!(Enter) => todo!(),
|
|
||||||
press!(Esc) => todo!(),
|
|
||||||
_ => {}
|
_ => {}
|
||||||
},
|
|
||||||
None => match event {
|
|
||||||
press!(Enter) => todo!(),
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if self.cursor < x_min {
|
if self.cursor < x_min {
|
||||||
|
|
|
||||||
34
src/main.rs
34
src/main.rs
|
|
@ -41,37 +41,3 @@ fn main () -> Usually<()> {
|
||||||
let state = Arc::new(RwLock::new(Taggart::new(&path)?));
|
let state = Arc::new(RwLock::new(Taggart::new(&path)?));
|
||||||
Tui::new()?.run(&state)
|
Tui::new()?.run(&state)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Taggart {
|
|
||||||
|
|
||||||
fn new (root: &impl AsRef<Path>) -> Usually<Self> {
|
|
||||||
Ok(Self {
|
|
||||||
_root: root.as_ref().into(),
|
|
||||||
paths: Self::collect(root)?,
|
|
||||||
cursor: 0,
|
|
||||||
offset: 0,
|
|
||||||
column: 0,
|
|
||||||
size: Measure::new(),
|
|
||||||
editing: None,
|
|
||||||
columns: Columns::default(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn collect (root: &impl AsRef<Path>) -> Usually<Vec<Entry>> {
|
|
||||||
let mut paths = vec![];
|
|
||||||
for entry in WalkDir::new(&root).into_iter()
|
|
||||||
.filter_entry(|e|!e.file_name().to_str().map(|s|s.starts_with(".")).unwrap_or(false))
|
|
||||||
{
|
|
||||||
let entry = entry?;
|
|
||||||
if entry.depth() == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if let Some(entry) = Entry::new(root, &entry)? {
|
|
||||||
paths.push(entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
paths.sort();
|
|
||||||
Ok(paths)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
||||||
55
src/model.rs
55
src/model.rs
|
|
@ -10,7 +10,60 @@ pub struct Taggart {
|
||||||
pub column: usize,
|
pub column: usize,
|
||||||
pub columns: Columns<Entry>,
|
pub columns: Columns<Entry>,
|
||||||
pub size: Measure<TuiOut>,
|
pub size: Measure<TuiOut>,
|
||||||
pub editing: Option<String>,
|
pub editing: Option<(usize, String)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Taggart {
|
||||||
|
pub fn new (root: &impl AsRef<Path>) -> Usually<Self> {
|
||||||
|
Ok(Self {
|
||||||
|
_root: root.as_ref().into(),
|
||||||
|
paths: Self::collect(root)?,
|
||||||
|
cursor: 0,
|
||||||
|
offset: 0,
|
||||||
|
column: 0,
|
||||||
|
size: Measure::new(),
|
||||||
|
editing: None,
|
||||||
|
columns: Columns::default(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
pub fn collect (root: &impl AsRef<Path>) -> Usually<Vec<Entry>> {
|
||||||
|
let mut paths = vec![];
|
||||||
|
for entry in WalkDir::new(&root).into_iter()
|
||||||
|
.filter_entry(|e|!e.file_name().to_str().map(|s|s.starts_with(".")).unwrap_or(false))
|
||||||
|
{
|
||||||
|
let entry = entry?;
|
||||||
|
if entry.depth() == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if let Some(entry) = Entry::new(root, &entry)? {
|
||||||
|
paths.push(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
paths.sort();
|
||||||
|
Ok(paths)
|
||||||
|
}
|
||||||
|
pub fn edit_begin (&mut self) {
|
||||||
|
let value = (self.columns.0[self.column].value)(&self.paths[self.cursor]);
|
||||||
|
let value = format!("{}", value.unwrap_or_default());
|
||||||
|
self.editing = Some((value.len(), value));
|
||||||
|
}
|
||||||
|
pub fn edit_cancel (&mut self) {
|
||||||
|
self.editing = None;
|
||||||
|
}
|
||||||
|
pub fn edit_confirm (&mut self) {
|
||||||
|
self.editing = None;
|
||||||
|
}
|
||||||
|
pub fn edit_insert (&mut self, c: char) {
|
||||||
|
if let Some((index, value)) = &mut self.editing {
|
||||||
|
self.editing = Some((*index, format!("{value}{c}")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn edit_backspace (&mut self) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
pub fn edit_delete (&mut self) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Ord, Eq, PartialEq, PartialOrd)]
|
#[derive(Ord, Eq, PartialEq, PartialOrd)]
|
||||||
|
|
|
||||||
10
src/view.rs
10
src/view.rs
|
|
@ -3,9 +3,9 @@ use tek_tui::ratatui::{style::{Color, Style}, prelude::Stylize};
|
||||||
use pad::PadStr;
|
use pad::PadStr;
|
||||||
|
|
||||||
pub struct Column<T> {
|
pub struct Column<T> {
|
||||||
title: Arc<str>,
|
pub title: Arc<str>,
|
||||||
width: usize,
|
pub width: usize,
|
||||||
value: Box<dyn Fn(&T)->Option<Arc<str>> + Send + Sync>,
|
pub value: Box<dyn Fn(&T)->Option<Arc<str>> + Send + Sync>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Column<T> {
|
impl<T> Column<T> {
|
||||||
|
|
@ -101,6 +101,10 @@ impl<'a> Content<TuiOut> for TreeTable<'a> {
|
||||||
to.fill_bg(fill, Color::Rgb(192, 128, 0));
|
to.fill_bg(fill, Color::Rgb(192, 128, 0));
|
||||||
let fill = [area.x() + x as u16, y, w, 1];
|
let fill = [area.x() + x as u16, y, w, 1];
|
||||||
to.fill_bg(fill, Color::Rgb(224, 192, 0));
|
to.fill_bg(fill, Color::Rgb(224, 192, 0));
|
||||||
|
if let Some((index, value)) = &self.0.editing {
|
||||||
|
let x = area.x() + if x > 0 { x + 1 } else { x } as u16;
|
||||||
|
to.blit(&value, x, y, None)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue