1use std::path::PathBuf;
8use std::sync::{Arc, RwLock};
9
10use rust_i18n::t;
11
12use crate::input::command_registry::CommandRegistry;
13use crate::input::commands::Suggestion;
14use crate::input::keybindings::KeyContext;
15use crate::input::quick_open::{BufferInfo, QuickOpenContext};
16use crate::services::async_bridge::AsyncMessage;
17use crate::services::plugins::PluginManager;
18use crate::view::prompt::{Prompt, PromptType};
19
20use super::file_open;
21use super::Editor;
22
23impl Editor {
24 pub fn start_prompt(&mut self, message: String, prompt_type: PromptType) {
28 self.start_prompt_with_suggestions(message, prompt_type, Vec::new());
29 }
30
31 pub(super) fn start_search_prompt(
36 &mut self,
37 message: String,
38 prompt_type: PromptType,
39 use_selection_range: bool,
40 ) {
41 self.pending_search_range = None;
43
44 let selection_range = self.active_cursors().primary().selection_range();
45
46 let selected_text = if let Some(range) = selection_range.clone() {
47 let state = self.active_state_mut();
48 let text = state.get_text_range(range.start, range.end);
49 if !text.contains('\n') && !text.is_empty() {
50 Some(text)
51 } else {
52 None
53 }
54 } else {
55 None
56 };
57
58 if use_selection_range {
59 self.pending_search_range = selection_range;
60 }
61
62 let from_history = selected_text.is_none();
64 let default_text = selected_text.or_else(|| {
65 self.get_prompt_history("search")
66 .and_then(|h| h.last().map(|s| s.to_string()))
67 });
68
69 self.start_prompt(message, prompt_type);
71
72 if let Some(text) = default_text {
74 if let Some(ref mut prompt) = self.prompt {
75 prompt.set_input(text.clone());
76 prompt.selection_anchor = Some(0);
77 prompt.cursor_pos = text.len();
78 }
79 if from_history {
80 self.get_or_create_prompt_history("search").init_at_last();
81 }
82 self.update_search_highlights(&text);
83 }
84 }
85
86 pub fn start_prompt_with_suggestions(
88 &mut self,
89 message: String,
90 prompt_type: PromptType,
91 suggestions: Vec<Suggestion>,
92 ) {
93 self.on_editor_focus_lost();
95
96 match prompt_type {
99 PromptType::Search | PromptType::ReplaceSearch | PromptType::QueryReplaceSearch => {
100 self.clear_search_highlights();
101 }
102 _ => {}
103 }
104
105 let needs_suggestions = matches!(
107 prompt_type,
108 PromptType::OpenFile | PromptType::SwitchProject | PromptType::SaveFileAs
109 );
110
111 self.prompt = Some(Prompt::with_suggestions(message, prompt_type, suggestions));
112
113 if needs_suggestions {
115 self.update_prompt_suggestions();
116 }
117 }
118
119 pub fn start_prompt_with_initial_text(
121 &mut self,
122 message: String,
123 prompt_type: PromptType,
124 initial_text: String,
125 ) {
126 self.on_editor_focus_lost();
128
129 self.prompt = Some(Prompt::with_initial_text(
130 message,
131 prompt_type,
132 initial_text,
133 ));
134 }
135
136 pub fn start_quick_open(&mut self) {
138 self.on_editor_focus_lost();
140
141 self.status_message = None;
143
144 self.goto_line_preview = None;
147
148 let mut prompt = Prompt::with_suggestions(String::new(), PromptType::QuickOpen, vec![]);
150 prompt.input = ">".to_string();
151 prompt.cursor_pos = 1;
152 self.prompt = Some(prompt);
153
154 self.update_quick_open_suggestions(">");
156 }
157
158 pub(super) fn build_quick_open_context(&self) -> QuickOpenContext {
160 let open_buffers = self
161 .buffers
162 .iter()
163 .filter_map(|(buffer_id, state)| {
164 let path = state.buffer.file_path()?;
165 let name = path
166 .file_name()
167 .map(|n| n.to_string_lossy().to_string())
168 .unwrap_or_else(|| format!("Buffer {}", buffer_id.0));
169 Some(BufferInfo {
170 id: buffer_id.0,
171 path: path.display().to_string(),
172 name,
173 modified: state.buffer.is_modified(),
174 })
175 })
176 .collect();
177
178 let has_lsp_config = {
179 let language = self
180 .buffers
181 .get(&self.active_buffer())
182 .map(|s| s.language.as_str());
183 language
184 .and_then(|lang| self.lsp.as_ref().and_then(|lsp| lsp.get_config(lang)))
185 .is_some()
186 };
187
188 QuickOpenContext {
189 cwd: self.working_dir.display().to_string(),
190 open_buffers,
191 active_buffer_id: self.active_buffer().0,
192 active_buffer_path: self
193 .active_state()
194 .buffer
195 .file_path()
196 .map(|p| p.display().to_string()),
197 has_selection: self.has_active_selection(),
198 key_context: self.key_context.clone(),
199 custom_contexts: self.active_custom_contexts.clone(),
200 buffer_mode: self
201 .buffer_metadata
202 .get(&self.active_buffer())
203 .and_then(|m| m.virtual_mode())
204 .map(|s| s.to_string()),
205 has_lsp_config,
206 }
207 }
208
209 pub(super) fn update_quick_open_suggestions(&mut self, input: &str) {
211 let context = self.build_quick_open_context();
212 let suggestions = if let Some((provider, query)) =
213 self.quick_open_registry.get_provider_for_input(input)
214 {
215 provider.suggestions(query, &context)
216 } else {
217 vec![]
218 };
219
220 if let Some(prompt) = &mut self.prompt {
221 prompt.suggestions = suggestions;
222 prompt.selected_suggestion = if prompt.suggestions.is_empty() {
223 None
224 } else {
225 Some(0)
226 };
227 }
228
229 let target = Self::parse_quick_open_goto_line_target(input);
234 self.apply_goto_line_preview(target);
235 }
236
237 pub(super) fn parse_quick_open_goto_line_target(input: &str) -> Option<usize> {
239 input
240 .strip_prefix(':')
241 .and_then(|rest| rest.trim().parse::<usize>().ok())
242 .filter(|&n| n > 0)
243 }
244
245 pub(super) fn apply_goto_line_preview(&mut self, target_line: Option<usize>) {
252 if let Some(line) = target_line {
253 self.save_goto_line_preview_snapshot();
254 self.goto_line_col(line, None);
255 let new_position = self.active_cursors().primary().position;
258 if let Some(snap) = self.goto_line_preview.as_mut() {
259 snap.last_jump_position = new_position;
260 }
261 } else {
262 self.restore_goto_line_preview_snapshot();
263 }
264 }
265
266 pub(super) fn save_goto_line_preview_snapshot(&mut self) {
270 if self.goto_line_preview.is_some() {
271 return;
272 }
273
274 let buffer_id = self.active_buffer();
275 let split_id = self.split_manager.active_split();
276 let (cursor_id, position, anchor, sticky_column) = {
277 let cursors = self.active_cursors();
278 let primary = cursors.primary();
279 (
280 cursors.primary_id(),
281 primary.position,
282 primary.anchor,
283 primary.sticky_column,
284 )
285 };
286 let (viewport_top_byte, viewport_top_view_line_offset, viewport_left_column) = {
287 let vp = self.active_viewport();
288 (vp.top_byte, vp.top_view_line_offset, vp.left_column)
289 };
290
291 self.goto_line_preview = Some(super::GotoLinePreviewSnapshot {
292 buffer_id,
293 split_id,
294 cursor_id,
295 position,
296 anchor,
297 sticky_column,
298 viewport_top_byte,
299 viewport_top_view_line_offset,
300 viewport_left_column,
301 last_jump_position: position,
305 });
306 }
307
308 pub(super) fn restore_goto_line_preview_snapshot(&mut self) {
317 let Some(snap) = self.goto_line_preview.take() else {
318 return;
319 };
320
321 if self.active_buffer() != snap.buffer_id
324 || self.split_manager.active_split() != snap.split_id
325 {
326 return;
327 }
328
329 let cursors = self.active_cursors();
330 let current = cursors.primary();
331
332 if current.position != snap.last_jump_position {
336 return;
337 }
338 let event = crate::model::event::Event::MoveCursor {
339 cursor_id: snap.cursor_id,
340 old_position: current.position,
341 new_position: snap.position,
342 old_anchor: current.anchor,
343 new_anchor: snap.anchor,
344 old_sticky_column: current.sticky_column,
345 new_sticky_column: snap.sticky_column,
346 };
347
348 let state = self.buffers.get_mut(&snap.buffer_id).unwrap();
349 let view_state = self.split_view_states.get_mut(&snap.split_id).unwrap();
350 state.apply(&mut view_state.cursors, &event);
351
352 let vp = &mut view_state.viewport;
353 vp.top_byte = snap.viewport_top_byte;
354 vp.top_view_line_offset = snap.viewport_top_view_line_offset;
355 vp.left_column = snap.viewport_left_column;
356 vp.set_skip_ensure_visible();
359 }
360
361 pub(super) fn cancel_search_prompt_if_active(&mut self) {
364 if let Some(ref prompt) = self.prompt {
365 if matches!(
366 prompt.prompt_type,
367 PromptType::Search
368 | PromptType::ReplaceSearch
369 | PromptType::Replace { .. }
370 | PromptType::QueryReplaceSearch
371 | PromptType::QueryReplace { .. }
372 | PromptType::QueryReplaceConfirm
373 ) {
374 self.prompt = None;
375 self.interactive_replace_state = None;
377 let ns = self.search_namespace.clone();
379 let state = self.active_state_mut();
380 state.overlays.clear_namespace(&ns, &mut state.marker_list);
381 }
382 }
383 }
384
385 pub(super) fn prefill_open_file_prompt(&mut self) {
387 if let Some(prompt) = self.prompt.as_mut() {
391 if prompt.prompt_type == PromptType::OpenFile {
392 prompt.input.clear();
393 prompt.cursor_pos = 0;
394 prompt.selection_anchor = None;
395 }
396 }
397 }
398
399 pub(super) fn init_file_open_state(&mut self) {
405 let buffer_id = self.active_buffer();
407
408 let initial_dir = if self.is_terminal_buffer(buffer_id) {
411 self.get_terminal_id(buffer_id)
412 .and_then(|tid| self.terminal_manager.get(tid))
413 .and_then(|handle| handle.cwd())
414 .unwrap_or_else(|| self.working_dir.clone())
415 } else {
416 self.active_state()
417 .buffer
418 .file_path()
419 .and_then(|path| path.parent())
420 .map(|p| p.to_path_buf())
421 .unwrap_or_else(|| self.working_dir.clone())
422 };
423
424 let show_hidden = self.config.file_browser.show_hidden;
426 self.file_open_state = Some(file_open::FileOpenState::new(
427 initial_dir.clone(),
428 show_hidden,
429 self.authority.filesystem.clone(),
430 ));
431
432 self.load_file_open_directory(initial_dir);
434 self.load_file_open_shortcuts_async();
435 }
436
437 pub(super) fn init_folder_open_state(&mut self) {
442 let initial_dir = self.working_dir.clone();
444
445 let show_hidden = self.config.file_browser.show_hidden;
447 self.file_open_state = Some(file_open::FileOpenState::new(
448 initial_dir.clone(),
449 show_hidden,
450 self.authority.filesystem.clone(),
451 ));
452
453 self.load_file_open_directory(initial_dir);
455 self.load_file_open_shortcuts_async();
456 }
457
458 pub fn change_working_dir(&mut self, new_path: PathBuf) {
468 let new_path = new_path.canonicalize().unwrap_or(new_path);
470
471 self.request_restart(new_path);
474 }
475
476 pub(super) fn load_file_open_directory(&mut self, path: PathBuf) {
478 if let Some(state) = &mut self.file_open_state {
480 state.current_dir = path.clone();
481 state.loading = true;
482 state.error = None;
483 state.update_shortcuts();
484 }
485
486 if let Some(ref runtime) = self.tokio_runtime {
488 let fs_manager = self.fs_manager.clone();
489 let sender = self.async_bridge.as_ref().map(|b| b.sender());
490
491 runtime.spawn(async move {
492 let result = fs_manager.list_dir_with_metadata(path).await;
493 if let Some(sender) = sender {
494 #[allow(clippy::let_underscore_must_use)]
496 let _ = sender.send(AsyncMessage::FileOpenDirectoryLoaded(result));
497 }
498 });
499 } else {
500 if let Some(state) = &mut self.file_open_state {
502 state.set_error("Async runtime not available".to_string());
503 }
504 }
505 }
506
507 pub(super) fn handle_file_open_directory_loaded(
509 &mut self,
510 result: std::io::Result<Vec<crate::services::fs::DirEntry>>,
511 ) {
512 match result {
513 Ok(entries) => {
514 if let Some(state) = &mut self.file_open_state {
515 state.set_entries(entries);
516 }
517 let filter = self
519 .prompt
520 .as_ref()
521 .map(|p| p.input.clone())
522 .unwrap_or_default();
523 if !filter.is_empty() {
524 if let Some(state) = &mut self.file_open_state {
525 state.apply_filter(&filter);
526 }
527 }
528 }
529 Err(e) => {
530 if let Some(state) = &mut self.file_open_state {
531 state.set_error(e.to_string());
532 }
533 }
534 }
535 }
536
537 pub(super) fn load_file_open_shortcuts_async(&mut self) {
541 if let Some(ref runtime) = self.tokio_runtime {
542 let filesystem = self.authority.filesystem.clone();
543 let sender = self.async_bridge.as_ref().map(|b| b.sender());
544
545 runtime.spawn(async move {
546 let shortcuts = tokio::task::spawn_blocking(move || {
548 file_open::FileOpenState::build_shortcuts_async(&*filesystem)
549 })
550 .await
551 .unwrap_or_default();
552
553 if let Some(sender) = sender {
554 #[allow(clippy::let_underscore_must_use)]
556 let _ = sender.send(AsyncMessage::FileOpenShortcutsLoaded(shortcuts));
557 }
558 });
559 }
560 }
561
562 pub(super) fn handle_file_open_shortcuts_loaded(
564 &mut self,
565 shortcuts: Vec<file_open::NavigationShortcut>,
566 ) {
567 if let Some(state) = &mut self.file_open_state {
568 state.merge_async_shortcuts(shortcuts);
569 }
570 }
571
572 pub fn cancel_prompt(&mut self) {
574 let theme_to_restore = if let Some(ref prompt) = self.prompt {
576 if let PromptType::SelectTheme { original_theme } = &prompt.prompt_type {
577 Some(original_theme.clone())
578 } else {
579 None
580 }
581 } else {
582 None
583 };
584
585 if let Some(ref prompt) = self.prompt {
587 if let Some(key) = Self::prompt_type_to_history_key(&prompt.prompt_type) {
589 if let Some(history) = self.prompt_histories.get_mut(&key) {
590 history.reset_navigation();
591 }
592 }
593 match &prompt.prompt_type {
594 PromptType::Search | PromptType::ReplaceSearch | PromptType::QueryReplaceSearch => {
595 self.clear_search_highlights();
596 }
597 PromptType::Plugin { custom_type } => {
598 use crate::services::plugins::hooks::HookArgs;
600 self.plugin_manager.run_hook(
601 "prompt_cancelled",
602 HookArgs::PromptCancelled {
603 prompt_type: custom_type.clone(),
604 input: prompt.input.clone(),
605 },
606 );
607 }
608 PromptType::LspRename { overlay_handle, .. } => {
609 let remove_overlay_event = crate::model::event::Event::RemoveOverlay {
611 handle: overlay_handle.clone(),
612 };
613 self.apply_event_to_active_buffer(&remove_overlay_event);
614 }
615 PromptType::OpenFile | PromptType::SwitchProject | PromptType::SaveFileAs => {
616 self.file_open_state = None;
618 self.file_browser_layout = None;
619 }
620 PromptType::AsyncPrompt => {
621 if let Some(callback_id) = self.pending_async_prompt_callback.take() {
623 self.plugin_manager
624 .resolve_callback(callback_id, "null".to_string());
625 }
626 }
627 PromptType::QuickOpen => {
628 if let Some((provider, _)) = self.quick_open_registry.get_provider_for_input("")
630 {
631 if let Some(fp) = provider
632 .as_any()
633 .downcast_ref::<crate::input::quick_open::providers::FileProvider>(
634 ) {
635 fp.cancel_loading();
636 }
637 }
638 self.restore_goto_line_preview_snapshot();
641 }
642 PromptType::GotoLine => {
643 self.restore_goto_line_preview_snapshot();
646 }
647 _ => {}
648 }
649 }
650
651 self.prompt = None;
652 self.pending_search_range = None;
653 self.status_message = Some(t!("search.cancelled").to_string());
654
655 if let Some(original_theme) = theme_to_restore {
657 self.preview_theme(&original_theme);
658 }
659 }
660
661 pub fn handle_prompt_scroll(&mut self, delta: i32) -> bool {
664 if let Some(ref mut prompt) = self.prompt {
665 if prompt.suggestions.is_empty() {
666 return false;
667 }
668
669 let current = prompt.selected_suggestion.unwrap_or(0);
670 let len = prompt.suggestions.len();
671
672 let new_selected = if delta < 0 {
675 current.saturating_sub((-delta) as usize)
677 } else {
678 (current + delta as usize).min(len.saturating_sub(1))
680 };
681
682 prompt.selected_suggestion = Some(new_selected);
683
684 if !matches!(prompt.prompt_type, PromptType::Plugin { .. }) {
686 if let Some(suggestion) = prompt.suggestions.get(new_selected) {
687 prompt.input = suggestion.get_value().to_string();
688 prompt.cursor_pos = prompt.input.len();
689 }
690 }
691
692 return true;
693 }
694 false
695 }
696
697 pub fn confirm_prompt(&mut self) -> Option<(String, PromptType, Option<usize>)> {
702 if let Some(prompt) = self.prompt.take() {
703 let selected_index = prompt.selected_suggestion;
704 let mut final_input = if prompt.sync_input_on_navigate {
706 prompt.input.clone()
709 } else if matches!(
710 prompt.prompt_type,
711 PromptType::OpenFile
712 | PromptType::SwitchProject
713 | PromptType::SaveFileAs
714 | PromptType::StopLspServer
715 | PromptType::RestartLspServer
716 | PromptType::SelectTheme { .. }
717 | PromptType::SelectLocale
718 | PromptType::SwitchToTab
719 | PromptType::SetLanguage
720 | PromptType::SetEncoding
721 | PromptType::SetLineEnding
722 | PromptType::Plugin { .. }
723 ) {
724 if let Some(selected_idx) = prompt.selected_suggestion {
726 if let Some(suggestion) = prompt.suggestions.get(selected_idx) {
727 if suggestion.disabled {
729 self.set_status_message(
730 t!(
731 "error.command_not_available",
732 command = suggestion.text.clone()
733 )
734 .to_string(),
735 );
736 return None;
737 }
738 suggestion.get_value().to_string()
740 } else {
741 prompt.input.clone()
742 }
743 } else {
744 prompt.input.clone()
745 }
746 } else {
747 prompt.input.clone()
748 };
749
750 if matches!(
752 prompt.prompt_type,
753 PromptType::StopLspServer | PromptType::RestartLspServer
754 ) {
755 let is_valid = prompt
756 .suggestions
757 .iter()
758 .any(|s| s.text == final_input || s.get_value() == final_input);
759 if !is_valid {
760 self.prompt = Some(prompt);
762 self.set_status_message(
763 t!("error.no_lsp_match", input = final_input.clone()).to_string(),
764 );
765 return None;
766 }
767 }
768
769 if matches!(prompt.prompt_type, PromptType::RemoveRuler) {
773 if prompt.input.is_empty() {
774 if let Some(selected_idx) = prompt.selected_suggestion {
776 if let Some(suggestion) = prompt.suggestions.get(selected_idx) {
777 final_input = suggestion.get_value().to_string();
778 }
779 } else {
780 self.prompt = Some(prompt);
781 return None;
782 }
783 } else {
784 let typed = prompt.input.trim().to_string();
786 let matched = prompt.suggestions.iter().find(|s| s.get_value() == typed);
787 if let Some(suggestion) = matched {
788 final_input = suggestion.get_value().to_string();
789 } else {
790 self.prompt = Some(prompt);
792 return None;
793 }
794 }
795 }
796
797 if let Some(key) = Self::prompt_type_to_history_key(&prompt.prompt_type) {
799 let history = self.get_or_create_prompt_history(&key);
800 history.push(final_input.clone());
801 history.reset_navigation();
802 }
803
804 Some((final_input, prompt.prompt_type, selected_index))
805 } else {
806 None
807 }
808 }
809
810 pub fn is_prompting(&self) -> bool {
812 self.prompt.is_some()
813 }
814
815 pub(super) fn get_or_create_prompt_history(
817 &mut self,
818 key: &str,
819 ) -> &mut crate::input::input_history::InputHistory {
820 self.prompt_histories.entry(key.to_string()).or_default()
821 }
822
823 pub(super) fn get_prompt_history(
825 &self,
826 key: &str,
827 ) -> Option<&crate::input::input_history::InputHistory> {
828 self.prompt_histories.get(key)
829 }
830
831 pub(super) fn prompt_type_to_history_key(
833 prompt_type: &crate::view::prompt::PromptType,
834 ) -> Option<String> {
835 use crate::view::prompt::PromptType;
836 match prompt_type {
837 PromptType::Search | PromptType::ReplaceSearch | PromptType::QueryReplaceSearch => {
838 Some("search".to_string())
839 }
840 PromptType::Replace { .. } | PromptType::QueryReplace { .. } => {
841 Some("replace".to_string())
842 }
843 PromptType::GotoLine => Some("goto_line".to_string()),
844 PromptType::Plugin { custom_type } => Some(format!("plugin:{}", custom_type)),
845 _ => None,
846 }
847 }
848
849 pub fn editor_mode(&self) -> Option<String> {
852 self.editor_mode.clone()
853 }
854
855 pub fn command_registry(&self) -> &Arc<RwLock<CommandRegistry>> {
857 &self.command_registry
858 }
859
860 pub fn plugin_manager(&self) -> &PluginManager {
862 &self.plugin_manager
863 }
864
865 pub fn plugin_manager_mut(&mut self) -> &mut PluginManager {
867 &mut self.plugin_manager
868 }
869
870 pub fn file_explorer_is_focused(&self) -> bool {
872 self.key_context == KeyContext::FileExplorer
873 }
874
875 pub fn prompt_input(&self) -> Option<&str> {
877 self.prompt.as_ref().map(|p| p.input.as_str())
878 }
879
880 pub fn has_active_selection(&self) -> bool {
882 self.active_cursors().primary().selection_range().is_some()
883 }
884
885 pub fn prompt_mut(&mut self) -> Option<&mut Prompt> {
887 self.prompt.as_mut()
888 }
889
890 pub fn set_status_message(&mut self, message: String) {
892 tracing::info!(target: "status", "{}", message);
893 self.plugin_status_message = None;
894 self.status_message = Some(message);
895 }
896
897 pub fn get_status_message(&self) -> Option<&String> {
899 self.plugin_status_message
900 .as_ref()
901 .or(self.status_message.as_ref())
902 }
903
904 pub fn get_plugin_errors(&self) -> &[String] {
907 &self.plugin_errors
908 }
909
910 pub fn clear_plugin_errors(&mut self) {
912 self.plugin_errors.clear();
913 }
914
915 pub fn update_prompt_suggestions(&mut self) {
917 let (prompt_type, input) = if let Some(prompt) = &self.prompt {
919 (prompt.prompt_type.clone(), prompt.input.clone())
920 } else {
921 return;
922 };
923
924 match prompt_type {
925 PromptType::QuickOpen => {
926 self.update_quick_open_suggestions(&input);
928 }
929 PromptType::Search | PromptType::ReplaceSearch | PromptType::QueryReplaceSearch => {
930 self.update_search_highlights(&input);
932 if let Some(history) = self.prompt_histories.get_mut("search") {
934 history.reset_navigation();
935 }
936 }
937 PromptType::Replace { .. } | PromptType::QueryReplace { .. } => {
938 if let Some(history) = self.prompt_histories.get_mut("replace") {
940 history.reset_navigation();
941 }
942 }
943 PromptType::GotoLine => {
944 if let Some(history) = self.prompt_histories.get_mut("goto_line") {
946 history.reset_navigation();
947 }
948 let target = input.trim().parse::<usize>().ok().filter(|&n| n > 0);
952 self.apply_goto_line_preview(target);
953 }
954 PromptType::OpenFile | PromptType::SwitchProject | PromptType::SaveFileAs => {
955 self.update_file_open_filter();
957 }
958 PromptType::Plugin { custom_type } => {
959 let key = format!("plugin:{}", custom_type);
961 if let Some(history) = self.prompt_histories.get_mut(&key) {
962 history.reset_navigation();
963 }
964 use crate::services::plugins::hooks::HookArgs;
966 self.plugin_manager.run_hook(
967 "prompt_changed",
968 HookArgs::PromptChanged {
969 prompt_type: custom_type,
970 input,
971 },
972 );
973 if let Some(prompt) = &mut self.prompt {
978 prompt.filter_suggestions(false);
979 }
980 }
981 PromptType::SwitchToTab
982 | PromptType::SelectTheme { .. }
983 | PromptType::StopLspServer
984 | PromptType::RestartLspServer
985 | PromptType::SetLanguage
986 | PromptType::SetEncoding
987 | PromptType::SetLineEnding => {
988 if let Some(prompt) = &mut self.prompt {
989 prompt.filter_suggestions(false);
990 }
991 }
992 PromptType::SelectLocale => {
993 if let Some(prompt) = &mut self.prompt {
995 prompt.filter_suggestions(true);
996 }
997 }
998 _ => {}
999 }
1000 }
1001}