From d46dbb9708c8726de5e2676d709e50f66bba9b4b Mon Sep 17 00:00:00 2001 From: Syniis Date: Sat, 27 Jan 2024 13:41:29 +0100 Subject: [PATCH] Incremental item path autocomplete --- common/src/cmd.rs | 18 ++++++++++++++++-- voxygen/src/cmd.rs | 12 ++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/common/src/cmd.rs b/common/src/cmd.rs index fa18862587..02c4267727 100644 --- a/common/src/cmd.rs +++ b/common/src/cmd.rs @@ -537,7 +537,7 @@ impl ServerChatCommand { ), ServerChatCommand::GiveItem => cmd( vec![ - Enum("item", ITEM_SPECS.clone(), Required), + AssetPath("item", ITEM_SPECS.clone(), Required), Integer("num", 1, Optional), ], "Give yourself some items.\nFor an example or to auto complete use Tab.", @@ -647,7 +647,7 @@ impl ServerChatCommand { ), ServerChatCommand::MakeNpc => cmd( vec![ - Enum("entity_config", ENTITY_CONFIGS.clone(), Required), + AssetPath("entity_config", ENTITY_CONFIGS.clone(), Required), Integer("num", 1, Optional), ], "Spawn entity from config near you.\nFor an example or to auto complete use Tab.", @@ -1079,6 +1079,7 @@ impl ServerChatCommand { ArgumentSpec::Message(_) => "{/.*/}", ArgumentSpec::SubCommand => "{} {/.*/}", ArgumentSpec::Enum(_, _, _) => "{}", + ArgumentSpec::AssetPath(_, _, _) => "{}", ArgumentSpec::Boolean(_, _, _) => "{}", ArgumentSpec::Flag(_) => "{}", }) @@ -1146,6 +1147,11 @@ pub enum ArgumentSpec { /// * Predefined string completions /// * whether it's optional Enum(&'static str, Vec, Requirement), + /// The argument is an asset path. The associated values are + /// * label + /// * List of all asset paths as strings for completion + /// * whether it's optional + AssetPath(&'static str, Vec, Requirement), /// The argument is likely a boolean. The associated values are /// * label /// * suggested tab-completion @@ -1222,6 +1228,13 @@ impl ArgumentSpec { format!("[{}]", label) } }, + ArgumentSpec::AssetPath(label, _, req) => { + if &Requirement::Required == req { + format!("<{}>", label) + } else { + format!("[{}]", label) + } + }, ArgumentSpec::Boolean(label, _, req) => { if &Requirement::Required == req { format!("<{}>", label) @@ -1246,6 +1259,7 @@ impl ArgumentSpec { | ArgumentSpec::Command(r) | ArgumentSpec::Message(r) | ArgumentSpec::Enum(_, _, r) + | ArgumentSpec::AssetPath(_, _, r) | ArgumentSpec::Boolean(_, _, r) => *r, ArgumentSpec::Flag(_) => Requirement::Optional, ArgumentSpec::SubCommand => Requirement::Required, diff --git a/voxygen/src/cmd.rs b/voxygen/src/cmd.rs index 9dffba8372..01f40339a4 100644 --- a/voxygen/src/cmd.rs +++ b/voxygen/src/cmd.rs @@ -17,6 +17,7 @@ use common::{ uuid::Uuid, }; use common_net::sync::WorldSyncExt; +use itertools::Itertools; use levenshtein::levenshtein; use specs::{Join, WorldExt}; use strum::{EnumIter, IntoEnumIterator}; @@ -100,6 +101,7 @@ impl ClientChatCommand { ArgumentSpec::Message(_) => "{/.*/}", ArgumentSpec::SubCommand => "{} {/.*/}", ArgumentSpec::Enum(_, _, _) => "{}", + ArgumentSpec::AssetPath(_, _, _) => "{}", ArgumentSpec::Boolean(_, _, _) => "{}", ArgumentSpec::Flag(_) => "{}", }) @@ -591,6 +593,16 @@ impl TabComplete for ArgumentSpec { .filter(|string| string.starts_with(part)) .map(|c| c.to_string()) .collect(), + ArgumentSpec::AssetPath(_, paths, _) => { + let depth = part.split('.').count(); + paths + .iter() + .map(|path| path.as_str().split('.').take(depth).join(".")) + .dedup() + .filter(|string| string.starts_with(part)) + .map(|c| c.to_string()) + .collect() + }, ArgumentSpec::Boolean(_, part, _) => ["true", "false"] .iter() .filter(|string| string.starts_with(part))