diff --git a/Cargo.lock b/Cargo.lock index 3fed98d..630b764 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1442,6 +1442,41 @@ dependencies = [ "which", ] +[[package]] +name = "editor-types" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e99679670f67825fcd24a23cb4eb655a0f92c82bd4d1c1a1357c0cd71e87" +dependencies = [ + "bitflags 2.9.1", + "editor-types-macros", + "keybindings", + "regex", +] + +[[package]] +name = "editor-types-macros" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42680de76cf91f231abd90cc623750d39077f7d2fadb7962325fb082871f4c66" +dependencies = [ + "editor-types-parser", + "nom", + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "editor-types-parser" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cac4b91fe830fbbe0a60c37ba0264b6e9ffc70e3664c028234dac59e79299ad4" +dependencies = [ + "nom", + "thiserror 1.0.69", +] + [[package]] name = "either" version = "1.15.0" @@ -2706,9 +2741,9 @@ dependencies = [ [[package]] name = "keybindings" -version = "0.0.1" +version = "0.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "680e4699c91c0622dd70da32c274881aadb1ac86252d738c3641266e90e4ca15" +checksum = "19a726307ed87e05155c31329676130e6a237e62dda80211f7e1ed811e47630f" dependencies = [ "textwrap", "unicode-segmentation", @@ -3292,15 +3327,16 @@ dependencies = [ [[package]] name = "modalkit" -version = "0.0.21" +version = "0.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc7599fc1bcd2f0a0b4598f23433b45613345a46419ab27d3a9adecb57acd648" +checksum = "6ed06f32b03a7504acadcb0d95d06f3d55258934c34b620ed95e3dae24f081a5" dependencies = [ "anymap2", "arboard", "bitflags 2.9.1", "crossterm", "derive_more", + "editor-types", "intervaltree", "keybindings", "nom", @@ -3314,9 +3350,9 @@ dependencies = [ [[package]] name = "modalkit-ratatui" -version = "0.0.21" +version = "0.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd3d88c86435d4b1fb22c7c0f978b09cb888338cafc10336715aa5070e92b6f6" +checksum = "a33bd64f6dd0011ee88f4f12b28108d3e63df0a5c86fe595d24561be9522f6ea" dependencies = [ "crossterm", "intervaltree", diff --git a/Cargo.toml b/Cargo.toml index 1ac3bf1..556fcc2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -77,13 +77,13 @@ features = ["zbus", "serde"] optional = true [dependencies.modalkit] -version = "0.0.21" +version = "0.0.23" default-features = false #git = "https://github.com/ulyssa/modalkit" #rev = "e40dbb0bfeabe4cfd08facd2acb446080a330d75" [dependencies.modalkit-ratatui] -version = "0.0.21" +version = "0.0.23" #git = "https://github.com/ulyssa/modalkit" #rev = "e40dbb0bfeabe4cfd08facd2acb446080a330d75" diff --git a/src/base.rs b/src/base.rs index fdb7875..56d4c2d 100644 --- a/src/base.rs +++ b/src/base.rs @@ -74,7 +74,7 @@ use modalkit::{ ApplicationStore, ApplicationWindowId, }, - completion::{complete_path, CompletionMap}, + completion::{complete_path, Completer, CompletionMap}, context::EditContext, cursor::Cursor, rope::EditRope, @@ -1914,11 +1914,20 @@ impl ApplicationInfo for IambInfo { type WindowId = IambId; type ContentId = IambBufferId; + fn content_of_command(ct: CommandType) -> IambBufferId { + IambBufferId::Command(ct) + } +} + +pub struct IambCompleter; + +impl Completer for IambCompleter { fn complete( + &mut self, text: &EditRope, cursor: &mut Cursor, content: &IambBufferId, - store: &mut ProgramStore, + store: &mut ChatStore, ) -> Vec { match content { IambBufferId::Command(CommandType::Command) => complete_cmdbar(text, cursor, store), @@ -1936,21 +1945,16 @@ impl ApplicationInfo for IambInfo { IambBufferId::UnreadList => vec![], } } - - fn content_of_command(ct: CommandType) -> IambBufferId { - IambBufferId::Command(ct) - } } /// Tab completion for user IDs. -fn complete_users(text: &EditRope, cursor: &mut Cursor, store: &ProgramStore) -> Vec { +fn complete_users(text: &EditRope, cursor: &mut Cursor, store: &ChatStore) -> Vec { let id = text .get_prefix_word_mut(cursor, &MATRIX_ID_WORD) .unwrap_or_else(EditRope::empty); let id = Cow::from(&id); store - .application .presences .complete(id.as_ref()) .into_iter() @@ -1959,7 +1963,7 @@ fn complete_users(text: &EditRope, cursor: &mut Cursor, store: &ProgramStore) -> } /// Tab completion within the message bar. -fn complete_msgbar(text: &EditRope, cursor: &mut Cursor, store: &ProgramStore) -> Vec { +fn complete_msgbar(text: &EditRope, cursor: &mut Cursor, store: &ChatStore) -> Vec { let id = text .get_prefix_word_mut(cursor, &MATRIX_ID_WORD) .unwrap_or_else(EditRope::empty); @@ -1968,13 +1972,12 @@ fn complete_msgbar(text: &EditRope, cursor: &mut Cursor, store: &ProgramStore) - match id.chars().next() { // Complete room aliases. Some('#') => { - return store.application.names.complete(id.as_ref()); + return store.names.complete(id.as_ref()); }, // Complete room identifiers. Some('!') => { return store - .application .rooms .complete(id.as_ref()) .into_iter() @@ -1984,7 +1987,7 @@ fn complete_msgbar(text: &EditRope, cursor: &mut Cursor, store: &ProgramStore) - // Complete Emoji shortcodes. Some(':') => { - let list = store.application.emojis.complete(&id[1..]); + let list = store.emojis.complete(&id[1..]); let iter = list.into_iter().take(200).map(|s| format!(":{}:", s)); return iter.collect(); @@ -1993,7 +1996,6 @@ fn complete_msgbar(text: &EditRope, cursor: &mut Cursor, store: &ProgramStore) - // Complete usernames for @ and empty strings. Some('@') | None => { return store - .application .presences .complete(id.as_ref()) .into_iter() @@ -2007,28 +2009,23 @@ fn complete_msgbar(text: &EditRope, cursor: &mut Cursor, store: &ProgramStore) - } /// Tab completion for Matrix identifiers (usernames, room aliases, etc.) -fn complete_matrix_names( - text: &EditRope, - cursor: &mut Cursor, - store: &ProgramStore, -) -> Vec { +fn complete_matrix_names(text: &EditRope, cursor: &mut Cursor, store: &ChatStore) -> Vec { let id = text .get_prefix_word_mut(cursor, &MATRIX_ID_WORD) .unwrap_or_else(EditRope::empty); let id = Cow::from(&id); - let list = store.application.names.complete(id.as_ref()); + let list = store.names.complete(id.as_ref()); if !list.is_empty() { return list; } - let list = store.application.presences.complete(id.as_ref()); + let list = store.presences.complete(id.as_ref()); if !list.is_empty() { return list.into_iter().map(|i| i.to_string()).collect(); } store - .application .rooms .complete(id.as_ref()) .into_iter() @@ -2037,12 +2034,12 @@ fn complete_matrix_names( } /// Tab completion for Emoji shortcode names. -fn complete_emoji(text: &EditRope, cursor: &mut Cursor, store: &ProgramStore) -> Vec { +fn complete_emoji(text: &EditRope, cursor: &mut Cursor, store: &ChatStore) -> Vec { let sc = text.get_prefix_word_mut(cursor, &WordStyle::Little); let sc = sc.unwrap_or_else(EditRope::empty); let sc = Cow::from(&sc); - store.application.emojis.complete(sc.as_ref()) + store.emojis.complete(sc.as_ref()) } /// Tab completion for command names. @@ -2050,11 +2047,11 @@ fn complete_cmdname( desc: CommandDescription, text: &EditRope, cursor: &mut Cursor, - store: &ProgramStore, + store: &ChatStore, ) -> Vec { // Complete command name and set cursor position. let _ = text.get_prefix_word_mut(cursor, &WordStyle::Little); - store.application.cmds.complete_name(desc.command.as_str()) + store.cmds.complete_name(desc.command.as_str()) } /// Tab completion for command arguments. @@ -2062,9 +2059,9 @@ fn complete_cmdarg( desc: CommandDescription, text: &EditRope, cursor: &mut Cursor, - store: &ProgramStore, + store: &ChatStore, ) -> Vec { - let cmd = match store.application.cmds.get(desc.command.as_str()) { + let cmd = match store.cmds.get(desc.command.as_str()) { Ok(cmd) => cmd, Err(_) => return vec![], }; @@ -2087,12 +2084,7 @@ fn complete_cmdarg( } /// Tab completion for commands. -fn complete_cmd( - cmd: &str, - text: &EditRope, - cursor: &mut Cursor, - store: &ProgramStore, -) -> Vec { +fn complete_cmd(cmd: &str, text: &EditRope, cursor: &mut Cursor, store: &ChatStore) -> Vec { match CommandDescription::from_str(cmd) { Ok(desc) => { if desc.arg.untrimmed.is_empty() { @@ -2109,7 +2101,7 @@ fn complete_cmd( } /// Tab completion for the command bar. -fn complete_cmdbar(text: &EditRope, cursor: &mut Cursor, store: &ProgramStore) -> Vec { +fn complete_cmdbar(text: &EditRope, cursor: &mut Cursor, store: &ChatStore) -> Vec { let eo = text.cursor_to_offset(cursor); let slice = text.slice(..eo); let cow = Cow::from(&slice); @@ -2289,6 +2281,7 @@ pub mod tests { #[tokio::test] async fn test_complete_msgbar() { let store = mock_store().await; + let store = store.application; let text = EditRope::from("going for a walk :walk "); let mut cursor = Cursor::new(0, 22); @@ -2312,6 +2305,7 @@ pub mod tests { #[tokio::test] async fn test_complete_cmdbar() { let store = mock_store().await; + let store = store.application; let users = vec![ "@user1:example.com", "@user2:example.com", diff --git a/src/main.rs b/src/main.rs index 9b8fe46..9060947 100644 --- a/src/main.rs +++ b/src/main.rs @@ -89,6 +89,7 @@ use crate::{ ChatStore, HomeserverAction, IambAction, + IambCompleter, IambError, IambId, IambInfo, @@ -529,7 +530,7 @@ impl Application { }, // Unimplemented. - Action::KeywordLookup => { + Action::KeywordLookup(_) => { // XXX: implement None }, @@ -1011,7 +1012,9 @@ async fn run(settings: ApplicationSettings) -> IambResult<()> { // Set up the async worker thread and global store. let worker = ClientWorker::spawn(client.clone(), settings.clone()).await; let store = ChatStore::new(worker.clone(), settings.clone()); - let store = Store::new(store); + let mut store = Store::new(store); + store.completer = Box::new(IambCompleter); + let store = Arc::new(AsyncMutex::new(store)); worker.init(store.clone()); diff --git a/src/windows/room/chat.rs b/src/windows/room/chat.rs index cb584f4..426a66c 100644 --- a/src/windows/room/chat.rs +++ b/src/windows/room/chat.rs @@ -864,16 +864,16 @@ impl PromptActions for ChatState { fn recall( &mut self, + filter: &RecallFilter, dir: &MoveDir1D, count: &Count, - prefixed: bool, ctx: &ProgramContext, _: &mut ProgramStore, ) -> EditResult, IambInfo> { let count = ctx.resolve(count); let rope = self.tbox.get(); - let text = self.sent.recall(&rope, &mut self.sent_scrollback, *dir, prefixed, count); + let text = self.sent.recall(&rope, &mut self.sent_scrollback, filter, *dir, count); if let Some(text) = text { self.tbox.set_text(text); @@ -897,9 +897,7 @@ impl Promptable for ChatState { match act { PromptAction::Submit => self.submit(ctx, store), PromptAction::Abort(empty) => self.abort(*empty, ctx, store), - PromptAction::Recall(dir, count, prefixed) => { - self.recall(dir, count, *prefixed, ctx, store) - }, + PromptAction::Recall(filter, dir, count) => self.recall(filter, dir, count, ctx, store), } } } diff --git a/src/windows/room/scrollback.rs b/src/windows/room/scrollback.rs index 53da0b7..5f32897 100644 --- a/src/windows/room/scrollback.rs +++ b/src/windows/room/scrollback.rs @@ -840,8 +840,8 @@ impl EditorActions for ScrollbackState { fn complete( &mut self, + _: &CompletionStyle, _: &CompletionType, - _: &CompletionSelection, _: &CompletionDisplay, _: &ProgramContext, _: &mut ProgramStore,