Update to modalkit{,-ratatui}@0.0.23 (#473)

This commit is contained in:
Ulyssa 2025-07-04 17:12:50 -07:00 committed by GitHub
parent 0ef5c39f7f
commit 52010d44d7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 81 additions and 50 deletions

48
Cargo.lock generated
View file

@ -1442,6 +1442,41 @@ dependencies = [
"which", "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]] [[package]]
name = "either" name = "either"
version = "1.15.0" version = "1.15.0"
@ -2706,9 +2741,9 @@ dependencies = [
[[package]] [[package]]
name = "keybindings" name = "keybindings"
version = "0.0.1" version = "0.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "680e4699c91c0622dd70da32c274881aadb1ac86252d738c3641266e90e4ca15" checksum = "19a726307ed87e05155c31329676130e6a237e62dda80211f7e1ed811e47630f"
dependencies = [ dependencies = [
"textwrap", "textwrap",
"unicode-segmentation", "unicode-segmentation",
@ -3292,15 +3327,16 @@ dependencies = [
[[package]] [[package]]
name = "modalkit" name = "modalkit"
version = "0.0.21" version = "0.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc7599fc1bcd2f0a0b4598f23433b45613345a46419ab27d3a9adecb57acd648" checksum = "6ed06f32b03a7504acadcb0d95d06f3d55258934c34b620ed95e3dae24f081a5"
dependencies = [ dependencies = [
"anymap2", "anymap2",
"arboard", "arboard",
"bitflags 2.9.1", "bitflags 2.9.1",
"crossterm", "crossterm",
"derive_more", "derive_more",
"editor-types",
"intervaltree", "intervaltree",
"keybindings", "keybindings",
"nom", "nom",
@ -3314,9 +3350,9 @@ dependencies = [
[[package]] [[package]]
name = "modalkit-ratatui" name = "modalkit-ratatui"
version = "0.0.21" version = "0.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd3d88c86435d4b1fb22c7c0f978b09cb888338cafc10336715aa5070e92b6f6" checksum = "a33bd64f6dd0011ee88f4f12b28108d3e63df0a5c86fe595d24561be9522f6ea"
dependencies = [ dependencies = [
"crossterm", "crossterm",
"intervaltree", "intervaltree",

View file

@ -77,13 +77,13 @@ features = ["zbus", "serde"]
optional = true optional = true
[dependencies.modalkit] [dependencies.modalkit]
version = "0.0.21" version = "0.0.23"
default-features = false default-features = false
#git = "https://github.com/ulyssa/modalkit" #git = "https://github.com/ulyssa/modalkit"
#rev = "e40dbb0bfeabe4cfd08facd2acb446080a330d75" #rev = "e40dbb0bfeabe4cfd08facd2acb446080a330d75"
[dependencies.modalkit-ratatui] [dependencies.modalkit-ratatui]
version = "0.0.21" version = "0.0.23"
#git = "https://github.com/ulyssa/modalkit" #git = "https://github.com/ulyssa/modalkit"
#rev = "e40dbb0bfeabe4cfd08facd2acb446080a330d75" #rev = "e40dbb0bfeabe4cfd08facd2acb446080a330d75"

View file

@ -74,7 +74,7 @@ use modalkit::{
ApplicationStore, ApplicationStore,
ApplicationWindowId, ApplicationWindowId,
}, },
completion::{complete_path, CompletionMap}, completion::{complete_path, Completer, CompletionMap},
context::EditContext, context::EditContext,
cursor::Cursor, cursor::Cursor,
rope::EditRope, rope::EditRope,
@ -1914,11 +1914,20 @@ impl ApplicationInfo for IambInfo {
type WindowId = IambId; type WindowId = IambId;
type ContentId = IambBufferId; type ContentId = IambBufferId;
fn content_of_command(ct: CommandType) -> IambBufferId {
IambBufferId::Command(ct)
}
}
pub struct IambCompleter;
impl Completer<IambInfo> for IambCompleter {
fn complete( fn complete(
&mut self,
text: &EditRope, text: &EditRope,
cursor: &mut Cursor, cursor: &mut Cursor,
content: &IambBufferId, content: &IambBufferId,
store: &mut ProgramStore, store: &mut ChatStore,
) -> Vec<String> { ) -> Vec<String> {
match content { match content {
IambBufferId::Command(CommandType::Command) => complete_cmdbar(text, cursor, store), IambBufferId::Command(CommandType::Command) => complete_cmdbar(text, cursor, store),
@ -1936,21 +1945,16 @@ impl ApplicationInfo for IambInfo {
IambBufferId::UnreadList => vec![], IambBufferId::UnreadList => vec![],
} }
} }
fn content_of_command(ct: CommandType) -> IambBufferId {
IambBufferId::Command(ct)
}
} }
/// Tab completion for user IDs. /// Tab completion for user IDs.
fn complete_users(text: &EditRope, cursor: &mut Cursor, store: &ProgramStore) -> Vec<String> { fn complete_users(text: &EditRope, cursor: &mut Cursor, store: &ChatStore) -> Vec<String> {
let id = text let id = text
.get_prefix_word_mut(cursor, &MATRIX_ID_WORD) .get_prefix_word_mut(cursor, &MATRIX_ID_WORD)
.unwrap_or_else(EditRope::empty); .unwrap_or_else(EditRope::empty);
let id = Cow::from(&id); let id = Cow::from(&id);
store store
.application
.presences .presences
.complete(id.as_ref()) .complete(id.as_ref())
.into_iter() .into_iter()
@ -1959,7 +1963,7 @@ fn complete_users(text: &EditRope, cursor: &mut Cursor, store: &ProgramStore) ->
} }
/// Tab completion within the message bar. /// Tab completion within the message bar.
fn complete_msgbar(text: &EditRope, cursor: &mut Cursor, store: &ProgramStore) -> Vec<String> { fn complete_msgbar(text: &EditRope, cursor: &mut Cursor, store: &ChatStore) -> Vec<String> {
let id = text let id = text
.get_prefix_word_mut(cursor, &MATRIX_ID_WORD) .get_prefix_word_mut(cursor, &MATRIX_ID_WORD)
.unwrap_or_else(EditRope::empty); .unwrap_or_else(EditRope::empty);
@ -1968,13 +1972,12 @@ fn complete_msgbar(text: &EditRope, cursor: &mut Cursor, store: &ProgramStore) -
match id.chars().next() { match id.chars().next() {
// Complete room aliases. // Complete room aliases.
Some('#') => { Some('#') => {
return store.application.names.complete(id.as_ref()); return store.names.complete(id.as_ref());
}, },
// Complete room identifiers. // Complete room identifiers.
Some('!') => { Some('!') => {
return store return store
.application
.rooms .rooms
.complete(id.as_ref()) .complete(id.as_ref())
.into_iter() .into_iter()
@ -1984,7 +1987,7 @@ fn complete_msgbar(text: &EditRope, cursor: &mut Cursor, store: &ProgramStore) -
// Complete Emoji shortcodes. // Complete Emoji shortcodes.
Some(':') => { 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)); let iter = list.into_iter().take(200).map(|s| format!(":{}:", s));
return iter.collect(); return iter.collect();
@ -1993,7 +1996,6 @@ fn complete_msgbar(text: &EditRope, cursor: &mut Cursor, store: &ProgramStore) -
// Complete usernames for @ and empty strings. // Complete usernames for @ and empty strings.
Some('@') | None => { Some('@') | None => {
return store return store
.application
.presences .presences
.complete(id.as_ref()) .complete(id.as_ref())
.into_iter() .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.) /// Tab completion for Matrix identifiers (usernames, room aliases, etc.)
fn complete_matrix_names( fn complete_matrix_names(text: &EditRope, cursor: &mut Cursor, store: &ChatStore) -> Vec<String> {
text: &EditRope,
cursor: &mut Cursor,
store: &ProgramStore,
) -> Vec<String> {
let id = text let id = text
.get_prefix_word_mut(cursor, &MATRIX_ID_WORD) .get_prefix_word_mut(cursor, &MATRIX_ID_WORD)
.unwrap_or_else(EditRope::empty); .unwrap_or_else(EditRope::empty);
let id = Cow::from(&id); 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() { if !list.is_empty() {
return list; return list;
} }
let list = store.application.presences.complete(id.as_ref()); let list = store.presences.complete(id.as_ref());
if !list.is_empty() { if !list.is_empty() {
return list.into_iter().map(|i| i.to_string()).collect(); return list.into_iter().map(|i| i.to_string()).collect();
} }
store store
.application
.rooms .rooms
.complete(id.as_ref()) .complete(id.as_ref())
.into_iter() .into_iter()
@ -2037,12 +2034,12 @@ fn complete_matrix_names(
} }
/// Tab completion for Emoji shortcode names. /// Tab completion for Emoji shortcode names.
fn complete_emoji(text: &EditRope, cursor: &mut Cursor, store: &ProgramStore) -> Vec<String> { fn complete_emoji(text: &EditRope, cursor: &mut Cursor, store: &ChatStore) -> Vec<String> {
let sc = text.get_prefix_word_mut(cursor, &WordStyle::Little); let sc = text.get_prefix_word_mut(cursor, &WordStyle::Little);
let sc = sc.unwrap_or_else(EditRope::empty); let sc = sc.unwrap_or_else(EditRope::empty);
let sc = Cow::from(&sc); let sc = Cow::from(&sc);
store.application.emojis.complete(sc.as_ref()) store.emojis.complete(sc.as_ref())
} }
/// Tab completion for command names. /// Tab completion for command names.
@ -2050,11 +2047,11 @@ fn complete_cmdname(
desc: CommandDescription, desc: CommandDescription,
text: &EditRope, text: &EditRope,
cursor: &mut Cursor, cursor: &mut Cursor,
store: &ProgramStore, store: &ChatStore,
) -> Vec<String> { ) -> Vec<String> {
// Complete command name and set cursor position. // Complete command name and set cursor position.
let _ = text.get_prefix_word_mut(cursor, &WordStyle::Little); 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. /// Tab completion for command arguments.
@ -2062,9 +2059,9 @@ fn complete_cmdarg(
desc: CommandDescription, desc: CommandDescription,
text: &EditRope, text: &EditRope,
cursor: &mut Cursor, cursor: &mut Cursor,
store: &ProgramStore, store: &ChatStore,
) -> Vec<String> { ) -> Vec<String> {
let cmd = match store.application.cmds.get(desc.command.as_str()) { let cmd = match store.cmds.get(desc.command.as_str()) {
Ok(cmd) => cmd, Ok(cmd) => cmd,
Err(_) => return vec![], Err(_) => return vec![],
}; };
@ -2087,12 +2084,7 @@ fn complete_cmdarg(
} }
/// Tab completion for commands. /// Tab completion for commands.
fn complete_cmd( fn complete_cmd(cmd: &str, text: &EditRope, cursor: &mut Cursor, store: &ChatStore) -> Vec<String> {
cmd: &str,
text: &EditRope,
cursor: &mut Cursor,
store: &ProgramStore,
) -> Vec<String> {
match CommandDescription::from_str(cmd) { match CommandDescription::from_str(cmd) {
Ok(desc) => { Ok(desc) => {
if desc.arg.untrimmed.is_empty() { if desc.arg.untrimmed.is_empty() {
@ -2109,7 +2101,7 @@ fn complete_cmd(
} }
/// Tab completion for the command bar. /// Tab completion for the command bar.
fn complete_cmdbar(text: &EditRope, cursor: &mut Cursor, store: &ProgramStore) -> Vec<String> { fn complete_cmdbar(text: &EditRope, cursor: &mut Cursor, store: &ChatStore) -> Vec<String> {
let eo = text.cursor_to_offset(cursor); let eo = text.cursor_to_offset(cursor);
let slice = text.slice(..eo); let slice = text.slice(..eo);
let cow = Cow::from(&slice); let cow = Cow::from(&slice);
@ -2289,6 +2281,7 @@ pub mod tests {
#[tokio::test] #[tokio::test]
async fn test_complete_msgbar() { async fn test_complete_msgbar() {
let store = mock_store().await; let store = mock_store().await;
let store = store.application;
let text = EditRope::from("going for a walk :walk "); let text = EditRope::from("going for a walk :walk ");
let mut cursor = Cursor::new(0, 22); let mut cursor = Cursor::new(0, 22);
@ -2312,6 +2305,7 @@ pub mod tests {
#[tokio::test] #[tokio::test]
async fn test_complete_cmdbar() { async fn test_complete_cmdbar() {
let store = mock_store().await; let store = mock_store().await;
let store = store.application;
let users = vec![ let users = vec![
"@user1:example.com", "@user1:example.com",
"@user2:example.com", "@user2:example.com",

View file

@ -89,6 +89,7 @@ use crate::{
ChatStore, ChatStore,
HomeserverAction, HomeserverAction,
IambAction, IambAction,
IambCompleter,
IambError, IambError,
IambId, IambId,
IambInfo, IambInfo,
@ -529,7 +530,7 @@ impl Application {
}, },
// Unimplemented. // Unimplemented.
Action::KeywordLookup => { Action::KeywordLookup(_) => {
// XXX: implement // XXX: implement
None None
}, },
@ -1011,7 +1012,9 @@ async fn run(settings: ApplicationSettings) -> IambResult<()> {
// Set up the async worker thread and global store. // Set up the async worker thread and global store.
let worker = ClientWorker::spawn(client.clone(), settings.clone()).await; let worker = ClientWorker::spawn(client.clone(), settings.clone()).await;
let store = ChatStore::new(worker.clone(), settings.clone()); 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)); let store = Arc::new(AsyncMutex::new(store));
worker.init(store.clone()); worker.init(store.clone());

View file

@ -864,16 +864,16 @@ impl PromptActions<ProgramContext, ProgramStore, IambInfo> for ChatState {
fn recall( fn recall(
&mut self, &mut self,
filter: &RecallFilter,
dir: &MoveDir1D, dir: &MoveDir1D,
count: &Count, count: &Count,
prefixed: bool,
ctx: &ProgramContext, ctx: &ProgramContext,
_: &mut ProgramStore, _: &mut ProgramStore,
) -> EditResult<Vec<(ProgramAction, ProgramContext)>, IambInfo> { ) -> EditResult<Vec<(ProgramAction, ProgramContext)>, IambInfo> {
let count = ctx.resolve(count); let count = ctx.resolve(count);
let rope = self.tbox.get(); 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 { if let Some(text) = text {
self.tbox.set_text(text); self.tbox.set_text(text);
@ -897,9 +897,7 @@ impl Promptable<ProgramContext, ProgramStore, IambInfo> for ChatState {
match act { match act {
PromptAction::Submit => self.submit(ctx, store), PromptAction::Submit => self.submit(ctx, store),
PromptAction::Abort(empty) => self.abort(*empty, ctx, store), PromptAction::Abort(empty) => self.abort(*empty, ctx, store),
PromptAction::Recall(dir, count, prefixed) => { PromptAction::Recall(filter, dir, count) => self.recall(filter, dir, count, ctx, store),
self.recall(dir, count, *prefixed, ctx, store)
},
} }
} }
} }

View file

@ -840,8 +840,8 @@ impl EditorActions<ProgramContext, ProgramStore, IambInfo> for ScrollbackState {
fn complete( fn complete(
&mut self, &mut self,
_: &CompletionStyle,
_: &CompletionType, _: &CompletionType,
_: &CompletionSelection,
_: &CompletionDisplay, _: &CompletionDisplay,
_: &ProgramContext, _: &ProgramContext,
_: &mut ProgramStore, _: &mut ProgramStore,