test(dired): teach describe.key about mode scope; drop one overclaim
`describe_key_identifies_every_default_binding` iterated every binding in the stack and asserted `pmacs.describe.key` resolves it context-free. That held only because no builtin had ever bound a mode-scoped key: dired is #129's first non-detection consumer, so its `n` / `p` / `g` correctly resolved to nothing and the test went red on the feature rather than on a defect. It now sets the effective context per binding -- the mode for a mode-scoped default, and explicitly NO mode for a global one, because a leaked mode legitimately shadows a global chord of the same name (dired's `RET` shadows `edit.newline-and-indent`, which is the point of the mode) and would make the assertion compare the wrong pair. A floor assertion keeps the new arm from going vacuous if the last mode-scoped default is ever removed. Also corrects a doc comment rather than leaving it to be believed: acceptance 3c does not pin the descent ROUTING. Dired holds focus in its own panel, so a raw `switch_buffer` lands in the same window and the mutation is vacuous against that test; dedication is what distinguishes the two paths, so the discriminating pin is the dedicated-panel test next to it. Verified by mutation, not assumed.
This commit is contained in:
parent
f71055a206
commit
e7fa9e9720
|
|
@ -5659,17 +5659,25 @@ mod tests {
|
|||
|
||||
// ---- T M2.11 acceptance --------------------------------------------------
|
||||
|
||||
/// Every chord in the default global keymap must round-trip through
|
||||
/// Every chord in the default keymap must round-trip through
|
||||
/// `pmacs.describe.key`: returning a non-nil table whose `command`
|
||||
/// matches the binding the keymap stack stores.
|
||||
///
|
||||
/// `describe.key` resolves against the **effective context**
|
||||
/// (buffer-local → mode → global), so a mode-scoped default is
|
||||
/// asserted with a buffer that carries that mode rather than
|
||||
/// context-free. Dired is the first builtin to bind mode-scoped keys
|
||||
/// (#129's first non-detection consumer), and without the mode in
|
||||
/// place its `n` / `p` / `g` correctly resolve to nothing.
|
||||
#[test]
|
||||
fn describe_key_identifies_every_default_binding() {
|
||||
use crate::keymap_stack::Scope;
|
||||
let s = EditorState::new();
|
||||
let kms = s.lua_host.keymaps().borrow();
|
||||
let bindings: Vec<(String, String)> = kms
|
||||
let bindings: Vec<(Scope, String, String)> = kms
|
||||
.iter_all()
|
||||
.into_iter()
|
||||
.map(|(_, seq, b)| (crate::key::display_sequence(&seq), b.command))
|
||||
.map(|(scope, seq, b)| (scope, crate::key::display_sequence(&seq), b.command))
|
||||
.collect();
|
||||
drop(kms);
|
||||
// Sanity floor: the default keymap binds at least the M1 surface.
|
||||
|
|
@ -5678,18 +5686,50 @@ mod tests {
|
|||
"default keymap unexpectedly small: {} bindings",
|
||||
bindings.len()
|
||||
);
|
||||
let modes: usize = bindings
|
||||
.iter()
|
||||
.filter(|(scope, _, _)| matches!(scope, Scope::Mode(_)))
|
||||
.count();
|
||||
assert!(
|
||||
modes >= 1,
|
||||
"a mode-scoped default is expected since dired Stage 1; \
|
||||
found none, so the mode arm below asserts nothing"
|
||||
);
|
||||
|
||||
for (seq, expected_command) in &bindings {
|
||||
for (scope, seq, expected_command) in &bindings {
|
||||
let mode = match scope {
|
||||
Scope::Mode(name) => Some(name.clone()),
|
||||
// No buffer-scoped defaults exist; a future one would
|
||||
// need its own buffer context here.
|
||||
Scope::Buffer(_) => continue,
|
||||
Scope::Global => None,
|
||||
};
|
||||
// Set the context explicitly on EVERY iteration, including
|
||||
// the global one: a mode left over from a previous iteration
|
||||
// legitimately shadows a global binding of the same chord
|
||||
// (dired's mode-scoped `RET` shadows
|
||||
// `edit.newline-and-indent`, which is the point of the
|
||||
// mode), so a leaked mode would make this assert the wrong
|
||||
// thing.
|
||||
let context = match &mode {
|
||||
Some(name) => {
|
||||
format!("pmacs.buffer.set_major_mode(pmacs.window.buffer(), {name:?}); ")
|
||||
}
|
||||
None => "pmacs.buffer.set_major_mode(pmacs.window.buffer(), nil); ".to_owned(),
|
||||
};
|
||||
let script = format!(
|
||||
"local r = pmacs.describe.key({seq:?}); \
|
||||
"{context}local r = pmacs.describe.key({seq:?}); \
|
||||
if r == nil then return 'nil' else return r.command end"
|
||||
);
|
||||
let got: String = s.lua_host.lua().load(&script).eval().unwrap_or_else(|e| {
|
||||
panic!("describe.key({seq}) raised: {e}");
|
||||
});
|
||||
assert_eq!(
|
||||
&got, expected_command,
|
||||
"describe.key for {seq:?} returned {got:?}, expected {expected_command:?}"
|
||||
&got,
|
||||
expected_command,
|
||||
"describe.key for {seq:?} (scope {}) returned {got:?}, \
|
||||
expected {expected_command:?}",
|
||||
scope.render()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -700,6 +700,14 @@ fn dired_canonicalization_is_the_cores_own_normalizer() {
|
|||
/// side window (Q#DR10): the next directory is the same kind of thing as
|
||||
/// the current one and belongs in the same slot. Neither replaced by a
|
||||
/// document window nor duplicated.
|
||||
///
|
||||
/// **This test does not pin the routing itself, and says so rather than
|
||||
/// implying otherwise:** dired holds the focus in its own panel here, so
|
||||
/// a raw `switch_buffer` lands in that same window and the assertions
|
||||
/// below hold either way (verified — the mutation is VACUOUS against
|
||||
/// this test). What distinguishes `display { side = … }` from the raw
|
||||
/// switch is dedication, so the discriminating pin is
|
||||
/// `dired_descent_from_a_dedicated_panel_leaves_the_pin_alone` below.
|
||||
#[test]
|
||||
fn dired_directory_descent_stays_in_its_side_window() {
|
||||
let td = fixture_dir();
|
||||
|
|
|
|||
Loading…
Reference in New Issue