Run slash commands both on enter and on argument completion that requires it (#16283)

Release Notes:

- N/A
This commit is contained in:
Kirill Bulatov 2024-08-15 19:36:30 +03:00 committed by GitHub
parent 5a30e29848
commit c45adce2e3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 61 additions and 34 deletions

View File

@ -2081,7 +2081,7 @@ impl ContextEditor {
} }
editor.insert(&format!("/{name}"), cx); editor.insert(&format!("/{name}"), cx);
if command.requires_argument() { if command.accepts_arguments() {
editor.insert(" ", cx); editor.insert(" ", cx);
editor.show_completions(&ShowCompletions::default(), cx); editor.show_completions(&ShowCompletions::default(), cx);
} }
@ -2094,6 +2094,10 @@ impl ContextEditor {
} }
pub fn confirm_command(&mut self, _: &ConfirmCommand, cx: &mut ViewContext<Self>) { pub fn confirm_command(&mut self, _: &ConfirmCommand, cx: &mut ViewContext<Self>) {
if self.editor.read(cx).has_active_completions_menu() {
return;
}
let selections = self.editor.read(cx).selections.disjoint_anchors(); let selections = self.editor.read(cx).selections.disjoint_anchors();
let mut commands_by_range = HashMap::default(); let mut commands_by_range = HashMap::default();
let workspace = self.workspace.clone(); let workspace = self.workspace.clone();

View File

@ -97,20 +97,25 @@ impl SlashCommandCompletionProvider {
let command = commands.command(&mat.string)?; let command = commands.command(&mat.string)?;
let mut new_text = mat.string.clone(); let mut new_text = mat.string.clone();
let requires_argument = command.requires_argument(); let requires_argument = command.requires_argument();
if requires_argument { let accepts_arguments = command.accepts_arguments();
if requires_argument || accepts_arguments {
new_text.push(' '); new_text.push(' ');
} }
let confirm = editor.clone().zip(workspace.clone()).and_then( let confirm =
|(editor, workspace)| { editor
(!requires_argument).then(|| { .clone()
.zip(workspace.clone())
.map(|(editor, workspace)| {
let command_name = mat.string.clone(); let command_name = mat.string.clone();
let command_range = command_range.clone(); let command_range = command_range.clone();
let editor = editor.clone(); let editor = editor.clone();
let workspace = workspace.clone(); let workspace = workspace.clone();
Arc::new( Arc::new(
move |intent: CompletionIntent, cx: &mut WindowContext| { move |intent: CompletionIntent, cx: &mut WindowContext| {
if intent.is_complete() { if !requires_argument
&& (!accepts_arguments || intent.is_complete())
{
editor editor
.update(cx, |editor, cx| { .update(cx, |editor, cx| {
editor.run_command( editor.run_command(
@ -123,12 +128,13 @@ impl SlashCommandCompletionProvider {
); );
}) })
.ok(); .ok();
false
} else {
requires_argument || accepts_arguments
} }
}, },
) as Arc<_> ) as Arc<_>
}) });
},
);
Some(project::Completion { Some(project::Completion {
old_range: name_range.clone(), old_range: name_range.clone(),
documentation: Some(Documentation::SingleLine(command.description())), documentation: Some(Documentation::SingleLine(command.description())),
@ -136,7 +142,6 @@ impl SlashCommandCompletionProvider {
label: command.label(cx), label: command.label(cx),
server_id: LanguageServerId(0), server_id: LanguageServerId(0),
lsp_completion: Default::default(), lsp_completion: Default::default(),
show_new_completions_on_confirm: requires_argument,
confirm, confirm,
}) })
}) })
@ -175,7 +180,7 @@ impl SlashCommandCompletionProvider {
.await? .await?
.into_iter() .into_iter()
.map(|new_argument| { .map(|new_argument| {
let confirm = if new_argument.run_command { let confirm =
editor editor
.clone() .clone()
.zip(workspace.clone()) .zip(workspace.clone())
@ -192,7 +197,7 @@ impl SlashCommandCompletionProvider {
let command_range = command_range.clone(); let command_range = command_range.clone();
let command_name = command_name.clone(); let command_name = command_name.clone();
move |intent: CompletionIntent, cx: &mut WindowContext| { move |intent: CompletionIntent, cx: &mut WindowContext| {
if intent.is_complete() { if new_argument.run_command || intent.is_complete() {
editor editor
.update(cx, |editor, cx| { .update(cx, |editor, cx| {
editor.run_command( editor.run_command(
@ -205,13 +210,13 @@ impl SlashCommandCompletionProvider {
); );
}) })
.ok(); .ok();
false
} else {
!new_argument.run_command
} }
} }
}) as Arc<_> }) as Arc<_>
}) });
} else {
None
};
let mut new_text = new_argument.new_text.clone(); let mut new_text = new_argument.new_text.clone();
if !new_argument.run_command { if !new_argument.run_command {
@ -229,7 +234,6 @@ impl SlashCommandCompletionProvider {
documentation: None, documentation: None,
server_id: LanguageServerId(0), server_id: LanguageServerId(0),
lsp_completion: Default::default(), lsp_completion: Default::default(),
show_new_completions_on_confirm: !new_argument.run_command,
confirm, confirm,
} }
}) })

View File

