From 24572649d6f16c74d79d0ca186d900223f2c5ae5 Mon Sep 17 00:00:00 2001 From: legs <145564979+justsomelegs@users.noreply.github.com> Date: Sun, 4 Jan 2026 22:15:22 +0000 Subject: [PATCH] editor: Add alignment setting to code completion context menu detail text (#45892) Closes #5154 Release Notes: - Added a setting (`completion_detail_alignment`) to change the detail text alignment in code completion context menus.
Right Alignment Left Alignment
image image
--------- Co-authored-by: Danilo Leal --- assets/settings/default.json | 2 + crates/editor/src/code_context_menus.rs | 78 ++++++++++++++++++- crates/editor/src/editor.rs | 4 +- crates/editor/src/editor_settings.rs | 9 ++- .../settings/src/settings_content/editor.rs | 26 +++++++ crates/settings/src/vscode_import.rs | 1 + crates/settings_ui/src/page_data.rs | 15 ++++ crates/settings_ui/src/settings_ui.rs | 1 + 8 files changed, 127 insertions(+), 9 deletions(-) diff --git a/assets/settings/default.json b/assets/settings/default.json index f12586a68039783c44015ae5963187ce986b9d8d..e0ce02ae2ebc25aa0cd4165315bd381d725923a3 100644 --- a/assets/settings/default.json +++ b/assets/settings/default.json @@ -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. diff --git a/crates/editor/src/code_context_menus.rs b/crates/editor/src/code_context_menus.rs index e5520be88e34307220126ebafdba6c6371a5db12..e1ea2822168c836caffd9ef6f59b263c6432d10b 100644 --- a/crates/editor/src/code_context_menus.rs +++ b/crates/editor/src/code_context_menus.rs @@ -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, ) -> 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::(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::