mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-27 11:17:01 -06:00
Merge pull request #4060 from dotCooCoo/feat/unknown-command-suggestion
Commands: an unknown command id is answered with the nearest command id
This commit is contained in:
@@ -56,7 +56,13 @@ pub(super) fn action_batch(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
return Err(bad(C, "batches cannot nest"));
|
||||
}
|
||||
if find_command(id).is_none() {
|
||||
return Err(bad(C, format!("commands[{i}]: unknown command `{id}`")));
|
||||
return Err(bad(
|
||||
C,
|
||||
match super::super::params::nearest_command(id) {
|
||||
Some(near) => format!("commands[{i}]: unknown command `{id}`; did you mean `{near}`?"),
|
||||
None => format!("commands[{i}]: unknown command `{id}`"),
|
||||
},
|
||||
));
|
||||
}
|
||||
}
|
||||
let source = str_param(p, "source").unwrap_or("folder");
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
use serde_json::Value;
|
||||
|
||||
use super::{bad, find_command};
|
||||
use super::{bad, command_specs, find_command};
|
||||
use crate::Result;
|
||||
|
||||
/// What a params description says about the keys of the params object.
|
||||
@@ -208,8 +208,12 @@ fn distance(a: &str, b: &str) -> usize {
|
||||
|
||||
/// The key of `keys` a misspelt `key` most likely meant: the nearest one, when it is near.
|
||||
fn nearest<'a>(key: &str, keys: &[&'a str]) -> Option<&'a str> {
|
||||
let near = keys.iter().map(|k| (distance(key, k), *k)).min()?;
|
||||
(near.0 <= (key.chars().count() / 3).max(1)).then_some(near.1)
|
||||
let len = key.chars().count();
|
||||
let most = (len / 3).max(1);
|
||||
// A key whose length differs by more than `most` is more than `most` edits away and isn't
|
||||
// measured.
|
||||
let near = keys.iter().filter(|k| k.chars().count().abs_diff(len) <= most).map(|k| (distance(key, k), *k)).min()?;
|
||||
(near.0 <= most).then_some(near.1)
|
||||
}
|
||||
|
||||
/// `params` has only keys the description `doc` of command `id` names, or the parameter error
|
||||
@@ -480,6 +484,21 @@ pub fn check_params(id: &str, params: &Value) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// The command id a misspelled `id`, which names no command, most likely meant: the nearest one,
|
||||
/// when it is near (as [`check_keys`] matches a misspelled key).
|
||||
pub(crate) fn nearest_command(id: &str) -> Option<&'static str> {
|
||||
let ids: Vec<&'static str> = command_specs().iter().map(|c| c.id).collect();
|
||||
nearest(id, &ids)
|
||||
}
|
||||
|
||||
/// The error for `id`, which names no command: with the nearest command id, when one is near.
|
||||
pub(crate) fn unknown_command(id: &str) -> crate::EngineError {
|
||||
match nearest_command(id) {
|
||||
Some(near) => crate::EngineError::UnknownCommandNear(id.to_string(), near.to_string()),
|
||||
None => crate::EngineError::UnknownCommand(id.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::Session {
|
||||
/// [`check_params`], and [`check_effect_params`] for the effects `effect.setParams` edits in
|
||||
/// this session's document (not as a step of a `command.batch`: what it edits is only there
|
||||
|
||||
Reference in New Issue
Block a user