feat: add quick searchable layer command

This commit is contained in:
gianlucafiore committed 2026-10-08 23:17:03 -03:00
1 parent d0e4f4097d
commit a6307b3666
15 files changed
+637 -25

No files matched your search

+22 -3
View File
@@ -303,9 +303,22 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
// Live incremental search for INSERT/MINSERT (see CommandInput)
let live = self.command_line.input.clone();
let i = self.active_tab;
let (should_update, opts, prompt) = if let Some(cmd) = self.tabs[i].active_cmd.as_mut() {
if cmd.on_live_input(&live) { (true, cmd.options(), cmd.prompt()) } else { (false, Vec::new(), String::new()) }
} else { (false, Vec::new(), String::new()) };
let (should_update, opts, prompt, suggestions) =
if let Some(cmd) = self.tabs[i].active_cmd.as_mut() {
let changed = cmd.on_live_input(&live);
let suggestions = cmd.text_suggestions(&live);
if changed {
(true, cmd.options(), cmd.prompt(), suggestions)
} else {
(false, Vec::new(), String::new(), suggestions)
}
} else {
(false, Vec::new(), String::new(), Vec::new())
};
self.command_line
.set_contextual_suggestions(suggestions);
if should_update {
self.command_line.set_step_options(opts);
if let Some(last) = self.command_line.history.last_mut() { if last.pinned { last.text = prompt; } }
@@ -727,6 +740,12 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
self.command_line.autocomplete_cursor = None;
return self.dispatch_command(&command);
}
} else if self.command_line.has_contextual_suggestions() {
// During an active command Enter accepts the highlighted
// contextual value instead of the user's partial search.
if let Some(value) = self.command_line.selected_suggestion() {
self.command_line.input = value;
}
}
let i = self.active_tab;
// A whole multi-token command line (`UCS Z 90`, `LINE 0,0
+1
View File
@@ -258,6 +258,7 @@ impl OpenCADStudio {
}
},
Message::DynTabNext => Some(self.on_context_menu_navigate(ContextMenuNav::Down)),
Message::DynTabPrev => Some(self.on_context_menu_navigate(ContextMenuNav::Up)),
Message::CommandFinalize | Message::CommandSpace => {
if self.command_line.input.trim().is_empty() {
Some(self.on_context_menu_navigate(ContextMenuNav::Enter))
+3
View File
@@ -1359,6 +1359,9 @@ impl OpenCADStudio {
self.shortcut_bindings
.entry("F5".to_string())
.or_insert_with(|| "ISOPLANE".to_string());
self.shortcut_bindings
.entry("SHIFT+TAB".to_string())
.or_insert_with(|| "DYNTABPREV".to_string());
}
/// Write the config only when it changed since the last write, so a toggle
+41 -10
View File
@@ -24,6 +24,7 @@ fn is_modal_blocked_key_msg(msg: &Message) -> bool {
| Message::CommandLineArrowProbe { .. }
| Message::CommandLineArrowResolved { .. }
| Message::DynTabNext
| Message::DynTabPrev
| Message::MTextCaretMove(_)
| Message::DeleteSelected
| Message::ToggleSnapEnabled
@@ -2156,16 +2157,22 @@ impl OpenCADStudio {
let i = self.active_tab;
// Capture prompt/options while holding cmd borrow, then release before
// borrowing command_line to satisfy borrow checker.
let (should_update, opts, prompt) =
let (should_update, opts, prompt, suggestions) =
if let Some(cmd) = self.tabs[i].active_cmd.as_mut() {
if cmd.on_live_input(&live_input) {
(true, cmd.options(), cmd.prompt())
let changed = cmd.on_live_input(&live_input);
let suggestions = cmd.text_suggestions(&live_input);
if changed {
(true, cmd.options(), cmd.prompt(), suggestions)
} else {
(false, Vec::new(), String::new())
(false, Vec::new(), String::new(), suggestions)
}
} else {
(false, Vec::new(), String::new())
(false, Vec::new(), String::new(), Vec::new())
};
self.command_line
.set_contextual_suggestions(suggestions);
if should_update {
self.command_line.set_step_options(opts);
// Update pinned prompt text live without pushing new history entry
@@ -2194,6 +2201,12 @@ impl OpenCADStudio {
}
Message::DynTabNext => {
if self.command_line.has_contextual_suggestions()
&& self.command_line.autocomplete_next()
{
return Task::none();
}
let i = self.active_tab;
let n = self.tabs[i].dyn_fields.len();
if n > 0 {
@@ -2205,6 +2218,13 @@ impl OpenCADStudio {
self.focus_cmd_input()
}
Message::DynTabPrev => {
if self.command_line.has_contextual_suggestions() {
self.command_line.autocomplete_prev();
}
self.focus_cmd_input()
}
Message::SplitModelViewport(horizontal) => {
let i = self.active_tab;
self.tabs[i].scene.split_active_pane(horizontal);
@@ -2241,7 +2261,8 @@ impl OpenCADStudio {
}
let i = self.active_tab;
if !self.command_line.history_navigation_active()
&& self.tabs[i].active_cmd.is_none()
&& (self.tabs[i].active_cmd.is_none()
|| self.command_line.has_contextual_suggestions())
&& self.command_line.autocomplete_prev()
{
return Task::none();
@@ -2267,7 +2288,8 @@ impl OpenCADStudio {
}
let i = self.active_tab;
if !self.command_line.history_navigation_active()
&& self.tabs[i].active_cmd.is_none()
&& (self.tabs[i].active_cmd.is_none()
|| self.command_line.has_contextual_suggestions())
&& self.command_line.autocomplete_next()
{
return Task::none();
@@ -2468,11 +2490,20 @@ impl OpenCADStudio {
}
}
Message::CommandSuggestionPick(cmd) => {
Message::CommandSuggestionPick(value) => {
self.command_line.close_history();
if self.tabs[self.active_tab].active_cmd.is_some()
&& self.command_line.has_contextual_suggestions()
{
self.command_line.input = value;
self.command_line.autocomplete_cursor = None;
return self.on_command_submit();
}
self.command_line.input.clear();
self.command_line.autocomplete_cursor = None;
self.command_line.close_history();
self.dispatch_command(&cmd)
self.dispatch_command(&value)
}
Message::CommandOptionPick(kw) => {