diff --git a/core/src/state/notebook.rs b/core/src/state/notebook.rs index e29e21b..25f545e 100644 --- a/core/src/state/notebook.rs +++ b/core/src/state/notebook.rs @@ -1,15 +1,16 @@ mod consume; mod directory_item; +mod inner_state; use { crate::{ data::{Directory, Note}, - event::KeyEvent, - state::{EntryState, GetInner}, + state::GetInner, types::DirectoryId, - Error, Event, Glues, NotebookEvent, NotebookTransition, Result, + Error, Event, Glues, NotebookTransition, Result, }, consume::{directory, note, traverse}, + inner_state::InnerState::{self, *}, }; pub use directory_item::{DirectoryItem, DirectoryItemChildren, TreeItem}; @@ -28,19 +29,6 @@ pub enum SelectedItem { None, } -#[derive(Clone)] -pub enum InnerState { - NoteSelected, - NoteMoreActions, - DirectorySelected, - DirectoryMoreActions, - NoteTreeNumber(usize), - EditingViewMode, - EditingEditMode, - EntryDialog(Box), -} -use InnerState::*; - impl NotebookState { pub async fn new(glues: &mut Glues) -> Result { let db = glues @@ -111,7 +99,6 @@ impl NotebookState { format!("Note '{name}' edit mode") } - EntryDialog(_) => "Global menu dialog".to_owned(), }) } @@ -162,7 +149,7 @@ impl NotebookState { "[Ctrl+h] Show editor keymap".to_owned(), ] } - DirectoryMoreActions | NoteMoreActions | EntryDialog(_) => { + DirectoryMoreActions | NoteMoreActions => { vec![ "[j] Next".to_owned(), "[k] Previous".to_owned(), @@ -195,185 +182,11 @@ impl NotebookState { } pub async fn consume(glues: &mut Glues, event: Event) -> Result { - use Event::*; - use NotebookEvent::*; - let db = glues .db .as_mut() .ok_or(Error::Wip("[consume] empty db".to_owned()))?; let state: &mut NotebookState = glues.state.get_inner_mut()?; - match (event, &state.inner_state) { - (Notebook(CloseEntryDialog), EntryDialog(inner_state)) => { - state.inner_state = *inner_state.clone(); - - Ok(NotebookTransition::None) - } - (event, EntryDialog(_)) => EntryState::consume(glues, event) - .await - .map(NotebookTransition::Entry), - (Key(KeyEvent::Esc), DirectorySelected | NoteSelected | EditingViewMode) => { - state.inner_state = EntryDialog(Box::new(state.inner_state.clone())); - - Ok(NotebookTransition::ShowEntryDialog) - } - (Notebook(OpenDirectory(directory_id)), DirectorySelected | NoteSelected) => { - directory::open(db, state, directory_id).await - } - (Key(KeyEvent::L) | Key(KeyEvent::Right), DirectorySelected) => { - let directory = state.get_selected_directory()?.clone(); - let directory_item = state.root.find(&directory.id).ok_or(Error::Wip( - "[Key::L] failed to find the target directory".to_owned(), - ))?; - - if directory_item.children.is_none() { - directory::open(db, state, directory.id.clone()).await - } else { - directory::close(state, directory) - } - } - (Notebook(CloseDirectory(directory_id)), DirectorySelected | NoteSelected) => { - let directory = state - .root - .find(&directory_id) - .ok_or(Error::Wip( - "[CloseDirectory] failed to find target directory".to_owned(), - ))? - .directory - .clone(); - - directory::close(state, directory) - } - (Key(KeyEvent::H) | Key(KeyEvent::Left), DirectorySelected) => { - let directory = state.get_selected_directory()?; - if state.root.directory.id == directory.id { - return Ok(NotebookTransition::None); - } - - let parent_item = state.root.find(&directory.parent_id).ok_or(Error::Wip( - "[Key::H] failed to find parent directory".to_owned(), - ))?; - let parent = parent_item.directory.clone(); - - directory::close(state, parent) - } - (Key(KeyEvent::H) | Key(KeyEvent::Left), NoteSelected) => { - let directory_id = &state.get_selected_note()?.directory_id; - let directory_item = state.root.find(directory_id).ok_or(Error::Wip( - "[Key::H] failed to find parent directory".to_owned(), - ))?; - let directory = directory_item.directory.clone(); - - directory::close(state, directory) - } - (Key(KeyEvent::J), DirectorySelected | NoteSelected) => traverse::select_next(state), - (Key(KeyEvent::K), DirectorySelected | NoteSelected) => traverse::select_prev(state), - (Key(KeyEvent::M), NoteSelected) => { - let note = state.get_selected_note()?.clone(); - - note::show_actions_dialog(state, note) - } - (Key(KeyEvent::M), DirectorySelected) => { - let directory = state.get_selected_directory()?.clone(); - - directory::show_actions_dialog(state, directory) - } - (Notebook(CloseNoteActionsDialog), NoteMoreActions) => { - let note = state.get_selected_note()?.clone(); - - note::select(state, note) - } - (Notebook(CloseDirectoryActionsDialog), DirectoryMoreActions) => { - let directory = state.get_selected_directory()?.clone(); - - directory::select(state, directory) - } - ( - Notebook(SelectNote(note)), - DirectorySelected | NoteSelected | NoteTreeNumber(_) | EditingViewMode, - ) => note::select(state, note), - ( - Notebook(SelectDirectory(directory)), - DirectorySelected | NoteSelected | NoteTreeNumber(_) | EditingViewMode, - ) => directory::select(state, directory), - (Notebook(RenameNote(new_name)), NoteMoreActions) => { - let note = state.get_selected_note()?.clone(); - - note::rename(db, state, note, new_name).await - } - (Notebook(RemoveNote), NoteMoreActions) => { - let note = state.get_selected_note()?.clone(); - - note::remove(db, state, note).await - } - (Notebook(RenameDirectory(new_name)), DirectoryMoreActions) => { - let directory = state.get_selected_directory()?.clone(); - - directory::rename(db, state, directory, new_name).await - } - (Notebook(RemoveDirectory), DirectoryMoreActions) => { - let directory = state.get_selected_directory()?.clone(); - - directory::remove(db, state, directory).await - } - (Notebook(AddNote(note_name)), DirectoryMoreActions) => { - let directory = state.get_selected_directory()?.clone(); - - note::add(db, state, directory, note_name).await - } - (Notebook(AddDirectory(directory_name)), DirectoryMoreActions) => { - let directory = state.get_selected_directory()?.clone(); - - directory::add(db, state, directory, directory_name).await - } - (Key(KeyEvent::O) | Notebook(OpenNote), NoteSelected) => { - let note = state.get_selected_note()?.clone(); - - note::open(db, state, note).await - } - (Notebook(UpdateNoteContent(content)), EditingViewMode) => { - note::update_content(db, state, content).await - } - (Key(KeyEvent::E) | Notebook(EditNote), EditingViewMode) => note::edit(state).await, - (Key(KeyEvent::B) | Notebook(BrowseNoteTree), EditingViewMode) => note::browse(state).await, - (Key(KeyEvent::Esc) | Notebook(ViewNote), EditingEditMode) => note::view(state).await, - (Cancel, NoteMoreActions) => { - let note = state.get_selected_note()?.clone(); - - note::select(state, note.clone()) - } - (Cancel, DirectoryMoreActions) => { - let directory = state.get_selected_directory()?.clone(); - - directory::select(state, directory) - } - (Key(KeyEvent::Num(n)), NoteSelected | DirectorySelected) => { - state.inner_state = NoteTreeNumber(n.into()); - - Ok(NotebookTransition::None) - } - (Key(KeyEvent::Num(n2)), NoteTreeNumber(n)) => { - state.inner_state = NoteTreeNumber(n2 + n * 10); - - Ok(NotebookTransition::None) - } - (Key(KeyEvent::Esc), NoteTreeNumber(_)) => { - match state.selected { - SelectedItem::Note { .. } => { - state.inner_state = NoteSelected; - } - SelectedItem::Directory { .. } => { - state.inner_state = DirectorySelected; - } - SelectedItem::None => {} - }; - - Ok(NotebookTransition::None) - } - (Key(KeyEvent::J), NoteTreeNumber(n)) => Ok(NotebookTransition::SelectNext(*n)), - (Key(KeyEvent::K), NoteTreeNumber(n)) => Ok(NotebookTransition::SelectPrev(*n)), - (event @ Key(_), _) => Ok(NotebookTransition::Inedible(event)), - _ => Err(Error::Wip("todo: Notebook::consume".to_owned())), - } + inner_state::consume(db, state, event).await } diff --git a/core/src/state/notebook/inner_state.rs b/core/src/state/notebook/inner_state.rs new file mode 100644 index 0000000..6194456 --- /dev/null +++ b/core/src/state/notebook/inner_state.rs @@ -0,0 +1,38 @@ +mod directory_more_actions; +mod directory_selected; +mod editing_edit_mode; +mod editing_view_mode; +mod note_more_actions; +mod note_selected; +mod note_tree_number; + +use crate::{db::Db, state::notebook::NotebookState, Event, NotebookTransition, Result}; + +#[derive(Clone)] +pub enum InnerState { + NoteSelected, + NoteMoreActions, + DirectorySelected, + DirectoryMoreActions, + NoteTreeNumber(usize), + EditingViewMode, + EditingEditMode, +} + +pub async fn consume( + db: &mut Db, + state: &mut NotebookState, + event: Event, +) -> Result { + use InnerState::*; + + match &state.inner_state { + NoteSelected => note_selected::consume(db, state, event).await, + DirectorySelected => directory_selected::consume(db, state, event).await, + NoteMoreActions => note_more_actions::consume(db, state, event).await, + DirectoryMoreActions => directory_more_actions::consume(db, state, event).await, + NoteTreeNumber(n) => note_tree_number::consume(db, state, *n, event).await, + EditingViewMode => editing_view_mode::consume(db, state, event).await, + EditingEditMode => editing_edit_mode::consume(db, state, event).await, + } +} diff --git a/core/src/state/notebook/inner_state/directory_more_actions.rs b/core/src/state/notebook/inner_state/directory_more_actions.rs new file mode 100644 index 0000000..1d5c7e4 --- /dev/null +++ b/core/src/state/notebook/inner_state/directory_more_actions.rs @@ -0,0 +1,49 @@ +use crate::{ + db::Db, + state::notebook::{directory, note, NotebookState}, + Error, Event, NotebookEvent, NotebookTransition, Result, +}; + +pub async fn consume( + db: &mut Db, + state: &mut NotebookState, + event: Event, +) -> Result { + use Event::*; + use NotebookEvent::*; + + match event { + Notebook(CloseDirectoryActionsDialog) => { + let directory = state.get_selected_directory()?.clone(); + + directory::select(state, directory) + } + Notebook(RenameDirectory(new_name)) => { + let directory = state.get_selected_directory()?.clone(); + + directory::rename(db, state, directory, new_name).await + } + Notebook(RemoveDirectory) => { + let directory = state.get_selected_directory()?.clone(); + + directory::remove(db, state, directory).await + } + Notebook(AddNote(note_name)) => { + let directory = state.get_selected_directory()?.clone(); + + note::add(db, state, directory, note_name).await + } + Notebook(AddDirectory(directory_name)) => { + let directory = state.get_selected_directory()?.clone(); + + directory::add(db, state, directory, directory_name).await + } + Cancel => { + let directory = state.get_selected_directory()?.clone(); + + directory::select(state, directory) + } + event @ Key(_) => Ok(NotebookTransition::Inedible(event)), + _ => Err(Error::Wip("todo: Notebook::consume".to_owned())), + } +} diff --git a/core/src/state/notebook/inner_state/directory_selected.rs b/core/src/state/notebook/inner_state/directory_selected.rs new file mode 100644 index 0000000..baa3c3a --- /dev/null +++ b/core/src/state/notebook/inner_state/directory_selected.rs @@ -0,0 +1,71 @@ +use crate::{ + db::Db, + state::notebook::{directory, note, traverse, InnerState, NotebookState}, + Error, Event, KeyEvent, NotebookEvent, NotebookTransition, Result, +}; + +pub async fn consume( + db: &mut Db, + state: &mut NotebookState, + event: Event, +) -> Result { + use Event::*; + use NotebookEvent::*; + + match event { + Notebook(OpenDirectory(directory_id)) => directory::open(db, state, directory_id).await, + Key(KeyEvent::L) | Key(KeyEvent::Right) => { + let directory = state.get_selected_directory()?.clone(); + let directory_item = state.root.find(&directory.id).ok_or(Error::Wip( + "[Key::L] failed to find the target directory".to_owned(), + ))?; + + if directory_item.children.is_none() { + directory::open(db, state, directory.id.clone()).await + } else { + directory::close(state, directory) + } + } + Notebook(CloseDirectory(directory_id)) => { + let directory = state + .root + .find(&directory_id) + .ok_or(Error::Wip( + "[CloseDirectory] failed to find target directory".to_owned(), + ))? + .directory + .clone(); + + directory::close(state, directory) + } + Key(KeyEvent::H) | Key(KeyEvent::Left) => { + let directory = state.get_selected_directory()?; + if state.root.directory.id == directory.id { + return Ok(NotebookTransition::None); + } + + let parent_item = state.root.find(&directory.parent_id).ok_or(Error::Wip( + "[Key::H] failed to find parent directory".to_owned(), + ))?; + let parent = parent_item.directory.clone(); + + directory::close(state, parent) + } + Key(KeyEvent::J) => traverse::select_next(state), + Key(KeyEvent::K) => traverse::select_prev(state), + Key(KeyEvent::M) => { + let directory = state.get_selected_directory()?.clone(); + + directory::show_actions_dialog(state, directory) + } + Notebook(SelectNote(note)) => note::select(state, note), + Notebook(SelectDirectory(directory)) => directory::select(state, directory), + Key(KeyEvent::Num(n)) => { + state.inner_state = InnerState::NoteTreeNumber(n.into()); + + Ok(NotebookTransition::None) + } + event @ Key(_) => Ok(NotebookTransition::Inedible(event)), + _ => Err(Error::Wip("todo: Notebook::consume".to_owned())), + } +} diff --git a/core/src/state/notebook/inner_state/editing_edit_mode.rs b/core/src/state/notebook/inner_state/editing_edit_mode.rs new file mode 100644 index 0000000..57c7eb2 --- /dev/null +++ b/core/src/state/notebook/inner_state/editing_edit_mode.rs @@ -0,0 +1,20 @@ +use crate::{ + db::Db, + state::notebook::{note, NotebookState}, + Error, Event, KeyEvent, NotebookEvent, NotebookTransition, Result, +}; + +pub async fn consume( + _db: &mut Db, + state: &mut NotebookState, + event: Event, +) -> Result { + use Event::*; + use NotebookEvent::*; + + match event { + Key(KeyEvent::Esc) | Notebook(ViewNote) => note::view(state).await, + event @ Key(_) => Ok(NotebookTransition::Inedible(event)), + _ => Err(Error::Wip("todo: Notebook::consume".to_owned())), + } +} diff --git a/core/src/state/notebook/inner_state/editing_view_mode.rs b/core/src/state/notebook/inner_state/editing_view_mode.rs new file mode 100644 index 0000000..5aa8190 --- /dev/null +++ b/core/src/state/notebook/inner_state/editing_view_mode.rs @@ -0,0 +1,24 @@ +use crate::{ + db::Db, + state::notebook::{directory, note, NotebookState}, + Error, Event, KeyEvent, NotebookEvent, NotebookTransition, Result, +}; + +pub async fn consume( + db: &mut Db, + state: &mut NotebookState, + event: Event, +) -> Result { + use Event::*; + use NotebookEvent::*; + + match event { + Notebook(SelectNote(note)) => note::select(state, note), + Notebook(SelectDirectory(directory)) => directory::select(state, directory), + Notebook(UpdateNoteContent(content)) => note::update_content(db, state, content).await, + Key(KeyEvent::E) | Notebook(EditNote) => note::edit(state).await, + Key(KeyEvent::B) | Notebook(BrowseNoteTree) => note::browse(state).await, + event @ Key(_) => Ok(NotebookTransition::Inedible(event)), + _ => Err(Error::Wip("todo: Notebook::consume".to_owned())), + } +} diff --git a/core/src/state/notebook/inner_state/note_more_actions.rs b/core/src/state/notebook/inner_state/note_more_actions.rs new file mode 100644 index 0000000..3d0d194 --- /dev/null +++ b/core/src/state/notebook/inner_state/note_more_actions.rs @@ -0,0 +1,39 @@ +use crate::{ + db::Db, + state::notebook::{note, NotebookState}, + Error, Event, NotebookEvent, NotebookTransition, Result, +}; + +pub async fn consume( + db: &mut Db, + state: &mut NotebookState, + event: Event, +) -> Result { + use Event::*; + use NotebookEvent::*; + + match event { + Notebook(CloseNoteActionsDialog) => { + let note = state.get_selected_note()?.clone(); + + note::select(state, note) + } + Notebook(RenameNote(new_name)) => { + let note = state.get_selected_note()?.clone(); + + note::rename(db, state, note, new_name).await + } + Notebook(RemoveNote) => { + let note = state.get_selected_note()?.clone(); + + note::remove(db, state, note).await + } + Cancel => { + let note = state.get_selected_note()?.clone(); + + note::select(state, note.clone()) + } + event @ Key(_) => Ok(NotebookTransition::Inedible(event)), + _ => Err(Error::Wip("todo: Notebook::consume".to_owned())), + } +} diff --git a/core/src/state/notebook/inner_state/note_selected.rs b/core/src/state/notebook/inner_state/note_selected.rs new file mode 100644 index 0000000..838a5bf --- /dev/null +++ b/core/src/state/notebook/inner_state/note_selected.rs @@ -0,0 +1,60 @@ +use crate::{ + db::Db, + state::notebook::{directory, note, traverse, InnerState, NotebookState}, + Error, Event, KeyEvent, NotebookEvent, NotebookTransition, Result, +}; + +pub async fn consume( + db: &mut Db, + state: &mut NotebookState, + event: Event, +) -> Result { + use Event::*; + use NotebookEvent::*; + + match event { + Notebook(OpenDirectory(directory_id)) => directory::open(db, state, directory_id).await, + Notebook(CloseDirectory(directory_id)) => { + let directory = state + .root + .find(&directory_id) + .ok_or(Error::Wip( + "[CloseDirectory] failed to find target directory".to_owned(), + ))? + .directory + .clone(); + + directory::close(state, directory) + } + Key(KeyEvent::H) | Key(KeyEvent::Left) => { + let directory_id = &state.get_selected_note()?.directory_id; + let directory_item = state.root.find(directory_id).ok_or(Error::Wip( + "[Key::H] failed to find parent directory".to_owned(), + ))?; + let directory = directory_item.directory.clone(); + + directory::close(state, directory) + } + Key(KeyEvent::J) => traverse::select_next(state), + Key(KeyEvent::K) => traverse::select_prev(state), + Key(KeyEvent::M) => { + let note = state.get_selected_note()?.clone(); + + note::show_actions_dialog(state, note) + } + Notebook(SelectNote(note)) => note::select(state, note), + Notebook(SelectDirectory(directory)) => directory::select(state, directory), + Key(KeyEvent::O) | Notebook(OpenNote) => { + let note = state.get_selected_note()?.clone(); + + note::open(db, state, note).await + } + Key(KeyEvent::Num(n)) => { + state.inner_state = InnerState::NoteTreeNumber(n.into()); + + Ok(NotebookTransition::None) + } + event @ Key(_) => Ok(NotebookTransition::Inedible(event)), + _ => Err(Error::Wip("todo: Notebook::consume".to_owned())), + } +} diff --git a/core/src/state/notebook/inner_state/note_tree_number.rs b/core/src/state/notebook/inner_state/note_tree_number.rs new file mode 100644 index 0000000..9f3a207 --- /dev/null +++ b/core/src/state/notebook/inner_state/note_tree_number.rs @@ -0,0 +1,42 @@ +use crate::{ + db::Db, + state::notebook::{directory, note, InnerState, NotebookState, SelectedItem}, + Error, Event, KeyEvent, NotebookEvent, NotebookTransition, Result, +}; + +pub async fn consume( + _db: &mut Db, + state: &mut NotebookState, + n: usize, + event: Event, +) -> Result { + use Event::*; + use NotebookEvent::*; + + match event { + Notebook(SelectNote(note)) => note::select(state, note), + Notebook(SelectDirectory(directory)) => directory::select(state, directory), + Key(KeyEvent::Num(n2)) => { + state.inner_state = InnerState::NoteTreeNumber(n2 + n * 10); + + Ok(NotebookTransition::None) + } + Key(KeyEvent::Esc) => { + match state.selected { + SelectedItem::Note { .. } => { + state.inner_state = InnerState::NoteSelected; + } + SelectedItem::Directory { .. } => { + state.inner_state = InnerState::DirectorySelected; + } + SelectedItem::None => {} + }; + + Ok(NotebookTransition::None) + } + Key(KeyEvent::J) => Ok(NotebookTransition::SelectNext(n)), + Key(KeyEvent::K) => Ok(NotebookTransition::SelectPrev(n)), + event @ Key(_) => Ok(NotebookTransition::Inedible(event)), + _ => Err(Error::Wip("todo: Notebook::consume".to_owned())), + } +} diff --git a/core/src/transition.rs b/core/src/transition.rs index a50dc72..3942469 100644 --- a/core/src/transition.rs +++ b/core/src/transition.rs @@ -67,9 +67,6 @@ pub enum NotebookTransition { SelectDirectory(Directory), UpdateNoteContent, - ShowEntryDialog, - Entry(EntryTransition), - #[strum(to_string = "Inedible::{0}")] Inedible(Event), None,