Add option for code context menu items to have dynamic width (#37404)
Follow up to https://github.com/zed-industries/zed/pull/30598 This PR introduces the `display_options` field in the `CompletionResponse`, allowing a code context menu width to be dynamically dictated based on its larger item. This will allow us to have the @-mentions and slash commands completion menus in the agent panel not be bigger than it needs to be. It may also be relevant/useful in the future for other use cases. For now, we set all instances of code context menus to use a fixed width, as defined in the PR linked above, which means this PR shouldn't cause any visual change. Release Notes: - N/A Co-authored-by: Michael Sloan <mgsloan+github@gmail.com>
This commit is contained in:
co-authored by
Michael Sloan
parent
4b96ad3fba
commit
946efb03df
@@ -11,9 +11,9 @@ use language::{Buffer, LanguageName, LanguageRegistry};
|
||||
use markdown::{Markdown, MarkdownElement};
|
||||
use multi_buffer::{Anchor, ExcerptId};
|
||||
use ordered_float::OrderedFloat;
|
||||
use project::CompletionSource;
|
||||
use project::lsp_store::CompletionDocumentation;
|
||||
use project::{CodeAction, Completion, TaskSourceKind};
|
||||
use project::{CompletionDisplayOptions, CompletionSource};
|
||||
use task::DebugScenario;
|
||||
use task::TaskContext;
|
||||
|
||||
@@ -232,6 +232,7 @@ pub struct CompletionsMenu {
|
||||
markdown_cache: Rc<RefCell<VecDeque<(MarkdownCacheKey, Entity<Markdown>)>>>,
|
||||
language_registry: Option<Arc<LanguageRegistry>>,
|
||||
language: Option<LanguageName>,
|
||||
display_options: CompletionDisplayOptions,
|
||||
snippet_sort_order: SnippetSortOrder,
|
||||
}
|
||||
|
||||
@@ -271,6 +272,7 @@ impl CompletionsMenu {
|
||||
is_incomplete: bool,
|
||||
buffer: Entity<Buffer>,
|
||||
completions: Box<[Completion]>,
|
||||
display_options: CompletionDisplayOptions,
|
||||
snippet_sort_order: SnippetSortOrder,
|
||||
language_registry: Option<Arc<LanguageRegistry>>,
|
||||
language: Option<LanguageName>,
|
||||
@@ -304,6 +306,7 @@ impl CompletionsMenu {
|
||||
markdown_cache: RefCell::new(VecDeque::new()).into(),
|
||||
language_registry,
|
||||
language,
|
||||
display_options,
|
||||
snippet_sort_order,
|
||||
};
|
||||
|
||||
@@ -375,6 +378,7 @@ impl CompletionsMenu {
|
||||
markdown_cache: RefCell::new(VecDeque::new()).into(),
|
||||
language_registry: None,
|
||||
language: None,
|
||||
display_options: CompletionDisplayOptions::default(),
|
||||
snippet_sort_order,
|
||||
}
|
||||
}
|
||||
@@ -737,6 +741,33 @@ impl CompletionsMenu {
|
||||
cx: &mut Context<Editor>,
|
||||
) -> AnyElement {
|
||||
let show_completion_documentation = self.show_completion_documentation;
|
||||
let widest_completion_ix = if self.display_options.dynamic_width {
|
||||
let completions = self.completions.borrow();
|
||||
let widest_completion_ix = self
|
||||
.entries
|
||||
.borrow()
|
||||
.iter()
|
||||
.enumerate()
|
||||
.max_by_key(|(_, mat)| {
|
||||
let completion = &completions[mat.candidate_id];
|
||||
let documentation = &completion.documentation;
|
||||
|
||||
let mut len = completion.label.text.chars().count();
|
||||
if let Some(CompletionDocumentation::SingleLine(text)) = documentation {
|
||||
if show_completion_documentation {
|
||||
len += text.chars().count();
|
||||
}
|
||||
}
|
||||
|
||||
len
|
||||
})
|
||||
.map(|(ix, _)| ix);
|
||||
drop(completions);
|
||||
widest_completion_ix
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let selected_item = self.selected_item;
|
||||
let completions = self.completions.clone();
|
||||
let entries = self.entries.clone();
|
||||
@@ -863,7 +894,13 @@ impl CompletionsMenu {
|
||||
.max_h(max_height_in_lines as f32 * window.line_height())
|
||||
.track_scroll(self.scroll_handle.clone())
|
||||
.with_sizing_behavior(ListSizingBehavior::Infer)
|
||||
.w(rems(34.));
|
||||
.map(|this| {
|
||||
if self.display_options.dynamic_width {
|
||||
this.with_width_from_item(widest_completion_ix)
|
||||
} else {
|
||||
this.w(rems(34.))
|
||||
}
|
||||
});
|
||||
|
||||
Popover::new().child(list).into_any_element()
|
||||
}
|
||||
|
||||
@@ -147,21 +147,22 @@ use multi_buffer::{
|
||||
use parking_lot::Mutex;
|
||||
use persistence::DB;
|
||||
use project::{
|
||||
BreakpointWithPosition, CodeAction, Completion, CompletionIntent, CompletionResponse,
|
||||
CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint, Location, LocationLink,
|
||||
PrepareRenameResponse, Project, ProjectItem, ProjectPath, ProjectTransaction, TaskSourceKind,
|
||||
debugger::breakpoint_store::Breakpoint,
|
||||
BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
|
||||
CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint,
|
||||
Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectPath,
|
||||
ProjectTransaction, TaskSourceKind,
|
||||
debugger::{
|
||||
breakpoint_store::{
|
||||
BreakpointEditAction, BreakpointSessionState, BreakpointState, BreakpointStore,
|
||||
BreakpointStoreEvent,
|
||||
Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
|
||||
BreakpointStore, BreakpointStoreEvent,
|
||||
},
|
||||
session::{Session, SessionEvent},
|
||||
},
|
||||
git_store::{GitStoreEvent, RepositoryEvent},
|
||||
lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
|
||||
project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter},
|
||||
project_settings::{GitGutterSetting, ProjectSettings},
|
||||
project_settings::{
|
||||
DiagnosticSeverity, GitGutterSetting, GoToDiagnosticSeverityFilter, ProjectSettings,
|
||||
},
|
||||
};
|
||||
use rand::{seq::SliceRandom, thread_rng};
|
||||
use rpc::{ErrorCode, ErrorExt, proto::PeerId};
|
||||
@@ -5635,17 +5636,25 @@ impl Editor {
|
||||
// that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
|
||||
let mut completions = Vec::new();
|
||||
let mut is_incomplete = false;
|
||||
let mut display_options: Option<CompletionDisplayOptions> = None;
|
||||
if let Some(provider_responses) = provider_responses.await.log_err()
|
||||
&& !provider_responses.is_empty()
|
||||
{
|
||||
for response in provider_responses {
|
||||
completions.extend(response.completions);
|
||||
is_incomplete = is_incomplete || response.is_incomplete;
|
||||
match display_options.as_mut() {
|
||||
None => {
|
||||
display_options = Some(response.display_options);
|
||||
}
|
||||
Some(options) => options.merge(&response.display_options),
|
||||
}
|
||||
}
|
||||
if completion_settings.words == WordsCompletionMode::Fallback {
|
||||
words = Task::ready(BTreeMap::default());
|
||||
}
|
||||
}
|
||||
let display_options = display_options.unwrap_or_default();
|
||||
|
||||
let mut words = words.await;
|
||||
if let Some(word_to_exclude) = &word_to_exclude {
|
||||
@@ -5687,6 +5696,7 @@ impl Editor {
|
||||
is_incomplete,
|
||||
buffer.clone(),
|
||||
completions.into(),
|
||||
display_options,
|
||||
snippet_sort_order,
|
||||
languages,
|
||||
language,
|
||||
@@ -22260,6 +22270,7 @@ fn snippet_completions(
|
||||
if scopes.is_empty() {
|
||||
return Task::ready(Ok(CompletionResponse {
|
||||
completions: vec![],
|
||||
display_options: CompletionDisplayOptions::default(),
|
||||
is_incomplete: false,
|
||||
}));
|
||||
}
|
||||
@@ -22284,6 +22295,7 @@ fn snippet_completions(
|
||||
if last_word.is_empty() {
|
||||
return Ok(CompletionResponse {
|
||||
completions: vec![],
|
||||
display_options: CompletionDisplayOptions::default(),
|
||||
is_incomplete: true,
|
||||
});
|
||||
}
|
||||
@@ -22405,6 +22417,7 @@ fn snippet_completions(
|
||||
|
||||
Ok(CompletionResponse {
|
||||
completions,
|
||||
display_options: CompletionDisplayOptions::default(),
|
||||
is_incomplete,
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user