Compare commits

..

3 commits

7 changed files with 68 additions and 104 deletions

48
Cargo.lock generated
View file

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

View file

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

View file

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

View file

@ -353,31 +353,29 @@ pub struct UserDisplayTunables {
pub type UserOverrides = HashMap<OwnedUserId, UserDisplayTunables>;
fn merge_sorts(profile: SortOverrides, global: SortOverrides) -> SortOverrides {
fn merge_sorts(a: SortOverrides, b: SortOverrides) -> SortOverrides {
SortOverrides {
chats: profile.chats.or(global.chats),
dms: profile.dms.or(global.dms),
rooms: profile.rooms.or(global.rooms),
spaces: profile.spaces.or(global.spaces),
members: profile.members.or(global.members),
chats: b.chats.or(a.chats),
dms: b.dms.or(a.dms),
rooms: b.rooms.or(a.rooms),
spaces: b.spaces.or(a.spaces),
members: b.members.or(a.members),
}
}
fn merge_maps<K, V>(
profile: Option<HashMap<K, V>>,
global: Option<HashMap<K, V>>,
) -> Option<HashMap<K, V>>
fn merge_maps<K, V>(a: Option<HashMap<K, V>>, b: Option<HashMap<K, V>>) -> Option<HashMap<K, V>>
where
K: Eq + Hash,
{
match (global, profile) {
(Some(m), None) | (None, Some(m)) => Some(m),
(Some(mut global), Some(profile)) => {
for (k, v) in profile {
global.insert(k, v);
match (a, b) {
(Some(a), None) => Some(a),
(None, Some(b)) => Some(b),
(Some(mut a), Some(b)) => {
for (k, v) in b {
a.insert(k, v);
}
Some(global)
Some(a)
},
(None, None) => None,
}
@ -920,7 +918,7 @@ impl ApplicationSettings {
}
};
let macros = merge_maps(profile.macros.take(), macros).unwrap_or_default();
let macros = merge_maps(macros, profile.macros.take()).unwrap_or_default();
let layout = profile.layout.take().or(layout).unwrap_or_default();
let tunables = global.unwrap_or_default();
@ -1133,10 +1131,10 @@ mod tests {
assert_eq!(res, Some(b.clone()));
let res = merge_maps(Some(b.clone()), Some(c.clone()));
assert_eq!(res, Some(b.clone()));
assert_eq!(res, Some(c.clone()));
let res = merge_maps(Some(c.clone()), Some(b.clone()));
assert_eq!(res, Some(c.clone()));
assert_eq!(res, Some(b.clone()));
}
#[test]

View file

@ -62,7 +62,7 @@ use modalkit::crossterm::{
use ratatui::{
backend::CrosstermBackend,
layout::Rect,
style::{Color, Modifier, Style},
style::{Color, Style},
text::Span,
widgets::Paragraph,
Terminal,
@ -89,7 +89,6 @@ use crate::{
ChatStore,
HomeserverAction,
IambAction,
IambCompleter,
IambError,
IambId,
IambInfo,
@ -328,9 +327,6 @@ impl Application {
.show_dialog(dialogstr)
.show_mode(modestr)
.borders(true)
.border_style(Style::default().add_modifier(Modifier::DIM))
.tab_style(Style::default().add_modifier(Modifier::DIM))
.tab_style_focused(Style::default().remove_modifier(Modifier::DIM))
.focus(focused);
f.render_stateful_widget(screen, area, sstate);
@ -533,7 +529,7 @@ impl Application {
},
// Unimplemented.
Action::KeywordLookup(_) => {
Action::KeywordLookup => {
// XXX: implement
None
},
@ -1015,9 +1011,7 @@ 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 mut store = Store::new(store);
store.completer = Box::new(IambCompleter);
let store = Store::new(store);
let store = Arc::new(AsyncMutex::new(store));
worker.init(store.clone());

View file

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

View file

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