Compare commits

...

7 Commits

Author SHA1 Message Date
Benedikt Peetz 4e839d4e2c
fix(config/lua): Add the 'jj' mapping the insert mode
This is just here to prove that the fixes for the KeyInputPending mode
actually work
2023-10-18 23:10:44 +02:00
Benedikt Peetz c024b73625
fix(ui): Display pending keys in KeyInputPending 2023-10-18 23:10:12 +02:00
Benedikt Peetz 18152bdded
fix(key_input): Also input pending keys, when leaving KeyInputPending 2023-10-18 23:09:09 +02:00
Benedikt Peetz 0ed99b6244
fix(config/lua): Generate the 'keymappings' table under 'std' 2023-10-18 23:03:16 +02:00
Benedikt Peetz b54f8e59e8
fix(key_input): Handle shifted characters correctly
This commit fixes multiple bugs introduced in the new keymapping system:

    When we can't find a keymapping for a string, we simply pass it
along, by calling the 'send_input_unprocessed' function with the
inputted key turned into it's string representation. Turning a shifted
key into it's repr. returned a doubly shifted string:
   'A' turned into '<S-A>', which then fails to parse as a valid key
input. Thus, we simply unshifted the value.
    The next bug, becoming apparent now, is caused by this: We never
reshifted the value, when we converted it into a crossterm key input
event.
2023-10-18 22:52:07 +02:00
Benedikt Peetz 66bf5e3b6f
build(update.sh): Include the language_macros dir in the update 2023-10-18 21:14:23 +02:00
Benedikt Peetz 97c7327d54
build(treewide): Update 2023-10-18 21:14:03 +02:00
9 changed files with 152 additions and 40 deletions

51
Cargo.lock generated
View File

