basalt_tui/note_editor/
mod.rs1pub mod ast;
2mod cursor;
3pub mod editor;
4pub mod parser;
5mod render;
6mod rich_text;
7pub mod state;
8mod text_buffer;
9mod text_wrap;
10mod viewport;
11mod virtual_document;
12
13use ratatui::{
14 crossterm::event::{KeyCode, KeyEvent, KeyModifiers},
15 layout::Size,
16};
17
18use crate::{
19 app::{calc_scroll_amount, ActivePane, Message as AppMessage, ScrollAmount},
20 explorer,
21 note_editor::state::{EditMode, NoteEditorState, View},
22 outline,
23};
24
25#[derive(Clone, Debug, PartialEq)]
26pub enum Message {
27 Save,
28 SwitchPaneNext,
29 SwitchPanePrevious,
30 ToggleExplorer,
31 ToggleOutline,
32 ToggleView,
33 EditView,
34 ReadView,
35 Exit,
36 KeyEvent(KeyEvent),
37 CursorUp,
38 CursorLeft,
39 CursorRight,
40 CursorWordForward,
41 CursorWordBackward,
42 CursorDown,
43 ScrollUp(ScrollAmount),
44 ScrollDown(ScrollAmount),
45 JumpToBlock(usize),
46 Delete,
47}
48
49pub fn update<'a>(
51 message: &Message,
52 screen_size: Size,
53 state: &mut NoteEditorState,
54) -> Option<AppMessage<'a>> {
55 match message {
56 Message::CursorLeft => state.cursor_left(1),
57 Message::CursorRight => state.cursor_right(1),
58 Message::JumpToBlock(idx) => state.cursor_jump(*idx),
59 Message::CursorUp => {
60 state.cursor_up(1);
61 return Some(AppMessage::Outline(outline::Message::SelectAt(
62 state.current_block(),
63 )));
64 }
65 Message::CursorDown => {
66 state.cursor_down(1);
67 return Some(AppMessage::Outline(outline::Message::SelectAt(
68 state.current_block(),
69 )));
70 }
71 Message::ScrollUp(scroll_amount) => {
72 state.cursor_up(calc_scroll_amount(scroll_amount, screen_size.height.into()));
73 return Some(AppMessage::Outline(outline::Message::SelectAt(
74 state.current_block(),
75 )));
76 }
77 Message::ScrollDown(scroll_amount) => {
78 state.cursor_down(calc_scroll_amount(scroll_amount, screen_size.height.into()));
79 return Some(AppMessage::Outline(outline::Message::SelectAt(
80 state.current_block(),
81 )));
82 }
83 _ => {}
84 };
85
86 match state.view {
87 View::Edit(..) => match message {
88 Message::CursorWordForward => state.cursor_word_forward(),
89 Message::CursorWordBackward => state.cursor_word_backward(),
90 Message::ToggleView => state.set_view(View::Read),
91 Message::KeyEvent(key) => {
92 match key.code {
93 KeyCode::Char(c) => {
94 state.insert_char(c);
95 }
96 KeyCode::Enter => {
97 state.insert_char('\n');
98 }
99 _ => {}
100 }
101
102 return Some(AppMessage::UpdateSelectedNoteContent((
103 state.content.to_string(),
104 None,
105 )));
106 }
107 Message::Delete => {
108 state.delete_char();
109 }
110 Message::Exit => {
111 state.exit_insert();
112 state.set_view(View::Read);
113 return Some(AppMessage::UpdateSelectedNoteContent((
114 state.content.to_string(),
115 Some(state.ast_nodes.clone()),
116 )));
117 }
118 _ => {}
119 },
120 View::Read => match message {
121 Message::ToggleView => state.set_view(View::Edit(EditMode::Source)),
122 Message::EditView => state.set_view(View::Edit(EditMode::Source)),
123 Message::ReadView => state.set_view(View::Read),
124 Message::ToggleExplorer => {
125 return Some(AppMessage::Explorer(explorer::Message::Toggle));
126 }
127 Message::ToggleOutline => {
128 return Some(AppMessage::Outline(outline::Message::Toggle));
129 }
130 Message::SwitchPaneNext => {
131 state.set_active(false);
132 return Some(AppMessage::SetActivePane(ActivePane::Outline));
133 }
134 Message::SwitchPanePrevious => {
135 state.set_active(false);
136 return Some(AppMessage::SetActivePane(ActivePane::Explorer));
137 }
138 Message::Save => {
139 let _ = state.save_to_file();
141 return Some(AppMessage::UpdateSelectedNoteContent((
142 state.content.to_string(),
143 None,
144 )));
145 }
146 _ => {}
147 },
148 }
149
150 None
151}
152
153pub fn handle_editing_event(key: &KeyEvent) -> Option<Message> {
154 match key.code {
155 KeyCode::Up => Some(Message::CursorUp),
156 KeyCode::Down => Some(Message::CursorDown),
157 KeyCode::Char('f') if key.modifiers.contains(KeyModifiers::ALT) => {
158 Some(Message::CursorWordForward)
159 }
160 KeyCode::Char('b') if key.modifiers.contains(KeyModifiers::ALT) => {
161 Some(Message::CursorWordBackward)
162 }
163 KeyCode::Left => Some(Message::CursorLeft),
164 KeyCode::Right => Some(Message::CursorRight),
165 KeyCode::Esc => Some(Message::Exit),
166 KeyCode::Backspace => Some(Message::Delete),
167 KeyCode::Char('e') if key.modifiers.contains(KeyModifiers::CONTROL) => {
168 Some(Message::ToggleView)
169 }
170 _ => Some(Message::KeyEvent(*key)),
171 }
172}