@ -103,6 +103,10 @@ impl SlashCommand for DiagnosticsSlashCommand {
false false
} }
fn accepts_arguments(&self) -> bool {
true
}
fn complete_argument( fn complete_argument(
self: Arc<Self>, self: Arc<Self>,
arguments: &[String], arguments: &[String],

View File

@ -39,6 +39,10 @@ impl SlashCommand for TabSlashCommand {
false false
} }
fn accepts_arguments(&self) -> bool {
true
}
fn complete_argument( fn complete_argument(
self: Arc<Self>, self: Arc<Self>,
arguments: &[String], arguments: &[String],
@ -94,15 +98,16 @@ impl SlashCommand for TabSlashCommand {
}) })
}); });
let active_item_completion = active_item_path.as_deref().map(|active_item_path| { let active_item_completion = active_item_path
let path_string = active_item_path.to_string_lossy().to_string(); .as_deref()
ArgumentCompletion { .map(|active_item_path| active_item_path.to_string_lossy().to_string())
.filter(|path_string| !argument_set.contains(path_string))
.map(|path_string| ArgumentCompletion {
label: path_string.clone().into(), label: path_string.clone().into(),
new_text: path_string, new_text: path_string,
replace_previous_arguments: false, replace_previous_arguments: false,
run_command, run_command,
} });
});
Ok(active_item_completion Ok(active_item_completion
.into_iter() .into_iter()

View File

@ -40,6 +40,10 @@ impl SlashCommand for TerminalSlashCommand {
false false
} }
fn accepts_arguments(&self) -> bool {
true
}
fn complete_argument( fn complete_argument(
self: Arc<Self>, self: Arc<Self>,
_arguments: &[String], _arguments: &[String],

View File

@ -42,6 +42,9 @@ pub trait SlashCommand: 'static + Send + Sync {
cx: &mut WindowContext, cx: &mut WindowContext,
) -> Task<Result<Vec<ArgumentCompletion>>>; ) -> Task<Result<Vec<ArgumentCompletion>>>;
fn requires_argument(&self) -> bool; fn requires_argument(&self) -> bool;
fn accepts_arguments(&self) -> bool {
self.requires_argument()
}
fn run( fn run(
self: Arc<Self>, self: Arc<Self>,
arguments: &[String], arguments: &[String],

View File

@ -314,7 +314,6 @@ impl MessageEditor {
server_id: LanguageServerId(0), // TODO: Make this optional or something? server_id: LanguageServerId(0), // TODO: Make this optional or something?
lsp_completion: Default::default(), // TODO: Make this optional or something? lsp_completion: Default::default(), // TODO: Make this optional or something?
confirm: None, confirm: None,
show_new_completions_on_confirm: false,
} }
}) })
.collect() .collect()

View File

@ -4379,11 +4379,11 @@ impl Editor {
this.refresh_inline_completion(true, cx); this.refresh_inline_completion(true, cx);
}); });
if let Some(confirm) = completion.confirm.as_ref() { let show_new_completions_on_confirm = completion
(confirm)(intent, cx); .confirm
} .as_ref()
.map_or(false, |confirm| confirm(intent, cx));
if completion.show_new_completions_on_confirm { if show_new_completions_on_confirm {
self.show_completions(&ShowCompletions { trigger: None }, cx); self.show_completions(&ShowCompletions { trigger: None }, cx);
} }
@ -11926,6 +11926,12 @@ impl Editor {
let bounds = self.last_bounds?; let bounds = self.last_bounds?;
Some(element::gutter_bounds(bounds, self.gutter_dimensions)) Some(element::gutter_bounds(bounds, self.gutter_dimensions))
} }
pub fn has_active_completions_menu(&self) -> bool {
self.context_menu.read().as_ref().map_or(false, |menu| {
menu.visible() && matches!(menu, ContextMenu::Completions(_))
})
}
} }
fn hunks_for_selections( fn hunks_for_selections(
@ -12141,7 +12147,6 @@ fn snippet_completions(
..Default::default() ..Default::default()
}, },
confirm: None, confirm: None,
show_new_completions_on_confirm: false,
}) })
}) })
.collect() .collect()

View File

@ -450,9 +450,10 @@ pub struct Completion {
/// The raw completion provided by the language server. /// The raw completion provided by the language server.
pub lsp_completion: lsp::CompletionItem, pub lsp_completion: lsp::CompletionItem,
/// An optional callback to invoke when this completion is confirmed. /// An optional callback to invoke when this completion is confirmed.
pub confirm: Option<Arc<dyn Send + Sync + Fn(CompletionIntent, &mut WindowContext)>>, /// Returns, whether new completions should be retriggered after the current one.
/// If true, the editor will show a new completion menu after this completion is confirmed. /// If `true` is returned, the editor will show a new completion menu after this completion is confirmed.
pub show_new_completions_on_confirm: bool, /// if no confirmation is provided or `false` is returned, the completion will be committed.
pub confirm: Option<Arc<dyn Send + Sync + Fn(CompletionIntent, &mut WindowContext) -> bool>>,
} }
impl std::fmt::Debug for Completion { impl std::fmt::Debug for Completion {
@ -9128,7 +9129,6 @@ impl Project {
filter_range: Default::default(), filter_range: Default::default(),
}, },
confirm: None, confirm: None,
show_new_completions_on_confirm: false,
}, },
false, false,
cx, cx,
@ -10765,7 +10765,6 @@ async fn populate_labels_for_completions(
documentation, documentation,
lsp_completion, lsp_completion,
confirm: None, confirm: None,
show_new_completions_on_confirm: false,
}) })
} }
} }