@ -667,7 +667,7 @@ dependencies = [
"hashbrown 0.14.1", "hashbrown 0.14.1",
"lock_api", "lock_api",
"once_cell", "once_cell",
"parking_lot_core 0.9.8", "parking_lot_core 0.9.9",
] ]
[[package]] [[package]]
@ -1034,7 +1034,7 @@ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.38", "syn 2.0.38",
"uuid 1.4.1", "uuid 1.5.0",
] ]
[[package]] [[package]]
@ -1206,16 +1206,16 @@ dependencies = [
[[package]] [[package]]
name = "iana-time-zone" name = "iana-time-zone"
version = "0.1.57" version = "0.1.58"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20"
dependencies = [ dependencies = [
"android_system_properties", "android_system_properties",
"core-foundation-sys", "core-foundation-sys",
"iana-time-zone-haiku", "iana-time-zone-haiku",
"js-sys", "js-sys",
"wasm-bindgen", "wasm-bindgen",
"windows", "windows-core",
] ]
[[package]] [[package]]
@ -1378,9 +1378,9 @@ checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f"
[[package]] [[package]]
name = "lock_api" name = "lock_api"
version = "0.4.10" version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"scopeguard", "scopeguard",
@ -1791,7 +1791,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
dependencies = [ dependencies = [
"lock_api", "lock_api",
"parking_lot_core 0.9.8", "parking_lot_core 0.9.9",
] ]
[[package]] [[package]]
@ -1810,13 +1810,13 @@ dependencies = [
[[package]] [[package]]
name = "parking_lot_core" name = "parking_lot_core"
version = "0.9.8" version = "0.9.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"libc", "libc",
"redox_syscall 0.3.5", "redox_syscall 0.4.1",
"smallvec", "smallvec",
"windows-targets", "windows-targets",
] ]
@ -2074,6 +2074,15 @@ dependencies = [
"bitflags 1.3.2", "bitflags 1.3.2",
] ]
[[package]]
name = "redox_syscall"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
dependencies = [
"bitflags 1.3.2",
]
[[package]] [[package]]
name = "redox_users" name = "redox_users"
version = "0.4.3" version = "0.4.3"
@ -2087,9 +2096,9 @@ dependencies = [
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.10.1" version = "1.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aaac441002f822bc9705a681810a4dd2963094b9ca0ddc41cb963a4c189189ea" checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
@ -2099,9 +2108,9 @@ dependencies = [
[[package]] [[package]]
name = "regex-automata" name = "regex-automata"
version = "0.4.2" version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5011c7e263a695dc8ca064cddb722af1be54e517a280b12a5356f98366899e5d" checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
@ -2209,7 +2218,7 @@ dependencies = [
"thiserror", "thiserror",
"tracing", "tracing",
"url", "url",
"uuid 1.4.1", "uuid 1.5.0",
"wildmatch", "wildmatch",
] ]
@ -2848,9 +2857,9 @@ dependencies = [
[[package]] [[package]]
name = "uuid" name = "uuid"
version = "1.4.1" version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" checksum = "88ad59a7560b41a70d191093a945f0b87bc1deeda46fb237479708a1d6b6cdfc"
dependencies = [ dependencies = [
"getrandom 0.2.10", "getrandom 0.2.10",
"wasm-bindgen", "wasm-bindgen",
@ -3036,10 +3045,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]] [[package]]
name = "windows" name = "windows-core"
version = "0.48.0" version = "0.51.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64"
dependencies = [ dependencies = [
"windows-targets", "windows-targets",
] ]

View File

@ -1,5 +1,8 @@
-- create the required tables under `std`
trinitrix.std = {keymaps = {}};
--- Add a new keymap. This is just a convenience function which registers the function --- Add a new keymap. This is just a convenience function which registers the function
-- and at the same time deals with the fact that the whole trinitrix api is async. --- and at the same time deals with the fact that the whole trinitrix api is async.
---@param mode string ---@param mode string
---@param key string ---@param key string
---@param callback function ---@param callback function
@ -21,6 +24,6 @@ trinitrix.std.keymaps.add("n", ":", trinitrix.api.ui.command_line_show)
trinitrix.std.keymaps.add("n", "i", trinitrix.api.ui.set_mode_insert) trinitrix.std.keymaps.add("n", "i", trinitrix.api.ui.set_mode_insert)
-- a simple test to prove that key chords work -- a simple test to prove that key chords work
trinitrix.std.keymaps.add("n", "jj", function() print("hi") end) trinitrix.std.keymaps.add("ni", "jj", function() print("hi") end)
trinitrix.std.keymaps.add("n", "q", trinitrix.api.exit) trinitrix.std.keymaps.add("n", "q", trinitrix.api.exit)

View File

@ -16,11 +16,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1697408734, "lastModified": 1697648018,
"narHash": "sha256-OVC6KKdeBAfP8NQ+NyatWfuLZNxmrOe7KUB2Qnaes2Y=", "narHash": "sha256-C7hHmozOpuG4G6/NAnd0/EE1osAzgIV+6eZbuRYtf5U=",
"owner": "ipetkov", "owner": "ipetkov",
"repo": "crane", "repo": "crane",
"rev": "d4bddd0a8c7c4b634f85d4fe415ee783ee135fd9", "rev": "bd2e69ee84552b2befe2594060513ea9e01bfeea",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -100,11 +100,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1697422411, "lastModified": 1697595136,
"narHash": "sha256-eCj20wEwATLm7Bd/+/wOIdbqq9jgvS6ZxMrxujX2DxU=", "narHash": "sha256-9honwiIeMbBKi7FzfEy89f1ShUiXz/gVxZSS048pKyc=",
"owner": "oxalica", "owner": "oxalica",
"repo": "rust-overlay", "repo": "rust-overlay",
"rev": "056256f2fcf3c5a652dbc3edba9ec1a956d41f56", "rev": "a2ccfb2134622b28668a274e403ba6f075ae1223",
"type": "github" "type": "github"
}, },
"original": { "original": {

View File

@ -8,6 +8,6 @@ proc-macro = true
[dependencies] [dependencies]
convert_case = "0.6.0" convert_case = "0.6.0"
proc-macro2 = "1.0.64" proc-macro2 = "1.0.69"
quote = "1.0.29" quote = "1.0.33"
syn = { version = "2.0.25", features = ["extra-traits", "full", "parsing"] } syn = { version = "2.0.38", features = ["extra-traits", "full", "parsing"] }

View File

@ -12,6 +12,25 @@ use crate::app::{
pub async fn handle(app: &mut App<'_>, input_event: &CrosstermEvent) -> Result<EventStatus> { pub async fn handle(app: &mut App<'_>, input_event: &CrosstermEvent) -> Result<EventStatus> {
async fn default(converted_key: Key, app: &mut App<'_>, old_state: &State) -> Result<()> { async fn default(converted_key: Key, app: &mut App<'_>, old_state: &State) -> Result<()> {
info!(
"No keymaps exist for key ('{}'), passing it along..",
converted_key
);
if let State::KeyInputPending {
old_state: _,
pending_keys,
} = app.status.state().clone()
{
for key in pending_keys {
app.tx
.send(Event::CommandEvent(
Command::Trinitrix(Api(Raw(SendInputUnprocessed(key.to_string_repr())))),
None,
))
.await?;
}
app.status.set_state(old_state.to_owned());
}
// Just let the input event slip through if no keymap matches // Just let the input event slip through if no keymap matches
app.tx app.tx
.send(Event::CommandEvent( .send(Event::CommandEvent(
@ -21,7 +40,6 @@ pub async fn handle(app: &mut App<'_>, input_event: &CrosstermEvent) -> Result<E
None, None,
)) ))
.await?; .await?;
app.status.set_state(old_state.to_owned());
Ok(()) Ok(())
} }
@ -65,7 +83,8 @@ pub async fn handle(app: &mut App<'_>, input_event: &CrosstermEvent) -> Result<E
if possible_key_maps.len() == 1 { if possible_key_maps.len() == 1 {
let possible_key_map = possible_key_maps.get(0).expect("The len is 1"); let possible_key_map = possible_key_maps.get(0).expect("The len is 1");
if possible_key_map.is_child() && possible_key_map.is_terminal() && should_call { if possible_key_map.is_child() && possible_key_map.is_terminal() && should_call
{
let function = possible_key_map let function = possible_key_map
.value() .value()
.expect("This node is terminal and a child, it should have a value"); .expect("This node is terminal and a child, it should have a value");

View File

@ -1,7 +1,8 @@
use std::{str::FromStr, fmt::Display}; use std::{fmt::Display, str::FromStr};
use anyhow::{bail, Context}; use anyhow::{bail, Context};
use crossterm::event::{Event, KeyEvent, KeyEventKind, KeyEventState, KeyModifiers}; use cli_log::{debug, info};
use crossterm::event::{Event, KeyCode, KeyEvent, KeyEventKind, KeyEventState, KeyModifiers};
use super::{Chars, KeyValue, Keys}; use super::{Chars, KeyValue, Keys};
@ -236,7 +237,33 @@ impl Into<Event> for Key {
} }
let output = Event::Key(KeyEvent { let output = Event::Key(KeyEvent {
code: self.value.unwrap_or(KeyValue::Null).into(), code: {
// We sorta hit a edge case here, if we have a shifted char we need to tell
// crossterm about that. Thus we need to manually apply the shift modifier on the
// value.
if self.shift {
if let Some(KeyValue::Char(char)) = self.value {
let upper_case_char: char = {
let chars = char.to_uppercase().collect::<Vec<char>>();
if chars.len() != 1 {
unimplemented!(
"
I have no idea how we handle this case,
we'll just have to hope, that it never comes up.
"
);
} else {
*chars.first().expect("We checked the length")
}
};
KeyCode::Char(upper_case_char)
} else {
self.value.unwrap_or(KeyValue::Null).into()
}
} else {
self.value.unwrap_or(KeyValue::Null).into()
}
},
modifiers, modifiers,
kind: KeyEventKind::Press, kind: KeyEventKind::Press,
state: KeyEventState::NONE, state: KeyEventState::NONE,
@ -266,7 +293,40 @@ impl TryFrom<&Event> for Key {
{ {
let key_code = key_event.code; let key_code = key_event.code;
output_key.value = Some(key_code.into()); if output_key.shift {
// We need to deal have an edge case for shift, as the value will be in the
// shifted form (for example 'A'). If we left that, we would get "<S-A>" as
// Key representation, which can't be parsed. So we simply unshift the 'A'
// here, turning the representation into: "<S-a>"
if let KeyCode::Char(char) = key_code {
let lower_case_char: char = {
let chars = char.to_lowercase().collect::<Vec<char>>();
if chars.len() != 1 {
unimplemented!(
"
I have no idea how we handle this case,
we'll just have to hope, that it never comes up.
"
);
} else {
*chars.first().expect("We checked the length")
}
};
info!(
"Had to translate key ('{}') to it's lowercase variant ('{}')",
char, lower_case_char
);
output_key.value = Some(KeyValue::Char(lower_case_char));
} else {
debug!(
"Key ('{}') is shifted but not a character!",
Into::<KeyValue>::into(key_code)
);
output_key.value = Some(key_code.into());
}
} else {
output_key.value = Some(key_code.into());
}
} }
Ok(output_key) Ok(output_key)

View File

@ -45,6 +45,21 @@ mod test {
) )
} }
#[test]
fn test_shift_a() {
let keys: Keys = "<S-a>".parse().unwrap();
assert_eq!(
keys,
Keys(vec![Key {
alt: false,
ctrl: false,
meta: false,
shift: true,
value: Some(KeyValue::Char('a'))
}])
)
}
#[test] #[test]
fn test_string_repr() { fn test_string_repr() {
let key = Key { let key = Key {

View File

@ -86,8 +86,8 @@ impl fmt::Display for State {
Self::Setup => write!(f, "Setup (!! workaround !!)"), Self::Setup => write!(f, "Setup (!! workaround !!)"),
Self::KeyInputPending { Self::KeyInputPending {
old_state: _, old_state: _,
pending_keys: _, pending_keys: keys,
} => write!(f, "Key Input Pending"), } => write!(f, "Key Input Pending: {}", keys),
} }
} }
} }

View File

@ -3,5 +3,11 @@
cargo update && cargo upgrade cargo update && cargo upgrade
cd ./language_macros || (echo "No language_macros directory" && exit 1)
cargo update && cargo upgrade
cd ..
git add Cargo.lock Cargo.toml flake.lock ./language_macros/Cargo.toml
# vim: ft=sh # vim: ft=sh