wip: basic editing

This commit is contained in:
🪞👃🪞 2025-03-09 05:12:56 +02:00
parent b13ce4f0d0
commit 5336ee358a
4 changed files with 90 additions and 57 deletions

View file

@ -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,24 +25,26 @@ 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 {
press!(Up) => { self.cursor = self.cursor.saturating_sub(1); }, Some(_value) => match event {
press!(Down) => { self.cursor = self.cursor + 1; }, press!(Char(c)) => self.edit_insert(*c),
press!(PageUp) => { self.cursor = self.cursor.saturating_sub(PAGE_SIZE); }, press!(Shift-Char(c)) => self.edit_insert(c.to_uppercase().next().unwrap()),
press!(PageDown) => { self.cursor += PAGE_SIZE; }, press!(Backspace) => self.edit_backspace(),
press!(Left) => { self.column = self.column.saturating_sub(1); }, press!(Delete) => self.edit_delete(),
press!(Right) => { self.column = self.column + 1; }, press!(Enter) => self.edit_cancel(),
press!(Char(' ')) => { open(&self.paths[self.cursor].path)?; } press!(Esc) => self.edit_confirm(),
_ => match &self.editing { _ => {}
Some(_value) => match event { },
press!(Enter) => todo!(), None => match event {
press!(Esc) => todo!(), press!(Up) => { self.cursor = self.cursor.saturating_sub(1); },
_ => {} press!(Down) => { self.cursor = self.cursor + 1; },
}, press!(PageUp) => { self.cursor = self.cursor.saturating_sub(PAGE_SIZE); },
None => match event { press!(PageDown) => { self.cursor += PAGE_SIZE; },
press!(Enter) => todo!(), press!(Left) => { self.column = self.column.saturating_sub(1); },
_ => {} press!(Right) => { self.column = self.column + 1; },
} press!(Char(' ')) => { open(&self.paths[self.cursor].path)?; }
press!(Enter) => self.edit_begin(),
_ => {}
} }
} }
if self.cursor < x_min { if self.cursor < x_min {

View file

@ -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)
}
}

View file

@ -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)]

View file

@ -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)
}
} }
} }
} }