From 065f71d671829caafb1cd15a6391d2470de511f1 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Fri, 19 May 2023 22:06:47 +0300 Subject: [PATCH 01/19] Do not refocus project search query on ESC press --- crates/search/src/project_search.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/crates/search/src/project_search.rs b/crates/search/src/project_search.rs index d96d77eb005aa099642f01f6499db60363caaf6d..915957401d440c40dd13d4b3364b0be76e09f3ef 100644 --- a/crates/search/src/project_search.rs +++ b/crates/search/src/project_search.rs @@ -48,7 +48,7 @@ pub fn init(cx: &mut AppContext) { cx.add_action(ProjectSearchBar::search_in_new); cx.add_action(ProjectSearchBar::select_next_match); cx.add_action(ProjectSearchBar::select_prev_match); - cx.add_action(ProjectSearchBar::toggle_focus); + cx.add_action(ProjectSearchBar::move_focus_to_results); cx.capture_action(ProjectSearchBar::tab); cx.capture_action(ProjectSearchBar::tab_previous); add_toggle_option_action::(SearchOption::CaseSensitive, cx); @@ -794,18 +794,16 @@ impl ProjectSearchBar { } } - fn toggle_focus(pane: &mut Pane, _: &ToggleFocus, cx: &mut ViewContext) { + fn move_focus_to_results(pane: &mut Pane, _: &ToggleFocus, cx: &mut ViewContext) { if let Some(search_view) = pane .active_item() .and_then(|item| item.downcast::()) { search_view.update(cx, |search_view, cx| { - if search_view.query_editor.is_focused(cx) { - if !search_view.model.read(cx).match_ranges.is_empty() { - search_view.focus_results_editor(cx); - } - } else { - search_view.focus_query_editor(cx); + if search_view.query_editor.is_focused(cx) + && !search_view.model.read(cx).match_ranges.is_empty() + { + search_view.focus_results_editor(cx); } }); } else { From fb11c3e4bf559ffe07563b2b453cf31f52529fa1 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 19 May 2023 16:52:30 -0700 Subject: [PATCH 02/19] Remove stray prints --- crates/project/src/project.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index 15741a27f17ce202468680af1f9d9e12a996293d..f91cd999f9dd0068f98ae9f30fda3067469481d2 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -2870,10 +2870,8 @@ impl Project { if let Some(LanguageServerState::Running { watched_paths, .. }) = self.language_servers.get_mut(&language_server_id) { - eprintln!("change watch"); let mut builders = HashMap::default(); for watcher in params.watchers { - eprintln!(" {}", watcher.glob_pattern); for worktree in &self.worktrees { if let Some(worktree) = worktree.upgrade(cx) { let worktree = worktree.read(cx); From e32233c8268216ec46ba12475ab35984cf4452e4 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 19 May 2023 17:15:05 -0700 Subject: [PATCH 03/19] Fix spurious setting error logs on non-existent setting keys --- crates/client/src/client.rs | 2 +- crates/editor/src/editor_settings.rs | 5 ++- crates/language/src/language_settings.rs | 2 +- crates/project/src/project_settings.rs | 2 +- crates/settings/src/settings_store.rs | 42 ++++++++++++---------- crates/workspace/src/workspace_settings.rs | 2 +- 6 files changed, 29 insertions(+), 26 deletions(-) diff --git a/crates/client/src/client.rs b/crates/client/src/client.rs index 311d9a2b8872cd3d63ad861cc986849d93d1e240..c9b83d805a4a87a65eda95f5b765c35841627d30 100644 --- a/crates/client/src/client.rs +++ b/crates/client/src/client.rs @@ -339,7 +339,7 @@ pub struct TelemetrySettings { pub metrics: bool, } -#[derive(Clone, Serialize, Deserialize, JsonSchema)] +#[derive(Default, Clone, Serialize, Deserialize, JsonSchema)] pub struct TelemetrySettingsContent { pub diagnostics: Option, pub metrics: Option, diff --git a/crates/editor/src/editor_settings.rs b/crates/editor/src/editor_settings.rs index 5108d2740875bd38dabea3c4ca06ca78784d1f35..a3f38a3dc096c6a4ce8365911313c31c147d06e7 100644 --- a/crates/editor/src/editor_settings.rs +++ b/crates/editor/src/editor_settings.rs @@ -10,17 +10,16 @@ pub struct EditorSettings { pub show_scrollbars: ShowScrollbars, } -#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Default)] +#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] #[serde(rename_all = "snake_case")] pub enum ShowScrollbars { - #[default] Auto, System, Always, Never, } -#[derive(Clone, Serialize, Deserialize, JsonSchema)] +#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)] pub struct EditorSettingsContent { pub cursor_blink: Option, pub hover_popover_enabled: Option, diff --git a/crates/language/src/language_settings.rs b/crates/language/src/language_settings.rs index d877304f1d991eeb22a58022f6c9723be71ba1cd..c98297c03648f7db9c307a592b4f7bf2dcfe279d 100644 --- a/crates/language/src/language_settings.rs +++ b/crates/language/src/language_settings.rs @@ -49,7 +49,7 @@ pub struct CopilotSettings { pub disabled_globs: Vec, } -#[derive(Clone, Serialize, Deserialize, JsonSchema)] +#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)] pub struct AllLanguageSettingsContent { #[serde(default)] pub features: Option, diff --git a/crates/project/src/project_settings.rs b/crates/project/src/project_settings.rs index 92e8cfcca79fc59f17a879c5c7ade0264a6b40bf..c542d1d13fd42c3cd2721c92981e74129556a554 100644 --- a/crates/project/src/project_settings.rs +++ b/crates/project/src/project_settings.rs @@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize}; use settings::Setting; use std::sync::Arc; -#[derive(Clone, Serialize, Deserialize, JsonSchema)] +#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)] pub struct ProjectSettings { #[serde(default)] pub lsp: HashMap, LspSettings>, diff --git a/crates/settings/src/settings_store.rs b/crates/settings/src/settings_store.rs index dd81b05434af71680f85f18b644839d7a6b47875..329b290a3192c66545e7001635917e448acc1e81 100644 --- a/crates/settings/src/settings_store.rs +++ b/crates/settings/src/settings_store.rs @@ -25,7 +25,7 @@ pub trait Setting: 'static { const KEY: Option<&'static str>; /// The type that is stored in an individual JSON file. - type FileContent: Clone + Serialize + DeserializeOwned + JsonSchema; + type FileContent: Clone + Default + Serialize + DeserializeOwned + JsonSchema; /// The logic for combining together values from one or more JSON files into the /// final value for this setting. @@ -460,11 +460,12 @@ impl SettingsStore { // If the global settings file changed, reload the global value for the field. if changed_local_path.is_none() { - setting_value.set_global_value(setting_value.load_setting( - &default_settings, - &user_settings_stack, - cx, - )?); + if let Some(value) = setting_value + .load_setting(&default_settings, &user_settings_stack, cx) + .log_err() + { + setting_value.set_global_value(value); + } } // Reload the local values for the setting. @@ -495,14 +496,12 @@ impl SettingsStore { continue; } - setting_value.set_local_value( - path.clone(), - setting_value.load_setting( - &default_settings, - &user_settings_stack, - cx, - )?, - ); + if let Some(value) = setting_value + .load_setting(&default_settings, &user_settings_stack, cx) + .log_err() + { + setting_value.set_local_value(path.clone(), value); + } } } } @@ -536,7 +535,12 @@ impl AnySettingValue for SettingValue { fn deserialize_setting(&self, mut json: &serde_json::Value) -> Result { if let Some(key) = T::KEY { - json = json.get(key).unwrap_or(&serde_json::Value::Null); + if let Some(value) = json.get(key) { + json = value; + } else { + let value = T::FileContent::default(); + return Ok(DeserializedSetting(Box::new(value))); + } } let value = T::FileContent::deserialize(json)?; Ok(DeserializedSetting(Box::new(value))) @@ -1126,7 +1130,7 @@ mod tests { staff: bool, } - #[derive(Clone, Serialize, Deserialize, JsonSchema)] + #[derive(Default, Clone, Serialize, Deserialize, JsonSchema)] struct UserSettingsJson { name: Option, age: Option, @@ -1170,7 +1174,7 @@ mod tests { key2: String, } - #[derive(Clone, Serialize, Deserialize, JsonSchema)] + #[derive(Clone, Default, Serialize, Deserialize, JsonSchema)] struct MultiKeySettingsJson { key1: Option, key2: Option, @@ -1203,7 +1207,7 @@ mod tests { Hour24, } - #[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] + #[derive(Clone, Default, Debug, Serialize, Deserialize, JsonSchema)] struct JournalSettingsJson { pub path: Option, pub hour_format: Option, @@ -1223,7 +1227,7 @@ mod tests { } } - #[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] + #[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema)] struct LanguageSettings { #[serde(default)] languages: HashMap, diff --git a/crates/workspace/src/workspace_settings.rs b/crates/workspace/src/workspace_settings.rs index 41e47964910575a06fb0891c5e75d6ced13eefd7..4ec0a22b06800869bce8dcbd0ef13a5e646b2c8b 100644 --- a/crates/workspace/src/workspace_settings.rs +++ b/crates/workspace/src/workspace_settings.rs @@ -17,7 +17,7 @@ pub struct WorkspaceSettings { pub git: GitSettings, } -#[derive(Clone, Serialize, Deserialize, JsonSchema)] +#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)] pub struct WorkspaceSettingsContent { pub active_pane_magnification: Option, pub confirm_quit: Option, From 7190840081212e1013dad588dbb3af913c89b304 Mon Sep 17 00:00:00 2001 From: Julia Date: Mon, 22 May 2023 09:12:36 -0400 Subject: [PATCH 04/19] Add paragraph based vertical movements --- assets/keymaps/default.json | 4 ++ crates/editor/src/editor.rs | 82 +++++++++++++++++++++++++++++++++++ crates/editor/src/movement.rs | 38 ++++++++++++++++ 3 files changed, 124 insertions(+) diff --git a/assets/keymaps/default.json b/assets/keymaps/default.json index 01a09e0cba8f54dc2b436914cf515fcc120d7eff..cab4333f74c30842e2f23927ece00c4c03a398f1 100644 --- a/assets/keymaps/default.json +++ b/assets/keymaps/default.json @@ -67,10 +67,12 @@ "cmd-z": "editor::Undo", "cmd-shift-z": "editor::Redo", "up": "editor::MoveUp", + "ctrl-up": "editor::MoveToStartOfParagraph", "pageup": "editor::PageUp", "shift-pageup": "editor::MovePageUp", "home": "editor::MoveToBeginningOfLine", "down": "editor::MoveDown", + "ctrl-down": "editor::MoveToEndOfParagraph", "pagedown": "editor::PageDown", "shift-pagedown": "editor::MovePageDown", "end": "editor::MoveToEndOfLine", @@ -103,6 +105,8 @@ "alt-shift-b": "editor::SelectToPreviousWordStart", "alt-shift-right": "editor::SelectToNextWordEnd", "alt-shift-f": "editor::SelectToNextWordEnd", + "ctrl-shift-up": "editor::SelectToStartOfParagraph", + "ctrl-shift-down": "editor::SelectToEndOfParagraph", "cmd-shift-up": "editor::SelectToBeginning", "cmd-shift-down": "editor::SelectToEnd", "cmd-a": "editor::SelectAll", diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 7207e3c91c6da9f1e1ecfb37b94a560c875127d3..cf614fccf729ae90ca9ea5f7d527e4979869ef9d 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -216,6 +216,8 @@ actions!( MoveToNextSubwordEnd, MoveToBeginningOfLine, MoveToEndOfLine, + MoveToStartOfParagraph, + MoveToEndOfParagraph, MoveToBeginning, MoveToEnd, SelectUp, @@ -226,6 +228,8 @@ actions!( SelectToPreviousSubwordStart, SelectToNextWordEnd, SelectToNextSubwordEnd, + SelectToStartOfParagraph, + SelectToEndOfParagraph, SelectToBeginning, SelectToEnd, SelectAll, @@ -337,6 +341,8 @@ pub fn init(cx: &mut AppContext) { cx.add_action(Editor::move_to_next_subword_end); cx.add_action(Editor::move_to_beginning_of_line); cx.add_action(Editor::move_to_end_of_line); + cx.add_action(Editor::move_to_start_of_paragraph); + cx.add_action(Editor::move_to_end_of_paragraph); cx.add_action(Editor::move_to_beginning); cx.add_action(Editor::move_to_end); cx.add_action(Editor::select_up); @@ -349,6 +355,8 @@ pub fn init(cx: &mut AppContext) { cx.add_action(Editor::select_to_next_subword_end); cx.add_action(Editor::select_to_beginning_of_line); cx.add_action(Editor::select_to_end_of_line); + cx.add_action(Editor::select_to_start_of_paragraph); + cx.add_action(Editor::select_to_end_of_paragraph); cx.add_action(Editor::select_to_beginning); cx.add_action(Editor::select_to_end); cx.add_action(Editor::select_all); @@ -4762,6 +4770,80 @@ impl Editor { }); } + pub fn move_to_start_of_paragraph( + &mut self, + _: &MoveToStartOfParagraph, + cx: &mut ViewContext, + ) { + if matches!(self.mode, EditorMode::SingleLine) { + cx.propagate_action(); + return; + } + + self.change_selections(Some(Autoscroll::fit()), cx, |s| { + s.move_with(|map, selection| { + selection.collapse_to( + movement::start_of_paragraph(map, selection.head()), + SelectionGoal::None, + ) + }); + }) + } + + pub fn move_to_end_of_paragraph( + &mut self, + _: &MoveToEndOfParagraph, + cx: &mut ViewContext, + ) { + if matches!(self.mode, EditorMode::SingleLine) { + cx.propagate_action(); + return; + } + + self.change_selections(Some(Autoscroll::fit()), cx, |s| { + s.move_with(|map, selection| { + selection.collapse_to( + movement::end_of_paragraph(map, selection.head()), + SelectionGoal::None, + ) + }); + }) + } + + pub fn select_to_start_of_paragraph( + &mut self, + _: &SelectToStartOfParagraph, + cx: &mut ViewContext, + ) { + if matches!(self.mode, EditorMode::SingleLine) { + cx.propagate_action(); + return; + } + + self.change_selections(Some(Autoscroll::fit()), cx, |s| { + s.move_heads_with(|map, head, _| { + (movement::start_of_paragraph(map, head), SelectionGoal::None) + }); + }) + } + + pub fn select_to_end_of_paragraph( + &mut self, + _: &SelectToEndOfParagraph, + cx: &mut ViewContext, + ) { + if matches!(self.mode, EditorMode::SingleLine) { + cx.propagate_action(); + return; + } + + self.change_selections(Some(Autoscroll::fit()), cx, |s| { + s.move_heads_with(|map, head, _| { + (movement::end_of_paragraph(map, head), SelectionGoal::None) + }); + }) + } + pub fn move_to_beginning(&mut self, _: &MoveToBeginning, cx: &mut ViewContext) { if matches!(self.mode, EditorMode::SingleLine) { cx.propagate_action(); diff --git a/crates/editor/src/movement.rs b/crates/editor/src/movement.rs index 6c9bd6cb4fe1554d9a04a840db78ff8edc88b4c9..523a0af9640aa98b3f3e3d7b9fd980768f1e4f89 100644 --- a/crates/editor/src/movement.rs +++ b/crates/editor/src/movement.rs @@ -193,6 +193,44 @@ pub fn next_subword_end(map: &DisplaySnapshot, point: DisplayPoint) -> DisplayPo }) } +pub fn start_of_paragraph(map: &DisplaySnapshot, display_point: DisplayPoint) -> DisplayPoint { + let point = display_point.to_point(map); + if point.row == 0 { + return map.max_point(); + } + + let mut found_non_blank_line = false; + for row in (0..point.row + 1).rev() { + let blank = map.buffer_snapshot.is_line_blank(row); + if found_non_blank_line && blank { + return Point::new(row, 0).to_display_point(map); + } + + found_non_blank_line |= !blank; + } + + DisplayPoint::zero() +} + +pub fn end_of_paragraph(map: &DisplaySnapshot, display_point: DisplayPoint) -> DisplayPoint { + let point = display_point.to_point(map); + if point.row == map.max_buffer_row() { + return DisplayPoint::zero(); + } + + let mut found_non_blank_line = false; + for row in point.row..map.max_buffer_row() + 1 { + let blank = map.buffer_snapshot.is_line_blank(row); + if found_non_blank_line && blank { + return Point::new(row, 0).to_display_point(map); + } + + found_non_blank_line |= !blank; + } + + map.max_point() +} + /// Scans for a boundary preceding the given start point `from` until a boundary is found, indicated by the /// given predicate returning true. The predicate is called with the character to the left and right /// of the candidate boundary location, and will be called with `\n` characters indicating the start From 44903bc193fc0b8ef04990aa3fd9073117fe9514 Mon Sep 17 00:00:00 2001 From: Julia Date: Mon, 22 May 2023 11:48:07 -0400 Subject: [PATCH 05/19] Add test for paragraph vertical movements --- crates/editor/src/editor_tests.rs | 112 ++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) diff --git a/crates/editor/src/editor_tests.rs b/crates/editor/src/editor_tests.rs index 9a21429301b6906e025f87c14659a8594279c11d..180de155e998fff1492c22311502d87ebcf744bf 100644 --- a/crates/editor/src/editor_tests.rs +++ b/crates/editor/src/editor_tests.rs @@ -1243,6 +1243,118 @@ fn test_prev_next_word_bounds_with_soft_wrap(cx: &mut TestAppContext) { }); } +#[gpui::test] +async fn test_move_start_of_paragraph_end_of_paragraph(cx: &mut gpui::TestAppContext) { + init_test(cx, |_| {}); + let mut cx = EditorTestContext::new(cx); + + let line_height = cx.editor(|editor, cx| editor.style(cx).text.line_height(cx.font_cache())); + cx.simulate_window_resize(cx.window_id, vec2f(100., 4. * line_height)); + + cx.set_state( + &r#"ˇone + two + + three + fourˇ + five + + six"# + .unindent(), + ); + + cx.update_editor(|editor, cx| editor.move_to_end_of_paragraph(&MoveToEndOfParagraph, cx)); + cx.assert_editor_state( + &r#"one + two + ˇ + three + four + five + ˇ + six"# + .unindent(), + ); + + cx.update_editor(|editor, cx| editor.move_to_end_of_paragraph(&MoveToEndOfParagraph, cx)); + cx.assert_editor_state( + &r#"one + two + + three + four + five + ˇ + sixˇ"# + .unindent(), + ); + + cx.update_editor(|editor, cx| editor.move_to_end_of_paragraph(&MoveToEndOfParagraph, cx)); + cx.assert_editor_state( + &r#"ˇone + two + + three + four + five + + sixˇ"# + .unindent(), + ); + + cx.update_editor(|editor, cx| editor.move_to_end_of_paragraph(&MoveToEndOfParagraph, cx)); + cx.assert_editor_state( + &r#"ˇone + two + ˇ + three + four + five + + six"# + .unindent(), + ); + + cx.update_editor(|editor, cx| editor.move_to_start_of_paragraph(&MoveToStartOfParagraph, cx)); + cx.assert_editor_state( + &r#"ˇone + two + + three + four + five + + sixˇ"# + .unindent(), + ); + + cx.update_editor(|editor, cx| editor.move_to_start_of_paragraph(&MoveToStartOfParagraph, cx)); + cx.assert_editor_state( + &r#"one + two + + three + four + five + ˇ + sixˇ"# + .unindent(), + ); + + cx.update_editor(|editor, cx| editor.move_to_start_of_paragraph(&MoveToStartOfParagraph, cx)); + cx.assert_editor_state( + &r#"one + two + ˇ + three + four + five + ˇ + six"# + .unindent(), + ); +} + #[gpui::test] async fn test_move_page_up_page_down(cx: &mut gpui::TestAppContext) { init_test(cx, |_| {}); From 21ada545b07030398a90bf1ef1dbe386cb6cd26c Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 22 May 2023 08:48:37 -0700 Subject: [PATCH 06/19] Remove assertions about behavior on invalid settings file --- crates/settings/src/settings_store.rs | 31 --------------------------- 1 file changed, 31 deletions(-) diff --git a/crates/settings/src/settings_store.rs b/crates/settings/src/settings_store.rs index 329b290a3192c66545e7001635917e448acc1e81..71b3cc635f4e03465d94cb498567c21bd36bd76a 100644 --- a/crates/settings/src/settings_store.rs +++ b/crates/settings/src/settings_store.rs @@ -830,37 +830,6 @@ mod tests { store.register_setting::(cx); store.register_setting::(cx); store.register_setting::(cx); - - // error - missing required field in default settings - store - .set_default_settings( - r#"{ - "user": { - "name": "John Doe", - "age": 30, - "staff": false - } - }"#, - cx, - ) - .unwrap_err(); - - // error - type error in default settings - store - .set_default_settings( - r#"{ - "turbo": "the-wrong-type", - "user": { - "name": "John Doe", - "age": 30, - "staff": false - } - }"#, - cx, - ) - .unwrap_err(); - - // valid default settings. store .set_default_settings( r#"{ From 8669dcdc81332f1d3f1cf89a45d3e919a6349277 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Mon, 22 May 2023 10:55:44 -0700 Subject: [PATCH 07/19] Make scrollbar content detection cheaper Remove scrollbars from multibuffers co-authored-by: max --- crates/editor/src/editor.rs | 8 +-- crates/editor/src/element.rs | 93 ++++++++++++++++--------------- crates/editor/src/multi_buffer.rs | 9 +++ crates/git/src/diff.rs | 4 ++ 4 files changed, 65 insertions(+), 49 deletions(-) diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 7207e3c91c6da9f1e1ecfb37b94a560c875127d3..0a4204ba2a0b635aec36818bc68cefb7ceb9a2fa 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -526,11 +526,9 @@ pub struct EditorSnapshot { } impl EditorSnapshot { - fn has_scrollbar_info(&self) -> bool { - self.buffer_snapshot - .git_diff_hunks_in_range(0..self.max_point().row()) - .next() - .is_some() + fn has_scrollbar_info(&self, is_singleton: bool) -> bool { + is_singleton && self.buffer_snapshot + .has_git_diffs() } } diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 57dc3293f6f9dc322c1a7744f97b21000fb34c0c..5a057390d58ac7c8f01138166b531085492948a7 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -1052,51 +1052,53 @@ impl EditorElement { ..Default::default() }); - let diff_style = theme::current(cx).editor.diff.clone(); - for hunk in layout - .position_map - .snapshot - .buffer_snapshot - .git_diff_hunks_in_range(0..(max_row.floor() as u32)) - { - let start_display = Point::new(hunk.buffer_range.start, 0) - .to_display_point(&layout.position_map.snapshot.display_snapshot); - let end_display = Point::new(hunk.buffer_range.end, 0) - .to_display_point(&layout.position_map.snapshot.display_snapshot); - let start_y = y_for_row(start_display.row() as f32); - let mut end_y = if hunk.buffer_range.start == hunk.buffer_range.end { - y_for_row((end_display.row() + 1) as f32) - } else { - y_for_row((end_display.row()) as f32) - }; + if layout.is_singleton { + let diff_style = theme::current(cx).editor.diff.clone(); + for hunk in layout + .position_map + .snapshot + .buffer_snapshot + .git_diff_hunks_in_range(0..(max_row.floor() as u32)) + { + let start_display = Point::new(hunk.buffer_range.start, 0) + .to_display_point(&layout.position_map.snapshot.display_snapshot); + let end_display = Point::new(hunk.buffer_range.end, 0) + .to_display_point(&layout.position_map.snapshot.display_snapshot); + let start_y = y_for_row(start_display.row() as f32); + let mut end_y = if hunk.buffer_range.start == hunk.buffer_range.end { + y_for_row((end_display.row() + 1) as f32) + } else { + y_for_row((end_display.row()) as f32) + }; - if end_y - start_y < 1. { - end_y = start_y + 1.; - } - let bounds = RectF::from_points(vec2f(left, start_y), vec2f(right, end_y)); - - let color = match hunk.status() { - DiffHunkStatus::Added => diff_style.inserted, - DiffHunkStatus::Modified => diff_style.modified, - DiffHunkStatus::Removed => diff_style.deleted, - }; - - let border = Border { - width: 1., - color: style.thumb.border.color, - overlay: false, - top: false, - right: true, - bottom: false, - left: true, - }; + if end_y - start_y < 1. { + end_y = start_y + 1.; + } + let bounds = RectF::from_points(vec2f(left, start_y), vec2f(right, end_y)); - scene.push_quad(Quad { - bounds, - background: Some(color), - border, - corner_radius: style.thumb.corner_radius, - }) + let color = match hunk.status() { + DiffHunkStatus::Added => diff_style.inserted, + DiffHunkStatus::Modified => diff_style.modified, + DiffHunkStatus::Removed => diff_style.deleted, + }; + + let border = Border { + width: 1., + color: style.thumb.border.color, + overlay: false, + top: false, + right: true, + bottom: false, + left: true, + }; + + scene.push_quad(Quad { + bounds, + background: Some(color), + border, + corner_radius: style.thumb.corner_radius, + }) + } } scene.push_quad(Quad { @@ -2067,7 +2069,8 @@ impl Element for EditorElement { let show_scrollbars = match settings::get::(cx).show_scrollbars { ShowScrollbars::Auto => { - snapshot.has_scrollbar_info() || editor.scroll_manager.scrollbars_visible() + snapshot.has_scrollbar_info(is_singleton) + || editor.scroll_manager.scrollbars_visible() } ShowScrollbars::System => editor.scroll_manager.scrollbars_visible(), ShowScrollbars::Always => true, @@ -2290,6 +2293,7 @@ impl Element for EditorElement { text_size, scrollbar_row_range, show_scrollbars, + is_singleton, max_row, gutter_margin, active_rows, @@ -2445,6 +2449,7 @@ pub struct LayoutState { selections: Vec<(ReplicaId, Vec)>, scrollbar_row_range: Range, show_scrollbars: bool, + is_singleton: bool, max_row: u32, context_menu: Option<(DisplayPoint, AnyElement)>, code_actions_indicator: Option<(u32, AnyElement)>, diff --git a/crates/editor/src/multi_buffer.rs b/crates/editor/src/multi_buffer.rs index 1423473e1ad8c3d952d6bb47ef95d20286e0a46f..6a617756974ee5a2021c1377ba2edb00468aa304 100644 --- a/crates/editor/src/multi_buffer.rs +++ b/crates/editor/src/multi_buffer.rs @@ -2841,6 +2841,15 @@ impl MultiBufferSnapshot { }) } + pub fn has_git_diffs(&self) -> bool { + for excerpt in self.excerpts.iter() { + if !excerpt.buffer.git_diff.is_empty() { + return true; + } + } + false + } + pub fn git_diff_hunks_in_range_rev<'a>( &'a self, row_range: Range, diff --git a/crates/git/src/diff.rs b/crates/git/src/diff.rs index 8704f850055aa4edb5f03109ecd1fa5d18d4aa5c..8260dfc98d9834f8cefff6dfc274a4d7a9e237d7 100644 --- a/crates/git/src/diff.rs +++ b/crates/git/src/diff.rs @@ -71,6 +71,10 @@ impl BufferDiff { } } + pub fn is_empty(&self) -> bool { + self.tree.is_empty() + } + pub fn hunks_in_row_range<'a>( &'a self, range: Range, From 6264b2478809b807e36dc33f0aa27be421bf5c0c Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Mon, 22 May 2023 11:04:36 -0700 Subject: [PATCH 08/19] fmt --- crates/editor/src/editor.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 0a4204ba2a0b635aec36818bc68cefb7ceb9a2fa..12f5b3b872f6c51fb5b33324c249e77659d3785e 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -527,8 +527,7 @@ pub struct EditorSnapshot { impl EditorSnapshot { fn has_scrollbar_info(&self, is_singleton: bool) -> bool { - is_singleton && self.buffer_snapshot - .has_git_diffs() + is_singleton && self.buffer_snapshot.has_git_diffs() } } From 6f4b6eec5b2584c33602928a0bc64f9f0af18f01 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Mon, 22 May 2023 11:10:13 -0700 Subject: [PATCH 09/19] Diagnostics pane was not focusable with the mouse --- crates/diagnostics/src/diagnostics.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/crates/diagnostics/src/diagnostics.rs b/crates/diagnostics/src/diagnostics.rs index a202a6082c0522901a349c9537e49a2fe7e2c6b8..27f75ea89680de1cc6fbe80d909edc33503dd690 100644 --- a/crates/diagnostics/src/diagnostics.rs +++ b/crates/diagnostics/src/diagnostics.rs @@ -33,7 +33,7 @@ use theme::ThemeSettings; use util::TryFutureExt; use workspace::{ item::{BreadcrumbText, Item, ItemEvent, ItemHandle}, - ItemNavHistory, Pane, ToolbarItemLocation, Workspace, + ItemNavHistory, Pane, ToolbarItemLocation, Workspace, PaneBackdrop, }; actions!(diagnostics, [Deploy]); @@ -90,11 +90,12 @@ impl View for ProjectDiagnosticsEditor { fn render(&mut self, cx: &mut ViewContext) -> AnyElement { if self.path_states.is_empty() { let theme = &theme::current(cx).project_diagnostics; - Label::new("No problems in workspace", theme.empty_message.clone()) + PaneBackdrop::new(cx.view_id(), Label::new("No problems in workspace", theme.empty_message.clone()) .aligned() .contained() .with_style(theme.container) - .into_any() + .into_any()).into_any() + } else { ChildView::new(&self.editor, cx).into_any() } From 04355215b2d1489a763345ac73078399bad7d18f Mon Sep 17 00:00:00 2001 From: Joseph Lyons Date: Mon, 22 May 2023 14:44:05 -0400 Subject: [PATCH 10/19] Indent all release note lines for each PR --- script/get-preview-channel-changes | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/script/get-preview-channel-changes b/script/get-preview-channel-changes index 47623125f9c28fa12898a21d1a629c69fcf6158e..5a0be3ed6669233bb50e001320259f09c626c288 100755 --- a/script/get-preview-channel-changes +++ b/script/get-preview-channel-changes @@ -69,9 +69,12 @@ async function main() { let releaseNotes = (pullRequest.body || "").split("Release Notes:")[1]; if (releaseNotes) { - releaseNotes = releaseNotes.trim(); + releaseNotes = releaseNotes.trim().split("\n") console.log(" Release Notes:"); - console.log(` ${releaseNotes}`); + + for (const line of releaseNotes) { + console.log(` ${line}`); + } } console.log() From e59c8e9d611405eb7063751f2ba87d2d0bc72324 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Mon, 22 May 2023 11:44:23 -0700 Subject: [PATCH 11/19] Fix diagnostic pane not being closeable --- crates/diagnostics/src/diagnostics.rs | 26 +++++++++++++++++--------- crates/editor/src/editor.rs | 2 ++ 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/crates/diagnostics/src/diagnostics.rs b/crates/diagnostics/src/diagnostics.rs index 27f75ea89680de1cc6fbe80d909edc33503dd690..182efdfdd6c520e30d285ed822f66f9a3f98a368 100644 --- a/crates/diagnostics/src/diagnostics.rs +++ b/crates/diagnostics/src/diagnostics.rs @@ -33,7 +33,7 @@ use theme::ThemeSettings; use util::TryFutureExt; use workspace::{ item::{BreadcrumbText, Item, ItemEvent, ItemHandle}, - ItemNavHistory, Pane, ToolbarItemLocation, Workspace, PaneBackdrop, + ItemNavHistory, Pane, PaneBackdrop, ToolbarItemLocation, Workspace, }; actions!(diagnostics, [Deploy]); @@ -90,12 +90,15 @@ impl View for ProjectDiagnosticsEditor { fn render(&mut self, cx: &mut ViewContext) -> AnyElement { if self.path_states.is_empty() { let theme = &theme::current(cx).project_diagnostics; - PaneBackdrop::new(cx.view_id(), Label::new("No problems in workspace", theme.empty_message.clone()) - .aligned() - .contained() - .with_style(theme.container) - .into_any()).into_any() - + PaneBackdrop::new( + cx.view_id(), + Label::new("No problems in workspace", theme.empty_message.clone()) + .aligned() + .contained() + .with_style(theme.container) + .into_any(), + ) + .into_any() } else { ChildView::new(&self.editor, cx).into_any() } @@ -162,8 +165,13 @@ impl ProjectDiagnosticsEditor { editor.set_vertical_scroll_margin(5, cx); editor }); - cx.subscribe(&editor, |_, _, event, cx| cx.emit(event.clone())) - .detach(); + cx.subscribe(&editor, |this, _, event, cx| { + cx.emit(event.clone()); + if event == &editor::Event::Focused && this.path_states.is_empty() { + cx.focus_self() + } + }) + .detach(); let project = project_handle.read(cx); let paths_to_update = project diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 7207e3c91c6da9f1e1ecfb37b94a560c875127d3..94fa23939bcdcfe0958945cad8fdc726c1720693 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -7128,6 +7128,7 @@ pub enum Event { BufferEdited, Edited, Reparsed, + Focused, Blurred, DirtyChanged, Saved, @@ -7181,6 +7182,7 @@ impl View for Editor { fn focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext) { if cx.is_self_focused() { let focused_event = EditorFocused(cx.handle()); + cx.emit(Event::Focused); cx.emit_global(focused_event); } if let Some(rename) = self.pending_rename.as_ref() { From bafc1d922e756cd369bea7cada4c85bc0c561595 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Mon, 22 May 2023 11:46:52 -0700 Subject: [PATCH 12/19] fmt --- crates/diagnostics/src/diagnostics.rs | 5 +++-- crates/editor/src/editor.rs | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/crates/diagnostics/src/diagnostics.rs b/crates/diagnostics/src/diagnostics.rs index 182efdfdd6c520e30d285ed822f66f9a3f98a368..29ea1273e24f4cf62942ad9627448920467cb1b1 100644 --- a/crates/diagnostics/src/diagnostics.rs +++ b/crates/diagnostics/src/diagnostics.rs @@ -105,8 +105,9 @@ impl View for ProjectDiagnosticsEditor { } fn focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext) { - if cx.is_self_focused() && !self.path_states.is_empty() { - cx.focus(&self.editor); + dbg!("Focus in"); + if dbg!(cx.is_self_focused()) && dbg!(!self.path_states.is_empty()) { + dbg!(cx.focus(&self.editor)); } } diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 94fa23939bcdcfe0958945cad8fdc726c1720693..6a43e5a93b86284c3547bcc6656bad3b0eab1e55 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -7180,6 +7180,7 @@ impl View for Editor { } fn focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext) { + dbg!("Editor Focus in"); if cx.is_self_focused() { let focused_event = EditorFocused(cx.handle()); cx.emit(Event::Focused); From 9c32b774aad9c152fd330f801a842ac2c8676720 Mon Sep 17 00:00:00 2001 From: Joseph Lyons Date: Mon, 22 May 2023 14:53:07 -0400 Subject: [PATCH 13/19] Add example of changelog line in PR template --- .github/pull_request_template.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 8d16a59bc12852ec9f06f3efa7ff43e0d333c038..f66fdce683a1d8633e25710e172b2ec1d553503a 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -2,4 +2,5 @@ Release Notes: -* [[Added foo / Fixed bar / No notes]] +* (Added|Fixed|Improved) ... ([#](https://github.com/zed-industries/community/issues/)). +* ... From 49566e5677affcf3a7a1378897ebf14ba61f07c3 Mon Sep 17 00:00:00 2001 From: Joseph Lyons Date: Mon, 22 May 2023 15:00:57 -0400 Subject: [PATCH 14/19] Update pull_request_template.md --- .github/pull_request_template.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index f66fdce683a1d8633e25710e172b2ec1d553503a..67a7ed31c9b5a4cfbf3ab6881c627b1a9db126c5 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -2,5 +2,12 @@ Release Notes: -* (Added|Fixed|Improved) ... ([#](https://github.com/zed-industries/community/issues/)). +Use `N/A` in this section if this item should be skipped in the release notes. + +Add release note lines here: + +* (Added|Fixed|Improved) ... ([#](https://github.com/zed-industries/community/issues/)). * ... + +If the release notes are only intended for a specific release channel only, add `(-only)` to the end of the release note line. +These will be removed by the person making the release. From 366f13bb5c5a9fa41c75deff76ee400ac9a7a31a Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Mon, 22 May 2023 12:12:56 -0700 Subject: [PATCH 15/19] Adjust scrollbar settings to be expandable --- assets/settings/default.json | 31 ++++++++++++++++------------ crates/editor/src/editor.rs | 6 ------ crates/editor/src/editor_settings.rs | 18 +++++++++++++--- crates/editor/src/element.rs | 21 +++++++++++-------- 4 files changed, 45 insertions(+), 31 deletions(-) diff --git a/assets/settings/default.json b/assets/settings/default.json index 4f149edb1053d10dfb6ae4764b439978f5130825..84db3f8ea1be70aa1243664a5bb5de3b04abf25a 100644 --- a/assets/settings/default.json +++ b/assets/settings/default.json @@ -52,19 +52,24 @@ // 3. Draw all invisible symbols: // "all" "show_whitespaces": "selection", - // Whether to show the scrollbar in the editor. - // This setting can take four values: - // - // 1. Show the scrollbar if there's important information or - // follow the system's configured behavior (default): - // "auto" - // 2. Match the system's configured behavior: - // "system" - // 3. Always show the scrollbar: - // "always" - // 4. Never show the scrollbar: - // "never" - "show_scrollbars": "auto", + // Scrollbar related settings + "scrollbar": { + // When to show the scrollbar in the editor. + // This setting can take four values: + // + // 1. Show the scrollbar if there's important information or + // follow the system's configured behavior (default): + // "auto" + // 2. Match the system's configured behavior: + // "system" + // 3. Always show the scrollbar: + // "always" + // 4. Never show the scrollbar: + // "never" + "when_to_show": "auto", + // Whether to show git diff indicators in the scrollbar. + "git_diff": true + }, // Whether the screen sharing icon is shown in the os status bar. "show_call_status_icon": true, // Whether to use language servers to provide code intelligence. diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 814435059ee9f9df5406a1ec1d786263a6971439..d8bf71e2f292490c4bc8a0f808194dbb1d48915a 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -533,12 +533,6 @@ pub struct EditorSnapshot { ongoing_scroll: OngoingScroll, } -impl EditorSnapshot { - fn has_scrollbar_info(&self, is_singleton: bool) -> bool { - is_singleton && self.buffer_snapshot.has_git_diffs() - } -} - #[derive(Clone, Debug)] struct SelectionHistoryEntry { selections: Arc<[Selection]>, diff --git a/crates/editor/src/editor_settings.rs b/crates/editor/src/editor_settings.rs index a3f38a3dc096c6a4ce8365911313c31c147d06e7..05045ca49067727edc01468cc29517715a8ecc9f 100644 --- a/crates/editor/src/editor_settings.rs +++ b/crates/editor/src/editor_settings.rs @@ -7,12 +7,18 @@ pub struct EditorSettings { pub cursor_blink: bool, pub hover_popover_enabled: bool, pub show_completions_on_input: bool, - pub show_scrollbars: ShowScrollbars, + pub scrollbar: Scrollbar, +} + +#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] +pub struct Scrollbar { + pub when_to_show: ShowScrollbar, + pub git_diff: bool } #[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] #[serde(rename_all = "snake_case")] -pub enum ShowScrollbars { +pub enum ShowScrollbar { Auto, System, Always, @@ -24,7 +30,13 @@ pub struct EditorSettingsContent { pub cursor_blink: Option, pub hover_popover_enabled: Option, pub show_completions_on_input: Option, - pub show_scrollbars: Option, + pub scrollbar: Option, +} + +#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] +pub struct ScrollbarContent { + pub when_to_show: Option, + pub git_diff: Option } impl Setting for EditorSettings { diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 5a057390d58ac7c8f01138166b531085492948a7..b5e09fc86c20e2897c1a45fbac5ee2efb10c0651 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -5,7 +5,7 @@ use super::{ }; use crate::{ display_map::{BlockStyle, DisplaySnapshot, FoldStatus, TransformBlock}, - editor_settings::ShowScrollbars, + editor_settings::ShowScrollbar, git::{diff_hunk_to_display, DisplayDiffHunk}, hover_popover::{ hide_hover, hover_at, HOVER_POPOVER_GAP, MIN_POPOVER_CHARACTER_WIDTH, @@ -1052,7 +1052,7 @@ impl EditorElement { ..Default::default() }); - if layout.is_singleton { + if layout.is_singleton && settings::get::(cx).scrollbar.git_diff { let diff_style = theme::current(cx).editor.diff.clone(); for hunk in layout .position_map @@ -2067,14 +2067,17 @@ impl Element for EditorElement { )); } - let show_scrollbars = match settings::get::(cx).show_scrollbars { - ShowScrollbars::Auto => { - snapshot.has_scrollbar_info(is_singleton) - || editor.scroll_manager.scrollbars_visible() + let scrollbar_settings = &settings::get::(cx).scrollbar; + let show_scrollbars = match scrollbar_settings.when_to_show { + ShowScrollbar::Auto => { + // Git + (is_singleton && scrollbar_settings.git_diff && snapshot.buffer_snapshot.has_git_diffs()) + // Scrollmanager + || editor.scroll_manager.scrollbars_visible() } - ShowScrollbars::System => editor.scroll_manager.scrollbars_visible(), - ShowScrollbars::Always => true, - ShowScrollbars::Never => false, + ShowScrollbar::System => editor.scroll_manager.scrollbars_visible(), + ShowScrollbar::Always => true, + ShowScrollbar::Never => false, }; let include_root = editor From 687ccd4c6feb25031f9a490257e87ea624159493 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Mon, 22 May 2023 12:13:23 -0700 Subject: [PATCH 16/19] fmt --- crates/editor/src/editor_settings.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/editor/src/editor_settings.rs b/crates/editor/src/editor_settings.rs index 05045ca49067727edc01468cc29517715a8ecc9f..d97006e5839248960edc3e0b35dc61890613dcaa 100644 --- a/crates/editor/src/editor_settings.rs +++ b/crates/editor/src/editor_settings.rs @@ -13,7 +13,7 @@ pub struct EditorSettings { #[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] pub struct Scrollbar { pub when_to_show: ShowScrollbar, - pub git_diff: bool + pub git_diff: bool, } #[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] @@ -36,7 +36,7 @@ pub struct EditorSettingsContent { #[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] pub struct ScrollbarContent { pub when_to_show: Option, - pub git_diff: Option + pub git_diff: Option, } impl Setting for EditorSettings { From cfdf9198dac938140daa662325bd5c043e69cbe0 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Mon, 22 May 2023 12:16:47 -0700 Subject: [PATCH 17/19] Switch back to --- assets/settings/default.json | 2 +- crates/editor/src/editor_settings.rs | 4 ++-- crates/editor/src/element.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/assets/settings/default.json b/assets/settings/default.json index 84db3f8ea1be70aa1243664a5bb5de3b04abf25a..e4e7a8c522d3585dda3ef9ac05a01d37b72bcda5 100644 --- a/assets/settings/default.json +++ b/assets/settings/default.json @@ -66,7 +66,7 @@ // "always" // 4. Never show the scrollbar: // "never" - "when_to_show": "auto", + "show": "auto", // Whether to show git diff indicators in the scrollbar. "git_diff": true }, diff --git a/crates/editor/src/editor_settings.rs b/crates/editor/src/editor_settings.rs index d97006e5839248960edc3e0b35dc61890613dcaa..7f01834b161b8f1db75a40145694f1c80e473755 100644 --- a/crates/editor/src/editor_settings.rs +++ b/crates/editor/src/editor_settings.rs @@ -12,7 +12,7 @@ pub struct EditorSettings { #[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] pub struct Scrollbar { - pub when_to_show: ShowScrollbar, + pub show: ShowScrollbar, pub git_diff: bool, } @@ -35,7 +35,7 @@ pub struct EditorSettingsContent { #[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] pub struct ScrollbarContent { - pub when_to_show: Option, + pub show: Option, pub git_diff: Option, } diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index b5e09fc86c20e2897c1a45fbac5ee2efb10c0651..13a24bfc2c1f884dc2dc1d8cc916e6fc22855ea4 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -2068,7 +2068,7 @@ impl Element for EditorElement { } let scrollbar_settings = &settings::get::(cx).scrollbar; - let show_scrollbars = match scrollbar_settings.when_to_show { + let show_scrollbars = match scrollbar_settings.show { ShowScrollbar::Auto => { // Git (is_singleton && scrollbar_settings.git_diff && snapshot.buffer_snapshot.has_git_diffs()) From 7689cdf3f944f44e28f14da389c07f4c417df47d Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 22 May 2023 12:53:22 -0700 Subject: [PATCH 18/19] Clear old diagnostics when restarting a language server --- crates/language/src/buffer.rs | 15 +++-- crates/language/src/diagnostic_set.rs | 4 ++ crates/project/src/project.rs | 17 +++++ crates/project/src/project_tests.rs | 89 +++++++++++++++++++++++++++ crates/project/src/worktree.rs | 39 ++++++++++++ 5 files changed, 160 insertions(+), 4 deletions(-) diff --git a/crates/language/src/buffer.rs b/crates/language/src/buffer.rs index 3a977024873baa82d39e50bae06a3e3e43b7f254..5539d1d941726148fc543a59652d57190e1d400d 100644 --- a/crates/language/src/buffer.rs +++ b/crates/language/src/buffer.rs @@ -1644,10 +1644,17 @@ impl Buffer { cx: &mut ModelContext, ) { if lamport_timestamp > self.diagnostics_timestamp { - match self.diagnostics.binary_search_by_key(&server_id, |e| e.0) { - Err(ix) => self.diagnostics.insert(ix, (server_id, diagnostics)), - Ok(ix) => self.diagnostics[ix].1 = diagnostics, - }; + let ix = self.diagnostics.binary_search_by_key(&server_id, |e| e.0); + if diagnostics.len() == 0 { + if let Ok(ix) = ix { + self.diagnostics.remove(ix); + } + } else { + match ix { + Err(ix) => self.diagnostics.insert(ix, (server_id, diagnostics)), + Ok(ix) => self.diagnostics[ix].1 = diagnostics, + }; + } self.diagnostics_timestamp = lamport_timestamp; self.diagnostics_update_count += 1; self.text.lamport_clock.observe(lamport_timestamp); diff --git a/crates/language/src/diagnostic_set.rs b/crates/language/src/diagnostic_set.rs index 948a7ee39471579a4cc9a8553b700ccf26c2b9ae..f269fce88d694c8efe2f255e302bbef7aed865ea 100644 --- a/crates/language/src/diagnostic_set.rs +++ b/crates/language/src/diagnostic_set.rs @@ -80,6 +80,10 @@ impl DiagnosticSet { } } + pub fn len(&self) -> usize { + self.diagnostics.summary().count + } + pub fn iter(&self) -> impl Iterator> { self.diagnostics.iter() } diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index f91cd999f9dd0068f98ae9f30fda3067469481d2..5b5d9038224925f1882b544e280083f546238c77 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -2565,6 +2565,23 @@ impl Project { } } + for buffer in self.opened_buffers.values() { + if let Some(buffer) = buffer.upgrade(cx) { + buffer.update(cx, |buffer, cx| { + buffer.update_diagnostics(server_id, Default::default(), cx); + }); + } + } + for worktree in &self.worktrees { + if let Some(worktree) = worktree.upgrade(cx) { + worktree.update(cx, |worktree, cx| { + if let Some(worktree) = worktree.as_local_mut() { + worktree.clear_diagnostics_for_language_server(server_id, cx); + } + }); + } + } + self.language_server_statuses.remove(&server_id); cx.notify(); diff --git a/crates/project/src/project_tests.rs b/crates/project/src/project_tests.rs index 69bcea8ce0426f7fe812618542336f3a018262f3..e48ce6258b34f38f438dd6035a533a99a0be5d0a 100644 --- a/crates/project/src/project_tests.rs +++ b/crates/project/src/project_tests.rs @@ -926,6 +926,95 @@ async fn test_restarting_server_with_diagnostics_running(cx: &mut gpui::TestAppC }); } +#[gpui::test] +async fn test_restarting_server_with_diagnostics_published(cx: &mut gpui::TestAppContext) { + init_test(cx); + + let mut language = Language::new( + LanguageConfig { + path_suffixes: vec!["rs".to_string()], + ..Default::default() + }, + None, + ); + let mut fake_servers = language + .set_fake_lsp_adapter(Arc::new(FakeLspAdapter { + ..Default::default() + })) + .await; + + let fs = FakeFs::new(cx.background()); + fs.insert_tree("/dir", json!({ "a.rs": "x" })).await; + + let project = Project::test(fs, ["/dir".as_ref()], cx).await; + project.update(cx, |project, _| project.languages.add(Arc::new(language))); + + let buffer = project + .update(cx, |project, cx| project.open_local_buffer("/dir/a.rs", cx)) + .await + .unwrap(); + + // Publish diagnostics + let fake_server = fake_servers.next().await.unwrap(); + fake_server.notify::(lsp::PublishDiagnosticsParams { + uri: Url::from_file_path("/dir/a.rs").unwrap(), + version: None, + diagnostics: vec![lsp::Diagnostic { + range: lsp::Range::new(lsp::Position::new(0, 0), lsp::Position::new(0, 0)), + severity: Some(lsp::DiagnosticSeverity::ERROR), + message: "the message".to_string(), + ..Default::default() + }], + }); + + cx.foreground().run_until_parked(); + buffer.read_with(cx, |buffer, _| { + assert_eq!( + buffer + .snapshot() + .diagnostics_in_range::<_, usize>(0..1, false) + .map(|entry| entry.diagnostic.message.clone()) + .collect::>(), + ["the message".to_string()] + ); + }); + project.read_with(cx, |project, cx| { + assert_eq!( + project.diagnostic_summary(cx), + DiagnosticSummary { + error_count: 1, + warning_count: 0, + } + ); + }); + + project.update(cx, |project, cx| { + project.restart_language_servers_for_buffers([buffer.clone()], cx); + }); + + // The diagnostics are cleared. + cx.foreground().run_until_parked(); + buffer.read_with(cx, |buffer, _| { + assert_eq!( + buffer + .snapshot() + .diagnostics_in_range::<_, usize>(0..1, false) + .map(|entry| entry.diagnostic.message.clone()) + .collect::>(), + Vec::::new(), + ); + }); + project.read_with(cx, |project, cx| { + assert_eq!( + project.diagnostic_summary(cx), + DiagnosticSummary { + error_count: 0, + warning_count: 0, + } + ); + }); +} + #[gpui::test] async fn test_restarted_server_reporting_invalid_buffer_version(cx: &mut gpui::TestAppContext) { init_test(cx); diff --git a/crates/project/src/worktree.rs b/crates/project/src/worktree.rs index 4f898aa91d2558c606b39dda29b83ea6ff24a3d8..7df99b577bfde01b0f405c0dc5a0bf9a1002e4c4 100644 --- a/crates/project/src/worktree.rs +++ b/crates/project/src/worktree.rs @@ -737,6 +737,45 @@ impl LocalWorktree { self.diagnostics.get(path).cloned().unwrap_or_default() } + pub fn clear_diagnostics_for_language_server( + &mut self, + server_id: LanguageServerId, + _: &mut ModelContext, + ) { + let worktree_id = self.id().to_proto(); + self.diagnostic_summaries + .retain(|path, summaries_by_server_id| { + if summaries_by_server_id.remove(&server_id).is_some() { + if let Some(share) = self.share.as_ref() { + self.client + .send(proto::UpdateDiagnosticSummary { + project_id: share.project_id, + worktree_id, + summary: Some(proto::DiagnosticSummary { + path: path.to_string_lossy().to_string(), + language_server_id: server_id.0 as u64, + error_count: 0, + warning_count: 0, + }), + }) + .log_err(); + } + !summaries_by_server_id.is_empty() + } else { + true + } + }); + + self.diagnostics.retain(|_, diagnostics_by_server_id| { + if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) { + diagnostics_by_server_id.remove(ix); + !diagnostics_by_server_id.is_empty() + } else { + true + } + }); + } + pub fn update_diagnostics( &mut self, server_id: LanguageServerId, From 96224fa7e84e97779911f17a9e1e65dd446cd71a Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Mon, 22 May 2023 13:57:07 -0700 Subject: [PATCH 19/19] Only fire update diff base when the dot repo is scanned --- crates/project/src/worktree.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/project/src/worktree.rs b/crates/project/src/worktree.rs index 4f898aa91d2558c606b39dda29b83ea6ff24a3d8..8d0896d2d1b66001b538c2f33e909e80d9650b71 100644 --- a/crates/project/src/worktree.rs +++ b/crates/project/src/worktree.rs @@ -329,7 +329,7 @@ pub struct LocalMutableSnapshot { #[derive(Debug, Clone)] pub struct LocalRepositoryEntry { pub(crate) scan_id: usize, - pub(crate) full_scan_id: usize, + pub(crate) git_dir_scan_id: usize, pub(crate) repo_ptr: Arc>, /// Path to the actual .git folder. /// Note: if .git is a file, this points to the folder indicated by the .git file @@ -830,7 +830,7 @@ impl LocalWorktree { old_repos.next(); } Ordering::Equal => { - if old_repo.scan_id != new_repo.scan_id { + if old_repo.git_dir_scan_id != new_repo.git_dir_scan_id { if let Some(entry) = self.entry_for_id(**new_entry_id) { diff.insert(entry.path.clone(), (*new_repo).clone()); } @@ -2006,7 +2006,7 @@ impl LocalSnapshot { work_dir_id, LocalRepositoryEntry { scan_id, - full_scan_id: scan_id, + git_dir_scan_id: scan_id, repo_ptr: repo, git_dir_path: parent_path.clone(), }, @@ -3166,7 +3166,7 @@ impl BackgroundScanner { snapshot.build_repo(dot_git_dir.into(), fs); return None; }; - if repo.full_scan_id == scan_id { + if repo.git_dir_scan_id == scan_id { return None; } (*entry_id, repo.repo_ptr.to_owned()) @@ -3183,7 +3183,7 @@ impl BackgroundScanner { snapshot.git_repositories.update(&entry_id, |entry| { entry.scan_id = scan_id; - entry.full_scan_id = scan_id; + entry.git_dir_scan_id = scan_id; }); snapshot.repository_entries.update(&work_dir, |entry| { @@ -3212,7 +3212,7 @@ impl BackgroundScanner { let local_repo = snapshot.get_local_repo(&repo)?.to_owned(); // Short circuit if we've already scanned everything - if local_repo.full_scan_id == scan_id { + if local_repo.git_dir_scan_id == scan_id { return None; }