keymap: refuse scope names with outer whitespace, which binding text trims

This commit is contained in:
aiongg committed 2026-10-20 15:08:43 +00:00
1 parent 0da8ea8a9f
commit 056a709d0f
2 files changed
+17 -4

No files matched your search

+8 -4
View File
@@ -9,17 +9,21 @@ pub const MAX_SCOPE_NAME: usize = 64;
const APP: &str = "Application";
/// The name of a scope. Never empty, at most [`MAX_SCOPE_NAME`] bytes, without `:`.
/// The name of a scope. Never empty, at most [`MAX_SCOPE_NAME`] bytes, without `:` or outer
/// whitespace.
#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize)]
#[serde(transparent)]
pub struct Scope(String);
impl Scope {
/// `None` for an empty name, one over [`MAX_SCOPE_NAME`] bytes, or one with `:` or a control
/// character.
/// `None` for an empty name, one over [`MAX_SCOPE_NAME`] bytes, one with `:` or a control
/// character, or one with whitespace at either end, which binding text would lose.
pub fn new(name: impl Into<String>) -> Option<Scope> {
let name = name.into();
let ok = !name.is_empty() && name.len() <= MAX_SCOPE_NAME && !name.chars().any(|c| c == ':' || c.is_control());
let ok = !name.is_empty()
&& name.len() <= MAX_SCOPE_NAME
&& name.trim() == name
&& !name.chars().any(|c| c == ':' || c.is_control());
ok.then_some(Scope(name))
}
+9
View File
@@ -375,6 +375,15 @@ fn binding_text_round_trips_for_every_key() {
assert_eq!(Binding::parse(": :"), Ok(Binding::new(Trigger::double(Chord::plain(Key::Colon)))));
}
#[test]
fn scope_names_with_outer_whitespace_are_refused() {
for name in [" Timeline", "Timeline ", "\u{a0}Timeline", ""] {
assert_eq!(Scope::new(name), None, "{name:?}");
}
assert_eq!(Scope::new("Time line").map(|s| s.to_string()).as_deref(), Some("Time line"));
assert_eq!(Binding::parse(" Timeline : K").map(|b| b.scope), Ok(Some(scope("Timeline"))));
}
#[test]
fn edits_are_refused_when_the_overrides_are_full() {
let catalog = vec![app("edit.copy", &["Cmd+C"]), app("edit.duplicate", &["Cmd+D"]), app("edit.cut", &[])];