mirror of
https://github.com/zed-industries/zed.git
synced 2026-07-09 16:00:35 +00:00
Add text icons for completion items (#56396)
Part of https://github.com/zed-industries/zed/issues/4943 Based on the last discussion, Zed does not want to have icons there, so technically closes the issue? Helix: <img width="735" height="266" alt="Screenshot 2026-05-11 at 12 47 36" src="https://github.com/user-attachments/assets/760e844b-6aad-4a42-ad39-28ea91fe4a90" /> VSCode: <img width="964" height="414" alt="Screenshot 2026-05-11 at 12 49 00" src="https://github.com/user-attachments/assets/37e383cd-e5aa-49a7-9a07-8af00ad07f27" /> <img width="970" height="453" alt="Screenshot 2026-05-11 at 12 49 04" src="https://github.com/user-attachments/assets/4787d12e-b897-4dfd-a325-30fb45bc6001" /> RustRover: <img width="1182" height="429" alt="Screenshot 2026-05-11 at 12 49 34" src="https://github.com/user-attachments/assets/5876ce8b-e33d-4f4b-b7a4-44a25048f9f2" /> <img width="1050" height="424" alt="Screenshot 2026-05-11 at 12 49 42" src="https://github.com/user-attachments/assets/4fbcb44b-00b7-4283-9423-556cc335c9b2" /> Zed: <img width="1191" height="457" alt="Screenshot 2026-05-11 at 12 54 17" src="https://github.com/user-attachments/assets/ff953146-c621-4c17-97f6-2f8504fef4cc" /> <img width="1149" height="446" alt="Screenshot 2026-05-11 at 12 54 29" src="https://github.com/user-attachments/assets/33112b67-2ed1-4bd2-92ea-762744336074" /> (tooltip on hover) <img width="797" height="223" alt="image" src="https://github.com/user-attachments/assets/9c06054c-51f0-4f9b-b740-a4076d2591c6" /> Disabled by default, use `"completion_menu_item_kind": "symbol"` to enable. Release Notes: - Added text icons for completion items (disabled by default, use `"completion_menu_item_kind": "symbol"` to enable)
This commit is contained in:
parent
51b43c90f9
commit
a5bf443ef6
9 changed files with 222 additions and 15 deletions
|
|
@ -315,6 +315,14 @@
|
|||
"completion_menu_scrollbar": "never",
|
||||
// Whether to align detail text in code completions context menus left or right.
|
||||
"completion_detail_alignment": "left",
|
||||
// How to display the LSP item kind (function, method, variable, etc.)
|
||||
// of each entry in the completions menu.
|
||||
//
|
||||
// 1. Do not display item kinds:
|
||||
// "off" (default)
|
||||
// 2. Display a single-letter badge, colorized based on the active syntax theme:
|
||||
// "symbol"
|
||||
"completion_menu_item_kind": "off",
|
||||
// How to display diffs in the editor.
|
||||
//
|
||||
// Default: split
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use gpui::{
|
|||
use itertools::Itertools;
|
||||
use language::CodeLabel;
|
||||
use language::{Buffer, LanguageName, LanguageRegistry};
|
||||
use lsp::CompletionItemTag;
|
||||
use lsp::{CompletionItemKind, CompletionItemTag};
|
||||
use markdown::{CopyButtonVisibility, Markdown, MarkdownElement};
|
||||
use multi_buffer::Anchor;
|
||||
use ordered_float::OrderedFloat;
|
||||
|
|
@ -29,8 +29,8 @@ use std::{
|
|||
};
|
||||
use task::ResolvedTask;
|
||||
use ui::{
|
||||
Color, IntoElement, ListItem, Pixels, Popover, ScrollAxes, Scrollbars, Styled, WithScrollbar,
|
||||
prelude::*,
|
||||
Color, IntoElement, ListItem, Pixels, Popover, ScrollAxes, Scrollbars, Styled, Tooltip,
|
||||
WithScrollbar, prelude::*,
|
||||
};
|
||||
use util::ResultExt;
|
||||
|
||||
|
|
@ -43,7 +43,7 @@ use crate::{
|
|||
};
|
||||
use crate::{CodeActionSource, EditorSettings};
|
||||
use collections::{HashSet, VecDeque};
|
||||
use settings::{CompletionDetailAlignment, Settings, SnippetSortOrder};
|
||||
use settings::{CompletionDetailAlignment, CompletionMenuItemKind, Settings, SnippetSortOrder};
|
||||
|
||||
pub const MENU_GAP: Pixels = px(4.);
|
||||
pub const MENU_ASIDE_X_PADDING: Pixels = px(16.);
|
||||
|
|
@ -782,8 +782,9 @@ impl CompletionsMenu {
|
|||
cx: &mut Context<Editor>,
|
||||
) -> AnyElement {
|
||||
let show_completion_documentation = self.show_completion_documentation;
|
||||
let completion_detail_alignment =
|
||||
EditorSettings::get_global(cx).completion_detail_alignment;
|
||||
let editor_settings = EditorSettings::get_global(cx);
|
||||
let completion_detail_alignment = editor_settings.completion_detail_alignment;
|
||||
let completion_menu_item_kind = editor_settings.completion_menu_item_kind;
|
||||
let widest_completion_ix = if self.display_options.dynamic_width {
|
||||
let completions = self.completions.borrow();
|
||||
let widest_completion_ix = self
|
||||
|
|
@ -952,7 +953,7 @@ impl CompletionsMenu {
|
|||
_ => None,
|
||||
};
|
||||
|
||||
let start_slot = completion
|
||||
let icon_or_color_slot = completion
|
||||
.color()
|
||||
.map(|color| {
|
||||
div()
|
||||
|
|
@ -971,6 +972,27 @@ impl CompletionsMenu {
|
|||
})
|
||||
});
|
||||
|
||||
let kind_letter_slot = match completion_menu_item_kind {
|
||||
CompletionMenuItemKind::Off => None,
|
||||
CompletionMenuItemKind::Symbol => Some(render_completion_kind_letter(
|
||||
completion.kind(),
|
||||
item_ix,
|
||||
&style,
|
||||
)),
|
||||
};
|
||||
|
||||
let start_slot = match (kind_letter_slot, icon_or_color_slot) {
|
||||
(Some(letter), Some(icon_or_color)) => Some(
|
||||
h_flex()
|
||||
.gap_0p5()
|
||||
.child(letter)
|
||||
.child(icon_or_color)
|
||||
.into_any_element(),
|
||||
),
|
||||
(Some(letter), None) => Some(letter),
|
||||
(None, slot) => slot,
|
||||
};
|
||||
|
||||
div()
|
||||
.min_w(COMPLETION_MENU_MIN_WIDTH)
|
||||
.max_w(COMPLETION_MENU_MAX_WIDTH)
|
||||
|
|
@ -1385,6 +1407,127 @@ impl CompletionsMenu {
|
|||
}
|
||||
}
|
||||
|
||||
fn render_completion_kind_letter(
|
||||
kind: Option<CompletionItemKind>,
|
||||
item_ix: usize,
|
||||
style: &EditorStyle,
|
||||
) -> AnyElement {
|
||||
let badge = div()
|
||||
.flex_none()
|
||||
.w(IconSize::XSmall.rems())
|
||||
.text_center()
|
||||
.text_size(rems_from_px(11.))
|
||||
.line_height(rems_from_px(14.));
|
||||
|
||||
let Some(kind) = kind else {
|
||||
return badge.into_any_element();
|
||||
};
|
||||
let Some(letter) = completion_kind_letter(kind) else {
|
||||
return badge.into_any_element();
|
||||
};
|
||||
|
||||
let color = completion_kind_highlight_name(kind)
|
||||
.and_then(|name| {
|
||||
style.syntax.style_for_name(name).or_else(|| {
|
||||
let (parent, _) = name.rsplit_once('.')?;
|
||||
style.syntax.style_for_name(parent)
|
||||
})
|
||||
})
|
||||
.and_then(|hl| hl.color);
|
||||
|
||||
badge
|
||||
.id(("completion-kind", item_ix))
|
||||
.tooltip(Tooltip::text(completion_kind_name(kind)))
|
||||
.child(letter)
|
||||
.when_some(color, |element, color| element.text_color(color))
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
fn completion_kind_name(kind: CompletionItemKind) -> &'static str {
|
||||
match kind {
|
||||
CompletionItemKind::TEXT => "Text",
|
||||
CompletionItemKind::METHOD => "Method",
|
||||
CompletionItemKind::FUNCTION => "Function",
|
||||
CompletionItemKind::CONSTRUCTOR => "Constructor",
|
||||
CompletionItemKind::FIELD => "Field",
|
||||
CompletionItemKind::VARIABLE => "Variable",
|
||||
CompletionItemKind::CLASS => "Class",
|
||||
CompletionItemKind::INTERFACE => "Interface",
|
||||
CompletionItemKind::MODULE => "Module",
|
||||
CompletionItemKind::PROPERTY => "Property",
|
||||
CompletionItemKind::UNIT => "Unit",
|
||||
CompletionItemKind::VALUE => "Value",
|
||||
CompletionItemKind::ENUM => "Enum",
|
||||
CompletionItemKind::KEYWORD => "Keyword",
|
||||
CompletionItemKind::SNIPPET => "Snippet",
|
||||
CompletionItemKind::COLOR => "Color",
|
||||
CompletionItemKind::FILE => "File",
|
||||
CompletionItemKind::REFERENCE => "Reference",
|
||||
CompletionItemKind::FOLDER => "Folder",
|
||||
CompletionItemKind::ENUM_MEMBER => "Enum Member",
|
||||
CompletionItemKind::CONSTANT => "Constant",
|
||||
CompletionItemKind::STRUCT => "Struct",
|
||||
CompletionItemKind::EVENT => "Event",
|
||||
CompletionItemKind::OPERATOR => "Operator",
|
||||
CompletionItemKind::TYPE_PARAMETER => "Type Parameter",
|
||||
_ => "Unknown",
|
||||
}
|
||||
}
|
||||
|
||||
fn completion_kind_letter(kind: CompletionItemKind) -> Option<&'static str> {
|
||||
Some(match kind {
|
||||
CompletionItemKind::TEXT => "t",
|
||||
CompletionItemKind::METHOD => "m",
|
||||
CompletionItemKind::FUNCTION => "f",
|
||||
CompletionItemKind::CONSTRUCTOR => "C",
|
||||
CompletionItemKind::FIELD => "f",
|
||||
CompletionItemKind::VARIABLE => "v",
|
||||
CompletionItemKind::CLASS => "c",
|
||||
CompletionItemKind::INTERFACE => "i",
|
||||
CompletionItemKind::MODULE => "M",
|
||||
CompletionItemKind::PROPERTY => "p",
|
||||
CompletionItemKind::UNIT => "u",
|
||||
CompletionItemKind::VALUE => "v",
|
||||
CompletionItemKind::ENUM => "e",
|
||||
CompletionItemKind::KEYWORD => "k",
|
||||
CompletionItemKind::SNIPPET => "s",
|
||||
CompletionItemKind::COLOR => "c",
|
||||
CompletionItemKind::FILE => "F",
|
||||
CompletionItemKind::REFERENCE => "r",
|
||||
CompletionItemKind::FOLDER => "D",
|
||||
CompletionItemKind::ENUM_MEMBER => "e",
|
||||
CompletionItemKind::CONSTANT => "c",
|
||||
CompletionItemKind::STRUCT => "S",
|
||||
CompletionItemKind::EVENT => "E",
|
||||
CompletionItemKind::OPERATOR => "o",
|
||||
CompletionItemKind::TYPE_PARAMETER => "T",
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
|
||||
fn completion_kind_highlight_name(kind: CompletionItemKind) -> Option<&'static str> {
|
||||
Some(match kind {
|
||||
CompletionItemKind::CLASS => "type",
|
||||
CompletionItemKind::CONSTANT => "constant",
|
||||
CompletionItemKind::CONSTRUCTOR => "constructor",
|
||||
CompletionItemKind::ENUM => "enum",
|
||||
CompletionItemKind::ENUM_MEMBER => "variant",
|
||||
CompletionItemKind::FIELD => "property",
|
||||
CompletionItemKind::FUNCTION => "function",
|
||||
CompletionItemKind::INTERFACE => "type",
|
||||
CompletionItemKind::METHOD => "function.method",
|
||||
CompletionItemKind::MODULE => "namespace",
|
||||
CompletionItemKind::OPERATOR => "operator",
|
||||
CompletionItemKind::PROPERTY => "property",
|
||||
CompletionItemKind::STRUCT => "type",
|
||||
CompletionItemKind::TYPE_PARAMETER => "type",
|
||||
CompletionItemKind::VARIABLE => "variable",
|
||||
CompletionItemKind::KEYWORD => "keyword",
|
||||
CompletionItemKind::SNIPPET => "string",
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
|
||||
fn exact_case_match_count(query: &str, string_match: &StringMatch) -> usize {
|
||||
let mut exact_matches = 0;
|
||||
let mut query_chars = query.chars();
|
||||
|
|
|
|||
|
|
@ -80,9 +80,9 @@ pub use display_map::{
|
|||
};
|
||||
pub use edit_prediction_types::Direction;
|
||||
pub use editor_settings::{
|
||||
CompletionDetailAlignment, CurrentLineHighlight, DiffViewStyle, DocumentColorsRenderMode,
|
||||
EditorSettings, EditorSettingsScrollbarProxy, ScrollBeyondLastLine, ScrollbarAxes,
|
||||
SearchSettings, ShowMinimap, ui_scrollbar_settings_from_raw,
|
||||
CompletionDetailAlignment, CompletionMenuItemKind, CurrentLineHighlight, DiffViewStyle,
|
||||
DocumentColorsRenderMode, EditorSettings, EditorSettingsScrollbarProxy, ScrollBeyondLastLine,
|
||||
ScrollbarAxes, SearchSettings, ShowMinimap, ui_scrollbar_settings_from_raw,
|
||||
};
|
||||
pub use element::{
|
||||
CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
|
||||
|
|
|
|||
|
|
@ -4,10 +4,11 @@ use gpui::App;
|
|||
use language::CursorShape;
|
||||
use project::project_settings::DiagnosticSeverity;
|
||||
pub use settings::{
|
||||
CodeLens, CompletionDetailAlignment, CurrentLineHighlight, DelayMs, DiffViewStyle, DisplayIn,
|
||||
DocumentColorsRenderMode, DoubleClickInMultibuffer, GoToDefinitionFallback,
|
||||
GoToDefinitionScrollStrategy, MinimapThumb, MinimapThumbBorder, MultiCursorModifier,
|
||||
ScrollBeyondLastLine, ScrollbarDiagnostics, SeedQuerySetting, ShowMinimap, SnippetSortOrder,
|
||||
CodeLens, CompletionDetailAlignment, CompletionMenuItemKind, CurrentLineHighlight, DelayMs,
|
||||
DiffViewStyle, DisplayIn, DocumentColorsRenderMode, DoubleClickInMultibuffer,
|
||||
GoToDefinitionFallback, GoToDefinitionScrollStrategy, MinimapThumb, MinimapThumbBorder,
|
||||
MultiCursorModifier, ScrollBeyondLastLine, ScrollbarDiagnostics, SeedQuerySetting, ShowMinimap,
|
||||
SnippetSortOrder,
|
||||
};
|
||||
use settings::{RegisterSetting, RelativeLineNumbers, Settings};
|
||||
use ui::scrollbars::ShowScrollbar;
|
||||
|
|
@ -63,6 +64,7 @@ pub struct EditorSettings {
|
|||
pub minimum_contrast_for_highlights: f32,
|
||||
pub completion_menu_scrollbar: ShowScrollbar,
|
||||
pub completion_detail_alignment: CompletionDetailAlignment,
|
||||
pub completion_menu_item_kind: CompletionMenuItemKind,
|
||||
pub diff_view_style: DiffViewStyle,
|
||||
pub minimum_split_diff_width: f32,
|
||||
}
|
||||
|
|
@ -304,6 +306,7 @@ impl Settings for EditorSettings {
|
|||
.map(ui_scrollbar_settings_from_raw)
|
||||
.unwrap(),
|
||||
completion_detail_alignment: editor.completion_detail_alignment.unwrap(),
|
||||
completion_menu_item_kind: editor.completion_menu_item_kind.unwrap(),
|
||||
diff_view_style: editor.diff_view_style.unwrap(),
|
||||
minimum_split_diff_width: editor.minimum_split_diff_width.unwrap(),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -315,6 +315,7 @@ impl VsCodeSettings {
|
|||
vertical_scroll_margin: self.read_f32("editor.cursorSurroundingLines"),
|
||||
completion_menu_scrollbar: None,
|
||||
completion_detail_alignment: None,
|
||||
completion_menu_item_kind: None,
|
||||
diff_view_style: None,
|
||||
minimum_split_diff_width: None,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -245,6 +245,16 @@ pub struct EditorSettingsContent {
|
|||
/// Default: left
|
||||
pub completion_detail_alignment: Option<CompletionDetailAlignment>,
|
||||
|
||||
/// How to display the LSP item kind (function, method, variable, etc.)
|
||||
/// of each entry in the completions menu.
|
||||
///
|
||||
/// - "off": do not display item kinds (default).
|
||||
/// - "symbol": display a single-letter badge, colorized based on the
|
||||
/// active syntax theme.
|
||||
///
|
||||
/// Default: off
|
||||
pub completion_menu_item_kind: Option<CompletionMenuItemKind>,
|
||||
|
||||
/// How to display diffs in the editor.
|
||||
///
|
||||
/// Default: split
|
||||
|
|
@ -300,6 +310,27 @@ pub enum CompletionDetailAlignment {
|
|||
Right,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Default,
|
||||
Clone,
|
||||
Copy,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
JsonSchema,
|
||||
MergeFrom,
|
||||
PartialEq,
|
||||
Eq,
|
||||
strum::VariantArray,
|
||||
strum::VariantNames,
|
||||
)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum CompletionMenuItemKind {
|
||||
#[default]
|
||||
Off,
|
||||
Symbol,
|
||||
}
|
||||
|
||||
impl RelativeLineNumbers {
|
||||
pub fn enabled(&self) -> bool {
|
||||
match self {
|
||||
|
|
|
|||
|
|
@ -8500,7 +8500,7 @@ fn language_settings_data() -> Box<[SettingsPageItem]> {
|
|||
]
|
||||
}
|
||||
|
||||
fn completions_section() -> [SettingsPageItem; 7] {
|
||||
fn completions_section() -> [SettingsPageItem; 8] {
|
||||
[
|
||||
SettingsPageItem::SectionHeader("Completions"),
|
||||
SettingsPageItem::SettingItem(SettingItem {
|
||||
|
|
@ -8612,6 +8612,21 @@ fn language_settings_data() -> Box<[SettingsPageItem]> {
|
|||
metadata: None,
|
||||
files: USER,
|
||||
}),
|
||||
SettingsPageItem::SettingItem(SettingItem {
|
||||
title: "Completion Menu Item Kind",
|
||||
description: "How to display the LSP item kind (function, method, variable, etc.) of each entry in the completions menu.",
|
||||
field: Box::new(SettingField {
|
||||
json_path: Some("editor.completion_menu_item_kind"),
|
||||
pick: |settings_content| {
|
||||
settings_content.editor.completion_menu_item_kind.as_ref()
|
||||
},
|
||||
write: |settings_content, value, _| {
|
||||
settings_content.editor.completion_menu_item_kind = value;
|
||||
},
|
||||
}),
|
||||
metadata: None,
|
||||
files: USER,
|
||||
}),
|
||||
]
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -500,6 +500,7 @@ fn init_renderers(cx: &mut App) {
|
|||
.add_basic_renderer::<settings::WordsCompletionMode>(render_dropdown)
|
||||
.add_basic_renderer::<settings::LspInsertMode>(render_dropdown)
|
||||
.add_basic_renderer::<settings::CompletionDetailAlignment>(render_dropdown)
|
||||
.add_basic_renderer::<settings::CompletionMenuItemKind>(render_dropdown)
|
||||
.add_basic_renderer::<settings::DiffViewStyle>(render_dropdown)
|
||||
.add_basic_renderer::<settings::AlternateScroll>(render_dropdown)
|
||||
.add_basic_renderer::<settings::TerminalBlink>(render_dropdown)
|
||||
|
|
|
|||
|
|
@ -384,6 +384,11 @@ TBD: Centered layout related settings
|
|||
"lsp_document_colors": "inlay", // none, inlay, border, background
|
||||
// When to show the scrollbar in the completion menu.
|
||||
"completion_menu_scrollbar": "never", // auto, system, always, never
|
||||
|
||||
// How to display the LSP item kind (function, method, variable, etc.)
|
||||
// of each entry in the completions menu. "symbol" shows a syntax-colored
|
||||
// single-letter badge.
|
||||
"completion_menu_item_kind": "off", // off, symbol
|
||||
// Turn on colorization of brackets in editors (configurable per language)
|
||||
"colorize_brackets": true,
|
||||
```
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue