feat(tui): Add input for entry rename and related handle events

This commit is contained in:
Patrick Auernig 2025-01-06 18:52:03 +01:00
parent a135e2417f
commit 4ea4644b90
2 changed files with 37 additions and 26 deletions

View File

@ -26,22 +26,24 @@ struct Projects {
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
struct Project(PathBuf);
struct Project {
path: PathBuf,
}
impl Project {
pub fn path(&self) -> &PathBuf {
&self.0
&self.path
}
pub fn name(&self) -> String {
let name = self.0.file_name().unwrap();
let name = self.path.file_name().unwrap();
name.to_string_lossy().to_string()
}
}
impl From<PathBuf> for Project {
fn from(value: PathBuf) -> Self {
Self(value)
fn from(path: PathBuf) -> Self {
Self { path }
}
}

View File

@ -23,6 +23,7 @@ enum Message {
SelectNext,
Confirm,
SearchUpdate,
RenameEntry,
}
@ -37,6 +38,7 @@ enum Mode {
struct State {
projects: Projects,
search: Input,
rename: Input,
mode: Mode,
should_exit: bool,
project_table: TableState,
@ -51,6 +53,7 @@ impl State {
Self {
projects,
search: Input::default(),
rename: Input::default(),
mode: Mode::default(),
should_exit: false,
project_table,
@ -117,6 +120,19 @@ fn handle_key_event(state: &mut State, tx: &mut mpsc::Sender<Message>, event: Ke
state.search.handle(InputRequest::DeletePrevChar);
Message::SearchUpdate
}
(Mode::Search, KeyModifiers::CONTROL, KeyCode::Char('r')) => {
state.mode = Mode::Rename;
Message::Noop
}
(Mode::Rename, KeyModifiers::NONE, KeyCode::Esc) => {
state.mode = Mode::Search;
Message::Noop
}
(Mode::Rename, KeyModifiers::NONE, KeyCode::Char(c)) => {
state.rename.handle(InputRequest::InsertChar(c));
Message::Noop
}
(Mode::Rename, KeyModifiers::NONE, KeyCode::Enter) => Message::RenameEntry,
(_, _, KeyCode::Enter) => Message::Confirm,
_ => Message::Noop,
@ -160,6 +176,7 @@ fn handle_messages(state: &mut State, rx: &mut mpsc::Receiver<Message>) -> Resul
Message::SearchUpdate => {
state.project_table.select_first();
}
Message::RenameEntry => {}
_ => (),
}
@ -171,37 +188,29 @@ fn draw(state: &mut State, frame: &mut Frame) {
let block = Block::default().borders(Borders::ALL);
frame.render_widget(&block, frame.area());
match state.mode {
Mode::Search => {
let layout = Layout::vertical([Constraint::Fill(1), Constraint::Max(2)]);
let inner_area = block.inner(frame.area());
let layout_rects = layout.split(inner_area);
draw_list(state, frame, layout_rects[0]);
draw_search(state, frame, layout_rects[1]);
}
Mode::Rename => {
let layout = Layout::vertical([Constraint::Fill(1)]);
let inner_area = block.inner(frame.area());
let layout_rects = layout.split(inner_area);
draw_list(state, frame, layout_rects[0]);
}
}
let layout = Layout::vertical([Constraint::Fill(1), Constraint::Max(2)]);
let inner_area = block.inner(frame.area());
let layout_rects = layout.split(inner_area);
draw_list(state, frame, layout_rects[0]);
draw_status(state, frame, layout_rects[1]);
}
fn draw_search(state: &mut State, frame: &mut Frame, area: Rect) {
const PROMPT_PREFIX: &str = "Search: ";
fn draw_status(state: &mut State, frame: &mut Frame, area: Rect) {
let (prefix, input) = match &state.mode {
Mode::Search => ("Search: ", &state.search),
Mode::Rename => ("Rename: ", &state.rename),
};
let search_input = &state.search;
let scroll_offset = (0, input.visual_scroll(area.width as usize) as u16);
let scroll_offset = (0, search_input.visual_scroll(area.width as usize) as u16);
let prompt = format!("{prefix}{}", input.value());
let prompt = format!("{PROMPT_PREFIX}{}", search_input.value());
let search = Paragraph::new(prompt).scroll(scroll_offset);
frame.render_widget(search, area);
let cursor_pos = (
area.x + (search_input.visual_cursor() + PROMPT_PREFIX.len()) as u16,
area.x + (input.visual_cursor() + prefix.len()) as u16,
area.y,
);
frame.set_cursor_position(cursor_pos)