Detailed changes
@@ -284,6 +284,8 @@
// 4. Never show the scrollbar:
// "never" (default)
"completion_menu_scrollbar": "never",
+ // Whether to align detail text in code completions context menus left or right.
+ "completion_detail_alignment": "left",
// Show method signatures in the editor, when inside parentheses.
"auto_signature_help": false,
// Whether to show the signature help after completion or a bracket pair inserted.
@@ -43,7 +43,7 @@ use crate::{
};
use crate::{CodeActionSource, EditorSettings};
use collections::{HashSet, VecDeque};
-use settings::{Settings, SnippetSortOrder};
+use settings::{CompletionDetailAlignment, Settings, SnippetSortOrder};
pub const MENU_GAP: Pixels = px(4.);
pub const MENU_ASIDE_X_PADDING: Pixels = px(16.);
@@ -786,6 +786,8 @@ 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 widest_completion_ix = if self.display_options.dynamic_width {
let completions = self.completions.borrow();
let widest_completion_ix = self
@@ -839,6 +841,7 @@ impl CompletionsMenu {
};
let filter_start = completion.label.filter_range.start;
+
let highlights = gpui::combine_highlights(
mat.ranges().map(|range| {
(
@@ -880,8 +883,58 @@ impl CompletionsMenu {
}),
);
- let completion_label = StyledText::new(completion.label.text.clone())
- .with_default_highlights(&style.text, highlights);
+ let highlights: Vec<_> = highlights.collect();
+
+ let filter_range = &completion.label.filter_range;
+ let full_text = &completion.label.text;
+
+ let main_text: String = full_text[filter_range.clone()].to_string();
+ let main_highlights: Vec<_> = highlights
+ .iter()
+ .filter_map(|(range, highlight)| {
+ if range.end <= filter_range.start
+ || range.start >= filter_range.end
+ {
+ return None;
+ }
+ let clamped_start =
+ range.start.max(filter_range.start) - filter_range.start;
+ let clamped_end =
+ range.end.min(filter_range.end) - filter_range.start;
+ Some((clamped_start..clamped_end, (*highlight)))
+ })
+ .collect();
+ let main_label = StyledText::new(main_text)
+ .with_default_highlights(&style.text, main_highlights);
+
+ let suffix_text: String = full_text[filter_range.end..].to_string();
+ let suffix_highlights: Vec<_> = highlights
+ .iter()
+ .filter_map(|(range, highlight)| {
+ if range.end <= filter_range.end {
+ return None;
+ }
+ let shifted_start = range.start.saturating_sub(filter_range.end);
+ let shifted_end = range.end - filter_range.end;
+ Some((shifted_start..shifted_end, (*highlight)))
+ })
+ .collect();
+ let suffix_label = if !suffix_text.is_empty() {
+ Some(
+ StyledText::new(suffix_text)
+ .with_default_highlights(&style.text, suffix_highlights),
+ )
+ } else {
+ None
+ };
+
+ let left_aligned_suffix =
+ matches!(completion_detail_alignment, CompletionDetailAlignment::Left);
+
+ let right_aligned_suffix = matches!(
+ completion_detail_alignment,
+ CompletionDetailAlignment::Right,
+ );
let documentation_label = match documentation {
Some(CompletionDocumentation::SingleLine(text))
@@ -942,7 +995,24 @@ impl CompletionsMenu {
}
}))
.start_slot::<AnyElement>(start_slot)
- .child(h_flex().overflow_hidden().child(completion_label))
+ .child(
+ h_flex()
+ .min_w_0()
+ .w_full()
+ .when(left_aligned_suffix, |this| this.justify_start())
+ .when(right_aligned_suffix, |this| {
+ this.justify_between()
+ })
+ .child(
+ div()
+ .flex_none()
+ .whitespace_nowrap()
+ .child(main_label),
+ )
+ .when_some(suffix_label, |this, suffix| {
+ this.child(div().truncate().child(suffix))
+ }),
+ )
.end_slot::<Label>(documentation_label),
)
})
@@ -53,8 +53,8 @@ pub(crate) use actions::*;
pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
pub use edit_prediction_types::Direction;
pub use editor_settings::{
- CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
- ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap,
+ CompletionDetailAlignment, CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings,
+ HideMouseMode, ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap,
};
pub use element::{
CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
@@ -4,9 +4,10 @@ use gpui::App;
use language::CursorShape;
use project::project_settings::DiagnosticSeverity;
pub use settings::{
- CurrentLineHighlight, DelayMs, DisplayIn, DocumentColorsRenderMode, DoubleClickInMultibuffer,
- GoToDefinitionFallback, HideMouseMode, MinimapThumb, MinimapThumbBorder, MultiCursorModifier,
- ScrollBeyondLastLine, ScrollbarDiagnostics, SeedQuerySetting, ShowMinimap, SnippetSortOrder,
+ CompletionDetailAlignment, CurrentLineHighlight, DelayMs, DisplayIn, DocumentColorsRenderMode,
+ DoubleClickInMultibuffer, GoToDefinitionFallback, HideMouseMode, MinimapThumb,
+ MinimapThumbBorder, MultiCursorModifier, ScrollBeyondLastLine, ScrollbarDiagnostics,
+ SeedQuerySetting, ShowMinimap, SnippetSortOrder,
};
use settings::{RegisterSetting, RelativeLineNumbers, Settings};
use ui::scrollbars::{ScrollbarVisibility, ShowScrollbar};
@@ -57,6 +58,7 @@ pub struct EditorSettings {
pub lsp_document_colors: DocumentColorsRenderMode,
pub minimum_contrast_for_highlights: f32,
pub completion_menu_scrollbar: ShowScrollbar,
+ pub completion_detail_alignment: CompletionDetailAlignment,
}
#[derive(Debug, Clone)]
pub struct Jupyter {
@@ -286,6 +288,7 @@ impl Settings for EditorSettings {
lsp_document_colors: editor.lsp_document_colors.unwrap(),
minimum_contrast_for_highlights: editor.minimum_contrast_for_highlights.unwrap().0,
completion_menu_scrollbar: editor.completion_menu_scrollbar.map(Into::into).unwrap(),
+ completion_detail_alignment: editor.completion_detail_alignment.unwrap(),
}
}
}
@@ -215,6 +215,11 @@ pub struct EditorSettingsContent {
/// 4. Never show the scrollbar:
/// "never" (default)
pub completion_menu_scrollbar: Option<ShowScrollbar>,
+
+ /// Whether to align detail text in code completions context menus left or right.
+ ///
+ /// Default: left
+ pub completion_detail_alignment: Option<CompletionDetailAlignment>,
}
#[derive(
@@ -237,6 +242,27 @@ pub enum RelativeLineNumbers {
Wrapped,
}
+#[derive(
+ Debug,
+ Default,
+ Clone,
+ Copy,
+ Serialize,
+ Deserialize,
+ JsonSchema,
+ MergeFrom,
+ PartialEq,
+ Eq,
+ strum::VariantArray,
+ strum::VariantNames,
+)]
+#[serde(rename_all = "snake_case")]
+pub enum CompletionDetailAlignment {
+ #[default]
+ Left,
+ Right,
+}
+
impl RelativeLineNumbers {
pub fn enabled(&self) -> bool {
match self {
@@ -302,6 +302,7 @@ impl VsCodeSettings {
use_smartcase_search: self.read_bool("search.smartCase"),
vertical_scroll_margin: self.read_f32("editor.cursorSurroundingLines"),
completion_menu_scrollbar: None,
+ completion_detail_alignment: None,
}
}
@@ -6974,6 +6974,21 @@ fn language_settings_data() -> Vec<SettingsPageItem> {
metadata: None,
files: USER,
}),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Completion Detail Alignment",
+ description: "Whether to align detail text in code completions context menus left or right.",
+ field: Box::new(SettingField {
+ json_path: Some("editor.completion_detail_alignment"),
+ pick: |settings_content| {
+ settings_content.editor.completion_detail_alignment.as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content.editor.completion_detail_alignment = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
SettingsPageItem::SectionHeader("Inlay Hints"),
SettingsPageItem::SettingItem(SettingItem {
title: "Enabled",
@@ -469,6 +469,7 @@ fn init_renderers(cx: &mut App) {
.add_basic_renderer::<settings::ShowDiagnostics>(render_dropdown)
.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::AlternateScroll>(render_dropdown)
.add_basic_renderer::<settings::TerminalBlink>(render_dropdown)
.add_basic_renderer::<settings::CursorShapeContent>(render_dropdown)