diff --git a/assets/settings/default.json b/assets/settings/default.json index 6dc573ddb6..2ae8d5c4a8 100644 --- a/assets/settings/default.json +++ b/assets/settings/default.json @@ -50,6 +50,13 @@ // Whether to pop the completions menu while typing in an editor without // explicitly requesting it. "show_completions_on_input": true, + // Whether to show wrap guides in the editor. Setting this to true will + // show a guide at the 'preferred_line_length' value if softwrap is set to + // 'preferred_line_length', and will show any additional guides as specified + // by the 'wrap_guides' setting. + "show_wrap_guides": true, + // Character counts at which to show wrap guides in the editor. + "wrap_guides": [], // Whether to use additional LSP queries to format (and amend) the code after // every "trigger" symbol input, defined by LSP server capabilities. "use_on_type_format": true, @@ -356,12 +363,6 @@ // LSP Specific settings. "lsp": { // Specify the LSP name as a key here. - // As of 8/10/22, supported LSPs are: - // pyright - // gopls - // rust-analyzer - // typescript-language-server - // vscode-json-languageserver // "rust-analyzer": { // //These initialization options are merged into Zed's defaults // "initialization_options": { diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index b790543ee5..87ba250a88 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -7086,6 +7086,20 @@ impl Editor { .text() } + pub fn wrap_guides(&self, cx: &AppContext) -> SmallVec<[(usize, bool); 2]> { + let mut wrap_guides = smallvec::smallvec![]; + + let settings = self.buffer.read(cx).settings_at(0, cx); + if settings.show_wrap_guides { + if let SoftWrap::Column(soft_wrap) = self.soft_wrap_mode(cx) { + wrap_guides.push((soft_wrap as usize, true)); + } + wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false))) + } + + wrap_guides + } + pub fn soft_wrap_mode(&self, cx: &AppContext) -> SoftWrap { let settings = self.buffer.read(cx).settings_at(0, cx); let mode = self diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 1189503c58..3f84d7e503 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -541,6 +541,25 @@ impl EditorElement { corner_radius: 0., }); } + + for (wrap_position, active) in layout.wrap_guides.iter() { + let x = text_bounds.origin_x() + wrap_position + layout.position_map.em_width / 2.; + let color = if *active { + self.style.active_wrap_guide + } else { + self.style.wrap_guide + }; + scene.push_quad(Quad { + bounds: RectF::new( + vec2f(x, text_bounds.origin_y()), + vec2f(1., text_bounds.height()), + ), + background: Some(color), + border: Border::new(0., Color::transparent_black()), + corner_radius: 0., + }); + } + } } @@ -1320,16 +1339,15 @@ impl EditorElement { } } - fn max_line_number_width(&self, snapshot: &EditorSnapshot, cx: &ViewContext) -> f32 { - let digit_count = (snapshot.max_buffer_row() as f32 + 1.).log10().floor() as usize + 1; + fn column_pixels(&self, column: usize, cx: &ViewContext) -> f32 { let style = &self.style; cx.text_layout_cache() .layout_str( - "1".repeat(digit_count).as_str(), + " ".repeat(column).as_str(), style.text.font_size, &[( - digit_count, + column, RunStyle { font_id: style.text.font_id, color: Color::black(), @@ -1340,6 +1358,11 @@ impl EditorElement { .width() } + fn max_line_number_width(&self, snapshot: &EditorSnapshot, cx: &ViewContext) -> f32 { + let digit_count = (snapshot.max_buffer_row() as f32 + 1.).log10().floor() as usize + 1; + self.column_pixels(digit_count, cx) + } + //Folds contained in a hunk are ignored apart from shrinking visual size //If a fold contains any hunks then that fold line is marked as modified fn layout_git_gutters( @@ -2025,6 +2048,12 @@ impl Element for EditorElement { } }; + let wrap_guides = editor + .wrap_guides(cx) + .iter() + .map(|(guide, active)| (self.column_pixels(*guide, cx), *active)) + .collect(); + let scroll_height = (snapshot.max_point().row() + 1) as f32 * line_height; if let EditorMode::AutoHeight { max_lines } = snapshot.mode { size.set_y( @@ -2385,6 +2414,7 @@ impl Element for EditorElement { snapshot, }), visible_display_row_range: start_row..end_row, + wrap_guides, gutter_size, gutter_padding, text_size, @@ -2535,6 +2565,7 @@ pub struct LayoutState { gutter_margin: f32, text_size: Vector2F, mode: EditorMode, + wrap_guides: SmallVec<[(f32, bool); 2]>, visible_display_row_range: Range, active_rows: BTreeMap, highlighted_rows: Option>, diff --git a/crates/language/src/language_settings.rs b/crates/language/src/language_settings.rs index 820217567a..c3f706802a 100644 --- a/crates/language/src/language_settings.rs +++ b/crates/language/src/language_settings.rs @@ -44,6 +44,8 @@ pub struct LanguageSettings { pub hard_tabs: bool, pub soft_wrap: SoftWrap, pub preferred_line_length: u32, + pub show_wrap_guides: bool, + pub wrap_guides: Vec, pub format_on_save: FormatOnSave, pub remove_trailing_whitespace_on_save: bool, pub ensure_final_newline_on_save: bool, @@ -84,6 +86,10 @@ pub struct LanguageSettingsContent { #[serde(default)] pub preferred_line_length: Option, #[serde(default)] + pub show_wrap_guides: Option, + #[serde(default)] + pub wrap_guides: Option>, + #[serde(default)] pub format_on_save: Option, #[serde(default)] pub remove_trailing_whitespace_on_save: Option, @@ -378,6 +384,9 @@ fn merge_settings(settings: &mut LanguageSettings, src: &LanguageSettingsContent merge(&mut settings.tab_size, src.tab_size); merge(&mut settings.hard_tabs, src.hard_tabs); merge(&mut settings.soft_wrap, src.soft_wrap); + merge(&mut settings.show_wrap_guides, src.show_wrap_guides); + merge(&mut settings.wrap_guides, src.wrap_guides.clone()); + merge( &mut settings.preferred_line_length, src.preferred_line_length, diff --git a/crates/theme/src/theme.rs b/crates/theme/src/theme.rs index 29c0d9ce8e..81ae7a65ca 100644 --- a/crates/theme/src/theme.rs +++ b/crates/theme/src/theme.rs @@ -691,6 +691,8 @@ pub struct Editor { pub document_highlight_read_background: Color, pub document_highlight_write_background: Color, pub diff: DiffStyle, + pub wrap_guide: Color, + pub active_wrap_guide: Color, pub line_number: Color, pub line_number_active: Color, pub guest_selections: Vec, diff --git a/styles/src/style_tree/editor.ts b/styles/src/style_tree/editor.ts index 7e20f09b32..0f87420610 100644 --- a/styles/src/style_tree/editor.ts +++ b/styles/src/style_tree/editor.ts @@ -170,6 +170,8 @@ export default function editor(): any { line_number: with_opacity(foreground(layer), 0.35), line_number_active: foreground(layer), rename_fade: 0.6, + wrap_guide: with_opacity(foreground(layer), 0.1), + active_wrap_guide: with_opacity(foreground(layer), 0.1), unnecessary_code_fade: 0.5, selection: theme.players[0], whitespace: theme.ramps.neutral(0.5).hex(),