From fbf1552be910a61e9a5a237d836847736fc197ae Mon Sep 17 00:00:00 2001 From: Sergey Onufrienko Date: Mon, 10 Jul 2023 20:41:39 +0100 Subject: [PATCH 01/41] Add color_family to theme --- styles/src/theme/create_theme.ts | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/styles/src/theme/create_theme.ts b/styles/src/theme/create_theme.ts index d2701f8341af973a3a4511c149c983cb221fa14d..3f4a0766547534d39e43546c722cd2179ce628b1 100644 --- a/styles/src/theme/create_theme.ts +++ b/styles/src/theme/create_theme.ts @@ -1,4 +1,4 @@ -import { Scale, Color } from "chroma-js" +import chroma, { Scale, Color } from "chroma-js" import { Syntax, ThemeSyntax, SyntaxHighlightStyle } from "./syntax" export { Syntax, ThemeSyntax, SyntaxHighlightStyle } import { @@ -32,6 +32,7 @@ export interface Theme { players: Players syntax?: Partial + color_family: ColorFamily } export interface Meta { @@ -69,6 +70,12 @@ export interface Players { "7": Player } +export interface ColorFamily { + range: ColorFamilyRange +} + +export type ColorFamilyRange = Partial<{ [K in keyof RampSet]: number }> + export interface Shadow { blur: number color: string @@ -162,6 +169,10 @@ export function create_theme(theme: ThemeConfig): Theme { "7": player(ramps.yellow), } + const color_family = { + range: build_color_family(ramps) + } + return { name, is_light, @@ -177,6 +188,7 @@ export function create_theme(theme: ThemeConfig): Theme { players, syntax, + color_family, } } @@ -187,6 +199,16 @@ function player(ramp: Scale): Player { } } +function build_color_family(ramps: RampSet): ColorFamilyRange { + const color_family: ColorFamilyRange = {} + + for (const ramp in ramps) { + color_family[ramp as keyof RampSet] = chroma(ramps[ramp as keyof RampSet](0.5)).luminance() + } + + return color_family +} + function lowest_layer(ramps: RampSet): Layer { return { base: build_style_set(ramps.neutral, 0.2, 1), From 036d3e811aa48bf62368dfcd6c9e5812bc16398f Mon Sep 17 00:00:00 2001 From: Sergey Onufrienko Date: Thu, 13 Jul 2023 22:09:31 +0100 Subject: [PATCH 02/41] feat: add low, high, range and scaling --- styles/src/theme/create_theme.ts | 33 ++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/styles/src/theme/create_theme.ts b/styles/src/theme/create_theme.ts index 3f4a0766547534d39e43546c722cd2179ce628b1..e0da345bc52a81a8519f5f36d1d7ab76d9a6ff4c 100644 --- a/styles/src/theme/create_theme.ts +++ b/styles/src/theme/create_theme.ts @@ -70,11 +70,14 @@ export interface Players { "7": Player } -export interface ColorFamily { - range: ColorFamilyRange -} +export type ColorFamily = Partial<{ [K in keyof RampSet]: ColorFamilyRange }> -export type ColorFamilyRange = Partial<{ [K in keyof RampSet]: number }> +export interface ColorFamilyRange { + low: number + high: number + range: number + scaling_value: number +} export interface Shadow { blur: number @@ -169,9 +172,7 @@ export function create_theme(theme: ThemeConfig): Theme { "7": player(ramps.yellow), } - const color_family = { - range: build_color_family(ramps) - } + const color_family = build_color_family(ramps) return { name, @@ -199,11 +200,23 @@ function player(ramp: Scale): Player { } } -function build_color_family(ramps: RampSet): ColorFamilyRange { - const color_family: ColorFamilyRange = {} +function build_color_family(ramps: RampSet): ColorFamily { + const color_family: ColorFamily = {} for (const ramp in ramps) { - color_family[ramp as keyof RampSet] = chroma(ramps[ramp as keyof RampSet](0.5)).luminance() + const ramp_value = ramps[ramp as keyof RampSet] + + const lightnessValues = [ramp_value(0).get('hsl.l') * 100, ramp_value(1).get('hsl.l') * 100] + const low = Math.min(...lightnessValues) + const high = Math.max(...lightnessValues) + const range = high - low + + color_family[ramp as keyof RampSet] = { + low, + high, + range, + scaling_value: 100 / range, + } } return color_family From 8c98b02e457ffb2fb0f457e9e2834ebbc9bebdd7 Mon Sep 17 00:00:00 2001 From: "Joseph T. Lyons" Date: Fri, 4 Aug 2023 15:09:08 -0400 Subject: [PATCH 03/41] Add `convert to {upper,lower} case` commands Co-Authored-By: Julia <30666851+ForLoveOfCats@users.noreply.github.com> --- crates/editor/src/editor.rs | 66 +++++++++++++++++++++++++++++++ crates/editor/src/editor_tests.rs | 59 +++++++++++++++++++++++++++ 2 files changed, 125 insertions(+) diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index a4d9259a6d7e7a63dc1606450ecef9d2aa4c53f4..ab952ba6e727fe7ced14fdcc37280bcb31ccfc9d 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -231,6 +231,8 @@ actions!( SortLinesCaseInsensitive, ReverseLines, ShuffleLines, + ConvertToUpperCase, + ConvertToLowerCase, Transpose, Cut, Copy, @@ -353,6 +355,8 @@ pub fn init(cx: &mut AppContext) { cx.add_action(Editor::sort_lines_case_insensitive); cx.add_action(Editor::reverse_lines); cx.add_action(Editor::shuffle_lines); + cx.add_action(Editor::convert_to_upper_case); + cx.add_action(Editor::convert_to_lower_case); cx.add_action(Editor::delete_to_previous_word_start); cx.add_action(Editor::delete_to_previous_subword_start); cx.add_action(Editor::delete_to_next_word_end); @@ -4306,6 +4310,68 @@ impl Editor { }); } + pub fn convert_to_upper_case(&mut self, _: &ConvertToUpperCase, cx: &mut ViewContext) { + self.manipulate_text(cx, |text| text.to_uppercase()) + } + + pub fn convert_to_lower_case(&mut self, _: &ConvertToLowerCase, cx: &mut ViewContext) { + self.manipulate_text(cx, |text| text.to_lowercase()) + } + + fn manipulate_text(&mut self, cx: &mut ViewContext, mut callback: Fn) + where + Fn: FnMut(&str) -> String, + { + let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); + let buffer = self.buffer.read(cx).snapshot(cx); + + let mut new_selections = Vec::new(); + let mut edits = Vec::new(); + for selection in self.selections.all::(cx) { + let selection_is_empty = selection.is_empty(); + + let (start, end) = if selection_is_empty { + let word_range = movement::surrounding_word( + &display_map, + selection.start.to_display_point(&display_map), + ); + let start = word_range.start.to_offset(&display_map, Bias::Left); + let end = word_range.end.to_offset(&display_map, Bias::Left); + (start, end) + } else { + (selection.start, selection.end) + }; + + let text = buffer.text_for_range(start..end).collect::(); + let text = callback(&text); + + if selection_is_empty { + new_selections.push(selection); + } else { + new_selections.push(Selection { + start, + end: start + text.len(), + goal: SelectionGoal::None, + ..selection + }); + } + + edits.push((start..end, text)); + } + + self.transact(cx, |this, cx| { + this.buffer.update(cx, |buffer, cx| { + buffer.edit(edits, None, cx); + }); + + this.change_selections(Some(Autoscroll::fit()), cx, |s| { + s.select(new_selections); + }); + + this.request_autoscroll(Autoscroll::fit(), cx); + }); + } + pub fn duplicate_line(&mut self, _: &DuplicateLine, cx: &mut ViewContext) { let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let buffer = &display_map.buffer_snapshot; diff --git a/crates/editor/src/editor_tests.rs b/crates/editor/src/editor_tests.rs index e8913505cab0d579afa7d1621fa54398a985844e..11d64f085cd35141aa98ff2bbafe20b5c51d96d4 100644 --- a/crates/editor/src/editor_tests.rs +++ b/crates/editor/src/editor_tests.rs @@ -2695,6 +2695,65 @@ async fn test_manipulate_lines_with_multi_selection(cx: &mut TestAppContext) { "}); } +#[gpui::test] +async fn test_manipulate_text(cx: &mut TestAppContext) { + init_test(cx, |_| {}); + + let mut cx = EditorTestContext::new(cx).await; + + // Test convert_to_upper_case() + cx.set_state(indoc! {" + «hello worldˇ» + "}); + cx.update_editor(|e, cx| e.convert_to_upper_case(&ConvertToUpperCase, cx)); + cx.assert_editor_state(indoc! {" + «HELLO WORLDˇ» + "}); + + // Test convert_to_lower_case() + cx.set_state(indoc! {" + «HELLO WORLDˇ» + "}); + cx.update_editor(|e, cx| e.convert_to_lower_case(&ConvertToLowerCase, cx)); + cx.assert_editor_state(indoc! {" + «hello worldˇ» + "}); + + // From here on out, test more complex cases of manipulate_text() with a single driver method: convert_to_upper_case() + + // Test no selection case - should affect words cursors are in + // Cursor at beginning, middle, and end of word + cx.set_state(indoc! {" + ˇhello big beauˇtiful worldˇ + "}); + cx.update_editor(|e, cx| e.convert_to_upper_case(&ConvertToUpperCase, cx)); + cx.assert_editor_state(indoc! {" + ˇHELLO big BEAUˇTIFUL WORLDˇ + "}); + + // Test multiple selections on a single line and across multiple lines + cx.set_state(indoc! {" + «Theˇ» quick «brown + foxˇ» jumps «overˇ» + the «lazyˇ» dog + "}); + cx.update_editor(|e, cx| e.convert_to_upper_case(&ConvertToUpperCase, cx)); + cx.assert_editor_state(indoc! {" + «THEˇ» quick «BROWN + FOXˇ» jumps «OVERˇ» + the «LAZYˇ» dog + "}); + + // Test case where text length grows + cx.set_state(indoc! {" + «tschüߡ» + "}); + cx.update_editor(|e, cx| e.convert_to_upper_case(&ConvertToUpperCase, cx)); + cx.assert_editor_state(indoc! {" + «TSCHÜSSˇ» + "}); +} + #[gpui::test] fn test_duplicate_line(cx: &mut TestAppContext) { init_test(cx, |_| {}); From 12e8f417e4ca3ff1d7aa019825b40c3b3d779483 Mon Sep 17 00:00:00 2001 From: "Joseph T. Lyons" Date: Fri, 4 Aug 2023 22:37:29 -0400 Subject: [PATCH 04/41] Add more convert to case commands ConvertToTitleCase ConvertToSnakeCase ConvertToKebabCase ConvertToUpperCamelCase ConvertToLowerCamelCase --- Cargo.lock | 10 ++++++++++ crates/editor/Cargo.toml | 3 ++- crates/editor/src/editor.rs | 39 +++++++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index fbf4e750c62c920a7158c712d48c4f6cd380bf6f..5afa1ebe6252ddabeb77067c2786d89301041a99 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1649,6 +1649,15 @@ dependencies = [ "theme", ] +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "copilot" version = "0.1.0" @@ -2314,6 +2323,7 @@ dependencies = [ "clock", "collections", "context_menu", + "convert_case", "copilot", "ctor", "db", diff --git a/crates/editor/Cargo.toml b/crates/editor/Cargo.toml index bc1c904404972cb847947b8c60147bcf4a41186b..2fdeee56c18150aa1f38f97176f288fe54412a21 100644 --- a/crates/editor/Cargo.toml +++ b/crates/editor/Cargo.toml @@ -47,6 +47,7 @@ workspace = { path = "../workspace" } aho-corasick = "0.7" anyhow.workspace = true +convert_case = "0.6.0" futures.workspace = true indoc = "1.0.4" itertools = "0.10" @@ -56,12 +57,12 @@ ordered-float.workspace = true parking_lot.workspace = true postage.workspace = true pulldown-cmark = { version = "0.9.2", default-features = false } +rand.workspace = true schemars.workspace = true serde.workspace = true serde_derive.workspace = true smallvec.workspace = true smol.workspace = true -rand.workspace = true tree-sitter-rust = { workspace = true, optional = true } tree-sitter-html = { workspace = true, optional = true } diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index ab952ba6e727fe7ced14fdcc37280bcb31ccfc9d..c70a1a8e048a62c87b9576547da8f6d6c62fb013 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -28,6 +28,7 @@ use blink_manager::BlinkManager; use client::{ClickhouseEvent, TelemetrySettings}; use clock::{Global, ReplicaId}; use collections::{BTreeMap, Bound, HashMap, HashSet, VecDeque}; +use convert_case::{Case, Casing}; use copilot::Copilot; pub use display_map::DisplayPoint; use display_map::*; @@ -233,6 +234,11 @@ actions!( ShuffleLines, ConvertToUpperCase, ConvertToLowerCase, + ConvertToTitleCase, + ConvertToSnakeCase, + ConvertToKebabCase, + ConvertToUpperCamelCase, + ConvertToLowerCamelCase, Transpose, Cut, Copy, @@ -357,6 +363,11 @@ pub fn init(cx: &mut AppContext) { cx.add_action(Editor::shuffle_lines); cx.add_action(Editor::convert_to_upper_case); cx.add_action(Editor::convert_to_lower_case); + cx.add_action(Editor::convert_to_title_case); + cx.add_action(Editor::convert_to_snake_case); + cx.add_action(Editor::convert_to_kebab_case); + cx.add_action(Editor::convert_to_upper_camel_case); + cx.add_action(Editor::convert_to_lower_camel_case); cx.add_action(Editor::delete_to_previous_word_start); cx.add_action(Editor::delete_to_previous_subword_start); cx.add_action(Editor::delete_to_next_word_end); @@ -4318,6 +4329,34 @@ impl Editor { self.manipulate_text(cx, |text| text.to_lowercase()) } + pub fn convert_to_title_case(&mut self, _: &ConvertToTitleCase, cx: &mut ViewContext) { + self.manipulate_text(cx, |text| text.to_case(Case::Title)) + } + + pub fn convert_to_snake_case(&mut self, _: &ConvertToSnakeCase, cx: &mut ViewContext) { + self.manipulate_text(cx, |text| text.to_case(Case::Snake)) + } + + pub fn convert_to_kebab_case(&mut self, _: &ConvertToKebabCase, cx: &mut ViewContext) { + self.manipulate_text(cx, |text| text.to_case(Case::Kebab)) + } + + pub fn convert_to_upper_camel_case( + &mut self, + _: &ConvertToUpperCamelCase, + cx: &mut ViewContext, + ) { + self.manipulate_text(cx, |text| text.to_case(Case::UpperCamel)) + } + + pub fn convert_to_lower_camel_case( + &mut self, + _: &ConvertToLowerCamelCase, + cx: &mut ViewContext, + ) { + self.manipulate_text(cx, |text| text.to_case(Case::Camel)) + } + fn manipulate_text(&mut self, cx: &mut ViewContext, mut callback: Fn) where Fn: FnMut(&str) -> String, From 1abb6a0176feb0b1fe78553a08a2f6675654a8cf Mon Sep 17 00:00:00 2001 From: "Joseph T. Lyons" Date: Sat, 5 Aug 2023 11:31:21 -0400 Subject: [PATCH 05/41] Expand empty selections to cover full word and fix bugs --- crates/editor/src/editor.rs | 21 +++++++++++---------- crates/editor/src/editor_tests.rs | 23 +++++++++++++++++++++-- 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index c70a1a8e048a62c87b9576547da8f6d6c62fb013..cd5e86b91098b35cad385331d5e8f28a380d3139 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -4366,6 +4366,8 @@ impl Editor { let mut new_selections = Vec::new(); let mut edits = Vec::new(); + let mut selection_adjustment = 0i32; + for selection in self.selections.all::(cx) { let selection_is_empty = selection.is_empty(); @@ -4382,18 +4384,17 @@ impl Editor { }; let text = buffer.text_for_range(start..end).collect::(); + let old_length = text.len() as i32; let text = callback(&text); - if selection_is_empty { - new_selections.push(selection); - } else { - new_selections.push(Selection { - start, - end: start + text.len(), - goal: SelectionGoal::None, - ..selection - }); - } + new_selections.push(Selection { + start: (start as i32 - selection_adjustment) as usize, + end: ((start + text.len()) as i32 - selection_adjustment) as usize, + goal: SelectionGoal::None, + ..selection + }); + + selection_adjustment += old_length - text.len() as i32; edits.push((start..end, text)); } diff --git a/crates/editor/src/editor_tests.rs b/crates/editor/src/editor_tests.rs index 11d64f085cd35141aa98ff2bbafe20b5c51d96d4..7e39647ac6370bcb3bba1ff0721764c6e3ee542d 100644 --- a/crates/editor/src/editor_tests.rs +++ b/crates/editor/src/editor_tests.rs @@ -2719,7 +2719,7 @@ async fn test_manipulate_text(cx: &mut TestAppContext) { «hello worldˇ» "}); - // From here on out, test more complex cases of manipulate_text() with a single driver method: convert_to_upper_case() + // From here on out, test more complex cases of manipulate_text() // Test no selection case - should affect words cursors are in // Cursor at beginning, middle, and end of word @@ -2728,7 +2728,7 @@ async fn test_manipulate_text(cx: &mut TestAppContext) { "}); cx.update_editor(|e, cx| e.convert_to_upper_case(&ConvertToUpperCase, cx)); cx.assert_editor_state(indoc! {" - ˇHELLO big BEAUˇTIFUL WORLDˇ + «HELLOˇ» big «BEAUTIFULˇ» «WORLDˇ» "}); // Test multiple selections on a single line and across multiple lines @@ -2752,6 +2752,25 @@ async fn test_manipulate_text(cx: &mut TestAppContext) { cx.assert_editor_state(indoc! {" «TSCHÜSSˇ» "}); + + // Test to make sure we don't crash when text shrinks + cx.set_state(indoc! {" + aaa_bbbˇ + "}); + cx.update_editor(|e, cx| e.convert_to_lower_camel_case(&ConvertToLowerCamelCase, cx)); + cx.assert_editor_state(indoc! {" + «aaaBbbˇ» + "}); + + // Test to make sure we all aware of the fact that each word can grow and shrink + // Final selections should be aware of this fact + cx.set_state(indoc! {" + aaa_bˇbb bbˇb_ccc ˇccc_ddd + "}); + cx.update_editor(|e, cx| e.convert_to_lower_camel_case(&ConvertToLowerCamelCase, cx)); + cx.assert_editor_state(indoc! {" + «aaaBbbˇ» «bbbCccˇ» «cccDddˇ» + "}); } #[gpui::test] From dcf8b00656eab32299338c2a63b69dc128fff19d Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Sat, 5 Aug 2023 18:00:44 -0600 Subject: [PATCH 06/41] WIP --- crates/gpui/src/app.rs | 59 ++++++++++++++++++++--------------- crates/gpui/src/app/window.rs | 2 +- 2 files changed, 35 insertions(+), 26 deletions(-) diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index d98033820bb60853403960adba3183f10782ce95..62d7d1d48aef6413dbfa3aed4e05d93dc32cf413 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -1442,7 +1442,7 @@ impl AppContext { window } - pub fn replace_root_view( + pub(crate) fn replace_root_view( &mut self, window_id: usize, build_root_view: F, @@ -3900,28 +3900,6 @@ impl WindowHandle { cx.update_window(self.window_id(), update) } - // pub fn update_root(&self, cx: &mut C, update: F) -> C::Result> - // where - // C: BorrowWindowContext, - // F: FnOnce(&mut V, &mut ViewContext) -> R, - // { - // cx.update_window(self.window_id, |cx| { - // cx.root_view() - // .clone() - // .downcast::() - // .map(|v| v.update(cx, update)) - // }) - // } - - pub fn read_root<'a>(&self, cx: &'a AppContext) -> &'a V { - let root_view = cx - .read_window(self.window_id(), |cx| { - cx.root_view().clone().downcast().unwrap() - }) - .unwrap(); - root_view.read(cx) - } - pub fn read_root_with(&self, cx: &C, read: F) -> C::Result where C: BorrowWindowContext, @@ -3935,6 +3913,20 @@ impl WindowHandle { }) } + pub fn update_root(&self, cx: &mut C, update: F) -> C::Result + where + C: BorrowWindowContext, + F: FnOnce(&mut V, &mut ViewContext) -> R, + { + cx.update_window(self.window_id, |cx| { + cx.root_view() + .clone() + .downcast::() + .unwrap() + .update(cx, update) + }) + } + pub fn add_view(&self, cx: &mut C, build_view: F) -> C::Result> where C: BorrowWindowContext, @@ -3943,6 +3935,23 @@ impl WindowHandle { { self.update(cx, |cx| cx.add_view(build_view)) } + + pub(crate) fn replace_root_view( + &self, + cx: &mut C, + build_root_view: F, + ) -> C::Result> + where + C: BorrowWindowContext, + F: FnOnce(&mut ViewContext) -> V, + { + cx.update_window(self.window_id, |cx| { + let root_view = self.add_view(cx, |cx| build_root_view(cx)); + cx.window.root_view = Some(root_view.clone().into_any()); + cx.window.focused_view_id = Some(root_view.id()); + root_view + }) + } } #[repr(transparent)] @@ -5329,7 +5338,7 @@ mod tests { TestView { events: Vec::new() } }); - assert_eq!(window.read_root(cx).events, ["before emit"]); + window.read_root_with(cx, |view, _| assert_eq!(view.events, ["before emit"])); } #[crate::test(self)] @@ -5381,7 +5390,7 @@ mod tests { TestView { events: Vec::new() } }); - assert_eq!(window.read_root(cx).events, ["before notify"]); + assert_eq!(window.read_root_with(cx, |view, _| assert_eq!(view.events, ["before notify"]))); } #[crate::test(self)] diff --git a/crates/gpui/src/app/window.rs b/crates/gpui/src/app/window.rs index 789341d46fa4788e24c7b4d7b1e44d0558e1f3b7..20992bfbaad03e03888e9971c8f4f88f829cdf46 100644 --- a/crates/gpui/src/app/window.rs +++ b/crates/gpui/src/app/window.rs @@ -1157,7 +1157,7 @@ impl<'a> WindowContext<'a> { self.window.platform_window.prompt(level, msg, answers) } - pub fn replace_root_view(&mut self, build_root_view: F) -> WindowHandle + pub(crate) fn replace_root_view(&mut self, build_root_view: F) -> WindowHandle where V: View, F: FnOnce(&mut ViewContext) -> V, From ef5b982ea5901f9f5ef78854e1bcba93b77dd2b6 Mon Sep 17 00:00:00 2001 From: "Joseph T. Lyons" Date: Sun, 6 Aug 2023 02:20:31 -0400 Subject: [PATCH 07/41] Fix bash path_suffixes and add line_comment --- crates/zed/src/languages/bash/config.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/zed/src/languages/bash/config.toml b/crates/zed/src/languages/bash/config.toml index 80b8753d80105f91ea9c0b802a2fe11ea61557c4..d03897a071d78c55c48ac97c4e829c7d2e05db1f 100644 --- a/crates/zed/src/languages/bash/config.toml +++ b/crates/zed/src/languages/bash/config.toml @@ -1,5 +1,6 @@ name = "Shell Script" -path_suffixes = [".sh", ".bash", ".bashrc", ".bash_profile", ".bash_aliases", ".bash_logout", ".profile", ".zsh", ".zshrc", ".zshenv", ".zsh_profile", ".zsh_aliases", ".zsh_histfile", ".zlogin"] +path_suffixes = ["sh", "bash", "bashrc", "bash_profile", "bash_aliases", "bash_logout", "profile", "zsh", "zshrc", "zshenv", "zsh_profile", "zsh_aliases", "zsh_histfile", "zlogin"] +line_comment = "# " first_line_pattern = "^#!.*\\b(?:ba|z)?sh\\b" brackets = [ { start = "[", end = "]", close = true, newline = false }, From adc50469ff0c938415c4995ce8ed7fb761021a68 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Sun, 6 Aug 2023 12:45:31 -0600 Subject: [PATCH 08/41] WIP --- Cargo.lock | 39 ++- Cargo.toml | 1 + crates/collab/src/tests/integration_tests.rs | 4 +- .../src/incoming_call_notification.rs | 2 +- .../src/project_shared_notification.rs | 2 +- crates/command_palette/src/command_palette.rs | 2 +- crates/diagnostics/src/diagnostics.rs | 4 +- crates/editor/src/editor_tests.rs | 2 +- .../src/test/editor_lsp_test_context.rs | 2 +- crates/editor/src/test/editor_test_context.rs | 2 +- crates/file_finder/src/file_finder.rs | 22 +- crates/gpui/Cargo.toml | 1 + crates/gpui/src/app.rs | 264 +++++++++--------- crates/gpui/src/app/test_app_context.rs | 33 ++- crates/gpui/src/app/window.rs | 21 +- crates/project_panel/src/project_panel.rs | 8 +- crates/project_symbols/src/project_symbols.rs | 2 +- crates/search/src/buffer_search.rs | 10 +- crates/search/src/project_search.rs | 4 +- crates/workspace/src/workspace.rs | 165 +++++------ crates/zed/src/zed.rs | 20 +- 21 files changed, 331 insertions(+), 279 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fbf4e750c62c920a7158c712d48c4f6cd380bf6f..6cd36252d1b8f09fd0a88027b09d4e4da0d7524b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1649,6 +1649,12 @@ dependencies = [ "theme", ] +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + [[package]] name = "copilot" version = "0.1.0" @@ -2133,6 +2139,19 @@ dependencies = [ "serde", ] +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version 0.4.0", + "syn 1.0.109", +] + [[package]] name = "dhat" version = "0.3.2" @@ -3096,6 +3115,7 @@ dependencies = [ "core-graphics", "core-text", "ctor", + "derive_more", "dhat", "env_logger 0.9.3", "etagere", @@ -5106,7 +5126,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39fe46acc5503595e5949c17b818714d26fdf9b4920eacf3b2947f0199f4a6ff" dependencies = [ - "rustc_version", + "rustc_version 0.3.3", ] [[package]] @@ -6276,7 +6296,16 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" dependencies = [ - "semver", + "semver 0.11.0", +] + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver 1.0.18", ] [[package]] @@ -6716,6 +6745,12 @@ dependencies = [ "semver-parser", ] +[[package]] +name = "semver" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" + [[package]] name = "semver-parser" version = "0.10.2" diff --git a/Cargo.toml b/Cargo.toml index 6e79c6b6576c290a4a0e85e56a80cfe9b100ff2b..1938e832e9cdb74c26a96abfa150f09b23a97d75 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -79,6 +79,7 @@ resolver = "2" anyhow = { version = "1.0.57" } async-trait = { version = "0.1" } ctor = { version = "0.1" } +derive_more = { version = "0.99.17" } env_logger = { version = "0.9" } futures = { version = "0.3" } globset = { version = "0.4" } diff --git a/crates/collab/src/tests/integration_tests.rs b/crates/collab/src/tests/integration_tests.rs index 037f97f71abc8a5961b3693c461522af985fbb55..1a8e6d938d6d6caac2b8caee501e1088ddeea5b3 100644 --- a/crates/collab/src/tests/integration_tests.rs +++ b/crates/collab/src/tests/integration_tests.rs @@ -3446,7 +3446,7 @@ async fn test_newline_above_or_below_does_not_move_guest_cursor( let editor_a = window_a.add_view(cx_a, |cx| Editor::for_buffer(buffer_a, Some(project_a), cx)); let mut editor_cx_a = EditorTestContext { cx: cx_a, - window_id: window_a.window_id(), + window_id: window_a.id(), editor: editor_a, }; @@ -3459,7 +3459,7 @@ async fn test_newline_above_or_below_does_not_move_guest_cursor( let editor_b = window_b.add_view(cx_b, |cx| Editor::for_buffer(buffer_b, Some(project_b), cx)); let mut editor_cx_b = EditorTestContext { cx: cx_b, - window_id: window_b.window_id(), + window_id: window_b.id(), editor: editor_b, }; diff --git a/crates/collab_ui/src/incoming_call_notification.rs b/crates/collab_ui/src/incoming_call_notification.rs index 770f5d5795c980df75a4ce0f888f72745f63970e..a9c5e697a5f60d0cb6f9c0e6baf7cac50aba192a 100644 --- a/crates/collab_ui/src/incoming_call_notification.rs +++ b/crates/collab_ui/src/incoming_call_notification.rs @@ -49,7 +49,7 @@ pub fn init(app_state: &Arc, cx: &mut AppContext) { |_| IncomingCallNotification::new(incoming_call.clone(), app_state.clone()), ); - notification_windows.push(window.window_id()); + notification_windows.push(window.id()); } } } diff --git a/crates/collab_ui/src/project_shared_notification.rs b/crates/collab_ui/src/project_shared_notification.rs index 5be7e33bf3cea049569ce294dbb3d8b1942cf38f..03ab91623b43270bf2592ced0f460b474fd0c435 100644 --- a/crates/collab_ui/src/project_shared_notification.rs +++ b/crates/collab_ui/src/project_shared_notification.rs @@ -52,7 +52,7 @@ pub fn init(app_state: &Arc, cx: &mut AppContext) { notification_windows .entry(*project_id) .or_insert(Vec::new()) - .push(window.window_id()); + .push(window.id()); } } room::Event::RemoteProjectUnshared { project_id } => { diff --git a/crates/command_palette/src/command_palette.rs b/crates/command_palette/src/command_palette.rs index 935358c2a126bfd59f90ffe89f7b7825063af8c9..7d4b4126b702774bf8c295d3b61f904ff7ebf80c 100644 --- a/crates/command_palette/src/command_palette.rs +++ b/crates/command_palette/src/command_palette.rs @@ -297,7 +297,7 @@ mod tests { let project = Project::test(app_state.fs.clone(), [], cx).await; let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx)); let workspace = window.root(cx); - let window_id = window.window_id(); + let window_id = window.id(); let editor = cx.add_view(window_id, |cx| { let mut editor = Editor::single_line(None, cx); editor.set_text("abc", cx); diff --git a/crates/diagnostics/src/diagnostics.rs b/crates/diagnostics/src/diagnostics.rs index f2db0a7763054d19ea85b591de6e8b8d63272740..2444465be666124adb706bcf1833c50c77cee081 100644 --- a/crates/diagnostics/src/diagnostics.rs +++ b/crates/diagnostics/src/diagnostics.rs @@ -857,7 +857,7 @@ mod tests { let project = Project::test(fs.clone(), ["/test".as_ref()], cx).await; let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx)); let workspace = window.root(cx); - let window_id = window.window_id(); + let window_id = window.id(); // Create some diagnostics project.update(cx, |project, cx| { @@ -1252,7 +1252,7 @@ mod tests { let project = Project::test(fs.clone(), ["/test".as_ref()], cx).await; let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx)); let workspace = window.root(cx); - let window_id = window.window_id(); + let window_id = window.id(); let view = cx.add_view(window_id, |cx| { ProjectDiagnosticsEditor::new(project.clone(), workspace.downgrade(), cx) diff --git a/crates/editor/src/editor_tests.rs b/crates/editor/src/editor_tests.rs index e8913505cab0d579afa7d1621fa54398a985844e..a114cd437b16bbad580d6e732bb004ac352d822a 100644 --- a/crates/editor/src/editor_tests.rs +++ b/crates/editor/src/editor_tests.rs @@ -525,7 +525,7 @@ async fn test_navigation_history(cx: &mut TestAppContext) { let project = Project::test(fs, [], cx).await; let window = cx.add_window(|cx| Workspace::test_new(project, cx)); let workspace = window.root(cx); - let window_id = window.window_id(); + let window_id = window.id(); let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone()); cx.add_view(window_id, |cx| { let buffer = MultiBuffer::build_simple(&sample_text(300, 5, 'a'), cx); diff --git a/crates/editor/src/test/editor_lsp_test_context.rs b/crates/editor/src/test/editor_lsp_test_context.rs index d25ca7bb88a86383166288fcb1ac6cd5cfd5997f..f53115f224a1cfe6cb4a3c634786c7e7e8c18305 100644 --- a/crates/editor/src/test/editor_lsp_test_context.rs +++ b/crates/editor/src/test/editor_lsp_test_context.rs @@ -99,7 +99,7 @@ impl<'a> EditorLspTestContext<'a> { Self { cx: EditorTestContext { cx, - window_id: window.window_id(), + window_id: window.id(), editor, }, lsp, diff --git a/crates/editor/src/test/editor_test_context.rs b/crates/editor/src/test/editor_test_context.rs index ac519764fdd8b671a92070118ec9b4937d135c64..c7ea1b4f3852301e300c5ff3f1db1dff65f342a2 100644 --- a/crates/editor/src/test/editor_test_context.rs +++ b/crates/editor/src/test/editor_test_context.rs @@ -39,7 +39,7 @@ impl<'a> EditorTestContext<'a> { let editor = window.root(cx); Self { cx, - window_id: window.window_id(), + window_id: window.id(), editor, } } diff --git a/crates/file_finder/src/file_finder.rs b/crates/file_finder/src/file_finder.rs index 84a45b083e6fdef0a2b4145e756f495fdc255300..12bf3242627619d390409bba044c0fa9cdcce3d4 100644 --- a/crates/file_finder/src/file_finder.rs +++ b/crates/file_finder/src/file_finder.rs @@ -619,7 +619,7 @@ mod tests { let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await; let window = cx.add_window(|cx| Workspace::test_new(project, cx)); let workspace = window.root(cx); - cx.dispatch_action(window.window_id(), Toggle); + cx.dispatch_action(window.id(), Toggle); let finder = cx.read(|cx| workspace.read(cx).modal::().unwrap()); finder @@ -632,8 +632,8 @@ mod tests { }); let active_pane = cx.read(|cx| workspace.read(cx).active_pane().clone()); - cx.dispatch_action(window.window_id(), SelectNext); - cx.dispatch_action(window.window_id(), Confirm); + cx.dispatch_action(window.id(), SelectNext); + cx.dispatch_action(window.id(), Confirm); active_pane .condition(cx, |pane, _| pane.active_item().is_some()) .await; @@ -674,7 +674,7 @@ mod tests { let project = Project::test(app_state.fs.clone(), ["/src".as_ref()], cx).await; let window = cx.add_window(|cx| Workspace::test_new(project, cx)); let workspace = window.root(cx); - cx.dispatch_action(window.window_id(), Toggle); + cx.dispatch_action(window.id(), Toggle); let finder = cx.read(|cx| workspace.read(cx).modal::().unwrap()); let file_query = &first_file_name[..3]; @@ -706,8 +706,8 @@ mod tests { }); let active_pane = cx.read(|cx| workspace.read(cx).active_pane().clone()); - cx.dispatch_action(window.window_id(), SelectNext); - cx.dispatch_action(window.window_id(), Confirm); + cx.dispatch_action(window.id(), SelectNext); + cx.dispatch_action(window.id(), Confirm); active_pane .condition(cx, |pane, _| pane.active_item().is_some()) .await; @@ -758,7 +758,7 @@ mod tests { let project = Project::test(app_state.fs.clone(), ["/src".as_ref()], cx).await; let window = cx.add_window(|cx| Workspace::test_new(project, cx)); let workspace = window.root(cx); - cx.dispatch_action(window.window_id(), Toggle); + cx.dispatch_action(window.id(), Toggle); let finder = cx.read(|cx| workspace.read(cx).modal::().unwrap()); let file_query = &first_file_name[..3]; @@ -790,8 +790,8 @@ mod tests { }); let active_pane = cx.read(|cx| workspace.read(cx).active_pane().clone()); - cx.dispatch_action(window.window_id(), SelectNext); - cx.dispatch_action(window.window_id(), Confirm); + cx.dispatch_action(window.id(), SelectNext); + cx.dispatch_action(window.id(), Confirm); active_pane .condition(cx, |pane, _| pane.active_item().is_some()) .await; @@ -1168,7 +1168,7 @@ mod tests { let project = Project::test(app_state.fs.clone(), ["/src".as_ref()], cx).await; let window = cx.add_window(|cx| Workspace::test_new(project, cx)); let workspace = window.root(cx); - let window_id = window.window_id(); + let window_id = window.id(); let worktree_id = cx.read(|cx| { let worktrees = workspace.read(cx).worktrees(cx).collect::>(); assert_eq!(worktrees.len(), 1); @@ -1376,7 +1376,7 @@ mod tests { let window = cx.add_window(|cx| Workspace::test_new(project, cx)); let workspace = window.root(cx); - let window_id = window.window_id(); + let window_id = window.id(); let worktree_id = cx.read(|cx| { let worktrees = workspace.read(cx).worktrees(cx).collect::>(); assert_eq!(worktrees.len(), 1,); diff --git a/crates/gpui/Cargo.toml b/crates/gpui/Cargo.toml index 31b7db008d28d56849c7ce36eb3f23336fe82fad..5bd7d0318439d2cbd46667f585be37ae25efa33e 100644 --- a/crates/gpui/Cargo.toml +++ b/crates/gpui/Cargo.toml @@ -22,6 +22,7 @@ sqlez = { path = "../sqlez" } async-task = "4.0.3" backtrace = { version = "0.3", optional = true } ctor.workspace = true +derive_more.workspace = true dhat = { version = "0.3", optional = true } env_logger = { version = "0.9", optional = true } etagere = "0.2" diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index 62d7d1d48aef6413dbfa3aed4e05d93dc32cf413..f967f134039081c1a89c71385e2fc25124a32bf3 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -23,6 +23,7 @@ use std::{ }; use anyhow::{anyhow, Context, Result}; +use derive_more::Deref; use parking_lot::Mutex; use postage::oneshot; use smallvec::SmallVec; @@ -132,11 +133,13 @@ pub trait BorrowAppContext { pub trait BorrowWindowContext { type Result; - fn read_window_with(&self, window_id: usize, f: F) -> Self::Result + fn read_window_with(&self, window_handle: H, f: F) -> Self::Result where + H: Into, F: FnOnce(&WindowContext) -> T; - fn update_window(&mut self, window_id: usize, f: F) -> Self::Result + fn update_window(&mut self, window_handle: H, f: F) -> Self::Result where + H: Into, F: FnOnce(&mut WindowContext) -> T; } @@ -300,13 +303,13 @@ impl App { result } - fn update_window T>( - &mut self, - window_id: usize, - callback: F, - ) -> Option { + fn update_window(&mut self, handle: H, callback: F) -> Option + where + H: Into, + F: FnOnce(&mut WindowContext) -> T, + { let mut state = self.0.borrow_mut(); - let result = state.update_window(window_id, callback); + let result = state.update_window(handle, callback); state.pending_notifications.clear(); result } @@ -333,6 +336,10 @@ impl AsyncAppContext { self.0.borrow_mut().update(callback) } + pub fn windows(&self) -> Vec { + self.0.borrow().windows().collect() + } + pub fn read_window T>( &self, window_id: usize, @@ -343,10 +350,10 @@ impl AsyncAppContext { pub fn update_window T>( &mut self, - window_id: usize, + handle: AnyWindowHandle, callback: F, ) -> Option { - self.0.borrow_mut().update_window(window_id, callback) + self.0.borrow_mut().update_window(handle, callback) } pub fn debug_elements(&self, window_id: usize) -> Option { @@ -359,14 +366,14 @@ impl AsyncAppContext { pub fn dispatch_action( &mut self, - window_id: usize, + window: impl Into, view_id: usize, action: &dyn Action, ) -> Result<()> { self.0 .borrow_mut() - .update_window(window_id, |window| { - window.dispatch_action(Some(view_id), action); + .update_window(window, |cx| { + cx.dispatch_action(Some(view_id), action); }) .ok_or_else(|| anyhow!("window not found")) } @@ -380,22 +387,6 @@ impl AsyncAppContext { .unwrap_or_default() } - pub fn has_window(&self, window_id: usize) -> bool { - self.read(|cx| cx.windows.contains_key(&window_id)) - } - - pub fn window_is_active(&self, window_id: usize) -> bool { - self.read(|cx| cx.windows.get(&window_id).map_or(false, |w| w.is_active)) - } - - pub fn root_view(&self, window_id: usize) -> Option { - self.read(|cx| cx.windows.get(&window_id).map(|w| w.root_view().clone())) - } - - pub fn window_ids(&self) -> Vec { - self.read(|cx| cx.windows.keys().copied().collect()) - } - pub fn add_model(&mut self, build_model: F) -> ModelHandle where T: Entity, @@ -501,7 +492,7 @@ pub struct AppContext { models: HashMap>, views: HashMap<(usize, usize), Box>, views_metadata: HashMap<(usize, usize), ViewMetadata>, - windows: HashMap, + windows: HashMap, globals: HashMap>, element_states: HashMap>, background: Arc, @@ -818,22 +809,6 @@ impl AppContext { Some(callback(&window_context)) } - pub fn update_window T>( - &mut self, - window_id: usize, - callback: F, - ) -> Option { - self.update(|app_context| { - let mut window = app_context.windows.remove(&window_id)?; - let mut window_context = WindowContext::mutable(app_context, &mut window, window_id); - let result = callback(&mut window_context); - if !window_context.removed { - app_context.windows.insert(window_id, window); - } - Some(result) - }) - } - pub fn update_active_window T>( &mut self, callback: F, @@ -1331,43 +1306,40 @@ impl AppContext { F: FnOnce(&mut ViewContext) -> V, { self.update(|this| { - let window_id = post_inc(&mut this.next_id); + let window = WindowHandle::::new(post_inc(&mut this.next_id)); let platform_window = this.platform - .open_window(window_id, window_options, this.foreground.clone()); - let window = this.build_window(window_id, platform_window, build_root_view); - this.windows.insert(window_id, window); - WindowHandle::new(window_id) + .open_window(window, window_options, this.foreground.clone()); + let window = this.build_window(window, platform_window, build_root_view); + this.windows.insert(window.into(), window); + window }) } - pub fn add_status_bar_item(&mut self, build_root_view: F) -> (usize, ViewHandle) + pub fn add_status_bar_item(&mut self, build_root_view: F) -> WindowHandle where V: View, F: FnOnce(&mut ViewContext) -> V, { self.update(|this| { - let window_id = post_inc(&mut this.next_id); - let platform_window = this.platform.add_status_item(window_id); - let window = this.build_window(window_id, platform_window, build_root_view); - let root_view = window.root_view().clone().downcast::().unwrap(); - - this.windows.insert(window_id, window); - this.update_window(window_id, |cx| { - root_view.update(cx, |view, cx| view.focus_in(cx.handle().into_any(), cx)) - }); + let handle = WindowHandle::::new(post_inc(&mut this.next_id)); + let platform_window = this.platform.add_status_item(handle.id()); + let window = this.build_window(handle, platform_window, build_root_view); - (window_id, root_view) + this.windows.insert(handle.into(), window); + handle.update_root(this, |view, cx| view.focus_in(cx.handle().into_any(), cx)); + handle }) } - pub fn build_window( + pub fn build_window( &mut self, - window_id: usize, + handle: H, mut platform_window: Box, build_root_view: F, ) -> Window where + H: Into, V: View, F: FnOnce(&mut ViewContext) -> V, { @@ -1375,7 +1347,7 @@ impl AppContext { let mut app = self.upgrade(); platform_window.on_event(Box::new(move |event| { - app.update_window(window_id, |cx| { + app.update_window(handle, |cx| { if let Event::KeyDown(KeyDownEvent { keystroke, .. }) = &event { if cx.dispatch_keystroke(keystroke) { return true; @@ -1391,35 +1363,35 @@ impl AppContext { { let mut app = self.upgrade(); platform_window.on_active_status_change(Box::new(move |is_active| { - app.update(|cx| cx.window_changed_active_status(window_id, is_active)) + app.update(|cx| cx.window_changed_active_status(handle, is_active)) })); } { let mut app = self.upgrade(); platform_window.on_resize(Box::new(move || { - app.update(|cx| cx.window_was_resized(window_id)) + app.update(|cx| cx.window_was_resized(handle)) })); } { let mut app = self.upgrade(); platform_window.on_moved(Box::new(move || { - app.update(|cx| cx.window_was_moved(window_id)) + app.update(|cx| cx.window_was_moved(handle)) })); } { let mut app = self.upgrade(); platform_window.on_fullscreen(Box::new(move |is_fullscreen| { - app.update(|cx| cx.window_was_fullscreen_changed(window_id, is_fullscreen)) + app.update(|cx| cx.window_was_fullscreen_changed(handle, is_fullscreen)) })); } { let mut app = self.upgrade(); platform_window.on_close(Box::new(move || { - app.update(|cx| cx.update_window(window_id, |cx| cx.remove_window())); + app.update(|cx| cx.update_window(handle, |cx| cx.remove_window())); })); } @@ -1431,27 +1403,20 @@ impl AppContext { platform_window.set_input_handler(Box::new(WindowInputHandler { app: self.upgrade().0, - window_id, + window_id: handle, })); - let mut window = Window::new(window_id, platform_window, self, build_root_view); - let mut cx = WindowContext::mutable(self, &mut window, window_id); + let mut window = Window::new(handle, platform_window, self, build_root_view); + let mut cx = WindowContext::mutable(self, &mut window, handle); cx.layout(false).expect("initial layout should not error"); let scene = cx.paint().expect("initial paint should not error"); window.platform_window.present_scene(scene); window } - pub(crate) fn replace_root_view( - &mut self, - window_id: usize, - build_root_view: F, - ) -> Option> - where - V: View, - F: FnOnce(&mut ViewContext) -> V, - { - self.update_window(window_id, |cx| cx.replace_root_view(build_root_view)) + pub fn windows(&self) -> impl Iterator { + todo!(); + None.into_iter() } pub fn read_view(&self, handle: &ViewHandle) -> &T { @@ -2192,11 +2157,20 @@ impl BorrowWindowContext for AppContext { AppContext::read_window(self, window_id, f) } - fn update_window(&mut self, window_id: usize, f: F) -> Self::Result + fn update_window(&mut self, window: usize, f: F) -> Self::Result where F: FnOnce(&mut WindowContext) -> T, { - AppContext::update_window(self, window_id, f) + self.update(|app_context| { + let mut window = app_context.windows.remove(&window_handle)?; + let mut window_context = + WindowContext::mutable(app_context, &mut window, window_handle); + let result = callback(&mut window_context); + if !window_context.removed { + app_context.windows.insert(window_handle, window); + } + Some(result) + }) } } @@ -3862,44 +3836,28 @@ impl Clone for WeakModelHandle { impl Copy for WeakModelHandle {} +#[derive(Deref, Copy, Clone)] pub struct WindowHandle { - window_id: usize, + #[deref] + any_handle: AnyWindowHandle, root_view_type: PhantomData, } -#[allow(dead_code)] impl WindowHandle { fn new(window_id: usize) -> Self { WindowHandle { - window_id, + any_handle: AnyWindowHandle { + window_id, + root_view_type: TypeId::of::(), + }, root_view_type: PhantomData, } } - pub fn window_id(&self) -> usize { - self.window_id - } - pub fn root(&self, cx: &C) -> C::Result> { self.read_with(cx, |cx| cx.root_view().clone().downcast().unwrap()) } - pub fn read_with(&self, cx: &C, read: F) -> C::Result - where - C: BorrowWindowContext, - F: FnOnce(&WindowContext) -> R, - { - cx.read_window_with(self.window_id(), |cx| read(cx)) - } - - pub fn update(&self, cx: &mut C, update: F) -> C::Result - where - C: BorrowWindowContext, - F: FnOnce(&mut WindowContext) -> R, - { - cx.update_window(self.window_id(), update) - } - pub fn read_root_with(&self, cx: &C, read: F) -> C::Result where C: BorrowWindowContext, @@ -3918,7 +3876,7 @@ impl WindowHandle { C: BorrowWindowContext, F: FnOnce(&mut V, &mut ViewContext) -> R, { - cx.update_window(self.window_id, |cx| { + cx.update_window(*self, |cx| { cx.root_view() .clone() .downcast::() @@ -3927,6 +3885,53 @@ impl WindowHandle { }) } + pub fn replace_root(&self, cx: &mut C, build_root: F) -> C::Result> + where + C: BorrowWindowContext, + F: FnOnce(&mut ViewContext) -> V, + { + cx.update_window(self.into_any(), |cx| { + let root_view = self.add_view(cx, |cx| build_root(cx)); + cx.window.root_view = Some(root_view.clone().into_any()); + cx.window.focused_view_id = Some(root_view.id()); + root_view + }) + } +} + +impl Into for WindowHandle { + fn into(self) -> AnyWindowHandle { + self.any_handle + } +} + +#[derive(Copy, Clone, Eq, PartialEq, Hash)] +pub struct AnyWindowHandle { + window_id: usize, + root_view_type: TypeId, +} + +impl AnyWindowHandle { + pub fn id(&self) -> usize { + self.window_id + } + + pub fn read_with(&self, cx: &C, read: F) -> C::Result + where + C: BorrowWindowContext, + F: FnOnce(&WindowContext) -> R, + { + cx.read_window_with(self.window_id, |cx| read(cx)) + } + + pub fn update(&self, cx: &mut C, update: F) -> C::Result + where + C: BorrowWindowContext, + F: FnOnce(&mut WindowContext) -> R, + { + cx.update_window(self.window_id, update) + } + pub fn add_view(&self, cx: &mut C, build_view: F) -> C::Result> where C: BorrowWindowContext, @@ -3936,21 +3941,16 @@ impl WindowHandle { self.update(cx, |cx| cx.add_view(build_view)) } - pub(crate) fn replace_root_view( - &self, - cx: &mut C, - build_root_view: F, - ) -> C::Result> - where - C: BorrowWindowContext, - F: FnOnce(&mut ViewContext) -> V, - { - cx.update_window(self.window_id, |cx| { - let root_view = self.add_view(cx, |cx| build_root_view(cx)); - cx.window.root_view = Some(root_view.clone().into_any()); - cx.window.focused_view_id = Some(root_view.id()); - root_view - }) + pub fn root_is(&self) -> bool { + self.root_view_type == TypeId::of::() + } + + pub fn is_active(&self, cx: &C) -> C::Result { + self.read_with(cx, |cx| cx.window.is_active) + } + + pub fn remove(&self, cx: &mut C) -> C::Result<()> { + self.update(cx, |cx| cx.remove_window()) } } @@ -5390,7 +5390,7 @@ mod tests { TestView { events: Vec::new() } }); - assert_eq!(window.read_root_with(cx, |view, _| assert_eq!(view.events, ["before notify"]))); + window.read_root_with(cx, |view, _| assert_eq!(view.events, ["before notify"])); } #[crate::test(self)] @@ -6227,7 +6227,7 @@ mod tests { // Check that global actions do not have a binding, even if a binding does exist in another view assert_eq!( - &available_actions(window.window_id(), view_1.id(), cx), + &available_actions(window.id(), view_1.id(), cx), &[ ("test::Action1", vec![Keystroke::parse("a").unwrap()]), ("test::GlobalAction", vec![]) @@ -6236,7 +6236,7 @@ mod tests { // Check that view 1 actions and bindings are available even when called from view 2 assert_eq!( - &available_actions(window.window_id(), view_2.id(), cx), + &available_actions(window.id(), view_2.id(), cx), &[ ("test::Action1", vec![Keystroke::parse("a").unwrap()]), ("test::Action2", vec![Keystroke::parse("b").unwrap()]), @@ -6299,7 +6299,7 @@ mod tests { ]); }); - let actions = cx.available_actions(window.window_id(), view.id()); + let actions = cx.available_actions(window.id(), view.id()); assert_eq!( actions[0].1.as_any().downcast_ref::(), Some(&ActionWithArg { arg: false }) @@ -6585,25 +6585,25 @@ mod tests { [("window 2", false), ("window 3", true)] ); - cx.simulate_window_activation(Some(window_2.window_id())); + cx.simulate_window_activation(Some(window_2.id())); assert_eq!( mem::take(&mut *events.borrow_mut()), [("window 3", false), ("window 2", true)] ); - cx.simulate_window_activation(Some(window_1.window_id())); + cx.simulate_window_activation(Some(window_1.id())); assert_eq!( mem::take(&mut *events.borrow_mut()), [("window 2", false), ("window 1", true)] ); - cx.simulate_window_activation(Some(window_3.window_id())); + cx.simulate_window_activation(Some(window_3.id())); assert_eq!( mem::take(&mut *events.borrow_mut()), [("window 1", false), ("window 3", true)] ); - cx.simulate_window_activation(Some(window_3.window_id())); + cx.simulate_window_activation(Some(window_3.id())); assert_eq!(mem::take(&mut *events.borrow_mut()), []); } diff --git a/crates/gpui/src/app/test_app_context.rs b/crates/gpui/src/app/test_app_context.rs index 3b574eb03ee3f6cfcae23cffff8f1c5359828c66..5b005d7d6f2cd527321c97b3690576433ed132e7 100644 --- a/crates/gpui/src/app/test_app_context.rs +++ b/crates/gpui/src/app/test_app_context.rs @@ -4,9 +4,9 @@ use crate::{ keymap_matcher::{Binding, Keystroke}, platform, platform::{Event, InputHandler, KeyDownEvent, Platform}, - Action, AppContext, BorrowAppContext, BorrowWindowContext, Entity, FontCache, Handle, - ModelContext, ModelHandle, Subscription, Task, View, ViewContext, ViewHandle, WeakHandle, - WindowContext, WindowHandle, + Action, AnyWindowHandle, AppContext, BorrowAppContext, BorrowWindowContext, Entity, FontCache, + Handle, ModelContext, ModelHandle, Subscription, Task, View, ViewContext, ViewHandle, + WeakHandle, WindowContext, WindowHandle, }; use collections::BTreeMap; use futures::Future; @@ -124,6 +124,13 @@ impl TestAppContext { } } + pub fn window(&self, window_id: usize) -> Option> { + self.cx + .borrow() + .read_window(window_id, |cx| cx.window()) + .flatten() + } + pub fn read_window T>( &self, window_id: usize, @@ -157,9 +164,9 @@ impl TestAppContext { .cx .borrow_mut() .add_window(Default::default(), build_root_view); - self.simulate_window_activation(Some(window.window_id())); + self.simulate_window_activation(Some(window.id())); - WindowHandle::new(window.window_id()) + WindowHandle::new(window.id()) } pub fn add_view(&mut self, window_id: usize, build_view: F) -> ViewHandle @@ -191,10 +198,14 @@ impl TestAppContext { self.cx.borrow_mut().subscribe_global(callback) } - pub fn window_ids(&self) -> Vec { - self.cx.borrow().windows.keys().copied().collect() + pub fn windows(&self) -> impl Iterator { + self.cx.borrow().windows() } + // pub fn window_ids(&self) -> Vec { + // self.cx.borrow().windows.keys().copied().collect() + // } + pub fn remove_all_windows(&mut self) { self.update(|cx| cx.windows.clear()); } @@ -311,15 +322,15 @@ impl TestAppContext { pub fn simulate_window_activation(&self, to_activate: Option) { self.cx.borrow_mut().update(|cx| { - let other_window_ids = cx + let other_windows = cx .windows .keys() - .filter(|window_id| Some(**window_id) != to_activate) + .filter(|window| Some(window.id()) != to_activate) .copied() .collect::>(); - for window_id in other_window_ids { - cx.window_changed_active_status(window_id, false) + for window in other_windows { + cx.window_changed_active_status(window.id(), false) } if let Some(to_activate) = to_activate { diff --git a/crates/gpui/src/app/window.rs b/crates/gpui/src/app/window.rs index 20992bfbaad03e03888e9971c8f4f88f829cdf46..cc8468edbd7dbced86061e70a2b17d7ee4578691 100644 --- a/crates/gpui/src/app/window.rs +++ b/crates/gpui/src/app/window.rs @@ -196,6 +196,16 @@ impl<'a> WindowContext<'a> { self.window_id } + pub fn window(&self) -> Option> { + self.window.root_view.as_ref().and_then(|root_view| { + if root_view.is::() { + Some(WindowHandle::new(self.window_id)) + } else { + None + } + }) + } + pub fn app_context(&mut self) -> &mut AppContext { &mut self.app_context } @@ -1157,17 +1167,6 @@ impl<'a> WindowContext<'a> { self.window.platform_window.prompt(level, msg, answers) } - pub(crate) fn replace_root_view(&mut self, build_root_view: F) -> WindowHandle - where - V: View, - F: FnOnce(&mut ViewContext) -> V, - { - let root_view = self.add_view(|cx| build_root_view(cx)); - self.window.focused_view_id = Some(root_view.id()); - self.window.root_view = Some(root_view.into_any()); - WindowHandle::new(self.window_id) - } - pub fn add_view(&mut self, build_view: F) -> ViewHandle where T: View, diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index 80847f9f4b97b3dc2cf2c32d6d11f0ec7dcbcc3a..021ea2d3bc3a817342e9eac684496ffeee5026bb 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -1872,7 +1872,7 @@ mod tests { let project = Project::test(fs.clone(), ["/root1".as_ref(), "/root2".as_ref()], cx).await; let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx)); let workspace = window.root(cx); - let window_id = window.window_id(); + let window_id = window.id(); let panel = workspace.update(cx, |workspace, cx| ProjectPanel::new(workspace, cx)); select_path(&panel, "root1", cx); @@ -2225,7 +2225,7 @@ mod tests { let project = Project::test(fs.clone(), ["/root1".as_ref(), "/root2".as_ref()], cx).await; let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx)); let workspace = window.root(cx); - let window_id = window.window_id(); + let window_id = window.id(); let panel = workspace.update(cx, |workspace, cx| ProjectPanel::new(workspace, cx)); select_path(&panel, "root1", cx); @@ -2402,7 +2402,7 @@ mod tests { let project = Project::test(fs.clone(), ["/src".as_ref()], cx).await; let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx)); let workspace = window.root(cx); - let window_id = window.window_id(); + let window_id = window.id(); let panel = workspace.update(cx, |workspace, cx| ProjectPanel::new(workspace, cx)); toggle_expand_dir(&panel, "src/test", cx); @@ -2493,7 +2493,7 @@ mod tests { let project = Project::test(fs.clone(), ["/src".as_ref()], cx).await; let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx)); let workspace = window.root(cx); - let window_id = window.window_id(); + let window_id = window.id(); let panel = workspace.update(cx, |workspace, cx| ProjectPanel::new(workspace, cx)); select_path(&panel, "src/", cx); diff --git a/crates/project_symbols/src/project_symbols.rs b/crates/project_symbols/src/project_symbols.rs index 4bd186fc98b3edb93bb4b2daa1b3e90633e3a0df..8471f3a3a7014d2034438839f76ae9b4214ded52 100644 --- a/crates/project_symbols/src/project_symbols.rs +++ b/crates/project_symbols/src/project_symbols.rs @@ -328,7 +328,7 @@ mod tests { let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx)); let workspace = window.root(cx); - let window_id = window.window_id(); + let window_id = window.id(); // Create the project symbols view. let symbols = cx.add_view(window_id, |cx| { diff --git a/crates/search/src/buffer_search.rs b/crates/search/src/buffer_search.rs index 265e4f02061539a685322a446fef9f7d94b00ffb..1e635432bd5c138f81410f3ac40ee461830ddb17 100644 --- a/crates/search/src/buffer_search.rs +++ b/crates/search/src/buffer_search.rs @@ -851,11 +851,11 @@ mod tests { }); let window = cx.add_window(|_| EmptyView); - let editor = cx.add_view(window.window_id(), |cx| { + let editor = cx.add_view(window.id(), |cx| { Editor::for_buffer(buffer.clone(), None, cx) }); - let search_bar = cx.add_view(window.window_id(), |cx| { + let search_bar = cx.add_view(window.id(), |cx| { let mut search_bar = BufferSearchBar::new(cx); search_bar.set_active_pane_item(Some(&editor), cx); search_bar.show(cx); @@ -1232,7 +1232,7 @@ mod tests { ); let buffer = cx.add_model(|cx| Buffer::new(0, buffer_text, cx)); let window = cx.add_window(|_| EmptyView); - let window_id = window.window_id(); + let window_id = window.id(); let editor = cx.add_view(window_id, |cx| Editor::for_buffer(buffer.clone(), None, cx)); @@ -1421,11 +1421,11 @@ mod tests { let buffer = cx.add_model(|cx| Buffer::new(0, buffer_text, cx)); let window = cx.add_window(|_| EmptyView); - let editor = cx.add_view(window.window_id(), |cx| { + let editor = cx.add_view(window.id(), |cx| { Editor::for_buffer(buffer.clone(), None, cx) }); - let search_bar = cx.add_view(window.window_id(), |cx| { + let search_bar = cx.add_view(window.id(), |cx| { let mut search_bar = BufferSearchBar::new(cx); search_bar.set_active_pane_item(Some(&editor), cx); search_bar.show(cx); diff --git a/crates/search/src/project_search.rs b/crates/search/src/project_search.rs index febd564050ddd0ea6355e83f69f505e80d924029..0db66b4e378a56c97e2e2d1290742e52e1329bda 100644 --- a/crates/search/src/project_search.rs +++ b/crates/search/src/project_search.rs @@ -1568,7 +1568,7 @@ pub mod tests { let project = Project::test(fs.clone(), ["/dir".as_ref()], cx).await; let window = cx.add_window(|cx| Workspace::test_new(project, cx)); let workspace = window.root(cx); - let window_id = window.window_id(); + let window_id = window.id(); let active_item = cx.read(|cx| { workspace @@ -1874,7 +1874,7 @@ pub mod tests { let project = Project::test(fs.clone(), ["/dir".as_ref()], cx).await; let window = cx.add_window(|cx| Workspace::test_new(project, cx)); let workspace = window.root(cx); - let window_id = window.window_id(); + let window_id = window.id(); workspace.update(cx, |workspace, cx| { ProjectSearchView::deploy(workspace, &workspace::NewSearch, cx) }); diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 09e4c4c2193e8521cd8c7dc9841a361933497e73..37fab1ee462d7a242c331ea5df169babbae3a6d8 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -37,7 +37,7 @@ use gpui::{ }, AnyModelHandle, AnyViewHandle, AnyWeakViewHandle, AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle, SizeConstraint, Subscription, Task, View, ViewContext, ViewHandle, - WeakViewHandle, WindowContext, + WeakViewHandle, WindowContext, WindowHandle, }; use item::{FollowableItem, FollowableItemHandle, Item, ItemHandle, ProjectItem}; use itertools::Itertools; @@ -749,7 +749,7 @@ impl Workspace { fn new_local( abs_paths: Vec, app_state: Arc, - requesting_window_id: Option, + requesting_window: Option>, cx: &mut AppContext, ) -> Task<( WeakViewHandle, @@ -793,55 +793,60 @@ impl Workspace { DB.next_id().await.unwrap_or(0) }; - let window = requesting_window_id.and_then(|window_id| { - cx.update(|cx| { - cx.replace_root_view(window_id, |cx| { - Workspace::new(workspace_id, project_handle.clone(), app_state.clone(), cx) - }) - }) - }); - let window = window.unwrap_or_else(|| { - let window_bounds_override = window_bounds_env_override(&cx); - let (bounds, display) = if let Some(bounds) = window_bounds_override { - (Some(bounds), None) - } else { - serialized_workspace - .as_ref() - .and_then(|serialized_workspace| { - let display = serialized_workspace.display?; - let mut bounds = serialized_workspace.bounds?; - - // Stored bounds are relative to the containing display. - // So convert back to global coordinates if that screen still exists - if let WindowBounds::Fixed(mut window_bounds) = bounds { - if let Some(screen) = cx.platform().screen_by_id(display) { - let screen_bounds = screen.bounds(); - window_bounds.set_origin_x( - window_bounds.origin_x() + screen_bounds.origin_x(), - ); - window_bounds.set_origin_y( - window_bounds.origin_y() + screen_bounds.origin_y(), - ); - bounds = WindowBounds::Fixed(window_bounds); - } else { - // Screen no longer exists. Return none here. - return None; + let window = if let Some(window) = requesting_window { + window.replace_root(&mut cx, |cx| { + Workspace::new(workspace_id, project_handle.clone(), app_state.clone(), cx) + }); + window + } else { + { + let window_bounds_override = window_bounds_env_override(&cx); + let (bounds, display) = if let Some(bounds) = window_bounds_override { + (Some(bounds), None) + } else { + serialized_workspace + .as_ref() + .and_then(|serialized_workspace| { + let display = serialized_workspace.display?; + let mut bounds = serialized_workspace.bounds?; + + // Stored bounds are relative to the containing display. + // So convert back to global coordinates if that screen still exists + if let WindowBounds::Fixed(mut window_bounds) = bounds { + if let Some(screen) = cx.platform().screen_by_id(display) { + let screen_bounds = screen.bounds(); + window_bounds.set_origin_x( + window_bounds.origin_x() + screen_bounds.origin_x(), + ); + window_bounds.set_origin_y( + window_bounds.origin_y() + screen_bounds.origin_y(), + ); + bounds = WindowBounds::Fixed(window_bounds); + } else { + // Screen no longer exists. Return none here. + return None; + } } - } - Some((bounds, display)) - }) - .unzip() - }; - - // Use the serialized workspace to construct the new window - cx.add_window( - (app_state.build_window_options)(bounds, display, cx.platform().as_ref()), - |cx| { - Workspace::new(workspace_id, project_handle.clone(), app_state.clone(), cx) - }, - ) - }); + Some((bounds, display)) + }) + .unzip() + }; + + // Use the serialized workspace to construct the new window + cx.add_window( + (app_state.build_window_options)(bounds, display, cx.platform().as_ref()), + |cx| { + Workspace::new( + workspace_id, + project_handle.clone(), + app_state.clone(), + cx, + ) + }, + ) + } + }; // We haven't yielded the main thread since obtaining the window handle, // so the window exists. @@ -1227,14 +1232,14 @@ impl Workspace { pub fn close_global(_: &CloseWindow, cx: &mut AppContext) { cx.spawn(|mut cx| async move { - let id = cx - .window_ids() + let window = cx + .windows() .into_iter() - .find(|&id| cx.window_is_active(id)); - if let Some(id) = id { + .find(|window| window.is_active(&cx).unwrap_or(false)); + if let Some(window) = window { //This can only get called when the window's project connection has been lost //so we don't need to prompt the user for anything and instead just close the window - cx.remove_window(id); + window.remove(&mut cx); } }) .detach(); @@ -1265,9 +1270,9 @@ impl Workspace { cx.spawn(|this, mut cx| async move { let workspace_count = cx - .window_ids() + .windows() .into_iter() - .filter_map(|window_id| cx.root_view(window_id)?.clone().downcast::()) + .filter(|window| window.root_is::()) .count(); if let Some(active_call) = active_call { @@ -1385,7 +1390,7 @@ impl Workspace { paths: Vec, cx: &mut ViewContext, ) -> Task> { - let window_id = cx.window_id(); + let window = cx.window::(); let is_remote = self.project.read(cx).is_remote(); let has_worktree = self.project.read(cx).worktrees(cx).next().is_some(); let has_dirty_items = self.items(cx).any(|item| item.is_dirty(cx)); @@ -1397,15 +1402,15 @@ impl Workspace { let app_state = self.app_state.clone(); cx.spawn(|_, mut cx| async move { - let window_id_to_replace = if let Some(close_task) = close_task { + let window_to_replace = if let Some(close_task) = close_task { if !close_task.await? { return Ok(()); } - Some(window_id) + window } else { None }; - cx.update(|cx| open_paths(&paths, &app_state, window_id_to_replace, cx)) + cx.update(|cx| open_paths(&paths, &app_state, window_to_replace, cx)) .await?; Ok(()) }) @@ -3851,7 +3856,7 @@ pub async fn last_opened_workspace_paths() -> Option { pub fn open_paths( abs_paths: &[PathBuf], app_state: &Arc, - requesting_window_id: Option, + requesting_window: Option>, cx: &mut AppContext, ) -> Task< Result<( @@ -3879,7 +3884,7 @@ pub fn open_paths( } else { Ok(cx .update(|cx| { - Workspace::new_local(abs_paths, app_state.clone(), requesting_window_id, cx) + Workspace::new_local(abs_paths, app_state.clone(), requesting_window, cx) }) .await) } @@ -4196,14 +4201,14 @@ mod tests { ); }); assert_eq!( - cx.current_window_title(window.window_id()).as_deref(), + cx.current_window_title(window.id()).as_deref(), Some("one.txt — root1") ); // Add a second item to a non-empty pane workspace.update(cx, |workspace, cx| workspace.add_item(Box::new(item2), cx)); assert_eq!( - cx.current_window_title(window.window_id()).as_deref(), + cx.current_window_title(window.id()).as_deref(), Some("two.txt — root1") ); project.read_with(cx, |project, cx| { @@ -4222,7 +4227,7 @@ mod tests { .await .unwrap(); assert_eq!( - cx.current_window_title(window.window_id()).as_deref(), + cx.current_window_title(window.id()).as_deref(), Some("one.txt — root1") ); project.read_with(cx, |project, cx| { @@ -4242,14 +4247,14 @@ mod tests { .await .unwrap(); assert_eq!( - cx.current_window_title(window.window_id()).as_deref(), + cx.current_window_title(window.id()).as_deref(), Some("one.txt — root1, root2") ); // Remove a project folder project.update(cx, |project, cx| project.remove_worktree(worktree_id, cx)); assert_eq!( - cx.current_window_title(window.window_id()).as_deref(), + cx.current_window_title(window.id()).as_deref(), Some("one.txt — root2") ); } @@ -4285,9 +4290,9 @@ mod tests { }); let task = workspace.update(cx, |w, cx| w.prepare_to_close(false, cx)); cx.foreground().run_until_parked(); - cx.simulate_prompt_answer(window.window_id(), 2 /* cancel */); + cx.simulate_prompt_answer(window.id(), 2 /* cancel */); cx.foreground().run_until_parked(); - assert!(!cx.has_pending_prompt(window.window_id())); + assert!(!cx.has_pending_prompt(window.id())); assert!(!task.await.unwrap()); } @@ -4346,10 +4351,10 @@ mod tests { assert_eq!(pane.items_len(), 4); assert_eq!(pane.active_item().unwrap().id(), item1.id()); }); - assert!(cx.has_pending_prompt(window.window_id())); + assert!(cx.has_pending_prompt(window.id())); // Confirm saving item 1. - cx.simulate_prompt_answer(window.window_id(), 0); + cx.simulate_prompt_answer(window.id(), 0); cx.foreground().run_until_parked(); // Item 1 is saved. There's a prompt to save item 3. @@ -4360,10 +4365,10 @@ mod tests { assert_eq!(pane.items_len(), 3); assert_eq!(pane.active_item().unwrap().id(), item3.id()); }); - assert!(cx.has_pending_prompt(window.window_id())); + assert!(cx.has_pending_prompt(window.id())); // Cancel saving item 3. - cx.simulate_prompt_answer(window.window_id(), 1); + cx.simulate_prompt_answer(window.id(), 1); cx.foreground().run_until_parked(); // Item 3 is reloaded. There's a prompt to save item 4. @@ -4374,10 +4379,10 @@ mod tests { assert_eq!(pane.items_len(), 2); assert_eq!(pane.active_item().unwrap().id(), item4.id()); }); - assert!(cx.has_pending_prompt(window.window_id())); + assert!(cx.has_pending_prompt(window.id())); // Confirm saving item 4. - cx.simulate_prompt_answer(window.window_id(), 0); + cx.simulate_prompt_answer(window.id(), 0); cx.foreground().run_until_parked(); // There's a prompt for a path for item 4. @@ -4480,7 +4485,7 @@ mod tests { &[ProjectEntryId::from_proto(0)] ); }); - cx.simulate_prompt_answer(window.window_id(), 0); + cx.simulate_prompt_answer(window.id(), 0); cx.foreground().run_until_parked(); left_pane.read_with(cx, |pane, cx| { @@ -4489,7 +4494,7 @@ mod tests { &[ProjectEntryId::from_proto(2)] ); }); - cx.simulate_prompt_answer(window.window_id(), 0); + cx.simulate_prompt_answer(window.id(), 0); cx.foreground().run_until_parked(); close.await.unwrap(); @@ -4549,7 +4554,7 @@ mod tests { item.read_with(cx, |item, _| assert_eq!(item.save_count, 2)); // Deactivating the window still saves the file. - cx.simulate_window_activation(Some(window.window_id())); + cx.simulate_window_activation(Some(window.id())); item.update(cx, |item, cx| { cx.focus_self(); item.is_dirty = true; @@ -4591,7 +4596,7 @@ mod tests { pane.update(cx, |pane, cx| pane.close_items(cx, move |id| id == item_id)) .await .unwrap(); - assert!(!cx.has_pending_prompt(window.window_id())); + assert!(!cx.has_pending_prompt(window.id())); item.read_with(cx, |item, _| assert_eq!(item.save_count, 5)); // Add the item again, ensuring autosave is prevented if the underlying file has been deleted. @@ -4612,7 +4617,7 @@ mod tests { let _close_items = pane.update(cx, |pane, cx| pane.close_items(cx, move |id| id == item_id)); deterministic.run_until_parked(); - assert!(cx.has_pending_prompt(window.window_id())); + assert!(cx.has_pending_prompt(window.id())); item.read_with(cx, |item, _| assert_eq!(item.save_count, 5)); } diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 46fcc014a138a727e2c3ceec01dbc0e3d6abee05..a8a287fb4e6fc964346378fad4eee09bc5eb057a 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -813,11 +813,12 @@ mod tests { // Replace existing windows let window_id = cx.window_ids()[0]; + let window = cx.read_window(window_id, |cx| cx.window()).flatten(); cx.update(|cx| { open_paths( &[PathBuf::from("/root/c"), PathBuf::from("/root/d")], &app_state, - Some(window_id), + window, cx, ) }) @@ -982,9 +983,8 @@ mod tests { .await; let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await; - let workspace = cx - .add_window(|cx| Workspace::test_new(project, cx)) - .root(cx); + let window = cx.add_window(|cx| Workspace::test_new(project, cx)); + let workspace = window.root(cx); let entries = cx.read(|cx| workspace.file_project_paths(cx)); let file1 = entries[0].clone(); @@ -1298,7 +1298,7 @@ mod tests { let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await; let window = cx.add_window(|cx| Workspace::test_new(project, cx)); let workspace = window.root(cx); - let window_id = window.window_id(); + let window_id = window.id(); // Open a file within an existing worktree. workspace @@ -1341,7 +1341,7 @@ mod tests { project.update(cx, |project, _| project.languages().add(rust_lang())); let window = cx.add_window(|cx| Workspace::test_new(project, cx)); let workspace = window.root(cx); - let window_id = window.window_id(); + let window_id = window.id(); let worktree = cx.read(|cx| workspace.read(cx).worktrees(cx).next().unwrap()); // Create a new untitled buffer @@ -1436,7 +1436,7 @@ mod tests { project.update(cx, |project, _| project.languages().add(rust_lang())); let window = cx.add_window(|cx| Workspace::test_new(project, cx)); let workspace = window.root(cx); - let window_id = window.window_id(); + let window_id = window.id(); // Create a new untitled buffer cx.dispatch_action(window_id, NewFile); @@ -1489,7 +1489,7 @@ mod tests { let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await; let window = cx.add_window(|cx| Workspace::test_new(project, cx)); let workspace = window.root(cx); - let window_id = window.window_id(); + let window_id = window.id(); let entries = cx.read(|cx| workspace.file_project_paths(cx)); let file1 = entries[0].clone(); @@ -2087,7 +2087,7 @@ mod tests { cx.foreground().run_until_parked(); let window = cx.add_window(|_| TestView); - let window_id = window.window_id(); + let window_id = window.id(); // Test loading the keymap base at all assert_key_bindings_for( @@ -2258,7 +2258,7 @@ mod tests { cx.foreground().run_until_parked(); let window = cx.add_window(|_| TestView); - let window_id = window.window_id(); + let window_id = window.id(); // Test loading the keymap base at all assert_key_bindings_for( From d4d32611fe3422e9dbb03d432fb8e746f7b8198c Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Sun, 6 Aug 2023 18:57:02 -0600 Subject: [PATCH 09/41] WIP --- crates/gpui/src/app.rs | 58 +++++++++++++++---------- crates/gpui/src/app/menu.rs | 6 +-- crates/gpui/src/app/test_app_context.rs | 12 ++--- 3 files changed, 44 insertions(+), 32 deletions(-) diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index f967f134039081c1a89c71385e2fc25124a32bf3..c2d2397d9c4f4e00ff73cb92358de2423f85a383 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -133,13 +133,11 @@ pub trait BorrowAppContext { pub trait BorrowWindowContext { type Result; - fn read_window_with(&self, window_handle: H, f: F) -> Self::Result + fn read_window_with(&self, window_id: usize, f: F) -> Self::Result where - H: Into, F: FnOnce(&WindowContext) -> T; - fn update_window(&mut self, window_handle: H, f: F) -> Self::Result + fn update_window(&mut self, window_id: usize, f: F) -> Self::Result where - H: Into, F: FnOnce(&mut WindowContext) -> T; } @@ -303,13 +301,12 @@ impl App { result } - fn update_window(&mut self, handle: H, callback: F) -> Option + fn update_window(&mut self, window_id: usize, callback: F) -> Option where - H: Into, F: FnOnce(&mut WindowContext) -> T, { let mut state = self.0.borrow_mut(); - let result = state.update_window(handle, callback); + let result = state.update_window(window_id, callback); state.pending_notifications.clear(); result } @@ -350,10 +347,10 @@ impl AsyncAppContext { pub fn update_window T>( &mut self, - handle: AnyWindowHandle, + window_id: usize, callback: F, ) -> Option { - self.0.borrow_mut().update_window(handle, callback) + self.0.borrow_mut().update_window(window_id, callback) } pub fn debug_elements(&self, window_id: usize) -> Option { @@ -366,13 +363,13 @@ impl AsyncAppContext { pub fn dispatch_action( &mut self, - window: impl Into, + window_id: usize, view_id: usize, action: &dyn Action, ) -> Result<()> { self.0 .borrow_mut() - .update_window(window, |cx| { + .update_window(window_id, |cx| { cx.dispatch_action(Some(view_id), action); }) .ok_or_else(|| anyhow!("window not found")) @@ -492,7 +489,7 @@ pub struct AppContext { models: HashMap>, views: HashMap<(usize, usize), Box>, views_metadata: HashMap<(usize, usize), ViewMetadata>, - windows: HashMap, + windows: HashMap, globals: HashMap>, element_states: HashMap>, background: Arc, @@ -1414,9 +1411,18 @@ impl AppContext { window } - pub fn windows(&self) -> impl Iterator { - todo!(); - None.into_iter() + pub fn main_window(&self) -> Option { + self.platform.main_window_id().and_then(|main_window_id| { + self.windows + .get(&main_window_id) + .map(|window| AnyWindowHandle::new(main_window_id, window.root_view().type_id())) + }) + } + + pub fn windows(&self) -> impl '_ + Iterator { + self.windows.iter().map(|(window_id, window)| { + AnyWindowHandle::new(*window_id, window.root_view().type_id()) + }) } pub fn read_view(&self, handle: &ViewHandle) -> &T { @@ -2157,17 +2163,16 @@ impl BorrowWindowContext for AppContext { AppContext::read_window(self, window_id, f) } - fn update_window(&mut self, window: usize, f: F) -> Self::Result + fn update_window(&mut self, window_id: usize, f: F) -> Self::Result where F: FnOnce(&mut WindowContext) -> T, { self.update(|app_context| { - let mut window = app_context.windows.remove(&window_handle)?; - let mut window_context = - WindowContext::mutable(app_context, &mut window, window_handle); - let result = callback(&mut window_context); + let mut window = app_context.windows.remove(&window_id)?; + let mut window_context = WindowContext::mutable(app_context, &mut window, window_id); + let result = f(&mut window_context); if !window_context.removed { - app_context.windows.insert(window_handle, window); + app_context.windows.insert(window_id, window); } Some(result) }) @@ -3876,7 +3881,7 @@ impl WindowHandle { C: BorrowWindowContext, F: FnOnce(&mut V, &mut ViewContext) -> R, { - cx.update_window(*self, |cx| { + cx.update_window(self.id(), |cx| { cx.root_view() .clone() .downcast::() @@ -3890,7 +3895,7 @@ impl WindowHandle { C: BorrowWindowContext, F: FnOnce(&mut ViewContext) -> V, { - cx.update_window(self.into_any(), |cx| { + cx.update_window(self.id(), |cx| { let root_view = self.add_view(cx, |cx| build_root(cx)); cx.window.root_view = Some(root_view.clone().into_any()); cx.window.focused_view_id = Some(root_view.id()); @@ -3912,6 +3917,13 @@ pub struct AnyWindowHandle { } impl AnyWindowHandle { + fn new(window_id: usize, root_view_type: TypeId) -> Self { + Self { + window_id, + root_view_type, + } + } + pub fn id(&self) -> usize { self.window_id } diff --git a/crates/gpui/src/app/menu.rs b/crates/gpui/src/app/menu.rs index a2ac13984bee5fcc7c248e5750080c84a5353aa0..1d8908b8fdda9627d2eb7df433a7c5b819f024ed 100644 --- a/crates/gpui/src/app/menu.rs +++ b/crates/gpui/src/app/menu.rs @@ -77,9 +77,9 @@ pub(crate) fn setup_menu_handlers(foreground_platform: &dyn ForegroundPlatform, let cx = app.0.clone(); move |action| { let mut cx = cx.borrow_mut(); - if let Some(main_window_id) = cx.platform.main_window_id() { - let dispatched = cx - .update_window(main_window_id, |cx| { + if let Some(main_window) = cx.main_window() { + let dispatched = main_window + .update(&mut *cx, |cx| { if let Some(view_id) = cx.focused_view_id() { cx.dispatch_action(Some(view_id), action); true diff --git a/crates/gpui/src/app/test_app_context.rs b/crates/gpui/src/app/test_app_context.rs index 5b005d7d6f2cd527321c97b3690576433ed132e7..dcbe810804b6ac8331a3a3da20868040c10fcd8d 100644 --- a/crates/gpui/src/app/test_app_context.rs +++ b/crates/gpui/src/app/test_app_context.rs @@ -198,8 +198,8 @@ impl TestAppContext { self.cx.borrow_mut().subscribe_global(callback) } - pub fn windows(&self) -> impl Iterator { - self.cx.borrow().windows() + pub fn windows(&self) -> Vec { + self.cx.borrow().windows().collect() } // pub fn window_ids(&self) -> Vec { @@ -322,15 +322,15 @@ impl TestAppContext { pub fn simulate_window_activation(&self, to_activate: Option) { self.cx.borrow_mut().update(|cx| { - let other_windows = cx + let other_window_ids = cx .windows .keys() - .filter(|window| Some(window.id()) != to_activate) + .filter(|window_id| Some(**window_id) != to_activate) .copied() .collect::>(); - for window in other_windows { - cx.window_changed_active_status(window.id(), false) + for window_id in other_window_ids { + cx.window_changed_active_status(window_id, false) } if let Some(to_activate) = to_activate { From 3e0d0e5c010f3f5f0c8e964af5fcfce621705b14 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 7 Aug 2023 13:54:47 -0600 Subject: [PATCH 10/41] WIP --- crates/gpui/src/app.rs | 186 ++++++++++++++++---- crates/gpui/src/app/test_app_context.rs | 59 ++++--- crates/gpui/src/app/window.rs | 16 +- crates/gpui/src/app/window_input_handler.rs | 27 ++- crates/workspace/src/workspace.rs | 11 +- 5 files changed, 221 insertions(+), 78 deletions(-) diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index c2d2397d9c4f4e00ff73cb92358de2423f85a383..730d0da5a054ea808dedd236892d4ca14aeefc30 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -133,12 +133,18 @@ pub trait BorrowAppContext { pub trait BorrowWindowContext { type Result; - fn read_window_with(&self, window_id: usize, f: F) -> Self::Result + fn read_window(&self, window_id: usize, f: F) -> Self::Result where F: FnOnce(&WindowContext) -> T; + fn read_window_optional(&self, window_id: usize, f: F) -> Option + where + F: FnOnce(&WindowContext) -> Option; fn update_window(&mut self, window_id: usize, f: F) -> Self::Result where F: FnOnce(&mut WindowContext) -> T; + fn update_window_optional(&mut self, window_id: usize, f: F) -> Option + where + F: FnOnce(&mut WindowContext) -> Option; } #[derive(Clone)] @@ -449,13 +455,22 @@ impl BorrowAppContext for AsyncAppContext { impl BorrowWindowContext for AsyncAppContext { type Result = Option; - fn read_window_with(&self, window_id: usize, f: F) -> Self::Result + fn read_window(&self, window_id: usize, f: F) -> Self::Result where F: FnOnce(&WindowContext) -> T, { self.0.borrow().read_with(|cx| cx.read_window(window_id, f)) } + fn read_window_optional(&self, window_id: usize, f: F) -> Option + where + F: FnOnce(&WindowContext) -> Option, + { + self.0 + .borrow_mut() + .update(|cx| cx.read_window_optional(window_id, f)) + } + fn update_window(&mut self, window_id: usize, f: F) -> Self::Result where F: FnOnce(&mut WindowContext) -> T, @@ -464,6 +479,15 @@ impl BorrowWindowContext for AsyncAppContext { .borrow_mut() .update(|cx| cx.update_window(window_id, f)) } + + fn update_window_optional(&mut self, window_id: usize, f: F) -> Option + where + F: FnOnce(&mut WindowContext) -> Option, + { + self.0 + .borrow_mut() + .update(|cx| cx.update_window_optional(window_id, f)) + } } type ActionCallback = dyn FnMut(&mut dyn AnyView, &dyn Action, &mut WindowContext, usize); @@ -1303,13 +1327,14 @@ impl AppContext { F: FnOnce(&mut ViewContext) -> V, { self.update(|this| { - let window = WindowHandle::::new(post_inc(&mut this.next_id)); + let window_id = post_inc(&mut this.next_id); let platform_window = this.platform - .open_window(window, window_options, this.foreground.clone()); - let window = this.build_window(window, platform_window, build_root_view); - this.windows.insert(window.into(), window); - window + .open_window(window_id, window_options, this.foreground.clone()); + let handle = WindowHandle::::new(window_id); + let window = this.build_window(handle, platform_window, build_root_view); + this.windows.insert(window_id, window); + handle }) } @@ -1319,11 +1344,11 @@ impl AppContext { F: FnOnce(&mut ViewContext) -> V, { self.update(|this| { - let handle = WindowHandle::::new(post_inc(&mut this.next_id)); - let platform_window = this.platform.add_status_item(handle.id()); + let window_id = post_inc(&mut this.next_id); + let platform_window = this.platform.add_status_item(window_id); + let handle = WindowHandle::::new(window_id); let window = this.build_window(handle, platform_window, build_root_view); - - this.windows.insert(handle.into(), window); + this.windows.insert(window_id, window); handle.update_root(this, |view, cx| view.focus_in(cx.handle().into_any(), cx)); handle }) @@ -1340,11 +1365,14 @@ impl AppContext { V: View, F: FnOnce(&mut ViewContext) -> V, { + let handle: AnyWindowHandle = handle.into(); + let window_id = handle.id(); + { let mut app = self.upgrade(); platform_window.on_event(Box::new(move |event| { - app.update_window(handle, |cx| { + app.update_window(window_id, |cx| { if let Event::KeyDown(KeyDownEvent { keystroke, .. }) = &event { if cx.dispatch_keystroke(keystroke) { return true; @@ -1360,35 +1388,35 @@ impl AppContext { { let mut app = self.upgrade(); platform_window.on_active_status_change(Box::new(move |is_active| { - app.update(|cx| cx.window_changed_active_status(handle, is_active)) + app.update(|cx| cx.window_changed_active_status(window_id, is_active)) })); } { let mut app = self.upgrade(); platform_window.on_resize(Box::new(move || { - app.update(|cx| cx.window_was_resized(handle)) + app.update(|cx| cx.window_was_resized(window_id)) })); } { let mut app = self.upgrade(); platform_window.on_moved(Box::new(move || { - app.update(|cx| cx.window_was_moved(handle)) + app.update(|cx| cx.window_was_moved(window_id)) })); } { let mut app = self.upgrade(); platform_window.on_fullscreen(Box::new(move |is_fullscreen| { - app.update(|cx| cx.window_was_fullscreen_changed(handle, is_fullscreen)) + app.update(|cx| cx.window_was_fullscreen_changed(window_id, is_fullscreen)) })); } { let mut app = self.upgrade(); platform_window.on_close(Box::new(move || { - app.update(|cx| cx.update_window(handle, |cx| cx.remove_window())); + app.update(|cx| cx.update_window(window_id, |cx| cx.remove_window())); })); } @@ -1400,11 +1428,11 @@ impl AppContext { platform_window.set_input_handler(Box::new(WindowInputHandler { app: self.upgrade().0, - window_id: handle, + window: handle, })); - let mut window = Window::new(handle, platform_window, self, build_root_view); - let mut cx = WindowContext::mutable(self, &mut window, handle); + let mut window = Window::new(window_id, platform_window, self, build_root_view); + let mut cx = WindowContext::mutable(self, &mut window, window_id); cx.layout(false).expect("initial layout should not error"); let scene = cx.paint().expect("initial paint should not error"); window.platform_window.present_scene(scene); @@ -2156,13 +2184,20 @@ impl BorrowAppContext for AppContext { impl BorrowWindowContext for AppContext { type Result = Option; - fn read_window_with(&self, window_id: usize, f: F) -> Self::Result + fn read_window(&self, window_id: usize, f: F) -> Self::Result where F: FnOnce(&WindowContext) -> T, { AppContext::read_window(self, window_id, f) } + fn read_window_optional(&self, window_id: usize, f: F) -> Option + where + F: FnOnce(&WindowContext) -> Option, + { + AppContext::read_window(self, window_id, f).flatten() + } + fn update_window(&mut self, window_id: usize, f: F) -> Self::Result where F: FnOnce(&mut WindowContext) -> T, @@ -2177,6 +2212,13 @@ impl BorrowWindowContext for AppContext { Some(result) }) } + + fn update_window_optional(&mut self, window_id: usize, f: F) -> Option + where + F: FnOnce(&mut WindowContext) -> Option, + { + AppContext::update_window(self, window_id, f).flatten() + } } #[derive(Debug)] @@ -3379,8 +3421,15 @@ impl BorrowAppContext for ViewContext<'_, '_, V> { impl BorrowWindowContext for ViewContext<'_, '_, V> { type Result = T; - fn read_window_with T>(&self, window_id: usize, f: F) -> T { - BorrowWindowContext::read_window_with(&*self.window_context, window_id, f) + fn read_window T>(&self, window_id: usize, f: F) -> T { + BorrowWindowContext::read_window(&*self.window_context, window_id, f) + } + + fn read_window_optional(&self, window_id: usize, f: F) -> Option + where + F: FnOnce(&WindowContext) -> Option, + { + BorrowWindowContext::read_window_optional(&*self.window_context, window_id, f) } fn update_window T>( @@ -3390,6 +3439,13 @@ impl BorrowWindowContext for ViewContext<'_, '_, V> { ) -> T { BorrowWindowContext::update_window(&mut *self.window_context, window_id, f) } + + fn update_window_optional(&mut self, window_id: usize, f: F) -> Option + where + F: FnOnce(&mut WindowContext) -> Option, + { + BorrowWindowContext::update_window_optional(&mut *self.window_context, window_id, f) + } } pub struct LayoutContext<'a, 'b, 'c, V: View> { @@ -3490,8 +3546,15 @@ impl BorrowAppContext for LayoutContext<'_, '_, '_, V> { impl BorrowWindowContext for LayoutContext<'_, '_, '_, V> { type Result = T; - fn read_window_with T>(&self, window_id: usize, f: F) -> T { - BorrowWindowContext::read_window_with(&*self.view_context, window_id, f) + fn read_window T>(&self, window_id: usize, f: F) -> T { + BorrowWindowContext::read_window(&*self.view_context, window_id, f) + } + + fn read_window_optional(&self, window_id: usize, f: F) -> Option + where + F: FnOnce(&WindowContext) -> Option, + { + BorrowWindowContext::read_window_optional(&*self.view_context, window_id, f) } fn update_window T>( @@ -3501,6 +3564,13 @@ impl BorrowWindowContext for LayoutContext<'_, '_, '_, V> { ) -> T { BorrowWindowContext::update_window(&mut *self.view_context, window_id, f) } + + fn update_window_optional(&mut self, window_id: usize, f: F) -> Option + where + F: FnOnce(&mut WindowContext) -> Option, + { + BorrowWindowContext::update_window_optional(&mut *self.view_context, window_id, f) + } } pub struct EventContext<'a, 'b, 'c, V: View> { @@ -3548,8 +3618,15 @@ impl BorrowAppContext for EventContext<'_, '_, '_, V> { impl BorrowWindowContext for EventContext<'_, '_, '_, V> { type Result = T; - fn read_window_with T>(&self, window_id: usize, f: F) -> T { - BorrowWindowContext::read_window_with(&*self.view_context, window_id, f) + fn read_window T>(&self, window_id: usize, f: F) -> T { + BorrowWindowContext::read_window(&*self.view_context, window_id, f) + } + + fn read_window_optional(&self, window_id: usize, f: F) -> Option + where + F: FnOnce(&WindowContext) -> Option, + { + BorrowWindowContext::read_window_optional(&*self.view_context, window_id, f) } fn update_window T>( @@ -3559,6 +3636,13 @@ impl BorrowWindowContext for EventContext<'_, '_, '_, V> { ) -> T { BorrowWindowContext::update_window(&mut *self.view_context, window_id, f) } + + fn update_window_optional(&mut self, window_id: usize, f: F) -> Option + where + F: FnOnce(&mut WindowContext) -> Option, + { + BorrowWindowContext::update_window_optional(&mut *self.view_context, window_id, f) + } } pub(crate) enum Reference<'a, T> { @@ -3841,13 +3925,24 @@ impl Clone for WeakModelHandle { impl Copy for WeakModelHandle {} -#[derive(Deref, Copy, Clone)] -pub struct WindowHandle { +#[derive(Deref)] +pub struct WindowHandle { #[deref] any_handle: AnyWindowHandle, - root_view_type: PhantomData, + root_view_type: PhantomData, +} + +impl Clone for WindowHandle { + fn clone(&self) -> Self { + Self { + any_handle: self.any_handle.clone(), + root_view_type: PhantomData, + } + } } +impl Copy for WindowHandle {} + impl WindowHandle { fn new(window_id: usize) -> Self { WindowHandle { @@ -3933,7 +4028,15 @@ impl AnyWindowHandle { C: BorrowWindowContext, F: FnOnce(&WindowContext) -> R, { - cx.read_window_with(self.window_id, |cx| read(cx)) + cx.read_window(self.window_id, |cx| read(cx)) + } + + pub fn read_optional_with(&self, cx: &C, read: F) -> Option + where + C: BorrowWindowContext, + F: FnOnce(&WindowContext) -> Option, + { + cx.read_window_optional(self.window_id, |cx| read(cx)) } pub fn update(&self, cx: &mut C, update: F) -> C::Result @@ -3944,6 +4047,14 @@ impl AnyWindowHandle { cx.update_window(self.window_id, update) } + pub fn update_optional(&self, cx: &mut C, update: F) -> Option + where + C: BorrowWindowContext, + F: FnOnce(&mut WindowContext) -> Option, + { + cx.update_window_optional(self.window_id, update) + } + pub fn add_view(&self, cx: &mut C, build_view: F) -> C::Result> where C: BorrowWindowContext, @@ -3953,6 +4064,17 @@ impl AnyWindowHandle { self.update(cx, |cx| cx.add_view(build_view)) } + pub fn downcast(self) -> Option> { + if self.root_view_type == TypeId::of::() { + Some(WindowHandle { + any_handle: self, + root_view_type: PhantomData, + }) + } else { + None + } + } + pub fn root_is(&self) -> bool { self.root_view_type == TypeId::of::() } @@ -4018,7 +4140,7 @@ impl ViewHandle { C: BorrowWindowContext, F: FnOnce(&T, &ViewContext) -> S, { - cx.read_window_with(self.window_id, |cx| { + cx.read_window(self.window_id, |cx| { let cx = ViewContext::immutable(cx, self.view_id); read(cx.read_view(self), &cx) }) diff --git a/crates/gpui/src/app/test_app_context.rs b/crates/gpui/src/app/test_app_context.rs index dcbe810804b6ac8331a3a3da20868040c10fcd8d..0331c7922e680fe1c45460bc2569c85ab77a3f19 100644 --- a/crates/gpui/src/app/test_app_context.rs +++ b/crates/gpui/src/app/test_app_context.rs @@ -92,33 +92,34 @@ impl TestAppContext { self.update(|cx| cx.dispatch_global_action_any(&action)); } - pub fn dispatch_keystroke(&mut self, window_id: usize, keystroke: Keystroke, is_held: bool) { - let handled = self - .cx - .borrow_mut() - .update_window(window_id, |cx| { - if cx.dispatch_keystroke(&keystroke) { - return true; - } + pub fn dispatch_keystroke( + &mut self, + window: AnyWindowHandle, + keystroke: Keystroke, + is_held: bool, + ) { + let handled = window.update(self, |cx| { + if cx.dispatch_keystroke(&keystroke) { + return true; + } - if cx.dispatch_event( - Event::KeyDown(KeyDownEvent { - keystroke: keystroke.clone(), - is_held, - }), - false, - ) { - return true; - } + if cx.dispatch_event( + Event::KeyDown(KeyDownEvent { + keystroke: keystroke.clone(), + is_held, + }), + false, + ) { + return true; + } - false - }) - .unwrap_or(false); + false + }); if !handled && !keystroke.cmd && !keystroke.ctrl { WindowInputHandler { app: self.cx.clone(), - window_id, + window, } .replace_text_in_range(None, &keystroke.key) } @@ -419,13 +420,20 @@ impl BorrowAppContext for TestAppContext { impl BorrowWindowContext for TestAppContext { type Result = T; - fn read_window_with T>(&self, window_id: usize, f: F) -> T { + fn read_window T>(&self, window_id: usize, f: F) -> T { self.cx .borrow() .read_window(window_id, f) .expect("window was closed") } + fn read_window_optional(&self, window_id: usize, f: F) -> Option + where + F: FnOnce(&WindowContext) -> Option, + { + BorrowWindowContext::read_window(self, window_id, f) + } + fn update_window T>( &mut self, window_id: usize, @@ -436,6 +444,13 @@ impl BorrowWindowContext for TestAppContext { .update_window(window_id, f) .expect("window was closed") } + + fn update_window_optional(&mut self, window_id: usize, f: F) -> Option + where + F: FnOnce(&mut WindowContext) -> Option, + { + BorrowWindowContext::update_window(self, window_id, f) + } } impl ModelHandle { diff --git a/crates/gpui/src/app/window.rs b/crates/gpui/src/app/window.rs index cc8468edbd7dbced86061e70a2b17d7ee4578691..d960b9da16a7c84d46fda2b17cd2650204aa1c08 100644 --- a/crates/gpui/src/app/window.rs +++ b/crates/gpui/src/app/window.rs @@ -144,7 +144,7 @@ impl BorrowAppContext for WindowContext<'_> { impl BorrowWindowContext for WindowContext<'_> { type Result = T; - fn read_window_with T>(&self, window_id: usize, f: F) -> T { + fn read_window T>(&self, window_id: usize, f: F) -> T { if self.window_id == window_id { f(self) } else { @@ -152,6 +152,13 @@ impl BorrowWindowContext for WindowContext<'_> { } } + fn read_window_optional(&self, window_id: usize, f: F) -> Option + where + F: FnOnce(&WindowContext) -> Option, + { + BorrowWindowContext::read_window(self, window_id, f) + } + fn update_window T>( &mut self, window_id: usize, @@ -163,6 +170,13 @@ impl BorrowWindowContext for WindowContext<'_> { panic!("update called with id of window that does not belong to this context") } } + + fn update_window_optional(&mut self, window_id: usize, f: F) -> Option + where + F: FnOnce(&mut WindowContext) -> Option, + { + BorrowWindowContext::update_window_optional(self, window_id, f) + } } impl<'a> WindowContext<'a> { diff --git a/crates/gpui/src/app/window_input_handler.rs b/crates/gpui/src/app/window_input_handler.rs index 8ee9f7eeff5c2a3e4f4d63ca55c9338f02e3ed69..d7c65b11fae6f6c66de0c4c0a1c4302400d651ba 100644 --- a/crates/gpui/src/app/window_input_handler.rs +++ b/crates/gpui/src/app/window_input_handler.rs @@ -2,11 +2,11 @@ use std::{cell::RefCell, ops::Range, rc::Rc}; use pathfinder_geometry::rect::RectF; -use crate::{platform::InputHandler, window::WindowContext, AnyView, AppContext}; +use crate::{platform::InputHandler, window::WindowContext, AnyView, AnyWindowHandle, AppContext}; pub struct WindowInputHandler { pub app: Rc>, - pub window_id: usize, + pub window: AnyWindowHandle, } impl WindowInputHandler { @@ -21,13 +21,12 @@ impl WindowInputHandler { // // See https://github.com/zed-industries/community/issues/444 let mut app = self.app.try_borrow_mut().ok()?; - app.update_window(self.window_id, |cx| { + self.window.update_optional(&mut *app, |cx| { let view_id = cx.window.focused_view_id?; - let view = cx.views.get(&(self.window_id, view_id))?; + let view = cx.views.get(&(self.window.id(), view_id))?; let result = f(view.as_ref(), &cx); Some(result) }) - .flatten() } fn update_focused_view(&mut self, f: F) -> Option @@ -35,11 +34,12 @@ impl WindowInputHandler { F: FnOnce(&mut dyn AnyView, &mut WindowContext, usize) -> T, { let mut app = self.app.try_borrow_mut().ok()?; - app.update_window(self.window_id, |cx| { - let view_id = cx.window.focused_view_id?; - cx.update_any_view(view_id, |view, cx| f(view, cx, view_id)) - }) - .flatten() + self.window + .update(&mut *app, |cx| { + let view_id = cx.window.focused_view_id?; + cx.update_any_view(view_id, |view, cx| f(view, cx, view_id)) + }) + .flatten() } } @@ -83,9 +83,8 @@ impl InputHandler for WindowInputHandler { } fn rect_for_range(&self, range_utf16: Range) -> Option { - self.app - .borrow() - .read_window(self.window_id, |cx| cx.rect_for_text_range(range_utf16)) - .flatten() + self.window.read_optional_with(&*self.app.borrow(), |cx| { + cx.rect_for_text_range(range_utf16) + }) } } diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 37fab1ee462d7a242c331ea5df169babbae3a6d8..c5e0e7e1ad6e2cb83b6c9cdb3dbd01f8f1687d3c 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -4035,16 +4035,9 @@ pub fn restart(_: &Restart, cx: &mut AppContext) { let should_confirm = settings::get::(cx).confirm_quit; cx.spawn(|mut cx| async move { let mut workspaces = cx - .window_ids() + .windows() .into_iter() - .filter_map(|window_id| { - Some( - cx.root_view(window_id)? - .clone() - .downcast::()? - .downgrade(), - ) - }) + .filter_map(|window| Some(window.downcast::()?.root(&cx)?.downgrade())) .collect::>(); // If multiple windows have unsaved changes, and need a save prompt, From 4e33654abaafd22de5140cc6e40f342351047a2a Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 7 Aug 2023 13:53:41 -0700 Subject: [PATCH 11/41] Make LspAdapter::process_diagnostics synchronous Co-authored-by: Nathan --- crates/language/src/language.rs | 14 ++++---------- crates/project/src/project.rs | 29 +++++++++++++---------------- crates/zed/src/languages/rust.rs | 4 ++-- 3 files changed, 19 insertions(+), 28 deletions(-) diff --git a/crates/language/src/language.rs b/crates/language/src/language.rs index 125e14d445f3872e9718cb2759016a09b0c28439..100ab275717066251973c3f6d547e32f72ff0b4c 100644 --- a/crates/language/src/language.rs +++ b/crates/language/src/language.rs @@ -182,8 +182,8 @@ impl CachedLspAdapter { self.adapter.workspace_configuration(cx) } - pub async fn process_diagnostics(&self, params: &mut lsp::PublishDiagnosticsParams) { - self.adapter.process_diagnostics(params).await + pub fn process_diagnostics(&self, params: &mut lsp::PublishDiagnosticsParams) { + self.adapter.process_diagnostics(params) } pub async fn process_completion(&self, completion_item: &mut lsp::CompletionItem) { @@ -262,7 +262,7 @@ pub trait LspAdapter: 'static + Send + Sync { container_dir: PathBuf, ) -> Option; - async fn process_diagnostics(&self, _: &mut lsp::PublishDiagnosticsParams) {} + fn process_diagnostics(&self, _: &mut lsp::PublishDiagnosticsParams) {} async fn process_completion(&self, _: &mut lsp::CompletionItem) {} @@ -1487,12 +1487,6 @@ impl Language { None } - pub async fn process_diagnostics(&self, diagnostics: &mut lsp::PublishDiagnosticsParams) { - for adapter in &self.adapters { - adapter.process_diagnostics(diagnostics).await; - } - } - pub async fn process_completion(self: &Arc, completion: &mut lsp::CompletionItem) { for adapter in &self.adapters { adapter.process_completion(completion).await; @@ -1756,7 +1750,7 @@ impl LspAdapter for Arc { unreachable!(); } - async fn process_diagnostics(&self, _: &mut lsp::PublishDiagnosticsParams) {} + fn process_diagnostics(&self, _: &mut lsp::PublishDiagnosticsParams) {} async fn disk_based_diagnostic_sources(&self) -> Vec { self.disk_based_diagnostics_sources.clone() diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index 6b905a1faa876bafd793b5e6fc02be4aacc437c2..1aa2a2dd40c2d01b98860d39420c6ec4ab894728 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -2769,24 +2769,21 @@ impl Project { language_server .on_notification::({ let adapter = adapter.clone(); - move |mut params, cx| { + move |mut params, mut cx| { let this = this; let adapter = adapter.clone(); - cx.spawn(|mut cx| async move { - adapter.process_diagnostics(&mut params).await; - if let Some(this) = this.upgrade(&cx) { - this.update(&mut cx, |this, cx| { - this.update_diagnostics( - server_id, - params, - &adapter.disk_based_diagnostic_sources, - cx, - ) - .log_err(); - }); - } - }) - .detach(); + adapter.process_diagnostics(&mut params); + if let Some(this) = this.upgrade(&cx) { + this.update(&mut cx, |this, cx| { + this.update_diagnostics( + server_id, + params, + &adapter.disk_based_diagnostic_sources, + cx, + ) + .log_err(); + }); + } } }) .detach(); diff --git a/crates/zed/src/languages/rust.rs b/crates/zed/src/languages/rust.rs index 97549b00583d45f3b03a730d2a10f43dc9b2f978..3c7f84fec7dced7f8241ff7009160b0d748191f4 100644 --- a/crates/zed/src/languages/rust.rs +++ b/crates/zed/src/languages/rust.rs @@ -102,7 +102,7 @@ impl LspAdapter for RustLspAdapter { Some("rust-analyzer/flycheck".into()) } - async fn process_diagnostics(&self, params: &mut lsp::PublishDiagnosticsParams) { + fn process_diagnostics(&self, params: &mut lsp::PublishDiagnosticsParams) { lazy_static! { static ref REGEX: Regex = Regex::new("(?m)`([^`]+)\n`$").unwrap(); } @@ -310,7 +310,7 @@ mod tests { }, ], }; - RustLspAdapter.process_diagnostics(&mut params).await; + RustLspAdapter.process_diagnostics(&mut params); assert_eq!(params.diagnostics[0].message, "use of moved value `a`"); From 580c2ea8eb7ec308ba0dc1d003b8addb212bc371 Mon Sep 17 00:00:00 2001 From: "Joseph T. Lyons" Date: Mon, 7 Aug 2023 17:07:01 -0400 Subject: [PATCH 12/41] Fix test name --- crates/util/src/paths.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/util/src/paths.rs b/crates/util/src/paths.rs index 7e0b240570f249b7dc97b17ea0fc85581fd44410..f231669197fcfdd560011132e406772da64e3050 100644 --- a/crates/util/src/paths.rs +++ b/crates/util/src/paths.rs @@ -294,7 +294,7 @@ mod tests { } #[test] - fn test_path_suffix() { + fn test_icon_suffix() { // No dots in name let path = Path::new("/a/b/c/file_name.rs"); assert_eq!(path.icon_suffix(), Some("rs")); From dbf25ea2ffbb77c8ad2276860c4e24a1da4fd70d Mon Sep 17 00:00:00 2001 From: "Joseph T. Lyons" Date: Mon, 7 Aug 2023 17:24:22 -0400 Subject: [PATCH 13/41] Add syntax highlighting for Cargo.toml files --- crates/zed/src/languages/toml/config.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/zed/src/languages/toml/config.toml b/crates/zed/src/languages/toml/config.toml index 4e89f5cabd99fb2faf120b32943be31d20d2a514..188239a8e0d2b518c99b9b6f69a14632bae37926 100644 --- a/crates/zed/src/languages/toml/config.toml +++ b/crates/zed/src/languages/toml/config.toml @@ -1,5 +1,5 @@ name = "TOML" -path_suffixes = ["toml"] +path_suffixes = ["Cargo.lock", "toml"] line_comment = "# " autoclose_before = ",]}" brackets = [ From ca21626064d078867c7241d7eb39b09f763fa894 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Mon, 7 Aug 2023 23:32:27 +0200 Subject: [PATCH 14/41] Baseline: Improve selection rendering for large quantities from 270ms to 90ms --- crates/editor/src/editor.rs | 64 +++++++++++++++++++++++++++++++++- crates/editor/src/element.rs | 67 +++++++++++++----------------------- 2 files changed, 86 insertions(+), 45 deletions(-) diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index cd5e86b91098b35cad385331d5e8f28a380d3139..8f8511deb697913c1e8e1fcebd6702177d504c34 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -90,7 +90,7 @@ use std::{ cmp::{self, Ordering, Reverse}, mem, num::NonZeroU32, - ops::{ControlFlow, Deref, DerefMut, Range}, + ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive}, path::Path, sync::Arc, time::{Duration, Instant}, @@ -7549,6 +7549,68 @@ impl Editor { results } + pub fn selected_rows( + &self, + search_range: Range, + display_snapshot: &DisplaySnapshot, + theme: &Theme, + ) -> Vec> { + let mut results = Vec::new(); + let buffer = &display_snapshot.buffer_snapshot; + let Some((color_fetcher, ranges)) = self.background_highlights + .get(&TypeId::of::()) else { + return vec![]; + }; + + let color = color_fetcher(theme); + let start_ix = match ranges.binary_search_by(|probe| { + let cmp = probe.end.cmp(&search_range.start, buffer); + if cmp.is_gt() { + Ordering::Greater + } else { + Ordering::Less + } + }) { + Ok(i) | Err(i) => i, + }; + let mut push_region = |start, end| { + if let (Some(start_display), Some(end_display)) = (start, end) { + results.push(start_display..=end_display); + } + }; + let mut start_row = None; + let mut end_row = None; + for range in &ranges[start_ix..] { + if range.start.cmp(&search_range.end, buffer).is_ge() { + break; + } + let start = range.start.to_point(buffer).row; + let end = range.end.to_point(buffer).row; + if start_row.is_none() { + assert_eq!(end_row, None); + start_row = Some(start); + end_row = Some(end); + continue; + } + if let Some(current_end) = end_row.as_mut() { + if start > *current_end + 1 { + push_region(start_row, end_row); + start_row = Some(start); + end_row = Some(end); + } else { + // Merge two hunks. + *current_end = end; + } + } else { + unreachable!(); + } + } + // We might still have a hunk that was not rendered (if there was a search hit on the last line) + push_region(start_row, end_row); + + results + } + pub fn highlight_text( &mut self, ranges: Vec>, diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 2d4b273f5ef0523f8ef8d9d9cd107c7e30bd659d..9ef95ec929a9ebb1425eed4c049f159e95c00466 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -1107,8 +1107,6 @@ impl EditorElement { if layout.is_singleton && scrollbar_settings.selections { let start_anchor = Anchor::min(); let end_anchor = Anchor::max(); - let mut start_row = None; - let mut end_row = None; let color = scrollbar_theme.selections; let border = Border { width: 1., @@ -1119,54 +1117,35 @@ impl EditorElement { bottom: false, left: true, }; - let mut push_region = |start, end| { - if let (Some(start_display), Some(end_display)) = (start, end) { - let start_y = y_for_row(start_display as f32); - let mut end_y = y_for_row(end_display 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)); - - scene.push_quad(Quad { - bounds, - background: Some(color), - border, - corner_radius: style.thumb.corner_radius, - }) + let mut push_region = |start: u32, end: u32| { + let start_y = y_for_row(start as f32); + let mut end_y = y_for_row(end 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)); + + scene.push_quad(Quad { + bounds, + background: Some(color), + border, + corner_radius: style.thumb.corner_radius, + }) }; - for (row, _) in &editor - .background_highlights_in_range_for::( + let start = std::time::Instant::now(); + + let background_ranges = editor + .selected_rows::( start_anchor..end_anchor, &layout.position_map.snapshot, &theme, - ) - { - let start_display = row.start; - let end_display = row.end; - - if start_row.is_none() { - assert_eq!(end_row, None); - start_row = Some(start_display.row()); - end_row = Some(end_display.row()); - continue; - } - if let Some(current_end) = end_row.as_mut() { - if start_display.row() > *current_end + 1 { - push_region(start_row, end_row); - start_row = Some(start_display.row()); - end_row = Some(end_display.row()); - } else { - // Merge two hunks. - *current_end = end_display.row(); - } - } else { - unreachable!(); - } + ); + dbg!(start.elapsed().as_millis()); + for row in background_ranges { + let start = row.start(); + let end = row.end(); + push_region(*start, *end); } - // We might still have a hunk that was not rendered (if there was a search hit on the last line) - push_region(start_row, end_row); } if layout.is_singleton && scrollbar_settings.git_diff { From fa168959764defa98ed2c7ce5173f38afb6135aa Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Tue, 8 Aug 2023 00:27:38 +0200 Subject: [PATCH 15/41] Do not query start of range if it's end is the same as the previous hunk's --- crates/editor/src/editor.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 8f8511deb697913c1e8e1fcebd6702177d504c34..c12bdc9c55c9b97a96da6452c6ca8ea9a8512098 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -7557,12 +7557,11 @@ impl Editor { ) -> Vec> { let mut results = Vec::new(); let buffer = &display_snapshot.buffer_snapshot; - let Some((color_fetcher, ranges)) = self.background_highlights + let Some((_, ranges)) = self.background_highlights .get(&TypeId::of::()) else { return vec![]; }; - let color = color_fetcher(theme); let start_ix = match ranges.binary_search_by(|probe| { let cmp = probe.end.cmp(&search_range.start, buffer); if cmp.is_gt() { @@ -7584,8 +7583,14 @@ impl Editor { if range.start.cmp(&search_range.end, buffer).is_ge() { break; } - let start = range.start.to_point(buffer).row; let end = range.end.to_point(buffer).row; + if let Some(current_row) = &end_row { + if end == *current_row { + continue; + } + } + let start = range.start.to_point(buffer).row; + if start_row.is_none() { assert_eq!(end_row, None); start_row = Some(start); From 42e12213571d475b5019113b49c1a88b3f0f0a30 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Tue, 8 Aug 2023 02:17:11 +0200 Subject: [PATCH 16/41] Add upper bound limit. Remove dbg! statements --- crates/editor/src/editor.rs | 4 +++- crates/editor/src/element.rs | 4 +--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index c12bdc9c55c9b97a96da6452c6ca8ea9a8512098..682974d61fb3b2993048db2105c740617cfba04e 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -7553,6 +7553,7 @@ impl Editor { &self, search_range: Range, display_snapshot: &DisplaySnapshot, + count: usize, theme: &Theme, ) -> Vec> { let mut results = Vec::new(); @@ -7572,6 +7573,7 @@ impl Editor { }) { Ok(i) | Err(i) => i, }; + let end_ix = count.min(ranges.len()); let mut push_region = |start, end| { if let (Some(start_display), Some(end_display)) = (start, end) { results.push(start_display..=end_display); @@ -7579,7 +7581,7 @@ impl Editor { }; let mut start_row = None; let mut end_row = None; - for range in &ranges[start_ix..] { + for range in &ranges[start_ix..end_ix] { if range.start.cmp(&search_range.end, buffer).is_ge() { break; } diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 9ef95ec929a9ebb1425eed4c049f159e95c00466..735abbbd13f0dd834c461f3792bd4adedd1b3f9b 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -1132,15 +1132,13 @@ impl EditorElement { corner_radius: style.thumb.corner_radius, }) }; - let start = std::time::Instant::now(); - let background_ranges = editor .selected_rows::( start_anchor..end_anchor, &layout.position_map.snapshot, + 50000, &theme, ); - dbg!(start.elapsed().as_millis()); for row in background_ranges { let start = row.start(); let end = row.end(); From 241d3951b8193d2ee1ba8fd177815531334da33b Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Tue, 8 Aug 2023 02:25:30 +0200 Subject: [PATCH 17/41] Remove redundant argument --- crates/editor/src/editor.rs | 1 - crates/editor/src/element.rs | 1 - 2 files changed, 2 deletions(-) diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 682974d61fb3b2993048db2105c740617cfba04e..0711e5eb024b6cfa9ea0b3f5bc6ee313d4c2cd52 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -7554,7 +7554,6 @@ impl Editor { search_range: Range, display_snapshot: &DisplaySnapshot, count: usize, - theme: &Theme, ) -> Vec> { let mut results = Vec::new(); let buffer = &display_snapshot.buffer_snapshot; diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 735abbbd13f0dd834c461f3792bd4adedd1b3f9b..c3c8681bcf0d572419c144ce410bdc32b52426b5 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -1137,7 +1137,6 @@ impl EditorElement { start_anchor..end_anchor, &layout.position_map.snapshot, 50000, - &theme, ); for row in background_ranges { let start = row.start(); From b0fc6da55b495dc5f43a934ee8b2d67eb1fbe62e Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Tue, 8 Aug 2023 02:37:27 +0200 Subject: [PATCH 18/41] Use display maps --- crates/editor/src/editor.rs | 21 ++++++++++++--------- crates/editor/src/element.rs | 6 +++--- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 0711e5eb024b6cfa9ea0b3f5bc6ee313d4c2cd52..8f4f97ad604dc15c47dbc2373495919059497dab 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -7554,7 +7554,7 @@ impl Editor { search_range: Range, display_snapshot: &DisplaySnapshot, count: usize, - ) -> Vec> { + ) -> Vec> { let mut results = Vec::new(); let buffer = &display_snapshot.buffer_snapshot; let Some((_, ranges)) = self.background_highlights @@ -7573,24 +7573,27 @@ impl Editor { Ok(i) | Err(i) => i, }; let end_ix = count.min(ranges.len()); - let mut push_region = |start, end| { + let mut push_region = |start: Option, end: Option| { if let (Some(start_display), Some(end_display)) = (start, end) { - results.push(start_display..=end_display); + results.push( + start_display.to_display_point(display_snapshot) + ..=end_display.to_display_point(display_snapshot), + ); } }; - let mut start_row = None; - let mut end_row = None; + let mut start_row: Option = None; + let mut end_row: Option = None; for range in &ranges[start_ix..end_ix] { if range.start.cmp(&search_range.end, buffer).is_ge() { break; } - let end = range.end.to_point(buffer).row; + let end = range.end.to_point(buffer); if let Some(current_row) = &end_row { - if end == *current_row { + if end.row == current_row.row { continue; } } - let start = range.start.to_point(buffer).row; + let start = range.start.to_point(buffer); if start_row.is_none() { assert_eq!(end_row, None); @@ -7599,7 +7602,7 @@ impl Editor { continue; } if let Some(current_end) = end_row.as_mut() { - if start > *current_end + 1 { + if start.row > current_end.row + 1 { push_region(start_row, end_row); start_row = Some(start); end_row = Some(end); diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index c3c8681bcf0d572419c144ce410bdc32b52426b5..30a9cba85c3e0bd92bc2fa0c2e121dc6e9949835 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -1117,9 +1117,9 @@ impl EditorElement { bottom: false, left: true, }; - let mut push_region = |start: u32, end: u32| { - let start_y = y_for_row(start as f32); - let mut end_y = y_for_row(end as f32); + let mut push_region = |start: DisplayPoint, end: DisplayPoint| { + let start_y = y_for_row(start.row() as f32); + let mut end_y = y_for_row(end.row() as f32); if end_y - start_y < 1. { end_y = start_y + 1.; } From 371c669e003f8082896706261779231b3c2dce11 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Tue, 8 Aug 2023 02:45:15 +0200 Subject: [PATCH 19/41] Address review feedback. Rename selected_rows to background_highlight_row_ranges. Do not return any ranges if there are more than 50k results --- crates/editor/src/editor.rs | 6 ++++-- crates/editor/src/element.rs | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 8f4f97ad604dc15c47dbc2373495919059497dab..17195cb22b5de1bc60c21c8169f929e020cc78f7 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -7549,7 +7549,7 @@ impl Editor { results } - pub fn selected_rows( + pub fn background_highlight_row_ranges( &self, search_range: Range, display_snapshot: &DisplaySnapshot, @@ -7616,7 +7616,9 @@ impl Editor { } // We might still have a hunk that was not rendered (if there was a search hit on the last line) push_region(start_row, end_row); - + if results.len() > count { + return vec![]; + } results } diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 30a9cba85c3e0bd92bc2fa0c2e121dc6e9949835..33ebd4c7bd632d5137b6f8f565e6e7010899abe1 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -1133,7 +1133,7 @@ impl EditorElement { }) }; let background_ranges = editor - .selected_rows::( + .background_highlight_row_ranges::( start_anchor..end_anchor, &layout.position_map.snapshot, 50000, From 486f5bc6ca186b07c415aea5794631c5f6cbcf80 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 7 Aug 2023 19:08:58 -0600 Subject: [PATCH 20/41] Get compiling --- crates/collab/src/tests/integration_tests.rs | 4 +- .../src/project_shared_notification.rs | 2 +- .../collab_ui/src/sharing_status_indicator.rs | 8 +- crates/editor/src/editor_tests.rs | 6 +- .../src/test/editor_lsp_test_context.rs | 2 +- crates/editor/src/test/editor_test_context.rs | 10 ++- crates/go_to_line/src/go_to_line.rs | 18 ++-- crates/gpui/src/app.rs | 7 ++ crates/gpui/src/app/window.rs | 2 +- crates/vim/src/editor_events.rs | 2 +- crates/vim/src/mode_indicator.rs | 2 +- crates/vim/src/test/vim_test_context.rs | 2 +- crates/workspace/src/workspace.rs | 52 ++++++----- crates/zed/src/zed.rs | 87 +++++++------------ 14 files changed, 97 insertions(+), 107 deletions(-) diff --git a/crates/collab/src/tests/integration_tests.rs b/crates/collab/src/tests/integration_tests.rs index 1a8e6d938d6d6caac2b8caee501e1088ddeea5b3..92ccee91c0ecb5cd6d8a0ca2af5928f9b6c3a72f 100644 --- a/crates/collab/src/tests/integration_tests.rs +++ b/crates/collab/src/tests/integration_tests.rs @@ -3446,7 +3446,7 @@ async fn test_newline_above_or_below_does_not_move_guest_cursor( let editor_a = window_a.add_view(cx_a, |cx| Editor::for_buffer(buffer_a, Some(project_a), cx)); let mut editor_cx_a = EditorTestContext { cx: cx_a, - window_id: window_a.id(), + window: window_a.into(), editor: editor_a, }; @@ -3459,7 +3459,7 @@ async fn test_newline_above_or_below_does_not_move_guest_cursor( let editor_b = window_b.add_view(cx_b, |cx| Editor::for_buffer(buffer_b, Some(project_b), cx)); let mut editor_cx_b = EditorTestContext { cx: cx_b, - window_id: window_b.id(), + window: window_b.into(), editor: editor_b, }; diff --git a/crates/collab_ui/src/project_shared_notification.rs b/crates/collab_ui/src/project_shared_notification.rs index 03ab91623b43270bf2592ced0f460b474fd0c435..d5e7c877f7067480688faedeb9b36be964878a72 100644 --- a/crates/collab_ui/src/project_shared_notification.rs +++ b/crates/collab_ui/src/project_shared_notification.rs @@ -5,7 +5,7 @@ use gpui::{ elements::*, geometry::{rect::RectF, vector::vec2f}, platform::{CursorStyle, MouseButton, WindowBounds, WindowKind, WindowOptions}, - AppContext, Entity, View, ViewContext, + AppContext, BorrowWindowContext, Entity, View, ViewContext, }; use std::sync::{Arc, Weak}; use workspace::AppState; diff --git a/crates/collab_ui/src/sharing_status_indicator.rs b/crates/collab_ui/src/sharing_status_indicator.rs index 3a1dde072f867b0791ae8fab90d6c6328857bb2a..a39ffc457a04cacacf351fcc2d85cac8c0a391cd 100644 --- a/crates/collab_ui/src/sharing_status_indicator.rs +++ b/crates/collab_ui/src/sharing_status_indicator.rs @@ -20,11 +20,11 @@ pub fn init(cx: &mut AppContext) { { status_indicator = Some(cx.add_status_bar_item(|_| SharingStatusIndicator)); } - } else if let Some((window_id, _)) = status_indicator.take() { - cx.update_window(window_id, |cx| cx.remove_window()); + } else if let Some(window) = status_indicator.take() { + window.update(cx, |cx| cx.remove_window()); } - } else if let Some((window_id, _)) = status_indicator.take() { - cx.update_window(window_id, |cx| cx.remove_window()); + } else if let Some(window) = status_indicator.take() { + window.update(cx, |cx| cx.remove_window()); } }) .detach(); diff --git a/crates/editor/src/editor_tests.rs b/crates/editor/src/editor_tests.rs index a114cd437b16bbad580d6e732bb004ac352d822a..9a65e2e9532c4c74c855b58ae714bd8c7d0970bf 100644 --- a/crates/editor/src/editor_tests.rs +++ b/crates/editor/src/editor_tests.rs @@ -1290,7 +1290,7 @@ async fn test_move_start_of_paragraph_end_of_paragraph(cx: &mut gpui::TestAppCon let mut cx = EditorTestContext::new(cx).await; 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.simulate_window_resize(cx.window.id(), vec2f(100., 4. * line_height)); cx.set_state( &r#"ˇone @@ -1401,7 +1401,7 @@ async fn test_scroll_page_up_page_down(cx: &mut gpui::TestAppContext) { init_test(cx, |_| {}); let mut cx = EditorTestContext::new(cx).await; let line_height = cx.editor(|editor, cx| editor.style(cx).text.line_height(cx.font_cache())); - cx.simulate_window_resize(cx.window_id, vec2f(1000., 4. * line_height + 0.5)); + cx.simulate_window_resize(cx.window.id(), vec2f(1000., 4. * line_height + 0.5)); cx.set_state( &r#"ˇone @@ -1439,7 +1439,7 @@ async fn test_move_page_up_page_down(cx: &mut gpui::TestAppContext) { let mut cx = EditorTestContext::new(cx).await; 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.simulate_window_resize(cx.window.id(), vec2f(100., 4. * line_height)); cx.set_state( &r#" diff --git a/crates/editor/src/test/editor_lsp_test_context.rs b/crates/editor/src/test/editor_lsp_test_context.rs index f53115f224a1cfe6cb4a3c634786c7e7e8c18305..83aaa3b703491b5f5334d173ca8d90e731aeb5e8 100644 --- a/crates/editor/src/test/editor_lsp_test_context.rs +++ b/crates/editor/src/test/editor_lsp_test_context.rs @@ -99,7 +99,7 @@ impl<'a> EditorLspTestContext<'a> { Self { cx: EditorTestContext { cx, - window_id: window.id(), + window: window.into(), editor, }, lsp, diff --git a/crates/editor/src/test/editor_test_context.rs b/crates/editor/src/test/editor_test_context.rs index c7ea1b4f3852301e300c5ff3f1db1dff65f342a2..118cddaa9226a543ca479f577428237d77539d5d 100644 --- a/crates/editor/src/test/editor_test_context.rs +++ b/crates/editor/src/test/editor_test_context.rs @@ -3,7 +3,8 @@ use crate::{ }; use futures::Future; use gpui::{ - keymap_matcher::Keystroke, AppContext, ContextHandle, ModelContext, ViewContext, ViewHandle, + keymap_matcher::Keystroke, AnyWindowHandle, AppContext, ContextHandle, ModelContext, + ViewContext, ViewHandle, }; use indoc::indoc; use language::{Buffer, BufferSnapshot}; @@ -21,7 +22,7 @@ use super::build_editor; pub struct EditorTestContext<'a> { pub cx: &'a mut gpui::TestAppContext, - pub window_id: usize, + pub window: AnyWindowHandle, pub editor: ViewHandle, } @@ -39,7 +40,7 @@ impl<'a> EditorTestContext<'a> { let editor = window.root(cx); Self { cx, - window_id: window.id(), + window: window.into(), editor, } } @@ -111,7 +112,8 @@ impl<'a> EditorTestContext<'a> { let keystroke_under_test_handle = self.add_assertion_context(format!("Simulated Keystroke: {:?}", keystroke_text)); let keystroke = Keystroke::parse(keystroke_text).unwrap(); - self.cx.dispatch_keystroke(self.window_id, keystroke, false); + + self.cx.dispatch_keystroke(self.window, keystroke, false); keystroke_under_test_handle } diff --git a/crates/go_to_line/src/go_to_line.rs b/crates/go_to_line/src/go_to_line.rs index 769f2eda55b4a165e138ee094adc4a581963a641..fa42a523741679c191c5fab053417243f4d5d4df 100644 --- a/crates/go_to_line/src/go_to_line.rs +++ b/crates/go_to_line/src/go_to_line.rs @@ -135,14 +135,16 @@ impl Entity for GoToLine { fn release(&mut self, cx: &mut AppContext) { let scroll_position = self.prev_scroll_position.take(); - cx.update_window(self.active_editor.window_id(), |cx| { - self.active_editor.update(cx, |editor, cx| { - editor.highlight_rows(None); - if let Some(scroll_position) = scroll_position { - editor.set_scroll_position(scroll_position, cx); - } - }) - }); + if let Some(window) = self.active_editor.window(cx) { + window.update(cx, |cx| { + self.active_editor.update(cx, |editor, cx| { + editor.highlight_rows(None); + if let Some(scroll_position) = scroll_position { + editor.set_scroll_position(scroll_position, cx); + } + }) + }); + } } } diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index 730d0da5a054ea808dedd236892d4ca14aeefc30..b95cb0179a84131afcccf2f07bd9929d166684d8 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -23,6 +23,7 @@ use std::{ }; use anyhow::{anyhow, Context, Result}; + use derive_more::Deref; use parking_lot::Mutex; use postage::oneshot; @@ -4127,6 +4128,12 @@ impl ViewHandle { self.window_id } + pub fn window(&self, cx: &C) -> C::Result { + cx.read_window(self.window_id, |cx| { + AnyWindowHandle::new(self.window_id, cx.window.root_view.type_id()) + }) + } + pub fn id(&self) -> usize { self.view_id } diff --git a/crates/gpui/src/app/window.rs b/crates/gpui/src/app/window.rs index d960b9da16a7c84d46fda2b17cd2650204aa1c08..70d02c1fa1265b5449b127a6736c8a81573be1e1 100644 --- a/crates/gpui/src/app/window.rs +++ b/crates/gpui/src/app/window.rs @@ -175,7 +175,7 @@ impl BorrowWindowContext for WindowContext<'_> { where F: FnOnce(&mut WindowContext) -> Option, { - BorrowWindowContext::update_window_optional(self, window_id, f) + BorrowWindowContext::update_window(self, window_id, f) } } diff --git a/crates/vim/src/editor_events.rs b/crates/vim/src/editor_events.rs index 60e63f982347b9fee2a10087d530527a1db69ad4..4fef6bd715eedbe49b1347b679a2ebe6d3a89f33 100644 --- a/crates/vim/src/editor_events.rs +++ b/crates/vim/src/editor_events.rs @@ -1,6 +1,6 @@ use crate::Vim; use editor::{EditorBlurred, EditorFocused, EditorReleased}; -use gpui::AppContext; +use gpui::{AppContext, BorrowWindowContext}; pub fn init(cx: &mut AppContext) { cx.subscribe_global(focused).detach(); diff --git a/crates/vim/src/mode_indicator.rs b/crates/vim/src/mode_indicator.rs index 639a7594f113c61bc8c232325ac8d769b2ac89e5..afd60af848be052060988ba961bb75e811f33d3b 100644 --- a/crates/vim/src/mode_indicator.rs +++ b/crates/vim/src/mode_indicator.rs @@ -1,6 +1,6 @@ use gpui::{ elements::{Empty, Label}, - AnyElement, Element, Entity, Subscription, View, ViewContext, + AnyElement, Element, Entity, Subscription, View, ViewContext, BorrowWindowContext }; use settings::SettingsStore; use workspace::{item::ItemHandle, StatusItemView}; diff --git a/crates/vim/src/test/vim_test_context.rs b/crates/vim/src/test/vim_test_context.rs index ea09e550916c4355b10d12b6d3a5a2207112dd16..839ab3aafc87e535a8b09096be6b58a5837063da 100644 --- a/crates/vim/src/test/vim_test_context.rs +++ b/crates/vim/src/test/vim_test_context.rs @@ -85,7 +85,7 @@ impl<'a> VimTestContext<'a> { } pub fn set_state(&mut self, text: &str, mode: Mode) -> ContextHandle { - let window_id = self.window_id; + let window_id = self.window.id(); self.update_window(window_id, |cx| { Vim::update(cx, |vim, cx| { vim.switch_mode(mode, false, cx); diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index c5e0e7e1ad6e2cb83b6c9cdb3dbd01f8f1687d3c..679c34611b37a4c7dd88e86c39338b75d9bfe9df 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -3827,9 +3827,9 @@ pub fn activate_workspace_for_project( cx: &mut AsyncAppContext, predicate: impl Fn(&mut Project, &mut ModelContext) -> bool, ) -> Option> { - for window_id in cx.window_ids() { - let handle = cx - .update_window(window_id, |cx| { + for window in cx.windows() { + let handle = window + .update(cx, |cx| { if let Some(workspace_handle) = cx.root_view().clone().downcast::() { let project = workspace_handle.read(cx).project.clone(); if project.update(cx, &predicate) { @@ -3945,18 +3945,23 @@ pub fn join_remote_project( ) -> Task> { cx.spawn(|mut cx| async move { let existing_workspace = cx - .window_ids() + .windows() .into_iter() - .filter_map(|window_id| cx.root_view(window_id)?.clone().downcast::()) - .find(|workspace| { - cx.read_window(workspace.window_id(), |cx| { - workspace.read(cx).project().read(cx).remote_id() == Some(project_id) + .find_map(|window| { + window.downcast::().and_then(|window| { + window.read_root_with(&cx, |workspace, cx| { + if workspace.project().read(cx).remote_id() == Some(project_id) { + Some(cx.handle().downgrade()) + } else { + None + } + }) }) - .unwrap_or(false) - }); + }) + .flatten(); let workspace = if let Some(existing_workspace) = existing_workspace { - existing_workspace.downgrade() + existing_workspace } else { let active_call = cx.read(ActiveCall::global); let room = active_call @@ -4034,19 +4039,19 @@ pub fn join_remote_project( pub fn restart(_: &Restart, cx: &mut AppContext) { let should_confirm = settings::get::(cx).confirm_quit; cx.spawn(|mut cx| async move { - let mut workspaces = cx + let mut workspace_windows = cx .windows() .into_iter() - .filter_map(|window| Some(window.downcast::()?.root(&cx)?.downgrade())) + .filter_map(|window| window.downcast::()) .collect::>(); // If multiple windows have unsaved changes, and need a save prompt, // prompt in the active window before switching to a different window. - workspaces.sort_by_key(|workspace| !cx.window_is_active(workspace.window_id())); + workspace_windows.sort_by_key(|window| window.is_active(&cx) == Some(false)); - if let (true, Some(workspace)) = (should_confirm, workspaces.first()) { + if let (true, Some(window)) = (should_confirm, workspace_windows.first()) { let answer = cx.prompt( - workspace.window_id(), + window.id(), PromptLevel::Info, "Are you sure you want to restart?", &["Restart", "Cancel"], @@ -4061,14 +4066,13 @@ pub fn restart(_: &Restart, cx: &mut AppContext) { } // If the user cancels any save prompt, then keep the app open. - for workspace in workspaces { - if !workspace - .update(&mut cx, |workspace, cx| { - workspace.prepare_to_close(true, cx) - })? - .await? - { - return Ok(()); + for window in workspace_windows { + if let Some(close) = window.update_root(&mut cx, |workspace, cx| { + workspace.prepare_to_close(true, cx) + }) { + if !close.await? { + return Ok(()); + } } } cx.platform().restart(); diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index a8a287fb4e6fc964346378fad4eee09bc5eb057a..2b9321b303e8610bed75b9da53b770dbc6267c3a 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -406,26 +406,19 @@ pub fn build_window_options( fn quit(_: &Quit, cx: &mut gpui::AppContext) { let should_confirm = settings::get::(cx).confirm_quit; cx.spawn(|mut cx| async move { - let mut workspaces = cx - .window_ids() + let mut workspace_windows = cx + .windows() .into_iter() - .filter_map(|window_id| { - Some( - cx.root_view(window_id)? - .clone() - .downcast::()? - .downgrade(), - ) - }) + .filter_map(|window| window.downcast::()) .collect::>(); // If multiple windows have unsaved changes, and need a save prompt, // prompt in the active window before switching to a different window. - workspaces.sort_by_key(|workspace| !cx.window_is_active(workspace.window_id())); + workspace_windows.sort_by_key(|window| window.is_active(&cx) == Some(false)); - if let (true, Some(workspace)) = (should_confirm, workspaces.first()) { + if let (true, Some(window)) = (should_confirm, workspace_windows.first()) { let answer = cx.prompt( - workspace.window_id(), + window.id(), PromptLevel::Info, "Are you sure you want to quit?", &["Quit", "Cancel"], @@ -440,14 +433,13 @@ fn quit(_: &Quit, cx: &mut gpui::AppContext) { } // If the user cancels any save prompt, then keep the app open. - for workspace in workspaces { - if !workspace - .update(&mut cx, |workspace, cx| { - workspace.prepare_to_close(true, cx) - })? - .await? - { - return Ok(()); + for window in workspace_windows { + if let Some(close) = window.update_root(&mut cx, |workspace, cx| { + workspace.prepare_to_close(false, cx) + }) { + if close.await? { + return Ok(()); + } } } cx.platform().quit(); @@ -782,17 +774,13 @@ mod tests { }) .await .unwrap(); - assert_eq!(cx.window_ids().len(), 1); + assert_eq!(cx.windows().len(), 1); cx.update(|cx| open_paths(&[PathBuf::from("/root/a")], &app_state, None, cx)) .await .unwrap(); - assert_eq!(cx.window_ids().len(), 1); - let workspace_1 = cx - .read_window(cx.window_ids()[0], |cx| cx.root_view().clone()) - .unwrap() - .downcast::() - .unwrap(); + assert_eq!(cx.windows().len(), 1); + let workspace_1 = cx.windows()[0].downcast::().unwrap().root(cx); workspace_1.update(cx, |workspace, cx| { assert_eq!(workspace.worktrees(cx).count(), 2); assert!(workspace.left_dock().read(cx).is_open()); @@ -809,28 +797,22 @@ mod tests { }) .await .unwrap(); - assert_eq!(cx.window_ids().len(), 2); + assert_eq!(cx.windows().len(), 2); // Replace existing windows - let window_id = cx.window_ids()[0]; - let window = cx.read_window(window_id, |cx| cx.window()).flatten(); + let window = cx.windows()[0].downcast::().unwrap(); cx.update(|cx| { open_paths( &[PathBuf::from("/root/c"), PathBuf::from("/root/d")], &app_state, - window, + Some(window), cx, ) }) .await .unwrap(); - assert_eq!(cx.window_ids().len(), 2); - let workspace_1 = cx - .read_window(cx.window_ids()[0], |cx| cx.root_view().clone()) - .unwrap() - .clone() - .downcast::() - .unwrap(); + assert_eq!(cx.windows().len(), 2); + let workspace_1 = cx.windows()[0].downcast::().unwrap().root(cx); workspace_1.update(cx, |workspace, cx| { assert_eq!( workspace @@ -856,14 +838,10 @@ mod tests { cx.update(|cx| open_paths(&[PathBuf::from("/root/a")], &app_state, None, cx)) .await .unwrap(); - assert_eq!(cx.window_ids().len(), 1); + assert_eq!(cx.windows().len(), 1); // When opening the workspace, the window is not in a edited state. - let workspace = cx - .read_window(cx.window_ids()[0], |cx| cx.root_view().clone()) - .unwrap() - .downcast::() - .unwrap(); + let workspace = cx.windows()[0].downcast::().unwrap().root(cx); let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone()); let editor = workspace.read_with(cx, |workspace, cx| { workspace @@ -917,12 +895,12 @@ mod tests { // buffer having unsaved changes. assert!(!cx.simulate_window_close(workspace.window_id())); executor.run_until_parked(); - assert_eq!(cx.window_ids().len(), 1); + assert_eq!(cx.windows().len(), 1); // The window is successfully closed after the user dismisses the prompt. cx.simulate_prompt_answer(workspace.window_id(), 1); executor.run_until_parked(); - assert_eq!(cx.window_ids().len(), 0); + assert_eq!(cx.windows().len(), 0); } #[gpui::test] @@ -935,12 +913,13 @@ mod tests { }) .await; - let window_id = *cx.window_ids().first().unwrap(); - let workspace = cx - .read_window(window_id, |cx| cx.root_view().clone()) + let window = cx + .windows() + .first() .unwrap() .downcast::() .unwrap(); + let workspace = window.root(cx); let editor = workspace.update(cx, |workspace, cx| { workspace @@ -1105,12 +1084,8 @@ mod tests { cx.update(|cx| open_paths(&[PathBuf::from("/dir1/")], &app_state, None, cx)) .await .unwrap(); - assert_eq!(cx.window_ids().len(), 1); - let workspace = cx - .read_window(cx.window_ids()[0], |cx| cx.root_view().clone()) - .unwrap() - .downcast::() - .unwrap(); + assert_eq!(cx.windows().len(), 1); + let workspace = cx.windows()[0].downcast::().unwrap().root(cx); #[track_caller] fn assert_project_panel_selection( From 0197d49230832118cf78f4b5c94d47d390b27d44 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 7 Aug 2023 19:45:43 -0600 Subject: [PATCH 21/41] Move activation simulation to AnyWindowHandle --- crates/gpui/src/app.rs | 31 +++++++++++++++++++++---- crates/gpui/src/app/test_app_context.rs | 28 ++++------------------ crates/workspace/src/workspace.rs | 6 ++--- 3 files changed, 34 insertions(+), 31 deletions(-) diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index b95cb0179a84131afcccf2f07bd9929d166684d8..bd3fbb8149fb6ecfd00bb461f8c4a21a22289047 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -4087,6 +4087,29 @@ impl AnyWindowHandle { pub fn remove(&self, cx: &mut C) -> C::Result<()> { self.update(cx, |cx| cx.remove_window()) } + + pub fn simulate_activation(&self, cx: &mut TestAppContext) { + self.update(cx, |cx| { + let other_window_ids = cx + .windows + .keys() + .filter(|window_id| **window_id != self.window_id) + .copied() + .collect::>(); + + for window_id in other_window_ids { + cx.window_changed_active_status(window_id, false) + } + + cx.window_changed_active_status(self.window_id, true) + }); + } + + pub fn simulate_deactivation(&self, cx: &mut TestAppContext) { + self.update(cx, |cx| { + cx.window_changed_active_status(self.window_id, false); + }) + } } #[repr(transparent)] @@ -6726,25 +6749,25 @@ mod tests { [("window 2", false), ("window 3", true)] ); - cx.simulate_window_activation(Some(window_2.id())); + window_2.simulate_activation(cx); assert_eq!( mem::take(&mut *events.borrow_mut()), [("window 3", false), ("window 2", true)] ); - cx.simulate_window_activation(Some(window_1.id())); + window_1.simulate_activation(cx); assert_eq!( mem::take(&mut *events.borrow_mut()), [("window 2", false), ("window 1", true)] ); - cx.simulate_window_activation(Some(window_3.id())); + window_3.simulate_activation(cx); assert_eq!( mem::take(&mut *events.borrow_mut()), [("window 1", false), ("window 3", true)] ); - cx.simulate_window_activation(Some(window_3.id())); + window_3.simulate_activation(cx); assert_eq!(mem::take(&mut *events.borrow_mut()), []); } diff --git a/crates/gpui/src/app/test_app_context.rs b/crates/gpui/src/app/test_app_context.rs index 0331c7922e680fe1c45460bc2569c85ab77a3f19..675d8b8528dc0b2c95b2c140207be6a4e3067563 100644 --- a/crates/gpui/src/app/test_app_context.rs +++ b/crates/gpui/src/app/test_app_context.rs @@ -156,17 +156,16 @@ impl TestAppContext { self.cx.borrow_mut().add_model(build_model) } - pub fn add_window(&mut self, build_root_view: F) -> WindowHandle + pub fn add_window(&mut self, build_root_view: F) -> WindowHandle where - T: View, - F: FnOnce(&mut ViewContext) -> T, + V: View, + F: FnOnce(&mut ViewContext) -> V, { let window = self .cx .borrow_mut() .add_window(Default::default(), build_root_view); - self.simulate_window_activation(Some(window.id())); - + window.simulate_activation(self); WindowHandle::new(window.id()) } @@ -321,25 +320,6 @@ impl TestAppContext { self.platform_window_mut(window_id).resize_handlers = handlers; } - pub fn simulate_window_activation(&self, to_activate: Option) { - self.cx.borrow_mut().update(|cx| { - let other_window_ids = cx - .windows - .keys() - .filter(|window_id| Some(**window_id) != to_activate) - .copied() - .collect::>(); - - for window_id in other_window_ids { - cx.window_changed_active_status(window_id, false) - } - - if let Some(to_activate) = to_activate { - cx.window_changed_active_status(to_activate, true) - } - }); - } - pub fn is_window_edited(&self, window_id: usize) -> bool { self.platform_window_mut(window_id).edited } diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 679c34611b37a4c7dd88e86c39338b75d9bfe9df..dc52614ecf497542306a7705e3be2f938d825315 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -4530,7 +4530,7 @@ mod tests { }); // Deactivating the window saves the file. - cx.simulate_window_activation(None); + window.simulate_deactivation(cx); deterministic.run_until_parked(); item.read_with(cx, |item, _| assert_eq!(item.save_count, 1)); @@ -4551,12 +4551,12 @@ mod tests { item.read_with(cx, |item, _| assert_eq!(item.save_count, 2)); // Deactivating the window still saves the file. - cx.simulate_window_activation(Some(window.id())); + window.simulate_activation(cx); item.update(cx, |item, cx| { cx.focus_self(); item.is_dirty = true; }); - cx.simulate_window_activation(None); + window.simulate_deactivation(cx); deterministic.run_until_parked(); item.read_with(cx, |item, _| assert_eq!(item.save_count, 3)); From f2be3181a98aab8c711d6c4f92b43dc891dc6ce0 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 7 Aug 2023 20:23:04 -0600 Subject: [PATCH 22/41] Move window-related methods from TestAppContext to AnyWindowHandle --- crates/collab/src/tests/integration_tests.rs | 4 +- crates/editor/src/editor_tests.rs | 9 +- crates/gpui/src/app/test_app_context.rs | 132 +++++++++---------- crates/project_panel/src/project_panel.rs | 26 ++-- crates/workspace/src/workspace.rs | 46 +++---- crates/zed/src/zed.rs | 29 ++-- 6 files changed, 118 insertions(+), 128 deletions(-) diff --git a/crates/collab/src/tests/integration_tests.rs b/crates/collab/src/tests/integration_tests.rs index 92ccee91c0ecb5cd6d8a0ca2af5928f9b6c3a72f..29dcd95eae076cd38ae36fb950a41eabe98905a0 100644 --- a/crates/collab/src/tests/integration_tests.rs +++ b/crates/collab/src/tests/integration_tests.rs @@ -1510,7 +1510,7 @@ async fn test_host_disconnect( .unwrap(); assert!(window_b.read_with(cx_b, |cx| editor_b.is_focused(cx))); editor_b.update(cx_b, |editor, cx| editor.insert("X", cx)); - assert!(cx_b.is_window_edited(workspace_b.window_id())); + assert!(window_b.is_edited(cx_b)); // Drop client A's connection. Collaborators should disappear and the project should not be shown as shared. server.forbid_connections(); @@ -1525,7 +1525,7 @@ async fn test_host_disconnect( window_b.read_with(cx_b, |cx| { assert_eq!(cx.focused_view_id(), None); }); - assert!(!cx_b.is_window_edited(workspace_b.window_id())); + assert!(!window_b.is_edited(cx_b)); // Ensure client B is not prompted to save edits when closing window after disconnecting. let can_close = workspace_b diff --git a/crates/editor/src/editor_tests.rs b/crates/editor/src/editor_tests.rs index 9a65e2e9532c4c74c855b58ae714bd8c7d0970bf..61fa952f944d1059c210629aa93eba0736d62459 100644 --- a/crates/editor/src/editor_tests.rs +++ b/crates/editor/src/editor_tests.rs @@ -1290,7 +1290,8 @@ async fn test_move_start_of_paragraph_end_of_paragraph(cx: &mut gpui::TestAppCon let mut cx = EditorTestContext::new(cx).await; 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)); + let window = cx.window; + window.simulate_resize(vec2f(100., 4. * line_height), &mut cx); cx.set_state( &r#"ˇone @@ -1401,7 +1402,8 @@ async fn test_scroll_page_up_page_down(cx: &mut gpui::TestAppContext) { init_test(cx, |_| {}); let mut cx = EditorTestContext::new(cx).await; let line_height = cx.editor(|editor, cx| editor.style(cx).text.line_height(cx.font_cache())); - cx.simulate_window_resize(cx.window.id(), vec2f(1000., 4. * line_height + 0.5)); + let window = cx.window; + window.simulate_resize(vec2f(1000., 4. * line_height + 0.5), &mut cx); cx.set_state( &r#"ˇone @@ -1439,7 +1441,8 @@ async fn test_move_page_up_page_down(cx: &mut gpui::TestAppContext) { let mut cx = EditorTestContext::new(cx).await; 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)); + let window = cx.window; + window.simulate_resize(vec2f(100., 4. * line_height), &mut cx); cx.set_state( &r#" diff --git a/crates/gpui/src/app/test_app_context.rs b/crates/gpui/src/app/test_app_context.rs index 675d8b8528dc0b2c95b2c140207be6a4e3067563..e298224caa2d0fc4829443a836cc9bbb91ef6087 100644 --- a/crates/gpui/src/app/test_app_context.rs +++ b/crates/gpui/src/app/test_app_context.rs @@ -202,10 +202,6 @@ impl TestAppContext { self.cx.borrow().windows().collect() } - // pub fn window_ids(&self) -> Vec { - // self.cx.borrow().windows.keys().copied().collect() - // } - pub fn remove_all_windows(&mut self) { self.update(|cx| cx.windows.clear()); } @@ -273,57 +269,6 @@ impl TestAppContext { self.foreground_platform.as_ref().did_prompt_for_new_path() } - pub fn simulate_prompt_answer(&self, window_id: usize, answer: usize) { - use postage::prelude::Sink as _; - - let mut done_tx = self - .platform_window_mut(window_id) - .pending_prompts - .borrow_mut() - .pop_front() - .expect("prompt was not called"); - done_tx.try_send(answer).ok(); - } - - pub fn has_pending_prompt(&self, window_id: usize) -> bool { - let window = self.platform_window_mut(window_id); - let prompts = window.pending_prompts.borrow_mut(); - !prompts.is_empty() - } - - pub fn current_window_title(&self, window_id: usize) -> Option { - self.platform_window_mut(window_id).title.clone() - } - - pub fn simulate_window_close(&self, window_id: usize) -> bool { - let handler = self - .platform_window_mut(window_id) - .should_close_handler - .take(); - if let Some(mut handler) = handler { - let should_close = handler(); - self.platform_window_mut(window_id).should_close_handler = Some(handler); - should_close - } else { - false - } - } - - pub fn simulate_window_resize(&self, window_id: usize, size: Vector2F) { - let mut window = self.platform_window_mut(window_id); - window.size = size; - let mut handlers = mem::take(&mut window.resize_handlers); - drop(window); - for handler in &mut handlers { - handler(); - } - self.platform_window_mut(window_id).resize_handlers = handlers; - } - - pub fn is_window_edited(&self, window_id: usize) -> bool { - self.platform_window_mut(window_id).edited - } - pub fn leak_detector(&self) -> Arc> { self.cx.borrow().leak_detector() } @@ -344,18 +289,6 @@ impl TestAppContext { self.assert_dropped(weak); } - fn platform_window_mut(&self, window_id: usize) -> std::cell::RefMut { - std::cell::RefMut::map(self.cx.borrow_mut(), |state| { - let window = state.windows.get_mut(&window_id).unwrap(); - let test_window = window - .platform_window - .as_any_mut() - .downcast_mut::() - .unwrap(); - test_window - }) - } - pub fn set_condition_duration(&mut self, duration: Option) { self.condition_duration = duration; } @@ -545,6 +478,71 @@ impl ModelHandle { } } +impl AnyWindowHandle { + pub fn has_pending_prompt(&self, cx: &mut TestAppContext) -> bool { + let window = self.platform_window_mut(cx); + let prompts = window.pending_prompts.borrow_mut(); + !prompts.is_empty() + } + + pub fn current_title(&self, cx: &mut TestAppContext) -> Option { + self.platform_window_mut(cx).title.clone() + } + + pub fn simulate_close(&self, cx: &mut TestAppContext) -> bool { + let handler = self.platform_window_mut(cx).should_close_handler.take(); + if let Some(mut handler) = handler { + let should_close = handler(); + self.platform_window_mut(cx).should_close_handler = Some(handler); + should_close + } else { + false + } + } + + pub fn simulate_resize(&self, size: Vector2F, cx: &mut TestAppContext) { + let mut window = self.platform_window_mut(cx); + window.size = size; + let mut handlers = mem::take(&mut window.resize_handlers); + drop(window); + for handler in &mut handlers { + handler(); + } + self.platform_window_mut(cx).resize_handlers = handlers; + } + + pub fn is_edited(&self, cx: &mut TestAppContext) -> bool { + self.platform_window_mut(cx).edited + } + + pub fn simulate_prompt_answer(&self, answer: usize, cx: &mut TestAppContext) { + use postage::prelude::Sink as _; + + let mut done_tx = self + .platform_window_mut(cx) + .pending_prompts + .borrow_mut() + .pop_front() + .expect("prompt was not called"); + done_tx.try_send(answer).ok(); + } + + fn platform_window_mut<'a>( + &self, + cx: &'a mut TestAppContext, + ) -> std::cell::RefMut<'a, platform::test::Window> { + std::cell::RefMut::map(cx.cx.borrow_mut(), |state| { + let window = state.windows.get_mut(&self.window_id).unwrap(); + let test_window = window + .platform_window + .as_any_mut() + .downcast_mut::() + .unwrap(); + test_window + }) + } +} + impl ViewHandle { pub fn next_notification(&self, cx: &TestAppContext) -> impl Future { use postage::prelude::{Sink as _, Stream as _}; diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index 021ea2d3bc3a817342e9eac684496ffeee5026bb..07aaea812a98d5758bb15b801c5cd8bdf1688e8f 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -1726,7 +1726,7 @@ impl ClipboardEntry { #[cfg(test)] mod tests { use super::*; - use gpui::{TestAppContext, ViewHandle}; + use gpui::{AnyWindowHandle, TestAppContext, ViewHandle}; use pretty_assertions::assert_eq; use project::FakeFs; use serde_json::json; @@ -2421,7 +2421,7 @@ mod tests { ); ensure_single_file_is_opened(window_id, &workspace, "test/first.rs", cx); - submit_deletion(window_id, &panel, cx); + submit_deletion(window.into(), &panel, cx); assert_eq!( visible_entries_as_strings(&panel, 0..10, cx), &[ @@ -2432,7 +2432,7 @@ mod tests { ], "Project panel should have no deleted file, no other file is selected in it" ); - ensure_no_open_items_and_panes(window_id, &workspace, cx); + ensure_no_open_items_and_panes(window.into(), &workspace, cx); select_path(&panel, "src/test/second.rs", cx); panel.update(cx, |panel, cx| panel.open_file(&Open, cx)); @@ -2464,13 +2464,13 @@ mod tests { .expect("Open item should be an editor"); open_editor.update(cx, |editor, cx| editor.set_text("Another text!", cx)); }); - submit_deletion(window_id, &panel, cx); + submit_deletion(window.into(), &panel, cx); assert_eq!( visible_entries_as_strings(&panel, 0..10, cx), &["v src", " v test", " third.rs"], "Project panel should have no deleted file, with one last file remaining" ); - ensure_no_open_items_and_panes(window_id, &workspace, cx); + ensure_no_open_items_and_panes(window.into(), &workspace, cx); } #[gpui::test] @@ -2910,12 +2910,12 @@ mod tests { } fn submit_deletion( - window_id: usize, + window: AnyWindowHandle, panel: &ViewHandle, cx: &mut TestAppContext, ) { assert!( - !cx.has_pending_prompt(window_id), + !window.has_pending_prompt(cx), "Should have no prompts before the deletion" ); panel.update(cx, |panel, cx| { @@ -2925,27 +2925,27 @@ mod tests { .detach_and_log_err(cx); }); assert!( - cx.has_pending_prompt(window_id), + window.has_pending_prompt(cx), "Should have a prompt after the deletion" ); - cx.simulate_prompt_answer(window_id, 0); + window.simulate_prompt_answer(0, cx); assert!( - !cx.has_pending_prompt(window_id), + !window.has_pending_prompt(cx), "Should have no prompts after prompt was replied to" ); cx.foreground().run_until_parked(); } fn ensure_no_open_items_and_panes( - window_id: usize, + window: AnyWindowHandle, workspace: &ViewHandle, cx: &mut TestAppContext, ) { assert!( - !cx.has_pending_prompt(window_id), + !window.has_pending_prompt(cx), "Should have no prompts after deletion operation closes the file" ); - cx.read_window(window_id, |cx| { + window.read_with(cx, |cx| { let open_project_paths = workspace .read(cx) .panes() diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index dc52614ecf497542306a7705e3be2f938d825315..da708c6ea727de82b1c288a9549e6d627fad07b3 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -4197,17 +4197,11 @@ mod tests { .map(|e| e.id) ); }); - assert_eq!( - cx.current_window_title(window.id()).as_deref(), - Some("one.txt — root1") - ); + assert_eq!(window.current_title(cx).as_deref(), Some("one.txt — root1")); // Add a second item to a non-empty pane workspace.update(cx, |workspace, cx| workspace.add_item(Box::new(item2), cx)); - assert_eq!( - cx.current_window_title(window.id()).as_deref(), - Some("two.txt — root1") - ); + assert_eq!(window.current_title(cx).as_deref(), Some("two.txt — root1")); project.read_with(cx, |project, cx| { assert_eq!( project.active_entry(), @@ -4223,10 +4217,7 @@ mod tests { }) .await .unwrap(); - assert_eq!( - cx.current_window_title(window.id()).as_deref(), - Some("one.txt — root1") - ); + assert_eq!(window.current_title(cx).as_deref(), Some("one.txt — root1")); project.read_with(cx, |project, cx| { assert_eq!( project.active_entry(), @@ -4244,16 +4235,13 @@ mod tests { .await .unwrap(); assert_eq!( - cx.current_window_title(window.id()).as_deref(), + window.current_title(cx).as_deref(), Some("one.txt — root1, root2") ); // Remove a project folder project.update(cx, |project, cx| project.remove_worktree(worktree_id, cx)); - assert_eq!( - cx.current_window_title(window.id()).as_deref(), - Some("one.txt — root2") - ); + assert_eq!(window.current_title(cx).as_deref(), Some("one.txt — root2")); } #[gpui::test] @@ -4287,9 +4275,9 @@ mod tests { }); let task = workspace.update(cx, |w, cx| w.prepare_to_close(false, cx)); cx.foreground().run_until_parked(); - cx.simulate_prompt_answer(window.id(), 2 /* cancel */); + window.simulate_prompt_answer(2, cx); // cancel cx.foreground().run_until_parked(); - assert!(!cx.has_pending_prompt(window.id())); + assert!(!window.has_pending_prompt(cx)); assert!(!task.await.unwrap()); } @@ -4348,10 +4336,10 @@ mod tests { assert_eq!(pane.items_len(), 4); assert_eq!(pane.active_item().unwrap().id(), item1.id()); }); - assert!(cx.has_pending_prompt(window.id())); + assert!(window.has_pending_prompt(cx)); // Confirm saving item 1. - cx.simulate_prompt_answer(window.id(), 0); + window.simulate_prompt_answer(0, cx); cx.foreground().run_until_parked(); // Item 1 is saved. There's a prompt to save item 3. @@ -4362,10 +4350,10 @@ mod tests { assert_eq!(pane.items_len(), 3); assert_eq!(pane.active_item().unwrap().id(), item3.id()); }); - assert!(cx.has_pending_prompt(window.id())); + assert!(window.has_pending_prompt(cx)); // Cancel saving item 3. - cx.simulate_prompt_answer(window.id(), 1); + window.simulate_prompt_answer(1, cx); cx.foreground().run_until_parked(); // Item 3 is reloaded. There's a prompt to save item 4. @@ -4376,10 +4364,10 @@ mod tests { assert_eq!(pane.items_len(), 2); assert_eq!(pane.active_item().unwrap().id(), item4.id()); }); - assert!(cx.has_pending_prompt(window.id())); + assert!(window.has_pending_prompt(cx)); // Confirm saving item 4. - cx.simulate_prompt_answer(window.id(), 0); + window.simulate_prompt_answer(0, cx); cx.foreground().run_until_parked(); // There's a prompt for a path for item 4. @@ -4482,7 +4470,7 @@ mod tests { &[ProjectEntryId::from_proto(0)] ); }); - cx.simulate_prompt_answer(window.id(), 0); + window.simulate_prompt_answer(0, cx); cx.foreground().run_until_parked(); left_pane.read_with(cx, |pane, cx| { @@ -4491,7 +4479,7 @@ mod tests { &[ProjectEntryId::from_proto(2)] ); }); - cx.simulate_prompt_answer(window.id(), 0); + window.simulate_prompt_answer(0, cx); cx.foreground().run_until_parked(); close.await.unwrap(); @@ -4593,7 +4581,7 @@ mod tests { pane.update(cx, |pane, cx| pane.close_items(cx, move |id| id == item_id)) .await .unwrap(); - assert!(!cx.has_pending_prompt(window.id())); + assert!(!window.has_pending_prompt(cx)); item.read_with(cx, |item, _| assert_eq!(item.save_count, 5)); // Add the item again, ensuring autosave is prevented if the underlying file has been deleted. @@ -4614,7 +4602,7 @@ mod tests { let _close_items = pane.update(cx, |pane, cx| pane.close_items(cx, move |id| id == item_id)); deterministic.run_until_parked(); - assert!(cx.has_pending_prompt(window.id())); + assert!(window.has_pending_prompt(cx)); item.read_with(cx, |item, _| assert_eq!(item.save_count, 5)); } diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 2b9321b303e8610bed75b9da53b770dbc6267c3a..3435727b1e0345ab1eef4cb63870b6b71f03c7f9 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -841,7 +841,8 @@ mod tests { assert_eq!(cx.windows().len(), 1); // When opening the workspace, the window is not in a edited state. - let workspace = cx.windows()[0].downcast::().unwrap().root(cx); + let window = cx.windows()[0].downcast::().unwrap(); + let workspace = window.root(cx); let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone()); let editor = workspace.read_with(cx, |workspace, cx| { workspace @@ -850,19 +851,19 @@ mod tests { .downcast::() .unwrap() }); - assert!(!cx.is_window_edited(workspace.window_id())); + assert!(!window.is_edited(cx)); // Editing a buffer marks the window as edited. editor.update(cx, |editor, cx| editor.insert("EDIT", cx)); - assert!(cx.is_window_edited(workspace.window_id())); + assert!(window.is_edited(cx)); // Undoing the edit restores the window's edited state. editor.update(cx, |editor, cx| editor.undo(&Default::default(), cx)); - assert!(!cx.is_window_edited(workspace.window_id())); + assert!(!window.is_edited(cx)); // Redoing the edit marks the window as edited again. editor.update(cx, |editor, cx| editor.redo(&Default::default(), cx)); - assert!(cx.is_window_edited(workspace.window_id())); + assert!(window.is_edited(cx)); // Closing the item restores the window's edited state. let close = pane.update(cx, |pane, cx| { @@ -870,9 +871,10 @@ mod tests { pane.close_active_item(&Default::default(), cx).unwrap() }); executor.run_until_parked(); - cx.simulate_prompt_answer(workspace.window_id(), 1); + + window.simulate_prompt_answer(1, cx); close.await.unwrap(); - assert!(!cx.is_window_edited(workspace.window_id())); + assert!(!window.is_edited(cx)); // Opening the buffer again doesn't impact the window's edited state. cx.update(|cx| open_paths(&[PathBuf::from("/root/a")], &app_state, None, cx)) @@ -885,20 +887,20 @@ mod tests { .downcast::() .unwrap() }); - assert!(!cx.is_window_edited(workspace.window_id())); + assert!(!window.is_edited(cx)); // Editing the buffer marks the window as edited. editor.update(cx, |editor, cx| editor.insert("EDIT", cx)); - assert!(cx.is_window_edited(workspace.window_id())); + assert!(window.is_edited(cx)); // Ensure closing the window via the mouse gets preempted due to the // buffer having unsaved changes. - assert!(!cx.simulate_window_close(workspace.window_id())); + assert!(!window.simulate_close(cx)); executor.run_until_parked(); assert_eq!(cx.windows().len(), 1); // The window is successfully closed after the user dismisses the prompt. - cx.simulate_prompt_answer(workspace.window_id(), 1); + window.simulate_prompt_answer(1, cx); executor.run_until_parked(); assert_eq!(cx.windows().len(), 0); } @@ -1273,7 +1275,6 @@ mod tests { let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await; let window = cx.add_window(|cx| Workspace::test_new(project, cx)); let workspace = window.root(cx); - let window_id = window.id(); // Open a file within an existing worktree. workspace @@ -1299,7 +1300,7 @@ mod tests { cx.read(|cx| assert!(editor.is_dirty(cx))); let save_task = workspace.update(cx, |workspace, cx| workspace.save_active_item(false, cx)); - cx.simulate_prompt_answer(window_id, 0); + window.simulate_prompt_answer(0, cx); save_task.await.unwrap(); editor.read_with(cx, |editor, cx| { assert!(!editor.is_dirty(cx)); @@ -1506,7 +1507,7 @@ mod tests { cx.dispatch_action(window_id, workspace::CloseActiveItem); cx.foreground().run_until_parked(); - cx.simulate_prompt_answer(window_id, 1); + window.simulate_prompt_answer(1, cx); cx.foreground().run_until_parked(); workspace.read_with(cx, |workspace, cx| { From 0f332238b3076d17fbaf2ff920cf9eaeda6ac2ac Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 7 Aug 2023 22:08:44 -0600 Subject: [PATCH 23/41] Remove unused method --- crates/gpui/src/app/test_app_context.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/crates/gpui/src/app/test_app_context.rs b/crates/gpui/src/app/test_app_context.rs index e298224caa2d0fc4829443a836cc9bbb91ef6087..e0fd0cb8e9f15407f25a22aaa0e768ff786caecc 100644 --- a/crates/gpui/src/app/test_app_context.rs +++ b/crates/gpui/src/app/test_app_context.rs @@ -125,13 +125,6 @@ impl TestAppContext { } } - pub fn window(&self, window_id: usize) -> Option> { - self.cx - .borrow() - .read_window(window_id, |cx| cx.window()) - .flatten() - } - pub fn read_window T>( &self, window_id: usize, From f0da6b05fdfec04e4583be1231c7d755dad24646 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 7 Aug 2023 22:15:53 -0600 Subject: [PATCH 24/41] Remove TestAppContext::add_view Instead, we now call this on window handles. --- crates/collab/src/tests.rs | 44 ++----------------- crates/collab/src/tests/integration_tests.rs | 40 ++++++++--------- crates/command_palette/src/command_palette.rs | 3 +- crates/diagnostics/src/diagnostics.rs | 6 +-- crates/editor/src/editor_tests.rs | 3 +- crates/gpui/src/app/test_app_context.rs | 9 ---- crates/project_symbols/src/project_symbols.rs | 3 +- crates/search/src/buffer_search.rs | 17 +++---- crates/search/src/project_search.rs | 3 +- 9 files changed, 35 insertions(+), 93 deletions(-) diff --git a/crates/collab/src/tests.rs b/crates/collab/src/tests.rs index 4804f5b0f1f24033fc79c12a6af5d87096a49a84..febe43ce5e1c78357c9ba4fa42c5a0f328b4ba9f 100644 --- a/crates/collab/src/tests.rs +++ b/crates/collab/src/tests.rs @@ -12,10 +12,7 @@ use client::{ use collections::{HashMap, HashSet}; use fs::FakeFs; use futures::{channel::oneshot, StreamExt as _}; -use gpui::{ - elements::*, executor::Deterministic, AnyElement, Entity, ModelHandle, TestAppContext, View, - ViewContext, ViewHandle, WeakViewHandle, -}; +use gpui::{executor::Deterministic, ModelHandle, TestAppContext, WindowHandle}; use language::LanguageRegistry; use parking_lot::Mutex; use project::{Project, WorktreeId}; @@ -466,43 +463,8 @@ impl TestClient { &self, project: &ModelHandle, cx: &mut TestAppContext, - ) -> ViewHandle { - struct WorkspaceContainer { - workspace: Option>, - } - - impl Entity for WorkspaceContainer { - type Event = (); - } - - impl View for WorkspaceContainer { - fn ui_name() -> &'static str { - "WorkspaceContainer" - } - - fn render(&mut self, cx: &mut ViewContext) -> AnyElement { - if let Some(workspace) = self - .workspace - .as_ref() - .and_then(|workspace| workspace.upgrade(cx)) - { - ChildView::new(&workspace, cx).into_any() - } else { - Empty::new().into_any() - } - } - } - - // We use a workspace container so that we don't need to remove the window in order to - // drop the workspace and we can use a ViewHandle instead. - let window = cx.add_window(|_| WorkspaceContainer { workspace: None }); - let container = window.root(cx); - let workspace = window.add_view(cx, |cx| Workspace::test_new(project.clone(), cx)); - container.update(cx, |container, cx| { - container.workspace = Some(workspace.downgrade()); - cx.notify(); - }); - workspace + ) -> WindowHandle { + cx.add_window(|cx| Workspace::test_new(project.clone(), cx)) } } diff --git a/crates/collab/src/tests/integration_tests.rs b/crates/collab/src/tests/integration_tests.rs index 29dcd95eae076cd38ae36fb950a41eabe98905a0..8ad7864adfc774888c395d9f14508a4e066edf63 100644 --- a/crates/collab/src/tests/integration_tests.rs +++ b/crates/collab/src/tests/integration_tests.rs @@ -6441,8 +6441,10 @@ async fn test_basic_following( .await .unwrap(); - let workspace_a = client_a.build_workspace(&project_a, cx_a); - let workspace_b = client_b.build_workspace(&project_b, cx_b); + let window_a = client_a.build_workspace(&project_a, cx_a); + let workspace_a = window_a.root(cx_a); + let window_b = client_b.build_workspace(&project_b, cx_b); + let workspace_b = window_b.root(cx_b); // Client A opens some editors. let pane_a = workspace_a.read_with(cx_a, |workspace, _| workspace.active_pane().clone()); @@ -6525,7 +6527,7 @@ async fn test_basic_following( cx_c.foreground().run_until_parked(); let active_call_c = cx_c.read(ActiveCall::global); let project_c = client_c.build_remote_project(project_id, cx_c).await; - let workspace_c = client_c.build_workspace(&project_c, cx_c); + let workspace_c = client_c.build_workspace(&project_c, cx_c).root(cx_c); active_call_c .update(cx_c, |call, cx| call.set_location(Some(&project_c), cx)) .await @@ -6543,7 +6545,7 @@ async fn test_basic_following( cx_d.foreground().run_until_parked(); let active_call_d = cx_d.read(ActiveCall::global); let project_d = client_d.build_remote_project(project_id, cx_d).await; - let workspace_d = client_d.build_workspace(&project_d, cx_d); + let workspace_d = client_d.build_workspace(&project_d, cx_d).root(cx_d); active_call_d .update(cx_d, |call, cx| call.set_location(Some(&project_d), cx)) .await @@ -6870,9 +6872,7 @@ async fn test_basic_following( }); // Client B activates a panel, and the previously-opened screen-sharing item gets activated. - let panel = cx_b.add_view(workspace_b.window_id(), |_| { - TestPanel::new(DockPosition::Left) - }); + let panel = window_b.add_view(cx_b, |_| TestPanel::new(DockPosition::Left)); workspace_b.update(cx_b, |workspace, cx| { workspace.add_panel(panel, cx); workspace.toggle_panel_focus::(cx); @@ -6900,7 +6900,7 @@ async fn test_basic_following( // Client B activates an item that doesn't implement following, // so the previously-opened screen-sharing item gets activated. - let unfollowable_item = cx_b.add_view(workspace_b.window_id(), |_| TestItem::new()); + let unfollowable_item = window_b.add_view(cx_b, |_| TestItem::new()); workspace_b.update(cx_b, |workspace, cx| { workspace.active_pane().update(cx, |pane, cx| { pane.add_item(Box::new(unfollowable_item), true, true, None, cx) @@ -7062,10 +7062,10 @@ async fn test_following_tab_order( .await .unwrap(); - let workspace_a = client_a.build_workspace(&project_a, cx_a); + let workspace_a = client_a.build_workspace(&project_a, cx_a).root(cx_a); let pane_a = workspace_a.read_with(cx_a, |workspace, _| workspace.active_pane().clone()); - let workspace_b = client_b.build_workspace(&project_b, cx_b); + let workspace_b = client_b.build_workspace(&project_b, cx_b).root(cx_b); let pane_b = workspace_b.read_with(cx_b, |workspace, _| workspace.active_pane().clone()); let client_b_id = project_a.read_with(cx_a, |project, _| { @@ -7188,7 +7188,7 @@ async fn test_peers_following_each_other( .unwrap(); // Client A opens some editors. - let workspace_a = client_a.build_workspace(&project_a, cx_a); + let workspace_a = client_a.build_workspace(&project_a, cx_a).root(cx_a); let pane_a1 = workspace_a.read_with(cx_a, |workspace, _| workspace.active_pane().clone()); let _editor_a1 = workspace_a .update(cx_a, |workspace, cx| { @@ -7200,7 +7200,7 @@ async fn test_peers_following_each_other( .unwrap(); // Client B opens an editor. - let workspace_b = client_b.build_workspace(&project_b, cx_b); + let workspace_b = client_b.build_workspace(&project_b, cx_b).root(cx_b); let pane_b1 = workspace_b.read_with(cx_b, |workspace, _| workspace.active_pane().clone()); let _editor_b1 = workspace_b .update(cx_b, |workspace, cx| { @@ -7359,7 +7359,7 @@ async fn test_auto_unfollowing( .unwrap(); // Client A opens some editors. - let workspace_a = client_a.build_workspace(&project_a, cx_a); + let workspace_a = client_a.build_workspace(&project_a, cx_a).root(cx_a); let _editor_a1 = workspace_a .update(cx_a, |workspace, cx| { workspace.open_path((worktree_id, "1.txt"), None, true, cx) @@ -7370,7 +7370,7 @@ async fn test_auto_unfollowing( .unwrap(); // Client B starts following client A. - let workspace_b = client_b.build_workspace(&project_b, cx_b); + let workspace_b = client_b.build_workspace(&project_b, cx_b).root(cx_b); let pane_b = workspace_b.read_with(cx_b, |workspace, _| workspace.active_pane().clone()); let leader_id = project_b.read_with(cx_b, |project, _| { project.collaborators().values().next().unwrap().peer_id @@ -7498,14 +7498,14 @@ async fn test_peers_simultaneously_following_each_other( client_a.fs.insert_tree("/a", json!({})).await; let (project_a, _) = client_a.build_local_project("/a", cx_a).await; - let workspace_a = client_a.build_workspace(&project_a, cx_a); + let workspace_a = client_a.build_workspace(&project_a, cx_a).root(cx_a); let project_id = active_call_a .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx)) .await .unwrap(); let project_b = client_b.build_remote_project(project_id, cx_b).await; - let workspace_b = client_b.build_workspace(&project_b, cx_b); + let workspace_b = client_b.build_workspace(&project_b, cx_b).root(cx_b); deterministic.run_until_parked(); let client_a_id = project_b.read_with(cx_b, |project, _| { @@ -7887,7 +7887,7 @@ async fn test_mutual_editor_inlay_hint_cache_update( .await .unwrap(); - let workspace_a = client_a.build_workspace(&project_a, cx_a); + let workspace_a = client_a.build_workspace(&project_a, cx_a).root(cx_a); cx_a.foreground().start_waiting(); let _buffer_a = project_a @@ -7955,7 +7955,7 @@ async fn test_mutual_editor_inlay_hint_cache_update( "Host editor update the cache version after every cache/view change", ); }); - let workspace_b = client_b.build_workspace(&project_b, cx_b); + let workspace_b = client_b.build_workspace(&project_b, cx_b).root(cx_b); let editor_b = workspace_b .update(cx_b, |workspace, cx| { workspace.open_path((worktree_id, "main.rs"), None, true, cx) @@ -8194,8 +8194,8 @@ async fn test_inlay_hint_refresh_is_forwarded( .await .unwrap(); - let workspace_a = client_a.build_workspace(&project_a, cx_a); - let workspace_b = client_b.build_workspace(&project_b, cx_b); + let workspace_a = client_a.build_workspace(&project_a, cx_a).root(cx_a); + let workspace_b = client_b.build_workspace(&project_b, cx_b).root(cx_b); cx_a.foreground().start_waiting(); cx_b.foreground().start_waiting(); diff --git a/crates/command_palette/src/command_palette.rs b/crates/command_palette/src/command_palette.rs index 7d4b4126b702774bf8c295d3b61f904ff7ebf80c..f51a6c923802c93b197f059aed2af24f7cfde0e9 100644 --- a/crates/command_palette/src/command_palette.rs +++ b/crates/command_palette/src/command_palette.rs @@ -297,8 +297,7 @@ mod tests { let project = Project::test(app_state.fs.clone(), [], cx).await; let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx)); let workspace = window.root(cx); - let window_id = window.id(); - let editor = cx.add_view(window_id, |cx| { + let editor = window.add_view(cx, |cx| { let mut editor = Editor::single_line(None, cx); editor.set_text("abc", cx); editor diff --git a/crates/diagnostics/src/diagnostics.rs b/crates/diagnostics/src/diagnostics.rs index 2444465be666124adb706bcf1833c50c77cee081..16a7340fae485b1c1b329315700437e4470c3af9 100644 --- a/crates/diagnostics/src/diagnostics.rs +++ b/crates/diagnostics/src/diagnostics.rs @@ -857,7 +857,6 @@ mod tests { let project = Project::test(fs.clone(), ["/test".as_ref()], cx).await; let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx)); let workspace = window.root(cx); - let window_id = window.id(); // Create some diagnostics project.update(cx, |project, cx| { @@ -944,7 +943,7 @@ mod tests { }); // Open the project diagnostics view while there are already diagnostics. - let view = cx.add_view(window_id, |cx| { + let view = window.add_view(cx, |cx| { ProjectDiagnosticsEditor::new(project.clone(), workspace.downgrade(), cx) }); @@ -1252,9 +1251,8 @@ mod tests { let project = Project::test(fs.clone(), ["/test".as_ref()], cx).await; let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx)); let workspace = window.root(cx); - let window_id = window.id(); - let view = cx.add_view(window_id, |cx| { + let view = window.add_view(cx, |cx| { ProjectDiagnosticsEditor::new(project.clone(), workspace.downgrade(), cx) }); diff --git a/crates/editor/src/editor_tests.rs b/crates/editor/src/editor_tests.rs index c9688011a443fe0cb75fadbd9124b1feace579d6..ec1cc1249895881485489b56474c61aafd78d31d 100644 --- a/crates/editor/src/editor_tests.rs +++ b/crates/editor/src/editor_tests.rs @@ -525,9 +525,8 @@ async fn test_navigation_history(cx: &mut TestAppContext) { let project = Project::test(fs, [], cx).await; let window = cx.add_window(|cx| Workspace::test_new(project, cx)); let workspace = window.root(cx); - let window_id = window.id(); let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone()); - cx.add_view(window_id, |cx| { + window.add_view(cx, |cx| { let buffer = MultiBuffer::build_simple(&sample_text(300, 5, 'a'), cx); let mut editor = build_editor(buffer.clone(), cx); let handle = cx.handle(); diff --git a/crates/gpui/src/app/test_app_context.rs b/crates/gpui/src/app/test_app_context.rs index e0fd0cb8e9f15407f25a22aaa0e768ff786caecc..ff988607b094f8d3253b8baaad2e6332bee4ad84 100644 --- a/crates/gpui/src/app/test_app_context.rs +++ b/crates/gpui/src/app/test_app_context.rs @@ -162,15 +162,6 @@ impl TestAppContext { WindowHandle::new(window.id()) } - pub fn add_view(&mut self, window_id: usize, build_view: F) -> ViewHandle - where - T: View, - F: FnOnce(&mut ViewContext) -> T, - { - self.update_window(window_id, |cx| cx.add_view(build_view)) - .expect("window not found") - } - pub fn observe_global(&mut self, callback: F) -> Subscription where E: Any, diff --git a/crates/project_symbols/src/project_symbols.rs b/crates/project_symbols/src/project_symbols.rs index 8471f3a3a7014d2034438839f76ae9b4214ded52..e88aee5dcfb6b9b5862ba92e6e8fc32fbc0da8cb 100644 --- a/crates/project_symbols/src/project_symbols.rs +++ b/crates/project_symbols/src/project_symbols.rs @@ -328,10 +328,9 @@ mod tests { let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx)); let workspace = window.root(cx); - let window_id = window.id(); // Create the project symbols view. - let symbols = cx.add_view(window_id, |cx| { + let symbols = window.add_view(cx, |cx| { ProjectSymbols::new( ProjectSymbolsDelegate::new(workspace.downgrade(), project.clone()), cx, diff --git a/crates/search/src/buffer_search.rs b/crates/search/src/buffer_search.rs index 1e635432bd5c138f81410f3ac40ee461830ddb17..b20ffed6d7e1ad94e9c311503c332e066e5c9b91 100644 --- a/crates/search/src/buffer_search.rs +++ b/crates/search/src/buffer_search.rs @@ -850,12 +850,9 @@ mod tests { ) }); let window = cx.add_window(|_| EmptyView); + let editor = window.add_view(cx, |cx| Editor::for_buffer(buffer.clone(), None, cx)); - let editor = cx.add_view(window.id(), |cx| { - Editor::for_buffer(buffer.clone(), None, cx) - }); - - let search_bar = cx.add_view(window.id(), |cx| { + let search_bar = window.add_view(cx, |cx| { let mut search_bar = BufferSearchBar::new(cx); search_bar.set_active_pane_item(Some(&editor), cx); search_bar.show(cx); @@ -1234,9 +1231,9 @@ mod tests { let window = cx.add_window(|_| EmptyView); let window_id = window.id(); - let editor = cx.add_view(window_id, |cx| Editor::for_buffer(buffer.clone(), None, cx)); + let editor = window.add_view(cx, |cx| Editor::for_buffer(buffer.clone(), None, cx)); - let search_bar = cx.add_view(window_id, |cx| { + let search_bar = window.add_view(cx, |cx| { let mut search_bar = BufferSearchBar::new(cx); search_bar.set_active_pane_item(Some(&editor), cx); search_bar.show(cx); @@ -1421,11 +1418,9 @@ mod tests { let buffer = cx.add_model(|cx| Buffer::new(0, buffer_text, cx)); let window = cx.add_window(|_| EmptyView); - let editor = cx.add_view(window.id(), |cx| { - Editor::for_buffer(buffer.clone(), None, cx) - }); + let editor = window.add_view(cx, |cx| Editor::for_buffer(buffer.clone(), None, cx)); - let search_bar = cx.add_view(window.id(), |cx| { + let search_bar = window.add_view(cx, |cx| { let mut search_bar = BufferSearchBar::new(cx); search_bar.set_active_pane_item(Some(&editor), cx); search_bar.show(cx); diff --git a/crates/search/src/project_search.rs b/crates/search/src/project_search.rs index 0db66b4e378a56c97e2e2d1290742e52e1329bda..dffd88db14229871a805a282ccbc49670697206e 100644 --- a/crates/search/src/project_search.rs +++ b/crates/search/src/project_search.rs @@ -1874,7 +1874,6 @@ pub mod tests { let project = Project::test(fs.clone(), ["/dir".as_ref()], cx).await; let window = cx.add_window(|cx| Workspace::test_new(project, cx)); let workspace = window.root(cx); - let window_id = window.id(); workspace.update(cx, |workspace, cx| { ProjectSearchView::deploy(workspace, &workspace::NewSearch, cx) }); @@ -1889,7 +1888,7 @@ pub mod tests { .expect("Search view expected to appear after new search event trigger") }); - let search_bar = cx.add_view(window_id, |cx| { + let search_bar = window.add_view(cx, |cx| { let mut search_bar = ProjectSearchBar::new(); search_bar.set_active_pane_item(Some(&search_view), cx); // search_bar.show(cx); From dba2facd23d94ebb79aab8a32b4318ab28320c83 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 7 Aug 2023 22:58:01 -0600 Subject: [PATCH 25/41] Remove window via handles --- crates/collab_ui/src/incoming_call_notification.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/collab_ui/src/incoming_call_notification.rs b/crates/collab_ui/src/incoming_call_notification.rs index a9c5e697a5f60d0cb6f9c0e6baf7cac50aba192a..6f86a74300acc36e6fc7240dd023cb0d034e4f03 100644 --- a/crates/collab_ui/src/incoming_call_notification.rs +++ b/crates/collab_ui/src/incoming_call_notification.rs @@ -7,7 +7,7 @@ use gpui::{ elements::*, geometry::{rect::RectF, vector::vec2f}, platform::{CursorStyle, MouseButton, WindowBounds, WindowKind, WindowOptions}, - AnyElement, AppContext, Entity, View, ViewContext, + AnyElement, AppContext, Entity, View, ViewContext, WindowHandle, }; use util::ResultExt; use workspace::AppState; @@ -16,10 +16,10 @@ pub fn init(app_state: &Arc, cx: &mut AppContext) { let app_state = Arc::downgrade(app_state); let mut incoming_call = ActiveCall::global(cx).read(cx).incoming(); cx.spawn(|mut cx| async move { - let mut notification_windows = Vec::new(); + let mut notification_windows: Vec> = Vec::new(); while let Some(incoming_call) = incoming_call.next().await { - for window_id in notification_windows.drain(..) { - cx.remove_window(window_id); + for window in notification_windows.drain(..) { + window.remove(&mut cx); } if let Some(incoming_call) = incoming_call { @@ -49,7 +49,7 @@ pub fn init(app_state: &Arc, cx: &mut AppContext) { |_| IncomingCallNotification::new(incoming_call.clone(), app_state.clone()), ); - notification_windows.push(window.id()); + notification_windows.push(window); } } } From 1aff642981fd8b6fd9f4a0b58d7ca43758485edb Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Tue, 8 Aug 2023 13:09:27 +0200 Subject: [PATCH 26/41] Do not highlgiht selections at all over the threshold --- crates/editor/src/editor.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 17195cb22b5de1bc60c21c8169f929e020cc78f7..02cd58524bb5e6b5b97a17b751d9a2304abbaf11 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -7572,7 +7572,6 @@ impl Editor { }) { Ok(i) | Err(i) => i, }; - let end_ix = count.min(ranges.len()); let mut push_region = |start: Option, end: Option| { if let (Some(start_display), Some(end_display)) = (start, end) { results.push( @@ -7583,7 +7582,10 @@ impl Editor { }; let mut start_row: Option = None; let mut end_row: Option = None; - for range in &ranges[start_ix..end_ix] { + if ranges.len() > count { + return vec![]; + } + for range in &ranges[start_ix..] { if range.start.cmp(&search_range.end, buffer).is_ge() { break; } @@ -7616,9 +7618,6 @@ impl Editor { } // We might still have a hunk that was not rendered (if there was a search hit on the last line) push_region(start_row, end_row); - if results.len() > count { - return vec![]; - } results } From 49f1f1c6c263e1346f0534660c8ce2c8c70859be Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 8 Aug 2023 09:13:17 -0600 Subject: [PATCH 27/41] Remove window when closing workspace in test --- crates/collab/src/tests/integration_tests.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/collab/src/tests/integration_tests.rs b/crates/collab/src/tests/integration_tests.rs index 8ad7864adfc774888c395d9f14508a4e066edf63..ce7fd8a094abb4006c97701c612ed65cae49a105 100644 --- a/crates/collab/src/tests/integration_tests.rs +++ b/crates/collab/src/tests/integration_tests.rs @@ -6527,7 +6527,8 @@ async fn test_basic_following( cx_c.foreground().run_until_parked(); let active_call_c = cx_c.read(ActiveCall::global); let project_c = client_c.build_remote_project(project_id, cx_c).await; - let workspace_c = client_c.build_workspace(&project_c, cx_c).root(cx_c); + let window_c = client_c.build_workspace(&project_c, cx_c); + let workspace_c = window_c.root(cx_c); active_call_c .update(cx_c, |call, cx| call.set_location(Some(&project_c), cx)) .await @@ -6643,6 +6644,7 @@ async fn test_basic_following( } // Client C closes the project. + window_c.remove(cx_c); cx_c.drop_last(workspace_c); // Clients A and B see that client B is following A, and client C is not present in the followers. From d896d89842ed11021482aaa477177d1203f56347 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 8 Aug 2023 11:08:37 -0600 Subject: [PATCH 28/41] Store an AnyWindowHandle in WindowContext --- crates/collab_ui/src/contact_list.rs | 4 +- .../src/project_shared_notification.rs | 16 +- crates/command_palette/src/command_palette.rs | 8 +- crates/context_menu/src/context_menu.rs | 12 +- crates/file_finder/src/file_finder.rs | 42 +- crates/go_to_line/src/go_to_line.rs | 18 +- crates/gpui/src/app.rs | 621 +++++++++--------- crates/gpui/src/app/test_app_context.rs | 32 +- crates/gpui/src/app/window.rs | 149 ++--- crates/project_panel/src/project_panel.rs | 28 +- crates/search/src/buffer_search.rs | 15 +- crates/search/src/project_search.rs | 25 +- crates/vim/src/editor_events.rs | 10 +- crates/vim/src/mode_indicator.rs | 4 +- crates/vim/src/test/vim_test_context.rs | 4 +- crates/workspace/src/dock.rs | 12 +- crates/workspace/src/pane.rs | 4 +- crates/workspace/src/workspace.rs | 22 +- crates/zed/src/zed.rs | 59 +- 19 files changed, 526 insertions(+), 559 deletions(-) diff --git a/crates/collab_ui/src/contact_list.rs b/crates/collab_ui/src/contact_list.rs index 428f2156d116133d063710fed99c890e8ad30869..a2b281856d923754e715e0e112eca2f5c682e605 100644 --- a/crates/collab_ui/src/contact_list.rs +++ b/crates/collab_ui/src/contact_list.rs @@ -305,7 +305,7 @@ impl ContactList { github_login ); let mut answer = cx.prompt(PromptLevel::Warning, &prompt_message, &["Remove", "Cancel"]); - let window_id = cx.window_id(); + let window = cx.window(); cx.spawn(|_, mut cx| async move { if answer.next().await == Some(0) { if let Err(e) = user_store @@ -313,7 +313,7 @@ impl ContactList { .await { cx.prompt( - window_id, + window, PromptLevel::Info, &format!("Failed to remove contact: {}", e), &["Ok"], diff --git a/crates/collab_ui/src/project_shared_notification.rs b/crates/collab_ui/src/project_shared_notification.rs index d5e7c877f7067480688faedeb9b36be964878a72..63922f2b65c91df1053533584ac8f1bf3473c899 100644 --- a/crates/collab_ui/src/project_shared_notification.rs +++ b/crates/collab_ui/src/project_shared_notification.rs @@ -5,7 +5,7 @@ use gpui::{ elements::*, geometry::{rect::RectF, vector::vec2f}, platform::{CursorStyle, MouseButton, WindowBounds, WindowKind, WindowOptions}, - AppContext, BorrowWindowContext, Entity, View, ViewContext, + AppContext, Entity, View, ViewContext, }; use std::sync::{Arc, Weak}; use workspace::AppState; @@ -52,20 +52,20 @@ pub fn init(app_state: &Arc, cx: &mut AppContext) { notification_windows .entry(*project_id) .or_insert(Vec::new()) - .push(window.id()); + .push(window); } } room::Event::RemoteProjectUnshared { project_id } => { - if let Some(window_ids) = notification_windows.remove(&project_id) { - for window_id in window_ids { - cx.update_window(window_id, |cx| cx.remove_window()); + if let Some(windows) = notification_windows.remove(&project_id) { + for window in windows { + window.remove(cx); } } } room::Event::Left => { - for (_, window_ids) in notification_windows.drain() { - for window_id in window_ids { - cx.update_window(window_id, |cx| cx.remove_window()); + for (_, windows) in notification_windows.drain() { + for window in windows { + window.remove(cx); } } } diff --git a/crates/command_palette/src/command_palette.rs b/crates/command_palette/src/command_palette.rs index f51a6c923802c93b197f059aed2af24f7cfde0e9..b3703aa64a4549596caf47b57fc91971c985b8f0 100644 --- a/crates/command_palette/src/command_palette.rs +++ b/crates/command_palette/src/command_palette.rs @@ -80,11 +80,11 @@ impl PickerDelegate for CommandPaletteDelegate { query: String, cx: &mut ViewContext>, ) -> gpui::Task<()> { - let window_id = cx.window_id(); let view_id = self.focused_view_id; + let window = cx.window(); cx.spawn(move |picker, mut cx| async move { let actions = cx - .available_actions(window_id, view_id) + .available_actions(window, view_id) .into_iter() .filter_map(|(name, action, bindings)| { let filtered = cx.read(|cx| { @@ -162,13 +162,13 @@ impl PickerDelegate for CommandPaletteDelegate { fn confirm(&mut self, _: bool, cx: &mut ViewContext>) { if !self.matches.is_empty() { - let window_id = cx.window_id(); + let window = cx.window(); let focused_view_id = self.focused_view_id; let action_ix = self.matches[self.selected_ix].candidate_id; let action = self.actions.remove(action_ix).action; cx.app_context() .spawn(move |mut cx| async move { - cx.dispatch_action(window_id, focused_view_id, action.as_ref()) + cx.dispatch_action(window, focused_view_id, action.as_ref()) }) .detach_and_log_err(cx); } diff --git a/crates/context_menu/src/context_menu.rs b/crates/context_menu/src/context_menu.rs index f58afab361f4db153824ad9488fb295588dac425..75cfd872b29aba9b03b1235faeaba24d8ac95ae7 100644 --- a/crates/context_menu/src/context_menu.rs +++ b/crates/context_menu/src/context_menu.rs @@ -218,12 +218,12 @@ impl ContextMenu { if let Some(ContextMenuItem::Item { action, .. }) = self.items.get(ix) { match action { ContextMenuItemAction::Action(action) => { - let window_id = cx.window_id(); + let window = cx.window(); let view_id = self.parent_view_id; let action = action.boxed_clone(); cx.app_context() .spawn(|mut cx| async move { - cx.dispatch_action(window_id, view_id, action.as_ref()) + cx.dispatch_action(window, view_id, action.as_ref()) }) .detach_and_log_err(cx); } @@ -480,17 +480,13 @@ impl ContextMenu { .on_down(MouseButton::Left, |_, _, _| {}) // Capture these events .on_click(MouseButton::Left, move |_, menu, cx| { menu.cancel(&Default::default(), cx); - let window_id = cx.window_id(); + let window = cx.window(); match &action { ContextMenuItemAction::Action(action) => { let action = action.boxed_clone(); cx.app_context() .spawn(|mut cx| async move { - cx.dispatch_action( - window_id, - view_id, - action.as_ref(), - ) + cx.dispatch_action(window, view_id, action.as_ref()) }) .detach_and_log_err(cx); } diff --git a/crates/file_finder/src/file_finder.rs b/crates/file_finder/src/file_finder.rs index 12bf3242627619d390409bba044c0fa9cdcce3d4..523d6e8a5caeb9edea4c990237263c66e7d384e4 100644 --- a/crates/file_finder/src/file_finder.rs +++ b/crates/file_finder/src/file_finder.rs @@ -619,7 +619,7 @@ mod tests { let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await; let window = cx.add_window(|cx| Workspace::test_new(project, cx)); let workspace = window.root(cx); - cx.dispatch_action(window.id(), Toggle); + cx.dispatch_action(window.into(), Toggle); let finder = cx.read(|cx| workspace.read(cx).modal::().unwrap()); finder @@ -632,8 +632,8 @@ mod tests { }); let active_pane = cx.read(|cx| workspace.read(cx).active_pane().clone()); - cx.dispatch_action(window.id(), SelectNext); - cx.dispatch_action(window.id(), Confirm); + cx.dispatch_action(window.into(), SelectNext); + cx.dispatch_action(window.into(), Confirm); active_pane .condition(cx, |pane, _| pane.active_item().is_some()) .await; @@ -674,7 +674,7 @@ mod tests { let project = Project::test(app_state.fs.clone(), ["/src".as_ref()], cx).await; let window = cx.add_window(|cx| Workspace::test_new(project, cx)); let workspace = window.root(cx); - cx.dispatch_action(window.id(), Toggle); + cx.dispatch_action(window.into(), Toggle); let finder = cx.read(|cx| workspace.read(cx).modal::().unwrap()); let file_query = &first_file_name[..3]; @@ -706,8 +706,8 @@ mod tests { }); let active_pane = cx.read(|cx| workspace.read(cx).active_pane().clone()); - cx.dispatch_action(window.id(), SelectNext); - cx.dispatch_action(window.id(), Confirm); + cx.dispatch_action(window.into(), SelectNext); + cx.dispatch_action(window.into(), Confirm); active_pane .condition(cx, |pane, _| pane.active_item().is_some()) .await; @@ -758,7 +758,7 @@ mod tests { let project = Project::test(app_state.fs.clone(), ["/src".as_ref()], cx).await; let window = cx.add_window(|cx| Workspace::test_new(project, cx)); let workspace = window.root(cx); - cx.dispatch_action(window.id(), Toggle); + cx.dispatch_action(window.into(), Toggle); let finder = cx.read(|cx| workspace.read(cx).modal::().unwrap()); let file_query = &first_file_name[..3]; @@ -790,8 +790,8 @@ mod tests { }); let active_pane = cx.read(|cx| workspace.read(cx).active_pane().clone()); - cx.dispatch_action(window.id(), SelectNext); - cx.dispatch_action(window.id(), Confirm); + cx.dispatch_action(window.into(), SelectNext); + cx.dispatch_action(window.into(), Confirm); active_pane .condition(cx, |pane, _| pane.active_item().is_some()) .await; @@ -1168,7 +1168,6 @@ mod tests { let project = Project::test(app_state.fs.clone(), ["/src".as_ref()], cx).await; let window = cx.add_window(|cx| Workspace::test_new(project, cx)); let workspace = window.root(cx); - let window_id = window.id(); let worktree_id = cx.read(|cx| { let worktrees = workspace.read(cx).worktrees(cx).collect::>(); assert_eq!(worktrees.len(), 1); @@ -1186,7 +1185,7 @@ mod tests { "fir", 1, "first.rs", - window_id, + window.into(), &workspace, &deterministic, cx, @@ -1201,7 +1200,7 @@ mod tests { "sec", 1, "second.rs", - window_id, + window.into(), &workspace, &deterministic, cx, @@ -1223,7 +1222,7 @@ mod tests { "thi", 1, "third.rs", - window_id, + window.into(), &workspace, &deterministic, cx, @@ -1255,7 +1254,7 @@ mod tests { "sec", 1, "second.rs", - window_id, + window.into(), &workspace, &deterministic, cx, @@ -1294,7 +1293,7 @@ mod tests { "thi", 1, "third.rs", - window_id, + window.into(), &workspace, &deterministic, cx, @@ -1376,7 +1375,6 @@ mod tests { let window = cx.add_window(|cx| Workspace::test_new(project, cx)); let workspace = window.root(cx); - let window_id = window.id(); let worktree_id = cx.read(|cx| { let worktrees = workspace.read(cx).worktrees(cx).collect::>(); assert_eq!(worktrees.len(), 1,); @@ -1411,7 +1409,7 @@ mod tests { "sec", 1, "second.rs", - window_id, + window.into(), &workspace, &deterministic, cx, @@ -1433,7 +1431,7 @@ mod tests { "fir", 1, "first.rs", - window_id, + window.into(), &workspace, &deterministic, cx, @@ -1465,12 +1463,12 @@ mod tests { input: &str, expected_matches: usize, expected_editor_title: &str, - window_id: usize, + window: gpui::AnyWindowHandle, workspace: &ViewHandle, deterministic: &gpui::executor::Deterministic, cx: &mut gpui::TestAppContext, ) -> Vec { - cx.dispatch_action(window_id, Toggle); + cx.dispatch_action(window, Toggle); let finder = cx.read(|cx| workspace.read(cx).modal::().unwrap()); finder .update(cx, |finder, cx| { @@ -1487,8 +1485,8 @@ mod tests { }); let active_pane = cx.read(|cx| workspace.read(cx).active_pane().clone()); - cx.dispatch_action(window_id, SelectNext); - cx.dispatch_action(window_id, Confirm); + cx.dispatch_action(window, SelectNext); + cx.dispatch_action(window, Confirm); deterministic.run_until_parked(); active_pane .condition(cx, |pane, _| pane.active_item().is_some()) diff --git a/crates/go_to_line/src/go_to_line.rs b/crates/go_to_line/src/go_to_line.rs index fa42a523741679c191c5fab053417243f4d5d4df..1d3b44fa4359ec31fbb3c6aab5ba9b161d23f693 100644 --- a/crates/go_to_line/src/go_to_line.rs +++ b/crates/go_to_line/src/go_to_line.rs @@ -135,16 +135,14 @@ impl Entity for GoToLine { fn release(&mut self, cx: &mut AppContext) { let scroll_position = self.prev_scroll_position.take(); - if let Some(window) = self.active_editor.window(cx) { - window.update(cx, |cx| { - self.active_editor.update(cx, |editor, cx| { - editor.highlight_rows(None); - if let Some(scroll_position) = scroll_position { - editor.set_scroll_position(scroll_position, cx); - } - }) - }); - } + self.active_editor.window().update(cx, |cx| { + self.active_editor.update(cx, |editor, cx| { + editor.highlight_rows(None); + if let Some(scroll_position) = scroll_position { + editor.set_scroll_position(scroll_position, cx); + } + }) + }); } } diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index ff8e343c2caaf361c2b178f16d1c94b492973cb8..e0f46b036a07322844daf0fd7ca30c4d546e185f 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -134,16 +134,16 @@ pub trait BorrowAppContext { pub trait BorrowWindowContext { type Result; - fn read_window(&self, window_id: usize, f: F) -> Self::Result + fn read_window(&self, window: AnyWindowHandle, f: F) -> Self::Result where F: FnOnce(&WindowContext) -> T; - fn read_window_optional(&self, window_id: usize, f: F) -> Option + fn read_window_optional(&self, window: AnyWindowHandle, f: F) -> Option where F: FnOnce(&WindowContext) -> Option; - fn update_window(&mut self, window_id: usize, f: F) -> Self::Result + fn update_window(&mut self, window: AnyWindowHandle, f: F) -> Self::Result where F: FnOnce(&mut WindowContext) -> T; - fn update_window_optional(&mut self, window_id: usize, f: F) -> Option + fn update_window_optional(&mut self, window: AnyWindowHandle, f: F) -> Option where F: FnOnce(&mut WindowContext) -> Option; } @@ -308,12 +308,12 @@ impl App { result } - fn update_window(&mut self, window_id: usize, callback: F) -> Option + fn update_window(&mut self, window: AnyWindowHandle, callback: F) -> Option where F: FnOnce(&mut WindowContext) -> T, { let mut state = self.0.borrow_mut(); - let result = state.update_window(window_id, callback); + let result = state.update_window(window, callback); state.pending_notifications.clear(); result } @@ -346,22 +346,22 @@ impl AsyncAppContext { pub fn read_window T>( &self, - window_id: usize, + window: AnyWindowHandle, callback: F, ) -> Option { - self.0.borrow_mut().read_window(window_id, callback) + self.0.borrow_mut().read_window(window, callback) } pub fn update_window T>( &mut self, - window_id: usize, + window: AnyWindowHandle, callback: F, ) -> Option { - self.0.borrow_mut().update_window(window_id, callback) + self.0.borrow_mut().update_window(window, callback) } - pub fn debug_elements(&self, window_id: usize) -> Option { - self.0.borrow().read_window(window_id, |cx| { + pub fn debug_elements(&self, window: AnyWindowHandle) -> Option { + self.0.borrow().read_window(window, |cx| { let root_view = cx.window.root_view(); let root_element = cx.window.rendered_views.get(&root_view.id())?; root_element.debug(cx).log_err() @@ -370,13 +370,13 @@ impl AsyncAppContext { pub fn dispatch_action( &mut self, - window_id: usize, + window: AnyWindowHandle, view_id: usize, action: &dyn Action, ) -> Result<()> { self.0 .borrow_mut() - .update_window(window_id, |cx| { + .update_window(window, |cx| { cx.dispatch_action(Some(view_id), action); }) .ok_or_else(|| anyhow!("window not found")) @@ -384,10 +384,10 @@ impl AsyncAppContext { pub fn available_actions( &self, - window_id: usize, + window: AnyWindowHandle, view_id: usize, ) -> Vec<(&'static str, Box, SmallVec<[Binding; 1]>)> { - self.read_window(window_id, |cx| cx.available_actions(view_id)) + self.read_window(window, |cx| cx.available_actions(view_id)) .unwrap_or_default() } @@ -411,23 +411,23 @@ impl AsyncAppContext { self.update(|cx| cx.add_window(window_options, build_root_view)) } - pub fn remove_window(&mut self, window_id: usize) { - self.update_window(window_id, |cx| cx.remove_window()); + pub fn remove_window(&mut self, window: AnyWindowHandle) { + self.update_window(window, |cx| cx.remove_window()); } - pub fn activate_window(&mut self, window_id: usize) { - self.update_window(window_id, |cx| cx.activate_window()); + pub fn activate_window(&mut self, window: AnyWindowHandle) { + self.update_window(window, |cx| cx.activate_window()); } // TODO: Can we eliminate this method and move it to WindowContext then call it with update_window?s pub fn prompt( &mut self, - window_id: usize, + window: AnyWindowHandle, level: PromptLevel, msg: &str, answers: &[&str], ) -> Option> { - self.update_window(window_id, |cx| cx.prompt(level, msg, answers)) + self.update_window(window, |cx| cx.prompt(level, msg, answers)) } pub fn platform(&self) -> Arc { @@ -456,38 +456,36 @@ impl BorrowAppContext for AsyncAppContext { impl BorrowWindowContext for AsyncAppContext { type Result = Option; - fn read_window(&self, window_id: usize, f: F) -> Self::Result + fn read_window(&self, window: AnyWindowHandle, f: F) -> Self::Result where F: FnOnce(&WindowContext) -> T, { - self.0.borrow().read_with(|cx| cx.read_window(window_id, f)) + self.0.borrow().read_with(|cx| cx.read_window(window, f)) } - fn read_window_optional(&self, window_id: usize, f: F) -> Option + fn read_window_optional(&self, window: AnyWindowHandle, f: F) -> Option where F: FnOnce(&WindowContext) -> Option, { self.0 .borrow_mut() - .update(|cx| cx.read_window_optional(window_id, f)) + .update(|cx| cx.read_window_optional(window, f)) } - fn update_window(&mut self, window_id: usize, f: F) -> Self::Result + fn update_window(&mut self, window: AnyWindowHandle, f: F) -> Self::Result where F: FnOnce(&mut WindowContext) -> T, { - self.0 - .borrow_mut() - .update(|cx| cx.update_window(window_id, f)) + self.0.borrow_mut().update(|cx| cx.update_window(window, f)) } - fn update_window_optional(&mut self, window_id: usize, f: F) -> Option + fn update_window_optional(&mut self, window: AnyWindowHandle, f: F) -> Option where F: FnOnce(&mut WindowContext) -> Option, { self.0 .borrow_mut() - .update(|cx| cx.update_window_optional(window_id, f)) + .update(|cx| cx.update_window_optional(window, f)) } } @@ -534,7 +532,7 @@ pub struct AppContext { global_actions: HashMap>, keystroke_matcher: KeymapMatcher, next_id: usize, - // next_window_id: usize, + // next_window: AnyWindowHandle, next_subscription_id: usize, frame_count: usize, @@ -794,13 +792,13 @@ impl AppContext { } } - pub fn view_ui_name(&self, window_id: usize, view_id: usize) -> Option<&'static str> { - Some(self.views.get(&(window_id, view_id))?.ui_name()) + pub fn view_ui_name(&self, window: AnyWindowHandle, view_id: usize) -> Option<&'static str> { + Some(self.views.get(&(window.id(), view_id))?.ui_name()) } - pub fn view_type_id(&self, window_id: usize, view_id: usize) -> Option { + pub fn view_type_id(&self, window: AnyWindowHandle, view_id: usize) -> Option { self.views_metadata - .get(&(window_id, view_id)) + .get(&(window.id(), view_id)) .map(|metadata| metadata.type_id) } @@ -823,11 +821,11 @@ impl AppContext { fn read_window T>( &self, - window_id: usize, + handle: AnyWindowHandle, callback: F, ) -> Option { - let window = self.windows.get(&window_id)?; - let window_context = WindowContext::immutable(self, &window, window_id); + let window = self.windows.get(&handle.id())?; + let window_context = WindowContext::immutable(self, &window, handle); Some(callback(&window_context)) } @@ -835,9 +833,8 @@ impl AppContext { &mut self, callback: F, ) -> Option { - self.platform - .main_window_id() - .and_then(|id| self.update_window(id, callback)) + self.main_window() + .and_then(|window| window.update(self, callback)) } pub fn prompt_for_paths( @@ -1075,10 +1072,10 @@ impl AppContext { } } - fn notify_view(&mut self, window_id: usize, view_id: usize) { + fn notify_view(&mut self, window: AnyWindowHandle, view_id: usize) { if self.pending_notifications.insert(view_id) { self.pending_effects - .push_back(Effect::ViewNotification { window_id, view_id }); + .push_back(Effect::ViewNotification { window, view_id }); } } @@ -1096,13 +1093,13 @@ impl AppContext { pub fn is_action_available(&self, action: &dyn Action) -> bool { let mut available_in_window = false; let action_id = action.id(); - if let Some(window_id) = self.platform.main_window_id() { + if let Some(window) = self.main_window() { available_in_window = self - .read_window(window_id, |cx| { + .read_window(window, |cx| { if let Some(focused_view_id) = cx.focused_view_id() { for view_id in cx.ancestors(focused_view_id) { if let Some(view_metadata) = - cx.views_metadata.get(&(window_id, view_id)) + cx.views_metadata.get(&(cx.window_handle.id(), view_id)) { if let Some(actions) = cx.actions.get(&view_metadata.type_id) { if actions.contains_key(&action_id) { @@ -1367,13 +1364,12 @@ impl AppContext { F: FnOnce(&mut ViewContext) -> V, { let handle: AnyWindowHandle = handle.into(); - let window_id = handle.id(); { let mut app = self.upgrade(); platform_window.on_event(Box::new(move |event| { - app.update_window(window_id, |cx| { + app.update_window(handle, |cx| { if let Event::KeyDown(KeyDownEvent { keystroke, .. }) = &event { if cx.dispatch_keystroke(keystroke) { return true; @@ -1389,35 +1385,35 @@ impl AppContext { { let mut app = self.upgrade(); platform_window.on_active_status_change(Box::new(move |is_active| { - app.update(|cx| cx.window_changed_active_status(window_id, is_active)) + app.update(|cx| cx.window_changed_active_status(handle, is_active)) })); } { let mut app = self.upgrade(); platform_window.on_resize(Box::new(move || { - app.update(|cx| cx.window_was_resized(window_id)) + app.update(|cx| cx.window_was_resized(handle)) })); } { let mut app = self.upgrade(); platform_window.on_moved(Box::new(move || { - app.update(|cx| cx.window_was_moved(window_id)) + app.update(|cx| cx.window_was_moved(handle)) })); } { let mut app = self.upgrade(); platform_window.on_fullscreen(Box::new(move |is_fullscreen| { - app.update(|cx| cx.window_was_fullscreen_changed(window_id, is_fullscreen)) + app.update(|cx| cx.window_was_fullscreen_changed(handle, is_fullscreen)) })); } { let mut app = self.upgrade(); platform_window.on_close(Box::new(move || { - app.update(|cx| cx.update_window(window_id, |cx| cx.remove_window())); + app.update(|cx| cx.update_window(handle, |cx| cx.remove_window())); })); } @@ -1432,8 +1428,8 @@ impl AppContext { window: handle, })); - let mut window = Window::new(window_id, platform_window, self, build_root_view); - let mut cx = WindowContext::mutable(self, &mut window, window_id); + let mut window = Window::new(handle, platform_window, self, build_root_view); + let mut cx = WindowContext::mutable(self, &mut window, handle); cx.layout(false).expect("initial layout should not error"); let scene = cx.paint().expect("initial paint should not error"); window.platform_window.present_scene(scene); @@ -1455,7 +1451,7 @@ impl AppContext { } pub fn read_view(&self, handle: &ViewHandle) -> &T { - if let Some(view) = self.views.get(&(handle.window_id, handle.view_id)) { + if let Some(view) = self.views.get(&(handle.window.id(), handle.view_id)) { view.as_any().downcast_ref().expect("downcast is type safe") } else { panic!("circular view reference for type {}", type_name::()); @@ -1465,7 +1461,7 @@ impl AppContext { fn upgrade_view_handle(&self, handle: &WeakViewHandle) -> Option> { if self.ref_counts.lock().is_entity_alive(handle.view_id) { Some(ViewHandle::new( - handle.window_id, + handle.window, handle.view_id, &self.ref_counts, )) @@ -1477,7 +1473,7 @@ impl AppContext { fn upgrade_any_view_handle(&self, handle: &AnyWeakViewHandle) -> Option { if self.ref_counts.lock().is_entity_alive(handle.view_id) { Some(AnyViewHandle::new( - handle.window_id, + handle.window, handle.view_id, handle.view_type, self.ref_counts.clone(), @@ -1585,9 +1581,10 @@ impl AppContext { observations.emit(model_id, |callback| callback(self)); } - Effect::ViewNotification { window_id, view_id } => { - self.handle_view_notification_effect(window_id, view_id) - } + Effect::ViewNotification { + window: window_id, + view_id, + } => self.handle_view_notification_effect(window_id, view_id), Effect::GlobalNotification { type_id } => { let mut subscriptions = self.global_observations.clone(); @@ -1618,13 +1615,13 @@ impl AppContext { Effect::Focus(mut effect) => { if focus_effects - .get(&effect.window_id()) + .get(&effect.window().id()) .map_or(false, |prev_effect| prev_effect.is_forced()) { effect.force(); } - focus_effects.insert(effect.window_id(), effect); + focus_effects.insert(effect.window().id(), effect); } Effect::FocusObservation { @@ -1639,42 +1636,38 @@ impl AppContext { ); } - Effect::ResizeWindow { window_id } => { - if let Some(window) = self.windows.get_mut(&window_id) { + Effect::ResizeWindow { window } => { + if let Some(window) = self.windows.get_mut(&window.id()) { window .invalidation .get_or_insert(WindowInvalidation::default()); } - self.handle_window_moved(window_id); + self.handle_window_moved(window); } - Effect::MoveWindow { window_id } => { - self.handle_window_moved(window_id); + Effect::MoveWindow { window } => { + self.handle_window_moved(window); } Effect::WindowActivationObservation { - window_id, + window, subscription_id, callback, } => self.window_activation_observations.add_callback( - window_id, + window.id(), subscription_id, callback, ), - Effect::ActivateWindow { - window_id, - is_active, - } => { - if self.handle_window_activation_effect(window_id, is_active) - && is_active + Effect::ActivateWindow { window, is_active } => { + if self.handle_window_activation_effect(window, is_active) && is_active { focus_effects - .entry(window_id) + .entry(window.id()) .or_insert_with(|| FocusEffect::View { - window_id, + window, view_id: self - .read_window(window_id, |cx| cx.focused_view_id()) + .read_window(window, |cx| cx.focused_view_id()) .flatten(), is_forced: true, }) @@ -1683,26 +1676,26 @@ impl AppContext { } Effect::WindowFullscreenObservation { - window_id, + window, subscription_id, callback, } => self.window_fullscreen_observations.add_callback( - window_id, + window.id(), subscription_id, callback, ), Effect::FullscreenWindow { - window_id, + window, is_fullscreen, - } => self.handle_fullscreen_effect(window_id, is_fullscreen), + } => self.handle_fullscreen_effect(window, is_fullscreen), Effect::WindowBoundsObservation { - window_id, + window, subscription_id, callback, } => self.window_bounds_observations.add_callback( - window_id, + window.id(), subscription_id, callback, ), @@ -1714,18 +1707,15 @@ impl AppContext { Effect::ActionDispatchNotification { action_id } => { self.handle_action_dispatch_notification_effect(action_id) } - Effect::WindowShouldCloseSubscription { - window_id, - callback, - } => { - self.handle_window_should_close_subscription_effect(window_id, callback) + Effect::WindowShouldCloseSubscription { window, callback } => { + self.handle_window_should_close_subscription_effect(window, callback) } Effect::Keystroke { - window_id, + window, keystroke, handled_by, result, - } => self.handle_keystroke_effect(window_id, keystroke, handled_by, result), + } => self.handle_keystroke_effect(window, keystroke, handled_by, result), Effect::ActiveLabeledTasksChanged => { self.handle_active_labeled_tasks_changed_effect() } @@ -1740,8 +1730,8 @@ impl AppContext { } self.pending_notifications.clear(); } else { - for window_id in self.windows.keys().cloned().collect::>() { - self.update_window(window_id, |cx| { + for window in self.windows().collect::>() { + self.update_window(window, |cx| { let invalidation = if refreshing { let mut invalidation = cx.window.invalidation.take().unwrap_or_default(); @@ -1757,7 +1747,7 @@ impl AppContext { let appearance = cx.window.platform_window.appearance(); cx.invalidate(invalidation, appearance); if let Some(old_parents) = cx.layout(refreshing).log_err() { - updated_windows.insert(window_id); + updated_windows.insert(window); if let Some(focused_view_id) = cx.focused_view_id() { let old_ancestors = std::iter::successors( @@ -1772,7 +1762,7 @@ impl AppContext { for old_ancestor in old_ancestors.iter().copied() { if !new_ancestors.contains(&old_ancestor) { if let Some(mut view) = - cx.views.remove(&(window_id, old_ancestor)) + cx.views.remove(&(window.id(), old_ancestor)) { view.focus_out( focused_view_id, @@ -1780,7 +1770,7 @@ impl AppContext { old_ancestor, ); cx.views - .insert((window_id, old_ancestor), view); + .insert((window.id(), old_ancestor), view); } } } @@ -1789,7 +1779,7 @@ impl AppContext { for new_ancestor in new_ancestors.iter().copied() { if !old_ancestors.contains(&new_ancestor) { if let Some(mut view) = - cx.views.remove(&(window_id, new_ancestor)) + cx.views.remove(&(window.id(), new_ancestor)) { view.focus_in( focused_view_id, @@ -1797,7 +1787,7 @@ impl AppContext { new_ancestor, ); cx.views - .insert((window_id, new_ancestor), view); + .insert((window.id(), new_ancestor), view); } } } @@ -1806,13 +1796,15 @@ impl AppContext { // there isn't any pending focus, focus the root view. let root_view_id = cx.window.root_view().id(); if focused_view_id != root_view_id - && !cx.views.contains_key(&(window_id, focused_view_id)) - && !focus_effects.contains_key(&window_id) + && !cx + .views + .contains_key(&(window.id(), focused_view_id)) + && !focus_effects.contains_key(&window.id()) { focus_effects.insert( - window_id, + window.id(), FocusEffect::View { - window_id, + window, view_id: Some(root_view_id), is_forced: false, }, @@ -1833,8 +1825,8 @@ impl AppContext { callback(self); } - for window_id in updated_windows.drain() { - self.update_window(window_id, |cx| { + for window in updated_windows.drain() { + self.update_window(window, |cx| { if let Some(scene) = cx.paint().log_err() { cx.window.platform_window.present_scene(scene); } @@ -1855,39 +1847,37 @@ impl AppContext { } } - fn window_was_resized(&mut self, window_id: usize) { + fn window_was_resized(&mut self, window: AnyWindowHandle) { self.pending_effects - .push_back(Effect::ResizeWindow { window_id }); + .push_back(Effect::ResizeWindow { window }); } - fn window_was_moved(&mut self, window_id: usize) { + fn window_was_moved(&mut self, window: AnyWindowHandle) { self.pending_effects - .push_back(Effect::MoveWindow { window_id }); + .push_back(Effect::MoveWindow { window }); } - fn window_was_fullscreen_changed(&mut self, window_id: usize, is_fullscreen: bool) { + fn window_was_fullscreen_changed(&mut self, window: AnyWindowHandle, is_fullscreen: bool) { self.pending_effects.push_back(Effect::FullscreenWindow { - window_id, + window, is_fullscreen, }); } - fn window_changed_active_status(&mut self, window_id: usize, is_active: bool) { - self.pending_effects.push_back(Effect::ActivateWindow { - window_id, - is_active, - }); + fn window_changed_active_status(&mut self, window: AnyWindowHandle, is_active: bool) { + self.pending_effects + .push_back(Effect::ActivateWindow { window, is_active }); } fn keystroke( &mut self, - window_id: usize, + window: AnyWindowHandle, keystroke: Keystroke, handled_by: Option>, result: MatchResult, ) { self.pending_effects.push_back(Effect::Keystroke { - window_id, + window, keystroke, handled_by, result, @@ -1910,16 +1900,16 @@ impl AppContext { fn handle_view_notification_effect( &mut self, - observed_window_id: usize, + observed_window: AnyWindowHandle, observed_view_id: usize, ) { - let view_key = (observed_window_id, observed_view_id); + let view_key = (observed_window.id(), observed_view_id); if let Some((view, mut view_metadata)) = self .views .remove(&view_key) .zip(self.views_metadata.remove(&view_key)) { - if let Some(window) = self.windows.get_mut(&observed_window_id) { + if let Some(window) = self.windows.get_mut(&observed_window.id()) { window .invalidation .get_or_insert_with(Default::default) @@ -1946,17 +1936,17 @@ impl AppContext { }) } - fn handle_fullscreen_effect(&mut self, window_id: usize, is_fullscreen: bool) { - self.update_window(window_id, |cx| { + fn handle_fullscreen_effect(&mut self, window: AnyWindowHandle, is_fullscreen: bool) { + self.update_window(window, |cx| { cx.window.is_fullscreen = is_fullscreen; let mut fullscreen_observations = cx.window_fullscreen_observations.clone(); - fullscreen_observations.emit(window_id, |callback| callback(is_fullscreen, cx)); + fullscreen_observations.emit(window.id(), |callback| callback(is_fullscreen, cx)); if let Some(uuid) = cx.window_display_uuid() { let bounds = cx.window_bounds(); let mut bounds_observations = cx.window_bounds_observations.clone(); - bounds_observations.emit(window_id, |callback| callback(bounds, uuid, cx)); + bounds_observations.emit(window.id(), |callback| callback(bounds, uuid, cx)); } Some(()) @@ -1965,42 +1955,42 @@ impl AppContext { fn handle_keystroke_effect( &mut self, - window_id: usize, + window: AnyWindowHandle, keystroke: Keystroke, handled_by: Option>, result: MatchResult, ) { - self.update_window(window_id, |cx| { + self.update_window(window, |cx| { let mut observations = cx.keystroke_observations.clone(); - observations.emit(window_id, move |callback| { + observations.emit(window.id(), move |callback| { callback(&keystroke, &result, handled_by.as_ref(), cx) }); }); } - fn handle_window_activation_effect(&mut self, window_id: usize, active: bool) -> bool { - self.update_window(window_id, |cx| { + fn handle_window_activation_effect(&mut self, window: AnyWindowHandle, active: bool) -> bool { + self.update_window(window, |cx| { if cx.window.is_active == active { return false; } cx.window.is_active = active; let mut observations = cx.window_activation_observations.clone(); - observations.emit(window_id, |callback| callback(active, cx)); + observations.emit(window.id(), |callback| callback(active, cx)); true }) .unwrap_or(false) } fn handle_focus_effect(&mut self, effect: FocusEffect) { - let window_id = effect.window_id(); - self.update_window(window_id, |cx| { + let window = effect.window(); + self.update_window(window, |cx| { // Ensure the newly-focused view still exists, otherwise focus // the root view instead. let focused_id = match effect { FocusEffect::View { view_id, .. } => { if let Some(view_id) = view_id { - if cx.views.contains_key(&(window_id, view_id)) { + if cx.views.contains_key(&(window.id(), view_id)) { Some(view_id) } else { Some(cx.root_view().id()) @@ -2025,9 +2015,9 @@ impl AppContext { if focus_changed { if let Some(blurred_id) = blurred_id { for view_id in cx.ancestors(blurred_id).collect::>() { - if let Some(mut view) = cx.views.remove(&(window_id, view_id)) { + if let Some(mut view) = cx.views.remove(&(window.id(), view_id)) { view.focus_out(blurred_id, cx, view_id); - cx.views.insert((window_id, view_id), view); + cx.views.insert((window.id(), view_id), view); } } @@ -2039,9 +2029,9 @@ impl AppContext { if focus_changed || effect.is_forced() { if let Some(focused_id) = focused_id { for view_id in cx.ancestors(focused_id).collect::>() { - if let Some(mut view) = cx.views.remove(&(window_id, view_id)) { + if let Some(mut view) = cx.views.remove(&(window.id(), view_id)) { view.focus_in(focused_id, cx, view_id); - cx.views.insert((window_id, view_id), view); + cx.views.insert((window.id(), view_id), view); } } @@ -2063,24 +2053,24 @@ impl AppContext { fn handle_window_should_close_subscription_effect( &mut self, - window_id: usize, + window: AnyWindowHandle, mut callback: WindowShouldCloseSubscriptionCallback, ) { let mut app = self.upgrade(); - if let Some(window) = self.windows.get_mut(&window_id) { + if let Some(window) = self.windows.get_mut(&window.id()) { window .platform_window .on_should_close(Box::new(move || app.update(|cx| callback(cx)))) } } - fn handle_window_moved(&mut self, window_id: usize) { - self.update_window(window_id, |cx| { + fn handle_window_moved(&mut self, window: AnyWindowHandle) { + self.update_window(window, |cx| { if let Some(display) = cx.window_display_uuid() { let bounds = cx.window_bounds(); cx.window_bounds_observations .clone() - .emit(window_id, move |callback| { + .emit(window.id(), move |callback| { callback(bounds, display, cx); true }); @@ -2097,10 +2087,10 @@ impl AppContext { }); } - pub fn focus(&mut self, window_id: usize, view_id: Option) { + pub fn focus(&mut self, window: AnyWindowHandle, view_id: Option) { self.pending_effects .push_back(Effect::Focus(FocusEffect::View { - window_id, + window, view_id, is_forced: false, })); @@ -2185,40 +2175,40 @@ impl BorrowAppContext for AppContext { impl BorrowWindowContext for AppContext { type Result = Option; - fn read_window(&self, window_id: usize, f: F) -> Self::Result + fn read_window(&self, window: AnyWindowHandle, f: F) -> Self::Result where F: FnOnce(&WindowContext) -> T, { - AppContext::read_window(self, window_id, f) + AppContext::read_window(self, window, f) } - fn read_window_optional(&self, window_id: usize, f: F) -> Option + fn read_window_optional(&self, window: AnyWindowHandle, f: F) -> Option where F: FnOnce(&WindowContext) -> Option, { - AppContext::read_window(self, window_id, f).flatten() + AppContext::read_window(self, window, f).flatten() } - fn update_window(&mut self, window_id: usize, f: F) -> Self::Result + fn update_window(&mut self, handle: AnyWindowHandle, f: F) -> Self::Result where F: FnOnce(&mut WindowContext) -> T, { self.update(|app_context| { - let mut window = app_context.windows.remove(&window_id)?; - let mut window_context = WindowContext::mutable(app_context, &mut window, window_id); + let mut window = app_context.windows.remove(&handle.id())?; + let mut window_context = WindowContext::mutable(app_context, &mut window, handle); let result = f(&mut window_context); if !window_context.removed { - app_context.windows.insert(window_id, window); + app_context.windows.insert(handle.id(), window); } Some(result) }) } - fn update_window_optional(&mut self, window_id: usize, f: F) -> Option + fn update_window_optional(&mut self, handle: AnyWindowHandle, f: F) -> Option where F: FnOnce(&mut WindowContext) -> Option, { - AppContext::update_window(self, window_id, f).flatten() + AppContext::update_window(self, handle, f).flatten() } } @@ -2242,22 +2232,22 @@ pub struct WindowInvalidation { #[derive(Debug)] pub enum FocusEffect { View { - window_id: usize, + window: AnyWindowHandle, view_id: Option, is_forced: bool, }, ViewParent { - window_id: usize, + window: AnyWindowHandle, view_id: usize, is_forced: bool, }, } impl FocusEffect { - fn window_id(&self) -> usize { + fn window(&self) -> AnyWindowHandle { match self { - FocusEffect::View { window_id, .. } => *window_id, - FocusEffect::ViewParent { window_id, .. } => *window_id, + FocusEffect::View { window, .. } => *window, + FocusEffect::ViewParent { window, .. } => *window, } } @@ -2303,7 +2293,7 @@ pub enum Effect { model_id: usize, }, ViewNotification { - window_id: usize, + window: AnyWindowHandle, view_id: usize, }, Deferred { @@ -2328,36 +2318,36 @@ pub enum Effect { callback: FocusObservationCallback, }, ResizeWindow { - window_id: usize, + window: AnyWindowHandle, }, MoveWindow { - window_id: usize, + window: AnyWindowHandle, }, ActivateWindow { - window_id: usize, + window: AnyWindowHandle, is_active: bool, }, WindowActivationObservation { - window_id: usize, + window: AnyWindowHandle, subscription_id: usize, callback: WindowActivationCallback, }, FullscreenWindow { - window_id: usize, + window: AnyWindowHandle, is_fullscreen: bool, }, WindowFullscreenObservation { - window_id: usize, + window: AnyWindowHandle, subscription_id: usize, callback: WindowFullscreenCallback, }, WindowBoundsObservation { - window_id: usize, + window: AnyWindowHandle, subscription_id: usize, callback: WindowBoundsCallback, }, Keystroke { - window_id: usize, + window: AnyWindowHandle, keystroke: Keystroke, handled_by: Option>, result: MatchResult, @@ -2367,7 +2357,7 @@ pub enum Effect { action_id: TypeId, }, WindowShouldCloseSubscription { - window_id: usize, + window: AnyWindowHandle, callback: WindowShouldCloseSubscriptionCallback, }, ActiveLabeledTasksChanged, @@ -2419,9 +2409,9 @@ impl Debug for Effect { .debug_struct("Effect::ModelNotification") .field("model_id", model_id) .finish(), - Effect::ViewNotification { window_id, view_id } => f + Effect::ViewNotification { window, view_id } => f .debug_struct("Effect::ViewNotification") - .field("window_id", window_id) + .field("window_id", &window.id()) .field("view_id", view_id) .finish(), Effect::GlobalNotification { type_id } => f @@ -2451,71 +2441,68 @@ impl Debug for Effect { .debug_struct("Effect::ActionDispatchNotification") .field("action_id", action_id) .finish(), - Effect::ResizeWindow { window_id } => f + Effect::ResizeWindow { window } => f .debug_struct("Effect::RefreshWindow") - .field("window_id", window_id) + .field("window_id", &window.id()) .finish(), - Effect::MoveWindow { window_id } => f + Effect::MoveWindow { window } => f .debug_struct("Effect::MoveWindow") - .field("window_id", window_id) + .field("window_id", &window.id()) .finish(), Effect::WindowActivationObservation { - window_id, + window, subscription_id, .. } => f .debug_struct("Effect::WindowActivationObservation") - .field("window_id", window_id) + .field("window_id", &window.id()) .field("subscription_id", subscription_id) .finish(), - Effect::ActivateWindow { - window_id, - is_active, - } => f + Effect::ActivateWindow { window, is_active } => f .debug_struct("Effect::ActivateWindow") - .field("window_id", window_id) + .field("window_id", &window.id()) .field("is_active", is_active) .finish(), Effect::FullscreenWindow { - window_id, + window, is_fullscreen, } => f .debug_struct("Effect::FullscreenWindow") - .field("window_id", window_id) + .field("window_id", &window.id()) .field("is_fullscreen", is_fullscreen) .finish(), Effect::WindowFullscreenObservation { - window_id, + window, subscription_id, callback: _, } => f .debug_struct("Effect::WindowFullscreenObservation") - .field("window_id", window_id) + .field("window_id", &window.id()) .field("subscription_id", subscription_id) .finish(), Effect::WindowBoundsObservation { - window_id, + window, subscription_id, callback: _, } => f .debug_struct("Effect::WindowBoundsObservation") - .field("window_id", window_id) + .field("window_id", &window.id()) .field("subscription_id", subscription_id) .finish(), Effect::RefreshWindows => f.debug_struct("Effect::FullViewRefresh").finish(), - Effect::WindowShouldCloseSubscription { window_id, .. } => f + Effect::WindowShouldCloseSubscription { window, .. } => f .debug_struct("Effect::WindowShouldCloseSubscription") - .field("window_id", window_id) + .field("window_id", &window.id()) .finish(), Effect::Keystroke { - window_id, + window, keystroke, handled_by, result, } => f .debug_struct("Effect::Keystroke") - .field("window_id", window_id) + .field("window_id", &window.id()) .field("keystroke", keystroke) .field( "keystroke", @@ -2613,9 +2600,14 @@ pub trait AnyView { cx: &mut WindowContext, view_id: usize, ); - fn any_handle(&self, window_id: usize, view_id: usize, cx: &AppContext) -> AnyViewHandle { + fn any_handle( + &self, + window: AnyWindowHandle, + view_id: usize, + cx: &AppContext, + ) -> AnyViewHandle { AnyViewHandle::new( - window_id, + window, view_id, self.as_any().type_id(), cx.ref_counts.clone(), @@ -2653,7 +2645,7 @@ where fn render(&mut self, cx: &mut WindowContext, view_id: usize) -> Box { let mut view_context = ViewContext::mutable(cx, view_id); let element = V::render(self, &mut view_context); - let view = WeakViewHandle::new(cx.window_id, view_id); + let view = WeakViewHandle::new(cx.window_handle, view_id); Box::new(RootElement::new(element, view)) } @@ -2664,11 +2656,11 @@ where } else { let focused_type = cx .views_metadata - .get(&(cx.window_id, focused_id)) + .get(&(cx.window_handle.id(), focused_id)) .unwrap() .type_id; AnyViewHandle::new( - cx.window_id, + cx.window_handle, focused_id, focused_type, cx.ref_counts.clone(), @@ -2684,11 +2676,11 @@ where } else { let blurred_type = cx .views_metadata - .get(&(cx.window_id, blurred_id)) + .get(&(cx.window_handle.id(), blurred_id)) .unwrap() .type_id; AnyViewHandle::new( - cx.window_id, + cx.window_handle, blurred_id, blurred_type, cx.ref_counts.clone(), @@ -2995,18 +2987,22 @@ impl<'a, 'b, V: View> ViewContext<'a, 'b, V> { pub fn handle(&self) -> ViewHandle { ViewHandle::new( - self.window_id, + self.window_handle, self.view_id, &self.window_context.ref_counts, ) } pub fn weak_handle(&self) -> WeakViewHandle { - WeakViewHandle::new(self.window_id, self.view_id) + WeakViewHandle::new(self.window_handle, self.view_id) } pub fn window_id(&self) -> usize { - self.window_id + self.window_handle.id() + } + + pub fn window(&self) -> AnyWindowHandle { + self.window_handle } pub fn view_id(&self) -> usize { @@ -3054,11 +3050,11 @@ impl<'a, 'b, V: View> ViewContext<'a, 'b, V> { } pub fn focus_parent(&mut self) { - let window_id = self.window_id; + let window = self.window_handle; let view_id = self.view_id; self.pending_effects .push_back(Effect::Focus(FocusEffect::ViewParent { - window_id, + window, view_id, is_forced: false, })); @@ -3072,13 +3068,13 @@ impl<'a, 'b, V: View> ViewContext<'a, 'b, V> { where F: 'static + FnMut(&mut V, &mut ViewContext) -> bool, { - let window_id = self.window_id; + let window = self.window_handle; let view = self.weak_handle(); self.pending_effects .push_back(Effect::WindowShouldCloseSubscription { - window_id, + window, callback: Box::new(move |cx| { - cx.update_window(window_id, |cx| { + cx.update_window(window, |cx| { if let Some(view) = view.upgrade(cx) { view.update(cx, |view, cx| callback(view, cx)) } else { @@ -3117,11 +3113,11 @@ impl<'a, 'b, V: View> ViewContext<'a, 'b, V> { H: Handle, F: 'static + FnMut(&mut V, H, &mut ViewContext), { - let window_id = self.window_id; + let window = self.window_handle; let observer = self.weak_handle(); self.window_context .observe_internal(handle, move |observed, cx| { - cx.update_window(window_id, |cx| { + cx.update_window(window, |cx| { if let Some(observer) = observer.upgrade(cx) { observer.update(cx, |observer, cx| { callback(observer, observed, cx); @@ -3140,10 +3136,10 @@ impl<'a, 'b, V: View> ViewContext<'a, 'b, V> { G: Any, F: 'static + FnMut(&mut V, &mut ViewContext), { - let window_id = self.window_id; + let window = self.window_handle; let observer = self.weak_handle(); self.window_context.observe_global::(move |cx| { - cx.update_window(window_id, |cx| { + cx.update_window(window, |cx| { if let Some(observer) = observer.upgrade(cx) { observer.update(cx, |observer, cx| callback(observer, cx)); } @@ -3176,11 +3172,11 @@ impl<'a, 'b, V: View> ViewContext<'a, 'b, V> { H: Handle, F: 'static + FnMut(&mut V, &E, &mut ViewContext), { - let window_id = self.window_id; + let window = self.window_handle; let observer = self.weak_handle(); self.window_context .observe_release(handle, move |released, cx| { - cx.update_window(window_id, |cx| { + cx.update_window(window, |cx| { if let Some(observer) = observer.upgrade(cx) { observer.update(cx, |observer, cx| { callback(observer, released, cx); @@ -3194,10 +3190,10 @@ impl<'a, 'b, V: View> ViewContext<'a, 'b, V> { where F: 'static + FnMut(&mut V, TypeId, &mut ViewContext), { - let window_id = self.window_id; + let window = self.window_handle; let observer = self.weak_handle(); self.window_context.observe_actions(move |action_id, cx| { - cx.update_window(window_id, |cx| { + cx.update_window(window, |cx| { if let Some(observer) = observer.upgrade(cx) { observer.update(cx, |observer, cx| { callback(observer, action_id, cx); @@ -3289,10 +3285,10 @@ impl<'a, 'b, V: View> ViewContext<'a, 'b, V> { where F: 'static + FnMut(&mut V, &mut ViewContext), { - let window_id = self.window_id; + let window = self.window_handle; let observer = self.weak_handle(); self.window_context.observe_active_labeled_tasks(move |cx| { - cx.update_window(window_id, |cx| { + cx.update_window(window, |cx| { if let Some(observer) = observer.upgrade(cx) { observer.update(cx, |observer, cx| { callback(observer, cx); @@ -3316,9 +3312,9 @@ impl<'a, 'b, V: View> ViewContext<'a, 'b, V> { } pub fn notify(&mut self) { - let window_id = self.window_id; + let window = self.window_handle; let view_id = self.view_id; - self.window_context.notify_view(window_id, view_id); + self.window_context.notify_view(window, view_id); } pub fn defer(&mut self, callback: impl 'static + FnOnce(&mut V, &mut ViewContext)) { @@ -3331,10 +3327,10 @@ impl<'a, 'b, V: View> ViewContext<'a, 'b, V> { &mut self, callback: impl 'static + FnOnce(&mut V, &mut ViewContext), ) { - let window_id = self.window_id; + let window = self.window_handle; let handle = self.handle(); self.window_context.after_window_update(move |cx| { - cx.update_window(window_id, |cx| { + cx.update_window(window, |cx| { handle.update(cx, |view, cx| { callback(view, cx); }) @@ -3422,30 +3418,30 @@ impl BorrowAppContext for ViewContext<'_, '_, V> { impl BorrowWindowContext for ViewContext<'_, '_, V> { type Result = T; - fn read_window T>(&self, window_id: usize, f: F) -> T { - BorrowWindowContext::read_window(&*self.window_context, window_id, f) + fn read_window T>(&self, window: AnyWindowHandle, f: F) -> T { + BorrowWindowContext::read_window(&*self.window_context, window, f) } - fn read_window_optional(&self, window_id: usize, f: F) -> Option + fn read_window_optional(&self, window: AnyWindowHandle, f: F) -> Option where F: FnOnce(&WindowContext) -> Option, { - BorrowWindowContext::read_window_optional(&*self.window_context, window_id, f) + BorrowWindowContext::read_window_optional(&*self.window_context, window, f) } fn update_window T>( &mut self, - window_id: usize, + window: AnyWindowHandle, f: F, ) -> T { - BorrowWindowContext::update_window(&mut *self.window_context, window_id, f) + BorrowWindowContext::update_window(&mut *self.window_context, window, f) } - fn update_window_optional(&mut self, window_id: usize, f: F) -> Option + fn update_window_optional(&mut self, window: AnyWindowHandle, f: F) -> Option where F: FnOnce(&mut WindowContext) -> Option, { - BorrowWindowContext::update_window_optional(&mut *self.window_context, window_id, f) + BorrowWindowContext::update_window_optional(&mut *self.window_context, window, f) } } @@ -3483,11 +3479,11 @@ impl<'a, 'b, 'c, V: View> LayoutContext<'a, 'b, 'c, V> { ) -> Option> { self.notify_if_view_ancestors_change(view_id); - let window_id = self.window_id; + let window = self.window_handle; let mut contexts = Vec::new(); let mut handler_depth = None; for (i, view_id) in self.ancestors(view_id).enumerate() { - if let Some(view_metadata) = self.views_metadata.get(&(window_id, view_id)) { + if let Some(view_metadata) = self.views_metadata.get(&(window.id(), view_id)) { if let Some(actions) = self.actions.get(&view_metadata.type_id) { if actions.contains_key(&action.id()) { handler_depth = Some(i); @@ -3547,30 +3543,30 @@ impl BorrowAppContext for LayoutContext<'_, '_, '_, V> { impl BorrowWindowContext for LayoutContext<'_, '_, '_, V> { type Result = T; - fn read_window T>(&self, window_id: usize, f: F) -> T { - BorrowWindowContext::read_window(&*self.view_context, window_id, f) + fn read_window T>(&self, window: AnyWindowHandle, f: F) -> T { + BorrowWindowContext::read_window(&*self.view_context, window, f) } - fn read_window_optional(&self, window_id: usize, f: F) -> Option + fn read_window_optional(&self, window: AnyWindowHandle, f: F) -> Option where F: FnOnce(&WindowContext) -> Option, { - BorrowWindowContext::read_window_optional(&*self.view_context, window_id, f) + BorrowWindowContext::read_window_optional(&*self.view_context, window, f) } fn update_window T>( &mut self, - window_id: usize, + window: AnyWindowHandle, f: F, ) -> T { - BorrowWindowContext::update_window(&mut *self.view_context, window_id, f) + BorrowWindowContext::update_window(&mut *self.view_context, window, f) } - fn update_window_optional(&mut self, window_id: usize, f: F) -> Option + fn update_window_optional(&mut self, window: AnyWindowHandle, f: F) -> Option where F: FnOnce(&mut WindowContext) -> Option, { - BorrowWindowContext::update_window_optional(&mut *self.view_context, window_id, f) + BorrowWindowContext::update_window_optional(&mut *self.view_context, window, f) } } @@ -3619,30 +3615,30 @@ impl BorrowAppContext for EventContext<'_, '_, '_, V> { impl BorrowWindowContext for EventContext<'_, '_, '_, V> { type Result = T; - fn read_window T>(&self, window_id: usize, f: F) -> T { - BorrowWindowContext::read_window(&*self.view_context, window_id, f) + fn read_window T>(&self, window: AnyWindowHandle, f: F) -> T { + BorrowWindowContext::read_window(&*self.view_context, window, f) } - fn read_window_optional(&self, window_id: usize, f: F) -> Option + fn read_window_optional(&self, window: AnyWindowHandle, f: F) -> Option where F: FnOnce(&WindowContext) -> Option, { - BorrowWindowContext::read_window_optional(&*self.view_context, window_id, f) + BorrowWindowContext::read_window_optional(&*self.view_context, window, f) } fn update_window T>( &mut self, - window_id: usize, + window: AnyWindowHandle, f: F, ) -> T { - BorrowWindowContext::update_window(&mut *self.view_context, window_id, f) + BorrowWindowContext::update_window(&mut *self.view_context, window, f) } - fn update_window_optional(&mut self, window_id: usize, f: F) -> Option + fn update_window_optional(&mut self, window: AnyWindowHandle, f: F) -> Option where F: FnOnce(&mut WindowContext) -> Option, { - BorrowWindowContext::update_window_optional(&mut *self.view_context, window_id, f) + BorrowWindowContext::update_window_optional(&mut *self.view_context, window, f) } } @@ -3977,7 +3973,7 @@ impl WindowHandle { C: BorrowWindowContext, F: FnOnce(&mut V, &mut ViewContext) -> R, { - cx.update_window(self.id(), |cx| { + cx.update_window(self.any_handle, |cx| { cx.root_view() .clone() .downcast::() @@ -3991,7 +3987,7 @@ impl WindowHandle { C: BorrowWindowContext, F: FnOnce(&mut ViewContext) -> V, { - cx.update_window(self.id(), |cx| { + cx.update_window(self.any_handle, |cx| { let root_view = self.add_view(cx, |cx| build_root(cx)); cx.window.root_view = Some(root_view.clone().into_any()); cx.window.focused_view_id = Some(root_view.id()); @@ -4006,7 +4002,7 @@ impl Into for WindowHandle { } } -#[derive(Copy, Clone, Eq, PartialEq, Hash)] +#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] pub struct AnyWindowHandle { window_id: usize, root_view_type: TypeId, @@ -4029,7 +4025,7 @@ impl AnyWindowHandle { C: BorrowWindowContext, F: FnOnce(&WindowContext) -> R, { - cx.read_window(self.window_id, |cx| read(cx)) + cx.read_window(*self, |cx| read(cx)) } pub fn read_optional_with(&self, cx: &C, read: F) -> Option @@ -4037,7 +4033,7 @@ impl AnyWindowHandle { C: BorrowWindowContext, F: FnOnce(&WindowContext) -> Option, { - cx.read_window_optional(self.window_id, |cx| read(cx)) + cx.read_window_optional(*self, |cx| read(cx)) } pub fn update(&self, cx: &mut C, update: F) -> C::Result @@ -4045,7 +4041,7 @@ impl AnyWindowHandle { C: BorrowWindowContext, F: FnOnce(&mut WindowContext) -> R, { - cx.update_window(self.window_id, update) + cx.update_window(*self, update) } pub fn update_optional(&self, cx: &mut C, update: F) -> Option @@ -4053,7 +4049,7 @@ impl AnyWindowHandle { C: BorrowWindowContext, F: FnOnce(&mut WindowContext) -> Option, { - cx.update_window_optional(self.window_id, update) + cx.update_window_optional(*self, update) } pub fn add_view(&self, cx: &mut C, build_view: F) -> C::Result> @@ -4092,24 +4088,22 @@ impl AnyWindowHandle { pub fn simulate_activation(&self, cx: &mut TestAppContext) { self.update(cx, |cx| { let other_window_ids = cx - .windows - .keys() - .filter(|window_id| **window_id != self.window_id) - .copied() + .windows() + .filter(|window| *window != *self) .collect::>(); - for window_id in other_window_ids { - cx.window_changed_active_status(window_id, false) + for window in other_window_ids { + cx.window_changed_active_status(window, false) } - cx.window_changed_active_status(self.window_id, true) + cx.window_changed_active_status(*self, true) }); } #[cfg(any(test, feature = "test-support"))] pub fn simulate_deactivation(&self, cx: &mut TestAppContext) { self.update(cx, |cx| { - cx.window_changed_active_status(self.window_id, false); + cx.window_changed_active_status(*self, false); }) } } @@ -4129,20 +4123,15 @@ impl Deref for ViewHandle { } impl ViewHandle { - fn new(window_id: usize, view_id: usize, ref_counts: &Arc>) -> Self { + fn new(window: AnyWindowHandle, view_id: usize, ref_counts: &Arc>) -> Self { Self { - any_handle: AnyViewHandle::new( - window_id, - view_id, - TypeId::of::(), - ref_counts.clone(), - ), + any_handle: AnyViewHandle::new(window, view_id, TypeId::of::(), ref_counts.clone()), view_type: PhantomData, } } pub fn downgrade(&self) -> WeakViewHandle { - WeakViewHandle::new(self.window_id, self.view_id) + WeakViewHandle::new(self.window, self.view_id) } pub fn into_any(self) -> AnyViewHandle { @@ -4150,13 +4139,11 @@ impl ViewHandle { } pub fn window_id(&self) -> usize { - self.window_id + self.window.id() } - pub fn window(&self, cx: &C) -> C::Result { - cx.read_window(self.window_id, |cx| { - AnyWindowHandle::new(self.window_id, cx.window.root_view.type_id()) - }) + pub fn window(&self) -> AnyWindowHandle { + self.window } pub fn id(&self) -> usize { @@ -4172,7 +4159,7 @@ impl ViewHandle { C: BorrowWindowContext, F: FnOnce(&T, &ViewContext) -> S, { - cx.read_window(self.window_id, |cx| { + cx.read_window(self.window, |cx| { let cx = ViewContext::immutable(cx, self.view_id); read(cx.read_view(self), &cx) }) @@ -4185,7 +4172,7 @@ impl ViewHandle { { let mut update = Some(update); - cx.update_window(self.window_id, |cx| { + cx.update_window(self.window, |cx| { cx.update_view(self, &mut |view, cx| { let update = update.take().unwrap(); update(view, cx) @@ -4200,31 +4187,31 @@ impl ViewHandle { impl Clone for ViewHandle { fn clone(&self) -> Self { - ViewHandle::new(self.window_id, self.view_id, &self.ref_counts) + ViewHandle::new(self.window, self.view_id, &self.ref_counts) } } impl PartialEq for ViewHandle { fn eq(&self, other: &Self) -> bool { - self.window_id == other.window_id && self.view_id == other.view_id + self.window == other.window && self.view_id == other.view_id } } impl PartialEq for ViewHandle { fn eq(&self, other: &AnyViewHandle) -> bool { - self.window_id == other.window_id && self.view_id == other.view_id + self.window == other.window && self.view_id == other.view_id } } impl PartialEq> for ViewHandle { fn eq(&self, other: &WeakViewHandle) -> bool { - self.window_id == other.window_id && self.view_id == other.view_id + self.window == other.window && self.view_id == other.view_id } } impl PartialEq> for WeakViewHandle { fn eq(&self, other: &ViewHandle) -> bool { - self.window_id == other.window_id && self.view_id == other.view_id + self.window == other.window && self.view_id == other.view_id } } @@ -4232,7 +4219,7 @@ impl Eq for ViewHandle {} impl Hash for ViewHandle { fn hash(&self, state: &mut H) { - self.window_id.hash(state); + self.window.hash(state); self.view_id.hash(state); } } @@ -4240,7 +4227,7 @@ impl Hash for ViewHandle { impl Debug for ViewHandle { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct(&format!("ViewHandle<{}>", type_name::())) - .field("window_id", &self.window_id) + .field("window_id", &self.window) .field("view_id", &self.view_id) .finish() } @@ -4254,7 +4241,7 @@ impl Handle for ViewHandle { } fn location(&self) -> EntityLocation { - EntityLocation::View(self.window_id, self.view_id) + EntityLocation::View(self.window.id(), self.view_id) } fn downgrade(&self) -> Self::Weak { @@ -4270,7 +4257,7 @@ impl Handle for ViewHandle { } pub struct AnyViewHandle { - window_id: usize, + window: AnyWindowHandle, view_id: usize, view_type: TypeId, ref_counts: Arc>, @@ -4281,12 +4268,12 @@ pub struct AnyViewHandle { impl AnyViewHandle { fn new( - window_id: usize, + window: AnyWindowHandle, view_id: usize, view_type: TypeId, ref_counts: Arc>, ) -> Self { - ref_counts.lock().inc_view(window_id, view_id); + ref_counts.lock().inc_view(window.id(), view_id); #[cfg(any(test, feature = "test-support"))] let handle_id = ref_counts @@ -4296,7 +4283,7 @@ impl AnyViewHandle { .handle_created(None, view_id); Self { - window_id, + window, view_id, view_type, ref_counts, @@ -4305,8 +4292,12 @@ impl AnyViewHandle { } } + pub fn window(&self) -> AnyWindowHandle { + self.window + } + pub fn window_id(&self) -> usize { - self.window_id + self.window.id() } pub fn id(&self) -> usize { @@ -4338,7 +4329,7 @@ impl AnyViewHandle { pub fn downgrade(&self) -> AnyWeakViewHandle { AnyWeakViewHandle { - window_id: self.window_id, + window: self.window, view_id: self.view_id, view_type: self.view_type, } @@ -4350,7 +4341,7 @@ impl AnyViewHandle { pub fn debug_json<'a, 'b>(&self, cx: &'b WindowContext<'a>) -> serde_json::Value { cx.views - .get(&(self.window_id, self.view_id)) + .get(&(self.window.id(), self.view_id)) .map_or_else(|| serde_json::Value::Null, |view| view.debug_json(cx)) } } @@ -4358,7 +4349,7 @@ impl AnyViewHandle { impl Clone for AnyViewHandle { fn clone(&self) -> Self { Self::new( - self.window_id, + self.window, self.view_id, self.view_type, self.ref_counts.clone(), @@ -4368,13 +4359,13 @@ impl Clone for AnyViewHandle { impl PartialEq for AnyViewHandle { fn eq(&self, other: &Self) -> bool { - self.window_id == other.window_id && self.view_id == other.view_id + self.window == other.window && self.view_id == other.view_id } } impl PartialEq> for AnyViewHandle { fn eq(&self, other: &ViewHandle) -> bool { - self.window_id == other.window_id && self.view_id == other.view_id + self.window == other.window && self.view_id == other.view_id } } @@ -4382,7 +4373,7 @@ impl Drop for AnyViewHandle { fn drop(&mut self) { self.ref_counts .lock() - .dec_view(self.window_id, self.view_id); + .dec_view(self.window.id(), self.view_id); #[cfg(any(test, feature = "test-support"))] self.ref_counts .lock() @@ -4395,7 +4386,7 @@ impl Drop for AnyViewHandle { impl Debug for AnyViewHandle { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("AnyViewHandle") - .field("window_id", &self.window_id) + .field("window_id", &self.window.id()) .field("view_id", &self.view_id) .finish() } @@ -4531,10 +4522,10 @@ impl WeakHandle for WeakViewHandle { } impl WeakViewHandle { - fn new(window_id: usize, view_id: usize) -> Self { + fn new(window: AnyWindowHandle, view_id: usize) -> Self { Self { any_handle: AnyWeakViewHandle { - window_id, + window, view_id, view_type: TypeId::of::(), }, @@ -4546,8 +4537,12 @@ impl WeakViewHandle { self.view_id } + pub fn window(&self) -> AnyWindowHandle { + self.window + } + pub fn window_id(&self) -> usize { - self.window_id + self.window.id() } pub fn into_any(self) -> AnyWeakViewHandle { @@ -4567,7 +4562,7 @@ impl WeakViewHandle { let handle = cx .upgrade_view_handle(self) .ok_or_else(|| anyhow!("view {} was dropped", V::ui_name()))?; - cx.read_window(self.window_id, |cx| handle.read_with(cx, read)) + cx.read_window(self.window, |cx| handle.read_with(cx, read)) .ok_or_else(|| anyhow!("window was removed")) }) } @@ -4581,7 +4576,7 @@ impl WeakViewHandle { let handle = cx .upgrade_view_handle(self) .ok_or_else(|| anyhow!("view {} was dropped", V::ui_name()))?; - cx.update_window(self.window_id, |cx| handle.update(cx, update)) + cx.update_window(self.window, |cx| handle.update(cx, update)) .ok_or_else(|| anyhow!("window was removed")) }) } @@ -4606,7 +4601,7 @@ impl Clone for WeakViewHandle { impl PartialEq for WeakViewHandle { fn eq(&self, other: &Self) -> bool { - self.window_id == other.window_id && self.view_id == other.view_id + self.window == other.window && self.view_id == other.view_id } } @@ -4620,7 +4615,7 @@ impl Hash for WeakViewHandle { #[derive(Debug, Clone, Copy, Eq, PartialEq)] pub struct AnyWeakViewHandle { - window_id: usize, + window: AnyWindowHandle, view_id: usize, view_type: TypeId, } @@ -4652,7 +4647,7 @@ impl AnyWeakViewHandle { impl Hash for AnyWeakViewHandle { fn hash(&self, state: &mut H) { - self.window_id.hash(state); + self.window.hash(state); self.view_id.hash(state); self.view_type.hash(state); } @@ -6393,7 +6388,7 @@ mod tests { // Check that global actions do not have a binding, even if a binding does exist in another view assert_eq!( - &available_actions(window.id(), view_1.id(), cx), + &available_actions(window.into(), view_1.id(), cx), &[ ("test::Action1", vec![Keystroke::parse("a").unwrap()]), ("test::GlobalAction", vec![]) @@ -6402,7 +6397,7 @@ mod tests { // Check that view 1 actions and bindings are available even when called from view 2 assert_eq!( - &available_actions(window.id(), view_2.id(), cx), + &available_actions(window.into(), view_2.id(), cx), &[ ("test::Action1", vec![Keystroke::parse("a").unwrap()]), ("test::Action2", vec![Keystroke::parse("b").unwrap()]), @@ -6412,11 +6407,11 @@ mod tests { // Produces a list of actions and key bindings fn available_actions( - window_id: usize, + window: AnyWindowHandle, view_id: usize, cx: &TestAppContext, ) -> Vec<(&'static str, Vec)> { - cx.available_actions(window_id, view_id) + cx.available_actions(window.into(), view_id) .into_iter() .map(|(action_name, _, bindings)| { ( @@ -6465,7 +6460,7 @@ mod tests { ]); }); - let actions = cx.available_actions(window.id(), view.id()); + let actions = cx.available_actions(window.into(), view.id()); assert_eq!( actions[0].1.as_any().downcast_ref::(), Some(&ActionWithArg { arg: false }) diff --git a/crates/gpui/src/app/test_app_context.rs b/crates/gpui/src/app/test_app_context.rs index ff988607b094f8d3253b8baaad2e6332bee4ad84..b1729d89b8591176f1fa9aa27ccc93cebdc65e8d 100644 --- a/crates/gpui/src/app/test_app_context.rs +++ b/crates/gpui/src/app/test_app_context.rs @@ -72,8 +72,8 @@ impl TestAppContext { cx } - pub fn dispatch_action(&mut self, window_id: usize, action: A) { - self.update_window(window_id, |window| { + pub fn dispatch_action(&mut self, window: AnyWindowHandle, action: A) { + self.update_window(window, |window| { window.dispatch_action(window.focused_view_id(), &action); }) .expect("window not found"); @@ -81,10 +81,10 @@ impl TestAppContext { pub fn available_actions( &self, - window_id: usize, + window: AnyWindowHandle, view_id: usize, ) -> Vec<(&'static str, Box, SmallVec<[Binding; 1]>)> { - self.read_window(window_id, |cx| cx.available_actions(view_id)) + self.read_window(window, |cx| cx.available_actions(view_id)) .unwrap_or_default() } @@ -127,18 +127,18 @@ impl TestAppContext { pub fn read_window T>( &self, - window_id: usize, + window: AnyWindowHandle, callback: F, ) -> Option { - self.cx.borrow().read_window(window_id, callback) + self.cx.borrow().read_window(window, callback) } pub fn update_window T>( &mut self, - window_id: usize, + window: AnyWindowHandle, callback: F, ) -> Option { - self.cx.borrow_mut().update_window(window_id, callback) + self.cx.borrow_mut().update_window(window, callback) } pub fn add_model(&mut self, build_model: F) -> ModelHandle @@ -317,36 +317,36 @@ impl BorrowAppContext for TestAppContext { impl BorrowWindowContext for TestAppContext { type Result = T; - fn read_window T>(&self, window_id: usize, f: F) -> T { + fn read_window T>(&self, window: AnyWindowHandle, f: F) -> T { self.cx .borrow() - .read_window(window_id, f) + .read_window(window, f) .expect("window was closed") } - fn read_window_optional(&self, window_id: usize, f: F) -> Option + fn read_window_optional(&self, window: AnyWindowHandle, f: F) -> Option where F: FnOnce(&WindowContext) -> Option, { - BorrowWindowContext::read_window(self, window_id, f) + BorrowWindowContext::read_window(self, window, f) } fn update_window T>( &mut self, - window_id: usize, + window: AnyWindowHandle, f: F, ) -> T { self.cx .borrow_mut() - .update_window(window_id, f) + .update_window(window, f) .expect("window was closed") } - fn update_window_optional(&mut self, window_id: usize, f: F) -> Option + fn update_window_optional(&mut self, window: AnyWindowHandle, f: F) -> Option where F: FnOnce(&mut WindowContext) -> Option, { - BorrowWindowContext::update_window(self, window_id, f) + BorrowWindowContext::update_window(self, window, f) } } diff --git a/crates/gpui/src/app/window.rs b/crates/gpui/src/app/window.rs index 70d02c1fa1265b5449b127a6736c8a81573be1e1..44a3c5cfdc8ded2e004df2da56ee6ce510396871 100644 --- a/crates/gpui/src/app/window.rs +++ b/crates/gpui/src/app/window.rs @@ -13,9 +13,9 @@ use crate::{ }, text_layout::TextLayoutCache, util::post_inc, - Action, AnyView, AnyViewHandle, AppContext, BorrowAppContext, BorrowWindowContext, Effect, - Element, Entity, Handle, LayoutContext, MouseRegion, MouseRegionId, SceneBuilder, Subscription, - View, ViewContext, ViewHandle, WindowHandle, WindowInvalidation, + Action, AnyView, AnyViewHandle, AnyWindowHandle, AppContext, BorrowAppContext, + BorrowWindowContext, Effect, Element, Entity, Handle, LayoutContext, MouseRegion, + MouseRegionId, SceneBuilder, Subscription, View, ViewContext, ViewHandle, WindowInvalidation, }; use anyhow::{anyhow, bail, Result}; use collections::{HashMap, HashSet}; @@ -60,7 +60,7 @@ pub struct Window { impl Window { pub fn new( - window_id: usize, + handle: AnyWindowHandle, platform_window: Box, cx: &mut AppContext, build_view: F, @@ -92,7 +92,7 @@ impl Window { appearance, }; - let mut window_context = WindowContext::mutable(cx, &mut window, window_id); + let mut window_context = WindowContext::mutable(cx, &mut window, handle); let root_view = window_context.add_view(|cx| build_view(cx)); if let Some(invalidation) = window_context.window.invalidation.take() { window_context.invalidate(invalidation, appearance); @@ -113,7 +113,7 @@ impl Window { pub struct WindowContext<'a> { pub(crate) app_context: Reference<'a, AppContext>, pub(crate) window: Reference<'a, Window>, - pub(crate) window_id: usize, + pub(crate) window_handle: AnyWindowHandle, pub(crate) removed: bool, } @@ -144,15 +144,15 @@ impl BorrowAppContext for WindowContext<'_> { impl BorrowWindowContext for WindowContext<'_> { type Result = T; - fn read_window T>(&self, window_id: usize, f: F) -> T { - if self.window_id == window_id { + fn read_window T>(&self, handle: AnyWindowHandle, f: F) -> T { + if self.window_handle == handle { f(self) } else { panic!("read_with called with id of window that does not belong to this context") } } - fn read_window_optional(&self, window_id: usize, f: F) -> Option + fn read_window_optional(&self, window_id: AnyWindowHandle, f: F) -> Option where F: FnOnce(&WindowContext) -> Option, { @@ -161,21 +161,21 @@ impl BorrowWindowContext for WindowContext<'_> { fn update_window T>( &mut self, - window_id: usize, + handle: AnyWindowHandle, f: F, ) -> T { - if self.window_id == window_id { + if self.window_handle == handle { f(self) } else { panic!("update called with id of window that does not belong to this context") } } - fn update_window_optional(&mut self, window_id: usize, f: F) -> Option + fn update_window_optional(&mut self, handle: AnyWindowHandle, f: F) -> Option where F: FnOnce(&mut WindowContext) -> Option, { - BorrowWindowContext::update_window(self, window_id, f) + BorrowWindowContext::update_window(self, handle, f) } } @@ -183,21 +183,25 @@ impl<'a> WindowContext<'a> { pub fn mutable( app_context: &'a mut AppContext, window: &'a mut Window, - window_id: usize, + handle: AnyWindowHandle, ) -> Self { Self { app_context: Reference::Mutable(app_context), window: Reference::Mutable(window), - window_id, + window_handle: handle, removed: false, } } - pub fn immutable(app_context: &'a AppContext, window: &'a Window, window_id: usize) -> Self { + pub fn immutable( + app_context: &'a AppContext, + window: &'a Window, + handle: AnyWindowHandle, + ) -> Self { Self { app_context: Reference::Immutable(app_context), window: Reference::Immutable(window), - window_id, + window_handle: handle, removed: false, } } @@ -207,17 +211,11 @@ impl<'a> WindowContext<'a> { } pub fn window_id(&self) -> usize { - self.window_id + self.window_handle.id() } - pub fn window(&self) -> Option> { - self.window.root_view.as_ref().and_then(|root_view| { - if root_view.is::() { - Some(WindowHandle::new(self.window_id)) - } else { - None - } - }) + pub fn window(&self) -> AnyWindowHandle { + self.window_handle } pub fn app_context(&mut self) -> &mut AppContext { @@ -240,10 +238,10 @@ impl<'a> WindowContext<'a> { where F: FnOnce(&mut dyn AnyView, &mut Self) -> T, { - let window_id = self.window_id; - let mut view = self.views.remove(&(window_id, view_id))?; + let handle = self.window_handle; + let mut view = self.views.remove(&(handle.id(), view_id))?; let result = f(view.as_mut(), self); - self.views.insert((window_id, view_id), view); + self.views.insert((handle.id(), view_id), view); Some(result) } @@ -268,9 +266,9 @@ impl<'a> WindowContext<'a> { } pub fn defer(&mut self, callback: impl 'static + FnOnce(&mut WindowContext)) { - let window_id = self.window_id; + let handle = self.window_handle; self.app_context.defer(move |cx| { - cx.update_window(window_id, |cx| callback(cx)); + cx.update_window(handle, |cx| callback(cx)); }) } @@ -310,10 +308,10 @@ impl<'a> WindowContext<'a> { H: Handle, F: 'static + FnMut(H, &E::Event, &mut WindowContext) -> bool, { - let window_id = self.window_id; + let window_handle = self.window_handle; self.app_context .subscribe_internal(handle, move |emitter, event, cx| { - cx.update_window(window_id, |cx| callback(emitter, event, cx)) + cx.update_window(window_handle, |cx| callback(emitter, event, cx)) .unwrap_or(false) }) } @@ -322,17 +320,17 @@ impl<'a> WindowContext<'a> { where F: 'static + FnMut(bool, &mut WindowContext) -> bool, { - let window_id = self.window_id; + let handle = self.window_handle; let subscription_id = post_inc(&mut self.next_subscription_id); self.pending_effects .push_back(Effect::WindowActivationObservation { - window_id, + window: handle, subscription_id, callback: Box::new(callback), }); Subscription::WindowActivationObservation( self.window_activation_observations - .subscribe(window_id, subscription_id), + .subscribe(handle.id(), subscription_id), ) } @@ -340,17 +338,17 @@ impl<'a> WindowContext<'a> { where F: 'static + FnMut(bool, &mut WindowContext) -> bool, { - let window_id = self.window_id; + let window = self.window_handle; let subscription_id = post_inc(&mut self.next_subscription_id); self.pending_effects .push_back(Effect::WindowFullscreenObservation { - window_id, + window, subscription_id, callback: Box::new(callback), }); Subscription::WindowActivationObservation( self.window_activation_observations - .subscribe(window_id, subscription_id), + .subscribe(window.id(), subscription_id), ) } @@ -358,17 +356,17 @@ impl<'a> WindowContext<'a> { where F: 'static + FnMut(WindowBounds, Uuid, &mut WindowContext) -> bool, { - let window_id = self.window_id; + let window = self.window_handle; let subscription_id = post_inc(&mut self.next_subscription_id); self.pending_effects .push_back(Effect::WindowBoundsObservation { - window_id, + window, subscription_id, callback: Box::new(callback), }); Subscription::WindowBoundsObservation( self.window_bounds_observations - .subscribe(window_id, subscription_id), + .subscribe(window.id(), subscription_id), ) } @@ -377,13 +375,13 @@ impl<'a> WindowContext<'a> { F: 'static + FnMut(&Keystroke, &MatchResult, Option<&Box>, &mut WindowContext) -> bool, { - let window_id = self.window_id; + let window = self.window_handle; let subscription_id = post_inc(&mut self.next_subscription_id); self.keystroke_observations - .add_callback(window_id, subscription_id, Box::new(callback)); + .add_callback(window.id(), subscription_id, Box::new(callback)); Subscription::KeystrokeObservation( self.keystroke_observations - .subscribe(window_id, subscription_id), + .subscribe(window.id(), subscription_id), ) } @@ -391,11 +389,11 @@ impl<'a> WindowContext<'a> { &self, view_id: usize, ) -> Vec<(&'static str, Box, SmallVec<[Binding; 1]>)> { - let window_id = self.window_id; + let handle = self.window_handle; let mut contexts = Vec::new(); let mut handler_depths_by_action_id = HashMap::::default(); for (depth, view_id) in self.ancestors(view_id).enumerate() { - if let Some(view_metadata) = self.views_metadata.get(&(window_id, view_id)) { + if let Some(view_metadata) = self.views_metadata.get(&(handle.id(), view_id)) { contexts.push(view_metadata.keymap_context.clone()); if let Some(actions) = self.actions.get(&view_metadata.type_id) { handler_depths_by_action_id @@ -440,13 +438,13 @@ impl<'a> WindowContext<'a> { } pub(crate) fn dispatch_keystroke(&mut self, keystroke: &Keystroke) -> bool { - let window_id = self.window_id; + let handle = self.window_handle; if let Some(focused_view_id) = self.focused_view_id() { let dispatch_path = self .ancestors(focused_view_id) .filter_map(|view_id| { self.views_metadata - .get(&(window_id, view_id)) + .get(&(handle.id(), view_id)) .map(|view| (view_id, view.keymap_context.clone())) }) .collect(); @@ -471,15 +469,10 @@ impl<'a> WindowContext<'a> { } }; - self.keystroke( - window_id, - keystroke.clone(), - handled_by, - match_result.clone(), - ); + self.keystroke(handle, keystroke.clone(), handled_by, match_result.clone()); keystroke_handled } else { - self.keystroke(window_id, keystroke.clone(), None, MatchResult::None); + self.keystroke(handle, keystroke.clone(), None, MatchResult::None); false } } @@ -487,7 +480,7 @@ impl<'a> WindowContext<'a> { pub(crate) fn dispatch_event(&mut self, event: Event, event_reused: bool) -> bool { let mut mouse_events = SmallVec::<[_; 2]>::new(); let mut notified_views: HashSet = Default::default(); - let window_id = self.window_id; + let handle = self.window_handle; // 1. Handle platform event. Keyboard events get dispatched immediately, while mouse events // get mapped into the mouse-specific MouseEvent type. @@ -851,19 +844,19 @@ impl<'a> WindowContext<'a> { } for view_id in notified_views { - self.notify_view(window_id, view_id); + self.notify_view(handle, view_id); } any_event_handled } pub(crate) fn dispatch_key_down(&mut self, event: &KeyDownEvent) -> bool { - let window_id = self.window_id; + let handle = self.window_handle; if let Some(focused_view_id) = self.window.focused_view_id { for view_id in self.ancestors(focused_view_id).collect::>() { - if let Some(mut view) = self.views.remove(&(window_id, view_id)) { + if let Some(mut view) = self.views.remove(&(handle.id(), view_id)) { let handled = view.key_down(event, self, view_id); - self.views.insert((window_id, view_id), view); + self.views.insert((handle.id(), view_id), view); if handled { return true; } @@ -877,12 +870,12 @@ impl<'a> WindowContext<'a> { } pub(crate) fn dispatch_key_up(&mut self, event: &KeyUpEvent) -> bool { - let window_id = self.window_id; + let handle = self.window_handle; if let Some(focused_view_id) = self.window.focused_view_id { for view_id in self.ancestors(focused_view_id).collect::>() { - if let Some(mut view) = self.views.remove(&(window_id, view_id)) { + if let Some(mut view) = self.views.remove(&(handle.id(), view_id)) { let handled = view.key_up(event, self, view_id); - self.views.insert((window_id, view_id), view); + self.views.insert((handle.id(), view_id), view); if handled { return true; } @@ -896,12 +889,12 @@ impl<'a> WindowContext<'a> { } pub(crate) fn dispatch_modifiers_changed(&mut self, event: &ModifiersChangedEvent) -> bool { - let window_id = self.window_id; + let handle = self.window_handle; if let Some(focused_view_id) = self.window.focused_view_id { for view_id in self.ancestors(focused_view_id).collect::>() { - if let Some(mut view) = self.views.remove(&(window_id, view_id)) { + if let Some(mut view) = self.views.remove(&(handle.id(), view_id)) { let handled = view.modifiers_changed(event, self, view_id); - self.views.insert((window_id, view_id), view); + self.views.insert((handle.id(), view_id), view); if handled { return true; } @@ -936,14 +929,14 @@ impl<'a> WindowContext<'a> { } pub fn render_view(&mut self, params: RenderParams) -> Result> { - let window_id = self.window_id; + let handle = self.window_handle; let view_id = params.view_id; let mut view = self .views - .remove(&(window_id, view_id)) + .remove(&(handle.id(), view_id)) .ok_or_else(|| anyhow!("view not found"))?; let element = view.render(self, view_id); - self.views.insert((window_id, view_id), view); + self.views.insert((handle.id(), view_id), view); Ok(element) } @@ -971,9 +964,9 @@ impl<'a> WindowContext<'a> { } else if old_parent_id == new_parent_id { current_view_id = *old_parent_id.unwrap(); } else { - let window_id = self.window_id; + let handle = self.window_handle; for view_id_to_notify in view_ids_to_notify { - self.notify_view(window_id, view_id_to_notify); + self.notify_view(handle, view_id_to_notify); } break; } @@ -1141,7 +1134,7 @@ impl<'a> WindowContext<'a> { } pub fn focus(&mut self, view_id: Option) { - self.app_context.focus(self.window_id, view_id); + self.app_context.focus(self.window_handle, view_id); } pub fn window_bounds(&self) -> WindowBounds { @@ -1194,26 +1187,26 @@ impl<'a> WindowContext<'a> { T: View, F: FnOnce(&mut ViewContext) -> Option, { - let window_id = self.window_id; + let handle = self.window_handle; let view_id = post_inc(&mut self.next_id); let mut cx = ViewContext::mutable(self, view_id); let handle = if let Some(view) = build_view(&mut cx) { let mut keymap_context = KeymapContext::default(); view.update_keymap_context(&mut keymap_context, cx.app_context()); self.views_metadata.insert( - (window_id, view_id), + (handle.id(), view_id), ViewMetadata { type_id: TypeId::of::(), keymap_context, }, ); - self.views.insert((window_id, view_id), Box::new(view)); + self.views.insert((handle.id(), view_id), Box::new(view)); self.window .invalidation .get_or_insert_with(Default::default) .updated .insert(view_id); - Some(ViewHandle::new(window_id, view_id, &self.ref_counts)) + Some(ViewHandle::new(handle, view_id, &self.ref_counts)) } else { None }; @@ -1390,7 +1383,7 @@ pub struct ChildView { impl ChildView { pub fn new(view: &AnyViewHandle, cx: &AppContext) -> Self { - let view_name = cx.view_ui_name(view.window_id(), view.id()).unwrap(); + let view_name = cx.view_ui_name(view.window, view.id()).unwrap(); Self { view_id: view.id(), view_name, diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index 07aaea812a98d5758bb15b801c5cd8bdf1688e8f..df4334a19fc7daf862504c6ef7ccfc6f3f9e3da0 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -1726,7 +1726,7 @@ impl ClipboardEntry { #[cfg(test)] mod tests { use super::*; - use gpui::{AnyWindowHandle, TestAppContext, ViewHandle}; + use gpui::{AnyWindowHandle, TestAppContext, ViewHandle, WindowHandle}; use pretty_assertions::assert_eq; use project::FakeFs; use serde_json::json; @@ -1872,7 +1872,6 @@ mod tests { let project = Project::test(fs.clone(), ["/root1".as_ref(), "/root2".as_ref()], cx).await; let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx)); let workspace = window.root(cx); - let window_id = window.id(); let panel = workspace.update(cx, |workspace, cx| ProjectPanel::new(workspace, cx)); select_path(&panel, "root1", cx); @@ -1894,7 +1893,7 @@ mod tests { // Add a file with the root folder selected. The filename editor is placed // before the first file in the root folder. panel.update(cx, |panel, cx| panel.new_file(&NewFile, cx)); - cx.read_window(window_id, |cx| { + window.read_with(cx, |cx| { let panel = panel.read(cx); assert!(panel.filename_editor.is_focused(cx)); }); @@ -2225,7 +2224,6 @@ mod tests { let project = Project::test(fs.clone(), ["/root1".as_ref(), "/root2".as_ref()], cx).await; let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx)); let workspace = window.root(cx); - let window_id = window.id(); let panel = workspace.update(cx, |workspace, cx| ProjectPanel::new(workspace, cx)); select_path(&panel, "root1", cx); @@ -2247,7 +2245,7 @@ mod tests { // Add a file with the root folder selected. The filename editor is placed // before the first file in the root folder. panel.update(cx, |panel, cx| panel.new_file(&NewFile, cx)); - cx.read_window(window_id, |cx| { + window.read_with(cx, |cx| { let panel = panel.read(cx); assert!(panel.filename_editor.is_focused(cx)); }); @@ -2402,7 +2400,6 @@ mod tests { let project = Project::test(fs.clone(), ["/src".as_ref()], cx).await; let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx)); let workspace = window.root(cx); - let window_id = window.id(); let panel = workspace.update(cx, |workspace, cx| ProjectPanel::new(workspace, cx)); toggle_expand_dir(&panel, "src/test", cx); @@ -2419,7 +2416,7 @@ mod tests { " third.rs" ] ); - ensure_single_file_is_opened(window_id, &workspace, "test/first.rs", cx); + ensure_single_file_is_opened(window, "test/first.rs", cx); submit_deletion(window.into(), &panel, cx); assert_eq!( @@ -2446,9 +2443,9 @@ mod tests { " third.rs" ] ); - ensure_single_file_is_opened(window_id, &workspace, "test/second.rs", cx); + ensure_single_file_is_opened(window, "test/second.rs", cx); - cx.update_window(window_id, |cx| { + window.update(cx, |cx| { let active_items = workspace .read(cx) .panes() @@ -2493,7 +2490,6 @@ mod tests { let project = Project::test(fs.clone(), ["/src".as_ref()], cx).await; let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx)); let workspace = window.root(cx); - let window_id = window.id(); let panel = workspace.update(cx, |workspace, cx| ProjectPanel::new(workspace, cx)); select_path(&panel, "src/", cx); @@ -2504,7 +2500,7 @@ mod tests { &["v src <== selected", " > test"] ); panel.update(cx, |panel, cx| panel.new_directory(&NewDirectory, cx)); - cx.read_window(window_id, |cx| { + window.read_with(cx, |cx| { let panel = panel.read(cx); assert!(panel.filename_editor.is_focused(cx)); }); @@ -2535,7 +2531,7 @@ mod tests { &["v src", " > test <== selected"] ); panel.update(cx, |panel, cx| panel.new_file(&NewFile, cx)); - cx.read_window(window_id, |cx| { + window.read_with(cx, |cx| { let panel = panel.read(cx); assert!(panel.filename_editor.is_focused(cx)); }); @@ -2585,7 +2581,7 @@ mod tests { ], ); panel.update(cx, |panel, cx| panel.rename(&Rename, cx)); - cx.read_window(window_id, |cx| { + window.read_with(cx, |cx| { let panel = panel.read(cx); assert!(panel.filename_editor.is_focused(cx)); }); @@ -2882,13 +2878,11 @@ mod tests { } fn ensure_single_file_is_opened( - window_id: usize, - workspace: &ViewHandle, + window: WindowHandle, expected_path: &str, cx: &mut TestAppContext, ) { - cx.read_window(window_id, |cx| { - let workspace = workspace.read(cx); + window.update_root(cx, |workspace, cx| { let worktrees = workspace.worktrees(cx).collect::>(); assert_eq!(worktrees.len(), 1); let worktree_id = WorktreeId::from_usize(worktrees[0].id()); diff --git a/crates/search/src/buffer_search.rs b/crates/search/src/buffer_search.rs index b20ffed6d7e1ad94e9c311503c332e066e5c9b91..c3b4f5caa668c7a74ef446744cfc4aaa04ee6df7 100644 --- a/crates/search/src/buffer_search.rs +++ b/crates/search/src/buffer_search.rs @@ -1229,8 +1229,6 @@ mod tests { ); let buffer = cx.add_model(|cx| Buffer::new(0, buffer_text, cx)); let window = cx.add_window(|_| EmptyView); - let window_id = window.id(); - let editor = window.add_view(cx, |cx| Editor::for_buffer(buffer.clone(), None, cx)); let search_bar = window.add_view(cx, |cx| { @@ -1249,12 +1247,13 @@ mod tests { search_bar.activate_current_match(cx); }); - cx.read_window(window_id, |cx| { + window.read_with(cx, |cx| { assert!( !editor.is_focused(cx), "Initially, the editor should not be focused" ); }); + let initial_selections = editor.update(cx, |editor, cx| { let initial_selections = editor.selections.display_ranges(cx); assert_eq!( @@ -1271,7 +1270,7 @@ mod tests { cx.focus(search_bar.query_editor.as_any()); search_bar.select_all_matches(&SelectAllMatches, cx); }); - cx.read_window(window_id, |cx| { + window.read_with(cx, |cx| { assert!( editor.is_focused(cx), "Should focus editor after successful SelectAllMatches" @@ -1295,7 +1294,7 @@ mod tests { search_bar.update(cx, |search_bar, cx| { search_bar.select_next_match(&SelectNextMatch, cx); }); - cx.read_window(window_id, |cx| { + window.read_with(cx, |cx| { assert!( editor.is_focused(cx), "Should still have editor focused after SelectNextMatch" @@ -1324,7 +1323,7 @@ mod tests { cx.focus(search_bar.query_editor.as_any()); search_bar.select_all_matches(&SelectAllMatches, cx); }); - cx.read_window(window_id, |cx| { + window.read_with(cx, |cx| { assert!( editor.is_focused(cx), "Should focus editor after successful SelectAllMatches" @@ -1348,7 +1347,7 @@ mod tests { search_bar.update(cx, |search_bar, cx| { search_bar.select_prev_match(&SelectPrevMatch, cx); }); - cx.read_window(window_id, |cx| { + window.read_with(cx, |cx| { assert!( editor.is_focused(cx), "Should still have editor focused after SelectPrevMatch" @@ -1384,7 +1383,7 @@ mod tests { search_bar.update(cx, |search_bar, cx| { search_bar.select_all_matches(&SelectAllMatches, cx); }); - cx.read_window(window_id, |cx| { + window.read_with(cx, |cx| { assert!( !editor.is_focused(cx), "Should not switch focus to editor if SelectAllMatches does not find any matches" diff --git a/crates/search/src/project_search.rs b/crates/search/src/project_search.rs index dffd88db14229871a805a282ccbc49670697206e..202d494560e7388b689a4b9f8750b07c62758697 100644 --- a/crates/search/src/project_search.rs +++ b/crates/search/src/project_search.rs @@ -1568,7 +1568,6 @@ pub mod tests { let project = Project::test(fs.clone(), ["/dir".as_ref()], cx).await; let window = cx.add_window(|cx| Workspace::test_new(project, cx)); let workspace = window.root(cx); - let window_id = window.id(); let active_item = cx.read(|cx| { workspace @@ -1599,9 +1598,9 @@ pub mod tests { }; let search_view_id = search_view.id(); - cx.spawn( - |mut cx| async move { cx.dispatch_action(window_id, search_view_id, &ToggleFocus) }, - ) + cx.spawn(|mut cx| async move { + cx.dispatch_action(window.into(), search_view_id, &ToggleFocus) + }) .detach(); deterministic.run_until_parked(); search_view.update(cx, |search_view, cx| { @@ -1651,9 +1650,9 @@ pub mod tests { "Search view should be focused after mismatching query had been used in search", ); }); - cx.spawn( - |mut cx| async move { cx.dispatch_action(window_id, search_view_id, &ToggleFocus) }, - ) + cx.spawn(|mut cx| async move { + cx.dispatch_action(window.into(), search_view_id, &ToggleFocus) + }) .detach(); deterministic.run_until_parked(); search_view.update(cx, |search_view, cx| { @@ -1683,9 +1682,9 @@ pub mod tests { "Search view with mismatching query should be focused after search results are available", ); }); - cx.spawn( - |mut cx| async move { cx.dispatch_action(window_id, search_view_id, &ToggleFocus) }, - ) + cx.spawn(|mut cx| async move { + cx.dispatch_action(window.into(), search_view_id, &ToggleFocus) + }) .detach(); deterministic.run_until_parked(); search_view.update(cx, |search_view, cx| { @@ -1713,9 +1712,9 @@ pub mod tests { ); }); - cx.spawn( - |mut cx| async move { cx.dispatch_action(window_id, search_view_id, &ToggleFocus) }, - ) + cx.spawn(|mut cx| async move { + cx.dispatch_action(window.into(), search_view_id, &ToggleFocus) + }) .detach(); deterministic.run_until_parked(); search_view.update(cx, |search_view, cx| { diff --git a/crates/vim/src/editor_events.rs b/crates/vim/src/editor_events.rs index 4fef6bd715eedbe49b1347b679a2ebe6d3a89f33..893f5e8a854aed40abc9ced5cb9219a57c8e1d53 100644 --- a/crates/vim/src/editor_events.rs +++ b/crates/vim/src/editor_events.rs @@ -1,6 +1,6 @@ use crate::Vim; use editor::{EditorBlurred, EditorFocused, EditorReleased}; -use gpui::{AppContext, BorrowWindowContext}; +use gpui::AppContext; pub fn init(cx: &mut AppContext) { cx.subscribe_global(focused).detach(); @@ -10,7 +10,7 @@ pub fn init(cx: &mut AppContext) { fn focused(EditorFocused(editor): &EditorFocused, cx: &mut AppContext) { if let Some(previously_active_editor) = Vim::read(cx).active_editor.clone() { - cx.update_window(previously_active_editor.window_id(), |cx| { + previously_active_editor.window().update(cx, |cx| { Vim::update(cx, |vim, cx| { vim.update_active_editor(cx, |previously_active_editor, cx| { vim.unhook_vim_settings(previously_active_editor, cx) @@ -19,7 +19,7 @@ fn focused(EditorFocused(editor): &EditorFocused, cx: &mut AppContext) { }); } - cx.update_window(editor.window_id(), |cx| { + editor.window().update(cx, |cx| { Vim::update(cx, |vim, cx| { vim.set_active_editor(editor.clone(), cx); }); @@ -27,7 +27,7 @@ fn focused(EditorFocused(editor): &EditorFocused, cx: &mut AppContext) { } fn blurred(EditorBlurred(editor): &EditorBlurred, cx: &mut AppContext) { - cx.update_window(editor.window_id(), |cx| { + editor.window().update(cx, |cx| { Vim::update(cx, |vim, cx| { if let Some(previous_editor) = vim.active_editor.clone() { if previous_editor == editor.clone() { @@ -41,7 +41,7 @@ fn blurred(EditorBlurred(editor): &EditorBlurred, cx: &mut AppContext) { } fn released(EditorReleased(editor): &EditorReleased, cx: &mut AppContext) { - cx.update_window(editor.window_id(), |cx| { + editor.window().update(cx, |cx| { cx.update_default_global(|vim: &mut Vim, _| { if let Some(previous_editor) = vim.active_editor.clone() { if previous_editor == editor.clone() { diff --git a/crates/vim/src/mode_indicator.rs b/crates/vim/src/mode_indicator.rs index afd60af848be052060988ba961bb75e811f33d3b..5d54a66723da31ab271c55510820a87a48e207cd 100644 --- a/crates/vim/src/mode_indicator.rs +++ b/crates/vim/src/mode_indicator.rs @@ -1,6 +1,6 @@ use gpui::{ elements::{Empty, Label}, - AnyElement, Element, Entity, Subscription, View, ViewContext, BorrowWindowContext + AnyElement, Element, Entity, Subscription, View, ViewContext, }; use settings::SettingsStore; use workspace::{item::ItemHandle, StatusItemView}; @@ -20,7 +20,7 @@ impl ModeIndicator { if let Some(mode_indicator) = handle.upgrade(cx) { match event { VimEvent::ModeChanged { mode } => { - cx.update_window(mode_indicator.window_id(), |cx| { + mode_indicator.window().update(cx, |cx| { mode_indicator.update(cx, move |mode_indicator, cx| { mode_indicator.set_mode(mode, cx); }) diff --git a/crates/vim/src/test/vim_test_context.rs b/crates/vim/src/test/vim_test_context.rs index 839ab3aafc87e535a8b09096be6b58a5837063da..5eaaef900e4719e0f17ff7aebd62cb0377cd1980 100644 --- a/crates/vim/src/test/vim_test_context.rs +++ b/crates/vim/src/test/vim_test_context.rs @@ -85,8 +85,8 @@ impl<'a> VimTestContext<'a> { } pub fn set_state(&mut self, text: &str, mode: Mode) -> ContextHandle { - let window_id = self.window.id(); - self.update_window(window_id, |cx| { + let window = self.window; + window.update(self.cx.cx.cx, |cx| { Vim::update(cx, |vim, cx| { vim.switch_mode(mode, false, cx); }) diff --git a/crates/workspace/src/dock.rs b/crates/workspace/src/dock.rs index ebaf399e22b3ecfa51b217327f5912a34dc7b542..5bb0fd93f8c9290c6f71f0ff94972115c9e3629c 100644 --- a/crates/workspace/src/dock.rs +++ b/crates/workspace/src/dock.rs @@ -203,7 +203,7 @@ impl Dock { pub fn panel_index_for_ui_name(&self, ui_name: &str, cx: &AppContext) -> Option { self.panel_entries.iter().position(|entry| { let panel = entry.panel.as_any(); - cx.view_ui_name(panel.window_id(), panel.id()) == Some(ui_name) + cx.view_ui_name(panel.window(), panel.id()) == Some(ui_name) }) } @@ -530,16 +530,12 @@ impl View for PanelButtons { tooltip_action.as_ref().map(|action| action.boxed_clone()); move |_, this, cx| { if let Some(tooltip_action) = &tooltip_action { - let window_id = cx.window_id(); + let window = cx.window(); let view_id = this.workspace.id(); let tooltip_action = tooltip_action.boxed_clone(); cx.spawn(|_, mut cx| async move { - cx.dispatch_action( - window_id, - view_id, - &*tooltip_action, - ) - .ok(); + cx.dispatch_action(window, view_id, &*tooltip_action) + .ok(); }) .detach(); } diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index 98883fac3372246d462585be76eb0bfd1a20bbae..ecbe25accad0ee5f1e52c785ddd80c588bb911df 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -1917,8 +1917,8 @@ impl Element for PaneBackdrop { MouseRegion::new::(child_view_id, 0, visible_bounds).on_down( gpui::platform::MouseButton::Left, move |_, _: &mut V, cx| { - let window_id = cx.window_id(); - cx.app_context().focus(window_id, Some(child_view_id)) + let window = cx.window(); + cx.app_context().focus(window, Some(child_view_id)) }, ), ); diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index da708c6ea727de82b1c288a9549e6d627fad07b3..f0990322653757344d459e2bc2ef1f8c569cbdcf 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -1250,11 +1250,11 @@ impl Workspace { _: &CloseWindow, cx: &mut ViewContext, ) -> Option>> { - let window_id = cx.window_id(); + let window = cx.window(); let prepare = self.prepare_to_close(false, cx); Some(cx.spawn(|_, mut cx| async move { if prepare.await? { - cx.remove_window(window_id); + cx.remove_window(window); } Ok(()) })) @@ -1266,7 +1266,7 @@ impl Workspace { cx: &mut ViewContext, ) -> Task> { let active_call = self.active_call().cloned(); - let window_id = cx.window_id(); + let window = cx.window(); cx.spawn(|this, mut cx| async move { let workspace_count = cx @@ -1281,7 +1281,7 @@ impl Workspace { && active_call.read_with(&cx, |call, _| call.room().is_some()) { let answer = cx.prompt( - window_id, + window, PromptLevel::Warning, "Do you want to leave the current call?", &["Close window and hang up", "Cancel"], @@ -1390,7 +1390,7 @@ impl Workspace { paths: Vec, cx: &mut ViewContext, ) -> Task> { - let window = cx.window::(); + let window = cx.window().downcast::(); let is_remote = self.project.read(cx).is_remote(); let has_worktree = self.project.read(cx).worktrees(cx).next().is_some(); let has_dirty_items = self.items(cx).any(|item| item.is_dirty(cx)); @@ -3181,7 +3181,7 @@ impl Workspace { let left_visible = left_dock.is_open(); let left_active_panel = left_dock.visible_panel().and_then(|panel| { Some( - cx.view_ui_name(panel.as_any().window_id(), panel.id())? + cx.view_ui_name(panel.as_any().window(), panel.id())? .to_string(), ) }); @@ -3194,7 +3194,7 @@ impl Workspace { let right_visible = right_dock.is_open(); let right_active_panel = right_dock.visible_panel().and_then(|panel| { Some( - cx.view_ui_name(panel.as_any().window_id(), panel.id())? + cx.view_ui_name(panel.as_any().window(), panel.id())? .to_string(), ) }); @@ -3207,7 +3207,7 @@ impl Workspace { let bottom_visible = bottom_dock.is_open(); let bottom_active_panel = bottom_dock.visible_panel().and_then(|panel| { Some( - cx.view_ui_name(panel.as_any().window_id(), panel.id())? + cx.view_ui_name(panel.as_any().window(), panel.id())? .to_string(), ) }); @@ -4000,7 +4000,7 @@ pub fn join_remote_project( workspace.downgrade() }; - cx.activate_window(workspace.window_id()); + cx.activate_window(workspace.window()); cx.platform().activate(true); workspace.update(&mut cx, |workspace, cx| { @@ -4049,9 +4049,9 @@ pub fn restart(_: &Restart, cx: &mut AppContext) { // prompt in the active window before switching to a different window. workspace_windows.sort_by_key(|window| window.is_active(&cx) == Some(false)); - if let (true, Some(window)) = (should_confirm, workspace_windows.first()) { + if let (true, Some(window)) = (should_confirm, workspace_windows.first().copied()) { let answer = cx.prompt( - window.id(), + window.into(), PromptLevel::Info, "Are you sure you want to restart?", &["Restart", "Cancel"], diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 3435727b1e0345ab1eef4cb63870b6b71f03c7f9..6397a1e6b2a818525b9e29879f0bd012dbc35e22 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -179,13 +179,12 @@ pub fn init(app_state: &Arc, cx: &mut gpui::AppContext) { move |workspace: &mut Workspace, _: &DebugElements, cx: &mut ViewContext| { let app_state = workspace.app_state().clone(); let markdown = app_state.languages.language_for_name("JSON"); - let window_id = cx.window_id(); + let window = cx.window(); cx.spawn(|workspace, mut cx| async move { let markdown = markdown.await.log_err(); - let content = to_string_pretty( - &cx.debug_elements(window_id) - .ok_or_else(|| anyhow!("could not debug elements for {window_id}"))?, - ) + let content = to_string_pretty(&cx.debug_elements(window).ok_or_else(|| { + anyhow!("could not debug elements for window {}", window.id()) + })?) .unwrap(); workspace .update(&mut cx, |workspace, cx| { @@ -416,9 +415,9 @@ fn quit(_: &Quit, cx: &mut gpui::AppContext) { // prompt in the active window before switching to a different window. workspace_windows.sort_by_key(|window| window.is_active(&cx) == Some(false)); - if let (true, Some(window)) = (should_confirm, workspace_windows.first()) { + if let (true, Some(window)) = (should_confirm, workspace_windows.first().copied()) { let answer = cx.prompt( - window.id(), + window.into(), PromptLevel::Info, "Are you sure you want to quit?", &["Quit", "Cancel"], @@ -716,8 +715,8 @@ mod tests { use editor::{scroll::autoscroll::Autoscroll, DisplayPoint, Editor}; use fs::{FakeFs, Fs}; use gpui::{ - actions, elements::Empty, executor::Deterministic, Action, AnyElement, AppContext, - AssetSource, Element, Entity, TestAppContext, View, ViewHandle, + actions, elements::Empty, executor::Deterministic, Action, AnyElement, AnyWindowHandle, + AppContext, AssetSource, Element, Entity, TestAppContext, View, ViewHandle, }; use language::LanguageRegistry; use node_runtime::NodeRuntime; @@ -1317,11 +1316,10 @@ mod tests { project.update(cx, |project, _| project.languages().add(rust_lang())); let window = cx.add_window(|cx| Workspace::test_new(project, cx)); let workspace = window.root(cx); - let window_id = window.id(); let worktree = cx.read(|cx| workspace.read(cx).worktrees(cx).next().unwrap()); // Create a new untitled buffer - cx.dispatch_action(window_id, NewFile); + cx.dispatch_action(window.into(), NewFile); let editor = workspace.read_with(cx, |workspace, cx| { workspace .active_item(cx) @@ -1376,7 +1374,7 @@ mod tests { // Open the same newly-created file in another pane item. The new editor should reuse // the same buffer. - cx.dispatch_action(window_id, NewFile); + cx.dispatch_action(window.into(), NewFile); workspace .update(cx, |workspace, cx| { workspace.split_and_clone( @@ -1412,10 +1410,9 @@ mod tests { project.update(cx, |project, _| project.languages().add(rust_lang())); let window = cx.add_window(|cx| Workspace::test_new(project, cx)); let workspace = window.root(cx); - let window_id = window.id(); // Create a new untitled buffer - cx.dispatch_action(window_id, NewFile); + cx.dispatch_action(window.into(), NewFile); let editor = workspace.read_with(cx, |workspace, cx| { workspace .active_item(cx) @@ -1465,7 +1462,6 @@ mod tests { let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await; let window = cx.add_window(|cx| Workspace::test_new(project, cx)); let workspace = window.root(cx); - let window_id = window.id(); let entries = cx.read(|cx| workspace.file_project_paths(cx)); let file1 = entries[0].clone(); @@ -1487,7 +1483,7 @@ mod tests { (editor.downgrade(), buffer) }); - cx.dispatch_action(window_id, pane::SplitRight); + cx.dispatch_action(window.into(), pane::SplitRight); let editor_2 = cx.update(|cx| { let pane_2 = workspace.read(cx).active_pane().clone(); assert_ne!(pane_1, pane_2); @@ -1497,7 +1493,7 @@ mod tests { pane2_item.downcast::().unwrap().downgrade() }); - cx.dispatch_action(window_id, workspace::CloseActiveItem); + cx.dispatch_action(window.into(), workspace::CloseActiveItem); cx.foreground().run_until_parked(); workspace.read_with(cx, |workspace, _| { @@ -1505,7 +1501,7 @@ mod tests { assert_eq!(workspace.active_pane(), &pane_1); }); - cx.dispatch_action(window_id, workspace::CloseActiveItem); + cx.dispatch_action(window.into(), workspace::CloseActiveItem); cx.foreground().run_until_parked(); window.simulate_prompt_answer(1, cx); cx.foreground().run_until_parked(); @@ -2063,11 +2059,10 @@ mod tests { cx.foreground().run_until_parked(); let window = cx.add_window(|_| TestView); - let window_id = window.id(); // Test loading the keymap base at all assert_key_bindings_for( - window_id, + window.into(), cx, vec![("backspace", &A), ("k", &ActivatePreviousPane)], line!(), @@ -2094,7 +2089,7 @@ mod tests { cx.foreground().run_until_parked(); assert_key_bindings_for( - window_id, + window.into(), cx, vec![("backspace", &B), ("k", &ActivatePreviousPane)], line!(), @@ -2117,7 +2112,7 @@ mod tests { cx.foreground().run_until_parked(); assert_key_bindings_for( - window_id, + window.into(), cx, vec![("backspace", &B), ("[", &ActivatePrevItem)], line!(), @@ -2125,7 +2120,7 @@ mod tests { #[track_caller] fn assert_key_bindings_for<'a>( - window_id: usize, + window: AnyWindowHandle, cx: &TestAppContext, actions: Vec<(&'static str, &'a dyn Action)>, line: u32, @@ -2133,7 +2128,7 @@ mod tests { for (key, action) in actions { // assert that... assert!( - cx.available_actions(window_id, 0) + cx.available_actions(window, 0) .into_iter() .any(|(_, bound_action, b)| { // action names match... @@ -2234,11 +2229,10 @@ mod tests { cx.foreground().run_until_parked(); let window = cx.add_window(|_| TestView); - let window_id = window.id(); // Test loading the keymap base at all assert_key_bindings_for( - window_id, + window.into(), cx, vec![("backspace", &A), ("k", &ActivatePreviousPane)], line!(), @@ -2264,7 +2258,12 @@ mod tests { cx.foreground().run_until_parked(); - assert_key_bindings_for(window_id, cx, vec![("k", &ActivatePreviousPane)], line!()); + assert_key_bindings_for( + window.into(), + cx, + vec![("k", &ActivatePreviousPane)], + line!(), + ); // Test modifying the base, while retaining the users keymap fs.save( @@ -2282,11 +2281,11 @@ mod tests { cx.foreground().run_until_parked(); - assert_key_bindings_for(window_id, cx, vec![("[", &ActivatePrevItem)], line!()); + assert_key_bindings_for(window.into(), cx, vec![("[", &ActivatePrevItem)], line!()); #[track_caller] fn assert_key_bindings_for<'a>( - window_id: usize, + window: AnyWindowHandle, cx: &TestAppContext, actions: Vec<(&'static str, &'a dyn Action)>, line: u32, @@ -2294,7 +2293,7 @@ mod tests { for (key, action) in actions { // assert that... assert!( - cx.available_actions(window_id, 0) + cx.available_actions(window, 0) .into_iter() .any(|(_, bound_action, b)| { // action names match... From da7dc9c880b06cf465aafacd8756abd9a6f60f86 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 8 Aug 2023 11:12:32 -0600 Subject: [PATCH 29/41] Work with window handles instead of ids in drag code --- crates/command_palette/src/command_palette.rs | 6 +-- crates/drag_and_drop/src/drag_and_drop.rs | 40 +++++++++---------- crates/project_panel/src/project_panel.rs | 6 +-- crates/terminal_view/src/terminal_panel.rs | 4 +- .../src/pane/dragged_item_receiver.rs | 12 +++--- 5 files changed, 34 insertions(+), 34 deletions(-) diff --git a/crates/command_palette/src/command_palette.rs b/crates/command_palette/src/command_palette.rs index b3703aa64a4549596caf47b57fc91971c985b8f0..0d398fcce909863991a198018eba6df4c84f929c 100644 --- a/crates/command_palette/src/command_palette.rs +++ b/crates/command_palette/src/command_palette.rs @@ -1,8 +1,8 @@ use collections::CommandPaletteFilter; use fuzzy::{StringMatch, StringMatchCandidate}; use gpui::{ - actions, elements::*, keymap_matcher::Keystroke, Action, AppContext, Element, MouseState, - ViewContext, + actions, elements::*, keymap_matcher::Keystroke, Action, AnyWindowHandle, AppContext, Element, + MouseState, ViewContext, }; use picker::{Picker, PickerDelegate, PickerEvent}; use std::cmp; @@ -28,7 +28,7 @@ pub struct CommandPaletteDelegate { pub enum Event { Dismissed, Confirmed { - window_id: usize, + window: AnyWindowHandle, focused_view_id: usize, action: Box, }, diff --git a/crates/drag_and_drop/src/drag_and_drop.rs b/crates/drag_and_drop/src/drag_and_drop.rs index 828e73040387058ca89adcdb164986513ef96860..ddfed0c858237077bd9ec20b5ace46dfe41e34d9 100644 --- a/crates/drag_and_drop/src/drag_and_drop.rs +++ b/crates/drag_and_drop/src/drag_and_drop.rs @@ -6,7 +6,7 @@ use gpui::{ geometry::{rect::RectF, vector::Vector2F}, platform::{CursorStyle, MouseButton}, scene::{MouseDown, MouseDrag}, - AnyElement, Element, View, ViewContext, WeakViewHandle, WindowContext, + AnyElement, AnyWindowHandle, Element, View, ViewContext, WeakViewHandle, WindowContext, }; const DEAD_ZONE: f32 = 4.; @@ -21,7 +21,7 @@ enum State { region: RectF, }, Dragging { - window_id: usize, + window: AnyWindowHandle, position: Vector2F, region_offset: Vector2F, region: RectF, @@ -49,14 +49,14 @@ impl Clone for State { region, }, State::Dragging { - window_id, + window, position, region_offset, region, payload, render, } => Self::Dragging { - window_id: window_id.clone(), + window: window.clone(), position: position.clone(), region_offset: region_offset.clone(), region: region.clone(), @@ -87,16 +87,16 @@ impl DragAndDrop { self.containers.insert(handle); } - pub fn currently_dragged(&self, window_id: usize) -> Option<(Vector2F, Rc)> { + pub fn currently_dragged(&self, window: AnyWindowHandle) -> Option<(Vector2F, Rc)> { self.currently_dragged.as_ref().and_then(|state| { if let State::Dragging { position, payload, - window_id: window_dragged_from, + window: window_dragged_from, .. } = state { - if &window_id != window_dragged_from { + if &window != window_dragged_from { return None; } @@ -126,9 +126,9 @@ impl DragAndDrop { cx: &mut WindowContext, render: Rc) -> AnyElement>, ) { - let window_id = cx.window_id(); + let window = cx.window(); cx.update_global(|this: &mut Self, cx| { - this.notify_containers_for_window(window_id, cx); + this.notify_containers_for_window(window, cx); match this.currently_dragged.as_ref() { Some(&State::Down { @@ -141,7 +141,7 @@ impl DragAndDrop { }) => { if (event.position - (region.origin() + region_offset)).length() > DEAD_ZONE { this.currently_dragged = Some(State::Dragging { - window_id, + window, region_offset, region, position: event.position, @@ -163,7 +163,7 @@ impl DragAndDrop { .. }) => { this.currently_dragged = Some(State::Dragging { - window_id, + window, region_offset, region, position: event.position, @@ -188,14 +188,14 @@ impl DragAndDrop { State::Down { .. } => None, State::DeadZone { .. } => None, State::Dragging { - window_id, + window, region_offset, position, region, payload, render, } => { - if cx.window_id() != window_id { + if cx.window() != window { return None; } @@ -260,27 +260,27 @@ impl DragAndDrop { pub fn cancel_dragging(&mut self, cx: &mut WindowContext) { if let Some(State::Dragging { - payload, window_id, .. + payload, window, .. }) = &self.currently_dragged { if payload.is::

() { - let window_id = *window_id; + let window = *window; self.currently_dragged = Some(State::Canceled); - self.notify_containers_for_window(window_id, cx); + self.notify_containers_for_window(window, cx); } } } fn finish_dragging(&mut self, cx: &mut WindowContext) { - if let Some(State::Dragging { window_id, .. }) = self.currently_dragged.take() { - self.notify_containers_for_window(window_id, cx); + if let Some(State::Dragging { window, .. }) = self.currently_dragged.take() { + self.notify_containers_for_window(window, cx); } } - fn notify_containers_for_window(&mut self, window_id: usize, cx: &mut WindowContext) { + fn notify_containers_for_window(&mut self, window: AnyWindowHandle, cx: &mut WindowContext) { self.containers.retain(|container| { if let Some(container) = container.upgrade(cx) { - if container.window_id() == window_id { + if container.window() == window { container.update(cx, |_, cx| cx.notify()); } true diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index df4334a19fc7daf862504c6ef7ccfc6f3f9e3da0..f7582f1764c573ee5e72ba66c09472e7643aa075 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -1415,7 +1415,7 @@ impl ProjectPanel { if cx .global::>() - .currently_dragged::(cx.window_id()) + .currently_dragged::(cx.window()) .is_some() && dragged_entry_destination .as_ref() @@ -1459,7 +1459,7 @@ impl ProjectPanel { .on_up(MouseButton::Left, move |_, this, cx| { if let Some((_, dragged_entry)) = cx .global::>() - .currently_dragged::(cx.window_id()) + .currently_dragged::(cx.window()) { this.move_entry( *dragged_entry, @@ -1472,7 +1472,7 @@ impl ProjectPanel { .on_move(move |_, this, cx| { if cx .global::>() - .currently_dragged::(cx.window_id()) + .currently_dragged::(cx.window()) .is_some() { this.dragged_entry_destination = if matches!(kind, EntryKind::File(_)) { diff --git a/crates/terminal_view/src/terminal_panel.rs b/crates/terminal_view/src/terminal_panel.rs index 6ad321c735deb00bb557058db5082761da9f7bbb..d00324cf166e8be68f355c0f4ad018a6d3d01fc1 100644 --- a/crates/terminal_view/src/terminal_panel.rs +++ b/crates/terminal_view/src/terminal_panel.rs @@ -48,7 +48,7 @@ impl TerminalPanel { fn new(workspace: &Workspace, cx: &mut ViewContext) -> Self { let weak_self = cx.weak_handle(); let pane = cx.add_view(|cx| { - let window_id = cx.window_id(); + let window = cx.window(); let mut pane = Pane::new( workspace.weak_handle(), workspace.project().clone(), @@ -60,7 +60,7 @@ impl TerminalPanel { pane.set_can_navigate(false, cx); pane.on_can_drop(move |drag_and_drop, cx| { drag_and_drop - .currently_dragged::(window_id) + .currently_dragged::(window) .map_or(false, |(_, item)| { item.handle.act_as::(cx).is_some() }) diff --git a/crates/workspace/src/pane/dragged_item_receiver.rs b/crates/workspace/src/pane/dragged_item_receiver.rs index 7146ab7b85b5dd4d91ceb4895fce060e34422ae3..2d3fe8ea8324411a7de5c2a70c1254648994652e 100644 --- a/crates/workspace/src/pane/dragged_item_receiver.rs +++ b/crates/workspace/src/pane/dragged_item_receiver.rs @@ -28,11 +28,11 @@ where let drag_and_drop = cx.global::>(); let drag_position = if (pane.can_drop)(drag_and_drop, cx) { drag_and_drop - .currently_dragged::(cx.window_id()) + .currently_dragged::(cx.window()) .map(|(drag_position, _)| drag_position) .or_else(|| { drag_and_drop - .currently_dragged::(cx.window_id()) + .currently_dragged::(cx.window()) .map(|(drag_position, _)| drag_position) }) } else { @@ -91,10 +91,10 @@ where let drag_and_drop = cx.global::>(); if drag_and_drop - .currently_dragged::(cx.window_id()) + .currently_dragged::(cx.window()) .is_some() || drag_and_drop - .currently_dragged::(cx.window_id()) + .currently_dragged::(cx.window()) .is_some() { cx.notify(); @@ -122,11 +122,11 @@ pub fn handle_dropped_item( } let drag_and_drop = cx.global::>(); let action = if let Some((_, dragged_item)) = - drag_and_drop.currently_dragged::(cx.window_id()) + drag_and_drop.currently_dragged::(cx.window()) { Action::Move(dragged_item.pane.clone(), dragged_item.handle.id()) } else if let Some((_, project_entry)) = - drag_and_drop.currently_dragged::(cx.window_id()) + drag_and_drop.currently_dragged::(cx.window()) { Action::Open(*project_entry) } else { From 0a4633f88f2166818ab57859783181a0972c0e77 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 8 Aug 2023 11:20:09 -0600 Subject: [PATCH 30/41] Remove more window id usage --- crates/gpui/src/app.rs | 14 +++----------- crates/gpui/src/app/menu.rs | 2 +- crates/gpui/src/app/window.rs | 8 ++------ crates/project/src/terminals.rs | 6 +++--- crates/terminal/src/terminal.rs | 6 +++--- crates/terminal_view/src/terminal_panel.rs | 4 ++-- crates/terminal_view/src/terminal_view.rs | 8 ++++---- crates/workspace/src/item.rs | 7 ++++--- crates/workspace/src/searchable.rs | 2 +- crates/zed/src/main.rs | 4 ++-- 10 files changed, 25 insertions(+), 36 deletions(-) diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index e0f46b036a07322844daf0fd7ca30c4d546e185f..e44ac93818fb768a8ae6ea12825ecb3a0e8d39ae 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -833,7 +833,7 @@ impl AppContext { &mut self, callback: F, ) -> Option { - self.main_window() + self.active_window() .and_then(|window| window.update(self, callback)) } @@ -1093,7 +1093,7 @@ impl AppContext { pub fn is_action_available(&self, action: &dyn Action) -> bool { let mut available_in_window = false; let action_id = action.id(); - if let Some(window) = self.main_window() { + if let Some(window) = self.active_window() { available_in_window = self .read_window(window, |cx| { if let Some(focused_view_id) = cx.focused_view_id() { @@ -1436,7 +1436,7 @@ impl AppContext { window } - pub fn main_window(&self) -> Option { + pub fn active_window(&self) -> Option { self.platform.main_window_id().and_then(|main_window_id| { self.windows .get(&main_window_id) @@ -2997,10 +2997,6 @@ impl<'a, 'b, V: View> ViewContext<'a, 'b, V> { WeakViewHandle::new(self.window_handle, self.view_id) } - pub fn window_id(&self) -> usize { - self.window_handle.id() - } - pub fn window(&self) -> AnyWindowHandle { self.window_handle } @@ -4138,10 +4134,6 @@ impl ViewHandle { self.any_handle } - pub fn window_id(&self) -> usize { - self.window.id() - } - pub fn window(&self) -> AnyWindowHandle { self.window } diff --git a/crates/gpui/src/app/menu.rs b/crates/gpui/src/app/menu.rs index 1d8908b8fdda9627d2eb7df433a7c5b819f024ed..67531a82975481c6a0bfa42511e6612175c94945 100644 --- a/crates/gpui/src/app/menu.rs +++ b/crates/gpui/src/app/menu.rs @@ -77,7 +77,7 @@ pub(crate) fn setup_menu_handlers(foreground_platform: &dyn ForegroundPlatform, let cx = app.0.clone(); move |action| { let mut cx = cx.borrow_mut(); - if let Some(main_window) = cx.main_window() { + if let Some(main_window) = cx.active_window() { let dispatched = main_window .update(&mut *cx, |cx| { if let Some(view_id) = cx.focused_view_id() { diff --git a/crates/gpui/src/app/window.rs b/crates/gpui/src/app/window.rs index 44a3c5cfdc8ded2e004df2da56ee6ce510396871..df3f8207556ced0bc1cff4521711a1468084f915 100644 --- a/crates/gpui/src/app/window.rs +++ b/crates/gpui/src/app/window.rs @@ -152,11 +152,11 @@ impl BorrowWindowContext for WindowContext<'_> { } } - fn read_window_optional(&self, window_id: AnyWindowHandle, f: F) -> Option + fn read_window_optional(&self, window: AnyWindowHandle, f: F) -> Option where F: FnOnce(&WindowContext) -> Option, { - BorrowWindowContext::read_window(self, window_id, f) + BorrowWindowContext::read_window(self, window, f) } fn update_window T>( @@ -210,10 +210,6 @@ impl<'a> WindowContext<'a> { self.removed = true; } - pub fn window_id(&self) -> usize { - self.window_handle.id() - } - pub fn window(&self) -> AnyWindowHandle { self.window_handle } diff --git a/crates/project/src/terminals.rs b/crates/project/src/terminals.rs index 7bd9ce8aecb011e287005803e5e186573b35899c..db5996829fa278db04e793d751d02ace086594e3 100644 --- a/crates/project/src/terminals.rs +++ b/crates/project/src/terminals.rs @@ -1,5 +1,5 @@ use crate::Project; -use gpui::{ModelContext, ModelHandle, WeakModelHandle}; +use gpui::{AnyWindowHandle, ModelContext, ModelHandle, WeakModelHandle}; use std::path::PathBuf; use terminal::{Terminal, TerminalBuilder, TerminalSettings}; @@ -11,7 +11,7 @@ impl Project { pub fn create_terminal( &mut self, working_directory: Option, - window_id: usize, + window: AnyWindowHandle, cx: &mut ModelContext, ) -> anyhow::Result> { if self.is_remote() { @@ -27,7 +27,7 @@ impl Project { settings.env.clone(), Some(settings.blinking.clone()), settings.alternate_scroll, - window_id, + window, ) .map(|builder| { let terminal_handle = cx.add_model(|cx| builder.subscribe(cx)); diff --git a/crates/terminal/src/terminal.rs b/crates/terminal/src/terminal.rs index 06befd5f4ef5b76a4cedccad0fdd526c7d6c0edc..f6cfe5ae309093ddffb7cca1b00666f22448b08d 100644 --- a/crates/terminal/src/terminal.rs +++ b/crates/terminal/src/terminal.rs @@ -53,7 +53,7 @@ use gpui::{ keymap_matcher::Keystroke, platform::{Modifiers, MouseButton, MouseMovedEvent, TouchPhase}, scene::{MouseDown, MouseDrag, MouseScrollWheel, MouseUp}, - AppContext, ClipboardItem, Entity, ModelContext, Task, + AnyWindowHandle, AppContext, ClipboardItem, Entity, ModelContext, Task, }; use crate::mappings::{ @@ -404,7 +404,7 @@ impl TerminalBuilder { mut env: HashMap, blink_settings: Option, alternate_scroll: AlternateScroll, - window_id: usize, + window: AnyWindowHandle, ) -> Result { let pty_config = { let alac_shell = match shell.clone() { @@ -462,7 +462,7 @@ impl TerminalBuilder { let pty = match tty::new( &pty_config, TerminalSize::default().into(), - window_id as u64, + window.id() as u64, ) { Ok(pty) => pty, Err(error) => { diff --git a/crates/terminal_view/src/terminal_panel.rs b/crates/terminal_view/src/terminal_panel.rs index d00324cf166e8be68f355c0f4ad018a6d3d01fc1..6be8a547cd37c8dc8c5fad225b06dd9fcbc6dafd 100644 --- a/crates/terminal_view/src/terminal_panel.rs +++ b/crates/terminal_view/src/terminal_panel.rs @@ -255,10 +255,10 @@ impl TerminalPanel { .clone(); let working_directory = crate::get_working_directory(workspace, cx, working_directory_strategy); - let window_id = cx.window_id(); + let window = cx.window(); if let Some(terminal) = workspace.project().update(cx, |project, cx| { project - .create_terminal(working_directory, window_id, cx) + .create_terminal(working_directory, window, cx) .log_err() }) { let terminal = Box::new(cx.add_view(|cx| { diff --git a/crates/terminal_view/src/terminal_view.rs b/crates/terminal_view/src/terminal_view.rs index a600046ac2861fb7b0b1250c65d4b31c1af3166c..970e0115df2545ce9f8979fc5e2efc876d08242f 100644 --- a/crates/terminal_view/src/terminal_view.rs +++ b/crates/terminal_view/src/terminal_view.rs @@ -112,11 +112,11 @@ impl TerminalView { let working_directory = get_working_directory(workspace, cx, strategy.working_directory.clone()); - let window_id = cx.window_id(); + let window = cx.window(); let terminal = workspace .project() .update(cx, |project, cx| { - project.create_terminal(working_directory, window_id, cx) + project.create_terminal(working_directory, window, cx) }) .notify_err(workspace, cx); @@ -741,7 +741,7 @@ impl Item for TerminalView { item_id: workspace::ItemId, cx: &mut ViewContext, ) -> Task>> { - let window_id = cx.window_id(); + let window = cx.window(); cx.spawn(|pane, mut cx| async move { let cwd = TERMINAL_DB .get_working_directory(item_id, workspace_id) @@ -762,7 +762,7 @@ impl Item for TerminalView { }); let terminal = project.update(&mut cx, |project, cx| { - project.create_terminal(cwd, window_id, cx) + project.create_terminal(cwd, window, cx) })?; Ok(pane.update(&mut cx, |_, cx| { cx.add_view(|cx| TerminalView::new(terminal, workspace, workspace_id, cx)) diff --git a/crates/workspace/src/item.rs b/crates/workspace/src/item.rs index f0af080d4a6cd9719db897a6320c869695092fe9..67827b78038b048ad619209b9a26bc5c0ba031b6 100644 --- a/crates/workspace/src/item.rs +++ b/crates/workspace/src/item.rs @@ -6,6 +6,7 @@ use crate::{AutosaveSetting, DelayedDebouncedEditAction, WorkspaceSettings}; use anyhow::Result; use client::{proto, Client}; use gpui::geometry::vector::Vector2F; +use gpui::AnyWindowHandle; use gpui::{ fonts::HighlightStyle, AnyElement, AnyViewHandle, AppContext, ModelHandle, Task, View, ViewContext, ViewHandle, WeakViewHandle, WindowContext, @@ -250,7 +251,7 @@ pub trait ItemHandle: 'static + fmt::Debug { fn workspace_deactivated(&self, cx: &mut WindowContext); fn navigate(&self, data: Box, cx: &mut WindowContext) -> bool; fn id(&self) -> usize; - fn window_id(&self) -> usize; + fn window(&self) -> AnyWindowHandle; fn as_any(&self) -> &AnyViewHandle; fn is_dirty(&self, cx: &AppContext) -> bool; fn has_conflict(&self, cx: &AppContext) -> bool; @@ -542,8 +543,8 @@ impl ItemHandle for ViewHandle { self.id() } - fn window_id(&self) -> usize { - self.window_id() + fn window(&self) -> AnyWindowHandle { + AnyViewHandle::window(self) } fn as_any(&self) -> &AnyViewHandle { diff --git a/crates/workspace/src/searchable.rs b/crates/workspace/src/searchable.rs index ae95838a742bb623a9376947e905d6054a82fff4..72117e1cabbefec98ba3af35ba5bd00571851647 100644 --- a/crates/workspace/src/searchable.rs +++ b/crates/workspace/src/searchable.rs @@ -235,7 +235,7 @@ impl From<&Box> for AnyViewHandle { impl PartialEq for Box { fn eq(&self, other: &Self) -> bool { - self.id() == other.id() && self.window_id() == other.window_id() + self.id() == other.id() && self.window() == other.window() } } diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index 2a1fef6a56efc5bf1c5496c935c134a752767066..bb30cac6d308b8df2a9a8d1db83084390b6adb61 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -931,11 +931,11 @@ pub fn dock_default_item_factory( .clone(); let working_directory = get_working_directory(workspace, cx, strategy); - let window_id = cx.window_id(); + let window = cx.window(); let terminal = workspace .project() .update(cx, |project, cx| { - project.create_terminal(working_directory, window_id, cx) + project.create_terminal(working_directory, window, cx) }) .notify_err(workspace, cx)?; From fe6a1886c1e26e821bc05cfc106ff3bffe322299 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 8 Aug 2023 11:20:42 -0600 Subject: [PATCH 31/41] Remove unused dock code --- crates/zed/src/main.rs | 34 ++-------------------------------- 1 file changed, 2 insertions(+), 32 deletions(-) diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index bb30cac6d308b8df2a9a8d1db83084390b6adb61..795c83aba6583e71a9da1eecb77c2d4d41e0780b 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -14,7 +14,7 @@ use futures::{ channel::{mpsc, oneshot}, FutureExt, SinkExt, StreamExt, }; -use gpui::{Action, App, AppContext, AssetSource, AsyncAppContext, Task, ViewContext}; +use gpui::{Action, App, AppContext, AssetSource, AsyncAppContext, Task}; use isahc::{config::Configurable, Request}; use language::{LanguageRegistry, Point}; use log::LevelFilter; @@ -43,7 +43,6 @@ use std::{ time::{Duration, SystemTime, UNIX_EPOCH}, }; use sum_tree::Bias; -use terminal_view::{get_working_directory, TerminalSettings, TerminalView}; use util::{ channel::ReleaseChannel, http::{self, HttpClient}, @@ -56,7 +55,7 @@ use fs::RealFs; #[cfg(debug_assertions)] use staff_mode::StaffMode; use util::{channel::RELEASE_CHANNEL, paths, ResultExt, TryFutureExt}; -use workspace::{item::ItemHandle, notifications::NotifyResultExt, AppState, Workspace}; +use workspace::AppState; use zed::{ assets::Assets, build_window_options, handle_keymap_file_changes, initialize_workspace, languages, menus, @@ -922,35 +921,6 @@ async fn handle_cli_connection( } } -pub fn dock_default_item_factory( - workspace: &mut Workspace, - cx: &mut ViewContext, -) -> Option> { - let strategy = settings::get::(cx) - .working_directory - .clone(); - let working_directory = get_working_directory(workspace, cx, strategy); - - let window = cx.window(); - let terminal = workspace - .project() - .update(cx, |project, cx| { - project.create_terminal(working_directory, window, cx) - }) - .notify_err(workspace, cx)?; - - let terminal_view = cx.add_view(|cx| { - TerminalView::new( - terminal, - workspace.weak_handle(), - workspace.database_id(), - cx, - ) - }); - - Some(Box::new(terminal_view)) -} - pub fn background_actions() -> &'static [(&'static str, &'static dyn Action)] { &[ ("Go to file", &file_finder::Toggle), From 1fd80ba8bd12e6dcfb26da3090ab876563422dee Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 8 Aug 2023 11:22:43 -0600 Subject: [PATCH 32/41] Remove AsyncAppContext::remove_window --- crates/gpui/src/app.rs | 4 ---- crates/workspace/src/workspace.rs | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index e44ac93818fb768a8ae6ea12825ecb3a0e8d39ae..2b3a3f3bf4a012f6e19b910fb4d0775faae2d9a8 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -411,10 +411,6 @@ impl AsyncAppContext { self.update(|cx| cx.add_window(window_options, build_root_view)) } - pub fn remove_window(&mut self, window: AnyWindowHandle) { - self.update_window(window, |cx| cx.remove_window()); - } - pub fn activate_window(&mut self, window: AnyWindowHandle) { self.update_window(window, |cx| cx.activate_window()); } diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index f0990322653757344d459e2bc2ef1f8c569cbdcf..f2a7a442f446a34ca265592dfdba46bcbbee855f 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -1254,7 +1254,7 @@ impl Workspace { let prepare = self.prepare_to_close(false, cx); Some(cx.spawn(|_, mut cx| async move { if prepare.await? { - cx.remove_window(window); + window.remove(&mut cx); } Ok(()) })) From 4f10f0ee865b92f6853cef9f9cd046d0c01eb8c0 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 8 Aug 2023 11:23:49 -0600 Subject: [PATCH 33/41] Remove window methods from AsyncAppContext --- crates/gpui/src/app.rs | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index 2b3a3f3bf4a012f6e19b910fb4d0775faae2d9a8..ddec0e10a3ccdbcdbe43b8b564fbba0501a913b0 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -344,22 +344,6 @@ impl AsyncAppContext { self.0.borrow().windows().collect() } - pub fn read_window T>( - &self, - window: AnyWindowHandle, - callback: F, - ) -> Option { - self.0.borrow_mut().read_window(window, callback) - } - - pub fn update_window T>( - &mut self, - window: AnyWindowHandle, - callback: F, - ) -> Option { - self.0.borrow_mut().update_window(window, callback) - } - pub fn debug_elements(&self, window: AnyWindowHandle) -> Option { self.0.borrow().read_window(window, |cx| { let root_view = cx.window.root_view(); From 95cd96e4becbf8e1404effb90893e5a1f6f0b3ce Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 8 Aug 2023 11:27:19 -0600 Subject: [PATCH 34/41] Move debug_elements to AnyWindowHandle --- crates/gpui/src/app.rs | 16 ++++++++-------- crates/zed/src/zed.rs | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index ddec0e10a3ccdbcdbe43b8b564fbba0501a913b0..5eb4ed744cbcfb54d83e0f72eab6a7e9dcf6bf97 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -344,14 +344,6 @@ impl AsyncAppContext { self.0.borrow().windows().collect() } - pub fn debug_elements(&self, window: AnyWindowHandle) -> Option { - self.0.borrow().read_window(window, |cx| { - let root_view = cx.window.root_view(); - let root_element = cx.window.rendered_views.get(&root_view.id())?; - root_element.debug(cx).log_err() - })? - } - pub fn dispatch_action( &mut self, window: AnyWindowHandle, @@ -4060,6 +4052,14 @@ impl AnyWindowHandle { self.update(cx, |cx| cx.remove_window()) } + pub fn debug_elements(&self, cx: &C) -> Option { + self.read_optional_with(cx, |cx| { + let root_view = cx.window.root_view(); + let root_element = cx.window.rendered_views.get(&root_view.id())?; + root_element.debug(cx).log_err() + }) + } + #[cfg(any(test, feature = "test-support"))] pub fn simulate_activation(&self, cx: &mut TestAppContext) { self.update(cx, |cx| { diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 6397a1e6b2a818525b9e29879f0bd012dbc35e22..1cde8d5b9a52b7970ae116f62752182eace1427d 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -182,7 +182,7 @@ pub fn init(app_state: &Arc, cx: &mut gpui::AppContext) { let window = cx.window(); cx.spawn(|workspace, mut cx| async move { let markdown = markdown.await.log_err(); - let content = to_string_pretty(&cx.debug_elements(window).ok_or_else(|| { + let content = to_string_pretty(&window.debug_elements(&cx).ok_or_else(|| { anyhow!("could not debug elements for window {}", window.id()) })?) .unwrap(); From b2d9ccc0a2f97a8ad4cde4fa15aa9bd500bfc63e Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 8 Aug 2023 11:38:07 -0600 Subject: [PATCH 35/41] Move more window methods off AsyncAppContext --- crates/collab_ui/src/contact_list.rs | 4 +- crates/command_palette/src/command_palette.rs | 13 ++-- crates/context_menu/src/context_menu.rs | 14 +++- crates/gpui/src/app.rs | 71 +++++++++---------- crates/search/src/project_search.rs | 12 ++-- crates/workspace/src/dock.rs | 7 +- crates/workspace/src/workspace.rs | 12 ++-- crates/zed/src/zed.rs | 4 +- 8 files changed, 73 insertions(+), 64 deletions(-) diff --git a/crates/collab_ui/src/contact_list.rs b/crates/collab_ui/src/contact_list.rs index a2b281856d923754e715e0e112eca2f5c682e605..49784523845918b601e2d856fc4fcec6ebe60550 100644 --- a/crates/collab_ui/src/contact_list.rs +++ b/crates/collab_ui/src/contact_list.rs @@ -312,11 +312,11 @@ impl ContactList { .update(&mut cx, |store, cx| store.remove_contact(user_id, cx)) .await { - cx.prompt( - window, + window.prompt( PromptLevel::Info, &format!("Failed to remove contact: {}", e), &["Ok"], + &mut cx, ); } } diff --git a/crates/command_palette/src/command_palette.rs b/crates/command_palette/src/command_palette.rs index 0d398fcce909863991a198018eba6df4c84f929c..101d4dc545cc2ecc2130a19989b8d57fea62fe97 100644 --- a/crates/command_palette/src/command_palette.rs +++ b/crates/command_palette/src/command_palette.rs @@ -1,8 +1,8 @@ use collections::CommandPaletteFilter; use fuzzy::{StringMatch, StringMatchCandidate}; use gpui::{ - actions, elements::*, keymap_matcher::Keystroke, Action, AnyWindowHandle, AppContext, Element, - MouseState, ViewContext, + actions, anyhow::anyhow, elements::*, keymap_matcher::Keystroke, Action, AnyWindowHandle, + AppContext, Element, MouseState, ViewContext, }; use picker::{Picker, PickerDelegate, PickerEvent}; use std::cmp; @@ -83,9 +83,10 @@ impl PickerDelegate for CommandPaletteDelegate { let view_id = self.focused_view_id; let window = cx.window(); cx.spawn(move |picker, mut cx| async move { - let actions = cx - .available_actions(window, view_id) + let actions = window + .available_actions(view_id, &cx) .into_iter() + .flatten() .filter_map(|(name, action, bindings)| { let filtered = cx.read(|cx| { if cx.has_global::() { @@ -168,7 +169,9 @@ impl PickerDelegate for CommandPaletteDelegate { let action = self.actions.remove(action_ix).action; cx.app_context() .spawn(move |mut cx| async move { - cx.dispatch_action(window, focused_view_id, action.as_ref()) + window + .dispatch_action(focused_view_id, action.as_ref(), &mut cx) + .ok_or_else(|| anyhow!("window was closed")) }) .detach_and_log_err(cx); } diff --git a/crates/context_menu/src/context_menu.rs b/crates/context_menu/src/context_menu.rs index 75cfd872b29aba9b03b1235faeaba24d8ac95ae7..a5534b6262c03166d462fe001ae130a891d4cfa3 100644 --- a/crates/context_menu/src/context_menu.rs +++ b/crates/context_menu/src/context_menu.rs @@ -1,5 +1,5 @@ use gpui::{ - anyhow, + anyhow::{self, anyhow}, elements::*, geometry::vector::Vector2F, keymap_matcher::KeymapContext, @@ -223,7 +223,9 @@ impl ContextMenu { let action = action.boxed_clone(); cx.app_context() .spawn(|mut cx| async move { - cx.dispatch_action(window, view_id, action.as_ref()) + window + .dispatch_action(view_id, action.as_ref(), &mut cx) + .ok_or_else(|| anyhow!("window was closed")) }) .detach_and_log_err(cx); } @@ -486,7 +488,13 @@ impl ContextMenu { let action = action.boxed_clone(); cx.app_context() .spawn(|mut cx| async move { - cx.dispatch_action(window, view_id, action.as_ref()) + window + .dispatch_action( + view_id, + action.as_ref(), + &mut cx, + ) + .ok_or_else(|| anyhow!("window was closed")) }) .detach_and_log_err(cx); } diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index 5eb4ed744cbcfb54d83e0f72eab6a7e9dcf6bf97..e6e11ca321bfe73a16a1755ce482878519009842 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -344,29 +344,6 @@ impl AsyncAppContext { self.0.borrow().windows().collect() } - pub fn dispatch_action( - &mut self, - window: AnyWindowHandle, - view_id: usize, - action: &dyn Action, - ) -> Result<()> { - self.0 - .borrow_mut() - .update_window(window, |cx| { - cx.dispatch_action(Some(view_id), action); - }) - .ok_or_else(|| anyhow!("window not found")) - } - - pub fn available_actions( - &self, - window: AnyWindowHandle, - view_id: usize, - ) -> Vec<(&'static str, Box, SmallVec<[Binding; 1]>)> { - self.read_window(window, |cx| cx.available_actions(view_id)) - .unwrap_or_default() - } - pub fn add_model(&mut self, build_model: F) -> ModelHandle where T: Entity, @@ -387,21 +364,6 @@ impl AsyncAppContext { self.update(|cx| cx.add_window(window_options, build_root_view)) } - pub fn activate_window(&mut self, window: AnyWindowHandle) { - self.update_window(window, |cx| cx.activate_window()); - } - - // TODO: Can we eliminate this method and move it to WindowContext then call it with update_window?s - pub fn prompt( - &mut self, - window: AnyWindowHandle, - level: PromptLevel, - msg: &str, - answers: &[&str], - ) -> Option> { - self.update_window(window, |cx| cx.prompt(level, msg, answers)) - } - pub fn platform(&self) -> Arc { self.0.borrow().platform().clone() } @@ -4060,6 +4022,39 @@ impl AnyWindowHandle { }) } + pub fn activate(&mut self, cx: &mut C) -> C::Result<()> { + self.update(cx, |cx| cx.activate_window()) + } + + pub fn prompt( + &self, + level: PromptLevel, + msg: &str, + answers: &[&str], + cx: &mut C, + ) -> C::Result> { + self.update(cx, |cx| cx.prompt(level, msg, answers)) + } + + pub fn dispatch_action( + &self, + view_id: usize, + action: &dyn Action, + cx: &mut C, + ) -> C::Result<()> { + self.update(cx, |cx| { + cx.dispatch_action(Some(view_id), action); + }) + } + + pub fn available_actions( + &self, + view_id: usize, + cx: &C, + ) -> C::Result, SmallVec<[Binding; 1]>)>> { + self.read_with(cx, |cx| cx.available_actions(view_id)) + } + #[cfg(any(test, feature = "test-support"))] pub fn simulate_activation(&self, cx: &mut TestAppContext) { self.update(cx, |cx| { diff --git a/crates/search/src/project_search.rs b/crates/search/src/project_search.rs index 202d494560e7388b689a4b9f8750b07c62758697..018ab9cb11525a1c3145ec96316095573d6406ef 100644 --- a/crates/search/src/project_search.rs +++ b/crates/search/src/project_search.rs @@ -1599,7 +1599,7 @@ pub mod tests { let search_view_id = search_view.id(); cx.spawn(|mut cx| async move { - cx.dispatch_action(window.into(), search_view_id, &ToggleFocus) + window.dispatch_action(search_view_id, &ToggleFocus, &mut cx); }) .detach(); deterministic.run_until_parked(); @@ -1650,9 +1650,9 @@ pub mod tests { "Search view should be focused after mismatching query had been used in search", ); }); - cx.spawn(|mut cx| async move { - cx.dispatch_action(window.into(), search_view_id, &ToggleFocus) - }) + cx.spawn( + |mut cx| async move { window.dispatch_action(search_view_id, &ToggleFocus, &mut cx) }, + ) .detach(); deterministic.run_until_parked(); search_view.update(cx, |search_view, cx| { @@ -1683,7 +1683,7 @@ pub mod tests { ); }); cx.spawn(|mut cx| async move { - cx.dispatch_action(window.into(), search_view_id, &ToggleFocus) + window.dispatch_action(search_view_id, &ToggleFocus, &mut cx); }) .detach(); deterministic.run_until_parked(); @@ -1713,7 +1713,7 @@ pub mod tests { }); cx.spawn(|mut cx| async move { - cx.dispatch_action(window.into(), search_view_id, &ToggleFocus) + window.dispatch_action(search_view_id, &ToggleFocus, &mut cx); }) .detach(); deterministic.run_until_parked(); diff --git a/crates/workspace/src/dock.rs b/crates/workspace/src/dock.rs index 5bb0fd93f8c9290c6f71f0ff94972115c9e3629c..e33c0a5391724ba16012ac87bf210f62da857461 100644 --- a/crates/workspace/src/dock.rs +++ b/crates/workspace/src/dock.rs @@ -534,8 +534,11 @@ impl View for PanelButtons { let view_id = this.workspace.id(); let tooltip_action = tooltip_action.boxed_clone(); cx.spawn(|_, mut cx| async move { - cx.dispatch_action(window, view_id, &*tooltip_action) - .ok(); + window.dispatch_action( + view_id, + &*tooltip_action, + &mut cx, + ); }) .detach(); } diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index f2a7a442f446a34ca265592dfdba46bcbbee855f..2f884b0ceb33d10e598057a65e1c44a60471227e 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -1280,11 +1280,11 @@ impl Workspace { && workspace_count == 1 && active_call.read_with(&cx, |call, _| call.room().is_some()) { - let answer = cx.prompt( - window, + let answer = window.prompt( PromptLevel::Warning, "Do you want to leave the current call?", &["Close window and hang up", "Cancel"], + &mut cx, ); if let Some(mut answer) = answer { @@ -4000,7 +4000,7 @@ pub fn join_remote_project( workspace.downgrade() }; - cx.activate_window(workspace.window()); + workspace.window().activate(&mut cx); cx.platform().activate(true); workspace.update(&mut cx, |workspace, cx| { @@ -4049,12 +4049,12 @@ pub fn restart(_: &Restart, cx: &mut AppContext) { // prompt in the active window before switching to a different window. workspace_windows.sort_by_key(|window| window.is_active(&cx) == Some(false)); - if let (true, Some(window)) = (should_confirm, workspace_windows.first().copied()) { - let answer = cx.prompt( - window.into(), + if let (true, Some(window)) = (should_confirm, workspace_windows.first()) { + let answer = window.prompt( PromptLevel::Info, "Are you sure you want to restart?", &["Restart", "Cancel"], + &mut cx, ); if let Some(mut answer) = answer { diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 1cde8d5b9a52b7970ae116f62752182eace1427d..8ad8080375ec22e1c60840a0cac0565e95969aaa 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -416,11 +416,11 @@ fn quit(_: &Quit, cx: &mut gpui::AppContext) { workspace_windows.sort_by_key(|window| window.is_active(&cx) == Some(false)); if let (true, Some(window)) = (should_confirm, workspace_windows.first().copied()) { - let answer = cx.prompt( - window.into(), + let answer = window.prompt( PromptLevel::Info, "Are you sure you want to quit?", &["Quit", "Cancel"], + &mut cx, ); if let Some(mut answer) = answer { From b77c336a3d719cc1a483e58319bcdf310739e774 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 8 Aug 2023 11:39:56 -0600 Subject: [PATCH 36/41] Return window handles from WeakItemHandle --- crates/workspace/src/item.rs | 6 +++--- crates/workspace/src/searchable.rs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/workspace/src/item.rs b/crates/workspace/src/item.rs index 67827b78038b048ad619209b9a26bc5c0ba031b6..21956be44683f0160c7be0d6387d4d03a60c25d7 100644 --- a/crates/workspace/src/item.rs +++ b/crates/workspace/src/item.rs @@ -281,7 +281,7 @@ pub trait ItemHandle: 'static + fmt::Debug { pub trait WeakItemHandle { fn id(&self) -> usize; - fn window_id(&self) -> usize; + fn window(&self) -> AnyWindowHandle; fn upgrade(&self, cx: &AppContext) -> Option>; } @@ -650,8 +650,8 @@ impl WeakItemHandle for WeakViewHandle { self.id() } - fn window_id(&self) -> usize { - self.window_id() + fn window(&self) -> AnyWindowHandle { + self.window() } fn upgrade(&self, cx: &AppContext) -> Option> { diff --git a/crates/workspace/src/searchable.rs b/crates/workspace/src/searchable.rs index 72117e1cabbefec98ba3af35ba5bd00571851647..7a470db7c926dd8d2a2aee171fd5d269b6eebab3 100644 --- a/crates/workspace/src/searchable.rs +++ b/crates/workspace/src/searchable.rs @@ -259,7 +259,7 @@ impl WeakSearchableItemHandle for WeakViewHandle { impl PartialEq for Box { fn eq(&self, other: &Self) -> bool { - self.id() == other.id() && self.window_id() == other.window_id() + self.id() == other.id() && self.window() == other.window() } } @@ -267,6 +267,6 @@ impl Eq for Box {} impl std::hash::Hash for Box { fn hash(&self, state: &mut H) { - (self.id(), self.window_id()).hash(state) + (self.id(), self.window().id()).hash(state) } } From afd89b256abb4e5519446de40c6c52067d1b6587 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 8 Aug 2023 16:06:53 -0600 Subject: [PATCH 37/41] Store AnyWindowHandles instead of usizes --- crates/gpui/src/app.rs | 126 ++++++++------------ crates/gpui/src/app/ref_counts.rs | 14 +-- crates/gpui/src/app/test_app_context.rs | 4 +- crates/gpui/src/app/window.rs | 28 ++--- crates/gpui/src/app/window_input_handler.rs | 2 +- crates/gpui/src/platform.rs | 8 +- crates/gpui/src/platform/mac/platform.rs | 12 +- crates/gpui/src/platform/mac/window.rs | 17 +-- crates/gpui/src/platform/test.rs | 40 ++++--- 9 files changed, 117 insertions(+), 134 deletions(-) diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index e6e11ca321bfe73a16a1755ce482878519009842..507cbffad279553dea2612dbb9a898ab4358ae8b 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -444,9 +444,9 @@ type WindowShouldCloseSubscriptionCallback = Box b pub struct AppContext { models: HashMap>, - views: HashMap<(usize, usize), Box>, - views_metadata: HashMap<(usize, usize), ViewMetadata>, - windows: HashMap, + views: HashMap<(AnyWindowHandle, usize), Box>, + views_metadata: HashMap<(AnyWindowHandle, usize), ViewMetadata>, + windows: HashMap, globals: HashMap>, element_states: HashMap>, background: Arc, @@ -727,12 +727,12 @@ impl AppContext { } pub fn view_ui_name(&self, window: AnyWindowHandle, view_id: usize) -> Option<&'static str> { - Some(self.views.get(&(window.id(), view_id))?.ui_name()) + Some(self.views.get(&(window, view_id))?.ui_name()) } pub fn view_type_id(&self, window: AnyWindowHandle, view_id: usize) -> Option { self.views_metadata - .get(&(window.id(), view_id)) + .get(&(window, view_id)) .map(|metadata| metadata.type_id) } @@ -758,7 +758,7 @@ impl AppContext { handle: AnyWindowHandle, callback: F, ) -> Option { - let window = self.windows.get(&handle.id())?; + let window = self.windows.get(&handle)?; let window_context = WindowContext::immutable(self, &window, handle); Some(callback(&window_context)) } @@ -1033,7 +1033,7 @@ impl AppContext { if let Some(focused_view_id) = cx.focused_view_id() { for view_id in cx.ancestors(focused_view_id) { if let Some(view_metadata) = - cx.views_metadata.get(&(cx.window_handle.id(), view_id)) + cx.views_metadata.get(&(cx.window_handle, view_id)) { if let Some(actions) = cx.actions.get(&view_metadata.type_id) { if actions.contains_key(&action_id) { @@ -1259,13 +1259,12 @@ impl AppContext { F: FnOnce(&mut ViewContext) -> V, { self.update(|this| { - let window_id = post_inc(&mut this.next_id); + let handle = WindowHandle::::new(post_inc(&mut this.next_id)); let platform_window = this.platform - .open_window(window_id, window_options, this.foreground.clone()); - let handle = WindowHandle::::new(window_id); - let window = this.build_window(handle, platform_window, build_root_view); - this.windows.insert(window_id, window); + .open_window(handle.into(), window_options, this.foreground.clone()); + let window = this.build_window(handle.into(), platform_window, build_root_view); + this.windows.insert(handle.into(), window); handle }) } @@ -1276,29 +1275,25 @@ impl AppContext { F: FnOnce(&mut ViewContext) -> V, { self.update(|this| { - let window_id = post_inc(&mut this.next_id); - let platform_window = this.platform.add_status_item(window_id); - let handle = WindowHandle::::new(window_id); - let window = this.build_window(handle, platform_window, build_root_view); - this.windows.insert(window_id, window); + let handle = WindowHandle::::new(post_inc(&mut this.next_id)); + let platform_window = this.platform.add_status_item(handle.into()); + let window = this.build_window(handle.into(), platform_window, build_root_view); + this.windows.insert(handle.into(), window); handle.update_root(this, |view, cx| view.focus_in(cx.handle().into_any(), cx)); handle }) } - pub fn build_window( + pub fn build_window( &mut self, - handle: H, + handle: AnyWindowHandle, mut platform_window: Box, build_root_view: F, ) -> Window where - H: Into, V: View, F: FnOnce(&mut ViewContext) -> V, { - let handle: AnyWindowHandle = handle.into(); - { let mut app = self.upgrade(); @@ -1371,21 +1366,15 @@ impl AppContext { } pub fn active_window(&self) -> Option { - self.platform.main_window_id().and_then(|main_window_id| { - self.windows - .get(&main_window_id) - .map(|window| AnyWindowHandle::new(main_window_id, window.root_view().type_id())) - }) + self.platform.main_window() } pub fn windows(&self) -> impl '_ + Iterator { - self.windows.iter().map(|(window_id, window)| { - AnyWindowHandle::new(*window_id, window.root_view().type_id()) - }) + self.windows.keys().copied() } pub fn read_view(&self, handle: &ViewHandle) -> &T { - if let Some(view) = self.views.get(&(handle.window.id(), handle.view_id)) { + if let Some(view) = self.views.get(&(handle.window, handle.view_id)) { view.as_any().downcast_ref().expect("downcast is type safe") } else { panic!("circular view reference for type {}", type_name::()); @@ -1437,13 +1426,13 @@ impl AppContext { .push_back(Effect::ModelRelease { model_id, model }); } - for (window_id, view_id) in dropped_views { + for (window, view_id) in dropped_views { self.subscriptions.remove(view_id); self.observations.remove(view_id); - self.views_metadata.remove(&(window_id, view_id)); - let mut view = self.views.remove(&(window_id, view_id)).unwrap(); + self.views_metadata.remove(&(window, view_id)); + let mut view = self.views.remove(&(window, view_id)).unwrap(); view.release(self); - if let Some(window) = self.windows.get_mut(&window_id) { + if let Some(window) = self.windows.get_mut(&window) { window.parents.remove(&view_id); window .invalidation @@ -1571,7 +1560,7 @@ impl AppContext { } Effect::ResizeWindow { window } => { - if let Some(window) = self.windows.get_mut(&window.id()) { + if let Some(window) = self.windows.get_mut(&window) { window .invalidation .get_or_insert(WindowInvalidation::default()); @@ -1696,15 +1685,14 @@ impl AppContext { for old_ancestor in old_ancestors.iter().copied() { if !new_ancestors.contains(&old_ancestor) { if let Some(mut view) = - cx.views.remove(&(window.id(), old_ancestor)) + cx.views.remove(&(window, old_ancestor)) { view.focus_out( focused_view_id, cx, old_ancestor, ); - cx.views - .insert((window.id(), old_ancestor), view); + cx.views.insert((window, old_ancestor), view); } } } @@ -1713,15 +1701,14 @@ impl AppContext { for new_ancestor in new_ancestors.iter().copied() { if !old_ancestors.contains(&new_ancestor) { if let Some(mut view) = - cx.views.remove(&(window.id(), new_ancestor)) + cx.views.remove(&(window, new_ancestor)) { view.focus_in( focused_view_id, cx, new_ancestor, ); - cx.views - .insert((window.id(), new_ancestor), view); + cx.views.insert((window, new_ancestor), view); } } } @@ -1730,9 +1717,7 @@ impl AppContext { // there isn't any pending focus, focus the root view. let root_view_id = cx.window.root_view().id(); if focused_view_id != root_view_id - && !cx - .views - .contains_key(&(window.id(), focused_view_id)) + && !cx.views.contains_key(&(window, focused_view_id)) && !focus_effects.contains_key(&window.id()) { focus_effects.insert( @@ -1837,13 +1822,13 @@ impl AppContext { observed_window: AnyWindowHandle, observed_view_id: usize, ) { - let view_key = (observed_window.id(), observed_view_id); + let view_key = (observed_window, observed_view_id); if let Some((view, mut view_metadata)) = self .views .remove(&view_key) .zip(self.views_metadata.remove(&view_key)) { - if let Some(window) = self.windows.get_mut(&observed_window.id()) { + if let Some(window) = self.windows.get_mut(&observed_window) { window .invalidation .get_or_insert_with(Default::default) @@ -1924,7 +1909,7 @@ impl AppContext { let focused_id = match effect { FocusEffect::View { view_id, .. } => { if let Some(view_id) = view_id { - if cx.views.contains_key(&(window.id(), view_id)) { + if cx.views.contains_key(&(window, view_id)) { Some(view_id) } else { Some(cx.root_view().id()) @@ -1949,9 +1934,9 @@ impl AppContext { if focus_changed { if let Some(blurred_id) = blurred_id { for view_id in cx.ancestors(blurred_id).collect::>() { - if let Some(mut view) = cx.views.remove(&(window.id(), view_id)) { + if let Some(mut view) = cx.views.remove(&(window, view_id)) { view.focus_out(blurred_id, cx, view_id); - cx.views.insert((window.id(), view_id), view); + cx.views.insert((window, view_id), view); } } @@ -1963,9 +1948,9 @@ impl AppContext { if focus_changed || effect.is_forced() { if let Some(focused_id) = focused_id { for view_id in cx.ancestors(focused_id).collect::>() { - if let Some(mut view) = cx.views.remove(&(window.id(), view_id)) { + if let Some(mut view) = cx.views.remove(&(window, view_id)) { view.focus_in(focused_id, cx, view_id); - cx.views.insert((window.id(), view_id), view); + cx.views.insert((window, view_id), view); } } @@ -1991,7 +1976,7 @@ impl AppContext { mut callback: WindowShouldCloseSubscriptionCallback, ) { let mut app = self.upgrade(); - if let Some(window) = self.windows.get_mut(&window.id()) { + if let Some(window) = self.windows.get_mut(&window) { window .platform_window .on_should_close(Box::new(move || app.update(|cx| callback(cx)))) @@ -2127,15 +2112,13 @@ impl BorrowWindowContext for AppContext { where F: FnOnce(&mut WindowContext) -> T, { - self.update(|app_context| { - let mut window = app_context.windows.remove(&handle.id())?; - let mut window_context = WindowContext::mutable(app_context, &mut window, handle); - let result = f(&mut window_context); - if !window_context.removed { - app_context.windows.insert(handle.id(), window); - } - Some(result) - }) + let mut window = self.windows.remove(&handle)?; + let mut window_context = WindowContext::mutable(self, &mut window, handle); + let result = f(&mut window_context); + if !window_context.removed { + self.windows.insert(handle, window); + } + Some(result) } fn update_window_optional(&mut self, handle: AnyWindowHandle, f: F) -> Option @@ -2590,7 +2573,7 @@ where } else { let focused_type = cx .views_metadata - .get(&(cx.window_handle.id(), focused_id)) + .get(&(cx.window_handle, focused_id)) .unwrap() .type_id; AnyViewHandle::new( @@ -2610,7 +2593,7 @@ where } else { let blurred_type = cx .views_metadata - .get(&(cx.window_handle.id(), blurred_id)) + .get(&(cx.window_handle, blurred_id)) .unwrap() .type_id; AnyViewHandle::new( @@ -3413,7 +3396,7 @@ impl<'a, 'b, 'c, V: View> LayoutContext<'a, 'b, 'c, V> { let mut contexts = Vec::new(); let mut handler_depth = None; for (i, view_id) in self.ancestors(view_id).enumerate() { - if let Some(view_metadata) = self.views_metadata.get(&(window.id(), view_id)) { + if let Some(view_metadata) = self.views_metadata.get(&(window, view_id)) { if let Some(actions) = self.actions.get(&view_metadata.type_id) { if actions.contains_key(&action.id()) { handler_depth = Some(i); @@ -3873,10 +3856,7 @@ impl Copy for WindowHandle {} impl WindowHandle { fn new(window_id: usize) -> Self { WindowHandle { - any_handle: AnyWindowHandle { - window_id, - root_view_type: TypeId::of::(), - }, + any_handle: AnyWindowHandle::new(window_id, TypeId::of::()), root_view_type: PhantomData, } } @@ -4240,7 +4220,7 @@ impl AnyViewHandle { view_type: TypeId, ref_counts: Arc>, ) -> Self { - ref_counts.lock().inc_view(window.id(), view_id); + ref_counts.lock().inc_view(window, view_id); #[cfg(any(test, feature = "test-support"))] let handle_id = ref_counts @@ -4308,7 +4288,7 @@ impl AnyViewHandle { pub fn debug_json<'a, 'b>(&self, cx: &'b WindowContext<'a>) -> serde_json::Value { cx.views - .get(&(self.window.id(), self.view_id)) + .get(&(self.window, self.view_id)) .map_or_else(|| serde_json::Value::Null, |view| view.debug_json(cx)) } } @@ -4338,9 +4318,7 @@ impl PartialEq> for AnyViewHandle { impl Drop for AnyViewHandle { fn drop(&mut self) { - self.ref_counts - .lock() - .dec_view(self.window.id(), self.view_id); + self.ref_counts.lock().dec_view(self.window, self.view_id); #[cfg(any(test, feature = "test-support"))] self.ref_counts .lock() diff --git a/crates/gpui/src/app/ref_counts.rs b/crates/gpui/src/app/ref_counts.rs index f0c1699f165ea8100ccdfe1facbfb8a3ac1a2d8e..63905326fe2483118221e79a57942d525c41701f 100644 --- a/crates/gpui/src/app/ref_counts.rs +++ b/crates/gpui/src/app/ref_counts.rs @@ -9,7 +9,7 @@ use collections::{hash_map::Entry, HashMap, HashSet}; #[cfg(any(test, feature = "test-support"))] use crate::util::post_inc; -use crate::ElementStateId; +use crate::{AnyWindowHandle, ElementStateId}; lazy_static! { static ref LEAK_BACKTRACE: bool = @@ -26,7 +26,7 @@ pub struct RefCounts { entity_counts: HashMap, element_state_counts: HashMap, dropped_models: HashSet, - dropped_views: HashSet<(usize, usize)>, + dropped_views: HashSet<(AnyWindowHandle, usize)>, dropped_element_states: HashSet, #[cfg(any(test, feature = "test-support"))] @@ -55,12 +55,12 @@ impl RefCounts { } } - pub fn inc_view(&mut self, window_id: usize, view_id: usize) { + pub fn inc_view(&mut self, window: AnyWindowHandle, view_id: usize) { match self.entity_counts.entry(view_id) { Entry::Occupied(mut entry) => *entry.get_mut() += 1, Entry::Vacant(entry) => { entry.insert(1); - self.dropped_views.remove(&(window_id, view_id)); + self.dropped_views.remove(&(window, view_id)); } } } @@ -94,12 +94,12 @@ impl RefCounts { } } - pub fn dec_view(&mut self, window_id: usize, view_id: usize) { + pub fn dec_view(&mut self, window: AnyWindowHandle, view_id: usize) { let count = self.entity_counts.get_mut(&view_id).unwrap(); *count -= 1; if *count == 0 { self.entity_counts.remove(&view_id); - self.dropped_views.insert((window_id, view_id)); + self.dropped_views.insert((window, view_id)); } } @@ -120,7 +120,7 @@ impl RefCounts { &mut self, ) -> ( HashSet, - HashSet<(usize, usize)>, + HashSet<(AnyWindowHandle, usize)>, HashSet, ) { ( diff --git a/crates/gpui/src/app/test_app_context.rs b/crates/gpui/src/app/test_app_context.rs index b1729d89b8591176f1fa9aa27ccc93cebdc65e8d..6d593c2e7247d6d6005b32320b2b4dd235b4cac8 100644 --- a/crates/gpui/src/app/test_app_context.rs +++ b/crates/gpui/src/app/test_app_context.rs @@ -159,7 +159,7 @@ impl TestAppContext { .borrow_mut() .add_window(Default::default(), build_root_view); window.simulate_activation(self); - WindowHandle::new(window.id()) + window } pub fn observe_global(&mut self, callback: F) -> Subscription @@ -516,7 +516,7 @@ impl AnyWindowHandle { cx: &'a mut TestAppContext, ) -> std::cell::RefMut<'a, platform::test::Window> { std::cell::RefMut::map(cx.cx.borrow_mut(), |state| { - let window = state.windows.get_mut(&self.window_id).unwrap(); + let window = state.windows.get_mut(&self).unwrap(); let test_window = window .platform_window .as_any_mut() diff --git a/crates/gpui/src/app/window.rs b/crates/gpui/src/app/window.rs index df3f8207556ced0bc1cff4521711a1468084f915..d39219e65d4b0f19e251676b0901b7a3019328d7 100644 --- a/crates/gpui/src/app/window.rs +++ b/crates/gpui/src/app/window.rs @@ -235,9 +235,9 @@ impl<'a> WindowContext<'a> { F: FnOnce(&mut dyn AnyView, &mut Self) -> T, { let handle = self.window_handle; - let mut view = self.views.remove(&(handle.id(), view_id))?; + let mut view = self.views.remove(&(handle, view_id))?; let result = f(view.as_mut(), self); - self.views.insert((handle.id(), view_id), view); + self.views.insert((handle, view_id), view); Some(result) } @@ -389,7 +389,7 @@ impl<'a> WindowContext<'a> { let mut contexts = Vec::new(); let mut handler_depths_by_action_id = HashMap::::default(); for (depth, view_id) in self.ancestors(view_id).enumerate() { - if let Some(view_metadata) = self.views_metadata.get(&(handle.id(), view_id)) { + if let Some(view_metadata) = self.views_metadata.get(&(handle, view_id)) { contexts.push(view_metadata.keymap_context.clone()); if let Some(actions) = self.actions.get(&view_metadata.type_id) { handler_depths_by_action_id @@ -440,7 +440,7 @@ impl<'a> WindowContext<'a> { .ancestors(focused_view_id) .filter_map(|view_id| { self.views_metadata - .get(&(handle.id(), view_id)) + .get(&(handle, view_id)) .map(|view| (view_id, view.keymap_context.clone())) }) .collect(); @@ -850,9 +850,9 @@ impl<'a> WindowContext<'a> { let handle = self.window_handle; if let Some(focused_view_id) = self.window.focused_view_id { for view_id in self.ancestors(focused_view_id).collect::>() { - if let Some(mut view) = self.views.remove(&(handle.id(), view_id)) { + if let Some(mut view) = self.views.remove(&(handle, view_id)) { let handled = view.key_down(event, self, view_id); - self.views.insert((handle.id(), view_id), view); + self.views.insert((handle, view_id), view); if handled { return true; } @@ -869,9 +869,9 @@ impl<'a> WindowContext<'a> { let handle = self.window_handle; if let Some(focused_view_id) = self.window.focused_view_id { for view_id in self.ancestors(focused_view_id).collect::>() { - if let Some(mut view) = self.views.remove(&(handle.id(), view_id)) { + if let Some(mut view) = self.views.remove(&(handle, view_id)) { let handled = view.key_up(event, self, view_id); - self.views.insert((handle.id(), view_id), view); + self.views.insert((handle, view_id), view); if handled { return true; } @@ -888,9 +888,9 @@ impl<'a> WindowContext<'a> { let handle = self.window_handle; if let Some(focused_view_id) = self.window.focused_view_id { for view_id in self.ancestors(focused_view_id).collect::>() { - if let Some(mut view) = self.views.remove(&(handle.id(), view_id)) { + if let Some(mut view) = self.views.remove(&(handle, view_id)) { let handled = view.modifiers_changed(event, self, view_id); - self.views.insert((handle.id(), view_id), view); + self.views.insert((handle, view_id), view); if handled { return true; } @@ -929,10 +929,10 @@ impl<'a> WindowContext<'a> { let view_id = params.view_id; let mut view = self .views - .remove(&(handle.id(), view_id)) + .remove(&(handle, view_id)) .ok_or_else(|| anyhow!("view not found"))?; let element = view.render(self, view_id); - self.views.insert((handle.id(), view_id), view); + self.views.insert((handle, view_id), view); Ok(element) } @@ -1190,13 +1190,13 @@ impl<'a> WindowContext<'a> { let mut keymap_context = KeymapContext::default(); view.update_keymap_context(&mut keymap_context, cx.app_context()); self.views_metadata.insert( - (handle.id(), view_id), + (handle, view_id), ViewMetadata { type_id: TypeId::of::(), keymap_context, }, ); - self.views.insert((handle.id(), view_id), Box::new(view)); + self.views.insert((handle, view_id), Box::new(view)); self.window .invalidation .get_or_insert_with(Default::default) diff --git a/crates/gpui/src/app/window_input_handler.rs b/crates/gpui/src/app/window_input_handler.rs index d7c65b11fae6f6c66de0c4c0a1c4302400d651ba..bdc871a80278eaf140887fa9e6d3b64077ac3150 100644 --- a/crates/gpui/src/app/window_input_handler.rs +++ b/crates/gpui/src/app/window_input_handler.rs @@ -23,7 +23,7 @@ impl WindowInputHandler { let mut app = self.app.try_borrow_mut().ok()?; self.window.update_optional(&mut *app, |cx| { let view_id = cx.window.focused_view_id?; - let view = cx.views.get(&(self.window.id(), view_id))?; + let view = cx.views.get(&(self.window, view_id))?; let result = f(view.as_ref(), &cx); Some(result) }) diff --git a/crates/gpui/src/platform.rs b/crates/gpui/src/platform.rs index 67f8e52c04f0cdf18aaf340860d0fe9adc44bc88..1d93a45fc7bd0e58ba2fd514e9db33a5c74e590b 100644 --- a/crates/gpui/src/platform.rs +++ b/crates/gpui/src/platform.rs @@ -19,7 +19,7 @@ use crate::{ }, keymap_matcher::KeymapMatcher, text_layout::{LineLayout, RunStyle}, - Action, ClipboardItem, Menu, Scene, + Action, AnyWindowHandle, ClipboardItem, Menu, Scene, }; use anyhow::{anyhow, bail, Result}; use async_task::Runnable; @@ -58,13 +58,13 @@ pub trait Platform: Send + Sync { fn open_window( &self, - id: usize, + handle: AnyWindowHandle, options: WindowOptions, executor: Rc, ) -> Box; - fn main_window_id(&self) -> Option; + fn main_window(&self) -> Option; - fn add_status_item(&self, id: usize) -> Box; + fn add_status_item(&self, handle: AnyWindowHandle) -> Box; fn write_to_clipboard(&self, item: ClipboardItem); fn read_from_clipboard(&self) -> Option; diff --git a/crates/gpui/src/platform/mac/platform.rs b/crates/gpui/src/platform/mac/platform.rs index 509c979b8536dfde31a9246b34edd7bd0ca88e0e..277ff8403f8df8ce96984c4a6fc896ad818df6f7 100644 --- a/crates/gpui/src/platform/mac/platform.rs +++ b/crates/gpui/src/platform/mac/platform.rs @@ -6,7 +6,7 @@ use crate::{ executor, keymap_matcher::KeymapMatcher, platform::{self, AppVersion, CursorStyle, Event}, - Action, ClipboardItem, Menu, MenuItem, + Action, AnyWindowHandle, ClipboardItem, Menu, MenuItem, }; use anyhow::{anyhow, Result}; use block::ConcreteBlock; @@ -590,18 +590,18 @@ impl platform::Platform for MacPlatform { fn open_window( &self, - id: usize, + handle: AnyWindowHandle, options: platform::WindowOptions, executor: Rc, ) -> Box { - Box::new(Window::open(id, options, executor, self.fonts())) + Box::new(Window::open(handle, options, executor, self.fonts())) } - fn main_window_id(&self) -> Option { - Window::main_window_id() + fn main_window(&self) -> Option { + Window::main_window() } - fn add_status_item(&self, _id: usize) -> Box { + fn add_status_item(&self, _handle: AnyWindowHandle) -> Box { Box::new(StatusItem::add(self.fonts())) } diff --git a/crates/gpui/src/platform/mac/window.rs b/crates/gpui/src/platform/mac/window.rs index c0f0ade7b926b59dc3a49a714483f576f3a64026..59324f473a97a4682efc277cce5b46e916a37b9a 100644 --- a/crates/gpui/src/platform/mac/window.rs +++ b/crates/gpui/src/platform/mac/window.rs @@ -13,6 +13,7 @@ use crate::{ Event, InputHandler, KeyDownEvent, Modifiers, ModifiersChangedEvent, MouseButton, MouseButtonEvent, MouseMovedEvent, Scene, WindowBounds, WindowKind, }, + AnyWindowHandle, }; use block::ConcreteBlock; use cocoa::{ @@ -282,7 +283,7 @@ struct InsertText { } struct WindowState { - id: usize, + handle: AnyWindowHandle, native_window: id, kind: WindowKind, event_callback: Option bool>>, @@ -426,7 +427,7 @@ pub struct Window(Rc>); impl Window { pub fn open( - id: usize, + handle: AnyWindowHandle, options: platform::WindowOptions, executor: Rc, fonts: Arc, @@ -504,7 +505,7 @@ impl Window { assert!(!native_view.is_null()); let window = Self(Rc::new(RefCell::new(WindowState { - id, + handle, native_window, kind: options.kind, event_callback: None, @@ -621,13 +622,13 @@ impl Window { } } - pub fn main_window_id() -> Option { + pub fn main_window() -> Option { unsafe { let app = NSApplication::sharedApplication(nil); let main_window: id = msg_send![app, mainWindow]; if msg_send![main_window, isKindOfClass: WINDOW_CLASS] { - let id = get_window_state(&*main_window).borrow().id; - Some(id) + let handle = get_window_state(&*main_window).borrow().handle; + Some(handle) } else { None } @@ -881,7 +882,7 @@ impl platform::Window for Window { fn is_topmost_for_position(&self, position: Vector2F) -> bool { let self_borrow = self.0.borrow(); - let self_id = self_borrow.id; + let self_id = self_borrow.handle; unsafe { let app = NSApplication::sharedApplication(nil); @@ -898,7 +899,7 @@ impl platform::Window for Window { let is_panel: BOOL = msg_send![top_most_window, isKindOfClass: PANEL_CLASS]; let is_window: BOOL = msg_send![top_most_window, isKindOfClass: WINDOW_CLASS]; if is_panel == YES || is_window == YES { - let topmost_window_id = get_window_state(&*top_most_window).borrow().id; + let topmost_window_id = get_window_state(&*top_most_window).borrow().handle; topmost_window_id == self_id } else { // Someone else's window is on top diff --git a/crates/gpui/src/platform/test.rs b/crates/gpui/src/platform/test.rs index f949a6cd78e90c3f4a0025fc5aaae5ad4d251d9a..6c11817b5c14171c6934c68acfd335c9b2790522 100644 --- a/crates/gpui/src/platform/test.rs +++ b/crates/gpui/src/platform/test.rs @@ -5,7 +5,7 @@ use crate::{ vector::{vec2f, Vector2F}, }, keymap_matcher::KeymapMatcher, - Action, ClipboardItem, Menu, + Action, AnyWindowHandle, ClipboardItem, Menu, }; use anyhow::{anyhow, Result}; use collections::VecDeque; @@ -102,7 +102,7 @@ pub struct Platform { fonts: Arc, current_clipboard_item: Mutex>, cursor: Mutex, - active_window_id: Arc>>, + active_window: Arc>>, } impl Platform { @@ -112,7 +112,7 @@ impl Platform { fonts: Arc::new(super::current::FontSystem::new()), current_clipboard_item: Default::default(), cursor: Mutex::new(CursorStyle::Arrow), - active_window_id: Default::default(), + active_window: Default::default(), } } } @@ -146,30 +146,30 @@ impl super::Platform for Platform { fn open_window( &self, - id: usize, + handle: AnyWindowHandle, options: super::WindowOptions, _executor: Rc, ) -> Box { - *self.active_window_id.lock() = Some(id); + *self.active_window.lock() = Some(handle); Box::new(Window::new( - id, + handle, match options.bounds { WindowBounds::Maximized | WindowBounds::Fullscreen => vec2f(1024., 768.), WindowBounds::Fixed(rect) => rect.size(), }, - self.active_window_id.clone(), + self.active_window.clone(), )) } - fn main_window_id(&self) -> Option { - self.active_window_id.lock().clone() + fn main_window(&self) -> Option { + self.active_window.lock().clone() } - fn add_status_item(&self, id: usize) -> Box { + fn add_status_item(&self, handle: AnyWindowHandle) -> Box { Box::new(Window::new( - id, + handle, vec2f(24., 24.), - self.active_window_id.clone(), + self.active_window.clone(), )) } @@ -256,7 +256,7 @@ impl super::Screen for Screen { } pub struct Window { - id: usize, + handle: AnyWindowHandle, pub(crate) size: Vector2F, scale_factor: f32, current_scene: Option, @@ -270,13 +270,17 @@ pub struct Window { pub(crate) title: Option, pub(crate) edited: bool, pub(crate) pending_prompts: RefCell>>, - active_window_id: Arc>>, + active_window: Arc>>, } impl Window { - pub fn new(id: usize, size: Vector2F, active_window_id: Arc>>) -> Self { + pub fn new( + handle: AnyWindowHandle, + size: Vector2F, + active_window: Arc>>, + ) -> Self { Self { - id, + handle, size, event_handlers: Default::default(), resize_handlers: Default::default(), @@ -290,7 +294,7 @@ impl Window { title: None, edited: false, pending_prompts: Default::default(), - active_window_id, + active_window, } } @@ -342,7 +346,7 @@ impl super::Window for Window { } fn activate(&self) { - *self.active_window_id.lock() = Some(self.id); + *self.active_window.lock() = Some(self.handle); } fn set_title(&mut self, title: &str) { From 8e49d1419a2ec3e832fc6716f2795305f35320df Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 8 Aug 2023 16:38:46 -0600 Subject: [PATCH 38/41] Minimize window id usage --- crates/gpui/src/app.rs | 58 +++++++++++++------------- crates/gpui/src/app/window.rs | 10 ++--- crates/gpui/src/platform/mac/window.rs | 6 +-- crates/theme/src/ui.rs | 1 - 4 files changed, 38 insertions(+), 37 deletions(-) diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index 507cbffad279553dea2612dbb9a898ab4358ae8b..8020147844d946ba7bb1ca307a6ee5df7445f4e3 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -477,10 +477,10 @@ pub struct AppContext { focus_observations: CallbackCollection, release_observations: CallbackCollection, action_dispatch_observations: CallbackCollection<(), ActionObservationCallback>, - window_activation_observations: CallbackCollection, - window_fullscreen_observations: CallbackCollection, - window_bounds_observations: CallbackCollection, - keystroke_observations: CallbackCollection, + window_activation_observations: CallbackCollection, + window_fullscreen_observations: CallbackCollection, + window_bounds_observations: CallbackCollection, + keystroke_observations: CallbackCollection, active_labeled_task_observations: CallbackCollection<(), ActiveLabeledTasksCallback>, foreground: Rc, @@ -1460,7 +1460,7 @@ impl AppContext { let mut refreshing = false; let mut updated_windows = HashSet::default(); - let mut focus_effects = HashMap::::default(); + let mut focus_effects = HashMap::::default(); loop { self.remove_dropped_entities(); if let Some(effect) = self.pending_effects.pop_front() { @@ -1538,13 +1538,13 @@ impl AppContext { Effect::Focus(mut effect) => { if focus_effects - .get(&effect.window().id()) + .get(&effect.window()) .map_or(false, |prev_effect| prev_effect.is_forced()) { effect.force(); } - focus_effects.insert(effect.window().id(), effect); + focus_effects.insert(effect.window(), effect); } Effect::FocusObservation { @@ -1577,7 +1577,7 @@ impl AppContext { subscription_id, callback, } => self.window_activation_observations.add_callback( - window.id(), + window, subscription_id, callback, ), @@ -1586,7 +1586,7 @@ impl AppContext { if self.handle_window_activation_effect(window, is_active) && is_active { focus_effects - .entry(window.id()) + .entry(window) .or_insert_with(|| FocusEffect::View { window, view_id: self @@ -1603,7 +1603,7 @@ impl AppContext { subscription_id, callback, } => self.window_fullscreen_observations.add_callback( - window.id(), + window, subscription_id, callback, ), @@ -1618,7 +1618,7 @@ impl AppContext { subscription_id, callback, } => self.window_bounds_observations.add_callback( - window.id(), + window, subscription_id, callback, ), @@ -1718,10 +1718,10 @@ impl AppContext { let root_view_id = cx.window.root_view().id(); if focused_view_id != root_view_id && !cx.views.contains_key(&(window, focused_view_id)) - && !focus_effects.contains_key(&window.id()) + && !focus_effects.contains_key(&window) { focus_effects.insert( - window.id(), + window, FocusEffect::View { window, view_id: Some(root_view_id), @@ -1860,12 +1860,12 @@ impl AppContext { cx.window.is_fullscreen = is_fullscreen; let mut fullscreen_observations = cx.window_fullscreen_observations.clone(); - fullscreen_observations.emit(window.id(), |callback| callback(is_fullscreen, cx)); + fullscreen_observations.emit(window, |callback| callback(is_fullscreen, cx)); if let Some(uuid) = cx.window_display_uuid() { let bounds = cx.window_bounds(); let mut bounds_observations = cx.window_bounds_observations.clone(); - bounds_observations.emit(window.id(), |callback| callback(bounds, uuid, cx)); + bounds_observations.emit(window, |callback| callback(bounds, uuid, cx)); } Some(()) @@ -1881,7 +1881,7 @@ impl AppContext { ) { self.update_window(window, |cx| { let mut observations = cx.keystroke_observations.clone(); - observations.emit(window.id(), move |callback| { + observations.emit(window, move |callback| { callback(&keystroke, &result, handled_by.as_ref(), cx) }); }); @@ -1895,7 +1895,7 @@ impl AppContext { cx.window.is_active = active; let mut observations = cx.window_activation_observations.clone(); - observations.emit(window.id(), |callback| callback(active, cx)); + observations.emit(window, |callback| callback(active, cx)); true }) .unwrap_or(false) @@ -1989,7 +1989,7 @@ impl AppContext { let bounds = cx.window_bounds(); cx.window_bounds_observations .clone() - .emit(window.id(), move |callback| { + .emit(window, move |callback| { callback(bounds, display, cx); true }); @@ -4038,12 +4038,12 @@ impl AnyWindowHandle { #[cfg(any(test, feature = "test-support"))] pub fn simulate_activation(&self, cx: &mut TestAppContext) { self.update(cx, |cx| { - let other_window_ids = cx + let other_windows = cx .windows() .filter(|window| *window != *self) .collect::>(); - for window in other_window_ids { + for window in other_windows { cx.window_changed_active_status(window, false) } @@ -4243,10 +4243,6 @@ impl AnyViewHandle { self.window } - pub fn window_id(&self) -> usize { - self.window.id() - } - pub fn id(&self) -> usize { self.view_id } @@ -4660,10 +4656,16 @@ pub enum Subscription { GlobalSubscription(callback_collection::Subscription), GlobalObservation(callback_collection::Subscription), FocusObservation(callback_collection::Subscription), - WindowActivationObservation(callback_collection::Subscription), - WindowFullscreenObservation(callback_collection::Subscription), - WindowBoundsObservation(callback_collection::Subscription), - KeystrokeObservation(callback_collection::Subscription), + WindowActivationObservation( + callback_collection::Subscription, + ), + WindowFullscreenObservation( + callback_collection::Subscription, + ), + WindowBoundsObservation( + callback_collection::Subscription, + ), + KeystrokeObservation(callback_collection::Subscription), ReleaseObservation(callback_collection::Subscription), ActionObservation(callback_collection::Subscription<(), ActionObservationCallback>), ActiveLabeledTasksObservation( diff --git a/crates/gpui/src/app/window.rs b/crates/gpui/src/app/window.rs index d39219e65d4b0f19e251676b0901b7a3019328d7..1012d7e77ecda14e9b1fcd98cfe6434a89da249c 100644 --- a/crates/gpui/src/app/window.rs +++ b/crates/gpui/src/app/window.rs @@ -326,7 +326,7 @@ impl<'a> WindowContext<'a> { }); Subscription::WindowActivationObservation( self.window_activation_observations - .subscribe(handle.id(), subscription_id), + .subscribe(handle, subscription_id), ) } @@ -344,7 +344,7 @@ impl<'a> WindowContext<'a> { }); Subscription::WindowActivationObservation( self.window_activation_observations - .subscribe(window.id(), subscription_id), + .subscribe(window, subscription_id), ) } @@ -362,7 +362,7 @@ impl<'a> WindowContext<'a> { }); Subscription::WindowBoundsObservation( self.window_bounds_observations - .subscribe(window.id(), subscription_id), + .subscribe(window, subscription_id), ) } @@ -374,10 +374,10 @@ impl<'a> WindowContext<'a> { let window = self.window_handle; let subscription_id = post_inc(&mut self.next_subscription_id); self.keystroke_observations - .add_callback(window.id(), subscription_id, Box::new(callback)); + .add_callback(window, subscription_id, Box::new(callback)); Subscription::KeystrokeObservation( self.keystroke_observations - .subscribe(window.id(), subscription_id), + .subscribe(window, subscription_id), ) } diff --git a/crates/gpui/src/platform/mac/window.rs b/crates/gpui/src/platform/mac/window.rs index 59324f473a97a4682efc277cce5b46e916a37b9a..2a722cad8293797a8dd54d6854729d4f0d2b44a3 100644 --- a/crates/gpui/src/platform/mac/window.rs +++ b/crates/gpui/src/platform/mac/window.rs @@ -882,7 +882,7 @@ impl platform::Window for Window { fn is_topmost_for_position(&self, position: Vector2F) -> bool { let self_borrow = self.0.borrow(); - let self_id = self_borrow.handle; + let self_handle = self_borrow.handle; unsafe { let app = NSApplication::sharedApplication(nil); @@ -899,8 +899,8 @@ impl platform::Window for Window { let is_panel: BOOL = msg_send![top_most_window, isKindOfClass: PANEL_CLASS]; let is_window: BOOL = msg_send![top_most_window, isKindOfClass: WINDOW_CLASS]; if is_panel == YES || is_window == YES { - let topmost_window_id = get_window_state(&*top_most_window).borrow().handle; - topmost_window_id == self_id + let topmost_window = get_window_state(&*top_most_window).borrow().handle; + topmost_window == self_handle } else { // Someone else's window is on top false diff --git a/crates/theme/src/ui.rs b/crates/theme/src/ui.rs index 308ea6f2d7b5e02c222a4e9f049ce58fa866e2bd..a16c3cb21e7631feab176dd33ce11fc48f126fec 100644 --- a/crates/theme/src/ui.rs +++ b/crates/theme/src/ui.rs @@ -192,7 +192,6 @@ where F: FnOnce(&mut gpui::ViewContext) -> D, { const TITLEBAR_HEIGHT: f32 = 28.; - // let active = cx.window_is_active(cx.window_id()); Flex::column() .with_child( From fc96676662f1dc9a06d08cdcf19993fc40c6c08e Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 8 Aug 2023 17:20:46 -0600 Subject: [PATCH 39/41] Use AppContext::update when updating windows so we handle effects --- crates/gpui/src/app.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index 8020147844d946ba7bb1ca307a6ee5df7445f4e3..8682e6c9dd6050b6586e64b9751d50d11bf924c4 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -2112,13 +2112,15 @@ impl BorrowWindowContext for AppContext { where F: FnOnce(&mut WindowContext) -> T, { - let mut window = self.windows.remove(&handle)?; - let mut window_context = WindowContext::mutable(self, &mut window, handle); - let result = f(&mut window_context); - if !window_context.removed { - self.windows.insert(handle, window); - } - Some(result) + self.update(|cx| { + let mut window = cx.windows.remove(&handle)?; + let mut window_context = WindowContext::mutable(cx, &mut window, handle); + let result = f(&mut window_context); + if !window_context.removed { + cx.windows.insert(handle, window); + } + Some(result) + }) } fn update_window_optional(&mut self, handle: AnyWindowHandle, f: F) -> Option From 0dc70e6cbf07e70c00c99aeab775410626c6a05a Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 8 Aug 2023 17:21:06 -0600 Subject: [PATCH 40/41] Rename mac platform Window to MacWindow for clarity --- crates/gpui/src/platform/mac.rs | 2 +- crates/gpui/src/platform/mac/platform.rs | 6 +++--- crates/gpui/src/platform/mac/window.rs | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/crates/gpui/src/platform/mac.rs b/crates/gpui/src/platform/mac.rs index 342c1c66d0cf424f95728db7065ea39fa8b79b64..92ab53f15e34dae90db9635d95eb6721c3a53ee6 100644 --- a/crates/gpui/src/platform/mac.rs +++ b/crates/gpui/src/platform/mac.rs @@ -21,7 +21,7 @@ pub use fonts::FontSystem; use platform::{MacForegroundPlatform, MacPlatform}; pub use renderer::Surface; use std::{ops::Range, rc::Rc, sync::Arc}; -use window::Window; +use window::MacWindow; use crate::executor; diff --git a/crates/gpui/src/platform/mac/platform.rs b/crates/gpui/src/platform/mac/platform.rs index 277ff8403f8df8ce96984c4a6fc896ad818df6f7..9a799c3a3a17767bb1be4fcdd9d7a7a217f52e11 100644 --- a/crates/gpui/src/platform/mac/platform.rs +++ b/crates/gpui/src/platform/mac/platform.rs @@ -1,6 +1,6 @@ use super::{ event::key_to_native, screen::Screen, status_item::StatusItem, BoolExt as _, Dispatcher, - FontSystem, Window, + FontSystem, MacWindow, }; use crate::{ executor, @@ -594,11 +594,11 @@ impl platform::Platform for MacPlatform { options: platform::WindowOptions, executor: Rc, ) -> Box { - Box::new(Window::open(handle, options, executor, self.fonts())) + Box::new(MacWindow::open(handle, options, executor, self.fonts())) } fn main_window(&self) -> Option { - Window::main_window() + MacWindow::main_window() } fn add_status_item(&self, _handle: AnyWindowHandle) -> Box { diff --git a/crates/gpui/src/platform/mac/window.rs b/crates/gpui/src/platform/mac/window.rs index 2a722cad8293797a8dd54d6854729d4f0d2b44a3..022346ea67b24e99a9644b9dce77b843d05a6fd0 100644 --- a/crates/gpui/src/platform/mac/window.rs +++ b/crates/gpui/src/platform/mac/window.rs @@ -423,9 +423,9 @@ impl WindowState { } } -pub struct Window(Rc>); +pub struct MacWindow(Rc>); -impl Window { +impl MacWindow { pub fn open( handle: AnyWindowHandle, options: platform::WindowOptions, @@ -636,7 +636,7 @@ impl Window { } } -impl Drop for Window { +impl Drop for MacWindow { fn drop(&mut self) { let this = self.0.borrow(); let window = this.native_window; @@ -650,7 +650,7 @@ impl Drop for Window { } } -impl platform::Window for Window { +impl platform::Window for MacWindow { fn bounds(&self) -> WindowBounds { self.0.as_ref().borrow().bounds() } From c523ccc4c7cd5739e465a194a4b621840a1cd021 Mon Sep 17 00:00:00 2001 From: "Joseph T. Lyons" Date: Tue, 8 Aug 2023 18:42:38 -0400 Subject: [PATCH 41/41] Fix code that identifies language via extension --- crates/language/src/language.rs | 4 +-- crates/util/src/paths.rs | 37 +++++++++++++++++++++-- crates/zed/src/languages/bash/config.toml | 2 +- 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/crates/language/src/language.rs b/crates/language/src/language.rs index 100ab275717066251973c3f6d547e32f72ff0b4c..223f5679aed05c8a5fee158f3a14959133c9151e 100644 --- a/crates/language/src/language.rs +++ b/crates/language/src/language.rs @@ -45,7 +45,7 @@ use syntax_map::SyntaxSnapshot; use theme::{SyntaxTheme, Theme}; use tree_sitter::{self, Query}; use unicase::UniCase; -use util::http::HttpClient; +use util::{http::HttpClient, paths::PathExt}; use util::{merge_json_value_into, post_inc, ResultExt, TryFutureExt as _, UnwrapFuture}; #[cfg(any(test, feature = "test-support"))] @@ -777,7 +777,7 @@ impl LanguageRegistry { ) -> UnwrapFuture>>> { let path = path.as_ref(); let filename = path.file_name().and_then(|name| name.to_str()); - let extension = path.extension().and_then(|name| name.to_str()); + let extension = path.extension_or_hidden_file_name(); let path_suffixes = [extension, filename]; self.get_or_load_language(|config| { let path_matches = config diff --git a/crates/util/src/paths.rs b/crates/util/src/paths.rs index f231669197fcfdd560011132e406772da64e3050..e7e6e0ac727da64de4f21306ddf88f3ee26134f9 100644 --- a/crates/util/src/paths.rs +++ b/crates/util/src/paths.rs @@ -33,6 +33,7 @@ pub mod legacy { pub trait PathExt { fn compact(&self) -> PathBuf; fn icon_suffix(&self) -> Option<&str>; + fn extension_or_hidden_file_name(&self) -> Option<&str>; } impl> PathExt for T { @@ -60,6 +61,7 @@ impl> PathExt for T { } } + /// Returns a suffix of the path that is used to determine which file icon to use fn icon_suffix(&self) -> Option<&str> { let file_name = self.as_ref().file_name()?.to_str()?; @@ -69,8 +71,16 @@ impl> PathExt for T { self.as_ref() .extension() - .map(|extension| extension.to_str()) - .flatten() + .and_then(|extension| extension.to_str()) + } + + /// Returns a file's extension or, if the file is hidden, its name without the leading dot + fn extension_or_hidden_file_name(&self) -> Option<&str> { + if let Some(extension) = self.as_ref().extension() { + return extension.to_str(); + } + + self.as_ref().file_name()?.to_str()?.split('.').last() } } @@ -315,4 +325,27 @@ mod tests { let path = Path::new("/a/b/c/.eslintrc.js"); assert_eq!(path.icon_suffix(), Some("eslintrc.js")); } + + #[test] + fn test_extension_or_hidden_file_name() { + // No dots in name + let path = Path::new("/a/b/c/file_name.rs"); + assert_eq!(path.extension_or_hidden_file_name(), Some("rs")); + + // Single dot in name + let path = Path::new("/a/b/c/file.name.rs"); + assert_eq!(path.extension_or_hidden_file_name(), Some("rs")); + + // Multiple dots in name + let path = Path::new("/a/b/c/long.file.name.rs"); + assert_eq!(path.extension_or_hidden_file_name(), Some("rs")); + + // Hidden file, no extension + let path = Path::new("/a/b/c/.gitignore"); + assert_eq!(path.extension_or_hidden_file_name(), Some("gitignore")); + + // Hidden file, with extension + let path = Path::new("/a/b/c/.eslintrc.js"); + assert_eq!(path.extension_or_hidden_file_name(), Some("js")); + } } diff --git a/crates/zed/src/languages/bash/config.toml b/crates/zed/src/languages/bash/config.toml index d03897a071d78c55c48ac97c4e829c7d2e05db1f..8c4513b2509fced29f2680186993343b4d0ac414 100644 --- a/crates/zed/src/languages/bash/config.toml +++ b/crates/zed/src/languages/bash/config.toml @@ -1,5 +1,5 @@ name = "Shell Script" -path_suffixes = ["sh", "bash", "bashrc", "bash_profile", "bash_aliases", "bash_logout", "profile", "zsh", "zshrc", "zshenv", "zsh_profile", "zsh_aliases", "zsh_histfile", "zlogin"] +path_suffixes = ["sh", "bash", "bashrc", "bash_profile", "bash_aliases", "bash_logout", "profile", "zsh", "zshrc", "zshenv", "zsh_profile", "zsh_aliases", "zsh_histfile", "zlogin", "zprofile"] line_comment = "# " first_line_pattern = "^#!.*\\b(?:ba|z)?sh\\b" brackets = [