From 86247bf657b3643cd81999c95f1cfb6c43c3f999 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Mon, 5 Jun 2023 15:48:36 +0200 Subject: [PATCH 001/104] editor: Highlight search results Z-1292 --- assets/settings/default.json | 4 +- crates/editor/src/editor_settings.rs | 2 + crates/editor/src/element.rs | 47 ++- crates/theme/src/theme.rs | 1 + styles/src/styleTree/editor.ts | 507 ++++++++++++++------------- 5 files changed, 305 insertions(+), 256 deletions(-) diff --git a/assets/settings/default.json b/assets/settings/default.json index bd73bcbf08032946736159393e8385107f5873d1..8576c1ed6535303e187ae094a5ffa761fd80c4fd 100644 --- a/assets/settings/default.json +++ b/assets/settings/default.json @@ -71,7 +71,9 @@ // "never" "show": "auto", // Whether to show git diff indicators in the scrollbar. - "git_diff": true + "git_diff": true, + // Whether to show selections in the scrollbar. + "selections": true }, "project_panel": { // Whether to show the git status in the project panel. diff --git a/crates/editor/src/editor_settings.rs b/crates/editor/src/editor_settings.rs index 387d4d2c340d2a3bb5b648d8232880de2d8f7fe1..f4499b5651cc158c66df3faad7f0ecf707e01bb6 100644 --- a/crates/editor/src/editor_settings.rs +++ b/crates/editor/src/editor_settings.rs @@ -15,6 +15,7 @@ pub struct EditorSettings { pub struct Scrollbar { pub show: ShowScrollbar, pub git_diff: bool, + pub selections: bool, } #[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] @@ -39,6 +40,7 @@ pub struct EditorSettingsContent { pub struct ScrollbarContent { pub show: Option, pub git_diff: Option, + pub selections: Option, } impl Setting for EditorSettings { diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index d6f9a2e90682f72d33d06ee1b37d813e35764094..5f7843f721dc133cc1fb234a88bbcb1e8b7cb705 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -1008,6 +1008,7 @@ impl EditorElement { bounds: RectF, layout: &mut LayoutState, cx: &mut ViewContext, + editor: &Editor, ) { enum ScrollbarMouseHandlers {} if layout.mode != EditorMode::Full { @@ -1050,9 +1051,49 @@ impl EditorElement { background: style.track.background_color, ..Default::default() }); + let scrollbar_settings = settings::get::(cx).scrollbar; + let theme = theme::current(cx); + let scrollbar_theme = &theme.editor.scrollbar; + if layout.is_singleton && scrollbar_settings.selections { + let start_anchor = Anchor::min(); + let end_anchor = Anchor::max(); + for (row, _) in &editor.background_highlights_in_range( + start_anchor..end_anchor, + &layout.position_map.snapshot, + &theme, + ) { + let start_display = row.start; + let end_display = row.end; + let start_y = y_for_row(start_display.row() as f32); + let mut end_y = y_for_row((end_display.row()) as f32); + if end_y - start_y < 1. { + end_y = start_y + 1.; + } + let bounds = RectF::from_points(vec2f(left, start_y), vec2f(right, end_y)); + + let color = scrollbar_theme.selections; + + let border = Border { + width: 1., + color: style.thumb.border.color, + overlay: false, + top: false, + right: true, + bottom: false, + left: true, + }; + + scene.push_quad(Quad { + bounds, + background: Some(color), + border, + corner_radius: style.thumb.corner_radius, + }) + } + } - if layout.is_singleton && settings::get::(cx).scrollbar.git_diff { - let diff_style = theme::current(cx).editor.scrollbar.git.clone(); + if layout.is_singleton && scrollbar_settings.git_diff { + let diff_style = scrollbar_theme.git.clone(); for hunk in layout .position_map .snapshot @@ -2359,7 +2400,7 @@ impl Element for EditorElement { if !layout.blocks.is_empty() { self.paint_blocks(scene, bounds, visible_bounds, layout, editor, cx); } - self.paint_scrollbar(scene, bounds, layout, cx); + self.paint_scrollbar(scene, bounds, layout, cx, &editor); scene.pop_layer(); scene.pop_layer(); diff --git a/crates/theme/src/theme.rs b/crates/theme/src/theme.rs index c7563ec87a3dfd20f3f2682a2a6e9848cecf5279..95d6348c626aafc28a032716eede382b62e0019f 100644 --- a/crates/theme/src/theme.rs +++ b/crates/theme/src/theme.rs @@ -700,6 +700,7 @@ pub struct Scrollbar { pub width: f32, pub min_height_factor: f32, pub git: GitDiffColors, + pub selections: Color, } #[derive(Clone, Deserialize, Default)] diff --git a/styles/src/styleTree/editor.ts b/styles/src/styleTree/editor.ts index 55f3da6e900f79a0f02f936b73dde9c376043027..859f9fe1b9345df04c8d40821e76743e899c0ef1 100644 --- a/styles/src/styleTree/editor.ts +++ b/styles/src/styleTree/editor.ts @@ -6,273 +6,276 @@ import hoverPopover from "./hoverPopover" import { buildSyntax } from "../theme/syntax" export default function editor(colorScheme: ColorScheme) { - const { isLight } = colorScheme + const { isLight } = colorScheme - let layer = colorScheme.highest + let layer = colorScheme.highest - const autocompleteItem = { - cornerRadius: 6, - padding: { - bottom: 2, - left: 6, - right: 6, - top: 2, - }, - } + const autocompleteItem = { + cornerRadius: 6, + padding: { + bottom: 2, + left: 6, + right: 6, + top: 2, + }, + } - function diagnostic(layer: Layer, styleSet: StyleSets) { - return { - textScaleFactor: 0.857, - header: { - border: border(layer, { - top: true, - }), - }, - message: { - text: text(layer, "sans", styleSet, "default", { size: "sm" }), - highlightText: text(layer, "sans", styleSet, "default", { - size: "sm", - weight: "bold", - }), - }, - } + function diagnostic(layer: Layer, styleSet: StyleSets) { + return { + textScaleFactor: 0.857, + header: { + border: border(layer, { + top: true, + }), + }, + message: { + text: text(layer, "sans", styleSet, "default", { size: "sm" }), + highlightText: text(layer, "sans", styleSet, "default", { + size: "sm", + weight: "bold", + }), + }, } + } - const syntax = buildSyntax(colorScheme) + const syntax = buildSyntax(colorScheme) - return { - textColor: syntax.primary.color, - background: background(layer), - activeLineBackground: withOpacity(background(layer, "on"), 0.75), - highlightedLineBackground: background(layer, "on"), - // Inline autocomplete suggestions, Co-pilot suggestions, etc. - suggestion: syntax.predictive, - codeActions: { - indicator: { - color: foreground(layer, "variant"), + return { + textColor: syntax.primary.color, + background: background(layer), + activeLineBackground: withOpacity(background(layer, "on"), 0.75), + highlightedLineBackground: background(layer, "on"), + // Inline autocomplete suggestions, Co-pilot suggestions, etc. + suggestion: syntax.predictive, + codeActions: { + indicator: { + color: foreground(layer, "variant"), - clicked: { - color: foreground(layer, "base"), - }, - hover: { - color: foreground(layer, "on"), - }, - active: { - color: foreground(layer, "on"), - }, - }, - verticalScale: 0.55, + clicked: { + color: foreground(layer, "base"), }, - folds: { - iconMarginScale: 2.5, - foldedIcon: "icons/chevron_right_8.svg", - foldableIcon: "icons/chevron_down_8.svg", - indicator: { - color: foreground(layer, "variant"), - - clicked: { - color: foreground(layer, "base"), - }, - hover: { - color: foreground(layer, "on"), - }, - active: { - color: foreground(layer, "on"), - }, - }, - ellipses: { - textColor: colorScheme.ramps.neutral(0.71).hex(), - cornerRadiusFactor: 0.15, - background: { - // Copied from hover_popover highlight - color: colorScheme.ramps.neutral(0.5).alpha(0.0).hex(), - - hover: { - color: colorScheme.ramps.neutral(0.5).alpha(0.5).hex(), - }, - - clicked: { - color: colorScheme.ramps.neutral(0.5).alpha(0.7).hex(), - }, - }, - }, - foldBackground: foreground(layer, "variant"), + hover: { + color: foreground(layer, "on"), }, - diff: { - deleted: isLight - ? colorScheme.ramps.red(0.5).hex() - : colorScheme.ramps.red(0.4).hex(), - modified: isLight - ? colorScheme.ramps.yellow(0.5).hex() - : colorScheme.ramps.yellow(0.5).hex(), - inserted: isLight - ? colorScheme.ramps.green(0.4).hex() - : colorScheme.ramps.green(0.5).hex(), - removedWidthEm: 0.275, - widthEm: 0.15, - cornerRadius: 0.05, + active: { + color: foreground(layer, "on"), }, - /** Highlights matching occurrences of what is under the cursor - * as well as matched brackets - */ - documentHighlightReadBackground: withOpacity( - foreground(layer, "accent"), - 0.1 - ), - documentHighlightWriteBackground: colorScheme.ramps - .neutral(0.5) - .alpha(0.4) - .hex(), // TODO: This was blend * 2 - errorColor: background(layer, "negative"), - gutterBackground: background(layer), - gutterPaddingFactor: 3.5, - lineNumber: withOpacity(foreground(layer), 0.35), - lineNumberActive: foreground(layer), - renameFade: 0.6, - unnecessaryCodeFade: 0.5, - selection: colorScheme.players[0], - whitespace: colorScheme.ramps.neutral(0.5).hex(), - guestSelections: [ - colorScheme.players[1], - colorScheme.players[2], - colorScheme.players[3], - colorScheme.players[4], - colorScheme.players[5], - colorScheme.players[6], - colorScheme.players[7], - ], - autocomplete: { - background: background(colorScheme.middle), - cornerRadius: 8, - padding: 4, - margin: { - left: -14, - }, - border: border(colorScheme.middle), - shadow: colorScheme.popoverShadow, - matchHighlight: foreground(colorScheme.middle, "accent"), - item: autocompleteItem, - hoveredItem: { - ...autocompleteItem, - matchHighlight: foreground( - colorScheme.middle, - "accent", - "hovered" - ), - background: background(colorScheme.middle, "hovered"), - }, - selectedItem: { - ...autocompleteItem, - matchHighlight: foreground( - colorScheme.middle, - "accent", - "active" - ), - background: background(colorScheme.middle, "active"), - }, + }, + verticalScale: 0.55, + }, + folds: { + iconMarginScale: 2.5, + foldedIcon: "icons/chevron_right_8.svg", + foldableIcon: "icons/chevron_down_8.svg", + indicator: { + color: foreground(layer, "variant"), + + clicked: { + color: foreground(layer, "base"), }, - diagnosticHeader: { - background: background(colorScheme.middle), - iconWidthFactor: 1.5, - textScaleFactor: 0.857, - border: border(colorScheme.middle, { - bottom: true, - top: true, - }), - code: { - ...text(colorScheme.middle, "mono", { size: "sm" }), - margin: { - left: 10, - }, - }, - source: { - text: text(colorScheme.middle, "sans", { - size: "sm", - weight: "bold", - }), - }, - message: { - highlightText: text(colorScheme.middle, "sans", { - size: "sm", - weight: "bold", - }), - text: text(colorScheme.middle, "sans", { size: "sm" }), - }, + hover: { + color: foreground(layer, "on"), }, - diagnosticPathHeader: { - background: background(colorScheme.middle), - textScaleFactor: 0.857, - filename: text(colorScheme.middle, "mono", { size: "sm" }), - path: { - ...text(colorScheme.middle, "mono", { size: "sm" }), - margin: { - left: 12, - }, - }, + active: { + color: foreground(layer, "on"), }, - errorDiagnostic: diagnostic(colorScheme.middle, "negative"), - warningDiagnostic: diagnostic(colorScheme.middle, "warning"), - informationDiagnostic: diagnostic(colorScheme.middle, "accent"), - hintDiagnostic: diagnostic(colorScheme.middle, "warning"), - invalidErrorDiagnostic: diagnostic(colorScheme.middle, "base"), - invalidHintDiagnostic: diagnostic(colorScheme.middle, "base"), - invalidInformationDiagnostic: diagnostic(colorScheme.middle, "base"), - invalidWarningDiagnostic: diagnostic(colorScheme.middle, "base"), - hoverPopover: hoverPopover(colorScheme), - linkDefinition: { - color: syntax.linkUri.color, - underline: syntax.linkUri.underline, + }, + ellipses: { + textColor: colorScheme.ramps.neutral(0.71).hex(), + cornerRadiusFactor: 0.15, + background: { + // Copied from hover_popover highlight + color: colorScheme.ramps.neutral(0.5).alpha(0.0).hex(), + + hover: { + color: colorScheme.ramps.neutral(0.5).alpha(0.5).hex(), + }, + + clicked: { + color: colorScheme.ramps.neutral(0.5).alpha(0.7).hex(), + }, }, - jumpIcon: { - color: foreground(layer, "on"), - iconWidth: 20, - buttonWidth: 20, - cornerRadius: 6, - padding: { - top: 6, - bottom: 6, - left: 6, - right: 6, - }, - hover: { - background: background(layer, "on", "hovered"), - }, + }, + foldBackground: foreground(layer, "variant"), + }, + diff: { + deleted: isLight + ? colorScheme.ramps.red(0.5).hex() + : colorScheme.ramps.red(0.4).hex(), + modified: isLight + ? colorScheme.ramps.yellow(0.5).hex() + : colorScheme.ramps.yellow(0.5).hex(), + inserted: isLight + ? colorScheme.ramps.green(0.4).hex() + : colorScheme.ramps.green(0.5).hex(), + removedWidthEm: 0.275, + widthEm: 0.15, + cornerRadius: 0.05, + }, + /** Highlights matching occurrences of what is under the cursor + * as well as matched brackets + */ + documentHighlightReadBackground: withOpacity( + foreground(layer, "accent"), + 0.1 + ), + documentHighlightWriteBackground: colorScheme.ramps + .neutral(0.5) + .alpha(0.4) + .hex(), // TODO: This was blend * 2 + errorColor: background(layer, "negative"), + gutterBackground: background(layer), + gutterPaddingFactor: 3.5, + lineNumber: withOpacity(foreground(layer), 0.35), + lineNumberActive: foreground(layer), + renameFade: 0.6, + unnecessaryCodeFade: 0.5, + selection: colorScheme.players[0], + whitespace: colorScheme.ramps.neutral(0.5).hex(), + guestSelections: [ + colorScheme.players[1], + colorScheme.players[2], + colorScheme.players[3], + colorScheme.players[4], + colorScheme.players[5], + colorScheme.players[6], + colorScheme.players[7], + ], + autocomplete: { + background: background(colorScheme.middle), + cornerRadius: 8, + padding: 4, + margin: { + left: -14, + }, + border: border(colorScheme.middle), + shadow: colorScheme.popoverShadow, + matchHighlight: foreground(colorScheme.middle, "accent"), + item: autocompleteItem, + hoveredItem: { + ...autocompleteItem, + matchHighlight: foreground( + colorScheme.middle, + "accent", + "hovered" + ), + background: background(colorScheme.middle, "hovered"), + }, + selectedItem: { + ...autocompleteItem, + matchHighlight: foreground( + colorScheme.middle, + "accent", + "active" + ), + background: background(colorScheme.middle, "active"), + }, + }, + diagnosticHeader: { + background: background(colorScheme.middle), + iconWidthFactor: 1.5, + textScaleFactor: 0.857, + border: border(colorScheme.middle, { + bottom: true, + top: true, + }), + code: { + ...text(colorScheme.middle, "mono", { size: "sm" }), + margin: { + left: 10, }, - scrollbar: { - width: 12, - minHeightFactor: 1.0, - track: { - border: border(layer, "variant", { left: true }), - }, - thumb: { - background: withOpacity(background(layer, "inverted"), 0.3), - border: { - width: 1, - color: borderColor(layer, "variant"), - top: false, - right: true, - left: true, - bottom: false, - }, - }, - git: { - deleted: isLight - ? withOpacity(colorScheme.ramps.red(0.5).hex(), 0.8) - : withOpacity(colorScheme.ramps.red(0.4).hex(), 0.8), - modified: isLight - ? withOpacity(colorScheme.ramps.yellow(0.5).hex(), 0.8) - : withOpacity(colorScheme.ramps.yellow(0.4).hex(), 0.8), - inserted: isLight - ? withOpacity(colorScheme.ramps.green(0.5).hex(), 0.8) - : withOpacity(colorScheme.ramps.green(0.4).hex(), 0.8), - }, + }, + source: { + text: text(colorScheme.middle, "sans", { + size: "sm", + weight: "bold", + }), + }, + message: { + highlightText: text(colorScheme.middle, "sans", { + size: "sm", + weight: "bold", + }), + text: text(colorScheme.middle, "sans", { size: "sm" }), + }, + }, + diagnosticPathHeader: { + background: background(colorScheme.middle), + textScaleFactor: 0.857, + filename: text(colorScheme.middle, "mono", { size: "sm" }), + path: { + ...text(colorScheme.middle, "mono", { size: "sm" }), + margin: { + left: 12, }, - compositionMark: { - underline: { - thickness: 1.0, - color: borderColor(layer), - }, + }, + }, + errorDiagnostic: diagnostic(colorScheme.middle, "negative"), + warningDiagnostic: diagnostic(colorScheme.middle, "warning"), + informationDiagnostic: diagnostic(colorScheme.middle, "accent"), + hintDiagnostic: diagnostic(colorScheme.middle, "warning"), + invalidErrorDiagnostic: diagnostic(colorScheme.middle, "base"), + invalidHintDiagnostic: diagnostic(colorScheme.middle, "base"), + invalidInformationDiagnostic: diagnostic(colorScheme.middle, "base"), + invalidWarningDiagnostic: diagnostic(colorScheme.middle, "base"), + hoverPopover: hoverPopover(colorScheme), + linkDefinition: { + color: syntax.linkUri.color, + underline: syntax.linkUri.underline, + }, + jumpIcon: { + color: foreground(layer, "on"), + iconWidth: 20, + buttonWidth: 20, + cornerRadius: 6, + padding: { + top: 6, + bottom: 6, + left: 6, + right: 6, + }, + hover: { + background: background(layer, "on", "hovered"), + }, + }, + scrollbar: { + width: 12, + minHeightFactor: 1.0, + track: { + border: border(layer, "variant", { left: true }), + }, + thumb: { + background: withOpacity(background(layer, "inverted"), 0.3), + border: { + width: 1, + color: borderColor(layer, "variant"), + top: false, + right: true, + left: true, + bottom: false, }, - syntax, - } + }, + git: { + deleted: isLight + ? withOpacity(colorScheme.ramps.red(0.5).hex(), 0.8) + : withOpacity(colorScheme.ramps.red(0.4).hex(), 0.8), + modified: isLight + ? withOpacity(colorScheme.ramps.yellow(0.5).hex(), 0.8) + : withOpacity(colorScheme.ramps.yellow(0.4).hex(), 0.8), + inserted: isLight + ? withOpacity(colorScheme.ramps.green(0.5).hex(), 0.8) + : withOpacity(colorScheme.ramps.green(0.4).hex(), 0.8), + }, + selections: isLight + ? withOpacity(colorScheme.ramps.blue(0.5).hex(), 0.8) + : withOpacity(colorScheme.ramps.blue(0.4).hex(), 0.8) + }, + compositionMark: { + underline: { + thickness: 1.0, + color: borderColor(layer), + }, + }, + syntax, + } } From 18dd3102bfbda57411153d215cae110ea8cd8617 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Wed, 28 Jun 2023 09:29:49 -0700 Subject: [PATCH 002/104] WIP: Add click out event to fix context menus --- crates/context_menu/src/context_menu.rs | 27 +++++++++++--------- crates/gpui/src/app/window.rs | 6 ++++- crates/gpui/src/scene/mouse_event.rs | 22 +++++++++++++++++ crates/gpui/src/scene/mouse_region.rs | 33 ++++++++++++++++++++++++- 4 files changed, 75 insertions(+), 13 deletions(-) diff --git a/crates/context_menu/src/context_menu.rs b/crates/context_menu/src/context_menu.rs index de78b51e9c071aadd28750c8f45b5d039c502a33..9bdf146da47e4f8e882cabbf0fd116b7f5676b7f 100644 --- a/crates/context_menu/src/context_menu.rs +++ b/crates/context_menu/src/context_menu.rs @@ -301,18 +301,23 @@ impl ContextMenu { cx: &mut ViewContext, ) { let mut items = items.into_iter().peekable(); - if items.peek().is_some() { - self.items = items.collect(); - self.anchor_position = anchor_position; - self.anchor_corner = anchor_corner; - self.visible = true; - self.show_count += 1; - if !cx.is_self_focused() { - self.previously_focused_view_id = cx.focused_view_id(); - } - cx.focus_self(); - } else { + dbg!(self.visible); + if (self.visible) { self.visible = false; + } else { + if items.peek().is_some() { + self.items = items.collect(); + self.anchor_position = anchor_position; + self.anchor_corner = anchor_corner; + self.visible = true; + self.show_count += 1; + if !cx.is_self_focused() { + self.previously_focused_view_id = cx.focused_view_id(); + } + cx.focus_self(); + } else { + self.visible = false; + } } cx.notify(); } diff --git a/crates/gpui/src/app/window.rs b/crates/gpui/src/app/window.rs index cffce6c3a6c646094f7247683def5d148c550138..cc6778c930c0fb7b8740738ca0c202be8a4d8fd2 100644 --- a/crates/gpui/src/app/window.rs +++ b/crates/gpui/src/app/window.rs @@ -9,7 +9,7 @@ use crate::{ }, scene::{ CursorRegion, MouseClick, MouseDown, MouseDownOut, MouseDrag, MouseEvent, MouseHover, - MouseMove, MouseMoveOut, MouseScrollWheel, MouseUp, MouseUpOut, Scene, + MouseMove, MouseMoveOut, MouseScrollWheel, MouseUp, MouseUpOut, Scene, MouseClickOut, }, text_layout::TextLayoutCache, util::post_inc, @@ -524,6 +524,10 @@ impl<'a> WindowContext<'a> { region: Default::default(), platform_event: e.clone(), })); + mouse_events.push(MouseEvent::ClickOut(MouseClickOut { + region: Default::default(), + platform_event: e.clone(), + })); } Event::MouseMoved( diff --git a/crates/gpui/src/scene/mouse_event.rs b/crates/gpui/src/scene/mouse_event.rs index cf0a08f33ed50ead5e5f4619cbb024603de780a9..a492da771b848574e29411e91d8876873ead4917 100644 --- a/crates/gpui/src/scene/mouse_event.rs +++ b/crates/gpui/src/scene/mouse_event.rs @@ -99,6 +99,20 @@ impl Deref for MouseClick { } } +#[derive(Debug, Default, Clone)] +pub struct MouseClickOut { + pub region: RectF, + pub platform_event: MouseButtonEvent, +} + +impl Deref for MouseClickOut { + type Target = MouseButtonEvent; + + fn deref(&self) -> &Self::Target { + &self.platform_event + } +} + #[derive(Debug, Default, Clone)] pub struct MouseDownOut { pub region: RectF, @@ -150,6 +164,7 @@ pub enum MouseEvent { Down(MouseDown), Up(MouseUp), Click(MouseClick), + ClickOut(MouseClickOut), DownOut(MouseDownOut), UpOut(MouseUpOut), ScrollWheel(MouseScrollWheel), @@ -165,6 +180,7 @@ impl MouseEvent { MouseEvent::Down(r) => r.region = region, MouseEvent::Up(r) => r.region = region, MouseEvent::Click(r) => r.region = region, + MouseEvent::ClickOut(r) => r.region = region, MouseEvent::DownOut(r) => r.region = region, MouseEvent::UpOut(r) => r.region = region, MouseEvent::ScrollWheel(r) => r.region = region, @@ -182,6 +198,7 @@ impl MouseEvent { MouseEvent::Down(_) => true, MouseEvent::Up(_) => true, MouseEvent::Click(_) => true, + MouseEvent::ClickOut(_) => true, MouseEvent::DownOut(_) => false, MouseEvent::UpOut(_) => false, MouseEvent::ScrollWheel(_) => true, @@ -222,6 +239,10 @@ impl MouseEvent { discriminant(&MouseEvent::Click(Default::default())) } + pub fn click_out_disc() -> Discriminant { + discriminant(&MouseEvent::ClickOut(Default::default())) + } + pub fn down_out_disc() -> Discriminant { discriminant(&MouseEvent::DownOut(Default::default())) } @@ -239,6 +260,7 @@ impl MouseEvent { MouseEvent::Down(e) => HandlerKey::new(Self::down_disc(), Some(e.button)), MouseEvent::Up(e) => HandlerKey::new(Self::up_disc(), Some(e.button)), MouseEvent::Click(e) => HandlerKey::new(Self::click_disc(), Some(e.button)), + MouseEvent::ClickOut(e) => HandlerKey::new(Self::click_out_disc(), Some(e.button)), MouseEvent::UpOut(e) => HandlerKey::new(Self::up_out_disc(), Some(e.button)), MouseEvent::DownOut(e) => HandlerKey::new(Self::down_out_disc(), Some(e.button)), MouseEvent::ScrollWheel(_) => HandlerKey::new(Self::scroll_wheel_disc(), None), diff --git a/crates/gpui/src/scene/mouse_region.rs b/crates/gpui/src/scene/mouse_region.rs index 0efc794148868c537eae37f4027ae8f23afa177c..7e1d5d6e1e4f12c0162607d3c4460fe37092a348 100644 --- a/crates/gpui/src/scene/mouse_region.rs +++ b/crates/gpui/src/scene/mouse_region.rs @@ -14,7 +14,7 @@ use super::{ MouseClick, MouseDown, MouseDownOut, MouseDrag, MouseEvent, MouseHover, MouseMove, MouseUp, MouseUpOut, }, - MouseMoveOut, MouseScrollWheel, + MouseMoveOut, MouseScrollWheel, MouseClickOut, }; #[derive(Clone)] @@ -89,6 +89,15 @@ impl MouseRegion { self } + pub fn on_click_out(mut self, button: MouseButton, handler: F) -> Self + where + V: View, + F: Fn(MouseClickOut, &mut V, &mut EventContext) + 'static, + { + self.handlers = self.handlers.on_click(button, handler); + self + } + pub fn on_down_out(mut self, button: MouseButton, handler: F) -> Self where V: View, @@ -405,6 +414,28 @@ impl HandlerSet { self } + pub fn on_click_out(mut self, button: MouseButton, handler: F) -> Self + where + V: View, + F: Fn(MouseClickOut, &mut V, &mut EventContext) + 'static, + { + self.insert(MouseEvent::click_out_disc(), Some(button), + Rc::new(move |region_event, view, cx, view_id| { + if let MouseEvent::ClickOut(e) = region_event { + let view = view.downcast_mut().unwrap(); + let mut cx = ViewContext::mutable(cx, view_id); + let mut cx = EventContext::new(&mut cx); + handler(e, view, &mut cx); + cx.handled + } else { + panic!( + "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::ClickOut, found {:?}", + region_event); + } + })); + self + } + pub fn on_down_out(mut self, button: MouseButton, handler: F) -> Self where V: View, From e0d618862c410741b65200ed3e7058184bef58d3 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Wed, 28 Jun 2023 16:23:07 -0700 Subject: [PATCH 003/104] Add click out handler Make all context menus on button click toggles instead of re-shows --- crates/context_menu/src/context_menu.rs | 31 ++++++++----------- crates/gpui/src/app/window.rs | 2 +- .../gpui/src/elements/mouse_event_handler.rs | 12 ++++++- crates/gpui/src/scene/mouse_region.rs | 6 +++- 4 files changed, 30 insertions(+), 21 deletions(-) diff --git a/crates/context_menu/src/context_menu.rs b/crates/context_menu/src/context_menu.rs index 9bdf146da47e4f8e882cabbf0fd116b7f5676b7f..a603b3578adb7aa86e657a327b35a4c2c40128cc 100644 --- a/crates/context_menu/src/context_menu.rs +++ b/crates/context_menu/src/context_menu.rs @@ -301,23 +301,18 @@ impl ContextMenu { cx: &mut ViewContext, ) { let mut items = items.into_iter().peekable(); - dbg!(self.visible); - if (self.visible) { - self.visible = false; - } else { - if items.peek().is_some() { - self.items = items.collect(); - self.anchor_position = anchor_position; - self.anchor_corner = anchor_corner; - self.visible = true; - self.show_count += 1; - if !cx.is_self_focused() { - self.previously_focused_view_id = cx.focused_view_id(); - } - cx.focus_self(); - } else { - self.visible = false; + if items.peek().is_some() { + self.items = items.collect(); + self.anchor_position = anchor_position; + self.anchor_corner = anchor_corner; + self.visible = true; + self.show_count += 1; + if !cx.is_self_focused() { + self.previously_focused_view_id = cx.focused_view_id(); } + cx.focus_self(); + } else { + self.visible = false; } cx.notify(); } @@ -482,10 +477,10 @@ impl ContextMenu { .contained() .with_style(style.container) }) - .on_down_out(MouseButton::Left, |_, this, cx| { + .on_click_out(MouseButton::Left, |_, this, cx| { this.cancel(&Default::default(), cx); }) - .on_down_out(MouseButton::Right, |_, this, cx| { + .on_click_out(MouseButton::Right, |_, this, cx| { this.cancel(&Default::default(), cx); }) } diff --git a/crates/gpui/src/app/window.rs b/crates/gpui/src/app/window.rs index cc6778c930c0fb7b8740738ca0c202be8a4d8fd2..5b15e62efac88815b79305560e842e6671b38fd8 100644 --- a/crates/gpui/src/app/window.rs +++ b/crates/gpui/src/app/window.rs @@ -716,7 +716,7 @@ impl<'a> WindowContext<'a> { } } - MouseEvent::MoveOut(_) | MouseEvent::UpOut(_) | MouseEvent::DownOut(_) => { + MouseEvent::MoveOut(_) | MouseEvent::UpOut(_) | MouseEvent::DownOut(_) | MouseEvent::ClickOut(_) => { for (mouse_region, _) in self.window.mouse_regions.iter().rev() { // NOT contains if !mouse_region diff --git a/crates/gpui/src/elements/mouse_event_handler.rs b/crates/gpui/src/elements/mouse_event_handler.rs index 6f2762db66144f1099bd05cee01be43f399b0141..03f481b071af9d9f8d09f01c60a4e1478770ebe9 100644 --- a/crates/gpui/src/elements/mouse_event_handler.rs +++ b/crates/gpui/src/elements/mouse_event_handler.rs @@ -8,7 +8,7 @@ use crate::{ platform::MouseButton, scene::{ CursorRegion, HandlerSet, MouseClick, MouseDown, MouseDownOut, MouseDrag, MouseHover, - MouseMove, MouseMoveOut, MouseScrollWheel, MouseUp, MouseUpOut, + MouseMove, MouseMoveOut, MouseScrollWheel, MouseUp, MouseUpOut, MouseClickOut, }, AnyElement, Element, EventContext, LayoutContext, MouseRegion, MouseState, SceneBuilder, SizeConstraint, View, ViewContext, @@ -136,6 +136,16 @@ impl MouseEventHandler { self } + pub fn on_click_out( + mut self, + button: MouseButton, + handler: impl Fn(MouseClickOut, &mut V, &mut EventContext) + 'static, + ) -> Self { + self.handlers = self.handlers.on_click_out(button, handler); + self + } + + pub fn on_down_out( mut self, button: MouseButton, diff --git a/crates/gpui/src/scene/mouse_region.rs b/crates/gpui/src/scene/mouse_region.rs index 7e1d5d6e1e4f12c0162607d3c4460fe37092a348..3576529eecd4ba50321bb51660346f8246a6adc0 100644 --- a/crates/gpui/src/scene/mouse_region.rs +++ b/crates/gpui/src/scene/mouse_region.rs @@ -94,7 +94,7 @@ impl MouseRegion { V: View, F: Fn(MouseClickOut, &mut V, &mut EventContext) + 'static, { - self.handlers = self.handlers.on_click(button, handler); + self.handlers = self.handlers.on_click_out(button, handler); self } @@ -255,6 +255,10 @@ impl HandlerSet { HandlerKey::new(MouseEvent::click_disc(), Some(button)), SmallVec::from_buf([Rc::new(|_, _, _, _| true)]), ); + set.insert( + HandlerKey::new(MouseEvent::click_out_disc(), Some(button)), + SmallVec::from_buf([Rc::new(|_, _, _, _| true)]), + ); set.insert( HandlerKey::new(MouseEvent::down_out_disc(), Some(button)), SmallVec::from_buf([Rc::new(|_, _, _, _| true)]), From 6ffa6afd20c693dadcc0cd5ca733c809cf465e7e Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Wed, 28 Jun 2023 16:35:57 -0700 Subject: [PATCH 004/104] fmt --- crates/gpui/src/app/window.rs | 9 ++++++--- crates/gpui/src/elements/mouse_event_handler.rs | 5 ++--- crates/gpui/src/scene/mouse_region.rs | 2 +- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/crates/gpui/src/app/window.rs b/crates/gpui/src/app/window.rs index 5b15e62efac88815b79305560e842e6671b38fd8..23fbb33fe142fc8c34eee86a7889fbeddd9bcc5a 100644 --- a/crates/gpui/src/app/window.rs +++ b/crates/gpui/src/app/window.rs @@ -8,8 +8,8 @@ use crate::{ MouseButton, MouseMovedEvent, PromptLevel, WindowBounds, }, scene::{ - CursorRegion, MouseClick, MouseDown, MouseDownOut, MouseDrag, MouseEvent, MouseHover, - MouseMove, MouseMoveOut, MouseScrollWheel, MouseUp, MouseUpOut, Scene, MouseClickOut, + CursorRegion, MouseClick, MouseClickOut, MouseDown, MouseDownOut, MouseDrag, MouseEvent, + MouseHover, MouseMove, MouseMoveOut, MouseScrollWheel, MouseUp, MouseUpOut, Scene, }, text_layout::TextLayoutCache, util::post_inc, @@ -716,7 +716,10 @@ impl<'a> WindowContext<'a> { } } - MouseEvent::MoveOut(_) | MouseEvent::UpOut(_) | MouseEvent::DownOut(_) | MouseEvent::ClickOut(_) => { + MouseEvent::MoveOut(_) + | MouseEvent::UpOut(_) + | MouseEvent::DownOut(_) + | MouseEvent::ClickOut(_) => { for (mouse_region, _) in self.window.mouse_regions.iter().rev() { // NOT contains if !mouse_region diff --git a/crates/gpui/src/elements/mouse_event_handler.rs b/crates/gpui/src/elements/mouse_event_handler.rs index 03f481b071af9d9f8d09f01c60a4e1478770ebe9..1b8142d96464ff7c9f30230510a13c58c6f08cb6 100644 --- a/crates/gpui/src/elements/mouse_event_handler.rs +++ b/crates/gpui/src/elements/mouse_event_handler.rs @@ -7,8 +7,8 @@ use crate::{ platform::CursorStyle, platform::MouseButton, scene::{ - CursorRegion, HandlerSet, MouseClick, MouseDown, MouseDownOut, MouseDrag, MouseHover, - MouseMove, MouseMoveOut, MouseScrollWheel, MouseUp, MouseUpOut, MouseClickOut, + CursorRegion, HandlerSet, MouseClick, MouseClickOut, MouseDown, MouseDownOut, MouseDrag, + MouseHover, MouseMove, MouseMoveOut, MouseScrollWheel, MouseUp, MouseUpOut, }, AnyElement, Element, EventContext, LayoutContext, MouseRegion, MouseState, SceneBuilder, SizeConstraint, View, ViewContext, @@ -145,7 +145,6 @@ impl MouseEventHandler { self } - pub fn on_down_out( mut self, button: MouseButton, diff --git a/crates/gpui/src/scene/mouse_region.rs b/crates/gpui/src/scene/mouse_region.rs index 3576529eecd4ba50321bb51660346f8246a6adc0..ca2cc04b9d1cf75c54ee9593705172f93c6f8ec4 100644 --- a/crates/gpui/src/scene/mouse_region.rs +++ b/crates/gpui/src/scene/mouse_region.rs @@ -14,7 +14,7 @@ use super::{ MouseClick, MouseDown, MouseDownOut, MouseDrag, MouseEvent, MouseHover, MouseMove, MouseUp, MouseUpOut, }, - MouseMoveOut, MouseScrollWheel, MouseClickOut, + MouseClickOut, MouseMoveOut, MouseScrollWheel, }; #[derive(Clone)] From 53666311733e591caf5b712ff10954fd40ea8c87 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Thu, 29 Jun 2023 17:10:51 -0700 Subject: [PATCH 005/104] Remove on_click_out handler from context menu Add 'delay_cancel()' method and on_down handler to relevant buttons --- crates/collab_ui/src/collab_titlebar_item.rs | 5 +- crates/context_menu/src/context_menu.rs | 58 ++++++++++++++++---- crates/copilot_button/src/copilot_button.rs | 7 ++- crates/terminal_view/src/terminal_element.rs | 21 +++---- crates/terminal_view/src/terminal_panel.rs | 2 + crates/workspace/src/pane.rs | 13 +++-- 6 files changed, 79 insertions(+), 27 deletions(-) diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index 2ab89281660b5750eb4028ce7a2ed87ccc46851a..5caebb9f0c033d9fda6aed87d155f4e1e5b9c655 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -317,7 +317,7 @@ impl CollabTitlebarItem { ), ] }; - user_menu.show(Default::default(), AnchorCorner::TopRight, items, cx); + user_menu.toggle(Default::default(), AnchorCorner::TopRight, items, cx); }); } @@ -683,6 +683,9 @@ impl CollabTitlebarItem { .into_any() }) .with_cursor_style(CursorStyle::PointingHand) + .on_down(MouseButton::Left, move |_, this, cx| { + this.user_menu.update(cx, |menu, _| menu.delay_cancel()); + }) .on_click(MouseButton::Left, move |_, this, cx| { this.toggle_user_menu(&Default::default(), cx) }) diff --git a/crates/context_menu/src/context_menu.rs b/crates/context_menu/src/context_menu.rs index a603b3578adb7aa86e657a327b35a4c2c40128cc..296f6bc04a35a72767b635f0047502d62a4556e5 100644 --- a/crates/context_menu/src/context_menu.rs +++ b/crates/context_menu/src/context_menu.rs @@ -124,6 +124,7 @@ pub struct ContextMenu { items: Vec, selected_index: Option, visible: bool, + delay_cancel: bool, previously_focused_view_id: Option, parent_view_id: usize, _actions_observation: Subscription, @@ -178,6 +179,7 @@ impl ContextMenu { pub fn new(parent_view_id: usize, cx: &mut ViewContext) -> Self { Self { show_count: 0, + delay_cancel: false, anchor_position: Default::default(), anchor_corner: AnchorCorner::TopLeft, position_mode: OverlayPositionMode::Window, @@ -232,15 +234,23 @@ impl ContextMenu { } } + pub fn delay_cancel(&mut self) { + self.delay_cancel = true; + } + fn cancel(&mut self, _: &Cancel, cx: &mut ViewContext) { - self.reset(cx); - let show_count = self.show_count; - cx.defer(move |this, cx| { - if cx.handle().is_focused(cx) && this.show_count == show_count { - let window_id = cx.window_id(); - (**cx).focus(window_id, this.previously_focused_view_id.take()); - } - }); + if !self.delay_cancel { + self.reset(cx); + let show_count = self.show_count; + cx.defer(move |this, cx| { + if cx.handle().is_focused(cx) && this.show_count == show_count { + let window_id = cx.window_id(); + (**cx).focus(window_id, this.previously_focused_view_id.take()); + } + }); + } else { + self.delay_cancel = false; + } } fn reset(&mut self, cx: &mut ViewContext) { @@ -293,6 +303,34 @@ impl ContextMenu { } } + pub fn toggle( + &mut self, + anchor_position: Vector2F, + anchor_corner: AnchorCorner, + items: Vec, + cx: &mut ViewContext, + ) { + if self.visible() { + self.cancel(&Cancel, cx); + } else { + let mut items = items.into_iter().peekable(); + if items.peek().is_some() { + self.items = items.collect(); + self.anchor_position = anchor_position; + self.anchor_corner = anchor_corner; + self.visible = true; + self.show_count += 1; + if !cx.is_self_focused() { + self.previously_focused_view_id = cx.focused_view_id(); + } + cx.focus_self(); + } else { + self.visible = false; + } + } + cx.notify(); + } + pub fn show( &mut self, anchor_position: Vector2F, @@ -477,10 +515,10 @@ impl ContextMenu { .contained() .with_style(style.container) }) - .on_click_out(MouseButton::Left, |_, this, cx| { + .on_down_out(MouseButton::Left, |_, this, cx| { this.cancel(&Default::default(), cx); }) - .on_click_out(MouseButton::Right, |_, this, cx| { + .on_down_out(MouseButton::Right, |_, this, cx| { this.cancel(&Default::default(), cx); }) } diff --git a/crates/copilot_button/src/copilot_button.rs b/crates/copilot_button/src/copilot_button.rs index 9b0581492f470a7d97988dc2c90b48ac63ddbc6d..5576451b1b0f1ac883ce0497f8df35a4fbcd245a 100644 --- a/crates/copilot_button/src/copilot_button.rs +++ b/crates/copilot_button/src/copilot_button.rs @@ -102,6 +102,9 @@ impl View for CopilotButton { } }) .with_cursor_style(CursorStyle::PointingHand) + .on_down(MouseButton::Left, |_, this, cx| { + this.popup_menu.update(cx, |menu, _| menu.delay_cancel()); + }) .on_click(MouseButton::Left, { let status = status.clone(); move |_, this, cx| match status { @@ -186,7 +189,7 @@ impl CopilotButton { })); self.popup_menu.update(cx, |menu, cx| { - menu.show( + menu.toggle( Default::default(), AnchorCorner::BottomRight, menu_options, @@ -266,7 +269,7 @@ impl CopilotButton { menu_options.push(ContextMenuItem::action("Sign Out", SignOut)); self.popup_menu.update(cx, |menu, cx| { - menu.show( + menu.toggle( Default::default(), AnchorCorner::BottomRight, menu_options, diff --git a/crates/terminal_view/src/terminal_element.rs b/crates/terminal_view/src/terminal_element.rs index 2f2ff2cdc3bde8bb5ee1c4a32978ed28518bd94f..b92059f5d605bc16c6578b254ce0431113cce200 100644 --- a/crates/terminal_view/src/terminal_element.rs +++ b/crates/terminal_view/src/terminal_element.rs @@ -395,16 +395,17 @@ impl TerminalElement { // Terminal Emulator controlled behavior: region = region // Start selections - .on_down( - MouseButton::Left, - TerminalElement::generic_button_handler( - connection, - origin, - move |terminal, origin, e, _cx| { - terminal.mouse_down(&e, origin); - }, - ), - ) + .on_down(MouseButton::Left, move |event, v: &mut TerminalView, cx| { + cx.focus_parent(); + v.context_menu.update(cx, |menu, _cx| menu.delay_cancel()); + if let Some(conn_handle) = connection.upgrade(cx) { + conn_handle.update(cx, |terminal, cx| { + terminal.mouse_down(&event, origin); + + cx.notify(); + }) + } + }) // Update drag selections .on_drag(MouseButton::Left, move |event, _: &mut TerminalView, cx| { if cx.is_self_focused() { diff --git a/crates/terminal_view/src/terminal_panel.rs b/crates/terminal_view/src/terminal_panel.rs index 6de6527a2617fae85ba1b1347cd9c3542c863994..11f8f7abde0509d970ebd65a972246e40ba2d05d 100644 --- a/crates/terminal_view/src/terminal_panel.rs +++ b/crates/terminal_view/src/terminal_panel.rs @@ -87,6 +87,7 @@ impl TerminalPanel { } }) }, + |_, _| {}, None, )) .with_child(Pane::render_tab_bar_button( @@ -100,6 +101,7 @@ impl TerminalPanel { Some(("Toggle Zoom".into(), Some(Box::new(workspace::ToggleZoom)))), cx, move |pane, cx| pane.toggle_zoom(&Default::default(), cx), + |_, _| {}, None, )) .into_any() diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index 9776fede2c3fb76c1639ba083ff9d3b0b6d06dca..e61e60d68f1babe60d9f826144b571666e6d8a77 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -273,6 +273,7 @@ impl Pane { Some(("New...".into(), None)), cx, |pane, cx| pane.deploy_new_menu(cx), + |pane, cx| pane.tab_bar_context_menu.handle.update(cx, |menu, _| menu.delay_cancel()), pane.tab_bar_context_menu .handle_if_kind(TabBarContextMenuKind::New), )) @@ -283,6 +284,7 @@ impl Pane { Some(("Split Pane".into(), None)), cx, |pane, cx| pane.deploy_split_menu(cx), + |pane, cx| pane.tab_bar_context_menu.handle.update(cx, |menu, _| menu.delay_cancel()), pane.tab_bar_context_menu .handle_if_kind(TabBarContextMenuKind::Split), )) @@ -304,6 +306,7 @@ impl Pane { Some((tooltip_label, Some(Box::new(ToggleZoom)))), cx, move |pane, cx| pane.toggle_zoom(&Default::default(), cx), + move |_, _| {}, None, ) }) @@ -988,7 +991,7 @@ impl Pane { fn deploy_split_menu(&mut self, cx: &mut ViewContext) { self.tab_bar_context_menu.handle.update(cx, |menu, cx| { - menu.show( + menu.toggle( Default::default(), AnchorCorner::TopRight, vec![ @@ -1006,7 +1009,7 @@ impl Pane { fn deploy_new_menu(&mut self, cx: &mut ViewContext) { self.tab_bar_context_menu.handle.update(cx, |menu, cx| { - menu.show( + menu.toggle( Default::default(), AnchorCorner::TopRight, vec![ @@ -1416,13 +1419,14 @@ impl Pane { .into_any() } - pub fn render_tab_bar_button)>( + pub fn render_tab_bar_button), F2: 'static + Fn(&mut Pane, &mut EventContext)>( index: usize, icon: &'static str, is_active: bool, tooltip: Option<(String, Option>)>, cx: &mut ViewContext, - on_click: F, + on_click: F1, + on_down: F2, context_menu: Option>, ) -> AnyElement { enum TabBarButton {} @@ -1440,6 +1444,7 @@ impl Pane { .with_height(style.button_width) }) .with_cursor_style(CursorStyle::PointingHand) + .on_down(MouseButton::Left, move |_, pane, cx| on_down(pane, cx)) .on_click(MouseButton::Left, move |_, pane, cx| on_click(pane, cx)) .into_any(); if let Some((tooltip, action)) = tooltip { From 73b0f3b23d126a9f06eec8cbf3fbcd15a4c3745f Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Thu, 29 Jun 2023 17:19:35 -0700 Subject: [PATCH 006/104] fmt --- crates/workspace/src/pane.rs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index e61e60d68f1babe60d9f826144b571666e6d8a77..6a20fab9a275571bd52a55b804e7d6b6407016e6 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -273,7 +273,11 @@ impl Pane { Some(("New...".into(), None)), cx, |pane, cx| pane.deploy_new_menu(cx), - |pane, cx| pane.tab_bar_context_menu.handle.update(cx, |menu, _| menu.delay_cancel()), + |pane, cx| { + pane.tab_bar_context_menu + .handle + .update(cx, |menu, _| menu.delay_cancel()) + }, pane.tab_bar_context_menu .handle_if_kind(TabBarContextMenuKind::New), )) @@ -284,7 +288,11 @@ impl Pane { Some(("Split Pane".into(), None)), cx, |pane, cx| pane.deploy_split_menu(cx), - |pane, cx| pane.tab_bar_context_menu.handle.update(cx, |menu, _| menu.delay_cancel()), + |pane, cx| { + pane.tab_bar_context_menu + .handle + .update(cx, |menu, _| menu.delay_cancel()) + }, pane.tab_bar_context_menu .handle_if_kind(TabBarContextMenuKind::Split), )) @@ -1419,7 +1427,10 @@ impl Pane { .into_any() } - pub fn render_tab_bar_button), F2: 'static + Fn(&mut Pane, &mut EventContext)>( + pub fn render_tab_bar_button< + F1: 'static + Fn(&mut Pane, &mut EventContext), + F2: 'static + Fn(&mut Pane, &mut EventContext), + >( index: usize, icon: &'static str, is_active: bool, From 33f5248d4f6c2395f8633aa307571e3b69dc7ff6 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Wed, 21 Jun 2023 15:23:52 -0700 Subject: [PATCH 007/104] Add the ability to make new directories by adding slashes to a file name --- Cargo.lock | 1 + Cargo.toml | 1 + crates/collab/Cargo.toml | 2 +- crates/fs/src/fs.rs | 6 + crates/project/Cargo.toml | 2 +- crates/project/src/worktree.rs | 23 +++- crates/project/src/worktree_tests.rs | 77 +++++++++++ crates/project_panel/Cargo.toml | 1 + crates/project_panel/src/project_panel.rs | 152 +++++++++++++++++++++- crates/settings/Cargo.toml | 2 +- 10 files changed, 259 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a9b2e29ea02e186af4b2034db7ee2e4ceca51a78..3748f24933cc08a2ae0a0e951f515f1450066a23 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5033,6 +5033,7 @@ dependencies = [ "language", "menu", "postage", + "pretty_assertions", "project", "schemars", "serde", diff --git a/Cargo.toml b/Cargo.toml index 3f3953096eda1e0e05dad60b3507b1c0a0843295..26555f32cd843c8c880bf7d9d000402a490e88c0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -101,6 +101,7 @@ time = { version = "0.3", features = ["serde", "serde-well-known"] } toml = { version = "0.5" } tree-sitter = "0.20" unindent = { version = "0.1.7" } +pretty_assertions = "1.3.0" [patch.crates-io] tree-sitter = { git = "https://github.com/tree-sitter/tree-sitter", rev = "49226023693107fba9a1191136a4f47f38cdca73" } diff --git a/crates/collab/Cargo.toml b/crates/collab/Cargo.toml index a87234ded77bf2876d60e0ba9ca87008c2209fec..0c752a20472fcd1280f626fd40b9492c817021c9 100644 --- a/crates/collab/Cargo.toml +++ b/crates/collab/Cargo.toml @@ -67,7 +67,7 @@ fs = { path = "../fs", features = ["test-support"] } git = { path = "../git", features = ["test-support"] } live_kit_client = { path = "../live_kit_client", features = ["test-support"] } lsp = { path = "../lsp", features = ["test-support"] } -pretty_assertions = "1.3.0" +pretty_assertions = "*" project = { path = "../project", features = ["test-support"] } rpc = { path = "../rpc", features = ["test-support"] } settings = { path = "../settings", features = ["test-support"] } diff --git a/crates/fs/src/fs.rs b/crates/fs/src/fs.rs index 592e6c9a5318b09cb92e01be484d099dfa526c99..ec8a249ff4c4626e420f072a148b268831e61ba7 100644 --- a/crates/fs/src/fs.rs +++ b/crates/fs/src/fs.rs @@ -279,6 +279,9 @@ impl Fs for RealFs { async fn save(&self, path: &Path, text: &Rope, line_ending: LineEnding) -> Result<()> { let buffer_size = text.summary().len.min(10 * 1024); + if let Some(path) = path.parent() { + self.create_dir(path).await?; + } let file = smol::fs::File::create(path).await?; let mut writer = smol::io::BufWriter::with_capacity(buffer_size, file); for chunk in chunks(text, line_ending) { @@ -1077,6 +1080,9 @@ impl Fs for FakeFs { self.simulate_random_delay().await; let path = normalize_path(path); let content = chunks(text, line_ending).collect(); + if let Some(path) = path.parent() { + self.create_dir(path).await?; + } self.write_file_internal(path, content)?; Ok(()) } diff --git a/crates/project/Cargo.toml b/crates/project/Cargo.toml index d6578c87ba6232461750de71091383618164f48e..dbc0c617f28bf9b46ab855f59e6fd8274f1a0315 100644 --- a/crates/project/Cargo.toml +++ b/crates/project/Cargo.toml @@ -64,7 +64,7 @@ itertools = "0.10" [dev-dependencies] ctor.workspace = true env_logger.workspace = true -pretty_assertions = "1.3.0" +pretty_assertions = "*" client = { path = "../client", features = ["test-support"] } collections = { path = "../collections", features = ["test-support"] } db = { path = "../db", features = ["test-support"] } diff --git a/crates/project/src/worktree.rs b/crates/project/src/worktree.rs index 20e693770f45f686a880b5aebd542eb74a96202e..a0497fa6771adbf87802e32bb1c0f92e6eaaf6b8 100644 --- a/crates/project/src/worktree.rs +++ b/crates/project/src/worktree.rs @@ -1001,10 +1001,25 @@ impl LocalWorktree { cx.spawn(|this, mut cx| async move { write.await?; - this.update(&mut cx, |this, cx| { - this.as_local_mut().unwrap().refresh_entry(path, None, cx) - }) - .await + let (result, refreshes) = this.update(&mut cx, |this, cx| { + let mut refreshes = Vec::new(); + for path in path.ancestors().skip(1) { + refreshes.push(this.as_local_mut().unwrap().refresh_entry( + path.into(), + None, + cx, + )); + } + ( + this.as_local_mut().unwrap().refresh_entry(path, None, cx), + refreshes, + ) + }); + for refresh in refreshes { + refresh.await.log_err(); + } + + result.await }) } diff --git a/crates/project/src/worktree_tests.rs b/crates/project/src/worktree_tests.rs index f908d702eb22aeb7dfb02eb4300611b7d22fbd73..efc5f4236907df74cce34faebe5db534c5026c75 100644 --- a/crates/project/src/worktree_tests.rs +++ b/crates/project/src/worktree_tests.rs @@ -936,6 +936,83 @@ async fn test_create_directory_during_initial_scan(cx: &mut TestAppContext) { ); } +#[gpui::test] +async fn test_create_dir_all_on_create_entry(cx: &mut TestAppContext) { + let client_fake = cx.read(|cx| Client::new(FakeHttpClient::with_404_response(), cx)); + + let fs_fake = FakeFs::new(cx.background()); + fs_fake.insert_tree( + "/root", + json!({ + "a": {}, + }), + ) + .await; + + let tree_fake = Worktree::local( + client_fake, + "/root".as_ref(), + true, + fs_fake, + Default::default(), + &mut cx.to_async(), + ) + .await + .unwrap(); + + let entry = tree_fake + .update(cx, |tree, cx| { + tree.as_local_mut() + .unwrap() + .create_entry("a/b/c/d.txt".as_ref(), false, cx) + }) + .await + .unwrap(); + assert!(entry.is_file()); + + cx.foreground().run_until_parked(); + tree_fake.read_with(cx, |tree, _| { + assert!(tree.entry_for_path("a/b/c/d.txt").unwrap().is_file()); + assert!(tree.entry_for_path("a/b/c/").unwrap().is_dir()); + assert!(tree.entry_for_path("a/b/").unwrap().is_dir()); + }); + + let client_real = cx.read(|cx| Client::new(FakeHttpClient::with_404_response(), cx)); + + let fs_real = Arc::new(RealFs); + let temp_root = temp_tree(json!({ + "a": {} + })); + + let tree_real = Worktree::local( + client_real, + temp_root.path(), + true, + fs_real, + Default::default(), + &mut cx.to_async(), + ) + .await + .unwrap(); + + let entry = tree_real + .update(cx, |tree, cx| { + tree.as_local_mut() + .unwrap() + .create_entry("a/b/c/d.txt".as_ref(), false, cx) + }) + .await + .unwrap(); + assert!(entry.is_file()); + + cx.foreground().run_until_parked(); + tree_real.read_with(cx, |tree, _| { + assert!(tree.entry_for_path("a/b/c/d.txt").unwrap().is_file()); + assert!(tree.entry_for_path("a/b/c/").unwrap().is_dir()); + assert!(tree.entry_for_path("a/b/").unwrap().is_dir()); + }); +} + #[gpui::test(iterations = 100)] async fn test_random_worktree_operations_during_initial_scan( cx: &mut TestAppContext, diff --git a/crates/project_panel/Cargo.toml b/crates/project_panel/Cargo.toml index 55efc09deb179437d837e7f50e1acbdb6613a2eb..33606fccc41854e3ae767fc691cd0edf15f047e2 100644 --- a/crates/project_panel/Cargo.toml +++ b/crates/project_panel/Cargo.toml @@ -27,6 +27,7 @@ serde_derive.workspace = true serde_json.workspace = true anyhow.workspace = true schemars.workspace = true +pretty_assertions.workspace = true unicase = "2.6" [dev-dependencies] diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index 3f80e023176003646657f10e1fbb60262de399f0..57a45ddb169c469cc817e2d9cb848ae8832c01ab 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -64,7 +64,7 @@ pub struct ProjectPanel { pending_serialization: Task>, } -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] struct Selection { worktree_id: WorktreeId, entry_id: ProjectEntryId, @@ -588,6 +588,7 @@ impl ProjectPanel { if selection.entry_id == edited_entry_id { selection.worktree_id = worktree_id; selection.entry_id = new_entry.id; + this.expand_to_selection(cx); } } this.update_visible_entries(None, cx); @@ -965,6 +966,25 @@ impl ProjectPanel { Some((worktree, entry)) } + fn expand_to_selection(&mut self, cx: &mut ViewContext) -> Option<()> { + let (worktree, entry) = self.selected_entry(cx)?; + let expanded_dir_ids = self.expanded_dir_ids.entry(worktree.id()).or_default(); + + for path in entry.path.ancestors() { + let Some(entry) = worktree.entry_for_path(path) else { + continue; + }; + if entry.is_dir() { + if let Err(idx) = expanded_dir_ids.binary_search(&entry.id) { + expanded_dir_ids.insert(idx, entry.id); + } + } + } + + + Some(()) + } + fn update_visible_entries( &mut self, new_selected_entry: Option<(WorktreeId, ProjectEntryId)>, @@ -1139,6 +1159,7 @@ impl ProjectPanel { for entry in visible_worktree_entries[entry_range].iter() { let status = git_status_setting.then(|| entry.git_status).flatten(); + let mut details = EntryDetails { filename: entry .path @@ -1592,6 +1613,7 @@ impl ClipboardEntry { mod tests { use super::*; use gpui::{TestAppContext, ViewHandle}; + use pretty_assertions::assert_eq; use project::FakeFs; use serde_json::json; use settings::SettingsStore; @@ -2002,6 +2024,134 @@ mod tests { ); } + #[gpui::test(iterations = 30)] + async fn test_adding_directories_via_file(cx: &mut gpui::TestAppContext) { + init_test(cx); + + let fs = FakeFs::new(cx.background()); + fs.insert_tree( + "/root1", + json!({ + ".dockerignore": "", + ".git": { + "HEAD": "", + }, + "a": { + "0": { "q": "", "r": "", "s": "" }, + "1": { "t": "", "u": "" }, + "2": { "v": "", "w": "", "x": "", "y": "" }, + }, + "b": { + "3": { "Q": "" }, + "4": { "R": "", "S": "", "T": "", "U": "" }, + }, + "C": { + "5": {}, + "6": { "V": "", "W": "" }, + "7": { "X": "" }, + "8": { "Y": {}, "Z": "" } + } + }), + ) + .await; + fs.insert_tree( + "/root2", + json!({ + "d": { + "9": "" + }, + "e": {} + }), + ) + .await; + + let project = Project::test(fs.clone(), ["/root1".as_ref(), "/root2".as_ref()], cx).await; + let (window_id, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx)); + let panel = workspace.update(cx, |workspace, cx| ProjectPanel::new(workspace, cx)); + + select_path(&panel, "root1", cx); + assert_eq!( + visible_entries_as_strings(&panel, 0..10, cx), + &[ + "v root1 <== selected", + " > .git", + " > a", + " > b", + " > C", + " .dockerignore", + "v root2", + " > d", + " > e", + ] + ); + + // 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| { + let panel = panel.read(cx); + assert!(panel.filename_editor.is_focused(cx)); + }); + assert_eq!( + visible_entries_as_strings(&panel, 0..10, cx), + &[ + "v root1", + " > .git", + " > a", + " > b", + " > C", + " [EDITOR: ''] <== selected", + " .dockerignore", + "v root2", + " > d", + " > e", + ] + ); + + + let confirm = panel.update(cx, |panel, cx| { + panel.filename_editor.update(cx, |editor, cx| { + editor.set_text("bdir1/dir2/the-new-filename", cx) + }); + panel.confirm(&Confirm, cx).unwrap() + }); + + assert_eq!( + visible_entries_as_strings(&panel, 0..10, cx), + &[ + "v root1", + " > .git", + " > a", + " > b", + " > C", + " [PROCESSING: 'bdir1/dir2/the-new-filename'] <== selected", + " .dockerignore", + "v root2", + " > d", + " > e", + ] + ); + + confirm.await.unwrap(); + assert_eq!( + visible_entries_as_strings(&panel, 0..13, cx), + &[ + "v root1", + " > .git", + " > a", + " > b", + " v bdir1", + " v dir2", + " the-new-filename <== selected", + " > C", + " .dockerignore", + "v root2", + " > d", + " > e", + ] + ); + } + #[gpui::test] async fn test_copy_paste(cx: &mut gpui::TestAppContext) { init_test(cx); diff --git a/crates/settings/Cargo.toml b/crates/settings/Cargo.toml index b5dc301a5c00cef3e58f3ae12702cdc222db1ee9..6c1ded805bb377b710568e52f948793a5a1f8f84 100644 --- a/crates/settings/Cargo.toml +++ b/crates/settings/Cargo.toml @@ -38,5 +38,5 @@ tree-sitter-json = "*" gpui = { path = "../gpui", features = ["test-support"] } fs = { path = "../fs", features = ["test-support"] } indoc.workspace = true -pretty_assertions = "1.3.0" +pretty_assertions = "*" unindent.workspace = true From cd670e340fa4a7e5c6d452a87ceee6329ae0ee21 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Thu, 29 Jun 2023 17:48:01 -0700 Subject: [PATCH 008/104] Fix edge case with absolute file paths --- crates/project_panel/src/project_panel.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index 57a45ddb169c469cc817e2d9cb848ae8832c01ab..fe8c6494202286e8f43f802dd9320315ecaf950e 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -547,7 +547,7 @@ impl ProjectPanel { worktree_id, entry_id: NEW_ENTRY_ID, }); - let new_path = entry.path.join(&filename); + let new_path = entry.path.join(&filename.trim_start_matches("/")); if path_already_exists(new_path.as_path()) { return None; } @@ -2111,7 +2111,7 @@ mod tests { let confirm = panel.update(cx, |panel, cx| { panel.filename_editor.update(cx, |editor, cx| { - editor.set_text("bdir1/dir2/the-new-filename", cx) + editor.set_text("/bdir1/dir2/the-new-filename", cx) }); panel.confirm(&Confirm, cx).unwrap() }); @@ -2124,7 +2124,7 @@ mod tests { " > a", " > b", " > C", - " [PROCESSING: 'bdir1/dir2/the-new-filename'] <== selected", + " [PROCESSING: '/bdir1/dir2/the-new-filename'] <== selected", " .dockerignore", "v root2", " > d", From 787412b545cd6e9e4cb0f40f5d33d3b9a4480a22 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Thu, 29 Jun 2023 17:49:42 -0700 Subject: [PATCH 009/104] fmt and update dependency --- crates/collab/Cargo.toml | 2 +- crates/project/Cargo.toml | 2 +- crates/project/src/worktree_tests.rs | 15 ++++++++------- crates/project_panel/src/project_panel.rs | 3 --- crates/settings/Cargo.toml | 2 +- 5 files changed, 11 insertions(+), 13 deletions(-) diff --git a/crates/collab/Cargo.toml b/crates/collab/Cargo.toml index 0c752a20472fcd1280f626fd40b9492c817021c9..c787287a0c2ee0c40aa4049e0bb807f7841e5360 100644 --- a/crates/collab/Cargo.toml +++ b/crates/collab/Cargo.toml @@ -67,7 +67,7 @@ fs = { path = "../fs", features = ["test-support"] } git = { path = "../git", features = ["test-support"] } live_kit_client = { path = "../live_kit_client", features = ["test-support"] } lsp = { path = "../lsp", features = ["test-support"] } -pretty_assertions = "*" +pretty_assertions.workspace = true project = { path = "../project", features = ["test-support"] } rpc = { path = "../rpc", features = ["test-support"] } settings = { path = "../settings", features = ["test-support"] } diff --git a/crates/project/Cargo.toml b/crates/project/Cargo.toml index dbc0c617f28bf9b46ab855f59e6fd8274f1a0315..bfe5f89f682c9f3a5333ae007366339d4c6b1577 100644 --- a/crates/project/Cargo.toml +++ b/crates/project/Cargo.toml @@ -64,7 +64,7 @@ itertools = "0.10" [dev-dependencies] ctor.workspace = true env_logger.workspace = true -pretty_assertions = "*" +pretty_assertions.workspace = true client = { path = "../client", features = ["test-support"] } collections = { path = "../collections", features = ["test-support"] } db = { path = "../db", features = ["test-support"] } diff --git a/crates/project/src/worktree_tests.rs b/crates/project/src/worktree_tests.rs index efc5f4236907df74cce34faebe5db534c5026c75..63f1f28eea4db296c003823bc26dc4fea61ed355 100644 --- a/crates/project/src/worktree_tests.rs +++ b/crates/project/src/worktree_tests.rs @@ -941,13 +941,14 @@ async fn test_create_dir_all_on_create_entry(cx: &mut TestAppContext) { let client_fake = cx.read(|cx| Client::new(FakeHttpClient::with_404_response(), cx)); let fs_fake = FakeFs::new(cx.background()); - fs_fake.insert_tree( - "/root", - json!({ - "a": {}, - }), - ) - .await; + fs_fake + .insert_tree( + "/root", + json!({ + "a": {}, + }), + ) + .await; let tree_fake = Worktree::local( client_fake, diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index fe8c6494202286e8f43f802dd9320315ecaf950e..c329ae4e51d0477eaba115c72597cd6248b6432c 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -981,7 +981,6 @@ impl ProjectPanel { } } - Some(()) } @@ -1159,7 +1158,6 @@ impl ProjectPanel { for entry in visible_worktree_entries[entry_range].iter() { let status = git_status_setting.then(|| entry.git_status).flatten(); - let mut details = EntryDetails { filename: entry .path @@ -2108,7 +2106,6 @@ mod tests { ] ); - let confirm = panel.update(cx, |panel, cx| { panel.filename_editor.update(cx, |editor, cx| { editor.set_text("/bdir1/dir2/the-new-filename", cx) diff --git a/crates/settings/Cargo.toml b/crates/settings/Cargo.toml index 6c1ded805bb377b710568e52f948793a5a1f8f84..06b81a0c61139ce0bd0a0c58a6101b8a043393bb 100644 --- a/crates/settings/Cargo.toml +++ b/crates/settings/Cargo.toml @@ -38,5 +38,5 @@ tree-sitter-json = "*" gpui = { path = "../gpui", features = ["test-support"] } fs = { path = "../fs", features = ["test-support"] } indoc.workspace = true -pretty_assertions = "*" +pretty_assertions.workspace = true unindent.workspace = true From a6dabf7acfef0f235bdd41d81daf8433b1955f59 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Thu, 29 Jun 2023 18:15:40 -0700 Subject: [PATCH 010/104] Make path updates minimal --- crates/project/src/worktree.rs | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/crates/project/src/worktree.rs b/crates/project/src/worktree.rs index a0497fa6771adbf87802e32bb1c0f92e6eaaf6b8..2b166bf6ef55859a78c233b19381e20fade29b4f 100644 --- a/crates/project/src/worktree.rs +++ b/crates/project/src/worktree.rs @@ -981,6 +981,19 @@ impl LocalWorktree { }) } + /// Find the lowest path in the worktree's datastructures that is an ancestor + pub fn lowest_ancestor(&self, path: &Path) -> PathBuf { + let mut lowest_ancestor = None; + for path in path.ancestors() { + if self.entry_for_path(path).is_some() { + lowest_ancestor = Some(path.to_path_buf()); + break; + } + } + + lowest_ancestor.unwrap_or_else(|| PathBuf::from("")) + } + pub fn create_entry( &self, path: impl Into>, @@ -988,6 +1001,7 @@ impl LocalWorktree { cx: &mut ModelContext, ) -> Task> { let path = path.into(); + let lowest_ancestor = self.lowest_ancestor(&path); let abs_path = self.absolutize(&path); let fs = self.fs.clone(); let write = cx.background().spawn(async move { @@ -1003,9 +1017,14 @@ impl LocalWorktree { write.await?; let (result, refreshes) = this.update(&mut cx, |this, cx| { let mut refreshes = Vec::new(); - for path in path.ancestors().skip(1) { + let refresh_paths = path.strip_prefix(&lowest_ancestor).unwrap(); + for refresh_path in refresh_paths.ancestors() { + let refresh_full_path = lowest_ancestor.join(refresh_path); + if refresh_full_path.as_path() == path.deref() { + continue; + } refreshes.push(this.as_local_mut().unwrap().refresh_entry( - path.into(), + refresh_full_path.into(), None, cx, )); From a9a51ab3addfda7c97a96d3194099077d13fc7a1 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Thu, 29 Jun 2023 18:21:35 -0700 Subject: [PATCH 011/104] Added more tests and minimal file updates --- crates/project/src/worktree_tests.rs | 35 ++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/crates/project/src/worktree_tests.rs b/crates/project/src/worktree_tests.rs index 63f1f28eea4db296c003823bc26dc4fea61ed355..8f130f648a7cbb32a30127df3967b2a9e7c97402 100644 --- a/crates/project/src/worktree_tests.rs +++ b/crates/project/src/worktree_tests.rs @@ -1012,6 +1012,41 @@ async fn test_create_dir_all_on_create_entry(cx: &mut TestAppContext) { assert!(tree.entry_for_path("a/b/c/").unwrap().is_dir()); assert!(tree.entry_for_path("a/b/").unwrap().is_dir()); }); + + // Test smallest change + let entry = tree_real + .update(cx, |tree, cx| { + tree.as_local_mut() + .unwrap() + .create_entry("a/b/c/e.txt".as_ref(), false, cx) + }) + .await + .unwrap(); + assert!(entry.is_file()); + + cx.foreground().run_until_parked(); + tree_real.read_with(cx, |tree, _| { + assert!(tree.entry_for_path("a/b/c/e.txt").unwrap().is_file()); + }); + + // Test largest change + let entry = tree_real + .update(cx, |tree, cx| { + tree.as_local_mut() + .unwrap() + .create_entry("d/e/f/g.txt".as_ref(), false, cx) + }) + .await + .unwrap(); + assert!(entry.is_file()); + + cx.foreground().run_until_parked(); + tree_real.read_with(cx, |tree, _| { + assert!(tree.entry_for_path("d/e/f/g.txt").unwrap().is_file()); + assert!(tree.entry_for_path("d/e/f").unwrap().is_dir()); + assert!(tree.entry_for_path("d/e/").unwrap().is_dir()); + assert!(tree.entry_for_path("d/").unwrap().is_dir()); + }); } #[gpui::test(iterations = 100)] From 9ee2707d43c877e8f2f9f7efa7b0d26e90d48833 Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Thu, 29 Jun 2023 22:45:54 -0600 Subject: [PATCH 012/104] vim: Add }/{ for start/end of paragraph Fixes: zed-industries/community#470 --- assets/keymaps/vim.json | 2 + crates/editor/src/editor.rs | 14 ++-- crates/editor/src/movement.rs | 24 +++++-- crates/vim/src/motion.rs | 118 +++++++++++++++++++++++++++++++++- 4 files changed, 149 insertions(+), 9 deletions(-) diff --git a/assets/keymaps/vim.json b/assets/keymaps/vim.json index afee6fcd2e998500ba55e08230473e91e68dbb96..e4c489c5b5e5b328f682c9e68e29ace596389684 100644 --- a/assets/keymaps/vim.json +++ b/assets/keymaps/vim.json @@ -37,6 +37,8 @@ "$": "vim::EndOfLine", "shift-g": "vim::EndOfDocument", "w": "vim::NextWordStart", + "{": "vim::StartOfParagraph", + "}": "vim::EndOfParagraph", "shift-w": [ "vim::NextWordStart", { diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 64332c102aa8a802bb6e428250b820597060590c..824802630dd88d194be61570d7bfeca4f2f087d6 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -5120,7 +5120,7 @@ impl Editor { self.change_selections(Some(Autoscroll::fit()), cx, |s| { s.move_with(|map, selection| { selection.collapse_to( - movement::start_of_paragraph(map, selection.head()), + movement::start_of_paragraph(map, selection.head(), 1), SelectionGoal::None, ) }); @@ -5140,7 +5140,7 @@ impl Editor { self.change_selections(Some(Autoscroll::fit()), cx, |s| { s.move_with(|map, selection| { selection.collapse_to( - movement::end_of_paragraph(map, selection.head()), + movement::end_of_paragraph(map, selection.head(), 1), SelectionGoal::None, ) }); @@ -5159,7 +5159,10 @@ impl Editor { self.change_selections(Some(Autoscroll::fit()), cx, |s| { s.move_heads_with(|map, head, _| { - (movement::start_of_paragraph(map, head), SelectionGoal::None) + ( + movement::start_of_paragraph(map, head, 1), + SelectionGoal::None, + ) }); }) } @@ -5176,7 +5179,10 @@ impl Editor { self.change_selections(Some(Autoscroll::fit()), cx, |s| { s.move_heads_with(|map, head, _| { - (movement::end_of_paragraph(map, head), SelectionGoal::None) + ( + movement::end_of_paragraph(map, head, 1), + SelectionGoal::None, + ) }); }) } diff --git a/crates/editor/src/movement.rs b/crates/editor/src/movement.rs index 523a0af9640aa98b3f3e3d7b9fd980768f1e4f89..8f1e6172e9ec28043b3d684ff5d8da3b3e4406e4 100644 --- a/crates/editor/src/movement.rs +++ b/crates/editor/src/movement.rs @@ -193,7 +193,11 @@ pub fn next_subword_end(map: &DisplaySnapshot, point: DisplayPoint) -> DisplayPo }) } -pub fn start_of_paragraph(map: &DisplaySnapshot, display_point: DisplayPoint) -> DisplayPoint { +pub fn start_of_paragraph( + map: &DisplaySnapshot, + display_point: DisplayPoint, + mut count: usize, +) -> DisplayPoint { let point = display_point.to_point(map); if point.row == 0 { return map.max_point(); @@ -203,7 +207,11 @@ pub fn start_of_paragraph(map: &DisplaySnapshot, display_point: DisplayPoint) -> for row in (0..point.row + 1).rev() { let blank = map.buffer_snapshot.is_line_blank(row); if found_non_blank_line && blank { - return Point::new(row, 0).to_display_point(map); + if count <= 1 { + return Point::new(row, 0).to_display_point(map); + } + count -= 1; + found_non_blank_line = false; } found_non_blank_line |= !blank; @@ -212,7 +220,11 @@ pub fn start_of_paragraph(map: &DisplaySnapshot, display_point: DisplayPoint) -> DisplayPoint::zero() } -pub fn end_of_paragraph(map: &DisplaySnapshot, display_point: DisplayPoint) -> DisplayPoint { +pub fn end_of_paragraph( + map: &DisplaySnapshot, + display_point: DisplayPoint, + mut count: usize, +) -> DisplayPoint { let point = display_point.to_point(map); if point.row == map.max_buffer_row() { return DisplayPoint::zero(); @@ -222,7 +234,11 @@ pub fn end_of_paragraph(map: &DisplaySnapshot, display_point: DisplayPoint) -> D for row in point.row..map.max_buffer_row() + 1 { let blank = map.buffer_snapshot.is_line_blank(row); if found_non_blank_line && blank { - return Point::new(row, 0).to_display_point(map); + if count <= 1 { + return Point::new(row, 0).to_display_point(map); + } + count -= 1; + found_non_blank_line = false; } found_non_blank_line |= !blank; diff --git a/crates/vim/src/motion.rs b/crates/vim/src/motion.rs index faf69d94734f95cd79dabaef3a165bbec7721c81..f39cd82fc144cc70c84828648f10aad977228259 100644 --- a/crates/vim/src/motion.rs +++ b/crates/vim/src/motion.rs @@ -31,6 +31,8 @@ pub enum Motion { CurrentLine, StartOfLine, EndOfLine, + StartOfParagraph, + EndOfParagraph, StartOfDocument, EndOfDocument, Matching, @@ -72,6 +74,8 @@ actions!( StartOfLine, EndOfLine, CurrentLine, + StartOfParagraph, + EndOfParagraph, StartOfDocument, EndOfDocument, Matching, @@ -92,6 +96,12 @@ pub fn init(cx: &mut AppContext) { cx.add_action(|_: &mut Workspace, _: &StartOfLine, cx: _| motion(Motion::StartOfLine, cx)); cx.add_action(|_: &mut Workspace, _: &EndOfLine, cx: _| motion(Motion::EndOfLine, cx)); cx.add_action(|_: &mut Workspace, _: &CurrentLine, cx: _| motion(Motion::CurrentLine, cx)); + cx.add_action(|_: &mut Workspace, _: &StartOfParagraph, cx: _| { + motion(Motion::StartOfParagraph, cx) + }); + cx.add_action(|_: &mut Workspace, _: &EndOfParagraph, cx: _| { + motion(Motion::EndOfParagraph, cx) + }); cx.add_action(|_: &mut Workspace, _: &StartOfDocument, cx: _| { motion(Motion::StartOfDocument, cx) }); @@ -142,7 +152,8 @@ impl Motion { pub fn linewise(&self) -> bool { use Motion::*; match self { - Down | Up | StartOfDocument | EndOfDocument | CurrentLine | NextLineStart => true, + Down | Up | StartOfDocument | EndOfDocument | CurrentLine | NextLineStart + | StartOfParagraph | EndOfParagraph => true, EndOfLine | NextWordEnd { .. } | Matching @@ -172,6 +183,8 @@ impl Motion { | Backspace | Right | StartOfLine + | StartOfParagraph + | EndOfParagraph | NextWordStart { .. } | PreviousWordStart { .. } | FirstNonWhitespace @@ -197,6 +210,8 @@ impl Motion { | Backspace | Right | StartOfLine + | StartOfParagraph + | EndOfParagraph | NextWordStart { .. } | PreviousWordStart { .. } | FirstNonWhitespace @@ -235,6 +250,14 @@ impl Motion { FirstNonWhitespace => (first_non_whitespace(map, point), SelectionGoal::None), StartOfLine => (start_of_line(map, point), SelectionGoal::None), EndOfLine => (end_of_line(map, point), SelectionGoal::None), + StartOfParagraph => ( + movement::start_of_paragraph(map, point, times), + SelectionGoal::None, + ), + EndOfParagraph => ( + movement::end_of_paragraph(map, point, times), + SelectionGoal::None, + ), CurrentLine => (end_of_line(map, point), SelectionGoal::None), StartOfDocument => (start_of_document(map, point, times), SelectionGoal::None), EndOfDocument => ( @@ -590,3 +613,96 @@ fn next_line_start(map: &DisplaySnapshot, point: DisplayPoint, times: usize) -> let new_row = (point.row() + times as u32).min(map.max_buffer_row()); map.clip_point(DisplayPoint::new(new_row, 0), Bias::Left) } + +#[cfg(test)] + +mod test { + + use crate::{state::Mode, test::VimTestContext}; + use indoc::indoc; + + #[gpui::test] + async fn test_start_end_of_paragraph(cx: &mut gpui::TestAppContext) { + let mut cx = VimTestContext::new(cx, true).await; + + let initial_state = indoc! {r"ˇabc + def + + paragraph + the second + + + + third and + final"}; + + // goes down once + cx.set_state(initial_state, Mode::Normal); + cx.simulate_keystrokes(["}"]); + cx.assert_state( + indoc! {r"abc + def + ˇ + paragraph + the second + + + + third and + final"}, + Mode::Normal, + ); + + // goes up once + cx.simulate_keystrokes(["{"]); + cx.assert_state(initial_state, Mode::Normal); + + // goes down twice + cx.simulate_keystrokes(["2", "}"]); + cx.assert_state( + indoc! {r"abc + def + + paragraph + the second + ˇ + + + third and + final"}, + Mode::Normal, + ); + + // goes down over multiple blanks + cx.simulate_keystrokes(["}"]); + cx.assert_state( + indoc! {r"abc + def + + paragraph + the second + + + + third and + finalˇ"}, + Mode::Normal, + ); + + // goes up twice + cx.simulate_keystrokes(["2", "{"]); + cx.assert_state( + indoc! {r"abc + def + ˇ + paragraph + the second + + + + third and + final"}, + Mode::Normal, + ) + } +} From abb58c41dbc8b31c02873ba294daf7530ff51e5e Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Thu, 29 Jun 2023 23:24:51 -0600 Subject: [PATCH 013/104] vim: Fix edge-case in } when trailing newline is absent MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added .assert_shared_state() to NeovimBackedTestContext – although it's not strictly necessary to show the expected behaviour in the test file (as we can just compare to neovim's JSON recording), it makes it much easier to understand what we're testing. --- crates/editor/src/test/editor_test_context.rs | 26 ++++++---- crates/vim/src/motion.rs | 52 ++++++++----------- .../src/test/neovim_backed_test_context.rs | 51 ++++++++++++++---- .../test_start_end_of_paragraph.json | 13 +++++ 4 files changed, 94 insertions(+), 48 deletions(-) create mode 100644 crates/vim/test_data/test_start_end_of_paragraph.json diff --git a/crates/editor/src/test/editor_test_context.rs b/crates/editor/src/test/editor_test_context.rs index 95da7ff297341e18f99ca57f7cbcadb707a8fdb4..bac70f139a6be8732e9b2b8bde9bce2b63144418 100644 --- a/crates/editor/src/test/editor_test_context.rs +++ b/crates/editor/src/test/editor_test_context.rs @@ -210,6 +210,10 @@ impl<'a> EditorTestContext<'a> { self.assert_selections(expected_selections, marked_text.to_string()) } + pub fn editor_state(&mut self) -> String { + generate_marked_text(self.buffer_text().as_str(), &self.editor_selections(), true) + } + #[track_caller] pub fn assert_editor_background_highlights(&mut self, marked_text: &str) { let expected_ranges = self.ranges(marked_text); @@ -248,14 +252,8 @@ impl<'a> EditorTestContext<'a> { self.assert_selections(expected_selections, expected_marked_text) } - #[track_caller] - fn assert_selections( - &mut self, - expected_selections: Vec>, - expected_marked_text: String, - ) { - let actual_selections = self - .editor + fn editor_selections(&self) -> Vec> { + self.editor .read_with(self.cx, |editor, cx| editor.selections.all::(cx)) .into_iter() .map(|s| { @@ -265,12 +263,22 @@ impl<'a> EditorTestContext<'a> { s.start..s.end } }) - .collect::>(); + .collect::>() + } + + #[track_caller] + fn assert_selections( + &mut self, + expected_selections: Vec>, + expected_marked_text: String, + ) { + let actual_selections = self.editor_selections(); let actual_marked_text = generate_marked_text(&self.buffer_text(), &actual_selections, true); if expected_selections != actual_selections { panic!( indoc! {" + {}Editor has unexpected selections. Expected selections: diff --git a/crates/vim/src/motion.rs b/crates/vim/src/motion.rs index f39cd82fc144cc70c84828648f10aad977228259..e8084cb4be13f8ffd3214b50bba1cc071d32193b 100644 --- a/crates/vim/src/motion.rs +++ b/crates/vim/src/motion.rs @@ -255,7 +255,7 @@ impl Motion { SelectionGoal::None, ), EndOfParagraph => ( - movement::end_of_paragraph(map, point, times), + map.clip_at_line_end(movement::end_of_paragraph(map, point, times)), SelectionGoal::None, ), CurrentLine => (end_of_line(map, point), SelectionGoal::None), @@ -618,12 +618,12 @@ fn next_line_start(map: &DisplaySnapshot, point: DisplayPoint, times: usize) -> mod test { - use crate::{state::Mode, test::VimTestContext}; + use crate::test::NeovimBackedTestContext; use indoc::indoc; #[gpui::test] async fn test_start_end_of_paragraph(cx: &mut gpui::TestAppContext) { - let mut cx = VimTestContext::new(cx, true).await; + let mut cx = NeovimBackedTestContext::new(cx).await; let initial_state = indoc! {r"ˇabc def @@ -637,10 +637,9 @@ mod test { final"}; // goes down once - cx.set_state(initial_state, Mode::Normal); - cx.simulate_keystrokes(["}"]); - cx.assert_state( - indoc! {r"abc + cx.set_shared_state(initial_state).await; + cx.simulate_shared_keystrokes(["}"]).await; + cx.assert_shared_state(indoc! {r"abc def ˇ paragraph @@ -649,18 +648,16 @@ mod test { third and - final"}, - Mode::Normal, - ); + final"}) + .await; // goes up once - cx.simulate_keystrokes(["{"]); - cx.assert_state(initial_state, Mode::Normal); + cx.simulate_shared_keystrokes(["{"]).await; + cx.assert_shared_state(initial_state).await; // goes down twice - cx.simulate_keystrokes(["2", "}"]); - cx.assert_state( - indoc! {r"abc + cx.simulate_shared_keystrokes(["2", "}"]).await; + cx.assert_shared_state(indoc! {r"abc def paragraph @@ -669,14 +666,12 @@ mod test { third and - final"}, - Mode::Normal, - ); + final"}) + .await; // goes down over multiple blanks - cx.simulate_keystrokes(["}"]); - cx.assert_state( - indoc! {r"abc + cx.simulate_shared_keystrokes(["}"]).await; + cx.assert_shared_state(indoc! {r"abc def paragraph @@ -685,14 +680,12 @@ mod test { third and - finalˇ"}, - Mode::Normal, - ); + finaˇl"}) + .await; // goes up twice - cx.simulate_keystrokes(["2", "{"]); - cx.assert_state( - indoc! {r"abc + cx.simulate_shared_keystrokes(["2", "{"]).await; + cx.assert_shared_state(indoc! {r"abc def ˇ paragraph @@ -701,8 +694,7 @@ mod test { third and - final"}, - Mode::Normal, - ) + final"}) + .await } } diff --git a/crates/vim/src/test/neovim_backed_test_context.rs b/crates/vim/src/test/neovim_backed_test_context.rs index 9b6bf976ca08a9a4ecf90a907f47772e8f1bdba1..7f9a84b666c4babdacba866bafef1f492f067c19 100644 --- a/crates/vim/src/test/neovim_backed_test_context.rs +++ b/crates/vim/src/test/neovim_backed_test_context.rs @@ -1,9 +1,10 @@ -use std::ops::{Deref, DerefMut}; +use indoc::indoc; +use std::ops::{Deref, DerefMut, Range}; use collections::{HashMap, HashSet}; use gpui::ContextHandle; use language::OffsetRangeExt; -use util::test::marked_text_offsets; +use util::test::{generate_marked_text, marked_text_offsets}; use super::{neovim_connection::NeovimConnection, NeovimBackedBindingTestContext, VimTestContext}; use crate::state::Mode; @@ -112,6 +113,43 @@ impl<'a> NeovimBackedTestContext<'a> { context_handle } + pub async fn assert_shared_state(&mut self, marked_text: &str) { + let neovim = self.neovim_state().await; + if neovim != marked_text { + panic!( + indoc! {"Test is incorrect (currently expected != neovim state) + + # currently expected: + {} + # neovim state: + {} + # zed state: + {}"}, + marked_text, + neovim, + self.editor_state(), + ) + } + self.assert_editor_state(marked_text) + } + + pub async fn neovim_state(&mut self) -> String { + generate_marked_text( + self.neovim.text().await.as_str(), + &vec![self.neovim_selection().await], + true, + ) + } + + async fn neovim_selection(&mut self) -> Range { + let mut neovim_selection = self.neovim.selection().await; + // Zed selections adjust themselves to make the end point visually make sense + if neovim_selection.start > neovim_selection.end { + neovim_selection.start.column += 1; + } + neovim_selection.to_offset(&self.buffer_snapshot()) + } + pub async fn assert_state_matches(&mut self) { assert_eq!( self.neovim.text().await, @@ -120,13 +158,8 @@ impl<'a> NeovimBackedTestContext<'a> { self.assertion_context() ); - let mut neovim_selection = self.neovim.selection().await; - // Zed selections adjust themselves to make the end point visually make sense - if neovim_selection.start > neovim_selection.end { - neovim_selection.start.column += 1; - } - let neovim_selection = neovim_selection.to_offset(&self.buffer_snapshot()); - self.assert_editor_selections(vec![neovim_selection]); + let selections = vec![self.neovim_selection().await]; + self.assert_editor_selections(selections); if let Some(neovim_mode) = self.neovim.mode().await { assert_eq!(neovim_mode, self.mode(), "{}", self.assertion_context(),); diff --git a/crates/vim/test_data/test_start_end_of_paragraph.json b/crates/vim/test_data/test_start_end_of_paragraph.json new file mode 100644 index 0000000000000000000000000000000000000000..0de4d84f50f6cb46ec29ee5ba2d394b07c9105cc --- /dev/null +++ b/crates/vim/test_data/test_start_end_of_paragraph.json @@ -0,0 +1,13 @@ +{"Put":{"state":"ˇabc\ndef\n\nparagraph\nthe second\n\n\n\nthird and\nfinal"}} +{"Key":"}"} +{"Get":{"state":"abc\ndef\nˇ\nparagraph\nthe second\n\n\n\nthird and\nfinal","mode":"Normal"}} +{"Key":"{"} +{"Get":{"state":"ˇabc\ndef\n\nparagraph\nthe second\n\n\n\nthird and\nfinal","mode":"Normal"}} +{"Key":"2"} +{"Key":"}"} +{"Get":{"state":"abc\ndef\n\nparagraph\nthe second\nˇ\n\n\nthird and\nfinal","mode":"Normal"}} +{"Key":"}"} +{"Get":{"state":"abc\ndef\n\nparagraph\nthe second\n\n\n\nthird and\nfinaˇl","mode":"Normal"}} +{"Key":"2"} +{"Key":"{"} +{"Get":{"state":"abc\ndef\nˇ\nparagraph\nthe second\n\n\n\nthird and\nfinal","mode":"Normal"}} From d22a576f5e05f0a3b1a83e67b40489f9068c4e74 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Thu, 29 Jun 2023 23:50:24 -0700 Subject: [PATCH 014/104] fix failing test --- crates/project/src/worktree.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/crates/project/src/worktree.rs b/crates/project/src/worktree.rs index 2b166bf6ef55859a78c233b19381e20fade29b4f..7596b0fcb79794d7971a495513e7c3b3ba69eba3 100644 --- a/crates/project/src/worktree.rs +++ b/crates/project/src/worktree.rs @@ -1016,13 +1016,14 @@ impl LocalWorktree { cx.spawn(|this, mut cx| async move { write.await?; let (result, refreshes) = this.update(&mut cx, |this, cx| { - let mut refreshes = Vec::new(); + let mut refreshes = Vec::>>::new(); let refresh_paths = path.strip_prefix(&lowest_ancestor).unwrap(); for refresh_path in refresh_paths.ancestors() { - let refresh_full_path = lowest_ancestor.join(refresh_path); - if refresh_full_path.as_path() == path.deref() { + if refresh_path == Path::new("") { continue; } + let refresh_full_path = lowest_ancestor.join(refresh_path); + refreshes.push(this.as_local_mut().unwrap().refresh_entry( refresh_full_path.into(), None, From 3d6e063a6dcabe7644a10891417dc648793afa70 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Thu, 29 Jun 2023 23:53:57 -0700 Subject: [PATCH 015/104] Fix method header --- crates/project/src/worktree.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/project/src/worktree.rs b/crates/project/src/worktree.rs index 7596b0fcb79794d7971a495513e7c3b3ba69eba3..d86b98e0ecbaee43dcecc14f3c5f188095c8977b 100644 --- a/crates/project/src/worktree.rs +++ b/crates/project/src/worktree.rs @@ -982,7 +982,7 @@ impl LocalWorktree { } /// Find the lowest path in the worktree's datastructures that is an ancestor - pub fn lowest_ancestor(&self, path: &Path) -> PathBuf { + fn lowest_ancestor(&self, path: &Path) -> PathBuf { let mut lowest_ancestor = None; for path in path.ancestors() { if self.entry_for_path(path).is_some() { From d8d0bdc479ce926512697bc04a6c0a485b611ad4 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Tue, 27 Jun 2023 12:02:30 +0200 Subject: [PATCH 016/104] WIP: git menu --- crates/collab_ui/src/branch_list.rs | 178 +++++++++++++++++++ crates/collab_ui/src/collab_titlebar_item.rs | 123 ++++++++++--- crates/collab_ui/src/collab_ui.rs | 2 + crates/fs/src/repository.rs | 32 +++- 4 files changed, 311 insertions(+), 24 deletions(-) create mode 100644 crates/collab_ui/src/branch_list.rs diff --git a/crates/collab_ui/src/branch_list.rs b/crates/collab_ui/src/branch_list.rs new file mode 100644 index 0000000000000000000000000000000000000000..8d755e8aa456abdfc4cc7656178b25060147ef46 --- /dev/null +++ b/crates/collab_ui/src/branch_list.rs @@ -0,0 +1,178 @@ +use client::{ContactRequestStatus, User, UserStore}; +use fuzzy::{StringMatch, StringMatchCandidate}; +use gpui::{elements::*, AppContext, ModelHandle, MouseState, Task, ViewContext}; +use picker::{Picker, PickerDelegate, PickerEvent}; +use project::Project; +use std::sync::Arc; +use util::{ResultExt, TryFutureExt}; + +pub fn init(cx: &mut AppContext) { + Picker::::init(cx); +} + +pub type BranchList = Picker; + +pub fn build_branch_list( + project: ModelHandle, + cx: &mut ViewContext, +) -> BranchList { + Picker::new( + BranchListDelegate { + branches: vec!["Foo".into(), "bar/baz".into()], + matches: vec![], + project, + selected_index: 0, + }, + cx, + ) + .with_theme(|theme| theme.picker.clone()) +} + +pub struct BranchListDelegate { + branches: Vec, + matches: Vec, + project: ModelHandle, + selected_index: usize, +} + +impl PickerDelegate for BranchListDelegate { + fn placeholder_text(&self) -> Arc { + "Select branch...".into() + } + + fn match_count(&self) -> usize { + self.matches.len() + } + + fn selected_index(&self) -> usize { + self.selected_index + } + + fn set_selected_index(&mut self, ix: usize, _: &mut ViewContext>) { + self.selected_index = ix; + } + + fn update_matches(&mut self, query: String, cx: &mut ViewContext>) -> Task<()> { + cx.spawn(move |picker, mut cx| async move { + let candidates = picker + .read_with(&mut cx, |view, cx| { + let delegate = view.delegate(); + let project = delegate.project.read(&cx); + let mut cwd = project + .visible_worktrees(cx) + .next() + .unwrap() + .read(cx) + .root_entry() + .unwrap() + .path + .to_path_buf(); + cwd.push(".git"); + let branches = project.fs().open_repo(&cwd).unwrap().lock().branches(); + branches + .unwrap() + .iter() + .cloned() + .enumerate() + .map(|(ix, command)| StringMatchCandidate { + id: ix, + string: command.clone(), + char_bag: command.chars().collect(), + }) + .collect::>() + }) + .unwrap(); + let matches = if query.is_empty() { + candidates + .into_iter() + .enumerate() + .map(|(index, candidate)| StringMatch { + candidate_id: index, + string: candidate.string, + positions: Vec::new(), + score: 0.0, + }) + .collect() + } else { + fuzzy::match_strings( + &candidates, + &query, + true, + 10000, + &Default::default(), + cx.background(), + ) + .await + }; + picker + .update(&mut cx, |picker, _| { + let delegate = picker.delegate_mut(); + //delegate.branches = actions; + delegate.matches = matches; + if delegate.matches.is_empty() { + delegate.selected_index = 0; + } else { + delegate.selected_index = + core::cmp::min(delegate.selected_index, delegate.matches.len() - 1); + } + }) + .log_err(); + }) + } + + fn confirm(&mut self, cx: &mut ViewContext>) { + log::error!("confirm {}", self.selected_index()); + let current_pick = self.selected_index(); + let current_pick = self.matches[current_pick].string.clone(); + log::error!("Hi? {current_pick}"); + let project = self.project.read(cx); + let mut cwd = project + .visible_worktrees(cx) + .next() + .unwrap() + .read(cx) + .root_entry() + .unwrap() + .path + .to_path_buf(); + cwd.push(".git"); + log::error!("{current_pick}"); + project + .fs() + .open_repo(&cwd) + .unwrap() + .lock() + .change_branch(¤t_pick) + .log_err(); + cx.emit(PickerEvent::Dismiss); + } + + fn dismissed(&mut self, cx: &mut ViewContext>) { + cx.emit(PickerEvent::Dismiss); + } + + fn render_match( + &self, + ix: usize, + mouse_state: &mut MouseState, + selected: bool, + cx: &gpui::AppContext, + ) -> AnyElement> { + let theme = &theme::current(cx); + let user = &self.matches[ix]; + let style = theme.picker.item.in_state(selected).style_for(mouse_state); + Flex::row() + .with_child( + Label::new(user.string.clone(), style.label.clone()) + .with_highlights(user.positions.clone()) + .contained() + .aligned() + .left(), + ) + .contained() + .with_style(style.container) + .constrained() + .with_height(theme.contact_finder.row_height) + .into_any() + } +} diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index 5caebb9f0c033d9fda6aed87d155f4e1e5b9c655..338ba6cf27de82c786834e584510b211a89d2583 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -1,5 +1,8 @@ use crate::{ - contact_notification::ContactNotification, contacts_popover, face_pile::FacePile, + branch_list::{build_branch_list, BranchList}, + contact_notification::ContactNotification, + contacts_popover, + face_pile::FacePile, toggle_deafen, toggle_mute, toggle_screen_sharing, LeaveCall, ToggleDeafen, ToggleMute, ToggleScreenSharing, }; @@ -12,12 +15,14 @@ use gpui::{ actions, color::Color, elements::*, + fonts::TextStyle, geometry::{rect::RectF, vector::vec2f, PathBuilder}, json::{self, ToJson}, platform::{CursorStyle, MouseButton}, AppContext, Entity, ImageData, LayoutContext, ModelHandle, SceneBuilder, Subscription, View, ViewContext, ViewHandle, WeakViewHandle, }; +use picker::PickerEvent; use project::{Project, RepositoryEntry}; use std::{ops::Range, sync::Arc}; use theme::{AvatarStyle, Theme}; @@ -31,6 +36,8 @@ actions!( [ ToggleContactsMenu, ToggleUserMenu, + ToggleVcsMenu, + SwitchBranch, ShareProject, UnshareProject, ] @@ -41,6 +48,7 @@ pub fn init(cx: &mut AppContext) { cx.add_action(CollabTitlebarItem::share_project); cx.add_action(CollabTitlebarItem::unshare_project); cx.add_action(CollabTitlebarItem::toggle_user_menu); + cx.add_action(CollabTitlebarItem::toggle_vcs_menu); } pub struct CollabTitlebarItem { @@ -49,6 +57,7 @@ pub struct CollabTitlebarItem { client: Arc, workspace: WeakViewHandle, contacts_popover: Option>, + branch_popover: Option>, user_menu: ViewHandle, _subscriptions: Vec, } @@ -69,12 +78,11 @@ impl View for CollabTitlebarItem { return Empty::new().into_any(); }; - let project = self.project.read(cx); let theme = theme::current(cx).clone(); let mut left_container = Flex::row(); let mut right_container = Flex::row().align_children_center(); - left_container.add_child(self.collect_title_root_names(&project, theme.clone(), cx)); + left_container.add_child(self.collect_title_root_names(theme.clone(), cx)); let user = self.user_store.read(cx).current_user(); let peer_id = self.client.peer_id(); @@ -182,22 +190,28 @@ impl CollabTitlebarItem { menu.set_position_mode(OverlayPositionMode::Local); menu }), + branch_popover: None, _subscriptions: subscriptions, } } fn collect_title_root_names( &self, - project: &Project, theme: Arc, - cx: &ViewContext, + cx: &mut ViewContext, ) -> AnyElement { - let mut names_and_branches = project.visible_worktrees(cx).map(|worktree| { - let worktree = worktree.read(cx); - (worktree.root_name(), worktree.root_git_entry()) - }); + let project = self.project.read(cx); + + let (name, entry) = { + let mut names_and_branches = project.visible_worktrees(cx).map(|worktree| { + let worktree = worktree.read(cx); + (worktree.root_name(), worktree.root_git_entry()) + }); - let (name, entry) = names_and_branches.next().unwrap_or(("", None)); + names_and_branches.next().unwrap_or(("", None)) + }; + + let name = name.to_owned(); let branch_prepended = entry .as_ref() .and_then(RepositoryEntry::branch) @@ -212,22 +226,37 @@ impl CollabTitlebarItem { text: text_style, highlight_text: Some(highlight), }; + let highlights = (0..name.len()).into_iter().collect(); let mut ret = Flex::row().with_child( - Label::new(name.to_owned(), style.clone()) - .with_highlights((0..name.len()).into_iter().collect()) - .contained() - .aligned() - .left() - .into_any_named("title-project-name"), - ); - if let Some(git_branch) = branch_prepended { - ret = ret.with_child( - Label::new(git_branch, style) + Stack::new().with_child( + Label::new(name, style.clone()) + .with_highlights(highlights) .contained() - .with_margin_right(item_spacing) .aligned() .left() - .into_any_named("title-project-branch"), + .into_any_named("title-project-name"), + ), + ); + if let Some(git_branch) = branch_prepended { + ret = ret.with_child( + Stack::new() + .with_child( + MouseEventHandler::::new(0, cx, |state, _| { + Label::new(git_branch, style) + .contained() + .with_margin_right(item_spacing) + .aligned() + .left() + .into_any_named("title-project-branch") + }) + .with_cursor_style(CursorStyle::PointingHand) + .on_click(MouseButton::Left, move |_, this, cx| { + this.toggle_vcs_menu(&Default::default(), cx) + }), + ) + .with_children( + self.render_branches_popover_host(&theme.workspace.titlebar, cx), + ), ) } ret.into_any() @@ -320,7 +349,55 @@ impl CollabTitlebarItem { user_menu.toggle(Default::default(), AnchorCorner::TopRight, items, cx); }); } + fn render_branches_popover_host<'a>( + &'a self, + _theme: &'a theme::Titlebar, + cx: &'a mut ViewContext, + ) -> Option> { + self.branch_popover.as_ref().map(|child| { + let theme = theme::current(cx).clone(); + let child = ChildView::new(child, cx); + let child = MouseEventHandler::::new(0, cx, |_, _| { + Flex::column() + .with_child(child.flex(1., true)) + .contained() + .with_style(theme.contacts_popover.container) + .constrained() + .with_width(theme.contacts_popover.width) + .with_height(theme.contacts_popover.height) + }) + .on_click(MouseButton::Left, |_, _, _| {}) + .on_down_out(MouseButton::Left, move |_, _, cx| cx.emit(())) + .into_any(); + + Overlay::new(child) + .with_fit_mode(OverlayFitMode::SwitchAnchor) + .with_anchor_corner(AnchorCorner::TopLeft) + .with_z_index(999) + .aligned() + .bottom() + .left() + .into_any() + }) + } + pub fn toggle_vcs_menu(&mut self, _: &ToggleVcsMenu, cx: &mut ViewContext) { + if self.branch_popover.take().is_none() { + let view = cx.add_view(|cx| build_branch_list(self.project.clone(), cx)); + cx.subscribe(&view, |this, _, event, cx| { + match event { + PickerEvent::Dismiss => { + this.contacts_popover = None; + } + } + cx.notify(); + }) + .detach(); + self.branch_popover = Some(view); + } + + cx.notify(); + } fn render_toggle_contacts_button( &self, theme: &Theme, @@ -733,7 +810,7 @@ impl CollabTitlebarItem { self.contacts_popover.as_ref().map(|popover| { Overlay::new(ChildView::new(popover, cx)) .with_fit_mode(OverlayFitMode::SwitchAnchor) - .with_anchor_corner(AnchorCorner::TopRight) + .with_anchor_corner(AnchorCorner::TopLeft) .with_z_index(999) .aligned() .bottom() diff --git a/crates/collab_ui/src/collab_ui.rs b/crates/collab_ui/src/collab_ui.rs index a809b9c7e6d54b2504aa1f4a95e7257396e930c4..26d9c70a4378af9e8ff90fa4a0af8babf5a45539 100644 --- a/crates/collab_ui/src/collab_ui.rs +++ b/crates/collab_ui/src/collab_ui.rs @@ -1,3 +1,4 @@ +mod branch_list; mod collab_titlebar_item; mod contact_finder; mod contact_list; @@ -28,6 +29,7 @@ actions!( ); pub fn init(app_state: &Arc, cx: &mut AppContext) { + branch_list::init(cx); collab_titlebar_item::init(cx); contact_list::init(cx); contact_finder::init(cx); diff --git a/crates/fs/src/repository.rs b/crates/fs/src/repository.rs index 488262887fd6c5c47ceee129840d72a5201531ca..af6198eda444ec772901ed6a856c57100232e2a3 100644 --- a/crates/fs/src/repository.rs +++ b/crates/fs/src/repository.rs @@ -1,6 +1,6 @@ use anyhow::Result; use collections::HashMap; -use git2::ErrorCode; +use git2::{BranchType, ErrorCode}; use parking_lot::Mutex; use rpc::proto; use serde_derive::{Deserialize, Serialize}; @@ -27,6 +27,12 @@ pub trait GitRepository: Send { fn statuses(&self) -> Option>; fn status(&self, path: &RepoPath) -> Result>; + fn branches(&self) -> Result> { + Ok(vec![]) + } + fn change_branch(&self, _: &str) -> Result<()> { + Ok(()) + } } impl std::fmt::Debug for dyn GitRepository { @@ -106,6 +112,30 @@ impl GitRepository for LibGitRepository { } } } + fn branches(&self) -> Result> { + let local_branches = self.branches(Some(BranchType::Local))?; + let valid_branches = local_branches + .filter_map(|branch| { + branch + .ok() + .map(|(branch, _)| branch.name().ok().flatten().map(String::from)) + .flatten() + }) + .collect(); + Ok(valid_branches) + } + fn change_branch(&self, name: &str) -> Result<()> { + let revision = self.find_branch(name, BranchType::Local)?; + let revision = revision.get(); + let as_tree = revision.peel_to_tree()?; + self.checkout_tree(as_tree.as_object(), None)?; + self.set_head( + revision + .name() + .ok_or_else(|| anyhow::anyhow!("Branch name could not be retrieved"))?, + )?; + Ok(()) + } } fn read_status(status: git2::Status) -> Option { From ac6e9c88e9400da223e2d0996c11c40d58ee24cd Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Tue, 27 Jun 2023 12:22:44 +0200 Subject: [PATCH 017/104] Render header and footer of git menu --- crates/collab_ui/src/branch_list.rs | 33 +++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/crates/collab_ui/src/branch_list.rs b/crates/collab_ui/src/branch_list.rs index 8d755e8aa456abdfc4cc7656178b25060147ef46..d946b9da3da54b4fd3c19a2b0b848cc0f55bb4ae 100644 --- a/crates/collab_ui/src/branch_list.rs +++ b/crates/collab_ui/src/branch_list.rs @@ -22,6 +22,7 @@ pub fn build_branch_list( matches: vec![], project, selected_index: 0, + last_query: String::default(), }, cx, ) @@ -33,6 +34,7 @@ pub struct BranchListDelegate { matches: Vec, project: ModelHandle, selected_index: usize, + last_query: String, } impl PickerDelegate for BranchListDelegate { @@ -109,6 +111,7 @@ impl PickerDelegate for BranchListDelegate { let delegate = picker.delegate_mut(); //delegate.branches = actions; delegate.matches = matches; + delegate.last_query = query; if delegate.matches.is_empty() { delegate.selected_index = 0; } else { @@ -175,4 +178,34 @@ impl PickerDelegate for BranchListDelegate { .with_height(theme.contact_finder.row_height) .into_any() } + fn render_header(&self, cx: &AppContext) -> Option>> { + let theme = &theme::current(cx); + let style = theme.picker.no_matches.label.clone(); + if self.last_query.is_empty() { + Some( + Flex::row() + .with_child(Label::new("Recent branches", style)) + .into_any(), + ) + } else { + Some( + Flex::row() + .with_child(Label::new("Branches", style)) + .into_any(), + ) + } + } + fn render_footer(&self, cx: &AppContext) -> Option>> { + if !self.last_query.is_empty() && !self.matches.is_empty() { + let theme = &theme::current(cx); + let style = theme.picker.no_matches.label.clone(); + Some( + Flex::row() + .with_child(Label::new(format!("{} matches", self.matches.len()), style)) + .into_any(), + ) + } else { + None + } + } } From 6747acbb84e9787fa530ba015fd4f17a4f085877 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Tue, 27 Jun 2023 12:40:53 +0200 Subject: [PATCH 018/104] Trail off branch names --- crates/collab_ui/src/branch_list.rs | 25 +++++++++++++------- crates/collab_ui/src/collab_titlebar_item.rs | 1 - 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/crates/collab_ui/src/branch_list.rs b/crates/collab_ui/src/branch_list.rs index d946b9da3da54b4fd3c19a2b0b848cc0f55bb4ae..ddd884523a67ff06fd4a413f35ae6570adde3d4b 100644 --- a/crates/collab_ui/src/branch_list.rs +++ b/crates/collab_ui/src/branch_list.rs @@ -1,4 +1,3 @@ -use client::{ContactRequestStatus, User, UserStore}; use fuzzy::{StringMatch, StringMatchCandidate}; use gpui::{elements::*, AppContext, ModelHandle, MouseState, Task, ViewContext}; use picker::{Picker, PickerDelegate, PickerEvent}; @@ -124,10 +123,8 @@ impl PickerDelegate for BranchListDelegate { } fn confirm(&mut self, cx: &mut ViewContext>) { - log::error!("confirm {}", self.selected_index()); let current_pick = self.selected_index(); let current_pick = self.matches[current_pick].string.clone(); - log::error!("Hi? {current_pick}"); let project = self.project.read(cx); let mut cwd = project .visible_worktrees(cx) @@ -139,7 +136,6 @@ impl PickerDelegate for BranchListDelegate { .path .to_path_buf(); cwd.push(".git"); - log::error!("{current_pick}"); project .fs() .open_repo(&cwd) @@ -161,13 +157,21 @@ impl PickerDelegate for BranchListDelegate { selected: bool, cx: &gpui::AppContext, ) -> AnyElement> { + const DISPLAYED_MATCH_LEN: usize = 29; let theme = &theme::current(cx); - let user = &self.matches[ix]; + let hit = &self.matches[ix]; + let shortened_branch_name = util::truncate_and_trailoff(&hit.string, DISPLAYED_MATCH_LEN); + let highlights = hit + .positions + .iter() + .copied() + .filter(|index| index < &DISPLAYED_MATCH_LEN) + .collect(); let style = theme.picker.item.in_state(selected).style_for(mouse_state); Flex::row() .with_child( - Label::new(user.string.clone(), style.label.clone()) - .with_highlights(user.positions.clone()) + Label::new(shortened_branch_name.clone(), style.label.clone()) + .with_highlights(highlights) .contained() .aligned() .left(), @@ -199,9 +203,14 @@ impl PickerDelegate for BranchListDelegate { if !self.last_query.is_empty() && !self.matches.is_empty() { let theme = &theme::current(cx); let style = theme.picker.no_matches.label.clone(); + // Render "1 match" and "0 matches", "42 matches"etc. + let suffix = if self.matches.len() == 1 { "" } else { "es" }; Some( Flex::row() - .with_child(Label::new(format!("{} matches", self.matches.len()), style)) + .with_child(Label::new( + format!("{} match{}", self.matches.len(), suffix), + style, + )) .into_any(), ) } else { diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index 338ba6cf27de82c786834e584510b211a89d2583..e306aa20b358b8f1423d6940df74c24d3938b910 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -361,7 +361,6 @@ impl CollabTitlebarItem { Flex::column() .with_child(child.flex(1., true)) .contained() - .with_style(theme.contacts_popover.container) .constrained() .with_width(theme.contacts_popover.width) .with_height(theme.contacts_popover.height) From 3027e4729abf2d9c83fe0d06683fa9834a4180f4 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Tue, 27 Jun 2023 13:28:50 +0200 Subject: [PATCH 019/104] Add timestamps to branches --- Cargo.lock | 1 + crates/collab_ui/src/branch_list.rs | 6 ++---- crates/fs/Cargo.toml | 1 + crates/fs/src/repository.rs | 21 +++++++++++++++------ 4 files changed, 19 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a9b2e29ea02e186af4b2034db7ee2e4ceca51a78..a59332520bd8f944b69f65d944c960c644ec587b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2549,6 +2549,7 @@ dependencies = [ "smol", "sum_tree", "tempfile", + "time 0.3.21", "util", ] diff --git a/crates/collab_ui/src/branch_list.rs b/crates/collab_ui/src/branch_list.rs index ddd884523a67ff06fd4a413f35ae6570adde3d4b..7da984a599009a3a4fbf6bdab7c550964e48c7c2 100644 --- a/crates/collab_ui/src/branch_list.rs +++ b/crates/collab_ui/src/branch_list.rs @@ -17,7 +17,6 @@ pub fn build_branch_list( ) -> BranchList { Picker::new( BranchListDelegate { - branches: vec!["Foo".into(), "bar/baz".into()], matches: vec![], project, selected_index: 0, @@ -29,7 +28,6 @@ pub fn build_branch_list( } pub struct BranchListDelegate { - branches: Vec, matches: Vec, project: ModelHandle, selected_index: usize, @@ -77,8 +75,8 @@ impl PickerDelegate for BranchListDelegate { .enumerate() .map(|(ix, command)| StringMatchCandidate { id: ix, - string: command.clone(), - char_bag: command.chars().collect(), + char_bag: command.name.chars().collect(), + string: command.name.into(), }) .collect::>() }) diff --git a/crates/fs/Cargo.toml b/crates/fs/Cargo.toml index cb738f567c31ce0a81b075e7697e384042003faa..b3ebd224b08a21d47f5636b6fb1da8357b65121c 100644 --- a/crates/fs/Cargo.toml +++ b/crates/fs/Cargo.toml @@ -31,6 +31,7 @@ serde_derive.workspace = true serde_json.workspace = true log.workspace = true libc = "0.2" +time.workspace = true [dev-dependencies] gpui = { path = "../gpui", features = ["test-support"] } diff --git a/crates/fs/src/repository.rs b/crates/fs/src/repository.rs index af6198eda444ec772901ed6a856c57100232e2a3..36df0dfb981b10a0d06f48c546d0945f802471be 100644 --- a/crates/fs/src/repository.rs +++ b/crates/fs/src/repository.rs @@ -16,6 +16,12 @@ use util::ResultExt; pub use git2::Repository as LibGitRepository; +#[derive(Clone, Debug, Hash, PartialEq)] +pub struct Branch { + pub name: Box, + /// Timestamp of most recent commit, normalized to Unix Epoch format. + pub unix_timestamp: Option, +} #[async_trait::async_trait] pub trait GitRepository: Send { fn reload_index(&self); @@ -27,7 +33,7 @@ pub trait GitRepository: Send { fn statuses(&self) -> Option>; fn status(&self, path: &RepoPath) -> Result>; - fn branches(&self) -> Result> { + fn branches(&self) -> Result> { Ok(vec![]) } fn change_branch(&self, _: &str) -> Result<()> { @@ -112,14 +118,17 @@ impl GitRepository for LibGitRepository { } } } - fn branches(&self) -> Result> { + fn branches(&self) -> Result> { let local_branches = self.branches(Some(BranchType::Local))?; let valid_branches = local_branches .filter_map(|branch| { - branch - .ok() - .map(|(branch, _)| branch.name().ok().flatten().map(String::from)) - .flatten() + branch.ok().and_then(|(branch, _)| { + let name = branch.name().ok().flatten().map(Box::from)?; + Some(Branch { + name, + unix_timestamp: None, + }) + }) }) .collect(); Ok(valid_branches) From 54fad5969f5f0aa649cccb27493e48d7cf99f5b3 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Tue, 27 Jun 2023 14:20:36 +0200 Subject: [PATCH 020/104] List recent branches --- crates/collab_ui/src/branch_list.rs | 23 ++++++++++++++++++----- crates/fs/src/repository.rs | 9 ++++++++- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/crates/collab_ui/src/branch_list.rs b/crates/collab_ui/src/branch_list.rs index 7da984a599009a3a4fbf6bdab7c550964e48c7c2..146e4c804113490779f30acd71747599772369a6 100644 --- a/crates/collab_ui/src/branch_list.rs +++ b/crates/collab_ui/src/branch_list.rs @@ -2,7 +2,7 @@ use fuzzy::{StringMatch, StringMatchCandidate}; use gpui::{elements::*, AppContext, ModelHandle, MouseState, Task, ViewContext}; use picker::{Picker, PickerDelegate, PickerEvent}; use project::Project; -use std::sync::Arc; +use std::{cmp::Ordering, sync::Arc}; use util::{ResultExt, TryFutureExt}; pub fn init(cx: &mut AppContext) { @@ -67,9 +67,23 @@ impl PickerDelegate for BranchListDelegate { .path .to_path_buf(); cwd.push(".git"); - let branches = project.fs().open_repo(&cwd).unwrap().lock().branches(); - branches + let mut branches = project + .fs() + .open_repo(&cwd) .unwrap() + .lock() + .branches() + .unwrap(); + if query.is_empty() { + const RECENT_BRANCHES_COUNT: usize = 10; + // Do a partial sort to show recent-ish branches first. + branches.select_nth_unstable_by(RECENT_BRANCHES_COUNT, |lhs, rhs| { + rhs.unix_timestamp.cmp(&lhs.unix_timestamp) + }); + branches.truncate(RECENT_BRANCHES_COUNT); + branches.sort_unstable_by(|lhs, rhs| lhs.name.cmp(&rhs.name)); + } + branches .iter() .cloned() .enumerate() @@ -106,15 +120,14 @@ impl PickerDelegate for BranchListDelegate { picker .update(&mut cx, |picker, _| { let delegate = picker.delegate_mut(); - //delegate.branches = actions; delegate.matches = matches; - delegate.last_query = query; if delegate.matches.is_empty() { delegate.selected_index = 0; } else { delegate.selected_index = core::cmp::min(delegate.selected_index, delegate.matches.len() - 1); } + delegate.last_query = query; }) .log_err(); }) diff --git a/crates/fs/src/repository.rs b/crates/fs/src/repository.rs index 36df0dfb981b10a0d06f48c546d0945f802471be..0e5fd8343fa1a7f441e9d7474c4ea0a96c0df575 100644 --- a/crates/fs/src/repository.rs +++ b/crates/fs/src/repository.rs @@ -124,9 +124,16 @@ impl GitRepository for LibGitRepository { .filter_map(|branch| { branch.ok().and_then(|(branch, _)| { let name = branch.name().ok().flatten().map(Box::from)?; + let timestamp = branch.get().peel_to_commit().ok()?.time(); + let unix_timestamp = timestamp.seconds(); + let timezone_offset = timestamp.offset_minutes(); + let utc_offset = + time::UtcOffset::from_whole_seconds(timezone_offset * 60).ok()?; + let unix_timestamp = + time::OffsetDateTime::from_unix_timestamp(unix_timestamp).ok()?; Some(Branch { name, - unix_timestamp: None, + unix_timestamp: Some(unix_timestamp.to_offset(utc_offset).unix_timestamp()), }) }) }) From c84f3b3bfc2a2434017ab23e3bcaeae98424623f Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Tue, 27 Jun 2023 20:12:20 +0200 Subject: [PATCH 021/104] Add toast for git checkout failure --- crates/collab_ui/src/branch_list.rs | 31 ++++++++++++++------ crates/collab_ui/src/collab_titlebar_item.rs | 22 +++++++------- 2 files changed, 34 insertions(+), 19 deletions(-) diff --git a/crates/collab_ui/src/branch_list.rs b/crates/collab_ui/src/branch_list.rs index 146e4c804113490779f30acd71747599772369a6..2558b24ae8b3d0bf5261145c761f96a65e8cd3e8 100644 --- a/crates/collab_ui/src/branch_list.rs +++ b/crates/collab_ui/src/branch_list.rs @@ -1,9 +1,10 @@ use fuzzy::{StringMatch, StringMatchCandidate}; -use gpui::{elements::*, AppContext, ModelHandle, MouseState, Task, ViewContext}; +use gpui::{elements::*, AppContext, ModelHandle, MouseState, Task, ViewContext, ViewHandle}; use picker::{Picker, PickerDelegate, PickerEvent}; use project::Project; use std::{cmp::Ordering, sync::Arc}; use util::{ResultExt, TryFutureExt}; +use workspace::{Toast, Workspace}; pub fn init(cx: &mut AppContext) { Picker::::init(cx); @@ -12,13 +13,13 @@ pub fn init(cx: &mut AppContext) { pub type BranchList = Picker; pub fn build_branch_list( - project: ModelHandle, + workspace: ViewHandle, cx: &mut ViewContext, ) -> BranchList { Picker::new( BranchListDelegate { matches: vec![], - project, + workspace, selected_index: 0, last_query: String::default(), }, @@ -29,7 +30,7 @@ pub fn build_branch_list( pub struct BranchListDelegate { matches: Vec, - project: ModelHandle, + workspace: ViewHandle, selected_index: usize, last_query: String, } @@ -56,7 +57,7 @@ impl PickerDelegate for BranchListDelegate { let candidates = picker .read_with(&mut cx, |view, cx| { let delegate = view.delegate(); - let project = delegate.project.read(&cx); + let project = delegate.workspace.read(cx).project().read(&cx); let mut cwd = project .visible_worktrees(cx) .next() @@ -136,7 +137,7 @@ impl PickerDelegate for BranchListDelegate { fn confirm(&mut self, cx: &mut ViewContext>) { let current_pick = self.selected_index(); let current_pick = self.matches[current_pick].string.clone(); - let project = self.project.read(cx); + let project = self.workspace.read(cx).project().read(cx); let mut cwd = project .visible_worktrees(cx) .next() @@ -147,13 +148,25 @@ impl PickerDelegate for BranchListDelegate { .path .to_path_buf(); cwd.push(".git"); - project + let status = project .fs() .open_repo(&cwd) .unwrap() .lock() - .change_branch(¤t_pick) - .log_err(); + .change_branch(¤t_pick); + if let Err(err) = &status { + const GIT_CHECKOUT_FAILURE_ID: usize = 2048; + self.workspace.update(cx, |model, ctx| { + model.show_toast( + Toast::new( + GIT_CHECKOUT_FAILURE_ID, + format!("Failed to check out branch `{current_pick}`, error: `{err}`"), + ), + ctx, + ) + }); + } + status.log_err(); cx.emit(PickerEvent::Dismiss); } diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index e306aa20b358b8f1423d6940df74c24d3938b910..b38ac39798de0de3542df73f928f56a0836e1703 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -381,18 +381,20 @@ impl CollabTitlebarItem { } pub fn toggle_vcs_menu(&mut self, _: &ToggleVcsMenu, cx: &mut ViewContext) { if self.branch_popover.take().is_none() { - let view = cx.add_view(|cx| build_branch_list(self.project.clone(), cx)); - cx.subscribe(&view, |this, _, event, cx| { - match event { - PickerEvent::Dismiss => { - this.contacts_popover = None; + if let Some(workspace) = self.workspace.upgrade(cx) { + let view = cx.add_view(|cx| build_branch_list(workspace, cx)); + cx.subscribe(&view, |this, _, event, cx| { + match event { + PickerEvent::Dismiss => { + this.contacts_popover = None; + } } - } - cx.notify(); - }) - .detach(); - self.branch_popover = Some(view); + cx.notify(); + }) + .detach(); + self.branch_popover = Some(view); + } } cx.notify(); From aeafa6f6d6242dd81c0162e6528b240f3c4b61c2 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Thu, 29 Jun 2023 11:40:10 +0200 Subject: [PATCH 022/104] Fix build after rebase --- crates/collab_ui/src/collab_titlebar_item.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index b38ac39798de0de3542df73f928f56a0836e1703..48a4e12ff53bcfc99489dc38e6447eed62e605b1 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -254,9 +254,7 @@ impl CollabTitlebarItem { this.toggle_vcs_menu(&Default::default(), cx) }), ) - .with_children( - self.render_branches_popover_host(&theme.workspace.titlebar, cx), - ), + .with_children(self.render_branches_popover_host(&theme.titlebar, cx)), ) } ret.into_any() From e57364ede6d4e3f89a560934ed814e9ec93138a0 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Thu, 29 Jun 2023 11:42:20 +0200 Subject: [PATCH 023/104] Remove unnecessary imports --- crates/collab_ui/src/branch_list.rs | 7 +++---- crates/collab_ui/src/collab_titlebar_item.rs | 3 +-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/crates/collab_ui/src/branch_list.rs b/crates/collab_ui/src/branch_list.rs index 2558b24ae8b3d0bf5261145c761f96a65e8cd3e8..2fb8721c946cd65bdefa61767c259d414403ebb6 100644 --- a/crates/collab_ui/src/branch_list.rs +++ b/crates/collab_ui/src/branch_list.rs @@ -1,9 +1,8 @@ use fuzzy::{StringMatch, StringMatchCandidate}; -use gpui::{elements::*, AppContext, ModelHandle, MouseState, Task, ViewContext, ViewHandle}; +use gpui::{elements::*, AppContext, MouseState, Task, ViewContext, ViewHandle}; use picker::{Picker, PickerDelegate, PickerEvent}; -use project::Project; -use std::{cmp::Ordering, sync::Arc}; -use util::{ResultExt, TryFutureExt}; +use std::sync::Arc; +use util::ResultExt; use workspace::{Toast, Workspace}; pub fn init(cx: &mut AppContext) { diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index 48a4e12ff53bcfc99489dc38e6447eed62e605b1..e6a0c98265d40ac24e727655667314b6c25d6b85 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -15,7 +15,6 @@ use gpui::{ actions, color::Color, elements::*, - fonts::TextStyle, geometry::{rect::RectF, vector::vec2f, PathBuilder}, json::{self, ToJson}, platform::{CursorStyle, MouseButton}, @@ -241,7 +240,7 @@ impl CollabTitlebarItem { ret = ret.with_child( Stack::new() .with_child( - MouseEventHandler::::new(0, cx, |state, _| { + MouseEventHandler::::new(0, cx, |_, _| { Label::new(git_branch, style) .contained() .with_margin_right(item_spacing) From 98f71a7fa3822840665c5fe7a1e25909b12d98ed Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Thu, 29 Jun 2023 11:47:50 +0200 Subject: [PATCH 024/104] Trail off project/branch name --- crates/collab_ui/src/collab_titlebar_item.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index e6a0c98265d40ac24e727655667314b6c25d6b85..5bef89d1ee8126a9f857c4368dc77b890187daca 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -28,7 +28,8 @@ use theme::{AvatarStyle, Theme}; use util::ResultExt; use workspace::{FollowNextCollaborator, Workspace}; -// const MAX_TITLE_LENGTH: usize = 75; +const MAX_PROJECT_NAME_LENGTH: usize = 40; +const MAX_BRANCH_NAME_LENGTH: usize = 40; actions!( collab, @@ -210,11 +211,16 @@ impl CollabTitlebarItem { names_and_branches.next().unwrap_or(("", None)) }; - let name = name.to_owned(); + let name = util::truncate_and_trailoff(name, MAX_PROJECT_NAME_LENGTH); let branch_prepended = entry .as_ref() .and_then(RepositoryEntry::branch) - .map(|branch| format!("/{branch}")); + .map(|branch| { + format!( + "/{}", + util::truncate_and_trailoff(&branch, MAX_BRANCH_NAME_LENGTH) + ) + }); let text_style = theme.titlebar.title.clone(); let item_spacing = theme.titlebar.item_spacing; From 1eb0f3d09156f01c280793d080702e3c0b78a7fb Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Thu, 29 Jun 2023 12:12:35 +0200 Subject: [PATCH 025/104] Update toast for checkout failure --- crates/collab_ui/src/branch_list.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/collab_ui/src/branch_list.rs b/crates/collab_ui/src/branch_list.rs index 2fb8721c946cd65bdefa61767c259d414403ebb6..eb6b9c6f54047dc037641452324006b0f1d7a4fe 100644 --- a/crates/collab_ui/src/branch_list.rs +++ b/crates/collab_ui/src/branch_list.rs @@ -159,7 +159,7 @@ impl PickerDelegate for BranchListDelegate { model.show_toast( Toast::new( GIT_CHECKOUT_FAILURE_ID, - format!("Failed to check out branch `{current_pick}`, error: `{err}`"), + format!("Failed to checkout branch '{current_pick}', check for conflicts or unstashed files"), ), ctx, ) From d000ea97398d64613056a4dba9f6602257bb1e36 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Thu, 29 Jun 2023 12:57:49 +0200 Subject: [PATCH 026/104] Fix warning about unused variable --- crates/collab_ui/src/branch_list.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/collab_ui/src/branch_list.rs b/crates/collab_ui/src/branch_list.rs index eb6b9c6f54047dc037641452324006b0f1d7a4fe..2d014cc1b93d8cf063d0ec6e44ec882f2a149b4e 100644 --- a/crates/collab_ui/src/branch_list.rs +++ b/crates/collab_ui/src/branch_list.rs @@ -153,7 +153,7 @@ impl PickerDelegate for BranchListDelegate { .unwrap() .lock() .change_branch(¤t_pick); - if let Err(err) = &status { + if status.is_err() { const GIT_CHECKOUT_FAILURE_ID: usize = 2048; self.workspace.update(cx, |model, ctx| { model.show_toast( From 888d3b3fd620722a44483222cd4c3201153b15a4 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Thu, 29 Jun 2023 18:03:01 +0200 Subject: [PATCH 027/104] Project dropdown menu --- Cargo.lock | 2 + crates/collab_ui/Cargo.toml | 2 + crates/collab_ui/src/collab_titlebar_item.rs | 79 +++++++++++++++++-- crates/recent_projects/Cargo.toml | 1 + crates/recent_projects/src/recent_projects.rs | 21 ++++- 5 files changed, 95 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a59332520bd8f944b69f65d944c960c644ec587b..d16248c85aea2e3123d101db114774df0fc19c64 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1415,6 +1415,7 @@ dependencies = [ "picker", "postage", "project", + "recent_projects", "serde", "serde_derive", "settings", @@ -5376,6 +5377,7 @@ version = "0.1.0" dependencies = [ "db", "editor", + "futures 0.3.28", "fuzzy", "gpui", "language", diff --git a/crates/collab_ui/Cargo.toml b/crates/collab_ui/Cargo.toml index ee410ccba7a57e68af7601e2ea3fd0fc654f653d..f81885c07a02fbc526d7c675762f3468db571d50 100644 --- a/crates/collab_ui/Cargo.toml +++ b/crates/collab_ui/Cargo.toml @@ -35,6 +35,7 @@ gpui = { path = "../gpui" } menu = { path = "../menu" } picker = { path = "../picker" } project = { path = "../project" } +recent_projects = {path = "../recent_projects"} settings = { path = "../settings" } theme = { path = "../theme" } theme_selector = { path = "../theme_selector" } @@ -42,6 +43,7 @@ util = { path = "../util" } workspace = { path = "../workspace" } zed-actions = {path = "../zed-actions"} + anyhow.workspace = true futures.workspace = true log.workspace = true diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index 5bef89d1ee8126a9f857c4368dc77b890187daca..8dccf2a71a5cf1097df80373b296d26c7e5de3cb 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -23,6 +23,7 @@ use gpui::{ }; use picker::PickerEvent; use project::{Project, RepositoryEntry}; +use recent_projects::{build_recent_projects, RecentProjects}; use std::{ops::Range, sync::Arc}; use theme::{AvatarStyle, Theme}; use util::ResultExt; @@ -37,6 +38,7 @@ actions!( ToggleContactsMenu, ToggleUserMenu, ToggleVcsMenu, + ToggleProjectMenu, SwitchBranch, ShareProject, UnshareProject, @@ -49,6 +51,7 @@ pub fn init(cx: &mut AppContext) { cx.add_action(CollabTitlebarItem::unshare_project); cx.add_action(CollabTitlebarItem::toggle_user_menu); cx.add_action(CollabTitlebarItem::toggle_vcs_menu); + cx.add_action(CollabTitlebarItem::toggle_project_menu); } pub struct CollabTitlebarItem { @@ -58,6 +61,7 @@ pub struct CollabTitlebarItem { workspace: WeakViewHandle, contacts_popover: Option>, branch_popover: Option>, + project_popover: Option>, user_menu: ViewHandle, _subscriptions: Vec, } @@ -191,6 +195,7 @@ impl CollabTitlebarItem { menu }), branch_popover: None, + project_popover: None, _subscriptions: subscriptions, } } @@ -233,14 +238,22 @@ impl CollabTitlebarItem { }; let highlights = (0..name.len()).into_iter().collect(); let mut ret = Flex::row().with_child( - Stack::new().with_child( - Label::new(name, style.clone()) - .with_highlights(highlights) - .contained() - .aligned() - .left() - .into_any_named("title-project-name"), - ), + Stack::new() + .with_child( + MouseEventHandler::::new(0, cx, |_, _| { + Label::new(name, style.clone()) + .with_highlights(highlights) + .contained() + .aligned() + .left() + .into_any_named("title-project-name") + }) + .with_cursor_style(CursorStyle::PointingHand) + .on_click(MouseButton::Left, move |_, this, cx| { + this.toggle_project_menu(&Default::default(), cx) + }), + ) + .with_children(self.render_project_popover_host(&theme.titlebar, cx)), ); if let Some(git_branch) = branch_prepended { ret = ret.with_child( @@ -382,6 +395,36 @@ impl CollabTitlebarItem { .into_any() }) } + fn render_project_popover_host<'a>( + &'a self, + _theme: &'a theme::Titlebar, + cx: &'a mut ViewContext, + ) -> Option> { + self.project_popover.as_ref().map(|child| { + let theme = theme::current(cx).clone(); + let child = ChildView::new(child, cx); + let child = MouseEventHandler::::new(0, cx, |_, _| { + Flex::column() + .with_child(child.flex(1., true)) + .contained() + .constrained() + .with_width(theme.contacts_popover.width) + .with_height(theme.contacts_popover.height) + }) + .on_click(MouseButton::Left, |_, _, _| {}) + .on_down_out(MouseButton::Left, move |_, _, cx| cx.emit(())) + .into_any(); + + Overlay::new(child) + .with_fit_mode(OverlayFitMode::SwitchAnchor) + .with_anchor_corner(AnchorCorner::TopLeft) + .with_z_index(999) + .aligned() + .bottom() + .left() + .into_any() + }) + } pub fn toggle_vcs_menu(&mut self, _: &ToggleVcsMenu, cx: &mut ViewContext) { if self.branch_popover.take().is_none() { if let Some(workspace) = self.workspace.upgrade(cx) { @@ -402,6 +445,26 @@ impl CollabTitlebarItem { cx.notify(); } + + pub fn toggle_project_menu(&mut self, _: &ToggleProjectMenu, cx: &mut ViewContext) { + log::error!("Toggling project menu"); + if self.project_popover.take().is_none() { + let view = cx.add_view(|cx| build_recent_projects(self.workspace.clone(), cx)); + cx.subscribe(&view, |this, _, event, cx| { + match event { + PickerEvent::Dismiss => { + this.project_popover = None; + } + } + + cx.notify(); + }) + .detach(); + self.project_popover = Some(view); + } + + cx.notify(); + } fn render_toggle_contacts_button( &self, theme: &Theme, diff --git a/crates/recent_projects/Cargo.toml b/crates/recent_projects/Cargo.toml index 14f8853c9c0aa9177365bb49b3f366d8fc3f2c0d..51774e8febaed924f201a8f088c86bd3ec0c0e31 100644 --- a/crates/recent_projects/Cargo.toml +++ b/crates/recent_projects/Cargo.toml @@ -21,6 +21,7 @@ util = { path = "../util"} theme = { path = "../theme" } workspace = { path = "../workspace" } +futures.workspace = true ordered-float.workspace = true postage.workspace = true smol.workspace = true diff --git a/crates/recent_projects/src/recent_projects.rs b/crates/recent_projects/src/recent_projects.rs index b13f72da0b247a4947b8bae505a2fe3b9e09cb67..ed901a7da888b01271c7a41cf8c1eb452963d877 100644 --- a/crates/recent_projects/src/recent_projects.rs +++ b/crates/recent_projects/src/recent_projects.rs @@ -64,9 +64,26 @@ fn toggle( })) } -type RecentProjects = Picker; +pub fn build_recent_projects( + workspace: WeakViewHandle, + cx: &mut ViewContext, +) -> RecentProjects { + let workspaces = futures::executor::block_on(async { + WORKSPACE_DB + .recent_workspaces_on_disk() + .await + .unwrap_or_default() + .into_iter() + .map(|(_, location)| location) + .collect() + }); + Picker::new(RecentProjectsDelegate::new(workspace, workspaces), cx) + .with_theme(|theme| theme.picker.clone()) +} + +pub type RecentProjects = Picker; -struct RecentProjectsDelegate { +pub struct RecentProjectsDelegate { workspace: WeakViewHandle, workspace_locations: Vec, selected_match_index: usize, From 818ddbc7031f764a444e103b77eecd4eb2aba91b Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Thu, 29 Jun 2023 18:04:58 +0200 Subject: [PATCH 028/104] Make project dropdown exclusive wrt git menu --- crates/collab_ui/src/collab_titlebar_item.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index 8dccf2a71a5cf1097df80373b296d26c7e5de3cb..c78ce2f4e1d8e8866e2af9d4be77054671cd391b 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -439,6 +439,7 @@ impl CollabTitlebarItem { cx.notify(); }) .detach(); + self.project_popover.take(); self.branch_popover = Some(view); } } @@ -447,7 +448,6 @@ impl CollabTitlebarItem { } pub fn toggle_project_menu(&mut self, _: &ToggleProjectMenu, cx: &mut ViewContext) { - log::error!("Toggling project menu"); if self.project_popover.take().is_none() { let view = cx.add_view(|cx| build_recent_projects(self.workspace.clone(), cx)); cx.subscribe(&view, |this, _, event, cx| { @@ -460,6 +460,7 @@ impl CollabTitlebarItem { cx.notify(); }) .detach(); + self.branch_popover.take(); self.project_popover = Some(view); } From 081e340d26285692785871fe3c754153463d54e7 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Thu, 29 Jun 2023 19:07:51 +0200 Subject: [PATCH 029/104] Do not query db on foreground thread. Co-authored-by: Mikayla --- crates/collab_ui/src/collab_titlebar_item.rs | 42 +++++++++++++------ crates/recent_projects/src/recent_projects.rs | 10 +---- 2 files changed, 30 insertions(+), 22 deletions(-) diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index c78ce2f4e1d8e8866e2af9d4be77054671cd391b..511113a36075313f27b44201a46c0283f9f34629 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -27,7 +27,7 @@ use recent_projects::{build_recent_projects, RecentProjects}; use std::{ops::Range, sync::Arc}; use theme::{AvatarStyle, Theme}; use util::ResultExt; -use workspace::{FollowNextCollaborator, Workspace}; +use workspace::{FollowNextCollaborator, Workspace, WORKSPACE_DB}; const MAX_PROJECT_NAME_LENGTH: usize = 40; const MAX_BRANCH_NAME_LENGTH: usize = 40; @@ -448,23 +448,39 @@ impl CollabTitlebarItem { } pub fn toggle_project_menu(&mut self, _: &ToggleProjectMenu, cx: &mut ViewContext) { + let workspace = self.workspace.clone(); if self.project_popover.take().is_none() { - let view = cx.add_view(|cx| build_recent_projects(self.workspace.clone(), cx)); - cx.subscribe(&view, |this, _, event, cx| { - match event { - PickerEvent::Dismiss => { - this.project_popover = None; - } - } + cx.spawn(|this, mut cx| async move { + let workspaces = WORKSPACE_DB + .recent_workspaces_on_disk() + .await + .unwrap_or_default() + .into_iter() + .map(|(_, location)| location) + .collect(); + + let workspace = workspace.clone(); + this.update(&mut cx, move |this, cx| { + let view = cx.add_view(|cx| build_recent_projects(workspace, workspaces, cx)); + + cx.subscribe(&view, |this, _, event, cx| { + match event { + PickerEvent::Dismiss => { + this.project_popover = None; + } + } - cx.notify(); + cx.notify(); + }) + .detach(); + this.branch_popover.take(); + this.project_popover = Some(view); + cx.notify(); + }) + .log_err(); }) .detach(); - self.branch_popover.take(); - self.project_popover = Some(view); } - - cx.notify(); } fn render_toggle_contacts_button( &self, diff --git a/crates/recent_projects/src/recent_projects.rs b/crates/recent_projects/src/recent_projects.rs index ed901a7da888b01271c7a41cf8c1eb452963d877..b3c9655645722a976bd3dffe8f430576753ad856 100644 --- a/crates/recent_projects/src/recent_projects.rs +++ b/crates/recent_projects/src/recent_projects.rs @@ -66,17 +66,9 @@ fn toggle( pub fn build_recent_projects( workspace: WeakViewHandle, + workspaces: Vec, cx: &mut ViewContext, ) -> RecentProjects { - let workspaces = futures::executor::block_on(async { - WORKSPACE_DB - .recent_workspaces_on_disk() - .await - .unwrap_or_default() - .into_iter() - .map(|(_, location)| location) - .collect() - }); Picker::new(RecentProjectsDelegate::new(workspace, workspaces), cx) .with_theme(|theme| theme.picker.clone()) } From c1a629215269b255b75629866fa79e229dd037fc Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Fri, 30 Jun 2023 12:15:47 +0200 Subject: [PATCH 030/104] Add missing call to cx.notify --- crates/collab_ui/src/collab_titlebar_item.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index 511113a36075313f27b44201a46c0283f9f34629..1fdce6f186e6965b47271261dcff32e0fc48c481 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -481,6 +481,7 @@ impl CollabTitlebarItem { }) .detach(); } + cx.notify(); } fn render_toggle_contacts_button( &self, From 3be8977ee86a3fb86ff27fbeb9c39e4797e28c9f Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Fri, 30 Jun 2023 14:00:37 +0200 Subject: [PATCH 031/104] Switch branches within spawn() --- crates/collab_ui/src/branch_list.rs | 87 +++++++++++++++-------------- 1 file changed, 46 insertions(+), 41 deletions(-) diff --git a/crates/collab_ui/src/branch_list.rs b/crates/collab_ui/src/branch_list.rs index 2d014cc1b93d8cf063d0ec6e44ec882f2a149b4e..038180b6716fa2cac876e914198170b3febd4f86 100644 --- a/crates/collab_ui/src/branch_list.rs +++ b/crates/collab_ui/src/branch_list.rs @@ -1,3 +1,4 @@ +use anyhow::{anyhow, bail}; use fuzzy::{StringMatch, StringMatchCandidate}; use gpui::{elements::*, AppContext, MouseState, Task, ViewContext, ViewHandle}; use picker::{Picker, PickerDelegate, PickerEvent}; @@ -53,7 +54,7 @@ impl PickerDelegate for BranchListDelegate { fn update_matches(&mut self, query: String, cx: &mut ViewContext>) -> Task<()> { cx.spawn(move |picker, mut cx| async move { - let candidates = picker + let Some(candidates) = picker .read_with(&mut cx, |view, cx| { let delegate = view.delegate(); let project = delegate.workspace.read(cx).project().read(&cx); @@ -67,13 +68,10 @@ impl PickerDelegate for BranchListDelegate { .path .to_path_buf(); cwd.push(".git"); - let mut branches = project - .fs() - .open_repo(&cwd) - .unwrap() + let Some(repo) = project.fs().open_repo(&cwd) else {bail!("Project does not have associated git repository.")}; + let mut branches = repo .lock() - .branches() - .unwrap(); + .branches()?; if query.is_empty() { const RECENT_BRANCHES_COUNT: usize = 10; // Do a partial sort to show recent-ish branches first. @@ -83,7 +81,7 @@ impl PickerDelegate for BranchListDelegate { branches.truncate(RECENT_BRANCHES_COUNT); branches.sort_unstable_by(|lhs, rhs| lhs.name.cmp(&rhs.name)); } - branches + Ok(branches .iter() .cloned() .enumerate() @@ -92,9 +90,10 @@ impl PickerDelegate for BranchListDelegate { char_bag: command.name.chars().collect(), string: command.name.into(), }) - .collect::>() + .collect::>()) }) - .unwrap(); + .log_err() else { return; }; + let Some(candidates) = candidates.log_err() else {return;}; let matches = if query.is_empty() { candidates .into_iter() @@ -136,37 +135,43 @@ impl PickerDelegate for BranchListDelegate { fn confirm(&mut self, cx: &mut ViewContext>) { let current_pick = self.selected_index(); let current_pick = self.matches[current_pick].string.clone(); - let project = self.workspace.read(cx).project().read(cx); - let mut cwd = project - .visible_worktrees(cx) - .next() - .unwrap() - .read(cx) - .root_entry() - .unwrap() - .path - .to_path_buf(); - cwd.push(".git"); - let status = project - .fs() - .open_repo(&cwd) - .unwrap() - .lock() - .change_branch(¤t_pick); - if status.is_err() { - const GIT_CHECKOUT_FAILURE_ID: usize = 2048; - self.workspace.update(cx, |model, ctx| { - model.show_toast( - Toast::new( - GIT_CHECKOUT_FAILURE_ID, - format!("Failed to checkout branch '{current_pick}', check for conflicts or unstashed files"), - ), - ctx, - ) - }); - } - status.log_err(); - cx.emit(PickerEvent::Dismiss); + cx.spawn(|picker, mut cx| async move { + picker.update(&mut cx, |this, cx| { + let project = this.delegate().workspace.read(cx).project().read(cx); + let mut cwd = project + .visible_worktrees(cx) + .next() + .ok_or_else(|| anyhow!("There are no visisible worktrees."))? + .read(cx) + .root_entry() + .ok_or_else(|| anyhow!("Worktree has no root entry."))? + .path + .to_path_buf(); + cwd.push(".git"); + let status = project + .fs() + .open_repo(&cwd) + .ok_or_else(|| anyhow!("Could not open repository at path `{}`", cwd.as_os_str().to_string_lossy()))? + .lock() + .change_branch(¤t_pick); + if status.is_err() { + const GIT_CHECKOUT_FAILURE_ID: usize = 2048; + this.delegate().workspace.update(cx, |model, ctx| { + model.show_toast( + Toast::new( + GIT_CHECKOUT_FAILURE_ID, + format!("Failed to checkout branch '{current_pick}', check for conflicts or unstashed files"), + ), + ctx, + ) + }); + status?; + } + cx.emit(PickerEvent::Dismiss); + + Ok::<(), anyhow::Error>(()) + }).log_err(); + }).detach(); } fn dismissed(&mut self, cx: &mut ViewContext>) { From b699e5c142f900ae0e38574ec2ad1e11e1a693cf Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Fri, 30 Jun 2023 16:23:27 +0200 Subject: [PATCH 032/104] Add styles to git menu --- crates/collab_ui/src/branch_list.rs | 40 +++++++++++-------------- crates/theme/src/theme.rs | 2 ++ styles/src/style_tree/contact_finder.ts | 2 ++ styles/src/style_tree/picker.ts | 29 ++++++++++++++++++ 4 files changed, 51 insertions(+), 22 deletions(-) diff --git a/crates/collab_ui/src/branch_list.rs b/crates/collab_ui/src/branch_list.rs index 038180b6716fa2cac876e914198170b3febd4f86..95e418e67ffc746d85dd155e2ea6e8b429e27a7b 100644 --- a/crates/collab_ui/src/branch_list.rs +++ b/crates/collab_ui/src/branch_list.rs @@ -2,7 +2,7 @@ use anyhow::{anyhow, bail}; use fuzzy::{StringMatch, StringMatchCandidate}; use gpui::{elements::*, AppContext, MouseState, Task, ViewContext, ViewHandle}; use picker::{Picker, PickerDelegate, PickerEvent}; -use std::sync::Arc; +use std::{ops::Not, sync::Arc}; use util::ResultExt; use workspace::{Toast, Workspace}; @@ -212,7 +212,7 @@ impl PickerDelegate for BranchListDelegate { } fn render_header(&self, cx: &AppContext) -> Option>> { let theme = &theme::current(cx); - let style = theme.picker.no_matches.label.clone(); + let style = theme.picker.header.clone(); if self.last_query.is_empty() { Some( Flex::row() @@ -221,28 +221,24 @@ impl PickerDelegate for BranchListDelegate { ) } else { Some( - Flex::row() - .with_child(Label::new("Branches", style)) - .into_any(), - ) - } - } - fn render_footer(&self, cx: &AppContext) -> Option>> { - if !self.last_query.is_empty() && !self.matches.is_empty() { - let theme = &theme::current(cx); - let style = theme.picker.no_matches.label.clone(); - // Render "1 match" and "0 matches", "42 matches"etc. - let suffix = if self.matches.len() == 1 { "" } else { "es" }; - Some( - Flex::row() - .with_child(Label::new( - format!("{} match{}", self.matches.len(), suffix), - style, - )) + Stack::new() + .with_child( + Flex::row() + .with_child(Label::new("Branches", style.clone()).aligned().left()), + ) + .with_children(self.matches.is_empty().not().then(|| { + let suffix = if self.matches.len() == 1 { "" } else { "es" }; + Flex::row() + .align_children_center() + .with_child(Label::new( + format!("{} match{}", self.matches.len(), suffix), + style, + )) + .aligned() + .right() + })) .into_any(), ) - } else { - None } } } diff --git a/crates/theme/src/theme.rs b/crates/theme/src/theme.rs index e54dcdfd1e987eaf24656bc735079db54d37f0bc..687547a3066bdf8e436a42f376bfd6ddb96f127e 100644 --- a/crates/theme/src/theme.rs +++ b/crates/theme/src/theme.rs @@ -585,6 +585,8 @@ pub struct Picker { pub empty_input_editor: FieldEditor, pub no_matches: ContainedLabel, pub item: Toggleable>, + pub header: LabelStyle, + pub footer: LabelStyle, } #[derive(Clone, Debug, Deserialize, Default, JsonSchema)] diff --git a/styles/src/style_tree/contact_finder.ts b/styles/src/style_tree/contact_finder.ts index e61d100264bb9713f312c27c446ff36f054e77f5..4815a4e98e5e4c0c789054b985a55fe8b0afbdd6 100644 --- a/styles/src/style_tree/contact_finder.ts +++ b/styles/src/style_tree/contact_finder.ts @@ -44,6 +44,8 @@ export default function contact_finder(theme: ColorScheme): any { no_matches: picker_style.no_matches, input_editor: picker_input, empty_input_editor: picker_input, + header: picker_style.header, + footer: picker_style.footer, }, row_height: 28, contact_avatar: { diff --git a/styles/src/style_tree/picker.ts b/styles/src/style_tree/picker.ts index 7ca76cd85f324d9cc640dd3845a1ca1d3e89a751..9918d1a2d66381562fc0864d1fa1425b960ea2c2 100644 --- a/styles/src/style_tree/picker.ts +++ b/styles/src/style_tree/picker.ts @@ -108,5 +108,34 @@ export default function picker(theme: ColorScheme): any { top: 8, }, }, + header: { + text: text(theme.lowest, "sans", "variant", { size: "xs" }), + padding: { + bottom: 4, + left: 12, + right: 12, + top: 4, + }, + margin: { + top: 1, + left: 4, + right: 4, + }, + }, + footer: { + text: text(theme.lowest, "sans", "variant", { size: "xs" }), + padding: { + bottom: 4, + left: 12, + right: 12, + top: 4, + }, + margin: { + top: 1, + left: 4, + right: 4, + }, + + } } } From ed75c316405814d2d06c96affb0d07de292ec3ad Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Fri, 30 Jun 2023 16:38:38 +0200 Subject: [PATCH 033/104] Improve styling of git menu --- crates/collab_ui/src/branch_list.rs | 23 +++++++++++++++++++---- crates/theme/src/theme.rs | 4 ++-- styles/src/style_tree/picker.ts | 21 +++++---------------- 3 files changed, 26 insertions(+), 22 deletions(-) diff --git a/crates/collab_ui/src/branch_list.rs b/crates/collab_ui/src/branch_list.rs index 95e418e67ffc746d85dd155e2ea6e8b429e27a7b..0abe83f7665168f77ede5ea8a1b92f4a71dc361b 100644 --- a/crates/collab_ui/src/branch_list.rs +++ b/crates/collab_ui/src/branch_list.rs @@ -215,8 +215,16 @@ impl PickerDelegate for BranchListDelegate { let style = theme.picker.header.clone(); if self.last_query.is_empty() { Some( - Flex::row() - .with_child(Label::new("Recent branches", style)) + Stack::new() + .with_child( + Flex::row() + .with_child(Label::new("Recent branches", style.label.clone())) + .contained() + .with_style(style.container) + .into_any(), + ) + .contained() + .with_style(style.container) .into_any(), ) } else { @@ -224,7 +232,11 @@ impl PickerDelegate for BranchListDelegate { Stack::new() .with_child( Flex::row() - .with_child(Label::new("Branches", style.clone()).aligned().left()), + .with_child( + Label::new("Branches", style.label.clone()).aligned().left(), + ) + .contained() + .with_style(style.container), ) .with_children(self.matches.is_empty().not().then(|| { let suffix = if self.matches.len() == 1 { "" } else { "es" }; @@ -232,11 +244,14 @@ impl PickerDelegate for BranchListDelegate { .align_children_center() .with_child(Label::new( format!("{} match{}", self.matches.len(), suffix), - style, + style.label, )) .aligned() .right() })) + .contained() + .with_style(style.container) + .constrained() .into_any(), ) } diff --git a/crates/theme/src/theme.rs b/crates/theme/src/theme.rs index 687547a3066bdf8e436a42f376bfd6ddb96f127e..c224131d1e0a22e9b973dc705a176c0fba51c44b 100644 --- a/crates/theme/src/theme.rs +++ b/crates/theme/src/theme.rs @@ -585,8 +585,8 @@ pub struct Picker { pub empty_input_editor: FieldEditor, pub no_matches: ContainedLabel, pub item: Toggleable>, - pub header: LabelStyle, - pub footer: LabelStyle, + pub header: ContainedLabel, + pub footer: ContainedLabel, } #[derive(Clone, Debug, Deserialize, Default, JsonSchema)] diff --git a/styles/src/style_tree/picker.ts b/styles/src/style_tree/picker.ts index 9918d1a2d66381562fc0864d1fa1425b960ea2c2..6a7221efb0e47c65d72a33b766b34adb341953c2 100644 --- a/styles/src/style_tree/picker.ts +++ b/styles/src/style_tree/picker.ts @@ -110,30 +110,19 @@ export default function picker(theme: ColorScheme): any { }, header: { text: text(theme.lowest, "sans", "variant", { size: "xs" }), - padding: { - bottom: 4, - left: 12, - right: 12, - top: 4, - }, + margin: { top: 1, - left: 4, - right: 4, + left: 8, + right: 8, }, }, footer: { text: text(theme.lowest, "sans", "variant", { size: "xs" }), - padding: { - bottom: 4, - left: 12, - right: 12, - top: 4, - }, margin: { top: 1, - left: 4, - right: 4, + left: 8, + right: 8, }, } From 4a654f52527bb2431478a778bc5771a45c489a04 Mon Sep 17 00:00:00 2001 From: "Joseph T. Lyons" Date: Fri, 30 Jun 2023 13:27:48 -0400 Subject: [PATCH 034/104] Fix bug preventing the assist command from working in certain keymaps --- assets/keymaps/atom.json | 4 +--- assets/keymaps/sublime_text.json | 4 +--- assets/keymaps/textmate.json | 6 +++--- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/assets/keymaps/atom.json b/assets/keymaps/atom.json index 60acf5ea6f17563c4d27ea42728f45509dc582ed..af845ae4f2111c6009a6b0629777987b22f1b8e3 100644 --- a/assets/keymaps/atom.json +++ b/assets/keymaps/atom.json @@ -24,9 +24,7 @@ ], "ctrl-shift-down": "editor::AddSelectionBelow", "ctrl-shift-up": "editor::AddSelectionAbove", - "cmd-shift-backspace": "editor::DeleteToBeginningOfLine", - "cmd-shift-enter": "editor::NewlineAbove", - "cmd-enter": "editor::NewlineBelow" + "cmd-shift-backspace": "editor::DeleteToBeginningOfLine" } }, { diff --git a/assets/keymaps/sublime_text.json b/assets/keymaps/sublime_text.json index 2d32b77d58a91b0a508a8da03754ce5eada9d64b..ca20802295923ec992ceaeb6dc2f514aa6a628c9 100644 --- a/assets/keymaps/sublime_text.json +++ b/assets/keymaps/sublime_text.json @@ -24,9 +24,7 @@ "ctrl-.": "editor::GoToHunk", "ctrl-,": "editor::GoToPrevHunk", "ctrl-backspace": "editor::DeleteToPreviousWordStart", - "ctrl-delete": "editor::DeleteToNextWordEnd", - "cmd-shift-enter": "editor::NewlineAbove", - "cmd-enter": "editor::NewlineBelow" + "ctrl-delete": "editor::DeleteToNextWordEnd" } }, { diff --git a/assets/keymaps/textmate.json b/assets/keymaps/textmate.json index 06be72742950a320ae483df70c37b2db8a4bcf02..591d6e443fec6e362a48dd40a6912a64f198732a 100644 --- a/assets/keymaps/textmate.json +++ b/assets/keymaps/textmate.json @@ -12,8 +12,6 @@ "ctrl-shift-d": "editor::DuplicateLine", "cmd-b": "editor::GoToDefinition", "cmd-j": "editor::ScrollCursorCenter", - "cmd-alt-enter": "editor::NewlineAbove", - "cmd-enter": "editor::NewlineBelow", "cmd-shift-l": "editor::SelectLine", "cmd-shift-t": "outline::Toggle", "alt-backspace": "editor::DeleteToPreviousWordStart", @@ -56,7 +54,9 @@ }, { "context": "Editor && mode == full", - "bindings": {} + "bindings": { + "cmd-alt-enter": "editor::NewlineAbove" + } }, { "context": "BufferSearchBar", From a5d9a10d7bf423b44bf43064b1a2dbb57ab235ea Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Fri, 30 Jun 2023 19:48:28 +0200 Subject: [PATCH 035/104] Focus dropdowns on open --- crates/collab_ui/src/collab_titlebar_item.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index 1fdce6f186e6965b47271261dcff32e0fc48c481..b68095878dcc21c2a93da6e488c4541c1349afa7 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -440,6 +440,7 @@ impl CollabTitlebarItem { }) .detach(); self.project_popover.take(); + cx.focus(&view); self.branch_popover = Some(view); } } @@ -473,6 +474,7 @@ impl CollabTitlebarItem { cx.notify(); }) .detach(); + cx.focus(&view); this.branch_popover.take(); this.project_popover = Some(view); cx.notify(); From cec884b5a52f076029b1e7851531ebce593ae555 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Fri, 30 Jun 2023 20:07:44 +0200 Subject: [PATCH 036/104] Add styles for project name/git menu --- crates/collab_ui/src/collab_titlebar_item.rs | 67 ++++++++++---------- styles/src/style_tree/titlebar.ts | 5 +- 2 files changed, 38 insertions(+), 34 deletions(-) diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index b68095878dcc21c2a93da6e488c4541c1349afa7..0857b2b79a01478992f4383187da6201d779fdb6 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -220,29 +220,17 @@ impl CollabTitlebarItem { let branch_prepended = entry .as_ref() .and_then(RepositoryEntry::branch) - .map(|branch| { - format!( - "/{}", - util::truncate_and_trailoff(&branch, MAX_BRANCH_NAME_LENGTH) - ) - }); - let text_style = theme.titlebar.title.clone(); + .map(|branch| util::truncate_and_trailoff(&branch, MAX_BRANCH_NAME_LENGTH)); + let project_style = theme.titlebar.title.clone(); + let git_style = theme.titlebar.git_branch.clone(); + let divider_style = theme.titlebar.project_name_divider.clone(); let item_spacing = theme.titlebar.item_spacing; - let mut highlight = text_style.clone(); - highlight.color = theme.titlebar.highlight_color; - - let style = LabelStyle { - text: text_style, - highlight_text: Some(highlight), - }; - let highlights = (0..name.len()).into_iter().collect(); let mut ret = Flex::row().with_child( Stack::new() .with_child( MouseEventHandler::::new(0, cx, |_, _| { - Label::new(name, style.clone()) - .with_highlights(highlights) + Label::new(name, project_style.text.clone()) .contained() .aligned() .left() @@ -251,28 +239,43 @@ impl CollabTitlebarItem { .with_cursor_style(CursorStyle::PointingHand) .on_click(MouseButton::Left, move |_, this, cx| { this.toggle_project_menu(&Default::default(), cx) - }), + }) + .contained() + .with_style(project_style.container), ) .with_children(self.render_project_popover_host(&theme.titlebar, cx)), ); if let Some(git_branch) = branch_prepended { ret = ret.with_child( - Stack::new() + Flex::row() .with_child( - MouseEventHandler::::new(0, cx, |_, _| { - Label::new(git_branch, style) - .contained() - .with_margin_right(item_spacing) - .aligned() - .left() - .into_any_named("title-project-branch") - }) - .with_cursor_style(CursorStyle::PointingHand) - .on_click(MouseButton::Left, move |_, this, cx| { - this.toggle_vcs_menu(&Default::default(), cx) - }), + Label::new("/", divider_style.text) + .contained() + .with_style(divider_style.container) + .aligned() + .left(), ) - .with_children(self.render_branches_popover_host(&theme.titlebar, cx)), + .with_child( + Stack::new() + .with_child( + MouseEventHandler::::new(0, cx, |_, _| { + Label::new(git_branch, git_style.text) + .contained() + .with_margin_right(item_spacing) + .aligned() + .left() + .into_any_named("title-project-branch") + }) + .with_cursor_style(CursorStyle::PointingHand) + .on_click( + MouseButton::Left, + move |_, this, cx| { + this.toggle_vcs_menu(&Default::default(), cx) + }, + ), + ) + .with_children(self.render_branches_popover_host(&theme.titlebar, cx)), + ), ) } ret.into_any() diff --git a/styles/src/style_tree/titlebar.ts b/styles/src/style_tree/titlebar.ts index 067d619bb524880c1ddd9085a889cf41d3177470..686f814a5d72c3c7ee7b07e3288c6c957536bdcd 100644 --- a/styles/src/style_tree/titlebar.ts +++ b/styles/src/style_tree/titlebar.ts @@ -173,8 +173,9 @@ export function titlebar(theme: ColorScheme): any { }, // Project - title: text(theme.lowest, "sans", "variant"), - highlight_color: text(theme.lowest, "sans", "active").color, + title: text(theme.lowest, "sans", "active"), + project_name_divider: text(theme.lowest, "sans", "variant"), + git_branch: text(theme.lowest, "sans", "variant"), // Collaborators leader_avatar: { From 7c2c1a279b2b78f9703707339781cd6ecc6f0bca Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Fri, 30 Jun 2023 20:09:30 +0200 Subject: [PATCH 037/104] Add missing rust-side definitions --- crates/theme/src/theme.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/theme/src/theme.rs b/crates/theme/src/theme.rs index c224131d1e0a22e9b973dc705a176c0fba51c44b..a4fbcedd32cca1aeb73fe39e4a963591f806e72c 100644 --- a/crates/theme/src/theme.rs +++ b/crates/theme/src/theme.rs @@ -118,8 +118,9 @@ pub struct Titlebar { #[serde(flatten)] pub container: ContainerStyle, pub height: f32, - pub title: TextStyle, - pub highlight_color: Color, + pub title: ContainedText, + pub project_name_divider: ContainedText, + pub git_branch: ContainedText, pub item_spacing: f32, pub face_pile_spacing: f32, pub avatar_ribbon: AvatarRibbon, From 92df76e632f7f76a5f064043d67ed09c4bf931b5 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 30 Jun 2023 11:20:50 -0700 Subject: [PATCH 038/104] Fix accidental ignoring of git FS events --- crates/project/src/worktree.rs | 80 +++++++++++++++------------- crates/project/src/worktree_tests.rs | 50 ++++++++--------- 2 files changed, 69 insertions(+), 61 deletions(-) diff --git a/crates/project/src/worktree.rs b/crates/project/src/worktree.rs index 20e693770f45f686a880b5aebd542eb74a96202e..2f793c84c97c9cf1d51071218e7c552641db4703 100644 --- a/crates/project/src/worktree.rs +++ b/crates/project/src/worktree.rs @@ -2140,6 +2140,7 @@ impl LocalSnapshot { impl BackgroundScannerState { fn should_scan_directory(&self, entry: &Entry) -> bool { (!entry.is_external && !entry.is_ignored) + || entry.path.file_name() == Some(&*DOT_GIT) || self.scanned_dirs.contains(&entry.id) // If we've ever scanned it, keep scanning || self .paths_to_scan @@ -2319,6 +2320,7 @@ impl BackgroundScannerState { .entry_for_id(entry_id) .map(|entry| RepositoryWorkDirectory(entry.path.clone())) else { continue }; + log::info!("reload git repository {:?}", dot_git_dir); let repository = repository.repo_ptr.lock(); let branch = repository.branch_name(); repository.reload_index(); @@ -2359,6 +2361,8 @@ impl BackgroundScannerState { } fn build_repository(&mut self, dot_git_path: Arc, fs: &dyn Fs) -> Option<()> { + log::info!("build git repository {:?}", dot_git_path); + let work_dir_path: Arc = dot_git_path.parent().unwrap().into(); // Guard against repositories inside the repository metadata @@ -3138,8 +3142,6 @@ impl BackgroundScanner { } async fn process_events(&mut self, mut abs_paths: Vec) { - log::debug!("received fs events {:?}", abs_paths); - let root_path = self.state.lock().snapshot.abs_path.clone(); let root_canonical_path = match self.fs.canonicalize(&root_path).await { Ok(path) => path, @@ -3150,7 +3152,6 @@ impl BackgroundScanner { }; let mut relative_paths = Vec::with_capacity(abs_paths.len()); - let mut unloaded_relative_paths = Vec::new(); abs_paths.sort_unstable(); abs_paths.dedup_by(|a, b| a.starts_with(&b)); abs_paths.retain(|abs_path| { @@ -3173,7 +3174,6 @@ impl BackgroundScanner { }); if !parent_dir_is_loaded { log::debug!("ignoring event {relative_path:?} within unloaded directory"); - unloaded_relative_paths.push(relative_path); return false; } @@ -3182,27 +3182,30 @@ impl BackgroundScanner { } }); - if !relative_paths.is_empty() { - let (scan_job_tx, scan_job_rx) = channel::unbounded(); - self.reload_entries_for_paths( - root_path, - root_canonical_path, - &relative_paths, - abs_paths, - Some(scan_job_tx.clone()), - ) - .await; - drop(scan_job_tx); - self.scan_dirs(false, scan_job_rx).await; - - let (scan_job_tx, scan_job_rx) = channel::unbounded(); - self.update_ignore_statuses(scan_job_tx).await; - self.scan_dirs(false, scan_job_rx).await; + if relative_paths.is_empty() { + return; } + log::debug!("received fs events {:?}", relative_paths); + + let (scan_job_tx, scan_job_rx) = channel::unbounded(); + self.reload_entries_for_paths( + root_path, + root_canonical_path, + &relative_paths, + abs_paths, + Some(scan_job_tx.clone()), + ) + .await; + drop(scan_job_tx); + self.scan_dirs(false, scan_job_rx).await; + + let (scan_job_tx, scan_job_rx) = channel::unbounded(); + self.update_ignore_statuses(scan_job_tx).await; + self.scan_dirs(false, scan_job_rx).await; + { let mut state = self.state.lock(); - relative_paths.extend(unloaded_relative_paths); state.reload_repositories(&relative_paths, self.fs.as_ref()); state.snapshot.completed_scan_id = state.snapshot.scan_id; for (_, entry_id) in mem::take(&mut state.removed_entry_ids) { @@ -3610,23 +3613,28 @@ impl BackgroundScanner { } } - let fs_entry = state.insert_entry(fs_entry, self.fs.as_ref()); - - if let Some(scan_queue_tx) = &scan_queue_tx { - let mut ancestor_inodes = state.snapshot.ancestor_inodes_for_path(&path); - if metadata.is_dir && !ancestor_inodes.contains(&metadata.inode) { - ancestor_inodes.insert(metadata.inode); - smol::block_on(scan_queue_tx.send(ScanJob { - abs_path, - path: path.clone(), - ignore_stack, - ancestor_inodes, - is_external: fs_entry.is_external, - scan_queue: scan_queue_tx.clone(), - })) - .unwrap(); + if let (Some(scan_queue_tx), true) = (&scan_queue_tx, fs_entry.is_dir()) { + if state.should_scan_directory(&fs_entry) { + let mut ancestor_inodes = + state.snapshot.ancestor_inodes_for_path(&path); + if !ancestor_inodes.contains(&metadata.inode) { + ancestor_inodes.insert(metadata.inode); + smol::block_on(scan_queue_tx.send(ScanJob { + abs_path, + path: path.clone(), + ignore_stack, + ancestor_inodes, + is_external: fs_entry.is_external, + scan_queue: scan_queue_tx.clone(), + })) + .unwrap(); + } + } else { + fs_entry.kind = EntryKind::UnloadedDir; } } + + state.insert_entry(fs_entry, self.fs.as_ref()); } Ok(None) => { self.remove_repo_path(&path, &mut state.snapshot); diff --git a/crates/project/src/worktree_tests.rs b/crates/project/src/worktree_tests.rs index f908d702eb22aeb7dfb02eb4300611b7d22fbd73..c9ed06dea723a5362652b97759e338e1e815c2c9 100644 --- a/crates/project/src/worktree_tests.rs +++ b/crates/project/src/worktree_tests.rs @@ -1654,37 +1654,37 @@ async fn test_git_status(deterministic: Arc, cx: &mut TestAppCont })); - let tree = Worktree::local( - build_client(cx), - root.path(), - true, - Arc::new(RealFs), - Default::default(), - &mut cx.to_async(), - ) - .await - .unwrap(); - - cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete()) - .await; - const A_TXT: &'static str = "a.txt"; const B_TXT: &'static str = "b.txt"; const E_TXT: &'static str = "c/d/e.txt"; const F_TXT: &'static str = "f.txt"; const DOTGITIGNORE: &'static str = ".gitignore"; const BUILD_FILE: &'static str = "target/build_file"; - let project_path: &Path = &Path::new("project"); + let project_path = Path::new("project"); + // Set up git repository before creating the worktree. let work_dir = root.path().join("project"); let mut repo = git_init(work_dir.as_path()); repo.add_ignore_rule(IGNORE_RULE).unwrap(); - git_add(Path::new(A_TXT), &repo); - git_add(Path::new(E_TXT), &repo); - git_add(Path::new(DOTGITIGNORE), &repo); + git_add(A_TXT, &repo); + git_add(E_TXT, &repo); + git_add(DOTGITIGNORE, &repo); git_commit("Initial commit", &repo); + let tree = Worktree::local( + build_client(cx), + root.path(), + true, + Arc::new(RealFs), + Default::default(), + &mut cx.to_async(), + ) + .await + .unwrap(); + tree.flush_fs_events(cx).await; + cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete()) + .await; deterministic.run_until_parked(); // Check that the right git state is observed on startup @@ -1704,39 +1704,39 @@ async fn test_git_status(deterministic: Arc, cx: &mut TestAppCont ); }); + // Modify a file in the working copy. std::fs::write(work_dir.join(A_TXT), "aa").unwrap(); - tree.flush_fs_events(cx).await; deterministic.run_until_parked(); + // The worktree detects that the file's git status has changed. tree.read_with(cx, |tree, _cx| { let snapshot = tree.snapshot(); - assert_eq!( snapshot.status_for_file(project_path.join(A_TXT)), Some(GitFileStatus::Modified) ); }); - git_add(Path::new(A_TXT), &repo); - git_add(Path::new(B_TXT), &repo); + // Create a commit in the git repository. + git_add(A_TXT, &repo); + git_add(B_TXT, &repo); git_commit("Committing modified and added", &repo); tree.flush_fs_events(cx).await; deterministic.run_until_parked(); - // Check that repo only changes are tracked + // The worktree detects that the files' git status have changed. tree.read_with(cx, |tree, _cx| { let snapshot = tree.snapshot(); - assert_eq!( snapshot.status_for_file(project_path.join(F_TXT)), Some(GitFileStatus::Added) ); - assert_eq!(snapshot.status_for_file(project_path.join(B_TXT)), None); assert_eq!(snapshot.status_for_file(project_path.join(A_TXT)), None); }); + // Modify files in the working copy and perform git operations on other files. git_reset(0, &repo); git_remove_index(Path::new(B_TXT), &repo); git_stash(&mut repo); From ae54e1d224e747ca9a997530184913adb3fe2b79 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Fri, 30 Jun 2023 08:19:57 +0300 Subject: [PATCH 039/104] Remove excessive hint update queries * Filter out queries for outdated buffers just before hint tasks spawn: multicared edits might empit standalone events simultaneously * Only spawn inlay update tasks for visible buffers with corresponding language * Do not spawn tasks for local projects' buffers without LSP servers --- crates/editor/src/editor.rs | 71 ++++- crates/editor/src/inlay_hint_cache.rs | 432 ++++++++++++++++++++------ crates/text/src/text.rs | 7 +- 3 files changed, 404 insertions(+), 106 deletions(-) diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 64332c102aa8a802bb6e428250b820597060590c..81f073ed62b548475a1ab5d61f755031b515a9b2 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -26,7 +26,7 @@ use aho_corasick::AhoCorasick; use anyhow::{anyhow, Result}; use blink_manager::BlinkManager; use client::{ClickhouseEvent, TelemetrySettings}; -use clock::ReplicaId; +use clock::{Global, ReplicaId}; use collections::{BTreeMap, Bound, HashMap, HashSet, VecDeque}; use copilot::Copilot; pub use display_map::DisplayPoint; @@ -1195,11 +1195,11 @@ enum GotoDefinitionKind { Type, } -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Clone)] enum InlayRefreshReason { SettingsChange(InlayHintSettings), NewLinesShown, - ExcerptEdited, + BufferEdited(HashSet>), RefreshRequested, } @@ -2617,7 +2617,7 @@ impl Editor { return; } - let invalidate_cache = match reason { + let (invalidate_cache, required_languages) = match reason { InlayRefreshReason::SettingsChange(new_settings) => { match self.inlay_hint_cache.update_settings( &self.buffer, @@ -2633,16 +2633,18 @@ impl Editor { return; } ControlFlow::Break(None) => return, - ControlFlow::Continue(()) => InvalidationStrategy::RefreshRequested, + ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None), } } - InlayRefreshReason::NewLinesShown => InvalidationStrategy::None, - InlayRefreshReason::ExcerptEdited => InvalidationStrategy::ExcerptEdited, - InlayRefreshReason::RefreshRequested => InvalidationStrategy::RefreshRequested, + InlayRefreshReason::NewLinesShown => (InvalidationStrategy::None, None), + InlayRefreshReason::BufferEdited(buffer_languages) => { + (InvalidationStrategy::BufferEdited, Some(buffer_languages)) + } + InlayRefreshReason::RefreshRequested => (InvalidationStrategy::RefreshRequested, None), }; self.inlay_hint_cache.refresh_inlay_hints( - self.excerpt_visible_offsets(cx), + self.excerpt_visible_offsets(required_languages.as_ref(), cx), invalidate_cache, cx, ) @@ -2661,8 +2663,9 @@ impl Editor { fn excerpt_visible_offsets( &self, + restrict_to_languages: Option<&HashSet>>, cx: &mut ViewContext<'_, '_, Editor>, - ) -> HashMap, Range)> { + ) -> HashMap, Global, Range)> { let multi_buffer = self.buffer().read(cx); let multi_buffer_snapshot = multi_buffer.snapshot(cx); let multi_buffer_visible_start = self @@ -2680,8 +2683,22 @@ impl Editor { .range_to_buffer_ranges(multi_buffer_visible_range, cx) .into_iter() .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty()) - .map(|(buffer, excerpt_visible_range, excerpt_id)| { - (excerpt_id, (buffer, excerpt_visible_range)) + .filter_map(|(buffer_handle, excerpt_visible_range, excerpt_id)| { + let buffer = buffer_handle.read(cx); + let language = buffer.language()?; + if let Some(restrict_to_languages) = restrict_to_languages { + if !restrict_to_languages.contains(language) { + return None; + } + } + Some(( + excerpt_id, + ( + buffer_handle, + buffer.version().clone(), + excerpt_visible_range, + ), + )) }) .collect() } @@ -7256,7 +7273,7 @@ impl Editor { fn on_buffer_event( &mut self, - _: ModelHandle, + multibuffer: ModelHandle, event: &multi_buffer::Event, cx: &mut ViewContext, ) { @@ -7268,7 +7285,33 @@ impl Editor { self.update_visible_copilot_suggestion(cx); } cx.emit(Event::BufferEdited); - self.refresh_inlays(InlayRefreshReason::ExcerptEdited, cx); + + if let Some(project) = &self.project { + let project = project.read(cx); + let languages_affected = multibuffer + .read(cx) + .all_buffers() + .into_iter() + .filter_map(|buffer| { + let buffer = buffer.read(cx); + let language = buffer.language()?; + if project.is_local() + && project.language_servers_for_buffer(buffer, cx).count() == 0 + { + None + } else { + Some(language) + } + }) + .cloned() + .collect::>(); + if !languages_affected.is_empty() { + self.refresh_inlays( + InlayRefreshReason::BufferEdited(languages_affected), + cx, + ); + } + } } multi_buffer::Event::ExcerptsAdded { buffer, diff --git a/crates/editor/src/inlay_hint_cache.rs b/crates/editor/src/inlay_hint_cache.rs index af7bf3e4c5fffa40d2bd539b699574524df09abe..3f9f8e4288bc843552b22f87c9c516a695f243e8 100644 --- a/crates/editor/src/inlay_hint_cache.rs +++ b/crates/editor/src/inlay_hint_cache.rs @@ -38,7 +38,7 @@ pub struct CachedExcerptHints { #[derive(Debug, Clone, Copy)] pub enum InvalidationStrategy { RefreshRequested, - ExcerptEdited, + BufferEdited, None, } @@ -94,7 +94,7 @@ impl InvalidationStrategy { fn should_invalidate(&self) -> bool { matches!( self, - InvalidationStrategy::RefreshRequested | InvalidationStrategy::ExcerptEdited + InvalidationStrategy::RefreshRequested | InvalidationStrategy::BufferEdited ) } } @@ -197,7 +197,7 @@ impl InlayHintCache { pub fn refresh_inlay_hints( &mut self, - mut excerpts_to_query: HashMap, Range)>, + mut excerpts_to_query: HashMap, Global, Range)>, invalidate: InvalidationStrategy, cx: &mut ViewContext, ) { @@ -342,105 +342,114 @@ impl InlayHintCache { fn spawn_new_update_tasks( editor: &mut Editor, - excerpts_to_query: HashMap, Range)>, + excerpts_to_query: HashMap, Global, Range)>, invalidate: InvalidationStrategy, update_cache_version: usize, cx: &mut ViewContext<'_, '_, Editor>, ) { let visible_hints = Arc::new(editor.visible_inlay_hints(cx)); - for (excerpt_id, (buffer_handle, excerpt_visible_range)) in excerpts_to_query { - if !excerpt_visible_range.is_empty() { - let buffer = buffer_handle.read(cx); - let buffer_snapshot = buffer.snapshot(); - let cached_excerpt_hints = editor.inlay_hint_cache.hints.get(&excerpt_id).cloned(); - if let Some(cached_excerpt_hints) = &cached_excerpt_hints { - let new_task_buffer_version = buffer_snapshot.version(); - let cached_excerpt_hints = cached_excerpt_hints.read(); - let cached_buffer_version = &cached_excerpt_hints.buffer_version; - if cached_excerpt_hints.version > update_cache_version - || cached_buffer_version.changed_since(new_task_buffer_version) - { - return; - } - if !new_task_buffer_version.changed_since(&cached_buffer_version) - && !matches!(invalidate, InvalidationStrategy::RefreshRequested) - { - return; - } - }; + for (excerpt_id, (buffer_handle, new_task_buffer_version, excerpt_visible_range)) in + excerpts_to_query + { + if excerpt_visible_range.is_empty() { + continue; + } + let buffer = buffer_handle.read(cx); + let buffer_snapshot = buffer.snapshot(); + if buffer_snapshot + .version() + .changed_since(&new_task_buffer_version) + { + continue; + } - let buffer_id = buffer.remote_id(); - let excerpt_visible_range_start = buffer.anchor_before(excerpt_visible_range.start); - let excerpt_visible_range_end = buffer.anchor_after(excerpt_visible_range.end); - - let (multi_buffer_snapshot, full_excerpt_range) = - editor.buffer.update(cx, |multi_buffer, cx| { - let multi_buffer_snapshot = multi_buffer.snapshot(cx); - ( - multi_buffer_snapshot, - multi_buffer - .excerpts_for_buffer(&buffer_handle, cx) - .into_iter() - .find(|(id, _)| id == &excerpt_id) - .map(|(_, range)| range.context), - ) - }); + let cached_excerpt_hints = editor.inlay_hint_cache.hints.get(&excerpt_id).cloned(); + if let Some(cached_excerpt_hints) = &cached_excerpt_hints { + let cached_excerpt_hints = cached_excerpt_hints.read(); + let cached_buffer_version = &cached_excerpt_hints.buffer_version; + if cached_excerpt_hints.version > update_cache_version + || cached_buffer_version.changed_since(&new_task_buffer_version) + { + continue; + } + if !new_task_buffer_version.changed_since(&cached_buffer_version) + && !matches!(invalidate, InvalidationStrategy::RefreshRequested) + { + continue; + } + }; - if let Some(full_excerpt_range) = full_excerpt_range { - let query = ExcerptQuery { - buffer_id, - excerpt_id, - dimensions: ExcerptDimensions { - excerpt_range_start: full_excerpt_range.start, - excerpt_range_end: full_excerpt_range.end, - excerpt_visible_range_start, - excerpt_visible_range_end, - }, - cache_version: update_cache_version, - invalidate, - }; + let buffer_id = buffer.remote_id(); + let excerpt_visible_range_start = buffer.anchor_before(excerpt_visible_range.start); + let excerpt_visible_range_end = buffer.anchor_after(excerpt_visible_range.end); + + let (multi_buffer_snapshot, full_excerpt_range) = + editor.buffer.update(cx, |multi_buffer, cx| { + let multi_buffer_snapshot = multi_buffer.snapshot(cx); + ( + multi_buffer_snapshot, + multi_buffer + .excerpts_for_buffer(&buffer_handle, cx) + .into_iter() + .find(|(id, _)| id == &excerpt_id) + .map(|(_, range)| range.context), + ) + }); - let new_update_task = |is_refresh_after_regular_task| { - new_update_task( - query, - multi_buffer_snapshot, - buffer_snapshot, - Arc::clone(&visible_hints), - cached_excerpt_hints, - is_refresh_after_regular_task, - cx, - ) - }; - match editor.inlay_hint_cache.update_tasks.entry(excerpt_id) { - hash_map::Entry::Occupied(mut o) => { - let update_task = o.get_mut(); - match (update_task.invalidate, invalidate) { - (_, InvalidationStrategy::None) => {} - ( - InvalidationStrategy::ExcerptEdited, - InvalidationStrategy::RefreshRequested, - ) if !update_task.task.is_running_rx.is_closed() => { - update_task.pending_refresh = Some(query); - } - _ => { - o.insert(UpdateTask { - invalidate, - cache_version: query.cache_version, - task: new_update_task(false), - pending_refresh: None, - }); - } + if let Some(full_excerpt_range) = full_excerpt_range { + let query = ExcerptQuery { + buffer_id, + excerpt_id, + dimensions: ExcerptDimensions { + excerpt_range_start: full_excerpt_range.start, + excerpt_range_end: full_excerpt_range.end, + excerpt_visible_range_start, + excerpt_visible_range_end, + }, + cache_version: update_cache_version, + invalidate, + }; + + let new_update_task = |is_refresh_after_regular_task| { + new_update_task( + query, + multi_buffer_snapshot, + buffer_snapshot, + Arc::clone(&visible_hints), + cached_excerpt_hints, + is_refresh_after_regular_task, + cx, + ) + }; + match editor.inlay_hint_cache.update_tasks.entry(excerpt_id) { + hash_map::Entry::Occupied(mut o) => { + let update_task = o.get_mut(); + match (update_task.invalidate, invalidate) { + (_, InvalidationStrategy::None) => {} + ( + InvalidationStrategy::BufferEdited, + InvalidationStrategy::RefreshRequested, + ) if !update_task.task.is_running_rx.is_closed() => { + update_task.pending_refresh = Some(query); + } + _ => { + o.insert(UpdateTask { + invalidate, + cache_version: query.cache_version, + task: new_update_task(false), + pending_refresh: None, + }); } - } - hash_map::Entry::Vacant(v) => { - v.insert(UpdateTask { - invalidate, - cache_version: query.cache_version, - task: new_update_task(false), - pending_refresh: None, - }); } } + hash_map::Entry::Vacant(v) => { + v.insert(UpdateTask { + invalidate, + cache_version: query.cache_version, + task: new_update_task(false), + pending_refresh: None, + }); + } } } } @@ -961,6 +970,247 @@ mod tests { }); } + #[gpui::test] + async fn test_no_hint_updates_for_unrelated_language_files(cx: &mut gpui::TestAppContext) { + let allowed_hint_kinds = HashSet::from_iter([None, Some(InlayHintKind::Type)]); + init_test(cx, |settings| { + settings.defaults.inlay_hints = Some(InlayHintSettings { + enabled: true, + show_type_hints: allowed_hint_kinds.contains(&Some(InlayHintKind::Type)), + show_parameter_hints: allowed_hint_kinds.contains(&Some(InlayHintKind::Parameter)), + show_other_hints: allowed_hint_kinds.contains(&None), + }) + }); + + let fs = FakeFs::new(cx.background()); + fs.insert_tree( + "/a", + json!({ + "main.rs": "fn main() { a } // and some long comment to ensure inlays are not trimmed out", + "other.md": "Test md file with some text", + }), + ) + .await; + let project = Project::test(fs, ["/a".as_ref()], cx).await; + let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx)); + let worktree_id = workspace.update(cx, |workspace, cx| { + workspace.project().read_with(cx, |project, cx| { + project.worktrees(cx).next().unwrap().read(cx).id() + }) + }); + + let mut rs_fake_servers = None; + let mut md_fake_servers = None; + for (name, path_suffix) in [("Rust", "rs"), ("Markdown", "md")] { + let mut language = Language::new( + LanguageConfig { + name: name.into(), + path_suffixes: vec![path_suffix.to_string()], + ..Default::default() + }, + Some(tree_sitter_rust::language()), + ); + let fake_servers = language + .set_fake_lsp_adapter(Arc::new(FakeLspAdapter { + name, + capabilities: lsp::ServerCapabilities { + inlay_hint_provider: Some(lsp::OneOf::Left(true)), + ..Default::default() + }, + ..Default::default() + })) + .await; + match name { + "Rust" => rs_fake_servers = Some(fake_servers), + "Markdown" => md_fake_servers = Some(fake_servers), + _ => unreachable!(), + } + project.update(cx, |project, _| { + project.languages().add(Arc::new(language)); + }); + } + + let _rs_buffer = project + .update(cx, |project, cx| { + project.open_local_buffer("/a/main.rs", cx) + }) + .await + .unwrap(); + cx.foreground().run_until_parked(); + cx.foreground().start_waiting(); + let rs_fake_server = rs_fake_servers.unwrap().next().await.unwrap(); + let rs_editor = workspace + .update(cx, |workspace, cx| { + workspace.open_path((worktree_id, "main.rs"), None, true, cx) + }) + .await + .unwrap() + .downcast::() + .unwrap(); + let rs_lsp_request_count = Arc::new(AtomicU32::new(0)); + rs_fake_server + .handle_request::(move |params, _| { + let task_lsp_request_count = Arc::clone(&rs_lsp_request_count); + async move { + assert_eq!( + params.text_document.uri, + lsp::Url::from_file_path("/a/main.rs").unwrap(), + ); + let i = Arc::clone(&task_lsp_request_count).fetch_add(1, Ordering::SeqCst); + Ok(Some(vec![lsp::InlayHint { + position: lsp::Position::new(0, i), + label: lsp::InlayHintLabel::String(i.to_string()), + kind: None, + text_edits: None, + tooltip: None, + padding_left: None, + padding_right: None, + data: None, + }])) + } + }) + .next() + .await; + cx.foreground().run_until_parked(); + rs_editor.update(cx, |editor, cx| { + let expected_layers = vec!["0".to_string()]; + assert_eq!( + expected_layers, + cached_hint_labels(editor), + "Should get its first hints when opening the editor" + ); + assert_eq!(expected_layers, visible_hint_labels(editor, cx)); + let inlay_cache = editor.inlay_hint_cache(); + assert_eq!( + inlay_cache.allowed_hint_kinds, allowed_hint_kinds, + "Cache should use editor settings to get the allowed hint kinds" + ); + assert_eq!( + inlay_cache.version, 1, + "Rust editor update the cache version after every cache/view change" + ); + }); + + cx.foreground().run_until_parked(); + let _md_buffer = project + .update(cx, |project, cx| { + project.open_local_buffer("/a/other.md", cx) + }) + .await + .unwrap(); + cx.foreground().run_until_parked(); + cx.foreground().start_waiting(); + let md_fake_server = md_fake_servers.unwrap().next().await.unwrap(); + let md_editor = workspace + .update(cx, |workspace, cx| { + workspace.open_path((worktree_id, "other.md"), None, true, cx) + }) + .await + .unwrap() + .downcast::() + .unwrap(); + let md_lsp_request_count = Arc::new(AtomicU32::new(0)); + md_fake_server + .handle_request::(move |params, _| { + let task_lsp_request_count = Arc::clone(&md_lsp_request_count); + async move { + assert_eq!( + params.text_document.uri, + lsp::Url::from_file_path("/a/other.md").unwrap(), + ); + let i = Arc::clone(&task_lsp_request_count).fetch_add(1, Ordering::SeqCst); + Ok(Some(vec![lsp::InlayHint { + position: lsp::Position::new(0, i), + label: lsp::InlayHintLabel::String(i.to_string()), + kind: None, + text_edits: None, + tooltip: None, + padding_left: None, + padding_right: None, + data: None, + }])) + } + }) + .next() + .await; + cx.foreground().run_until_parked(); + md_editor.update(cx, |editor, cx| { + let expected_layers = vec!["0".to_string()]; + assert_eq!( + expected_layers, + cached_hint_labels(editor), + "Markdown editor should have a separate verison, repeating Rust editor rules" + ); + assert_eq!(expected_layers, visible_hint_labels(editor, cx)); + let inlay_cache = editor.inlay_hint_cache(); + assert_eq!(inlay_cache.allowed_hint_kinds, allowed_hint_kinds); + assert_eq!(inlay_cache.version, 1); + }); + + rs_editor.update(cx, |editor, cx| { + editor.change_selections(None, cx, |s| s.select_ranges([13..13])); + editor.handle_input("some rs change", cx); + }); + cx.foreground().run_until_parked(); + rs_editor.update(cx, |editor, cx| { + let expected_layers = vec!["1".to_string()]; + assert_eq!( + expected_layers, + cached_hint_labels(editor), + "Rust inlay cache should change after the edit" + ); + assert_eq!(expected_layers, visible_hint_labels(editor, cx)); + let inlay_cache = editor.inlay_hint_cache(); + assert_eq!(inlay_cache.allowed_hint_kinds, allowed_hint_kinds); + assert_eq!( + inlay_cache.version, 2, + "Every time hint cache changes, cache version should be incremented" + ); + }); + md_editor.update(cx, |editor, cx| { + let expected_layers = vec!["0".to_string()]; + assert_eq!( + expected_layers, + cached_hint_labels(editor), + "Markdown editor should not be affected by Rust editor changes" + ); + assert_eq!(expected_layers, visible_hint_labels(editor, cx)); + let inlay_cache = editor.inlay_hint_cache(); + assert_eq!(inlay_cache.allowed_hint_kinds, allowed_hint_kinds); + assert_eq!(inlay_cache.version, 1); + }); + + md_editor.update(cx, |editor, cx| { + editor.change_selections(None, cx, |s| s.select_ranges([13..13])); + editor.handle_input("some md change", cx); + }); + cx.foreground().run_until_parked(); + md_editor.update(cx, |editor, cx| { + let expected_layers = vec!["1".to_string()]; + assert_eq!( + expected_layers, + cached_hint_labels(editor), + "Rust editor should not be affected by Markdown editor changes" + ); + assert_eq!(expected_layers, visible_hint_labels(editor, cx)); + let inlay_cache = editor.inlay_hint_cache(); + assert_eq!(inlay_cache.allowed_hint_kinds, allowed_hint_kinds); + assert_eq!(inlay_cache.version, 2); + }); + rs_editor.update(cx, |editor, cx| { + let expected_layers = vec!["1".to_string()]; + assert_eq!( + expected_layers, + cached_hint_labels(editor), + "Markdown editor should also change independently" + ); + assert_eq!(expected_layers, visible_hint_labels(editor, cx)); + let inlay_cache = editor.inlay_hint_cache(); + assert_eq!(inlay_cache.allowed_hint_kinds, allowed_hint_kinds); + assert_eq!(inlay_cache.version, 2); + }); + } + #[gpui::test] async fn test_hint_setting_changes(cx: &mut gpui::TestAppContext) { let allowed_hint_kinds = HashSet::from_iter([None, Some(InlayHintKind::Type)]); diff --git a/crates/text/src/text.rs b/crates/text/src/text.rs index 28c5125de246e15ea0a75cfe47fdb13a3a0db5f0..7c94f25e1eb73c125e61effef56565cb9597bd85 100644 --- a/crates/text/src/text.rs +++ b/crates/text/src/text.rs @@ -2489,7 +2489,12 @@ impl ToOffset for Point { impl ToOffset for usize { fn to_offset(&self, snapshot: &BufferSnapshot) -> usize { - assert!(*self <= snapshot.len(), "offset {self} is out of range"); + assert!( + *self <= snapshot.len(), + "offset {} is out of range, max allowed is {}", + self, + snapshot.len() + ); *self } } From 138de37cbffef208c2e0f9f171796afd73d91e4f Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Fri, 30 Jun 2023 16:10:49 -0700 Subject: [PATCH 040/104] Add basic sound handling infrastructure --- Cargo.lock | 463 ++++++++++++++++++++++++++++++++++--- crates/call/Cargo.toml | 1 + crates/call/src/call.rs | 14 +- crates/call/src/room.rs | 42 ++++ crates/collab/src/tests.rs | 2 +- crates/zed/src/assets.rs | 1 + crates/zed/src/main.rs | 2 +- crates/zed/src/zed.rs | 2 +- 8 files changed, 495 insertions(+), 32 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3748f24933cc08a2ae0a0e951f515f1450066a23..6dcf614e08a5e30cc5241ee8b77c3da66f19270c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -177,6 +177,28 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" +[[package]] +name = "alsa" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8512c9117059663fb5606788fbca3619e2a91dac0e3fe516242eab1fa6be5e44" +dependencies = [ + "alsa-sys", + "bitflags", + "libc", + "nix", +] + +[[package]] +name = "alsa-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db8fee663d06c4e303404ef5f40488a53e062f89ba8bfed81f42325aafad1527" +dependencies = [ + "libc", + "pkg-config", +] + [[package]] name = "ambient-authority" version = "0.0.1" @@ -756,6 +778,26 @@ dependencies = [ "serde", ] +[[package]] +name = "bindgen" +version = "0.64.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4243e6031260db77ede97ad86c27e501d646a27ab57b59a574f725d98ab1fb4" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "peeking_take_while", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 1.0.109", +] + [[package]] name = "bindgen" version = "0.65.1" @@ -857,7 +899,7 @@ checksum = "0754613691538d51f329cce9af41d7b7ca150bc973056f1156611489475f54f7" dependencies = [ "borsh-derive-internal", "borsh-schema-derive-internal", - "proc-macro-crate", + "proc-macro-crate 0.1.5", "proc-macro2", "syn 1.0.109", ] @@ -997,6 +1039,7 @@ dependencies = [ "media", "postage", "project", + "rodio", "settings", "util", ] @@ -1082,6 +1125,12 @@ dependencies = [ "jobserver", ] +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + [[package]] name = "cexpr" version = "0.6.0" @@ -1155,7 +1204,7 @@ dependencies = [ "bitflags", "clap_derive 3.2.25", "clap_lex 0.2.4", - "indexmap", + "indexmap 1.9.3", "once_cell", "strsim", "termcolor", @@ -1226,6 +1275,12 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" +[[package]] +name = "claxon" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bfbf56724aa9eca8afa4fcfadeb479e722935bb2a0900c2d37e0cc477af0688" + [[package]] name = "cli" version = "0.1.0" @@ -1444,6 +1499,16 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +[[package]] +name = "combine" +version = "4.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" +dependencies = [ + "bytes 1.4.0", + "memchr", +] + [[package]] name = "command_palette" version = "0.1.0" @@ -1540,11 +1605,17 @@ name = "core-foundation" version = "0.9.3" source = "git+https://github.com/servo/core-foundation-rs?rev=079665882507dd5e2ff77db3de5070c1f6c0fb85#079665882507dd5e2ff77db3de5070c1f6c0fb85" dependencies = [ - "core-foundation-sys", + "core-foundation-sys 0.8.3", "libc", "uuid 0.5.1", ] +[[package]] +name = "core-foundation-sys" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b" + [[package]] name = "core-foundation-sys" version = "0.8.3" @@ -1594,6 +1665,51 @@ dependencies = [ "libc", ] +[[package]] +name = "coreaudio-rs" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb17e2d1795b1996419648915df94bc7103c28f7b48062d7acf4652fc371b2ff" +dependencies = [ + "bitflags", + "core-foundation-sys 0.6.2", + "coreaudio-sys", +] + +[[package]] +name = "coreaudio-sys" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f034b2258e6c4ade2f73bf87b21047567fb913ee9550837c2316d139b0262b24" +dependencies = [ + "bindgen 0.64.0", +] + +[[package]] +name = "cpal" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d959d90e938c5493000514b446987c07aed46c668faaa7d34d6c7a67b1a578c" +dependencies = [ + "alsa", + "core-foundation-sys 0.8.3", + "coreaudio-rs", + "dasp_sample", + "jni 0.19.0", + "js-sys", + "libc", + "mach2", + "ndk", + "ndk-context", + "oboe", + "once_cell", + "parking_lot 0.12.1", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows 0.46.0", +] + [[package]] name = "cpp_demangle" version = "0.3.5" @@ -1924,6 +2040,12 @@ dependencies = [ "parking_lot_core 0.9.7", ] +[[package]] +name = "dasp_sample" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c87e182de0887fd5361989c677c4e8f5000cd9491d6d563161a8f3a5519fc7f" + [[package]] name = "data-url" version = "0.1.1" @@ -2233,6 +2355,12 @@ dependencies = [ "serde", ] +[[package]] +name = "equivalent" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88bffebc5d80432c9b140ee17875ff173a8ab62faad5b257da912bd2f6c1c0a1" + [[package]] name = "erased-serde" version = "0.3.25" @@ -2793,7 +2921,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d" dependencies = [ "fallible-iterator", - "indexmap", + "indexmap 1.9.3", "stable_deref_trait", ] @@ -2889,7 +3017,7 @@ dependencies = [ "anyhow", "async-task", "backtrace", - "bindgen", + "bindgen 0.65.1", "block", "cc", "cocoa", @@ -2961,7 +3089,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap", + "indexmap 1.9.3", "slab", "tokio", "tokio-util 0.7.8", @@ -2995,6 +3123,12 @@ dependencies = [ "ahash 0.8.3", ] +[[package]] +name = "hashbrown" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" + [[package]] name = "hashlink" version = "0.8.1" @@ -3105,6 +3239,12 @@ dependencies = [ "digest 0.10.6", ] +[[package]] +name = "hound" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d13cdbd5dbb29f9c88095bbdc2590c9cba0d0a1269b983fef6b2cdd7e9f4db1" + [[package]] name = "http" version = "0.2.9" @@ -3213,11 +3353,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0722cd7114b7de04316e7ea5456a0bbb20e4adb46fd27a3697adb812cff0f37c" dependencies = [ "android_system_properties", - "core-foundation-sys", + "core-foundation-sys 0.8.3", "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "windows", + "windows 0.48.0", ] [[package]] @@ -3287,6 +3427,16 @@ dependencies = [ "serde", ] +[[package]] +name = "indexmap" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +dependencies = [ + "equivalent", + "hashbrown 0.14.0", +] + [[package]] name = "indoc" version = "1.0.9" @@ -3459,6 +3609,40 @@ dependencies = [ "cc", ] +[[package]] +name = "jni" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" +dependencies = [ + "cesu8", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", +] + +[[package]] +name = "jni" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "039022cdf4d7b1cf548d31f60ae783138e5fd42013f6271049d7df7afadef96c" +dependencies = [ + "cesu8", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + [[package]] name = "jobserver" version = "0.1.26" @@ -3661,6 +3845,17 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" +[[package]] +name = "lewton" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "777b48df9aaab155475a83a7df3070395ea1ac6902f5cd062b8f2b028075c030" +dependencies = [ + "byteorder", + "ogg", + "tinyvec", +] + [[package]] name = "libc" version = "0.2.144" @@ -3893,6 +4088,15 @@ dependencies = [ "libc", ] +[[package]] +name = "mach2" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d0d1830bcd151a6fc4aea1369af235b36c1528fe976b8ff678683c9995eade8" +dependencies = [ + "libc", +] + [[package]] name = "malloc_buf" version = "0.0.6" @@ -3949,7 +4153,7 @@ name = "media" version = "0.1.0" dependencies = [ "anyhow", - "bindgen", + "bindgen 0.65.1", "block", "bytes 1.4.0", "core-foundation", @@ -4207,6 +4411,35 @@ dependencies = [ "tempfile", ] +[[package]] +name = "ndk" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "451422b7e4718271c8b5b3aadf5adedba43dc76312454b387e98fae0fc951aa0" +dependencies = [ + "bitflags", + "jni-sys", + "ndk-sys", + "num_enum", + "raw-window-handle", + "thiserror", +] + +[[package]] +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + +[[package]] +name = "ndk-sys" +version = "0.4.1+23.1.7779620" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cf2aae958bd232cac5069850591667ad422d263686d75b52a065f9badeee5a3" +dependencies = [ + "jni-sys", +] + [[package]] name = "net2" version = "0.2.38" @@ -4315,6 +4548,17 @@ dependencies = [ "zeroize", ] +[[package]] +name = "num-derive" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "num-integer" version = "0.1.45" @@ -4367,6 +4611,27 @@ dependencies = [ "libc", ] +[[package]] +name = "num_enum" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "nvim-rs" version = "0.5.0" @@ -4409,7 +4674,7 @@ checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424" dependencies = [ "crc32fast", "hashbrown 0.11.2", - "indexmap", + "indexmap 1.9.3", "memchr", ] @@ -4422,6 +4687,38 @@ dependencies = [ "memchr", ] +[[package]] +name = "oboe" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8868cc237ee02e2d9618539a23a8d228b9bb3fc2e7a5b11eed3831de77c395d0" +dependencies = [ + "jni 0.20.0", + "ndk", + "ndk-context", + "num-derive", + "num-traits", + "oboe-sys", +] + +[[package]] +name = "oboe-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f44155e7fb718d3cfddcf70690b2b51ac4412f347cd9e4fbe511abe9cd7b5f2" +dependencies = [ + "cc", +] + +[[package]] +name = "ogg" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6951b4e8bf21c8193da321bcce9c9dd2e13c858fe078bf9054a288b419ae5d6e" +dependencies = [ + "byteorder", +] + [[package]] name = "once_cell" version = "1.17.1" @@ -4711,7 +5008,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4" dependencies = [ "fixedbitset", - "indexmap", + "indexmap 1.9.3", ] [[package]] @@ -4788,7 +5085,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9bd9647b268a3d3e14ff09c23201133a62589c658db02bb7388c7246aafe0590" dependencies = [ "base64 0.21.0", - "indexmap", + "indexmap 1.9.3", "line-wrap", "quick-xml", "serde", @@ -4921,6 +5218,16 @@ dependencies = [ "toml", ] +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -5333,6 +5640,12 @@ dependencies = [ "rand_core 0.5.1", ] +[[package]] +name = "raw-window-handle" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" + [[package]] name = "rayon" version = "1.7.0" @@ -5616,6 +5929,19 @@ dependencies = [ "rmp", ] +[[package]] +name = "rodio" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdf1d4dea18dff2e9eb6dca123724f8b60ef44ad74a9ad283cdfe025df7e73fa" +dependencies = [ + "claxon", + "cpal", + "hound", + "lewton", + "symphonia", +] + [[package]] name = "rope" version = "0.1.0" @@ -6117,7 +6443,7 @@ checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254" dependencies = [ "bitflags", "core-foundation", - "core-foundation-sys", + "core-foundation-sys 0.8.3", "libc", "security-framework-sys", ] @@ -6128,7 +6454,7 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4" dependencies = [ - "core-foundation-sys", + "core-foundation-sys 0.8.3", "libc", ] @@ -6202,7 +6528,7 @@ version = "1.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" dependencies = [ - "indexmap", + "indexmap 1.9.3", "itoa 1.0.6", "ryu", "serde", @@ -6214,7 +6540,7 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d7b9ce5b0a63c6269b9623ed828b39259545a6ec0d8a35d6135ad6af6232add" dependencies = [ - "indexmap", + "indexmap 1.9.3", "itoa 0.4.8", "ryu", "serde", @@ -6249,7 +6575,7 @@ version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "578a7433b776b56a35785ed5ce9a7e777ac0598aac5a6dd1b4b18a307c7fc71b" dependencies = [ - "indexmap", + "indexmap 1.9.3", "ryu", "serde", "yaml-rust", @@ -6623,7 +6949,7 @@ dependencies = [ "hex", "hkdf", "hmac 0.12.1", - "indexmap", + "indexmap 1.9.3", "itoa 1.0.6", "libc", "libsqlite3-sys", @@ -6774,6 +7100,56 @@ dependencies = [ "siphasher", ] +[[package]] +name = "symphonia" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62e48dba70095f265fdb269b99619b95d04c89e619538138383e63310b14d941" +dependencies = [ + "lazy_static", + "symphonia-bundle-mp3", + "symphonia-core", + "symphonia-metadata", +] + +[[package]] +name = "symphonia-bundle-mp3" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f31d7fece546f1e6973011a9eceae948133bbd18fd3d52f6073b1e38ae6368a" +dependencies = [ + "bitflags", + "lazy_static", + "log", + "symphonia-core", + "symphonia-metadata", +] + +[[package]] +name = "symphonia-core" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c73eb88fee79705268cc7b742c7bc93a7b76e092ab751d0833866970754142" +dependencies = [ + "arrayvec 0.7.2", + "bitflags", + "bytemuck", + "lazy_static", + "log", +] + +[[package]] +name = "symphonia-metadata" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89c3e1937e31d0e068bbe829f66b2f2bfaa28d056365279e0ef897172c3320c0" +dependencies = [ + "encoding_rs", + "lazy_static", + "log", + "symphonia-core", +] + [[package]] name = "syn" version = "1.0.109" @@ -6819,7 +7195,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a902e9050fca0a5d6877550b769abd2bd1ce8c04634b941dbe2809735e1a1e33" dependencies = [ "cfg-if 1.0.0", - "core-foundation-sys", + "core-foundation-sys 0.8.3", "libc", "ntapi 0.4.1", "once_cell", @@ -6988,7 +7364,7 @@ dependencies = [ "anyhow", "fs", "gpui", - "indexmap", + "indexmap 1.9.3", "parking_lot 0.11.2", "schemars", "serde", @@ -7294,6 +7670,23 @@ dependencies = [ "serde", ] +[[package]] +name = "toml_datetime" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" + +[[package]] +name = "toml_edit" +version = "0.19.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "266f016b7f039eec8a1a80dfe6156b633d208b9fccca5e4db1d6775b0c4e34a7" +dependencies = [ + "indexmap 2.0.0", + "toml_datetime", + "winnow", +] + [[package]] name = "tonic" version = "0.6.2" @@ -7333,7 +7726,7 @@ checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" dependencies = [ "futures-core", "futures-util", - "indexmap", + "indexmap 1.9.3", "pin-project", "pin-project-lite 0.2.9", "rand 0.8.5", @@ -8190,7 +8583,7 @@ version = "0.85.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "570460c58b21e9150d2df0eaaedbb7816c34bcec009ae0dcc976e40ba81463e7" dependencies = [ - "indexmap", + "indexmap 1.9.3", ] [[package]] @@ -8204,7 +8597,7 @@ dependencies = [ "backtrace", "bincode", "cfg-if 1.0.0", - "indexmap", + "indexmap 1.9.3", "lazy_static", "libc", "log", @@ -8278,7 +8671,7 @@ dependencies = [ "anyhow", "cranelift-entity", "gimli 0.26.2", - "indexmap", + "indexmap 1.9.3", "log", "more-asserts", "object 0.28.4", @@ -8348,7 +8741,7 @@ dependencies = [ "backtrace", "cc", "cfg-if 1.0.0", - "indexmap", + "indexmap 1.9.3", "libc", "log", "mach", @@ -8604,6 +8997,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdacb41e6a96a052c6cb63a144f24900236121c6f63f4f8219fef5977ecb0c25" +dependencies = [ + "windows-targets 0.42.2", +] + [[package]] name = "windows" version = "0.48.0" @@ -8760,6 +9162,15 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +[[package]] +name = "winnow" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca0ace3845f0d96209f0375e6d367e3eb87eb65d27d445bdc9f1843a26f39448" +dependencies = [ + "memchr", +] + [[package]] name = "winreg" version = "0.10.1" @@ -8949,7 +9360,7 @@ dependencies = [ "gpui", "ignore", "image", - "indexmap", + "indexmap 1.9.3", "install_cli", "isahc", "journal", diff --git a/crates/call/Cargo.toml b/crates/call/Cargo.toml index 4e83b552fb64fcd2b787eb80cb5ec2cd88cbafcc..86ff1a55433f010e09feaea124ffa5d19202adf4 100644 --- a/crates/call/Cargo.toml +++ b/crates/call/Cargo.toml @@ -30,6 +30,7 @@ media = { path = "../media" } project = { path = "../project" } settings = { path = "../settings" } util = { path = "../util" } +rodio = "0.17.1" anyhow.workspace = true async-broadcast = "0.4" diff --git a/crates/call/src/call.rs b/crates/call/src/call.rs index 0a8f150194ed201401218d29d6b1602f5c1a1d82..42cb5f2f87e1e5d323421f636bace4f609acf1a9 100644 --- a/crates/call/src/call.rs +++ b/crates/call/src/call.rs @@ -1,24 +1,32 @@ +mod assets; pub mod participant; pub mod room; use std::sync::Arc; use anyhow::{anyhow, Result}; +use assets::SoundRegistry; use client::{proto, Client, TypedEnvelope, User, UserStore}; use collections::HashSet; use futures::{future::Shared, FutureExt}; use postage::watch; use gpui::{ - AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle, Subscription, Task, - WeakModelHandle, + AppContext, AssetSource, AsyncAppContext, Entity, ModelContext, ModelHandle, Subscription, + Task, WeakModelHandle, }; use project::Project; pub use participant::ParticipantLocation; pub use room::Room; -pub fn init(client: Arc, user_store: ModelHandle, cx: &mut AppContext) { +pub fn init( + client: Arc, + user_store: ModelHandle, + source: impl AssetSource, + cx: &mut AppContext, +) { + cx.set_global(SoundRegistry::new(source)); let active_call = cx.add_model(|cx| ActiveCall::new(client, user_store, cx)); cx.set_global(active_call); } diff --git a/crates/call/src/room.rs b/crates/call/src/room.rs index da298f9ca25757f91f394e217099eb236a275827..b80e994fcf9e727fa3f74802a1c59d5ae0b96462 100644 --- a/crates/call/src/room.rs +++ b/crates/call/src/room.rs @@ -1,4 +1,5 @@ use crate::{ + assets::SoundRegistry, participant::{LocalParticipant, ParticipantLocation, RemoteParticipant, RemoteVideoTrack}, IncomingCall, }; @@ -18,11 +19,30 @@ use live_kit_client::{ }; use postage::stream::Stream; use project::Project; +use rodio::{OutputStream, OutputStreamHandle, Source}; use std::{future::Future, mem, pin::Pin, sync::Arc, time::Duration}; use util::{post_inc, ResultExt, TryFutureExt}; pub const RECONNECT_TIMEOUT: Duration = Duration::from_secs(30); +enum Sound { + Joined, + Leaved, + Mute, + Unmute, +} + +impl Sound { + fn file(&self) -> &'static str { + match self { + Self::Joined => "joined", + Self::Leaved => "leave", + Self::Mute => "mute", + Self::Unmute => "unmute", + } + } +} + #[derive(Clone, Debug, PartialEq, Eq)] pub enum Event { ParticipantLocationChanged { @@ -48,6 +68,8 @@ pub enum Event { pub struct Room { id: u64, live_kit: Option, + _sound_output_stream: Option, + sound_output_handle: Option, status: RoomStatus, shared_projects: HashSet>, joined_projects: HashSet>, @@ -176,9 +198,14 @@ impl Room { let maintain_connection = cx.spawn_weak(|this, cx| Self::maintain_connection(this, client.clone(), cx).log_err()); + let (sound_output_stream, sound_output_handle) = + OutputStream::try_default().log_err().unzip(); + Self { id, live_kit: live_kit_room, + _sound_output_stream: sound_output_stream, + sound_output_handle, status: RoomStatus::Online, shared_projects: Default::default(), joined_projects: Default::default(), @@ -910,6 +937,18 @@ impl Room { }) } + fn play_sound(&self, sound: Sound, cx: &AppContext) { + let Some(output_handle) = self.sound_output_handle.as_ref() else { + return; + }; + + let Some(source) = SoundRegistry::global(cx).get(sound.file()) else { + return; + }; + + output_handle.play_raw(source.convert_samples()).log_err(); + } + pub fn join_project( &mut self, id: u64, @@ -922,6 +961,9 @@ impl Room { cx.spawn(|this, mut cx| async move { let project = Project::remote(id, client, user_store, language_registry, fs, cx.clone()).await?; + + cx.read(|cx| this.read(cx).play_sound(Sound::Joined, cx)); + this.update(&mut cx, |this, cx| { this.joined_projects.retain(|project| { if let Some(project) = project.upgrade(cx) { diff --git a/crates/collab/src/tests.rs b/crates/collab/src/tests.rs index b51c5240a833661152f4f6f9c72ae5f522e51344..5906eecee15421c391041a8de2c25a677c382af0 100644 --- a/crates/collab/src/tests.rs +++ b/crates/collab/src/tests.rs @@ -203,7 +203,7 @@ impl TestServer { language::init(cx); editor::init_settings(cx); workspace::init(app_state.clone(), cx); - call::init(client.clone(), user_store.clone(), cx); + call::init(client.clone(), user_store.clone(), (), cx); }); client diff --git a/crates/zed/src/assets.rs b/crates/zed/src/assets.rs index 6eb8a44f0fb613a637af1fb6e20d2a80a359bf9f..574016c25d00e75e6fc1bb57e4b5fbb57f92e07b 100644 --- a/crates/zed/src/assets.rs +++ b/crates/zed/src/assets.rs @@ -7,6 +7,7 @@ use rust_embed::RustEmbed; #[include = "fonts/**/*"] #[include = "icons/**/*"] #[include = "themes/**/*"] +#[include = "sounds/**/*"] #[include = "*.md"] #[exclude = "*.DS_Store"] pub struct Assets; diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index 31a00cb916ef358e4da6c009d31039e4ca6d2ba4..0fb540ece67ea9f38b1626dd5636ea5051a2bca2 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -190,7 +190,7 @@ fn main() { theme_selector::init(cx); activity_indicator::init(cx); language_tools::init(cx); - call::init(app_state.client.clone(), app_state.user_store.clone(), cx); + call::init(app_state.client.clone(), app_state.user_store.clone(), Assets, cx); collab_ui::init(&app_state, cx); feedback::init(cx); welcome::init(cx); diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index a7c6956a34d4b15f007e5de2ffcc63cc51f83855..9d75ad99521b6e8e57e79fea61ffdf92fb98668a 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -2160,7 +2160,7 @@ mod tests { state.initialize_workspace = initialize_workspace; state.build_window_options = build_window_options; theme::init((), cx); - call::init(app_state.client.clone(), app_state.user_store.clone(), cx); + call::init(app_state.client.clone(), app_state.user_store.clone(), (), cx); workspace::init(app_state.clone(), cx); Project::init_settings(cx); language::init(cx); From 525521eeb39ccb97f3f8ecba72e0d3e5aeb66f01 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Sat, 1 Jul 2023 01:38:36 +0200 Subject: [PATCH 041/104] Render match count next to branch label --- crates/collab_ui/src/branch_list.rs | 93 ++++++++++++++++------------- crates/picker/src/picker.rs | 10 +++- 2 files changed, 58 insertions(+), 45 deletions(-) diff --git a/crates/collab_ui/src/branch_list.rs b/crates/collab_ui/src/branch_list.rs index 0abe83f7665168f77ede5ea8a1b92f4a71dc361b..8c06326780e4552b14b573c299592df6f64811ce 100644 --- a/crates/collab_ui/src/branch_list.rs +++ b/crates/collab_ui/src/branch_list.rs @@ -1,6 +1,8 @@ use anyhow::{anyhow, bail}; use fuzzy::{StringMatch, StringMatchCandidate}; -use gpui::{elements::*, AppContext, MouseState, Task, ViewContext, ViewHandle}; +use gpui::{ + elements::*, platform::MouseButton, AppContext, MouseState, Task, ViewContext, ViewHandle, +}; use picker::{Picker, PickerDelegate, PickerEvent}; use std::{ops::Not, sync::Arc}; use util::ResultExt; @@ -210,50 +212,55 @@ impl PickerDelegate for BranchListDelegate { .with_height(theme.contact_finder.row_height) .into_any() } - fn render_header(&self, cx: &AppContext) -> Option>> { + fn render_header( + &self, + cx: &mut ViewContext>, + ) -> Option>> { let theme = &theme::current(cx); let style = theme.picker.header.clone(); - if self.last_query.is_empty() { - Some( - Stack::new() - .with_child( - Flex::row() - .with_child(Label::new("Recent branches", style.label.clone())) - .contained() - .with_style(style.container) - .into_any(), - ) - .contained() - .with_style(style.container) - .into_any(), - ) + let label = if self.last_query.is_empty() { + Stack::new() + .with_child( + Flex::row() + .with_child(Label::new("Recent branches", style.label.clone())) + .contained() + .with_style(style.container) + .into_any(), + ) + .contained() + .with_style(style.container) + .into_any() } else { - Some( - Stack::new() - .with_child( - Flex::row() - .with_child( - Label::new("Branches", style.label.clone()).aligned().left(), - ) - .contained() - .with_style(style.container), - ) - .with_children(self.matches.is_empty().not().then(|| { - let suffix = if self.matches.len() == 1 { "" } else { "es" }; - Flex::row() - .align_children_center() - .with_child(Label::new( - format!("{} match{}", self.matches.len(), suffix), - style.label, - )) - .aligned() - .right() - })) - .contained() - .with_style(style.container) - .constrained() - .into_any(), - ) - } + Stack::new() + .with_child( + Flex::row() + .with_child(Label::new("Branches", style.label.clone()).aligned().left()) + .contained() + .with_style(style.container), + ) + .with_children(self.matches.is_empty().not().then(|| { + let suffix = if self.matches.len() == 1 { "" } else { "es" }; + Flex::row() + .align_children_center() + .with_child(Label::new( + format!("{} match{}", self.matches.len(), suffix), + style.label, + )) + .aligned() + .right() + })) + .contained() + .with_style(style.container) + .constrained() + .into_any() + }; + Some( + MouseEventHandler::::new(0, cx, move |_, _| label) + .on_click(MouseButton::Left, move |_, _, _| {}) + .on_down_out(MouseButton::Left, move |_, _, cx| { + cx.emit(PickerEvent::Dismiss) + }) + .into_any(), + ) } } diff --git a/crates/picker/src/picker.rs b/crates/picker/src/picker.rs index 33d6e842415f9f4cba317f64ab9ff58b926608d8..978d018ccf6a9833c48e29a8fed2178c93bd18ac 100644 --- a/crates/picker/src/picker.rs +++ b/crates/picker/src/picker.rs @@ -45,10 +45,16 @@ pub trait PickerDelegate: Sized + 'static { fn center_selection_after_match_updates(&self) -> bool { false } - fn render_header(&self, _cx: &AppContext) -> Option>> { + fn render_header( + &self, + _cx: &mut ViewContext>, + ) -> Option>> { None } - fn render_footer(&self, _cx: &AppContext) -> Option>> { + fn render_footer( + &self, + _cx: &mut ViewContext>, + ) -> Option>> { None } } From 026ad191ebefce8234035295175e16ebe9263978 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Sat, 1 Jul 2023 01:49:00 +0200 Subject: [PATCH 042/104] Dismiss dropdowns on click out --- crates/collab_ui/src/collab_titlebar_item.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index 0857b2b79a01478992f4383187da6201d779fdb6..ea90a879cec13d5086c886d28a53c8bd03391d61 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -385,7 +385,11 @@ impl CollabTitlebarItem { .with_height(theme.contacts_popover.height) }) .on_click(MouseButton::Left, |_, _, _| {}) - .on_down_out(MouseButton::Left, move |_, _, cx| cx.emit(())) + .on_down_out(MouseButton::Left, move |_, this, cx| { + this.branch_popover.take(); + cx.emit(()); + cx.notify(); + }) .into_any(); Overlay::new(child) @@ -415,7 +419,11 @@ impl CollabTitlebarItem { .with_height(theme.contacts_popover.height) }) .on_click(MouseButton::Left, |_, _, _| {}) - .on_down_out(MouseButton::Left, move |_, _, cx| cx.emit(())) + .on_down_out(MouseButton::Left, move |_, this, cx| { + this.project_popover.take(); + cx.emit(()); + cx.notify(); + }) .into_any(); Overlay::new(child) From e36d5f41c8a29bbb81ae683fa262251c3f103e41 Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Fri, 30 Jun 2023 12:38:28 -0600 Subject: [PATCH 043/104] Fix % when on the last character of the line Contributes: zed-industries/community#682 --- crates/vim/src/motion.rs | 50 ++++++++++++++++++++++++- crates/vim/test_data/test_matching.json | 17 +++++++++ 2 files changed, 65 insertions(+), 2 deletions(-) create mode 100644 crates/vim/test_data/test_matching.json diff --git a/crates/vim/src/motion.rs b/crates/vim/src/motion.rs index e8084cb4be13f8ffd3214b50bba1cc071d32193b..07b095dd5e186412d566badc8cbdda5be637130b 100644 --- a/crates/vim/src/motion.rs +++ b/crates/vim/src/motion.rs @@ -525,10 +525,13 @@ fn matching(map: &DisplaySnapshot, display_point: DisplayPoint) -> DisplayPoint if line_end == point { line_end = map.max_point().to_point(map); } - line_end.column = line_end.column.saturating_sub(1); let line_range = map.prev_line_boundary(point).0..line_end; - let ranges = map.buffer_snapshot.bracket_ranges(line_range.clone()); + let visible_line_range = + line_range.start..Point::new(line_range.end.row, line_range.end.column.saturating_sub(1)); + let ranges = map + .buffer_snapshot + .bracket_ranges(visible_line_range.clone()); if let Some(ranges) = ranges { let line_range = line_range.start.to_offset(&map.buffer_snapshot) ..line_range.end.to_offset(&map.buffer_snapshot); @@ -697,4 +700,47 @@ mod test { final"}) .await } + + #[gpui::test] + async fn test_matching(cx: &mut gpui::TestAppContext) { + let mut cx = NeovimBackedTestContext::new(cx).await; + + cx.set_shared_state(indoc! {r"func ˇ(a string) { + do(something(with.and_arrays[0, 2])) + }"}) + .await; + cx.simulate_shared_keystrokes(["%"]).await; + cx.assert_shared_state(indoc! {r"func (a stringˇ) { + do(something(with.and_arrays[0, 2])) + }"}) + .await; + + // test it works on the last character of the line + cx.set_shared_state(indoc! {r"func (a string) ˇ{ + do(something(with.and_arrays[0, 2])) + }"}) + .await; + cx.simulate_shared_keystrokes(["%"]).await; + cx.assert_shared_state(indoc! {r"func (a string) { + do(something(with.and_arrays[0, 2])) + ˇ}"}) + .await; + + // test it works on immediate nesting + cx.set_shared_state("ˇ{()}").await; + cx.simulate_shared_keystrokes(["%"]).await; + cx.assert_shared_state("{()ˇ}").await; + cx.simulate_shared_keystrokes(["%"]).await; + cx.assert_shared_state("ˇ{()}").await; + + // test it works on immediate nesting inside braces + cx.set_shared_state("{\n ˇ{()}\n}").await; + cx.simulate_shared_keystrokes(["%"]).await; + cx.assert_shared_state("{\n {()ˇ}\n}").await; + + // test it jumps to the next paren on a line + cx.set_shared_state("func ˇboop() {\n}").await; + cx.simulate_shared_keystrokes(["%"]).await; + cx.assert_shared_state("func boop(ˇ) {\n}").await; + } } diff --git a/crates/vim/test_data/test_matching.json b/crates/vim/test_data/test_matching.json new file mode 100644 index 0000000000000000000000000000000000000000..5c8d7529b97e7e86b1c9fb5970aac220d2de4def --- /dev/null +++ b/crates/vim/test_data/test_matching.json @@ -0,0 +1,17 @@ +{"Put":{"state":"func ˇ(a string) {\n do(something(with.and_arrays[0, 2]))\n}"}} +{"Key":"%"} +{"Get":{"state":"func (a stringˇ) {\n do(something(with.and_arrays[0, 2]))\n}","mode":"Normal"}} +{"Put":{"state":"func (a string) ˇ{\ndo(something(with.and_arrays[0, 2]))\n}"}} +{"Key":"%"} +{"Get":{"state":"func (a string) {\ndo(something(with.and_arrays[0, 2]))\nˇ}","mode":"Normal"}} +{"Put":{"state":"ˇ{()}"}} +{"Key":"%"} +{"Get":{"state":"{()ˇ}","mode":"Normal"}} +{"Key":"%"} +{"Get":{"state":"ˇ{()}","mode":"Normal"}} +{"Put":{"state":"{\n ˇ{()}\n}"}} +{"Key":"%"} +{"Get":{"state":"{\n {()ˇ}\n}","mode":"Normal"}} +{"Put":{"state":"func ˇboop() {\n}"}} +{"Key":"%"} +{"Get":{"state":"func boop(ˇ) {\n}","mode":"Normal"}} From 43d4f043312407dd20923bc2d2cbec6771bfe217 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Mon, 3 Jul 2023 11:17:12 +0300 Subject: [PATCH 044/104] Do not add extra spaces to hints --- crates/editor/src/display_map/inlay_map.rs | 89 ++++++++++++++++++++++ crates/editor/src/editor.rs | 11 +-- 2 files changed, 90 insertions(+), 10 deletions(-) diff --git a/crates/editor/src/display_map/inlay_map.rs b/crates/editor/src/display_map/inlay_map.rs index affb75f58d25eca1827d229e2106d76eb5cbcb8f..99b22dcbb6405bae83327ab64cd4a527c086fe61 100644 --- a/crates/editor/src/display_map/inlay_map.rs +++ b/crates/editor/src/display_map/inlay_map.rs @@ -49,6 +49,19 @@ pub struct InlayProperties { pub text: T, } +impl InlayProperties { + pub fn new(position: Anchor, hint: &project::InlayHint) -> Self { + let mut text = hint.text(); + if hint.padding_right && !text.ends_with(' ') { + text.push(' '); + } + if hint.padding_left && !text.starts_with(' ') { + text.insert(0, ' '); + } + Self { position, text } + } +} + impl sum_tree::Item for Transform { type Summary = TransformSummary; @@ -1095,6 +1108,7 @@ mod tests { use super::*; use crate::{InlayId, MultiBuffer}; use gpui::AppContext; + use project::{InlayHint, InlayHintLabel}; use rand::prelude::*; use settings::SettingsStore; use std::{cmp::Reverse, env, sync::Arc}; @@ -1102,6 +1116,81 @@ mod tests { use text::Patch; use util::post_inc; + #[test] + fn test_inlay_properties_label_padding() { + assert_eq!( + InlayProperties::new( + Anchor::min(), + &InlayHint { + label: InlayHintLabel::String("a".to_string()), + buffer_id: 0, + position: text::Anchor::default(), + padding_left: false, + padding_right: false, + tooltip: None, + kind: None, + }, + ) + .text, + "a", + "Should not pad label if not requested" + ); + + assert_eq!( + InlayProperties::new( + Anchor::min(), + &InlayHint { + label: InlayHintLabel::String("a".to_string()), + buffer_id: 0, + position: text::Anchor::default(), + padding_left: true, + padding_right: true, + tooltip: None, + kind: None, + }, + ) + .text, + " a ", + "Should pad label for every side requested" + ); + + assert_eq!( + InlayProperties::new( + Anchor::min(), + &InlayHint { + label: InlayHintLabel::String(" a ".to_string()), + buffer_id: 0, + position: text::Anchor::default(), + padding_left: false, + padding_right: false, + tooltip: None, + kind: None, + }, + ) + .text, + " a ", + "Should not change already padded label" + ); + + assert_eq!( + InlayProperties::new( + Anchor::min(), + &InlayHint { + label: InlayHintLabel::String(" a ".to_string()), + buffer_id: 0, + position: text::Anchor::default(), + padding_left: true, + padding_right: true, + tooltip: None, + kind: None, + }, + ) + .text, + " a ", + "Should not change already padded label" + ); + } + #[gpui::test] fn test_basic_inlays(cx: &mut AppContext) { let buffer = MultiBuffer::build_simple("abcdefghi", cx); diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 81f073ed62b548475a1ab5d61f755031b515a9b2..016b2c7a287f531ae3e9ceceba456853b2b4f1e6 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -2712,16 +2712,7 @@ impl Editor { let buffer = self.buffer.read(cx).read(cx); let new_inlays = to_insert .into_iter() - .map(|(position, id, hint)| { - let mut text = hint.text(); - if hint.padding_right { - text.push(' '); - } - if hint.padding_left { - text.insert(0, ' '); - } - (id, InlayProperties { position, text }) - }) + .map(|(position, id, hint)| (id, InlayProperties::new(position, &hint))) .collect(); drop(buffer); self.display_map.update(cx, |display_map, cx| { From 4eedc3e6464564ab536c7cd1470a6c3262ccf4f1 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Mon, 3 Jul 2023 16:15:41 +0200 Subject: [PATCH 045/104] Remove flex from underneath the pickers --- crates/collab_ui/src/collab_titlebar_item.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index ea90a879cec13d5086c886d28a53c8bd03391d61..1a4869a5836fbfba3c17e074a3f0ea93e4c6cc2d 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -377,8 +377,8 @@ impl CollabTitlebarItem { let theme = theme::current(cx).clone(); let child = ChildView::new(child, cx); let child = MouseEventHandler::::new(0, cx, |_, _| { - Flex::column() - .with_child(child.flex(1., true)) + child + .flex(1., true) .contained() .constrained() .with_width(theme.contacts_popover.width) @@ -390,6 +390,7 @@ impl CollabTitlebarItem { cx.emit(()); cx.notify(); }) + .contained() .into_any(); Overlay::new(child) @@ -411,8 +412,8 @@ impl CollabTitlebarItem { let theme = theme::current(cx).clone(); let child = ChildView::new(child, cx); let child = MouseEventHandler::::new(0, cx, |_, _| { - Flex::column() - .with_child(child.flex(1., true)) + child + .flex(1., true) .contained() .constrained() .with_width(theme.contacts_popover.width) From 85701c9b80e2addbb7eb11e9fdafa1a9517f2c3a Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Mon, 3 Jul 2023 17:05:45 +0300 Subject: [PATCH 046/104] Do not perform OnTypeFormating after pair brace insert Co-Authored-By: Julia Risley --- crates/editor/src/editor.rs | 6 +- crates/editor/src/editor_tests.rs | 105 ++++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+), 2 deletions(-) diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 016b2c7a287f531ae3e9ceceba456853b2b4f1e6..992ecd74597ee1d006f92711ab63182a648f64fb 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -2026,6 +2026,7 @@ impl Editor { } let selections = self.selections.all_adjusted(cx); + let mut brace_inserted = false; let mut edits = Vec::new(); let mut new_selections = Vec::with_capacity(selections.len()); let mut new_autoclose_regions = Vec::new(); @@ -2084,6 +2085,7 @@ impl Editor { selection.range(), format!("{}{}", text, bracket_pair.end).into(), )); + brace_inserted = true; continue; } } @@ -2110,6 +2112,7 @@ impl Editor { selection.end..selection.end, bracket_pair.end.as_str().into(), )); + brace_inserted = true; new_selections.push(( Selection { id: selection.id, @@ -2177,8 +2180,7 @@ impl Editor { let had_active_copilot_suggestion = this.has_active_copilot_suggestion(cx); this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections)); - // When buffer contents is updated and caret is moved, try triggering on type formatting. - if settings::get::(cx).use_on_type_format { + if !brace_inserted && settings::get::(cx).use_on_type_format { if let Some(on_type_format_task) = this.trigger_on_type_formatting(text.to_string(), cx) { diff --git a/crates/editor/src/editor_tests.rs b/crates/editor/src/editor_tests.rs index 657a7a744e938c1ba10f8ee264b735b6dcd85446..9e726d6cc45437bbaf287a1e82849ad66a60b9a9 100644 --- a/crates/editor/src/editor_tests.rs +++ b/crates/editor/src/editor_tests.rs @@ -6979,6 +6979,111 @@ async fn test_copilot_disabled_globs( assert!(copilot_requests.try_next().is_ok()); } +#[gpui::test] +async fn test_on_type_formatting_not_triggered(cx: &mut gpui::TestAppContext) { + init_test(cx, |_| {}); + + let mut language = Language::new( + LanguageConfig { + name: "Rust".into(), + path_suffixes: vec!["rs".to_string()], + brackets: BracketPairConfig { + pairs: vec![BracketPair { + start: "{".to_string(), + end: "}".to_string(), + close: true, + newline: true, + }], + disabled_scopes_by_bracket_ix: Vec::new(), + }, + ..Default::default() + }, + Some(tree_sitter_rust::language()), + ); + let mut fake_servers = language + .set_fake_lsp_adapter(Arc::new(FakeLspAdapter { + capabilities: lsp::ServerCapabilities { + document_on_type_formatting_provider: Some(lsp::DocumentOnTypeFormattingOptions { + first_trigger_character: "{".to_string(), + more_trigger_character: None, + }), + ..Default::default() + }, + ..Default::default() + })) + .await; + + let fs = FakeFs::new(cx.background()); + fs.insert_tree( + "/a", + json!({ + "main.rs": "fn main() { let a = 5; }", + "other.rs": "// Test file", + }), + ) + .await; + let project = Project::test(fs, ["/a".as_ref()], cx).await; + project.update(cx, |project, _| project.languages().add(Arc::new(language))); + let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx)); + let worktree_id = workspace.update(cx, |workspace, cx| { + workspace.project().read_with(cx, |project, cx| { + project.worktrees(cx).next().unwrap().read(cx).id() + }) + }); + + let buffer = project + .update(cx, |project, cx| { + project.open_local_buffer("/a/main.rs", cx) + }) + .await + .unwrap(); + cx.foreground().run_until_parked(); + cx.foreground().start_waiting(); + let fake_server = fake_servers.next().await.unwrap(); + let editor_handle = workspace + .update(cx, |workspace, cx| { + workspace.open_path((worktree_id, "main.rs"), None, true, cx) + }) + .await + .unwrap() + .downcast::() + .unwrap(); + + fake_server.handle_request::(|params, _| async move { + assert_eq!( + params.text_document_position.text_document.uri, + lsp::Url::from_file_path("/a/main.rs").unwrap(), + ); + assert_eq!( + params.text_document_position.position, + lsp::Position::new(0, 21), + ); + + Ok(Some(vec![lsp::TextEdit { + new_text: "]".to_string(), + range: lsp::Range::new(lsp::Position::new(0, 22), lsp::Position::new(0, 22)), + }])) + }); + + editor_handle.update(cx, |editor, cx| { + cx.focus(&editor_handle); + editor.change_selections(None, cx, |s| { + s.select_ranges([Point::new(0, 21)..Point::new(0, 20)]) + }); + editor.handle_input("{", cx); + }); + + cx.foreground().run_until_parked(); + + buffer.read_with(cx, |buffer, _| { + assert_eq!( + buffer.text(), + "fn main() { let a = {5}; }", + "No extra braces from on type formatting should appear in the buffer" + ) + }); +} + fn empty_range(row: usize, column: usize) -> Range { let point = DisplayPoint::new(row as u32, column as u32); point..point From 14eab4e94fae61b860bba70c8e74ba979bbf53c4 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Mon, 3 Jul 2023 19:22:43 +0200 Subject: [PATCH 047/104] branch list: dismiss correct window on PickerEvent. Query proper window --- crates/collab_ui/src/branch_list.rs | 18 ++++++++---------- crates/collab_ui/src/collab_titlebar_item.rs | 2 +- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/crates/collab_ui/src/branch_list.rs b/crates/collab_ui/src/branch_list.rs index 8c06326780e4552b14b573c299592df6f64811ce..e0f85aa65a3fe303c9ce0a79b82c83a779ea42bf 100644 --- a/crates/collab_ui/src/branch_list.rs +++ b/crates/collab_ui/src/branch_list.rs @@ -60,24 +60,24 @@ impl PickerDelegate for BranchListDelegate { .read_with(&mut cx, |view, cx| { let delegate = view.delegate(); let project = delegate.workspace.read(cx).project().read(&cx); - let mut cwd = project + let mut cwd = + project .visible_worktrees(cx) .next() .unwrap() .read(cx) - .root_entry() - .unwrap() - .path + .abs_path() .to_path_buf(); cwd.push(".git"); let Some(repo) = project.fs().open_repo(&cwd) else {bail!("Project does not have associated git repository.")}; let mut branches = repo .lock() .branches()?; - if query.is_empty() { - const RECENT_BRANCHES_COUNT: usize = 10; + const RECENT_BRANCHES_COUNT: usize = 10; + if query.is_empty() && branches.len() > RECENT_BRANCHES_COUNT { + // Truncate list of recent branches // Do a partial sort to show recent-ish branches first. - branches.select_nth_unstable_by(RECENT_BRANCHES_COUNT, |lhs, rhs| { + branches.select_nth_unstable_by(RECENT_BRANCHES_COUNT - 1, |lhs, rhs| { rhs.unix_timestamp.cmp(&lhs.unix_timestamp) }); branches.truncate(RECENT_BRANCHES_COUNT); @@ -145,9 +145,7 @@ impl PickerDelegate for BranchListDelegate { .next() .ok_or_else(|| anyhow!("There are no visisible worktrees."))? .read(cx) - .root_entry() - .ok_or_else(|| anyhow!("Worktree has no root entry."))? - .path + .abs_path() .to_path_buf(); cwd.push(".git"); let status = project diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index 1a4869a5836fbfba3c17e074a3f0ea93e4c6cc2d..8af3acf7beeef38d7c33d588a2d4749589d9c88e 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -444,7 +444,7 @@ impl CollabTitlebarItem { cx.subscribe(&view, |this, _, event, cx| { match event { PickerEvent::Dismiss => { - this.contacts_popover = None; + this.branch_popover = None; } } From b055f594b06bd0ad56dab64b24c5af613f538ddd Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Mon, 3 Jul 2023 12:50:17 -0600 Subject: [PATCH 048/104] vim: ctrl-c to exit visual mode Fixes: zed-industries/community#1447 Contributes: zed-industries/community#1089 --- assets/keymaps/vim.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/assets/keymaps/vim.json b/assets/keymaps/vim.json index afee6fcd2e998500ba55e08230473e91e68dbb96..d0190788343619ad9efc62819437793246a3a5a7 100644 --- a/assets/keymaps/vim.json +++ b/assets/keymaps/vim.json @@ -305,6 +305,10 @@ "vim::PushOperator", "Replace" ], + "ctrl-c": [ + "vim::SwitchMode", + "Normal" + ], "> >": "editor::Indent", "< <": "editor::Outdent" } From fe57e04016c120eb83441b8722febed1f6b4984f Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Mon, 3 Jul 2023 12:55:41 -0600 Subject: [PATCH 049/104] vim: Allow ^ as a motion Fixes: zed-industries/community#856 --- assets/keymaps/vim.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/keymaps/vim.json b/assets/keymaps/vim.json index d0190788343619ad9efc62819437793246a3a5a7..86e5b51f19cc7f0ba0c72d4caff135776fb047dd 100644 --- a/assets/keymaps/vim.json +++ b/assets/keymaps/vim.json @@ -35,6 +35,7 @@ "l": "vim::Right", "right": "vim::Right", "$": "vim::EndOfLine", + "^": "vim::FirstNonWhitespace", "shift-g": "vim::EndOfDocument", "w": "vim::NextWordStart", "shift-w": [ @@ -165,7 +166,6 @@ "shift-a": "vim::InsertEndOfLine", "x": "vim::DeleteRight", "shift-x": "vim::DeleteLeft", - "^": "vim::FirstNonWhitespace", "o": "vim::InsertLineBelow", "shift-o": "vim::InsertLineAbove", "~": "vim::ChangeCase", From d2127825e3e2f16fc756344246a7c58448514c7a Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Mon, 3 Jul 2023 13:30:04 -0700 Subject: [PATCH 050/104] Add first-pass sound support to Zed --- Cargo.lock | 17 ++++- Cargo.toml | 1 + assets/sounds/joined.wav | Bin 0 -> 16142 bytes assets/sounds/leave.wav | Bin 0 -> 137188 bytes assets/sounds/mute.wav | Bin 0 -> 29314 bytes assets/sounds/unmute.wav | Bin 0 -> 133336 bytes crates/audio/Cargo.toml | 23 +++++++ crates/audio/src/assets.rs | 44 +++++++++++++ crates/audio/src/audio.rs | 59 +++++++++++++++++ crates/call/Cargo.toml | 2 +- crates/call/src/call.rs | 6 +- crates/call/src/room.rs | 128 +++++++++++++++++-------------------- crates/collab/Cargo.toml | 1 + crates/collab/src/tests.rs | 3 +- crates/zed/Cargo.toml | 1 + crates/zed/src/main.rs | 4 +- crates/zed/src/zed.rs | 3 +- 17 files changed, 213 insertions(+), 79 deletions(-) create mode 100644 assets/sounds/joined.wav create mode 100644 assets/sounds/leave.wav create mode 100644 assets/sounds/mute.wav create mode 100644 assets/sounds/unmute.wav create mode 100644 crates/audio/Cargo.toml create mode 100644 crates/audio/src/assets.rs create mode 100644 crates/audio/src/audio.rs diff --git a/Cargo.lock b/Cargo.lock index 6dcf614e08a5e30cc5241ee8b77c3da66f19270c..07db6c0e7c9f537a1bae92e3888d1420f63424f3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -612,6 +612,19 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "audio" +version = "0.1.0" +dependencies = [ + "anyhow", + "collections", + "gpui", + "log", + "parking_lot 0.11.2", + "rodio", + "util", +] + [[package]] name = "auto_update" version = "0.1.0" @@ -1028,6 +1041,7 @@ version = "0.1.0" dependencies = [ "anyhow", "async-broadcast", + "audio", "client", "collections", "fs", @@ -1039,7 +1053,6 @@ dependencies = [ "media", "postage", "project", - "rodio", "settings", "util", ] @@ -1392,6 +1405,7 @@ version = "0.15.0" dependencies = [ "anyhow", "async-tungstenite", + "audio", "axum", "axum-extra", "base64 0.13.1", @@ -9331,6 +9345,7 @@ dependencies = [ "async-recursion 0.3.2", "async-tar", "async-trait", + "audio", "auto_update", "backtrace", "breadcrumbs", diff --git a/Cargo.toml b/Cargo.toml index 26555f32cd843c8c880bf7d9d000402a490e88c0..1708ccfc0a81ec92ac626ef2a6816c55e16a44df 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,7 @@ members = [ "crates/activity_indicator", "crates/ai", + "crates/audio", "crates/auto_update", "crates/breadcrumbs", "crates/call", diff --git a/assets/sounds/joined.wav b/assets/sounds/joined.wav new file mode 100644 index 0000000000000000000000000000000000000000..70cd41d16f9b21dcb46a0f91e7f446a4157f8239 GIT binary patch literal 16142 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

-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�>;(#`b*dUN70#w)$sjs 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%0DKkn{W3HQMgB4vg~2rt8sP{I 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 Zw!dq+{npEOfBcho-u>arx85j~J_Zedc$EME literal 0 HcmV?d00001 diff --git a/assets/sounds/unmute.wav b/assets/sounds/unmute.wav new file mode 100644 index 0000000000000000000000000000000000000000..d87decead02aa91fbcccbd661631636b5ee0975b GIT binary patch literal 133336 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

*xdFeH?dx;nq&{_=fa#81(@Li;$R(vv&BJgoI&O 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 IF1cO*2aA8;;Q#;t literal 0 HcmV?d00001 diff --git a/crates/audio/Cargo.toml b/crates/audio/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..182e421eb88c96ac2792763c829d2bd02300843e --- /dev/null +++ b/crates/audio/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "audio" +version = "0.1.0" +edition = "2021" +publish = false + +[lib] +path = "src/audio.rs" +doctest = false + +[dependencies] +gpui = { path = "../gpui" } +collections = { path = "../collections" } +util = { path = "../util" } + +rodio = "0.17.1" + +log.workspace = true + +anyhow.workspace = true +parking_lot.workspace = true + +[dev-dependencies] diff --git a/crates/audio/src/assets.rs b/crates/audio/src/assets.rs new file mode 100644 index 0000000000000000000000000000000000000000..b58e1f6aee89683a4b6300e107c66db016b882cb --- /dev/null +++ b/crates/audio/src/assets.rs @@ -0,0 +1,44 @@ +use std::{io::Cursor, sync::Arc}; + +use anyhow::Result; +use collections::HashMap; +use gpui::{AppContext, AssetSource}; +use rodio::{ + source::{Buffered, SamplesConverter}, + Decoder, Source, +}; + +type Sound = Buffered>>, f32>>; + +pub struct SoundRegistry { + cache: Arc>>, + assets: Box, +} + +impl SoundRegistry { + pub fn new(source: impl AssetSource) -> Arc { + Arc::new(Self { + cache: Default::default(), + assets: Box::new(source), + }) + } + + pub fn global(cx: &AppContext) -> Arc { + cx.global::>().clone() + } + + pub fn get(&self, name: &str) -> Result> { + if let Some(wav) = self.cache.lock().get(name) { + return Ok(wav.clone()); + } + + let path = format!("sounds/{}.wav", name); + let bytes = self.assets.load(&path)?.into_owned(); + let cursor = Cursor::new(bytes); + let source = Decoder::new(cursor)?.convert_samples::().buffered(); + + self.cache.lock().insert(name.to_string(), source.clone()); + + Ok(source) + } +} diff --git a/crates/audio/src/audio.rs b/crates/audio/src/audio.rs new file mode 100644 index 0000000000000000000000000000000000000000..fd3f4e0515b586a6f336734d92dd1efe534adc7f --- /dev/null +++ b/crates/audio/src/audio.rs @@ -0,0 +1,59 @@ +use assets::SoundRegistry; +use gpui::{AppContext, AssetSource}; +use rodio::{OutputStream, OutputStreamHandle}; +use util::ResultExt; + +mod assets; + +pub fn init(source: impl AssetSource, cx: &mut AppContext) { + cx.set_global(SoundRegistry::new(source)); + cx.set_global(Audio::new()); +} + +pub enum Sound { + Joined, + Leave, + Mute, + Unmute, +} + +impl Sound { + fn file(&self) -> &'static str { + match self { + Self::Joined => "joined", + Self::Leave => "leave", + Self::Mute => "mute", + Self::Unmute => "unmute", + } + } +} + +pub struct Audio { + _output_stream: Option, + output_handle: Option, +} + +impl Audio { + pub fn new() -> Self { + let (_output_stream, output_handle) = OutputStream::try_default().log_err().unzip(); + + Self { + _output_stream, + output_handle, + } + } + + pub fn play_sound(sound: Sound, cx: &AppContext) { + let this = cx.global::(); + + let Some(output_handle) = this.output_handle.as_ref() else { + return; + }; + + let Some(source) = SoundRegistry::global(cx).get(sound.file()).log_err() else { + return; + }; + + output_handle.play_raw(source).log_err(); + } +} diff --git a/crates/call/Cargo.toml b/crates/call/Cargo.toml index 86ff1a55433f010e09feaea124ffa5d19202adf4..61f35932479311de30df72ac0cc8ee17dcabcc38 100644 --- a/crates/call/Cargo.toml +++ b/crates/call/Cargo.toml @@ -19,6 +19,7 @@ test-support = [ ] [dependencies] +audio = { path = "../audio" } client = { path = "../client" } collections = { path = "../collections" } gpui = { path = "../gpui" } @@ -30,7 +31,6 @@ media = { path = "../media" } project = { path = "../project" } settings = { path = "../settings" } util = { path = "../util" } -rodio = "0.17.1" anyhow.workspace = true async-broadcast = "0.4" diff --git a/crates/call/src/call.rs b/crates/call/src/call.rs index 42cb5f2f87e1e5d323421f636bace4f609acf1a9..74ce7c2e75d4e44982cc159963b35367332ba0fc 100644 --- a/crates/call/src/call.rs +++ b/crates/call/src/call.rs @@ -1,18 +1,16 @@ -mod assets; pub mod participant; pub mod room; use std::sync::Arc; use anyhow::{anyhow, Result}; -use assets::SoundRegistry; use client::{proto, Client, TypedEnvelope, User, UserStore}; use collections::HashSet; use futures::{future::Shared, FutureExt}; use postage::watch; use gpui::{ - AppContext, AssetSource, AsyncAppContext, Entity, ModelContext, ModelHandle, Subscription, + AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle, Subscription, Task, WeakModelHandle, }; use project::Project; @@ -23,10 +21,8 @@ pub use room::Room; pub fn init( client: Arc, user_store: ModelHandle, - source: impl AssetSource, cx: &mut AppContext, ) { - cx.set_global(SoundRegistry::new(source)); let active_call = cx.add_model(|cx| ActiveCall::new(client, user_store, cx)); cx.set_global(active_call); } diff --git a/crates/call/src/room.rs b/crates/call/src/room.rs index b80e994fcf9e727fa3f74802a1c59d5ae0b96462..10cfc862e919a9438d4a7293a4abf4bdee80a068 100644 --- a/crates/call/src/room.rs +++ b/crates/call/src/room.rs @@ -1,9 +1,9 @@ use crate::{ - assets::SoundRegistry, participant::{LocalParticipant, ParticipantLocation, RemoteParticipant, RemoteVideoTrack}, IncomingCall, }; use anyhow::{anyhow, Result}; +use audio::{Audio, Sound}; use client::{ proto::{self, PeerId}, Client, TypedEnvelope, User, UserStore, @@ -19,30 +19,11 @@ use live_kit_client::{ }; use postage::stream::Stream; use project::Project; -use rodio::{OutputStream, OutputStreamHandle, Source}; use std::{future::Future, mem, pin::Pin, sync::Arc, time::Duration}; use util::{post_inc, ResultExt, TryFutureExt}; pub const RECONNECT_TIMEOUT: Duration = Duration::from_secs(30); -enum Sound { - Joined, - Leaved, - Mute, - Unmute, -} - -impl Sound { - fn file(&self) -> &'static str { - match self { - Self::Joined => "joined", - Self::Leaved => "leave", - Self::Mute => "mute", - Self::Unmute => "unmute", - } - } -} - #[derive(Clone, Debug, PartialEq, Eq)] pub enum Event { ParticipantLocationChanged { @@ -68,8 +49,6 @@ pub enum Event { pub struct Room { id: u64, live_kit: Option, - _sound_output_stream: Option, - sound_output_handle: Option, status: RoomStatus, shared_projects: HashSet>, joined_projects: HashSet>, @@ -173,6 +152,7 @@ impl Room { let connect = room.connect(&connection_info.server_url, &connection_info.token); cx.spawn(|this, mut cx| async move { connect.await?; + this.update(&mut cx, |this, cx| this.share_microphone(cx)) .await?; @@ -198,14 +178,11 @@ impl Room { let maintain_connection = cx.spawn_weak(|this, cx| Self::maintain_connection(this, client.clone(), cx).log_err()); - let (sound_output_stream, sound_output_handle) = - OutputStream::try_default().log_err().unzip(); + Audio::play_sound(Sound::Joined, cx); Self { id, live_kit: live_kit_room, - _sound_output_stream: sound_output_stream, - sound_output_handle, status: RoomStatus::Online, shared_projects: Default::default(), joined_projects: Default::default(), @@ -292,6 +269,7 @@ impl Room { room.apply_room_update(room_proto, cx)?; anyhow::Ok(()) })?; + Ok(room) }) } @@ -333,6 +311,8 @@ impl Room { } } + Audio::play_sound(Sound::Leave, cx); + self.status = RoomStatus::Offline; self.remote_participants.clear(); self.pending_participants.clear(); @@ -937,18 +917,6 @@ impl Room { }) } - fn play_sound(&self, sound: Sound, cx: &AppContext) { - let Some(output_handle) = self.sound_output_handle.as_ref() else { - return; - }; - - let Some(source) = SoundRegistry::global(cx).get(sound.file()) else { - return; - }; - - output_handle.play_raw(source.convert_samples()).log_err(); - } - pub fn join_project( &mut self, id: u64, @@ -962,8 +930,6 @@ impl Room { let project = Project::remote(id, client, user_store, language_registry, fs, cx.clone()).await?; - cx.read(|cx| this.read(cx).play_sound(Sound::Joined, cx)); - this.update(&mut cx, |this, cx| { this.joined_projects.retain(|project| { if let Some(project) = project.upgrade(cx) { @@ -1269,38 +1235,20 @@ impl Room { }) }) } - fn set_mute( - live_kit: &mut LiveKitRoom, - should_mute: bool, - cx: &mut ModelContext, - ) -> Result>> { - if !should_mute { - // clear user muting state. - live_kit.muted_by_user = false; - } - match &mut live_kit.microphone_track { - LocalTrack::None => Err(anyhow!("microphone was not shared")), - LocalTrack::Pending { muted, .. } => { - *muted = should_mute; - cx.notify(); - Ok(Task::Ready(Some(Ok(())))) - } - LocalTrack::Published { - track_publication, - muted, - } => { - *muted = should_mute; - cx.notify(); - Ok(cx.background().spawn(track_publication.set_mute(*muted))) - } - } - } + pub fn toggle_mute(&mut self, cx: &mut ModelContext) -> Result>> { let should_mute = !self.is_muted(); if let Some(live_kit) = self.live_kit.as_mut() { - let ret = Self::set_mute(live_kit, should_mute, cx); + let (ret_task, old_muted) = live_kit.set_mute(should_mute, cx)?; live_kit.muted_by_user = should_mute; - ret + + if old_muted == true && live_kit.deafened == true { + if let Some(task) = self.toggle_deafen(cx).ok() { + task.detach(); + } + } + + Ok(ret_task) } else { Err(anyhow!("LiveKit not started")) } @@ -1316,7 +1264,7 @@ impl Room { // When deafening, mute user's mic as well. // When undeafening, unmute user's mic unless it was manually muted prior to deafening. if live_kit.deafened || !live_kit.muted_by_user { - mute_task = Some(Self::set_mute(live_kit, live_kit.deafened, cx)?); + mute_task = Some(live_kit.set_mute(live_kit.deafened, cx)?.0); }; for participant in self.remote_participants.values() { for track in live_kit @@ -1389,6 +1337,48 @@ struct LiveKitRoom { _maintain_tracks: [Task<()>; 2], } +impl LiveKitRoom { + fn set_mute( + self: &mut LiveKitRoom, + should_mute: bool, + cx: &mut ModelContext, + ) -> Result<(Task>, bool)> { + if !should_mute { + // clear user muting state. + self.muted_by_user = false; + } + + let (result, old_muted) = match &mut self.microphone_track { + LocalTrack::None => Err(anyhow!("microphone was not shared")), + LocalTrack::Pending { muted, .. } => { + let old_muted = *muted; + *muted = should_mute; + cx.notify(); + Ok((Task::Ready(Some(Ok(()))), old_muted)) + } + LocalTrack::Published { + track_publication, + muted, + } => { + let old_muted = *muted; + *muted = should_mute; + cx.notify(); + Ok((cx.background().spawn(track_publication.set_mute(*muted)), old_muted)) + } + }?; + + if old_muted != should_mute { + if should_mute { + Audio::play_sound(Sound::Mute, cx); + } else { + Audio::play_sound(Sound::Unmute, cx); + } + } + + Ok((result, old_muted)) + } +} + enum LocalTrack { None, Pending { diff --git a/crates/collab/Cargo.toml b/crates/collab/Cargo.toml index c787287a0c2ee0c40aa4049e0bb807f7841e5360..cc7263aa9725f73d892cd9dc3c0b72714b4c850d 100644 --- a/crates/collab/Cargo.toml +++ b/crates/collab/Cargo.toml @@ -14,6 +14,7 @@ name = "seed" required-features = ["seed-support"] [dependencies] +audio = { path = "../audio" } collections = { path = "../collections" } live_kit_server = { path = "../live_kit_server" } rpc = { path = "../rpc" } diff --git a/crates/collab/src/tests.rs b/crates/collab/src/tests.rs index 5906eecee15421c391041a8de2c25a677c382af0..b1d0bedb2cf23c856f320aacabb8d2fb489f2e2a 100644 --- a/crates/collab/src/tests.rs +++ b/crates/collab/src/tests.rs @@ -203,7 +203,8 @@ impl TestServer { language::init(cx); editor::init_settings(cx); workspace::init(app_state.clone(), cx); - call::init(client.clone(), user_store.clone(), (), cx); + audio::init((), cx); + call::init(client.clone(), user_store.clone(), cx); }); client diff --git a/crates/zed/Cargo.toml b/crates/zed/Cargo.toml index 6434d369510a43f70868646426cde90618ac09fe..97d7f717ce41c6281b8d34760d9c380a04016db4 100644 --- a/crates/zed/Cargo.toml +++ b/crates/zed/Cargo.toml @@ -16,6 +16,7 @@ name = "Zed" path = "src/main.rs" [dependencies] +audio = { path = "../audio" } activity_indicator = { path = "../activity_indicator" } auto_update = { path = "../auto_update" } breadcrumbs = { path = "../breadcrumbs" } diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index 0fb540ece67ea9f38b1626dd5636ea5051a2bca2..3da8c24617909abb00cd6aa19e1d6adff6cad010 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -180,6 +180,8 @@ fn main() { background_actions, }); cx.set_global(Arc::downgrade(&app_state)); + + audio::init(Assets, cx); auto_update::init(http.clone(), client::ZED_SERVER_URL.clone(), cx); workspace::init(app_state.clone(), cx); @@ -190,7 +192,7 @@ fn main() { theme_selector::init(cx); activity_indicator::init(cx); language_tools::init(cx); - call::init(app_state.client.clone(), app_state.user_store.clone(), Assets, cx); + call::init(app_state.client.clone(), app_state.user_store.clone(), cx); collab_ui::init(&app_state, cx); feedback::init(cx); welcome::init(cx); diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 9d75ad99521b6e8e57e79fea61ffdf92fb98668a..874fea6500274ee572458d424e3f6c3a0e6c016b 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -2160,7 +2160,8 @@ mod tests { state.initialize_workspace = initialize_workspace; state.build_window_options = build_window_options; theme::init((), cx); - call::init(app_state.client.clone(), app_state.user_store.clone(), (), cx); + audio::init((), cx); + call::init(app_state.client.clone(), app_state.user_store.clone(), cx); workspace::init(app_state.clone(), cx); Project::init_settings(cx); language::init(cx); From 0e4c9040914551d2c429e2bd5eedc9df4b4da2d6 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Mon, 3 Jul 2023 13:36:03 -0700 Subject: [PATCH 051/104] Add joined sound effect when new participants join the room --- crates/call/src/call.rs | 10 +++------- crates/call/src/room.rs | 7 ++++++- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/crates/call/src/call.rs b/crates/call/src/call.rs index 74ce7c2e75d4e44982cc159963b35367332ba0fc..0a8f150194ed201401218d29d6b1602f5c1a1d82 100644 --- a/crates/call/src/call.rs +++ b/crates/call/src/call.rs @@ -10,19 +10,15 @@ use futures::{future::Shared, FutureExt}; use postage::watch; use gpui::{ - AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle, Subscription, - Task, WeakModelHandle, + AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle, Subscription, Task, + WeakModelHandle, }; use project::Project; pub use participant::ParticipantLocation; pub use room::Room; -pub fn init( - client: Arc, - user_store: ModelHandle, - cx: &mut AppContext, -) { +pub fn init(client: Arc, user_store: ModelHandle, cx: &mut AppContext) { let active_call = cx.add_model(|cx| ActiveCall::new(client, user_store, cx)); cx.set_global(active_call); } diff --git a/crates/call/src/room.rs b/crates/call/src/room.rs index 10cfc862e919a9438d4a7293a4abf4bdee80a068..eed73ba1b1d5f2151a0f93ff10f3e7ac562f17c2 100644 --- a/crates/call/src/room.rs +++ b/crates/call/src/room.rs @@ -663,6 +663,8 @@ impl Room { }, ); + Audio::play_sound(Sound::Joined, cx); + if let Some(live_kit) = this.live_kit.as_ref() { let video_tracks = live_kit.room.remote_video_tracks(&user.id.to_string()); @@ -1363,7 +1365,10 @@ impl LiveKitRoom { let old_muted = *muted; *muted = should_mute; cx.notify(); - Ok((cx.background().spawn(track_publication.set_mute(*muted)), old_muted)) + Ok(( + cx.background().spawn(track_publication.set_mute(*muted)), + old_muted, + )) } }?; From c700342a1c4fdc3b11265f81b6281dc54e0e80c0 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Mon, 3 Jul 2023 13:48:17 -0700 Subject: [PATCH 052/104] Guard against uninstantiated globals in tests --- crates/audio/src/audio.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/audio/src/audio.rs b/crates/audio/src/audio.rs index fd3f4e0515b586a6f336734d92dd1efe534adc7f..0216bf47be16dd23457c732a8ab944cbd5de5d37 100644 --- a/crates/audio/src/audio.rs +++ b/crates/audio/src/audio.rs @@ -44,6 +44,10 @@ impl Audio { } pub fn play_sound(sound: Sound, cx: &AppContext) { + if !cx.has_global::() { + return; + } + let this = cx.global::(); let Some(output_handle) = this.output_handle.as_ref() else { From 0733e8d50f0ffa3339cb03c14b661ca2f4334d9f Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Mon, 3 Jul 2023 15:20:10 -0600 Subject: [PATCH 053/104] Remove editor::Cancel binding from vim When you hit in the command palette, it first editor::Cancel because the command palette is also a focused editor; this binding was catching before the `menu::Cancel` that you probably want. From looking at the uses of editor::Cancel it seems like the only way to trigger this is with in an editor. Rather than trying to hook into the existing editor cancel and add vim-specific behaviour, we'll instead take responsibility for binding directly to when necessary. Fixes: zed-industries/community#1347 --- assets/keymaps/vim.json | 10 ++++++++-- crates/vim/src/test.rs | 14 ++++++++++++++ crates/vim/src/test/vim_test_context.rs | 2 ++ crates/vim/src/vim.rs | 23 ++--------------------- 4 files changed, 26 insertions(+), 23 deletions(-) diff --git a/assets/keymaps/vim.json b/assets/keymaps/vim.json index 86e5b51f19cc7f0ba0c72d4caff135776fb047dd..e08ce47caf4b785ca79b3ae9345f49b51919c81d 100644 --- a/assets/keymaps/vim.json +++ b/assets/keymaps/vim.json @@ -93,7 +93,10 @@ ], "ctrl-o": "pane::GoBack", "ctrl-]": "editor::GoToDefinition", - "escape": "editor::Cancel", + "escape": [ + "vim::SwitchMode", + "Normal" + ], "0": "vim::StartOfLine", // When no number operator present, use start of line motion "1": [ "vim::Number", @@ -325,7 +328,10 @@ "bindings": { "tab": "vim::Tab", "enter": "vim::Enter", - "escape": "editor::Cancel" + "escape": [ + "vim::SwitchMode", + "Normal" + ] } } ] diff --git a/crates/vim/src/test.rs b/crates/vim/src/test.rs index b6c5b7ca51c928072c242ee534bc29c29833878b..a6efbd4da1de34447d7165040bd6da32a79faa9c 100644 --- a/crates/vim/src/test.rs +++ b/crates/vim/src/test.rs @@ -4,6 +4,7 @@ mod neovim_connection; mod vim_binding_test_context; mod vim_test_context; +use command_palette::CommandPalette; pub use neovim_backed_binding_test_context::*; pub use neovim_backed_test_context::*; pub use vim_binding_test_context::*; @@ -139,3 +140,16 @@ async fn test_indent_outdent(cx: &mut gpui::TestAppContext) { cx.simulate_keystrokes(["shift-v", "down", ">", ">"]); cx.assert_editor_state("aa\n b«b\n cˇ»c"); } + +#[gpui::test] +async fn test_escape_command_palette(cx: &mut gpui::TestAppContext) { + let mut cx = VimTestContext::new(cx, true).await; + + cx.set_state("aˇbc\n", Mode::Normal); + cx.simulate_keystrokes(["i", "cmd-shift-p"]); + + assert!(cx.workspace(|workspace, _| workspace.modal::().is_some())); + cx.simulate_keystroke("escape"); + assert!(!cx.workspace(|workspace, _| workspace.modal::().is_some())); + cx.assert_state("aˇbc\n", Mode::Insert); +} diff --git a/crates/vim/src/test/vim_test_context.rs b/crates/vim/src/test/vim_test_context.rs index 3e66d6bb1c0e78b581ffdb328d24d06f08814d7f..f9ba577231f5de6317f1194e14a6ad4cf139e06b 100644 --- a/crates/vim/src/test/vim_test_context.rs +++ b/crates/vim/src/test/vim_test_context.rs @@ -21,12 +21,14 @@ impl<'a> VimTestContext<'a> { cx.update(|cx| { search::init(cx); crate::init(cx); + command_palette::init(cx); }); cx.update(|cx| { cx.update_global(|store: &mut SettingsStore, cx| { store.update_user_settings::(cx, |s| *s = Some(enabled)); }); + settings::KeymapFile::load_asset("keymaps/default.json", cx).unwrap(); settings::KeymapFile::load_asset("keymaps/vim.json", cx).unwrap(); }); diff --git a/crates/vim/src/vim.rs b/crates/vim/src/vim.rs index eae8643cf36e7897a0ed995c41d0bd4177d889f8..2bcc2254eed1d75dd88ec446428c306cd1d677ba 100644 --- a/crates/vim/src/vim.rs +++ b/crates/vim/src/vim.rs @@ -12,7 +12,7 @@ mod visual; use anyhow::Result; use collections::CommandPaletteFilter; -use editor::{Bias, Cancel, Editor, EditorMode, Event}; +use editor::{Bias, Editor, EditorMode, Event}; use gpui::{ actions, impl_actions, AppContext, Subscription, ViewContext, ViewHandle, WeakViewHandle, WindowContext, @@ -64,22 +64,6 @@ pub fn init(cx: &mut AppContext) { Vim::update(cx, |vim, cx| vim.push_number(n, cx)); }); - // Editor Actions - cx.add_action(|_: &mut Editor, _: &Cancel, cx| { - // If we are in aren't in normal mode or have an active operator, swap to normal mode - // Otherwise forward cancel on to the editor - let vim = Vim::read(cx); - if vim.state.mode != Mode::Normal || vim.active_operator().is_some() { - WindowContext::defer(cx, |cx| { - Vim::update(cx, |state, cx| { - state.switch_mode(Mode::Normal, false, cx); - }); - }); - } else { - cx.propagate_action(); - } - }); - cx.add_action(|_: &mut Workspace, _: &Tab, cx| { Vim::active_editor_input_ignored(" ".into(), cx) }); @@ -109,10 +93,7 @@ pub fn observe_keystrokes(cx: &mut WindowContext) { cx.observe_keystrokes(|_keystroke, _result, handled_by, cx| { if let Some(handled_by) = handled_by { // Keystroke is handled by the vim system, so continue forward - // Also short circuit if it is the special cancel action - if handled_by.namespace() == "vim" - || (handled_by.namespace() == "editor" && handled_by.name() == "Cancel") - { + if handled_by.namespace() == "vim" { return true; } } From d5acfe8fc12e21fd01ded66cc3433795c9acf9aa Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Tue, 4 Jul 2023 00:13:04 -0400 Subject: [PATCH 054/104] Use theme store to pass `color_scheme` directly to components --- styles/package-lock.json | 64 ++++++++++++++++++- styles/package.json | 15 +++-- styles/src/build_themes.ts | 14 ++-- styles/src/component/icon_button.ts | 13 ++-- styles/src/component/text_button.ts | 17 +++-- styles/src/styleTree/editor.ts | 0 styles/src/style_tree/app.ts | 56 ++++++++-------- styles/src/style_tree/assistant.ts | 6 +- styles/src/style_tree/command_palette.ts | 6 +- styles/src/style_tree/contact_finder.ts | 8 ++- styles/src/style_tree/contact_list.ts | 6 +- styles/src/style_tree/contact_notification.ts | 6 +- styles/src/style_tree/contacts_popover.ts | 6 +- styles/src/style_tree/context_menu.ts | 6 +- styles/src/style_tree/copilot.ts | 6 +- styles/src/style_tree/editor.ts | 9 ++- styles/src/style_tree/feedback.ts | 6 +- styles/src/style_tree/hover_popover.ts | 6 +- .../style_tree/incoming_call_notification.ts | 8 +-- styles/src/style_tree/picker.ts | 6 +- styles/src/style_tree/project_diagnostics.ts | 6 +- styles/src/style_tree/project_panel.ts | 23 +++---- .../style_tree/project_shared_notification.ts | 8 +-- styles/src/style_tree/search.ts | 6 +- styles/src/style_tree/shared_screen.ts | 6 +- .../style_tree/simple_message_notification.ts | 6 +- styles/src/style_tree/status_bar.ts | 6 +- styles/src/style_tree/tab_bar.ts | 6 +- styles/src/style_tree/terminal.ts | 6 +- styles/src/style_tree/titlebar.ts | 20 ++++-- .../src/style_tree/toolbar_dropdown_menu.ts | 6 +- styles/src/style_tree/tooltip.ts | 6 +- styles/src/style_tree/update_notification.ts | 6 +- styles/src/style_tree/welcome.ts | 6 +- styles/src/style_tree/workspace.ts | 14 ++-- styles/src/theme/index.ts | 21 ++++++ 36 files changed, 280 insertions(+), 136 deletions(-) delete mode 100644 styles/src/styleTree/editor.ts diff --git a/styles/package-lock.json b/styles/package-lock.json index 3f73a0b4e533899055b2a03e60938eb384e1e583..6fc5f746e52e93f16263d37f6d1ef57cebbf822f 100644 --- a/styles/package-lock.json +++ b/styles/package-lock.json @@ -27,7 +27,8 @@ "ts-node": "^10.9.1", "typescript": "^5.1.5", "utility-types": "^3.10.0", - "vitest": "^0.32.0" + "vitest": "^0.32.0", + "zustand": "^4.3.8" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -2595,6 +2596,12 @@ "node": ">= 0.8" } }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "peer": true + }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -2706,6 +2713,18 @@ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "peer": true, + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, "node_modules/loupe": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz", @@ -3292,6 +3311,18 @@ } ] }, + "node_modules/react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", @@ -4025,6 +4056,14 @@ "punycode": "^2.1.0" } }, + "node_modules/use-sync-external-store": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/utility-types": { "version": "3.10.0", "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.10.0.tgz", @@ -4305,6 +4344,29 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zustand": { + "version": "4.3.8", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.3.8.tgz", + "integrity": "sha512-4h28KCkHg5ii/wcFFJ5Fp+k1J3gJoasaIbppdgZFO4BPJnsNxL0mQXBSFgOgAdCdBj35aDTPvdAJReTMntFPGg==", + "dependencies": { + "use-sync-external-store": "1.2.0" + }, + "engines": { + "node": ">=12.7.0" + }, + "peerDependencies": { + "immer": ">=9.0", + "react": ">=16.8" + }, + "peerDependenciesMeta": { + "immer": { + "optional": true + }, + "react": { + "optional": true + } + } } } } diff --git a/styles/package.json b/styles/package.json index d82bbb7e817675ffde132e31922691ba7a117fea..16e95d90d5bebb18e7cfffe88e8d0098b48eb00f 100644 --- a/styles/package.json +++ b/styles/package.json @@ -16,21 +16,22 @@ "@tokens-studio/types": "^0.2.3", "@types/chroma-js": "^2.4.0", "@types/node": "^18.14.1", + "@typescript-eslint/eslint-plugin": "^5.60.1", + "@typescript-eslint/parser": "^5.60.1", + "@vitest/coverage-v8": "^0.32.0", "ayu": "^8.0.1", "chroma-js": "^2.4.2", "deepmerge": "^4.3.0", + "eslint": "^8.43.0", + "eslint-import-resolver-typescript": "^3.5.5", + "eslint-plugin-import": "^2.27.5", "json-schema-to-typescript": "^13.0.2", "toml": "^3.0.0", "ts-deepmerge": "^6.0.3", "ts-node": "^10.9.1", + "typescript": "^5.1.5", "utility-types": "^3.10.0", "vitest": "^0.32.0", - "@typescript-eslint/eslint-plugin": "^5.60.1", - "@typescript-eslint/parser": "^5.60.1", - "@vitest/coverage-v8": "^0.32.0", - "eslint": "^8.43.0", - "eslint-import-resolver-typescript": "^3.5.5", - "eslint-plugin-import": "^2.27.5", - "typescript": "^5.1.5" + "zustand": "^4.3.8" } } diff --git a/styles/src/build_themes.ts b/styles/src/build_themes.ts index 5a091719df2cf1bd115e0570d58fc84b18a66fc4..a9cbad94e7fb104adc35e22c6a0b6943aa44992f 100644 --- a/styles/src/build_themes.ts +++ b/styles/src/build_themes.ts @@ -4,6 +4,7 @@ import * as path from "path" import app from "./style_tree/app" import { ColorScheme, create_color_scheme } from "./theme/color_scheme" import { themes } from "./themes" +import { useThemeStore } from "./theme" const assets_directory = `${__dirname}/../../assets` const temp_directory = fs.mkdtempSync(path.join(tmpdir(), "build-themes")) @@ -20,10 +21,17 @@ function clear_themes(theme_directory: string) { } } +const all_themes: ColorScheme[] = themes.map((theme) => + create_color_scheme(theme) +) + function write_themes(themes: ColorScheme[], output_directory: string) { clear_themes(output_directory) for (const color_scheme of themes) { - const style_tree = app(color_scheme) + const { setTheme } = useThemeStore.getState() + setTheme(color_scheme) + + const style_tree = app() const style_tree_json = JSON.stringify(style_tree, null, 2) const temp_path = path.join(temp_directory, `${color_scheme.name}.json`) const out_path = path.join( @@ -36,8 +44,4 @@ function write_themes(themes: ColorScheme[], output_directory: string) { } } -const all_themes: ColorScheme[] = themes.map((theme) => - create_color_scheme(theme) -) - write_themes(all_themes, `${assets_directory}/themes`) diff --git a/styles/src/component/icon_button.ts b/styles/src/component/icon_button.ts index 79891c2477809a1312c968241ee833b62f0922cd..18b900e83328bf4bd409e30b9579d0296c6b338b 100644 --- a/styles/src/component/icon_button.ts +++ b/styles/src/component/icon_button.ts @@ -1,6 +1,6 @@ import { interactive, toggleable } from "../element" import { background, foreground } from "../style_tree/components" -import { ColorScheme } from "../theme/color_scheme" +import { useTheme, ColorScheme } from "../theme" export type Margin = { top: number @@ -22,10 +22,9 @@ type ToggleableIconButtonOptions = IconButtonOptions & { active_color?: keyof ColorScheme["lowest"] } -export function icon_button( - theme: ColorScheme, - { color, margin, layer }: IconButtonOptions -) { +export function icon_button({ color, margin, layer }: IconButtonOptions) { + const theme = useTheme() + if (!color) color = "base" const m = { @@ -75,8 +74,8 @@ export function toggleable_icon_button( return toggleable({ state: { - inactive: icon_button(theme, { color, margin }), - active: icon_button(theme, { + inactive: icon_button({ color, margin }), + active: icon_button({ color: active_color ? active_color : color, margin, layer: theme.middle, diff --git a/styles/src/component/text_button.ts b/styles/src/component/text_button.ts index 477c2515e320d5e1d4ac2b2cdaf7f8dd587cdde8..50737f976686f4a33b1d4ab5d5a81e61ebefd108 100644 --- a/styles/src/component/text_button.ts +++ b/styles/src/component/text_button.ts @@ -5,7 +5,7 @@ import { foreground, text, } from "../style_tree/components" -import { ColorScheme } from "../theme/color_scheme" +import { useTheme, ColorScheme } from "../theme" import { Margin } from "./icon_button" interface TextButtonOptions { @@ -22,10 +22,13 @@ type ToggleableTextButtonOptions = TextButtonOptions & { active_color?: keyof ColorScheme["lowest"] } -export function text_button( - theme: ColorScheme, - { color, layer, margin, text_properties }: TextButtonOptions -) { +export function text_button({ + color, + layer, + margin, + text_properties, +}: TextButtonOptions) { + const theme = useTheme() if (!color) color = "base" const text_options: TextProperties = { @@ -79,8 +82,8 @@ export function toggleable_text_button( return toggleable({ state: { - inactive: text_button(theme, { color, margin }), - active: text_button(theme, { + inactive: text_button({ color, margin }), + active: text_button({ color: active_color ? active_color : color, margin, layer: theme.middle, diff --git a/styles/src/styleTree/editor.ts b/styles/src/styleTree/editor.ts deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/styles/src/style_tree/app.ts b/styles/src/style_tree/app.ts index 684614d073b495870b1fc06418623587cc69b768..e4bf232b624ed01f6dd1ddcd20826ab6a43aca1d 100644 --- a/styles/src/style_tree/app.ts +++ b/styles/src/style_tree/app.ts @@ -17,45 +17,47 @@ import terminal from "./terminal" import contact_list from "./contact_list" import toolbar_dropdown_menu from "./toolbar_dropdown_menu" import incoming_call_notification from "./incoming_call_notification" -import { ColorScheme } from "../theme/color_scheme" import welcome from "./welcome" import copilot from "./copilot" import assistant from "./assistant" import { titlebar } from "./titlebar" import editor from "./editor" import feedback from "./feedback" +import { useTheme } from "../common" + +export default function app(): any { + const theme = useTheme() -export default function app(theme: ColorScheme): any { return { meta: { name: theme.name, is_light: theme.is_light, }, - command_palette: command_palette(theme), - contact_notification: contact_notification(theme), - project_shared_notification: project_shared_notification(theme), - incoming_call_notification: incoming_call_notification(theme), - picker: picker(theme), - workspace: workspace(theme), - titlebar: titlebar(theme), - copilot: copilot(theme), - welcome: welcome(theme), - context_menu: context_menu(theme), - editor: editor(theme), - project_diagnostics: project_diagnostics(theme), - project_panel: project_panel(theme), - contacts_popover: contacts_popover(theme), - contact_finder: contact_finder(theme), - contact_list: contact_list(theme), - toolbar_dropdown_menu: toolbar_dropdown_menu(theme), - search: search(theme), - shared_screen: shared_screen(theme), - update_notification: update_notification(theme), - simple_message_notification: simple_message_notification(theme), - tooltip: tooltip(theme), - terminal: terminal(theme), - assistant: assistant(theme), - feedback: feedback(theme), + command_palette: command_palette(), + contact_notification: contact_notification(), + project_shared_notification: project_shared_notification(), + incoming_call_notification: incoming_call_notification(), + picker: picker(), + workspace: workspace(), + titlebar: titlebar(), + copilot: copilot(), + welcome: welcome(), + context_menu: context_menu(), + editor: editor(), + project_diagnostics: project_diagnostics(), + project_panel: project_panel(), + contacts_popover: contacts_popover(), + contact_finder: contact_finder(), + contact_list: contact_list(), + toolbar_dropdown_menu: toolbar_dropdown_menu(), + search: search(), + shared_screen: shared_screen(), + update_notification: update_notification(), + simple_message_notification: simple_message_notification(), + tooltip: tooltip(), + terminal: terminal(), + assistant: assistant(), + feedback: feedback(), color_scheme: { ...theme, players: Object.values(theme.players), diff --git a/styles/src/style_tree/assistant.ts b/styles/src/style_tree/assistant.ts index bdde221acae12f47711f46ea66c5dcc1fbb21d31..6df02a0e330bc24ebc01e7b216be1ed64e20ecd3 100644 --- a/styles/src/style_tree/assistant.ts +++ b/styles/src/style_tree/assistant.ts @@ -1,8 +1,10 @@ -import { ColorScheme } from "../theme/color_scheme" import { text, border, background, foreground } from "./components" import { interactive } from "../element" +import { useTheme } from "../theme" + +export default function assistant(): any { + const theme = useTheme() -export default function assistant(theme: ColorScheme): any { return { container: { background: background(theme.highest), diff --git a/styles/src/style_tree/command_palette.ts b/styles/src/style_tree/command_palette.ts index 289deef54b63b8b71fd24960d88508f7f7d44c98..2f7404c8d4ed2b909e29a4086c7a2339645fea7d 100644 --- a/styles/src/style_tree/command_palette.ts +++ b/styles/src/style_tree/command_palette.ts @@ -1,9 +1,11 @@ -import { ColorScheme } from "../theme/color_scheme" import { with_opacity } from "../theme/color" import { text, background } from "./components" import { toggleable } from "../element" +import { useTheme } from "../theme" + +export default function command_palette(): any { + const theme = useTheme() -export default function command_palette(theme: ColorScheme): any { const key = toggleable({ base: { text: text(theme.highest, "mono", "variant", "default", { diff --git a/styles/src/style_tree/contact_finder.ts b/styles/src/style_tree/contact_finder.ts index e61d100264bb9713f312c27c446ff36f054e77f5..2d57e16dfd5cf9f308b3f3a53d7863f99532507d 100644 --- a/styles/src/style_tree/contact_finder.ts +++ b/styles/src/style_tree/contact_finder.ts @@ -1,8 +1,10 @@ import picker from "./picker" -import { ColorScheme } from "../theme/color_scheme" import { background, border, foreground, text } from "./components" +import { useTheme } from "../theme" + +export default function contact_finder(): any { + const theme = useTheme() -export default function contact_finder(theme: ColorScheme): any { const side_margin = 6 const contact_button = { background: background(theme.middle, "variant"), @@ -12,7 +14,7 @@ export default function contact_finder(theme: ColorScheme): any { corner_radius: 8, } - const picker_style = picker(theme) + const picker_style = picker() const picker_input = { background: background(theme.middle, "on"), corner_radius: 6, diff --git a/styles/src/style_tree/contact_list.ts b/styles/src/style_tree/contact_list.ts index 93f88e2d4afe4df10a943b5d8e04b42d15160e69..1955231f59514847e59248c42f8d301895e38462 100644 --- a/styles/src/style_tree/contact_list.ts +++ b/styles/src/style_tree/contact_list.ts @@ -1,4 +1,3 @@ -import { ColorScheme } from "../theme/color_scheme" import { background, border, @@ -7,7 +6,10 @@ import { text, } from "./components" import { interactive, toggleable } from "../element" -export default function contacts_panel(theme: ColorScheme): any { +import { useTheme } from "../theme" +export default function contacts_panel(): any { + const theme = useTheme() + const name_margin = 8 const side_padding = 12 diff --git a/styles/src/style_tree/contact_notification.ts b/styles/src/style_tree/contact_notification.ts index 8de5496d91e41d054e5f2eee29f08cc7e0c31054..365e3a646ddf71c8f0ba522fe092f9e951d04cd4 100644 --- a/styles/src/style_tree/contact_notification.ts +++ b/styles/src/style_tree/contact_notification.ts @@ -1,8 +1,10 @@ -import { ColorScheme } from "../theme/color_scheme" import { background, foreground, text } from "./components" import { interactive } from "../element" +import { useTheme } from "../theme" + +export default function contact_notification(): any { + const theme = useTheme() -export default function contact_notification(theme: ColorScheme): any { const avatar_size = 12 const header_padding = 8 diff --git a/styles/src/style_tree/contacts_popover.ts b/styles/src/style_tree/contacts_popover.ts index 4e3f8899e046bc27ddcc394c42e845278b73a51d..0ce63d088a72028e6e221cc5739adfe2376d608d 100644 --- a/styles/src/style_tree/contacts_popover.ts +++ b/styles/src/style_tree/contacts_popover.ts @@ -1,7 +1,9 @@ -import { ColorScheme } from "../theme/color_scheme" +import { useTheme } from "../theme" import { background, border } from "./components" -export default function contacts_popover(theme: ColorScheme): any { +export default function contacts_popover(): any { + const theme = useTheme() + return { background: background(theme.middle), corner_radius: 6, diff --git a/styles/src/style_tree/context_menu.ts b/styles/src/style_tree/context_menu.ts index af45942d2d56d69dcb4ca799282d71c203223eec..d4266a71fe6f3974dcf8a154002f658fadf38d07 100644 --- a/styles/src/style_tree/context_menu.ts +++ b/styles/src/style_tree/context_menu.ts @@ -1,8 +1,10 @@ -import { ColorScheme } from "../theme/color_scheme" import { background, border, border_color, text } from "./components" import { interactive, toggleable } from "../element" +import { useTheme } from "../theme" + +export default function context_menu(): any { + const theme = useTheme() -export default function context_menu(theme: ColorScheme): any { return { background: background(theme.middle), corner_radius: 10, diff --git a/styles/src/style_tree/copilot.ts b/styles/src/style_tree/copilot.ts index eee6880e0cfa240ad6b9ce38bc3d7252bf1a427e..f002db5ef586a39abfe3e8698cf4e5ddafb390b3 100644 --- a/styles/src/style_tree/copilot.ts +++ b/styles/src/style_tree/copilot.ts @@ -1,7 +1,9 @@ -import { ColorScheme } from "../theme/color_scheme" import { background, border, foreground, svg, text } from "./components" import { interactive } from "../element" -export default function copilot(theme: ColorScheme): any { +import { useTheme } from "../theme" +export default function copilot(): any { + const theme = useTheme() + const content_width = 264 const cta_button = diff --git a/styles/src/style_tree/editor.ts b/styles/src/style_tree/editor.ts index af58276d162acc741a22079d8cb59b3885e2b6dc..31fa86110da30c5ad56f75291bce674b194fa2fd 100644 --- a/styles/src/style_tree/editor.ts +++ b/styles/src/style_tree/editor.ts @@ -1,5 +1,5 @@ import { with_opacity } from "../theme/color" -import { ColorScheme, Layer, StyleSets } from "../theme/color_scheme" +import { Layer, StyleSets } from "../theme/color_scheme" import { background, border, @@ -11,8 +11,11 @@ import hover_popover from "./hover_popover" import { build_syntax } from "../theme/syntax" import { interactive, toggleable } from "../element" +import { useTheme } from "../theme" + +export default function editor(): any { + const theme = useTheme() -export default function editor(theme: ColorScheme): any { const { is_light } = theme const layer = theme.highest @@ -248,7 +251,7 @@ export default function editor(theme: ColorScheme): any { invalid_hint_diagnostic: diagnostic(theme.middle, "base"), invalid_information_diagnostic: diagnostic(theme.middle, "base"), invalid_warning_diagnostic: diagnostic(theme.middle, "base"), - hover_popover: hover_popover(theme), + hover_popover: hover_popover(), link_definition: { color: syntax.link_uri.color, underline: syntax.link_uri.underline, diff --git a/styles/src/style_tree/feedback.ts b/styles/src/style_tree/feedback.ts index 9217b609299426d5444c9e2703fe843aa98e2350..2bb63e951be4764a6cdb33544abf404a84a11d7e 100644 --- a/styles/src/style_tree/feedback.ts +++ b/styles/src/style_tree/feedback.ts @@ -1,8 +1,10 @@ -import { ColorScheme } from "../theme/color_scheme" import { background, border, text } from "./components" import { interactive } from "../element" +import { useTheme } from "../theme" + +export default function feedback(): any { + const theme = useTheme() -export default function feedback(theme: ColorScheme): any { return { submit_button: interactive({ base: { diff --git a/styles/src/style_tree/hover_popover.ts b/styles/src/style_tree/hover_popover.ts index f4695057419d3adb0af4c8f46413574f6817a479..80f22503496771bf39d8a271c3cfe66988a4b96f 100644 --- a/styles/src/style_tree/hover_popover.ts +++ b/styles/src/style_tree/hover_popover.ts @@ -1,7 +1,9 @@ -import { ColorScheme } from "../theme/color_scheme" +import { useTheme } from "../theme" import { background, border, foreground, text } from "./components" -export default function hover_popover(theme: ColorScheme): any { +export default function hover_popover(): any { + const theme = useTheme() + const base_container = { background: background(theme.middle), corner_radius: 8, diff --git a/styles/src/style_tree/incoming_call_notification.ts b/styles/src/style_tree/incoming_call_notification.ts index ca46596e57fc46ca4fef1baa50d342b41f720c8a..294ec00a73152f4a79f96ba2e0866cc25baf5fa7 100644 --- a/styles/src/style_tree/incoming_call_notification.ts +++ b/styles/src/style_tree/incoming_call_notification.ts @@ -1,9 +1,9 @@ -import { ColorScheme } from "../theme/color_scheme" +import { useTheme } from "../theme" import { background, border, text } from "./components" -export default function incoming_call_notification( - theme: ColorScheme -): unknown { +export default function incoming_call_notification(): unknown { + const theme = useTheme() + const avatar_size = 48 return { window_height: 74, diff --git a/styles/src/style_tree/picker.ts b/styles/src/style_tree/picker.ts index 7ca76cd85f324d9cc640dd3845a1ca1d3e89a751..d57021efb8ca765f196518d8c79727ba4d88513d 100644 --- a/styles/src/style_tree/picker.ts +++ b/styles/src/style_tree/picker.ts @@ -1,9 +1,11 @@ -import { ColorScheme } from "../theme/color_scheme" import { with_opacity } from "../theme/color" import { background, border, text } from "./components" import { interactive, toggleable } from "../element" +import { useTheme } from "../theme" + +export default function picker(): any { + const theme = useTheme() -export default function picker(theme: ColorScheme): any { const container = { background: background(theme.lowest), border: border(theme.lowest), diff --git a/styles/src/style_tree/project_diagnostics.ts b/styles/src/style_tree/project_diagnostics.ts index 5962b98a26ce20ebe2c8c06245cb0d134c3397e9..1c13b31a4af969518d7d06f4668334480a84bdd4 100644 --- a/styles/src/style_tree/project_diagnostics.ts +++ b/styles/src/style_tree/project_diagnostics.ts @@ -1,7 +1,9 @@ -import { ColorScheme } from "../theme/color_scheme" +import { useTheme } from "../theme" import { background, text } from "./components" -export default function project_diagnostics(theme: ColorScheme): any { +export default function project_diagnostics(): any { + const theme = useTheme() + return { background: background(theme.highest), tab_icon_spacing: 4, diff --git a/styles/src/style_tree/project_panel.ts b/styles/src/style_tree/project_panel.ts index d1024778f1d1423eba265ca7a4ee8be7706975cc..af997d0a6e8099a0b8449bf0685df1dd4a0a4eda 100644 --- a/styles/src/style_tree/project_panel.ts +++ b/styles/src/style_tree/project_panel.ts @@ -1,4 +1,3 @@ -import { ColorScheme } from "../theme/color_scheme" import { with_opacity } from "../theme/color" import { Border, @@ -10,7 +9,10 @@ import { } from "./components" import { interactive, toggleable } from "../element" import merge from "ts-deepmerge" -export default function project_panel(theme: ColorScheme): any { +import { useTheme } from "../theme" +export default function project_panel(): any { + const theme = useTheme() + const { is_light } = theme type EntryStateProps = { @@ -65,13 +67,12 @@ export default function project_panel(theme: ColorScheme): any { const unselected_hovered_style = merge( base_properties, { background: background(theme.middle, "hovered") }, - unselected?.hovered ?? {}, + unselected?.hovered ?? {} ) const unselected_clicked_style = merge( base_properties, - { background: background(theme.middle, "pressed"), } - , - unselected?.clicked ?? {}, + { background: background(theme.middle, "pressed") }, + unselected?.clicked ?? {} ) const selected_default_style = merge( base_properties, @@ -79,18 +80,15 @@ export default function project_panel(theme: ColorScheme): any { background: background(theme.lowest), text: text(theme.lowest, "sans", { size: "sm" }), }, - selected_style?.default ?? {}, - + selected_style?.default ?? {} ) const selected_hovered_style = merge( base_properties, { background: background(theme.lowest, "hovered"), text: text(theme.lowest, "sans", { size: "sm" }), - }, - selected_style?.hovered ?? {}, - + selected_style?.hovered ?? {} ) const selected_clicked_style = merge( base_properties, @@ -98,8 +96,7 @@ export default function project_panel(theme: ColorScheme): any { background: background(theme.lowest, "pressed"), text: text(theme.lowest, "sans", { size: "sm" }), }, - selected_style?.clicked ?? {}, - + selected_style?.clicked ?? {} ) return toggleable({ diff --git a/styles/src/style_tree/project_shared_notification.ts b/styles/src/style_tree/project_shared_notification.ts index ffda0f4b70812a9ff1c1ea65ac87a280c8836bad..e7c1dcedd513ecaf07d16464c8510ccd93d36df8 100644 --- a/styles/src/style_tree/project_shared_notification.ts +++ b/styles/src/style_tree/project_shared_notification.ts @@ -1,9 +1,9 @@ -import { ColorScheme } from "../theme/color_scheme" +import { useTheme } from "../theme" import { background, border, text } from "./components" -export default function project_shared_notification( - theme: ColorScheme -): unknown { +export default function project_shared_notification(): unknown { + const theme = useTheme() + const avatar_size = 48 return { window_height: 74, diff --git a/styles/src/style_tree/search.ts b/styles/src/style_tree/search.ts index df260f95b79dc00a22eb3fa23c31b32d03c0007e..5c16d03233ee7af3f22fb3c67bf9b5b4a69f524d 100644 --- a/styles/src/style_tree/search.ts +++ b/styles/src/style_tree/search.ts @@ -1,9 +1,11 @@ -import { ColorScheme } from "../theme/color_scheme" import { with_opacity } from "../theme/color" import { background, border, foreground, text } from "./components" import { interactive, toggleable } from "../element" +import { useTheme } from "../theme" + +export default function search(): any { + const theme = useTheme() -export default function search(theme: ColorScheme): any { // Search input const editor = { background: background(theme.highest), diff --git a/styles/src/style_tree/shared_screen.ts b/styles/src/style_tree/shared_screen.ts index b57c483f1c27b106e44f6a482dc9d8c64cdacacb..aca7fd7f0778d6984cf5d26aea7cab007fad8ebb 100644 --- a/styles/src/style_tree/shared_screen.ts +++ b/styles/src/style_tree/shared_screen.ts @@ -1,7 +1,9 @@ -import { ColorScheme } from "../theme/color_scheme" +import { useTheme } from "../theme" import { background } from "./components" -export default function sharedScreen(theme: ColorScheme) { +export default function sharedScreen() { + const theme = useTheme() + return { background: background(theme.highest), } diff --git a/styles/src/style_tree/simple_message_notification.ts b/styles/src/style_tree/simple_message_notification.ts index 0b5c1e0c294dc9b6f96afb9614a4841b65e2281c..35133f04a2de39cb722b87784f77e08f270fcb78 100644 --- a/styles/src/style_tree/simple_message_notification.ts +++ b/styles/src/style_tree/simple_message_notification.ts @@ -1,8 +1,10 @@ -import { ColorScheme } from "../theme/color_scheme" import { background, border, foreground, text } from "./components" import { interactive } from "../element" +import { useTheme } from "../theme" + +export default function simple_message_notification(): any { + const theme = useTheme() -export default function simple_message_notification(theme: ColorScheme): any { const header_padding = 8 return { diff --git a/styles/src/style_tree/status_bar.ts b/styles/src/style_tree/status_bar.ts index bde40d570c5c2bc8b42af00a52eca9ccb7b8e26b..9aeea866f3b33c738e6630c54ce92b21408cb6f2 100644 --- a/styles/src/style_tree/status_bar.ts +++ b/styles/src/style_tree/status_bar.ts @@ -1,7 +1,9 @@ -import { ColorScheme } from "../theme/color_scheme" import { background, border, foreground, text } from "./components" import { interactive, toggleable } from "../element" -export default function status_bar(theme: ColorScheme): any { +import { useTheme } from "../common" +export default function status_bar(): any { + const theme = useTheme() + const layer = theme.lowest const status_container = { diff --git a/styles/src/style_tree/tab_bar.ts b/styles/src/style_tree/tab_bar.ts index 55fd2c314a9781d4719f5d16fd5cd498202f89a1..29769f9bae27ba5cc69cf81dae95f915051f4bd8 100644 --- a/styles/src/style_tree/tab_bar.ts +++ b/styles/src/style_tree/tab_bar.ts @@ -1,9 +1,11 @@ -import { ColorScheme } from "../theme/color_scheme" import { with_opacity } from "../theme/color" import { text, border, background, foreground } from "./components" import { interactive, toggleable } from "../element" +import { useTheme } from "../common" + +export default function tab_bar(): any { + const theme = useTheme() -export default function tab_bar(theme: ColorScheme): any { const height = 32 const active_layer = theme.highest diff --git a/styles/src/style_tree/terminal.ts b/styles/src/style_tree/terminal.ts index e902aa42647a56b1de3642a0c89673863a62754f..5b98eebfcdb416dfd0acdfd7f15076785eec59b7 100644 --- a/styles/src/style_tree/terminal.ts +++ b/styles/src/style_tree/terminal.ts @@ -1,6 +1,8 @@ -import { ColorScheme } from "../theme/color_scheme" +import { useTheme } from "../theme" + +export default function terminal() { + const theme = useTheme() -export default function terminal(theme: ColorScheme) { /** * Colors are controlled per-cell in the terminal grid. * Cells can be set to any of these more 'theme-capable' colors diff --git a/styles/src/style_tree/titlebar.ts b/styles/src/style_tree/titlebar.ts index 067d619bb524880c1ddd9085a889cf41d3177470..4dbd8f08f9ad014b8de71b9add006478bb8b351d 100644 --- a/styles/src/style_tree/titlebar.ts +++ b/styles/src/style_tree/titlebar.ts @@ -1,7 +1,7 @@ -import { ColorScheme } from "../common" import { icon_button, toggleable_icon_button } from "../component/icon_button" import { toggleable_text_button } from "../component/text_button" import { interactive, toggleable } from "../element" +import { useTheme } from "../theme" import { with_opacity } from "../theme/color" import { background, border, foreground, text } from "./components" @@ -22,7 +22,9 @@ function build_spacing( } } -function call_controls(theme: ColorScheme) { +function call_controls() { + const theme = useTheme() + const button_height = 18 const space = build_spacing(TITLEBAR_HEIGHT, button_height, ITEM_SPACING) @@ -69,7 +71,9 @@ function call_controls(theme: ColorScheme) { * When logged in shows the user's avatar and a chevron, * When logged out only shows a chevron. */ -function user_menu(theme: ColorScheme) { +function user_menu() { + const theme = useTheme() + const button_height = 18 const space = build_spacing(TITLEBAR_HEIGHT, button_height, ITEM_SPACING) @@ -155,7 +159,9 @@ function user_menu(theme: ColorScheme) { } } -export function titlebar(theme: ColorScheme): any { +export function titlebar(): any { + const theme = useTheme() + const avatar_width = 15 const avatar_outer_width = avatar_width + 4 const follower_avatar_width = 14 @@ -237,14 +243,14 @@ export function titlebar(theme: ColorScheme): any { corner_radius: 6, }, - leave_call_button: icon_button(theme, { + leave_call_button: icon_button({ margin: { left: ITEM_SPACING / 2, right: ITEM_SPACING, }, }), - ...call_controls(theme), + ...call_controls(), toggle_contacts_button: toggleable_icon_button(theme, { margin: { @@ -261,6 +267,6 @@ export function titlebar(theme: ColorScheme): any { background: foreground(theme.lowest, "accent"), }, share_button: toggleable_text_button(theme, {}), - user_menu: user_menu(theme), + user_menu: user_menu(), } } diff --git a/styles/src/style_tree/toolbar_dropdown_menu.ts b/styles/src/style_tree/toolbar_dropdown_menu.ts index dc22ac73cf09033a9f446555e871401990b0e81c..97f29ab18c0b873f68b4b020bb2722cadfaa1fbc 100644 --- a/styles/src/style_tree/toolbar_dropdown_menu.ts +++ b/styles/src/style_tree/toolbar_dropdown_menu.ts @@ -1,7 +1,9 @@ -import { ColorScheme } from "../theme/color_scheme" import { background, border, text } from "./components" import { interactive, toggleable } from "../element" -export default function dropdown_menu(theme: ColorScheme): any { +import { useTheme } from "../theme" +export default function dropdown_menu(): any { + const theme = useTheme() + return { row_height: 30, background: background(theme.middle), diff --git a/styles/src/style_tree/tooltip.ts b/styles/src/style_tree/tooltip.ts index 2fa5db04d4f96eee33cca9ea9190dff275ad7e0c..54a2d7b78de071f316ee0151a2f99e7f4198d842 100644 --- a/styles/src/style_tree/tooltip.ts +++ b/styles/src/style_tree/tooltip.ts @@ -1,7 +1,9 @@ -import { ColorScheme } from "../theme/color_scheme" +import { useTheme } from "../theme" import { background, border, text } from "./components" -export default function tooltip(theme: ColorScheme): any { +export default function tooltip(): any { + const theme = useTheme() + return { background: background(theme.middle), border: border(theme.middle), diff --git a/styles/src/style_tree/update_notification.ts b/styles/src/style_tree/update_notification.ts index d14e840450f36a39bc705ac6018563bc1bf4ad81..2d0c36d74cce4514fb48c915f249276c44bc628a 100644 --- a/styles/src/style_tree/update_notification.ts +++ b/styles/src/style_tree/update_notification.ts @@ -1,8 +1,10 @@ -import { ColorScheme } from "../theme/color_scheme" import { foreground, text } from "./components" import { interactive } from "../element" +import { useTheme } from "../theme" + +export default function update_notification(): any { + const theme = useTheme() -export default function update_notification(theme: ColorScheme): any { const header_padding = 8 return { diff --git a/styles/src/style_tree/welcome.ts b/styles/src/style_tree/welcome.ts index fad8dfe23523ba3b1654072251adf3b466963906..8ff15d5d26fd05856747eaa898df9cc052b6f2b7 100644 --- a/styles/src/style_tree/welcome.ts +++ b/styles/src/style_tree/welcome.ts @@ -1,4 +1,3 @@ -import { ColorScheme } from "../theme/color_scheme" import { with_opacity } from "../theme/color" import { border, @@ -9,8 +8,11 @@ import { svg, } from "./components" import { interactive } from "../element" +import { useTheme } from "../theme" + +export default function welcome(): any { + const theme = useTheme() -export default function welcome(theme: ColorScheme): any { const checkbox_base = { corner_radius: 4, padding: { diff --git a/styles/src/style_tree/workspace.ts b/styles/src/style_tree/workspace.ts index 0326de414abea6e189cae93a1321fe0a8c0f4fa0..5aee3c987d34b75d25db5bc9ad69f4d2a0938f7b 100644 --- a/styles/src/style_tree/workspace.ts +++ b/styles/src/style_tree/workspace.ts @@ -1,4 +1,3 @@ -import { ColorScheme } from "../theme/color_scheme" import { with_opacity } from "../theme/color" import { background, @@ -11,9 +10,12 @@ import { import statusBar from "./status_bar" import tabBar from "./tab_bar" import { interactive } from "../element" - import { titlebar } from "./titlebar" -export default function workspace(theme: ColorScheme): any { +import { useTheme } from "../theme" + +export default function workspace(): any { + const theme = useTheme() + const { is_light } = theme return { @@ -85,7 +87,7 @@ export default function workspace(theme: ColorScheme): any { }, leader_border_opacity: 0.7, leader_border_width: 2.0, - tab_bar: tabBar(theme), + tab_bar: tabBar(), modal: { margin: { bottom: 52, @@ -123,8 +125,8 @@ export default function workspace(theme: ColorScheme): any { color: border_color(theme.lowest), width: 1, }, - status_bar: statusBar(theme), - titlebar: titlebar(theme), + status_bar: statusBar(), + titlebar: titlebar(), toolbar: { height: 34, background: background(theme.highest), diff --git a/styles/src/theme/index.ts b/styles/src/theme/index.ts index 22287bf6699a7f690b1b6b29b0689adc47dea757..100248b1a8df5fc1edfb0a1b92a7ecde27c7bae0 100644 --- a/styles/src/theme/index.ts +++ b/styles/src/theme/index.ts @@ -1,3 +1,24 @@ +import { create } from "zustand" +import { ColorScheme } from "./color_scheme" + +type ThemeState = { + theme: ColorScheme | undefined + setTheme: (theme: ColorScheme) => void +} + +export const useThemeStore = create((set) => ({ + theme: undefined, + setTheme: (theme) => set(() => ({ theme })), +})) + +export const useTheme = (): ColorScheme => { + const { theme } = useThemeStore.getState() + + if (!theme) throw new Error("Tried to use theme before it was loaded") + + return theme +} + export * from "./color_scheme" export * from "./ramps" export * from "./syntax" From 8a5e7047f0e59178e11eadd96a4a7b3ef417fbf7 Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Tue, 4 Jul 2023 00:32:27 -0400 Subject: [PATCH 055/104] Update a few more components --- styles/src/build_tokens.ts | 2 +- styles/src/theme/tokens/color_scheme.ts | 23 ++++++++++++-------- styles/src/theme/tokens/players.ts | 28 ++++++++++++++----------- 3 files changed, 31 insertions(+), 22 deletions(-) diff --git a/styles/src/build_tokens.ts b/styles/src/build_tokens.ts index e33c3712e64d94d56b9b20d9317c270dd0b0aa28..f51e5eb6cf25caf90052a8a45847fb84ee91a4a2 100644 --- a/styles/src/build_tokens.ts +++ b/styles/src/build_tokens.ts @@ -60,7 +60,7 @@ function write_tokens(themes: ColorScheme[], tokens_directory: string) { for (const theme of themes) { const file_name = slugify(theme.name) + ".json" - const tokens = theme_tokens(theme) + const tokens = theme_tokens() const tokens_json = JSON.stringify(tokens, null, 2) const out_path = path.join(tokens_directory, file_name) fs.writeFileSync(out_path, tokens_json, { mode: 0o644 }) diff --git a/styles/src/theme/tokens/color_scheme.ts b/styles/src/theme/tokens/color_scheme.ts index a8ce4ec2d252de5f8ec13963c5f41ecbb8ab3424..efbeaaa901eb110964d180f1e92a349c47624efd 100644 --- a/styles/src/theme/tokens/color_scheme.ts +++ b/styles/src/theme/tokens/color_scheme.ts @@ -15,6 +15,7 @@ import { PlayersToken, players_token } from "./players" import { color_token } from "./token" import { Syntax } from "../syntax" import editor from "../../style_tree/editor" +import { useTheme } from "@/src/common" interface ColorSchemeTokens { name: SingleOtherToken @@ -39,12 +40,14 @@ const create_shadow_token = ( } } -const popover_shadow_token = (theme: ColorScheme): SingleBoxShadowToken => { +const popover_shadow_token = (): SingleBoxShadowToken => { + const theme = useTheme() const shadow = theme.popover_shadow return create_shadow_token(shadow, "popover_shadow") } -const modal_shadow_token = (theme: ColorScheme): SingleBoxShadowToken => { +const modal_shadow_token = (): SingleBoxShadowToken => { + const theme = useTheme() const shadow = theme.modal_shadow return create_shadow_token(shadow, "modal_shadow") } @@ -68,13 +71,15 @@ function syntax_highlight_style_color_tokens( }, {} as ThemeSyntaxColorTokens) } -const syntax_tokens = (theme: ColorScheme): ColorSchemeTokens["syntax"] => { - const syntax = editor(theme).syntax +const syntax_tokens = (): ColorSchemeTokens["syntax"] => { + const syntax = editor().syntax return syntax_highlight_style_color_tokens(syntax) } -export function theme_tokens(theme: ColorScheme): ColorSchemeTokens { +export function theme_tokens(): ColorSchemeTokens { + const theme = useTheme() + return { name: { name: "themeName", @@ -89,9 +94,9 @@ export function theme_tokens(theme: ColorScheme): ColorSchemeTokens { lowest: layer_token(theme.lowest, "lowest"), middle: layer_token(theme.middle, "middle"), highest: layer_token(theme.highest, "highest"), - popover_shadow: popover_shadow_token(theme), - modal_shadow: modal_shadow_token(theme), - players: players_token(theme), - syntax: syntax_tokens(theme), + popover_shadow: popover_shadow_token(), + modal_shadow: modal_shadow_token(), + players: players_token(), + syntax: syntax_tokens(), } } diff --git a/styles/src/theme/tokens/players.ts b/styles/src/theme/tokens/players.ts index 545a712ff123e12aaa2dd32a9645ea64001dd061..85573a1a8f6c4031de681e5d9a43f2d4893dac2b 100644 --- a/styles/src/theme/tokens/players.ts +++ b/styles/src/theme/tokens/players.ts @@ -1,12 +1,14 @@ import { SingleColorToken } from "@tokens-studio/types" import { color_token } from "./token" -import { ColorScheme, Players } from "../color_scheme" +import { Players } from "../color_scheme" +import { useTheme } from "@/src/common" export type PlayerToken = Record<"selection" | "cursor", SingleColorToken> export type PlayersToken = Record -function build_player_token(theme: ColorScheme, index: number): PlayerToken { +function build_player_token(index: number): PlayerToken { + const theme = useTheme() const player_number = index.toString() as keyof Players return { @@ -21,13 +23,15 @@ function build_player_token(theme: ColorScheme, index: number): PlayerToken { } } -export const players_token = (theme: ColorScheme): PlayersToken => ({ - "0": build_player_token(theme, 0), - "1": build_player_token(theme, 1), - "2": build_player_token(theme, 2), - "3": build_player_token(theme, 3), - "4": build_player_token(theme, 4), - "5": build_player_token(theme, 5), - "6": build_player_token(theme, 6), - "7": build_player_token(theme, 7), -}) +export const players_token = (): PlayersToken => { + return { + "0": build_player_token(0), + "1": build_player_token(1), + "2": build_player_token(2), + "3": build_player_token(3), + "4": build_player_token(4), + "5": build_player_token(5), + "6": build_player_token(6), + "7": build_player_token(7), + } +} From 5a1476a1e58c43e64d051e5af9786d8edaa85088 Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Tue, 4 Jul 2023 00:40:01 -0400 Subject: [PATCH 056/104] Remove unused `color_scheme` field in the theme --- crates/theme/src/theme.rs | 1 - styles/src/style_tree/app.ts | 17 +---------------- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/crates/theme/src/theme.rs b/crates/theme/src/theme.rs index e54dcdfd1e987eaf24656bc735079db54d37f0bc..20f07878267c4f05448a20199ab16aef3dd8e181 100644 --- a/crates/theme/src/theme.rs +++ b/crates/theme/src/theme.rs @@ -65,7 +65,6 @@ pub struct Theme { pub assistant: AssistantStyle, pub feedback: FeedbackStyle, pub welcome: WelcomeStyle, - pub color_scheme: ColorScheme, pub titlebar: Titlebar, } diff --git a/styles/src/style_tree/app.ts b/styles/src/style_tree/app.ts index e4bf232b624ed01f6dd1ddcd20826ab6a43aca1d..ccfdd60a981f4d5e763ce35902b0456bf0d703cd 100644 --- a/styles/src/style_tree/app.ts +++ b/styles/src/style_tree/app.ts @@ -57,21 +57,6 @@ export default function app(): any { tooltip: tooltip(), terminal: terminal(), assistant: assistant(), - feedback: feedback(), - color_scheme: { - ...theme, - players: Object.values(theme.players), - ramps: { - neutral: theme.ramps.neutral.colors(100, "hex"), - red: theme.ramps.red.colors(100, "hex"), - orange: theme.ramps.orange.colors(100, "hex"), - yellow: theme.ramps.yellow.colors(100, "hex"), - green: theme.ramps.green.colors(100, "hex"), - cyan: theme.ramps.cyan.colors(100, "hex"), - blue: theme.ramps.blue.colors(100, "hex"), - violet: theme.ramps.violet.colors(100, "hex"), - magenta: theme.ramps.magenta.colors(100, "hex"), - }, - }, + feedback: feedback() } } From c409059dc45e0a677bd61239c35405df6f26bbd1 Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Tue, 4 Jul 2023 00:41:13 -0400 Subject: [PATCH 057/104] Revert "Remove unused `color_scheme` field in the theme" This reverts commit 5a1476a1e58c43e64d051e5af9786d8edaa85088. --- crates/theme/src/theme.rs | 1 + styles/src/style_tree/app.ts | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/crates/theme/src/theme.rs b/crates/theme/src/theme.rs index 20f07878267c4f05448a20199ab16aef3dd8e181..e54dcdfd1e987eaf24656bc735079db54d37f0bc 100644 --- a/crates/theme/src/theme.rs +++ b/crates/theme/src/theme.rs @@ -65,6 +65,7 @@ pub struct Theme { pub assistant: AssistantStyle, pub feedback: FeedbackStyle, pub welcome: WelcomeStyle, + pub color_scheme: ColorScheme, pub titlebar: Titlebar, } diff --git a/styles/src/style_tree/app.ts b/styles/src/style_tree/app.ts index ccfdd60a981f4d5e763ce35902b0456bf0d703cd..e4bf232b624ed01f6dd1ddcd20826ab6a43aca1d 100644 --- a/styles/src/style_tree/app.ts +++ b/styles/src/style_tree/app.ts @@ -57,6 +57,21 @@ export default function app(): any { tooltip: tooltip(), terminal: terminal(), assistant: assistant(), - feedback: feedback() + feedback: feedback(), + color_scheme: { + ...theme, + players: Object.values(theme.players), + ramps: { + neutral: theme.ramps.neutral.colors(100, "hex"), + red: theme.ramps.red.colors(100, "hex"), + orange: theme.ramps.orange.colors(100, "hex"), + yellow: theme.ramps.yellow.colors(100, "hex"), + green: theme.ramps.green.colors(100, "hex"), + cyan: theme.ramps.cyan.colors(100, "hex"), + blue: theme.ramps.blue.colors(100, "hex"), + violet: theme.ramps.violet.colors(100, "hex"), + magenta: theme.ramps.magenta.colors(100, "hex"), + }, + }, } } From a732b2e04347be269fc096ff5314035e4e492c8c Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Tue, 4 Jul 2023 00:44:12 -0400 Subject: [PATCH 058/104] Remove unused `color_scheme` field in the theme I totally didn't mean to commit this right to main T_T --- crates/theme/src/theme.rs | 1 - styles/src/style_tree/app.ts | 17 +---------------- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/crates/theme/src/theme.rs b/crates/theme/src/theme.rs index e54dcdfd1e987eaf24656bc735079db54d37f0bc..20f07878267c4f05448a20199ab16aef3dd8e181 100644 --- a/crates/theme/src/theme.rs +++ b/crates/theme/src/theme.rs @@ -65,7 +65,6 @@ pub struct Theme { pub assistant: AssistantStyle, pub feedback: FeedbackStyle, pub welcome: WelcomeStyle, - pub color_scheme: ColorScheme, pub titlebar: Titlebar, } diff --git a/styles/src/style_tree/app.ts b/styles/src/style_tree/app.ts index e4bf232b624ed01f6dd1ddcd20826ab6a43aca1d..ccfdd60a981f4d5e763ce35902b0456bf0d703cd 100644 --- a/styles/src/style_tree/app.ts +++ b/styles/src/style_tree/app.ts @@ -57,21 +57,6 @@ export default function app(): any { tooltip: tooltip(), terminal: terminal(), assistant: assistant(), - feedback: feedback(), - color_scheme: { - ...theme, - players: Object.values(theme.players), - ramps: { - neutral: theme.ramps.neutral.colors(100, "hex"), - red: theme.ramps.red.colors(100, "hex"), - orange: theme.ramps.orange.colors(100, "hex"), - yellow: theme.ramps.yellow.colors(100, "hex"), - green: theme.ramps.green.colors(100, "hex"), - cyan: theme.ramps.cyan.colors(100, "hex"), - blue: theme.ramps.blue.colors(100, "hex"), - violet: theme.ramps.violet.colors(100, "hex"), - magenta: theme.ramps.magenta.colors(100, "hex"), - }, - }, + feedback: feedback() } } From 65dbb3892672447af726b5875dc1e529a8b9ccc1 Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Tue, 4 Jul 2023 01:20:56 -0400 Subject: [PATCH 059/104] `color_scheme` -> `theme` --- docs/zed/syntax-highlighting.md | 2 +- styles/src/build_themes.ts | 16 ++-- styles/src/build_tokens.ts | 17 ++-- styles/src/component/icon_button.ts | 14 +-- styles/src/component/text_button.ts | 14 +-- styles/src/style_tree/components.ts | 2 +- styles/src/style_tree/editor.ts | 4 +- .../{color_scheme.ts => create_theme.ts} | 4 +- styles/src/theme/index.ts | 10 +-- styles/src/theme/ramps.ts | 2 +- styles/src/theme/syntax.ts | 86 +++++++++---------- styles/src/theme/theme_config.ts | 67 --------------- styles/src/theme/tokens/layer.ts | 2 +- styles/src/theme/tokens/players.ts | 4 +- .../tokens/{color_scheme.ts => theme.ts} | 11 ++- 15 files changed, 93 insertions(+), 162 deletions(-) rename styles/src/theme/{color_scheme.ts => create_theme.ts} (98%) rename styles/src/theme/tokens/{color_scheme.ts => theme.ts} (93%) diff --git a/docs/zed/syntax-highlighting.md b/docs/zed/syntax-highlighting.md index 3878fcc6e992fd6b38b62ddfc29186b37ede7e8c..d4331ee367934453b19c6cd30af57924409b34d7 100644 --- a/docs/zed/syntax-highlighting.md +++ b/docs/zed/syntax-highlighting.md @@ -35,7 +35,7 @@ Match a property identifier and highlight it using the identifier `@property`. I ``` ```ts -function buildDefaultSyntax(colorScheme: ColorScheme): Partial { +function buildDefaultSyntax(colorScheme: Theme): Partial { // ... } ``` diff --git a/styles/src/build_themes.ts b/styles/src/build_themes.ts index a9cbad94e7fb104adc35e22c6a0b6943aa44992f..17575663a1f88b17870b1b146b47e7086bf3e2ba 100644 --- a/styles/src/build_themes.ts +++ b/styles/src/build_themes.ts @@ -2,7 +2,7 @@ import * as fs from "fs" import { tmpdir } from "os" import * as path from "path" import app from "./style_tree/app" -import { ColorScheme, create_color_scheme } from "./theme/color_scheme" +import { Theme, create_theme } from "./theme/create_theme" import { themes } from "./themes" import { useThemeStore } from "./theme" @@ -21,22 +21,22 @@ function clear_themes(theme_directory: string) { } } -const all_themes: ColorScheme[] = themes.map((theme) => - create_color_scheme(theme) +const all_themes: Theme[] = themes.map((theme) => + create_theme(theme) ) -function write_themes(themes: ColorScheme[], output_directory: string) { +function write_themes(themes: Theme[], output_directory: string) { clear_themes(output_directory) - for (const color_scheme of themes) { + for (const theme of themes) { const { setTheme } = useThemeStore.getState() - setTheme(color_scheme) + setTheme(theme) const style_tree = app() const style_tree_json = JSON.stringify(style_tree, null, 2) - const temp_path = path.join(temp_directory, `${color_scheme.name}.json`) + const temp_path = path.join(temp_directory, `${theme.name}.json`) const out_path = path.join( output_directory, - `${color_scheme.name}.json` + `${theme.name}.json` ) fs.writeFileSync(temp_path, style_tree_json) fs.renameSync(temp_path, out_path) diff --git a/styles/src/build_tokens.ts b/styles/src/build_tokens.ts index f51e5eb6cf25caf90052a8a45847fb84ee91a4a2..fd6aa18ced50af53b6bcf4c3c386d1774c7ab00d 100644 --- a/styles/src/build_tokens.ts +++ b/styles/src/build_tokens.ts @@ -1,9 +1,9 @@ import * as fs from "fs" import * as path from "path" -import { ColorScheme, create_color_scheme } from "./common" +import { Theme, create_theme, useThemeStore } from "./common" import { themes } from "./themes" import { slugify } from "./utils/slugify" -import { theme_tokens } from "./theme/tokens/color_scheme" +import { theme_tokens } from "./theme/tokens/theme" const TOKENS_DIRECTORY = path.join(__dirname, "..", "target", "tokens") const TOKENS_FILE = path.join(TOKENS_DIRECTORY, "$themes.json") @@ -27,7 +27,7 @@ type TokenSet = { selected_token_sets: { [key: string]: "enabled" } } -function build_token_set_order(theme: ColorScheme[]): { +function build_token_set_order(theme: Theme[]): { token_set_order: string[] } { const token_set_order: string[] = theme.map((scheme) => @@ -36,7 +36,7 @@ function build_token_set_order(theme: ColorScheme[]): { return { token_set_order } } -function build_themes_index(theme: ColorScheme[]): TokenSet[] { +function build_themes_index(theme: Theme[]): TokenSet[] { const themes_index: TokenSet[] = theme.map((scheme, index) => { const id = `${scheme.is_light ? "light" : "dark"}_${scheme.name .toLowerCase() @@ -55,10 +55,13 @@ function build_themes_index(theme: ColorScheme[]): TokenSet[] { return themes_index } -function write_tokens(themes: ColorScheme[], tokens_directory: string) { +function write_tokens(themes: Theme[], tokens_directory: string) { clear_tokens(tokens_directory) for (const theme of themes) { + const { setTheme } = useThemeStore.getState() + setTheme(theme) + const file_name = slugify(theme.name) + ".json" const tokens = theme_tokens() const tokens_json = JSON.stringify(tokens, null, 2) @@ -80,8 +83,8 @@ function write_tokens(themes: ColorScheme[], tokens_directory: string) { console.log(`- ${METADATA_FILE} created`) } -const all_themes: ColorScheme[] = themes.map((theme) => - create_color_scheme(theme) +const all_themes: Theme[] = themes.map((theme) => + create_theme(theme) ) write_tokens(all_themes, TOKENS_DIRECTORY) diff --git a/styles/src/component/icon_button.ts b/styles/src/component/icon_button.ts index 18b900e83328bf4bd409e30b9579d0296c6b338b..6887fc7c30e1f234fd043bb115c2658039b5f806 100644 --- a/styles/src/component/icon_button.ts +++ b/styles/src/component/icon_button.ts @@ -1,6 +1,6 @@ import { interactive, toggleable } from "../element" import { background, foreground } from "../style_tree/components" -import { useTheme, ColorScheme } from "../theme" +import { useTheme, Theme } from "../theme" export type Margin = { top: number @@ -11,15 +11,15 @@ export type Margin = { interface IconButtonOptions { layer?: - | ColorScheme["lowest"] - | ColorScheme["middle"] - | ColorScheme["highest"] - color?: keyof ColorScheme["lowest"] + | Theme["lowest"] + | Theme["middle"] + | Theme["highest"] + color?: keyof Theme["lowest"] margin?: Partial } type ToggleableIconButtonOptions = IconButtonOptions & { - active_color?: keyof ColorScheme["lowest"] + active_color?: keyof Theme["lowest"] } export function icon_button({ color, margin, layer }: IconButtonOptions) { @@ -67,7 +67,7 @@ export function icon_button({ color, margin, layer }: IconButtonOptions) { } export function toggleable_icon_button( - theme: ColorScheme, + theme: Theme, { color, active_color, margin }: ToggleableIconButtonOptions ) { if (!color) color = "base" diff --git a/styles/src/component/text_button.ts b/styles/src/component/text_button.ts index 50737f976686f4a33b1d4ab5d5a81e61ebefd108..58b2a1cbf2ff31a8e4fc50b9e1165bca78ec6b4a 100644 --- a/styles/src/component/text_button.ts +++ b/styles/src/component/text_button.ts @@ -5,21 +5,21 @@ import { foreground, text, } from "../style_tree/components" -import { useTheme, ColorScheme } from "../theme" +import { useTheme, Theme } from "../theme" import { Margin } from "./icon_button" interface TextButtonOptions { layer?: - | ColorScheme["lowest"] - | ColorScheme["middle"] - | ColorScheme["highest"] - color?: keyof ColorScheme["lowest"] + | Theme["lowest"] + | Theme["middle"] + | Theme["highest"] + color?: keyof Theme["lowest"] margin?: Partial text_properties?: TextProperties } type ToggleableTextButtonOptions = TextButtonOptions & { - active_color?: keyof ColorScheme["lowest"] + active_color?: keyof Theme["lowest"] } export function text_button({ @@ -75,7 +75,7 @@ export function text_button({ } export function toggleable_text_button( - theme: ColorScheme, + theme: Theme, { color, active_color, margin }: ToggleableTextButtonOptions ) { if (!color) color = "base" diff --git a/styles/src/style_tree/components.ts b/styles/src/style_tree/components.ts index db32712f41b5d0d2f8cf785ea53a2008b6a80cdf..43a5fa9d28e2c96f25a9975db15d139bee4ff897 100644 --- a/styles/src/style_tree/components.ts +++ b/styles/src/style_tree/components.ts @@ -1,5 +1,5 @@ import { font_families, font_sizes, FontWeight } from "../common" -import { Layer, Styles, StyleSets, Style } from "../theme/color_scheme" +import { Layer, Styles, StyleSets, Style } from "../theme/create_theme" function is_style_set(key: any): key is StyleSets { return [ diff --git a/styles/src/style_tree/editor.ts b/styles/src/style_tree/editor.ts index 31fa86110da30c5ad56f75291bce674b194fa2fd..a2fec116420a44443cc3984d8bd55851e0cef68d 100644 --- a/styles/src/style_tree/editor.ts +++ b/styles/src/style_tree/editor.ts @@ -1,5 +1,5 @@ import { with_opacity } from "../theme/color" -import { Layer, StyleSets } from "../theme/color_scheme" +import { Layer, StyleSets } from "../theme/create_theme" import { background, border, @@ -48,7 +48,7 @@ export default function editor(): any { } } - const syntax = build_syntax(theme) + const syntax = build_syntax() return { text_color: syntax.primary.color, diff --git a/styles/src/theme/color_scheme.ts b/styles/src/theme/create_theme.ts similarity index 98% rename from styles/src/theme/color_scheme.ts rename to styles/src/theme/create_theme.ts index 933c6160535386dea3f7b3b517c3d95b234cbcbe..dff4c3dbc47c9a3542304d8544bb577e3fed22f6 100644 --- a/styles/src/theme/color_scheme.ts +++ b/styles/src/theme/create_theme.ts @@ -8,7 +8,7 @@ import { } from "./theme_config" import { get_ramps } from "./ramps" -export interface ColorScheme { +export interface Theme { name: string is_light: boolean @@ -105,7 +105,7 @@ export interface Style { foreground: string } -export function create_color_scheme(theme: ThemeConfig): ColorScheme { +export function create_theme(theme: ThemeConfig): Theme { const { name, appearance, diff --git a/styles/src/theme/index.ts b/styles/src/theme/index.ts index 100248b1a8df5fc1edfb0a1b92a7ecde27c7bae0..ca8aaa461fa12204b35596f34056c02c52d740e4 100644 --- a/styles/src/theme/index.ts +++ b/styles/src/theme/index.ts @@ -1,9 +1,9 @@ import { create } from "zustand" -import { ColorScheme } from "./color_scheme" +import { Theme } from "./create_theme" type ThemeState = { - theme: ColorScheme | undefined - setTheme: (theme: ColorScheme) => void + theme: Theme | undefined + setTheme: (theme: Theme) => void } export const useThemeStore = create((set) => ({ @@ -11,7 +11,7 @@ export const useThemeStore = create((set) => ({ setTheme: (theme) => set(() => ({ theme })), })) -export const useTheme = (): ColorScheme => { +export const useTheme = (): Theme => { const { theme } = useThemeStore.getState() if (!theme) throw new Error("Tried to use theme before it was loaded") @@ -19,7 +19,7 @@ export const useTheme = (): ColorScheme => { return theme } -export * from "./color_scheme" +export * from "./create_theme" export * from "./ramps" export * from "./syntax" export * from "./theme_config" diff --git a/styles/src/theme/ramps.ts b/styles/src/theme/ramps.ts index 118d0c727456f5369abbd1ca3bb2cbd016921fac..c5b915a8c50c02529d136f0d42c9d6c61d832eaa 100644 --- a/styles/src/theme/ramps.ts +++ b/styles/src/theme/ramps.ts @@ -1,5 +1,5 @@ import chroma, { Color, Scale } from "chroma-js" -import { RampSet } from "./color_scheme" +import { RampSet } from "./create_theme" import { ThemeConfigInputColors, ThemeConfigInputColorsKeys, diff --git a/styles/src/theme/syntax.ts b/styles/src/theme/syntax.ts index c0d68e418e459687e1b9a73d5e98c25711625125..540a1d0ff9822d5a8c2cf292ddba5ace6839ac6d 100644 --- a/styles/src/theme/syntax.ts +++ b/styles/src/theme/syntax.ts @@ -1,6 +1,5 @@ import deepmerge from "deepmerge" -import { FontWeight, font_weights } from "../common" -import { ColorScheme } from "./color_scheme" +import { FontWeight, font_weights, useTheme } from "../common" import chroma from "chroma-js" export interface SyntaxHighlightStyle { @@ -123,7 +122,9 @@ const default_syntax_highlight_style: Omit = { italic: false, } -function build_default_syntax(color_scheme: ColorScheme): Syntax { +function build_default_syntax(): Syntax { + const theme = useTheme() + // Make a temporary object that is allowed to be missing // the "color" property for each style const syntax: { @@ -141,8 +142,8 @@ function build_default_syntax(color_scheme: ColorScheme): Syntax { // predictive color distinct from any other color in the theme const predictive = chroma .mix( - color_scheme.ramps.neutral(0.4).hex(), - color_scheme.ramps.blue(0.4).hex(), + theme.ramps.neutral(0.4).hex(), + theme.ramps.blue(0.4).hex(), 0.45, "lch" ) @@ -151,32 +152,32 @@ function build_default_syntax(color_scheme: ColorScheme): Syntax { // hint color distinct from any other color in the theme const hint = chroma .mix( - color_scheme.ramps.neutral(0.6).hex(), - color_scheme.ramps.blue(0.4).hex(), + theme.ramps.neutral(0.6).hex(), + theme.ramps.blue(0.4).hex(), 0.45, "lch" ) .hex() const color = { - primary: color_scheme.ramps.neutral(1).hex(), - comment: color_scheme.ramps.neutral(0.71).hex(), - punctuation: color_scheme.ramps.neutral(0.86).hex(), + primary: theme.ramps.neutral(1).hex(), + comment: theme.ramps.neutral(0.71).hex(), + punctuation: theme.ramps.neutral(0.86).hex(), predictive: predictive, hint: hint, - emphasis: color_scheme.ramps.blue(0.5).hex(), - string: color_scheme.ramps.orange(0.5).hex(), - function: color_scheme.ramps.yellow(0.5).hex(), - type: color_scheme.ramps.cyan(0.5).hex(), - constructor: color_scheme.ramps.blue(0.5).hex(), - variant: color_scheme.ramps.blue(0.5).hex(), - property: color_scheme.ramps.blue(0.5).hex(), - enum: color_scheme.ramps.orange(0.5).hex(), - operator: color_scheme.ramps.orange(0.5).hex(), - number: color_scheme.ramps.green(0.5).hex(), - boolean: color_scheme.ramps.green(0.5).hex(), - constant: color_scheme.ramps.green(0.5).hex(), - keyword: color_scheme.ramps.blue(0.5).hex(), + emphasis: theme.ramps.blue(0.5).hex(), + string: theme.ramps.orange(0.5).hex(), + function: theme.ramps.yellow(0.5).hex(), + type: theme.ramps.cyan(0.5).hex(), + constructor: theme.ramps.blue(0.5).hex(), + variant: theme.ramps.blue(0.5).hex(), + property: theme.ramps.blue(0.5).hex(), + enum: theme.ramps.orange(0.5).hex(), + operator: theme.ramps.orange(0.5).hex(), + number: theme.ramps.green(0.5).hex(), + boolean: theme.ramps.green(0.5).hex(), + constant: theme.ramps.green(0.5).hex(), + keyword: theme.ramps.blue(0.5).hex(), } // Then assign colors and use Syntax to enforce each style getting it's own color @@ -211,11 +212,11 @@ function build_default_syntax(color_scheme: ColorScheme): Syntax { weight: font_weights.bold, }, link_uri: { - color: color_scheme.ramps.green(0.5).hex(), + color: theme.ramps.green(0.5).hex(), underline: true, }, link_text: { - color: color_scheme.ramps.orange(0.5).hex(), + color: theme.ramps.orange(0.5).hex(), italic: true, }, "text.literal": { @@ -231,7 +232,7 @@ function build_default_syntax(color_scheme: ColorScheme): Syntax { color: color.punctuation, }, "punctuation.special": { - color: color_scheme.ramps.neutral(0.86).hex(), + color: theme.ramps.neutral(0.86).hex(), }, "punctuation.list_marker": { color: color.punctuation, @@ -252,10 +253,10 @@ function build_default_syntax(color_scheme: ColorScheme): Syntax { color: color.string, }, constructor: { - color: color_scheme.ramps.blue(0.5).hex(), + color: theme.ramps.blue(0.5).hex(), }, variant: { - color: color_scheme.ramps.blue(0.5).hex(), + color: theme.ramps.blue(0.5).hex(), }, type: { color: color.type, @@ -264,16 +265,16 @@ function build_default_syntax(color_scheme: ColorScheme): Syntax { color: color.primary, }, label: { - color: color_scheme.ramps.blue(0.5).hex(), + color: theme.ramps.blue(0.5).hex(), }, tag: { - color: color_scheme.ramps.blue(0.5).hex(), + color: theme.ramps.blue(0.5).hex(), }, attribute: { - color: color_scheme.ramps.blue(0.5).hex(), + color: theme.ramps.blue(0.5).hex(), }, property: { - color: color_scheme.ramps.blue(0.5).hex(), + color: theme.ramps.blue(0.5).hex(), }, constant: { color: color.constant, @@ -307,17 +308,18 @@ function build_default_syntax(color_scheme: ColorScheme): Syntax { return default_syntax } -function merge_syntax( - default_syntax: Syntax, - color_scheme: ColorScheme -): Syntax { - if (!color_scheme.syntax) { +export function build_syntax(): Syntax { + const theme = useTheme() + + const default_syntax: Syntax = build_default_syntax() + + if (!theme.syntax) { return default_syntax } - return deepmerge>( + const syntax = deepmerge>( default_syntax, - color_scheme.syntax, + theme.syntax, { arrayMerge: (destinationArray, sourceArray) => [ ...destinationArray, @@ -325,12 +327,6 @@ function merge_syntax( ], } ) -} - -export function build_syntax(color_scheme: ColorScheme): Syntax { - const default_syntax: Syntax = build_default_syntax(color_scheme) - - const syntax = merge_syntax(default_syntax, color_scheme) return syntax } diff --git a/styles/src/theme/theme_config.ts b/styles/src/theme/theme_config.ts index 26462bee6d43970c1db61e470fcab48aed20c1d0..bc8f07425f9e676a27d36ec929ea9a116006c694 100644 --- a/styles/src/theme/theme_config.ts +++ b/styles/src/theme/theme_config.ts @@ -66,35 +66,10 @@ type ThemeConfigProperties = ThemeMeta & { override: ThemeConfigOverrides } -// This should be the format a theme is defined as export type ThemeConfig = { [K in keyof ThemeConfigProperties]: ThemeConfigProperties[K] } -interface ThemeColors { - neutral: string[] - red: string[] - orange: string[] - yellow: string[] - green: string[] - cyan: string[] - blue: string[] - violet: string[] - magenta: string[] -} - -type ThemeSyntax = Required - -export type ThemeProperties = ThemeMeta & { - color: ThemeColors - syntax: ThemeSyntax -} - -// This should be a theme after all its properties have been resolved -export type Theme = { - [K in keyof ThemeProperties]: ThemeProperties[K] -} - export enum ThemeAppearance { Light = "light", Dark = "dark", @@ -104,45 +79,3 @@ export enum ThemeLicenseType { MIT = "MIT", Apache2 = "Apache License 2.0", } - -export type ThemeFamilyItem = - | ThemeConfig - | { light: ThemeConfig; dark: ThemeConfig } - -type ThemeFamilyProperties = Partial> & { - name: string - default: ThemeFamilyItem - variants: { - [key: string]: ThemeFamilyItem - } -} - -// Idea: A theme family is a collection of themes that share the same name -// For example, a theme family could be `One Dark` and have a `light` and `dark` variant -// The Ayu family could have `light`, `mirage`, and `dark` variants - -type ThemeFamily = { - [K in keyof ThemeFamilyProperties]: ThemeFamilyProperties[K] -} - -/** The collection of all themes - * - * Example: - * ```ts - * { - * one_dark, - * one_light, - * ayu: { - * name: 'Ayu', - * default: 'ayu_mirage', - * variants: { - * light: 'ayu_light', - * mirage: 'ayu_mirage', - * dark: 'ayu_dark', - * }, - * }, - * ... - * } - * ``` - */ -export type ThemeIndex = Record diff --git a/styles/src/theme/tokens/layer.ts b/styles/src/theme/tokens/layer.ts index a2e539092e4a9f0a4d49a74a615867e69bc6a923..6b4e1d79f761bb389838044d668769f7a12e4f74 100644 --- a/styles/src/theme/tokens/layer.ts +++ b/styles/src/theme/tokens/layer.ts @@ -1,5 +1,5 @@ import { SingleColorToken } from "@tokens-studio/types" -import { Layer, Style, StyleSet } from "../color_scheme" +import { Layer, Style, StyleSet } from "../create_theme" import { color_token } from "./token" interface StyleToken { diff --git a/styles/src/theme/tokens/players.ts b/styles/src/theme/tokens/players.ts index 85573a1a8f6c4031de681e5d9a43f2d4893dac2b..4bf605aa93f00e3de3bb84c01c1a9e82f3989d20 100644 --- a/styles/src/theme/tokens/players.ts +++ b/styles/src/theme/tokens/players.ts @@ -1,7 +1,7 @@ import { SingleColorToken } from "@tokens-studio/types" import { color_token } from "./token" -import { Players } from "../color_scheme" -import { useTheme } from "@/src/common" +import { Players } from "../create_theme" +import { useTheme } from "../../../src/common" export type PlayerToken = Record<"selection" | "cursor", SingleColorToken> diff --git a/styles/src/theme/tokens/color_scheme.ts b/styles/src/theme/tokens/theme.ts similarity index 93% rename from styles/src/theme/tokens/color_scheme.ts rename to styles/src/theme/tokens/theme.ts index efbeaaa901eb110964d180f1e92a349c47624efd..f759bc813910416d88a2097134dc95654d6ab3b3 100644 --- a/styles/src/theme/tokens/color_scheme.ts +++ b/styles/src/theme/tokens/theme.ts @@ -5,19 +5,18 @@ import { TokenTypes, } from "@tokens-studio/types" import { - ColorScheme, Shadow, SyntaxHighlightStyle, ThemeSyntax, -} from "../color_scheme" +} from "../create_theme" import { LayerToken, layer_token } from "./layer" import { PlayersToken, players_token } from "./players" import { color_token } from "./token" import { Syntax } from "../syntax" import editor from "../../style_tree/editor" -import { useTheme } from "@/src/common" +import { useTheme } from "../../../src/common" -interface ColorSchemeTokens { +interface ThemeTokens { name: SingleOtherToken appearance: SingleOtherToken lowest: LayerToken @@ -71,13 +70,13 @@ function syntax_highlight_style_color_tokens( }, {} as ThemeSyntaxColorTokens) } -const syntax_tokens = (): ColorSchemeTokens["syntax"] => { +const syntax_tokens = (): ThemeTokens["syntax"] => { const syntax = editor().syntax return syntax_highlight_style_color_tokens(syntax) } -export function theme_tokens(): ColorSchemeTokens { +export function theme_tokens(): ThemeTokens { const theme = useTheme() return { From f461a709702110fec0b1587187e36210bebf1a55 Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Tue, 4 Jul 2023 01:37:45 -0400 Subject: [PATCH 060/104] Remove unused ts aliases --- styles/tsconfig.json | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/styles/tsconfig.json b/styles/tsconfig.json index 925935ebb5f2f1335f838f89465a6c8ad65ce312..281bd74b215bd16426bb6a8f9d68ddeb5a5bea43 100644 --- a/styles/tsconfig.json +++ b/styles/tsconfig.json @@ -22,17 +22,9 @@ "strictPropertyInitialization": false, "skipLibCheck": true, "useUnknownInCatchVariables": false, - "baseUrl": ".", - "paths": { - "@/*": ["./*"], - "@element/*": ["./src/element/*"], - "@component/*": ["./src/component/*"], - "@styleTree/*": ["./src/styleTree/*"], - "@theme/*": ["./src/theme/*"], - "@types/*": ["./src/util/*"], - "@themes/*": ["./src/themes/*"], - "@util/*": ["./src/util/*"] - } + "baseUrl": "." }, - "exclude": ["node_modules"] + "exclude": [ + "node_modules" + ] } From 0d18b72cf86d74287f4cfc61da5ecaacd82498cb Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Mon, 3 Jul 2023 23:52:11 -0600 Subject: [PATCH 061/104] vim: Further improve ~ handling Now works with Visual{line} mode, collapses selections like nvim, and doesn't fall off the end of the line. --- crates/vim/src/normal/case.rs | 96 +++++++++++++++------- crates/vim/src/test/neovim_connection.rs | 16 +++- crates/vim/test_data/test_change_case.json | 18 ++++ 3 files changed, 99 insertions(+), 31 deletions(-) create mode 100644 crates/vim/test_data/test_change_case.json diff --git a/crates/vim/src/normal/case.rs b/crates/vim/src/normal/case.rs index ba527af0bb0b994f571dad2cf5a5ed466a9e3b98..b3e101262d02a54f31f668dd665bcdad6a59875e 100644 --- a/crates/vim/src/normal/case.rs +++ b/crates/vim/src/normal/case.rs @@ -1,29 +1,51 @@ +use editor::scroll::autoscroll::Autoscroll; use gpui::ViewContext; -use language::Point; +use language::{Bias, Point}; use workspace::Workspace; -use crate::{motion::Motion, normal::ChangeCase, Vim}; +use crate::{normal::ChangeCase, state::Mode, Vim}; pub fn change_case(_: &mut Workspace, _: &ChangeCase, cx: &mut ViewContext) { Vim::update(cx, |vim, cx| { - let count = vim.pop_number_operator(cx); + let count = vim.pop_number_operator(cx).unwrap_or(1) as u32; vim.update_active_editor(cx, |editor, cx| { - editor.set_clip_at_line_ends(false, cx); - editor.transact(cx, |editor, cx| { - editor.change_selections(None, cx, |s| { - s.move_with(|map, selection| { - if selection.start == selection.end { - Motion::Right.expand_selection(map, selection, count, true); + let mut ranges = Vec::new(); + let mut cursor_positions = Vec::new(); + let snapshot = editor.buffer().read(cx).snapshot(cx); + for selection in editor.selections.all::(cx) { + match vim.state.mode { + Mode::Visual { line: true } => { + let start = Point::new(selection.start.row, 0); + let end = + Point::new(selection.end.row, snapshot.line_len(selection.end.row)); + ranges.push(start..end); + cursor_positions.push(start..start); + } + Mode::Visual { line: false } => { + ranges.push(selection.start..selection.end); + cursor_positions.push(selection.start..selection.start); + } + Mode::Insert | Mode::Normal => { + let start = selection.start; + let mut end = start; + for _ in 0..count { + end = snapshot.clip_point(end + Point::new(0, 1), Bias::Right); } - }) - }); - let selections = editor.selections.all::(cx); - for selection in selections.into_iter().rev() { + ranges.push(start..end); + + if end.column == snapshot.line_len(end.row) { + end = snapshot.clip_point(end - Point::new(0, 1), Bias::Left); + } + cursor_positions.push(end..end) + } + } + } + editor.transact(cx, |editor, cx| { + for range in ranges.into_iter().rev() { let snapshot = editor.buffer().read(cx).snapshot(cx); editor.buffer().update(cx, |buffer, cx| { - let range = selection.start..selection.end; let text = snapshot - .text_for_range(selection.start..selection.end) + .text_for_range(range.start..range.end) .flat_map(|s| s.chars()) .flat_map(|c| { if c.is_lowercase() { @@ -37,28 +59,46 @@ pub fn change_case(_: &mut Workspace, _: &ChangeCase, cx: &mut ViewContext Date: Tue, 4 Jul 2023 16:00:59 +0200 Subject: [PATCH 062/104] Fix click behaviour of vcs/project dropdowns --- crates/collab_ui/src/collab_titlebar_item.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index 8af3acf7beeef38d7c33d588a2d4749589d9c88e..3bc890f91ba571e8b120c37ff7fe61936343518a 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -237,9 +237,10 @@ impl CollabTitlebarItem { .into_any_named("title-project-name") }) .with_cursor_style(CursorStyle::PointingHand) - .on_click(MouseButton::Left, move |_, this, cx| { + .on_down(MouseButton::Left, move |_, this, cx| { this.toggle_project_menu(&Default::default(), cx) }) + .on_click(MouseButton::Left, move |_, _, _| {}) .contained() .with_style(project_style.container), ) @@ -267,12 +268,10 @@ impl CollabTitlebarItem { .into_any_named("title-project-branch") }) .with_cursor_style(CursorStyle::PointingHand) - .on_click( - MouseButton::Left, - move |_, this, cx| { - this.toggle_vcs_menu(&Default::default(), cx) - }, - ), + .on_down(MouseButton::Left, move |_, this, cx| { + this.toggle_vcs_menu(&Default::default(), cx) + }) + .on_click(MouseButton::Left, move |_, _, _| {}), ) .with_children(self.render_branches_popover_host(&theme.titlebar, cx)), ), From 48371ab8b2ba823278dc5fb0853673128e3a71c5 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Tue, 4 Jul 2023 16:30:17 +0200 Subject: [PATCH 063/104] Remove PickerEvent::Dismiss emission from picker header --- crates/collab_ui/src/branch_list.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/crates/collab_ui/src/branch_list.rs b/crates/collab_ui/src/branch_list.rs index e0f85aa65a3fe303c9ce0a79b82c83a779ea42bf..a1693fd6c46a6a14141768f40af519fb9ca5b773 100644 --- a/crates/collab_ui/src/branch_list.rs +++ b/crates/collab_ui/src/branch_list.rs @@ -255,9 +255,7 @@ impl PickerDelegate for BranchListDelegate { Some( MouseEventHandler::::new(0, cx, move |_, _| label) .on_click(MouseButton::Left, move |_, _, _| {}) - .on_down_out(MouseButton::Left, move |_, _, cx| { - cx.emit(PickerEvent::Dismiss) - }) + .on_down_out(MouseButton::Left, move |_, _, _| {}) .into_any(), ) } From 4c51ab8a255910cb30efb2cd819b4bfec13623e0 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Tue, 4 Jul 2023 20:58:33 +0300 Subject: [PATCH 064/104] Accept `null` as a valid action, to disable a keystroke co-authored-by: Mikayla Maki --- crates/gpui/src/app/window.rs | 8 +- crates/gpui/src/gpui.rs | 2 + crates/settings/src/keymap_file.rs | 47 +++++---- crates/zed/src/zed.rs | 161 +++++++++++++++++++++++++++++ 4 files changed, 197 insertions(+), 21 deletions(-) diff --git a/crates/gpui/src/app/window.rs b/crates/gpui/src/app/window.rs index 23fbb33fe142fc8c34eee86a7889fbeddd9bcc5a..743f99ee6217b068dc08ae5259b5642f901d1bf9 100644 --- a/crates/gpui/src/app/window.rs +++ b/crates/gpui/src/app/window.rs @@ -14,8 +14,8 @@ 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, WindowInvalidation, + Element, Entity, Handle, LayoutContext, MouseRegion, MouseRegionId, NoAction, SceneBuilder, + Subscription, View, ViewContext, ViewHandle, WindowInvalidation, }; use anyhow::{anyhow, bail, Result}; use collections::{HashMap, HashSet}; @@ -434,7 +434,11 @@ impl<'a> WindowContext<'a> { MatchResult::None => false, MatchResult::Pending => true, MatchResult::Matches(matches) => { + let no_action_id = (NoAction {}).id(); for (view_id, action) in matches { + if action.id() == no_action_id { + return false; + } if self.dispatch_action(Some(*view_id), action.as_ref()) { self.keystroke_matcher.clear_pending(); handled_by = Some(action.boxed_clone()); diff --git a/crates/gpui/src/gpui.rs b/crates/gpui/src/gpui.rs index 25d022d8ed8735e66d450b5be7b3d41cf62fcd51..3442934b3a9520ecca113433f420c63a15140489 100644 --- a/crates/gpui/src/gpui.rs +++ b/crates/gpui/src/gpui.rs @@ -31,3 +31,5 @@ pub use window::{Axis, SizeConstraint, Vector2FExt, WindowContext}; pub use anyhow; pub use serde_json; + +actions!(zed, [NoAction]); diff --git a/crates/settings/src/keymap_file.rs b/crates/settings/src/keymap_file.rs index d2e656ebe3cd1231f665a69e7284b1121c218776..93cb2ab3d74bd873f55c75d4b4415e7fbf782b51 100644 --- a/crates/settings/src/keymap_file.rs +++ b/crates/settings/src/keymap_file.rs @@ -1,7 +1,7 @@ use crate::{settings_store::parse_json_with_comments, SettingsAssets}; use anyhow::{anyhow, Context, Result}; use collections::BTreeMap; -use gpui::{keymap_matcher::Binding, AppContext}; +use gpui::{keymap_matcher::Binding, AppContext, NoAction}; use schemars::{ gen::{SchemaGenerator, SchemaSettings}, schema::{InstanceType, Schema, SchemaObject, SingleOrVec, SubschemaValidation}, @@ -11,18 +11,18 @@ use serde::Deserialize; use serde_json::Value; use util::{asset_str, ResultExt}; -#[derive(Deserialize, Default, Clone, JsonSchema)] +#[derive(Debug, Deserialize, Default, Clone, JsonSchema)] #[serde(transparent)] pub struct KeymapFile(Vec); -#[derive(Deserialize, Default, Clone, JsonSchema)] +#[derive(Debug, Deserialize, Default, Clone, JsonSchema)] pub struct KeymapBlock { #[serde(default)] context: Option, bindings: BTreeMap, } -#[derive(Deserialize, Default, Clone)] +#[derive(Debug, Deserialize, Default, Clone)] #[serde(transparent)] pub struct KeymapAction(Value); @@ -61,21 +61,22 @@ impl KeymapFile { // We want to deserialize the action data as a `RawValue` so that we can // deserialize the action itself dynamically directly from the JSON // string. But `RawValue` currently does not work inside of an untagged enum. - if let Value::Array(items) = action { - let Ok([name, data]): Result<[serde_json::Value; 2], _> = items.try_into() else { - return Some(Err(anyhow!("Expected array of length 2"))); - }; - let serde_json::Value::String(name) = name else { - return Some(Err(anyhow!("Expected first item in array to be a string."))) - }; - cx.deserialize_action( - &name, - Some(data), - ) - } else if let Value::String(name) = action { - cx.deserialize_action(&name, None) - } else { - return Some(Err(anyhow!("Expected two-element array, got {:?}", action))); + match action { + Value::Array(items) => { + let Ok([name, data]): Result<[serde_json::Value; 2], _> = items.try_into() else { + return Some(Err(anyhow!("Expected array of length 2"))); + }; + let serde_json::Value::String(name) = name else { + return Some(Err(anyhow!("Expected first item in array to be a string."))) + }; + cx.deserialize_action( + &name, + Some(data), + ) + }, + Value::String(name) => cx.deserialize_action(&name, None), + Value::Null => Ok(no_action()), + _ => return Some(Err(anyhow!("Expected two-element array, got {action:?}"))), } .with_context(|| { format!( @@ -115,6 +116,10 @@ impl KeymapFile { instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::Array))), ..Default::default() }), + Schema::Object(SchemaObject { + instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::Null))), + ..Default::default() + }), ]), ..Default::default() })), @@ -129,6 +134,10 @@ impl KeymapFile { } } +fn no_action() -> Box { + Box::new(NoAction {}) +} + #[cfg(test)] mod tests { use crate::KeymapFile; diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 874fea6500274ee572458d424e3f6c3a0e6c016b..0df16f4bab13fa56ed3211e462d8203be161c331 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -2074,6 +2074,167 @@ mod tests { line!(), ); + #[track_caller] + fn assert_key_bindings_for<'a>( + window_id: usize, + cx: &TestAppContext, + actions: Vec<(&'static str, &'a dyn Action)>, + line: u32, + ) { + for (key, action) in actions { + // assert that... + assert!( + cx.available_actions(window_id, 0) + .into_iter() + .any(|(_, bound_action, b)| { + // action names match... + bound_action.name() == action.name() + && bound_action.namespace() == action.namespace() + // and key strokes contain the given key + && b.iter() + .any(|binding| binding.keystrokes().iter().any(|k| k.key == key)) + }), + "On {} Failed to find {} with key binding {}", + line, + action.name(), + key + ); + } + } + } + + #[gpui::test] + async fn test_disabled_keymap_binding(cx: &mut gpui::TestAppContext) { + struct TestView; + + impl Entity for TestView { + type Event = (); + } + + impl View for TestView { + fn ui_name() -> &'static str { + "TestView" + } + + fn render(&mut self, _: &mut ViewContext) -> AnyElement { + Empty::new().into_any() + } + } + + let executor = cx.background(); + let fs = FakeFs::new(executor.clone()); + + actions!(test, [A, B]); + // From the Atom keymap + actions!(workspace, [ActivatePreviousPane]); + // From the JetBrains keymap + actions!(pane, [ActivatePrevItem]); + + fs.save( + "/settings.json".as_ref(), + &r#" + { + "base_keymap": "Atom" + } + "# + .into(), + Default::default(), + ) + .await + .unwrap(); + + fs.save( + "/keymap.json".as_ref(), + &r#" + [ + { + "bindings": { + "backspace": "test::A" + } + } + ] + "# + .into(), + Default::default(), + ) + .await + .unwrap(); + + cx.update(|cx| { + cx.set_global(SettingsStore::test(cx)); + theme::init(Assets, cx); + welcome::init(cx); + + cx.add_global_action(|_: &A, _cx| {}); + cx.add_global_action(|_: &B, _cx| {}); + cx.add_global_action(|_: &ActivatePreviousPane, _cx| {}); + cx.add_global_action(|_: &ActivatePrevItem, _cx| {}); + + let settings_rx = watch_config_file( + executor.clone(), + fs.clone(), + PathBuf::from("/settings.json"), + ); + let keymap_rx = + watch_config_file(executor.clone(), fs.clone(), PathBuf::from("/keymap.json")); + + handle_keymap_file_changes(keymap_rx, cx); + handle_settings_file_changes(settings_rx, cx); + }); + + cx.foreground().run_until_parked(); + + let (window_id, _view) = cx.add_window(|_| TestView); + + // Test loading the keymap base at all + assert_key_bindings_for( + window_id, + cx, + vec![("backspace", &A), ("k", &ActivatePreviousPane)], + line!(), + ); + + // Test disabling the key binding for the base keymap + fs.save( + "/keymap.json".as_ref(), + &r#" + [ + { + "bindings": { + "backspace": null + } + } + ] + "# + .into(), + Default::default(), + ) + .await + .unwrap(); + + cx.foreground().run_until_parked(); + + assert_key_bindings_for(window_id, cx, vec![("k", &ActivatePreviousPane)], line!()); + + // Test modifying the base, while retaining the users keymap + fs.save( + "/settings.json".as_ref(), + &r#" + { + "base_keymap": "JetBrains" + } + "# + .into(), + Default::default(), + ) + .await + .unwrap(); + + cx.foreground().run_until_parked(); + + assert_key_bindings_for(window_id, cx, vec![("[", &ActivatePrevItem)], line!()); + + #[track_caller] fn assert_key_bindings_for<'a>( window_id: usize, cx: &TestAppContext, From a7ce602bac0902e62c544b3cf0a9132160d9aef1 Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Tue, 4 Jul 2023 16:18:42 -0400 Subject: [PATCH 065/104] Update collaboration sounds, add sounds to screensharing --- assets/sounds/joined.wav | Bin 16142 -> 0 bytes assets/sounds/joined_call.wav | Bin 0 -> 28808 bytes assets/sounds/leave.wav | Bin 137188 -> 0 bytes assets/sounds/leave_call.wav | Bin 0 -> 30916 bytes assets/sounds/mute.wav | Bin 29314 -> 56088 bytes assets/sounds/start_screenshare.wav | Bin 0 -> 12188 bytes assets/sounds/stop_screenshare.wav | Bin 0 -> 14024 bytes assets/sounds/unmute.wav | Bin 133336 -> 48834 bytes crates/audio/src/audio.rs | 8 ++++++-- crates/call/src/room.rs | 5 +++++ 10 files changed, 11 insertions(+), 2 deletions(-) delete mode 100644 assets/sounds/joined.wav create mode 100644 assets/sounds/joined_call.wav delete mode 100644 assets/sounds/leave.wav create mode 100644 assets/sounds/leave_call.wav create mode 100644 assets/sounds/start_screenshare.wav create mode 100644 assets/sounds/stop_screenshare.wav diff --git a/assets/sounds/joined.wav b/assets/sounds/joined.wav deleted file mode 100644 index 70cd41d16f9b21dcb46a0f91e7f446a4157f8239..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16142 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 X{gU3qehEd1tFLp;JMvsaMG*cUnYqlI literal 0 HcmV?d00001 diff --git a/assets/sounds/leave.wav b/assets/sounds/leave.wav deleted file mode 100644 index 27dcea38f450b6f4ff48abf6cc4346258c5aa17d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 137188 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

-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�>;(#`b*dUN70#w)$sjs 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%0DKkn{W3HQMgB4vg~2rt8sP{I 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 literal 29314 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 Zw!dq+{npEOfBcho-u>arx85j~J_Zedc$EME diff --git a/assets/sounds/start_screenshare.wav b/assets/sounds/start_screenshare.wav new file mode 100644 index 0000000000000000000000000000000000000000..7b72a90af16a0c3b539d0400fd175c4152369083 GIT binary patch literal 12188 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 E0~PTRx&QzG literal 0 HcmV?d00001 diff --git a/assets/sounds/stop_screenshare.wav b/assets/sounds/stop_screenshare.wav new file mode 100644 index 0000000000000000000000000000000000000000..1fe13e21b4246ed0fdf9d3778955b02b64468e99 GIT binary patch literal 14024 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 H$sqp)Rh24{ literal 0 HcmV?d00001 diff --git a/assets/sounds/unmute.wav b/assets/sounds/unmute.wav index d87decead02aa91fbcccbd661631636b5ee0975b..f8c90f691670f01f90505bb26592410dc7733d62 100644 GIT binary patch literal 48834 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

*xdFeH?dx;nq&{_=fa#81(@Li;$R(vv&BJgoI&O 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 IF1cO*2aA8;;Q#;t diff --git a/crates/audio/src/audio.rs b/crates/audio/src/audio.rs index 0216bf47be16dd23457c732a8ab944cbd5de5d37..233b0f62aa5aa02d82e1524a2c7ea0fa96b836ce 100644 --- a/crates/audio/src/audio.rs +++ b/crates/audio/src/audio.rs @@ -15,15 +15,19 @@ pub enum Sound { Leave, Mute, Unmute, + StartScreenshare, + StopScreenshare, } impl Sound { fn file(&self) -> &'static str { match self { - Self::Joined => "joined", - Self::Leave => "leave", + Self::Joined => "joined_call", + Self::Leave => "leave_call", Self::Mute => "mute", Self::Unmute => "unmute", + Self::StartScreenshare => "start_screenshare", + Self::StopScreenshare => "stop_screenshare", } } } diff --git a/crates/call/src/room.rs b/crates/call/src/room.rs index eed73ba1b1d5f2151a0f93ff10f3e7ac562f17c2..87e6faf988d58290c8b0c659887e021cacd1abc2 100644 --- a/crates/call/src/room.rs +++ b/crates/call/src/room.rs @@ -1222,6 +1222,9 @@ impl Room { }; cx.notify(); } + + Audio::play_sound(Sound::StartScreenshare, cx); + Ok(()) } Err(error) => { @@ -1311,6 +1314,8 @@ impl Room { } => { live_kit.room.unpublish_track(track_publication); cx.notify(); + + Audio::play_sound(Sound::StopScreenshare, cx); Ok(()) } } From 25564ea0585120863ba80e8c58eacaa27fbf8c2a Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 5 Jul 2023 09:39:04 +0200 Subject: [PATCH 066/104] Introduce a `WindowContext::focus` method that implies the window id --- crates/context_menu/src/context_menu.rs | 3 +-- crates/gpui/src/app.rs | 9 +++------ crates/gpui/src/app/window.rs | 4 ++++ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/crates/context_menu/src/context_menu.rs b/crates/context_menu/src/context_menu.rs index 296f6bc04a35a72767b635f0047502d62a4556e5..f58afab361f4db153824ad9488fb295588dac425 100644 --- a/crates/context_menu/src/context_menu.rs +++ b/crates/context_menu/src/context_menu.rs @@ -244,8 +244,7 @@ impl ContextMenu { let show_count = self.show_count; cx.defer(move |this, cx| { if cx.handle().is_focused(cx) && this.show_count == show_count { - let window_id = cx.window_id(); - (**cx).focus(window_id, this.previously_focused_view_id.take()); + (**cx).focus(this.previously_focused_view_id.take()); } }); } else { diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index 20043a9093638c8f10c125dd39c9b3dea8855bed..fec2ca595b3ced76c877f80f3491c34fca29dd2a 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -2971,14 +2971,12 @@ impl<'a, 'b, V: View> ViewContext<'a, 'b, V> { } pub fn focus(&mut self, handle: &AnyViewHandle) { - self.window_context - .focus(handle.window_id, Some(handle.view_id)); + self.window_context.focus(Some(handle.view_id)); } pub fn focus_self(&mut self) { - let window_id = self.window_id; let view_id = self.view_id; - self.window_context.focus(window_id, Some(view_id)); + self.window_context.focus(Some(view_id)); } pub fn is_self_focused(&self) -> bool { @@ -2997,8 +2995,7 @@ impl<'a, 'b, V: View> ViewContext<'a, 'b, V> { } pub fn blur(&mut self) { - let window_id = self.window_id; - self.window_context.focus(window_id, None); + self.window_context.focus(None); } pub fn on_window_should_close(&mut self, mut callback: F) diff --git a/crates/gpui/src/app/window.rs b/crates/gpui/src/app/window.rs index 743f99ee6217b068dc08ae5259b5642f901d1bf9..4edfa5b2846fa697eca36d97fea7c39891144e29 100644 --- a/crates/gpui/src/app/window.rs +++ b/crates/gpui/src/app/window.rs @@ -1096,6 +1096,10 @@ impl<'a> WindowContext<'a> { self.window.focused_view_id } + pub fn focus(&mut self, view_id: Option) { + self.app_context.focus(self.window_id, view_id); + } + pub fn window_bounds(&self) -> WindowBounds { self.window.platform_window.bounds() } From a8602b2a0ce9d71593cddea0f8fdec3533aa1783 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 5 Jul 2023 09:39:56 +0200 Subject: [PATCH 067/104] Add `Modal::has_focus` and introduce a `ModalHandle` trait object --- crates/go_to_line/src/go_to_line.rs | 11 +++++++++++ crates/picker/src/picker.rs | 11 +++++++++++ crates/workspace/src/workspace.rs | 16 ++++++++++++++++ 3 files changed, 38 insertions(+) diff --git a/crates/go_to_line/src/go_to_line.rs b/crates/go_to_line/src/go_to_line.rs index 0b41ee6dca3630450668a7eac69aeea2e99d3400..769f2eda55b4a165e138ee094adc4a581963a641 100644 --- a/crates/go_to_line/src/go_to_line.rs +++ b/crates/go_to_line/src/go_to_line.rs @@ -24,6 +24,7 @@ pub struct GoToLine { prev_scroll_position: Option, cursor_point: Point, max_point: Point, + has_focus: bool, } pub enum Event { @@ -57,6 +58,7 @@ impl GoToLine { prev_scroll_position: scroll_position, cursor_point, max_point, + has_focus: false, } } @@ -178,11 +180,20 @@ impl View for GoToLine { } fn focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext) { + self.has_focus = true; cx.focus(&self.line_editor); } + + fn focus_out(&mut self, _: AnyViewHandle, _: &mut ViewContext) { + self.has_focus = false; + } } impl Modal for GoToLine { + fn has_focus(&self) -> bool { + self.has_focus + } + fn dismiss_on_event(event: &Self::Event) -> bool { matches!(event, Event::Dismissed) } diff --git a/crates/picker/src/picker.rs b/crates/picker/src/picker.rs index 33d6e842415f9f4cba317f64ab9ff58b926608d8..ac0f3b5a190081e8ee9b045b7269a72675db4a48 100644 --- a/crates/picker/src/picker.rs +++ b/crates/picker/src/picker.rs @@ -25,6 +25,7 @@ pub struct Picker { theme: Arc theme::Picker>>>, confirmed: bool, pending_update_matches: Task>, + has_focus: bool, } pub trait PickerDelegate: Sized + 'static { @@ -140,13 +141,22 @@ impl View for Picker { } fn focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext) { + self.has_focus = true; if cx.is_self_focused() { cx.focus(&self.query_editor); } } + + fn focus_out(&mut self, _: AnyViewHandle, _: &mut ViewContext) { + self.has_focus = false; + } } impl Modal for Picker { + fn has_focus(&self) -> bool { + self.has_focus + } + fn dismiss_on_event(event: &Self::Event) -> bool { matches!(event, PickerEvent::Dismiss) } @@ -191,6 +201,7 @@ impl Picker { theme, confirmed: false, pending_update_matches: Task::ready(None), + has_focus: false, }; this.update_matches(String::new(), cx); this diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 066ea5f8a6a339f7b499bc35f7213fefe690eb8f..0a9b1f6c83493b8ccf0bb317dbb4937ea80c45a3 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -97,9 +97,25 @@ lazy_static! { } pub trait Modal: View { + fn has_focus(&self) -> bool; fn dismiss_on_event(event: &Self::Event) -> bool; } +trait ModalHandle { + fn as_any(&self) -> &AnyViewHandle; + fn has_focus(&self, cx: &WindowContext) -> bool; +} + +impl ModalHandle for ViewHandle { + fn as_any(&self) -> &AnyViewHandle { + self + } + + fn has_focus(&self, cx: &WindowContext) -> bool { + self.read(cx).has_focus() + } +} + #[derive(Clone, PartialEq)] pub struct RemoveWorktreeFromProject(pub WorktreeId); From 03a00df8b1f7addf1dacde7cdb3d63739561e8f8 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 5 Jul 2023 09:40:26 +0200 Subject: [PATCH 068/104] Restore focus to previously focused view when dismissing a modal --- crates/workspace/src/workspace.rs | 36 +++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 0a9b1f6c83493b8ccf0bb317dbb4937ea80c45a3..60aefe42134961ef31972dc2c75d19d2815b9514 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -482,7 +482,7 @@ pub enum Event { pub struct Workspace { weak_self: WeakViewHandle, remote_entity_subscription: Option, - modal: Option, + modal: Option, zoomed: Option, zoomed_position: Option, center: PaneGroup, @@ -511,6 +511,11 @@ pub struct Workspace { pane_history_timestamp: Arc, } +struct ActiveModal { + view: Box, + previously_focused_view_id: Option, +} + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub struct ViewId { pub creator: PeerId, @@ -1498,8 +1503,10 @@ impl Workspace { cx.notify(); // Whatever modal was visible is getting clobbered. If its the same type as V, then return // it. Otherwise, create a new modal and set it as active. - let already_open_modal = self.modal.take().and_then(|modal| modal.downcast::()); - if let Some(already_open_modal) = already_open_modal { + if let Some(already_open_modal) = self + .dismiss_modal(cx) + .and_then(|modal| modal.downcast::()) + { cx.focus_self(); Some(already_open_modal) } else { @@ -1510,8 +1517,12 @@ impl Workspace { } }) .detach(); + let previously_focused_view_id = cx.focused_view_id(); cx.focus(&modal); - self.modal = Some(modal.into_any()); + self.modal = Some(ActiveModal { + view: Box::new(modal), + previously_focused_view_id, + }); None } } @@ -1519,13 +1530,20 @@ impl Workspace { pub fn modal(&self) -> Option> { self.modal .as_ref() - .and_then(|modal| modal.clone().downcast::()) + .and_then(|modal| modal.view.as_any().clone().downcast::()) } - pub fn dismiss_modal(&mut self, cx: &mut ViewContext) { - if self.modal.take().is_some() { - cx.focus(&self.active_pane); + pub fn dismiss_modal(&mut self, cx: &mut ViewContext) -> Option { + if let Some(modal) = self.modal.take() { + if let Some(previously_focused_view_id) = modal.previously_focused_view_id { + if modal.view.has_focus(cx) { + cx.window_context().focus(Some(previously_focused_view_id)); + } + } cx.notify(); + Some(modal.view.as_any().clone()) + } else { + None } } @@ -3512,7 +3530,7 @@ impl View for Workspace { ) })) .with_children(self.modal.as_ref().map(|modal| { - ChildView::new(modal, cx) + ChildView::new(modal.view.as_any(), cx) .contained() .with_style(theme.workspace.modal) .aligned() From d5f0df94f7a923da5259d8799851037862fd721c Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 5 Jul 2023 11:41:24 +0200 Subject: [PATCH 069/104] Support `assistant: quote selection` on multibuffers --- crates/ai/src/assistant.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ai/src/assistant.rs b/crates/ai/src/assistant.rs index 9ca54e661a74d935356bf52378613e9ffb1dcb0e..2b4f733c8053cd9ba0095f86bc02a4cfeb4bab03 100644 --- a/crates/ai/src/assistant.rs +++ b/crates/ai/src/assistant.rs @@ -1911,7 +1911,7 @@ impl ConversationEditor { let Some(panel) = workspace.panel::(cx) else { return; }; - let Some(editor) = workspace.active_item(cx).and_then(|item| item.downcast::()) else { + let Some(editor) = workspace.active_item(cx).and_then(|item| item.act_as::(cx)) else { return; }; From 64b77bfa8d194cfddfc8e8b98db0abf6b711e73f Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Wed, 5 Jul 2023 14:04:16 +0200 Subject: [PATCH 070/104] Remove stacks from branch list header Co-authored-by: Antonio --- crates/collab_ui/src/branch_list.rs | 29 +++++------------------------ 1 file changed, 5 insertions(+), 24 deletions(-) diff --git a/crates/collab_ui/src/branch_list.rs b/crates/collab_ui/src/branch_list.rs index a1693fd6c46a6a14141768f40af519fb9ca5b773..25999bf995ed4d075eb71c805385751ae2819747 100644 --- a/crates/collab_ui/src/branch_list.rs +++ b/crates/collab_ui/src/branch_list.rs @@ -217,25 +217,13 @@ impl PickerDelegate for BranchListDelegate { let theme = &theme::current(cx); let style = theme.picker.header.clone(); let label = if self.last_query.is_empty() { - Stack::new() - .with_child( - Flex::row() - .with_child(Label::new("Recent branches", style.label.clone())) - .contained() - .with_style(style.container) - .into_any(), - ) + Flex::row() + .with_child(Label::new("Recent branches", style.label.clone())) .contained() .with_style(style.container) - .into_any() } else { - Stack::new() - .with_child( - Flex::row() - .with_child(Label::new("Branches", style.label.clone()).aligned().left()) - .contained() - .with_style(style.container), - ) + Flex::row() + .with_child(Label::new("Branches", style.label.clone()).aligned().left()) .with_children(self.matches.is_empty().not().then(|| { let suffix = if self.matches.len() == 1 { "" } else { "es" }; Flex::row() @@ -249,14 +237,7 @@ impl PickerDelegate for BranchListDelegate { })) .contained() .with_style(style.container) - .constrained() - .into_any() }; - Some( - MouseEventHandler::::new(0, cx, move |_, _| label) - .on_click(MouseButton::Left, move |_, _, _| {}) - .on_down_out(MouseButton::Left, move |_, _, _| {}) - .into_any(), - ) + Some(label.into_any()) } } From 8b3b1a607458a41fb8c2a9a9bb4d671da81ff97e Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Wed, 5 Jul 2023 14:08:21 +0200 Subject: [PATCH 071/104] fixup! Remove stacks from branch list header --- crates/collab_ui/src/branch_list.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/crates/collab_ui/src/branch_list.rs b/crates/collab_ui/src/branch_list.rs index 25999bf995ed4d075eb71c805385751ae2819747..229d1fdc292b48fe94521272b30f4ceefbe80e45 100644 --- a/crates/collab_ui/src/branch_list.rs +++ b/crates/collab_ui/src/branch_list.rs @@ -1,8 +1,6 @@ use anyhow::{anyhow, bail}; use fuzzy::{StringMatch, StringMatchCandidate}; -use gpui::{ - elements::*, platform::MouseButton, AppContext, MouseState, Task, ViewContext, ViewHandle, -}; +use gpui::{elements::*, AppContext, MouseState, Task, ViewContext, ViewHandle}; use picker::{Picker, PickerDelegate, PickerEvent}; use std::{ops::Not, sync::Arc}; use util::ResultExt; From 6ba1c3071a53e566e9c0fdfd75326589e0fc6cb1 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Wed, 5 Jul 2023 15:23:56 +0300 Subject: [PATCH 072/104] Simplify inlay map data --- crates/editor/src/display_map/inlay_map.rs | 28 +++++++++++++--------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/crates/editor/src/display_map/inlay_map.rs b/crates/editor/src/display_map/inlay_map.rs index 99b22dcbb6405bae83327ab64cd4a527c086fe61..90e5c8a9cecdcacf67251fa79b4b558f60f2d6a7 100644 --- a/crates/editor/src/display_map/inlay_map.rs +++ b/crates/editor/src/display_map/inlay_map.rs @@ -2,7 +2,7 @@ use crate::{ multi_buffer::{MultiBufferChunks, MultiBufferRows}, Anchor, InlayId, MultiBufferSnapshot, ToOffset, }; -use collections::{BTreeMap, BTreeSet, HashMap}; +use collections::{BTreeMap, BTreeSet}; use gpui::fonts::HighlightStyle; use language::{Chunk, Edit, Point, Rope, TextSummary}; use std::{ @@ -19,7 +19,6 @@ use super::TextHighlights; pub struct InlayMap { snapshot: InlaySnapshot, - inlays_by_id: HashMap, inlays: Vec, } @@ -381,7 +380,6 @@ impl InlayMap { ( Self { snapshot: snapshot.clone(), - inlays_by_id: HashMap::default(), inlays: Vec::new(), }, snapshot, @@ -531,13 +529,14 @@ impl InlayMap { let snapshot = &mut self.snapshot; let mut edits = BTreeSet::new(); - self.inlays.retain(|inlay| !to_remove.contains(&inlay.id)); - for inlay_id in to_remove { - if let Some(inlay) = self.inlays_by_id.remove(&inlay_id) { + self.inlays.retain(|inlay| { + let retain = !to_remove.contains(&inlay.id); + if !retain { let offset = inlay.position.to_offset(&snapshot.buffer); edits.insert(offset); } - } + retain + }); for (existing_id, properties) in to_insert { let inlay = Inlay { @@ -551,7 +550,6 @@ impl InlayMap { continue; } - self.inlays_by_id.insert(inlay.id, inlay.clone()); match self .inlays .binary_search_by(|probe| probe.position.cmp(&inlay.position, &snapshot.buffer)) @@ -627,7 +625,13 @@ impl InlayMap { }, )); } else { - to_remove.push(*self.inlays_by_id.keys().choose(rng).unwrap()); + to_remove.push( + self.inlays + .iter() + .choose(rng) + .map(|inlay| inlay.id) + .unwrap(), + ); } } log::info!("removing inlays: {:?}", to_remove); @@ -1478,8 +1482,10 @@ mod tests { ); // The inlays can be manually removed. - let (inlay_snapshot, _) = inlay_map - .splice::(inlay_map.inlays_by_id.keys().copied().collect(), Vec::new()); + let (inlay_snapshot, _) = inlay_map.splice::( + inlay_map.inlays.iter().map(|inlay| inlay.id).collect(), + Vec::new(), + ); assert_eq!(inlay_snapshot.text(), "abxJKLyDzefghi"); } From d7f6b5e1a07f645a22160df2f39f424d02d69998 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Wed, 5 Jul 2023 15:58:31 +0300 Subject: [PATCH 073/104] Remove InlayProperties --- crates/editor/src/display_map.rs | 7 +- crates/editor/src/display_map/inlay_map.rs | 167 ++++++++++----------- crates/editor/src/editor.rs | 41 +++-- crates/editor/src/inlay_hint_cache.rs | 28 ++-- 4 files changed, 117 insertions(+), 126 deletions(-) diff --git a/crates/editor/src/display_map.rs b/crates/editor/src/display_map.rs index 714dc74509cbf4ed744a9a9217f18bd52c1c85cb..6e04833f17ba1c4c0b706265540497cf2bc99824 100644 --- a/crates/editor/src/display_map.rs +++ b/crates/editor/src/display_map.rs @@ -20,7 +20,6 @@ use language::{ use std::{any::TypeId, fmt::Debug, num::NonZeroU32, ops::Range, sync::Arc}; use sum_tree::{Bias, TreeMap}; use tab_map::TabMap; -use text::Rope; use wrap_map::WrapMap; pub use block_map::{ @@ -28,7 +27,7 @@ pub use block_map::{ BlockDisposition, BlockId, BlockProperties, BlockStyle, RenderBlock, TransformBlock, }; -pub use self::inlay_map::{Inlay, InlayProperties}; +pub use self::inlay_map::Inlay; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum FoldStatus { @@ -246,10 +245,10 @@ impl DisplayMap { self.inlay_map.current_inlays() } - pub fn splice_inlays>( + pub fn splice_inlays( &mut self, to_remove: Vec, - to_insert: Vec<(InlayId, InlayProperties)>, + to_insert: Vec, cx: &mut ModelContext, ) { if to_remove.is_empty() && to_insert.is_empty() { diff --git a/crates/editor/src/display_map/inlay_map.rs b/crates/editor/src/display_map/inlay_map.rs index 90e5c8a9cecdcacf67251fa79b4b558f60f2d6a7..6a59cecae8e2ecb172cd3e72b447b29cb33d42c4 100644 --- a/crates/editor/src/display_map/inlay_map.rs +++ b/crates/editor/src/display_map/inlay_map.rs @@ -4,7 +4,7 @@ use crate::{ }; use collections::{BTreeMap, BTreeSet}; use gpui::fonts::HighlightStyle; -use language::{Chunk, Edit, Point, Rope, TextSummary}; +use language::{Chunk, Edit, Point, TextSummary}; use std::{ any::TypeId, cmp, @@ -13,7 +13,7 @@ use std::{ vec, }; use sum_tree::{Bias, Cursor, SumTree}; -use text::Patch; +use text::{Patch, Rope}; use super::TextHighlights; @@ -42,14 +42,8 @@ pub struct Inlay { pub text: text::Rope, } -#[derive(Debug, Clone)] -pub struct InlayProperties { - pub position: Anchor, - pub text: T, -} - -impl InlayProperties { - pub fn new(position: Anchor, hint: &project::InlayHint) -> Self { +impl Inlay { + pub fn hint(id: usize, position: Anchor, hint: &project::InlayHint) -> Self { let mut text = hint.text(); if hint.padding_right && !text.ends_with(' ') { text.push(' '); @@ -57,7 +51,19 @@ impl InlayProperties { if hint.padding_left && !text.starts_with(' ') { text.insert(0, ' '); } - Self { position, text } + Self { + id: InlayId::Hint(id), + position, + text: text.into(), + } + } + + pub fn suggestion>(id: usize, position: Anchor, text: T) -> Self { + Self { + id: InlayId::Suggestion(id), + position, + text: text.into(), + } } } @@ -521,10 +527,10 @@ impl InlayMap { } } - pub fn splice>( + pub fn splice( &mut self, to_remove: Vec, - to_insert: Vec<(InlayId, InlayProperties)>, + to_insert: Vec, ) -> (InlaySnapshot, Vec) { let snapshot = &mut self.snapshot; let mut edits = BTreeSet::new(); @@ -538,28 +544,23 @@ impl InlayMap { retain }); - for (existing_id, properties) in to_insert { - let inlay = Inlay { - id: existing_id, - position: properties.position, - text: properties.text.into(), - }; - + for inlay_to_insert in to_insert { // Avoid inserting empty inlays. - if inlay.text.is_empty() { + if inlay_to_insert.text.is_empty() { continue; } - match self - .inlays - .binary_search_by(|probe| probe.position.cmp(&inlay.position, &snapshot.buffer)) - { + let offset = inlay_to_insert.position.to_offset(&snapshot.buffer); + match self.inlays.binary_search_by(|probe| { + probe + .position + .cmp(&inlay_to_insert.position, &snapshot.buffer) + }) { Ok(ix) | Err(ix) => { - self.inlays.insert(ix, inlay.clone()); + self.inlays.insert(ix, inlay_to_insert); } } - let offset = inlay.position.to_offset(&snapshot.buffer); edits.insert(offset); } @@ -617,13 +618,11 @@ impl InlayMap { } else { InlayId::Suggestion(post_inc(next_inlay_id)) }; - to_insert.push(( - inlay_id, - InlayProperties { - position: snapshot.buffer.anchor_at(position, bias), - text, - }, - )); + to_insert.push(Inlay { + id: inlay_id, + position: snapshot.buffer.anchor_at(position, bias), + text: text.into(), + }); } else { to_remove.push( self.inlays @@ -1123,7 +1122,8 @@ mod tests { #[test] fn test_inlay_properties_label_padding() { assert_eq!( - InlayProperties::new( + Inlay::hint( + 0, Anchor::min(), &InlayHint { label: InlayHintLabel::String("a".to_string()), @@ -1135,13 +1135,15 @@ mod tests { kind: None, }, ) - .text, + .text + .to_string(), "a", "Should not pad label if not requested" ); assert_eq!( - InlayProperties::new( + Inlay::hint( + 0, Anchor::min(), &InlayHint { label: InlayHintLabel::String("a".to_string()), @@ -1153,13 +1155,15 @@ mod tests { kind: None, }, ) - .text, + .text + .to_string(), " a ", "Should pad label for every side requested" ); assert_eq!( - InlayProperties::new( + Inlay::hint( + 0, Anchor::min(), &InlayHint { label: InlayHintLabel::String(" a ".to_string()), @@ -1171,13 +1175,15 @@ mod tests { kind: None, }, ) - .text, + .text + .to_string(), " a ", "Should not change already padded label" ); assert_eq!( - InlayProperties::new( + Inlay::hint( + 0, Anchor::min(), &InlayHint { label: InlayHintLabel::String(" a ".to_string()), @@ -1189,7 +1195,8 @@ mod tests { kind: None, }, ) - .text, + .text + .to_string(), " a ", "Should not change already padded label" ); @@ -1205,13 +1212,11 @@ mod tests { let (inlay_snapshot, _) = inlay_map.splice( Vec::new(), - vec![( - InlayId::Hint(post_inc(&mut next_inlay_id)), - InlayProperties { - position: buffer.read(cx).snapshot(cx).anchor_after(3), - text: "|123|", - }, - )], + vec![Inlay { + id: InlayId::Hint(post_inc(&mut next_inlay_id)), + position: buffer.read(cx).snapshot(cx).anchor_after(3), + text: "|123|".into(), + }], ); assert_eq!(inlay_snapshot.text(), "abc|123|defghi"); assert_eq!( @@ -1284,20 +1289,16 @@ mod tests { let (inlay_snapshot, _) = inlay_map.splice( Vec::new(), vec![ - ( - InlayId::Hint(post_inc(&mut next_inlay_id)), - InlayProperties { - position: buffer.read(cx).snapshot(cx).anchor_before(3), - text: "|123|", - }, - ), - ( - InlayId::Suggestion(post_inc(&mut next_inlay_id)), - InlayProperties { - position: buffer.read(cx).snapshot(cx).anchor_after(3), - text: "|456|", - }, - ), + Inlay { + id: InlayId::Hint(post_inc(&mut next_inlay_id)), + position: buffer.read(cx).snapshot(cx).anchor_before(3), + text: "|123|".into(), + }, + Inlay { + id: InlayId::Suggestion(post_inc(&mut next_inlay_id)), + position: buffer.read(cx).snapshot(cx).anchor_after(3), + text: "|456|".into(), + }, ], ); assert_eq!(inlay_snapshot.text(), "abx|123||456|yDzefghi"); @@ -1482,7 +1483,7 @@ mod tests { ); // The inlays can be manually removed. - let (inlay_snapshot, _) = inlay_map.splice::( + let (inlay_snapshot, _) = inlay_map.splice( inlay_map.inlays.iter().map(|inlay| inlay.id).collect(), Vec::new(), ); @@ -1499,27 +1500,21 @@ mod tests { let (inlay_snapshot, _) = inlay_map.splice( Vec::new(), vec![ - ( - InlayId::Hint(post_inc(&mut next_inlay_id)), - InlayProperties { - position: buffer.read(cx).snapshot(cx).anchor_before(0), - text: "|123|\n", - }, - ), - ( - InlayId::Hint(post_inc(&mut next_inlay_id)), - InlayProperties { - position: buffer.read(cx).snapshot(cx).anchor_before(4), - text: "|456|", - }, - ), - ( - InlayId::Suggestion(post_inc(&mut next_inlay_id)), - InlayProperties { - position: buffer.read(cx).snapshot(cx).anchor_before(7), - text: "\n|567|\n", - }, - ), + Inlay { + id: InlayId::Hint(post_inc(&mut next_inlay_id)), + position: buffer.read(cx).snapshot(cx).anchor_before(0), + text: "|123|\n".into(), + }, + Inlay { + id: InlayId::Hint(post_inc(&mut next_inlay_id)), + position: buffer.read(cx).snapshot(cx).anchor_before(4), + text: "|456|".into(), + }, + Inlay { + id: InlayId::Suggestion(post_inc(&mut next_inlay_id)), + position: buffer.read(cx).snapshot(cx).anchor_before(7), + text: "\n|567|\n".into(), + }, ], ); assert_eq!(inlay_snapshot.text(), "|123|\nabc\n|456|def\n|567|\n\nghi"); @@ -1609,7 +1604,7 @@ mod tests { (offset, inlay.clone()) }) .collect::>(); - let mut expected_text = Rope::from(buffer_snapshot.text().as_str()); + let mut expected_text = Rope::from(buffer_snapshot.text()); for (offset, inlay) in inlays.into_iter().rev() { expected_text.replace(offset..offset, &inlay.text.to_string()); } diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 992ecd74597ee1d006f92711ab63182a648f64fb..e979bd9c1edef14fdc73500c760d481c2981d403 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -190,6 +190,15 @@ pub enum InlayId { Hint(usize), } +impl InlayId { + fn id(&self) -> usize { + match self { + Self::Suggestion(id) => *id, + Self::Hint(id) => *id, + } + } +} + actions!( editor, [ @@ -2708,17 +2717,11 @@ impl Editor { fn splice_inlay_hints( &self, to_remove: Vec, - to_insert: Vec<(Anchor, InlayId, project::InlayHint)>, + to_insert: Vec, cx: &mut ViewContext, ) { - let buffer = self.buffer.read(cx).read(cx); - let new_inlays = to_insert - .into_iter() - .map(|(position, id, hint)| (id, InlayProperties::new(position, &hint))) - .collect(); - drop(buffer); self.display_map.update(cx, |display_map, cx| { - display_map.splice_inlays(to_remove, new_inlays, cx); + display_map.splice_inlays(to_remove, to_insert, cx); }); } @@ -3403,7 +3406,7 @@ impl Editor { } self.display_map.update(cx, |map, cx| { - map.splice_inlays::<&str>(vec![suggestion.id], Vec::new(), cx) + map.splice_inlays(vec![suggestion.id], Vec::new(), cx) }); cx.notify(); true @@ -3436,7 +3439,7 @@ impl Editor { fn take_active_copilot_suggestion(&mut self, cx: &mut ViewContext) -> Option { let suggestion = self.copilot_state.suggestion.take()?; self.display_map.update(cx, |map, cx| { - map.splice_inlays::<&str>(vec![suggestion.id], Default::default(), cx); + map.splice_inlays(vec![suggestion.id], Default::default(), cx); }); let buffer = self.buffer.read(cx).read(cx); @@ -3467,21 +3470,11 @@ impl Editor { to_remove.push(suggestion.id); } - let suggestion_inlay_id = InlayId::Suggestion(post_inc(&mut self.next_inlay_id)); - let to_insert = vec![( - suggestion_inlay_id, - InlayProperties { - position: cursor, - text: text.clone(), - }, - )]; + let suggestion_inlay = + Inlay::suggestion(post_inc(&mut self.next_inlay_id), cursor, text); + self.copilot_state.suggestion = Some(suggestion_inlay.clone()); self.display_map.update(cx, move |map, cx| { - map.splice_inlays(to_remove, to_insert, cx) - }); - self.copilot_state.suggestion = Some(Inlay { - id: suggestion_inlay_id, - position: cursor, - text, + map.splice_inlays(to_remove, vec![suggestion_inlay], cx) }); cx.notify(); } else { diff --git a/crates/editor/src/inlay_hint_cache.rs b/crates/editor/src/inlay_hint_cache.rs index 3f9f8e4288bc843552b22f87c9c516a695f243e8..a6ea3962d28f27ff45cab2efc5f85a4a3a861d68 100644 --- a/crates/editor/src/inlay_hint_cache.rs +++ b/crates/editor/src/inlay_hint_cache.rs @@ -45,7 +45,7 @@ pub enum InvalidationStrategy { #[derive(Debug, Default)] pub struct InlaySplice { pub to_remove: Vec, - pub to_insert: Vec<(Anchor, InlayId, InlayHint)>, + pub to_insert: Vec, } struct UpdateTask { @@ -285,13 +285,13 @@ impl InlayHintCache { if !old_kinds.contains(&cached_hint.kind) && new_kinds.contains(&cached_hint.kind) { - to_insert.push(( + to_insert.push(Inlay::hint( + cached_hint_id.id(), multi_buffer_snapshot.anchor_in_excerpt( *excerpt_id, cached_hint.position, ), - *cached_hint_id, - cached_hint.clone(), + &cached_hint, )); } excerpt_cache.next(); @@ -307,11 +307,11 @@ impl InlayHintCache { for (cached_hint_id, maybe_missed_cached_hint) in excerpt_cache { let cached_hint_kind = maybe_missed_cached_hint.kind; if !old_kinds.contains(&cached_hint_kind) && new_kinds.contains(&cached_hint_kind) { - to_insert.push(( + to_insert.push(Inlay::hint( + cached_hint_id.id(), multi_buffer_snapshot .anchor_in_excerpt(*excerpt_id, maybe_missed_cached_hint.position), - *cached_hint_id, - maybe_missed_cached_hint.clone(), + &maybe_missed_cached_hint, )); } } @@ -657,18 +657,22 @@ async fn fetch_and_update_hints( for new_hint in new_update.add_to_cache { let new_hint_position = multi_buffer_snapshot .anchor_in_excerpt(query.excerpt_id, new_hint.position); - let new_inlay_id = InlayId::Hint(post_inc(&mut editor.next_inlay_id)); + let new_inlay_id = post_inc(&mut editor.next_inlay_id); if editor .inlay_hint_cache .allowed_hint_kinds .contains(&new_hint.kind) { - splice - .to_insert - .push((new_hint_position, new_inlay_id, new_hint.clone())); + splice.to_insert.push(Inlay::hint( + new_inlay_id, + new_hint_position, + &new_hint, + )); } - cached_excerpt_hints.hints.push((new_inlay_id, new_hint)); + cached_excerpt_hints + .hints + .push((InlayId::Hint(new_inlay_id), new_hint)); } cached_excerpt_hints From cc88bff1ff6d378429a61fa34bcd36caed05214e Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Wed, 5 Jul 2023 15:25:33 +0200 Subject: [PATCH 074/104] Fix click-through behaviour of git panel Co-authored-by: Antonio --- crates/gpui/src/app/window.rs | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/crates/gpui/src/app/window.rs b/crates/gpui/src/app/window.rs index 23fbb33fe142fc8c34eee86a7889fbeddd9bcc5a..a04aaf8a28041a120bf469df81fedb35cfe87f53 100644 --- a/crates/gpui/src/app/window.rs +++ b/crates/gpui/src/app/window.rs @@ -482,20 +482,19 @@ impl<'a> WindowContext<'a> { // If there is already clicked_button stored, don't replace it. if self.window.clicked_button.is_none() { - self.window.clicked_region_ids = self - .window - .mouse_regions - .iter() - .filter_map(|(region, _)| { - if region.bounds.contains_point(e.position) { - Some(region.id()) - } else { - None - } - }) - .collect(); + let window = &mut *self.window; + window.clicked_region_ids.clear(); + + let mut highest_z_index = 0; + for (region, z_index) in window.mouse_regions.iter() { + if region.bounds.contains_point(e.position) && *z_index >= highest_z_index { + highest_z_index = *z_index; + window.clicked_region_ids.clear(); + window.clicked_region_ids.insert(region.id()); + } + } - self.window.clicked_button = Some(e.button); + window.clicked_button = Some(e.button); } mouse_events.push(MouseEvent::Down(MouseDown { From 85add260f6fbde3d412dc8afa6ce60e65ac77413 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Wed, 5 Jul 2023 16:48:52 +0200 Subject: [PATCH 075/104] Track regions instead of clicks. Get rid of superfluous params in RenderParams related to hover & click state. Co-authored-by: Antonio --- crates/gpui/src/app.rs | 14 ++++++---- crates/gpui/src/app/window.rs | 49 ++++++++++++++++++----------------- 2 files changed, 34 insertions(+), 29 deletions(-) diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index 20043a9093638c8f10c125dd39c9b3dea8855bed..dfd5fe7bb28bacaab5637ea0fef245c1e237c58e 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -3304,11 +3304,15 @@ impl<'a, 'b, V: View> ViewContext<'a, 'b, V> { let region_id = MouseRegionId::new::(self.view_id, region_id); MouseState { hovered: self.window.hovered_region_ids.contains(®ion_id), - clicked: self - .window - .clicked_region_ids - .get(®ion_id) - .and_then(|_| self.window.clicked_button), + clicked: if let Some((clicked_region_id, button)) = self.window.clicked_region { + if region_id == clicked_region_id { + Some(button) + } else { + None + } + } else { + None + }, accessed_hovered: false, accessed_clicked: false, } diff --git a/crates/gpui/src/app/window.rs b/crates/gpui/src/app/window.rs index a04aaf8a28041a120bf469df81fedb35cfe87f53..5a77017a1192d4f1386b92f6e77c010a6bb164e4 100644 --- a/crates/gpui/src/app/window.rs +++ b/crates/gpui/src/app/window.rs @@ -53,7 +53,7 @@ pub struct Window { last_mouse_moved_event: Option, pub(crate) hovered_region_ids: HashSet, pub(crate) clicked_region_ids: HashSet, - pub(crate) clicked_button: Option, + pub(crate) clicked_region: Option<(MouseRegionId, MouseButton)>, mouse_position: Vector2F, text_layout_cache: TextLayoutCache, } @@ -86,7 +86,7 @@ impl Window { last_mouse_moved_event: None, hovered_region_ids: Default::default(), clicked_region_ids: Default::default(), - clicked_button: None, + clicked_region: None, mouse_position: vec2f(0., 0.), titlebar_height, appearance, @@ -480,21 +480,32 @@ impl<'a> WindowContext<'a> { // specific ancestor element that contained both [positions]' // So we need to store the overlapping regions on mouse down. - // If there is already clicked_button stored, don't replace it. - if self.window.clicked_button.is_none() { - let window = &mut *self.window; - window.clicked_region_ids.clear(); + // If there is already region being clicked, don't replace it. + if self.window.clicked_region.is_none() { + self.window.clicked_region_ids = self + .window + .mouse_regions + .iter() + .filter_map(|(region, _)| { + if region.bounds.contains_point(e.position) { + Some(region.id()) + } else { + None + } + }) + .collect(); let mut highest_z_index = 0; - for (region, z_index) in window.mouse_regions.iter() { + let mut clicked_region_id = None; + for (region, z_index) in self.window.mouse_regions.iter() { if region.bounds.contains_point(e.position) && *z_index >= highest_z_index { highest_z_index = *z_index; - window.clicked_region_ids.clear(); - window.clicked_region_ids.insert(region.id()); + clicked_region_id = Some(region.id()); } } - window.clicked_button = Some(e.button); + self.window.clicked_region = + clicked_region_id.map(|region_id| (region_id, e.button)); } mouse_events.push(MouseEvent::Down(MouseDown { @@ -559,7 +570,7 @@ impl<'a> WindowContext<'a> { prev_mouse_position: self.window.mouse_position, platform_event: e.clone(), })); - } else if let Some(clicked_button) = self.window.clicked_button { + } else if let Some((_, clicked_button)) = self.window.clicked_region { // Mouse up event happened outside the current window. Simulate mouse up button event let button_event = e.to_button_event(clicked_button); mouse_events.push(MouseEvent::Up(MouseUp { @@ -682,8 +693,8 @@ impl<'a> WindowContext<'a> { // Only raise click events if the released button is the same as the one stored if self .window - .clicked_button - .map(|clicked_button| clicked_button == e.button) + .clicked_region + .map(|(_, clicked_button)| clicked_button == e.button) .unwrap_or(false) { // Clear clicked regions and clicked button @@ -691,7 +702,7 @@ impl<'a> WindowContext<'a> { &mut self.window.clicked_region_ids, Default::default(), ); - self.window.clicked_button = None; + self.window.clicked_region = None; // Find regions which still overlap with the mouse since the last MouseDown happened for (mouse_region, _) in self.window.mouse_regions.iter().rev() { @@ -866,18 +877,10 @@ impl<'a> WindowContext<'a> { } for view_id in &invalidation.updated { let titlebar_height = self.window.titlebar_height; - let hovered_region_ids = self.window.hovered_region_ids.clone(); - let clicked_region_ids = self - .window - .clicked_button - .map(|button| (self.window.clicked_region_ids.clone(), button)); - let element = self .render_view(RenderParams { view_id: *view_id, titlebar_height, - hovered_region_ids, - clicked_region_ids, refreshing: false, appearance, }) @@ -1182,8 +1185,6 @@ impl<'a> WindowContext<'a> { pub struct RenderParams { pub view_id: usize, pub titlebar_height: f32, - pub hovered_region_ids: HashSet, - pub clicked_region_ids: Option<(HashSet, MouseButton)>, pub refreshing: bool, pub appearance: Appearance, } From ec47464bba1e77379a0f3ca7b8cb169a9300b50b Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Wed, 5 Jul 2023 16:56:08 +0200 Subject: [PATCH 076/104] branch_list: Show match count on the right hand side of a header. Co-authored-by: Antonio --- crates/collab_ui/src/branch_list.rs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/crates/collab_ui/src/branch_list.rs b/crates/collab_ui/src/branch_list.rs index 229d1fdc292b48fe94521272b30f4ceefbe80e45..16fefbd2ebc135a72e056a75e7a2486c7704cab8 100644 --- a/crates/collab_ui/src/branch_list.rs +++ b/crates/collab_ui/src/branch_list.rs @@ -221,17 +221,14 @@ impl PickerDelegate for BranchListDelegate { .with_style(style.container) } else { Flex::row() - .with_child(Label::new("Branches", style.label.clone()).aligned().left()) + .with_child(Label::new("Branches", style.label.clone())) .with_children(self.matches.is_empty().not().then(|| { let suffix = if self.matches.len() == 1 { "" } else { "es" }; - Flex::row() - .align_children_center() - .with_child(Label::new( - format!("{} match{}", self.matches.len(), suffix), - style.label, - )) - .aligned() - .right() + Label::new( + format!("{} match{}", self.matches.len(), suffix), + style.label, + ) + .flex_float() })) .contained() .with_style(style.container) From 0e0d78df84f49b07f2b337985da235975c873943 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Wed, 5 Jul 2023 18:04:40 +0200 Subject: [PATCH 077/104] Do not render recent paths in toolbar's project switcher --- crates/recent_projects/src/recent_projects.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/crates/recent_projects/src/recent_projects.rs b/crates/recent_projects/src/recent_projects.rs index b3c9655645722a976bd3dffe8f430576753ad856..4ba6103167b29669376cb69354b9a942feb96196 100644 --- a/crates/recent_projects/src/recent_projects.rs +++ b/crates/recent_projects/src/recent_projects.rs @@ -48,7 +48,7 @@ fn toggle( let workspace = cx.weak_handle(); cx.add_view(|cx| { RecentProjects::new( - RecentProjectsDelegate::new(workspace, workspace_locations), + RecentProjectsDelegate::new(workspace, workspace_locations, true), cx, ) .with_max_size(800., 1200.) @@ -69,8 +69,11 @@ pub fn build_recent_projects( workspaces: Vec, cx: &mut ViewContext, ) -> RecentProjects { - Picker::new(RecentProjectsDelegate::new(workspace, workspaces), cx) - .with_theme(|theme| theme.picker.clone()) + Picker::new( + RecentProjectsDelegate::new(workspace, workspaces, false), + cx, + ) + .with_theme(|theme| theme.picker.clone()) } pub type RecentProjects = Picker; @@ -80,18 +83,21 @@ pub struct RecentProjectsDelegate { workspace_locations: Vec, selected_match_index: usize, matches: Vec, + render_paths: bool, } impl RecentProjectsDelegate { fn new( workspace: WeakViewHandle, workspace_locations: Vec, + render_paths: bool, ) -> Self { Self { workspace, workspace_locations, selected_match_index: 0, matches: Default::default(), + render_paths, } } } @@ -197,6 +203,7 @@ impl PickerDelegate for RecentProjectsDelegate { highlighted_location .paths .into_iter() + .filter(|_| self.render_paths) .map(|highlighted_path| highlighted_path.render(style.label.clone())), ) .flex(1., false) From 1baa13561d374152a82c182da2b417e66a64280d Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Wed, 5 Jul 2023 12:50:56 -0400 Subject: [PATCH 078/104] Update project & git menus to be Toggleable> Co-Authored-By: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> --- crates/collab_ui/src/collab_titlebar_item.rs | 18 ++++++++++-------- crates/theme/src/theme.rs | 4 ++-- styles/src/style_tree/titlebar.ts | 9 +++++++-- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index 3bc890f91ba571e8b120c37ff7fe61936343518a..c8f1d7cf3038662bb9e24960e21efaee95f8a903 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -221,17 +221,19 @@ impl CollabTitlebarItem { .as_ref() .and_then(RepositoryEntry::branch) .map(|branch| util::truncate_and_trailoff(&branch, MAX_BRANCH_NAME_LENGTH)); - let project_style = theme.titlebar.title.clone(); - let git_style = theme.titlebar.git_branch.clone(); + let project_style = theme.titlebar.project_menu_button.clone(); + let git_style = theme.titlebar.git_menu_button.clone(); let divider_style = theme.titlebar.project_name_divider.clone(); let item_spacing = theme.titlebar.item_spacing; let mut ret = Flex::row().with_child( Stack::new() .with_child( - MouseEventHandler::::new(0, cx, |_, _| { - Label::new(name, project_style.text.clone()) + MouseEventHandler::::new(0, cx, |mouse_state, _| { + let style = project_style.in_state(self.project_popover.is_some()).style_for(mouse_state); + Label::new(name, style.text.clone()) .contained() + .with_style(style.container) .aligned() .left() .into_any_named("title-project-name") @@ -241,8 +243,6 @@ impl CollabTitlebarItem { this.toggle_project_menu(&Default::default(), cx) }) .on_click(MouseButton::Left, move |_, _, _| {}) - .contained() - .with_style(project_style.container), ) .with_children(self.render_project_popover_host(&theme.titlebar, cx)), ); @@ -259,9 +259,11 @@ impl CollabTitlebarItem { .with_child( Stack::new() .with_child( - MouseEventHandler::::new(0, cx, |_, _| { - Label::new(git_branch, git_style.text) + MouseEventHandler::::new(0, cx, |mouse_state, _| { + let style = git_style.in_state(self.branch_popover.is_some()).style_for(mouse_state); + Label::new(git_branch, style.text.clone()) .contained() + .with_style(style.container.clone()) .with_margin_right(item_spacing) .aligned() .left() diff --git a/crates/theme/src/theme.rs b/crates/theme/src/theme.rs index a4fbcedd32cca1aeb73fe39e4a963591f806e72c..3a7924f36ee813c6de7ce9bce41f04d1cf9655d4 100644 --- a/crates/theme/src/theme.rs +++ b/crates/theme/src/theme.rs @@ -118,9 +118,9 @@ pub struct Titlebar { #[serde(flatten)] pub container: ContainerStyle, pub height: f32, - pub title: ContainedText, + pub project_menu_button: Toggleable>, pub project_name_divider: ContainedText, - pub git_branch: ContainedText, + pub git_menu_button: Toggleable>, pub item_spacing: f32, pub face_pile_spacing: f32, pub avatar_ribbon: AvatarRibbon, diff --git a/styles/src/style_tree/titlebar.ts b/styles/src/style_tree/titlebar.ts index 686f814a5d72c3c7ee7b07e3288c6c957536bdcd..109db8db20ced6d42ac1690166365fbb9ec4a62e 100644 --- a/styles/src/style_tree/titlebar.ts +++ b/styles/src/style_tree/titlebar.ts @@ -173,9 +173,14 @@ export function titlebar(theme: ColorScheme): any { }, // Project - title: text(theme.lowest, "sans", "active"), project_name_divider: text(theme.lowest, "sans", "variant"), - git_branch: text(theme.lowest, "sans", "variant"), + + project_menu_button: toggleable_text_button(theme, { + color: 'base', + }), + git_menu_button: toggleable_text_button(theme, { + color: 'variant', + }), // Collaborators leader_avatar: { From b80281e556577c03c72027a45078aeaa0e5435c9 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Wed, 5 Jul 2023 18:57:06 +0200 Subject: [PATCH 079/104] cargo fmt --- crates/collab_ui/src/collab_titlebar_item.rs | 32 ++++++++++++-------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index c8f1d7cf3038662bb9e24960e21efaee95f8a903..73450e7c7d9974f83d78d6c0ad7b4e26ec4fefa3 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -230,7 +230,9 @@ impl CollabTitlebarItem { Stack::new() .with_child( MouseEventHandler::::new(0, cx, |mouse_state, _| { - let style = project_style.in_state(self.project_popover.is_some()).style_for(mouse_state); + let style = project_style + .in_state(self.project_popover.is_some()) + .style_for(mouse_state); Label::new(name, style.text.clone()) .contained() .with_style(style.container) @@ -242,7 +244,7 @@ impl CollabTitlebarItem { .on_down(MouseButton::Left, move |_, this, cx| { this.toggle_project_menu(&Default::default(), cx) }) - .on_click(MouseButton::Left, move |_, _, _| {}) + .on_click(MouseButton::Left, move |_, _, _| {}), ) .with_children(self.render_project_popover_host(&theme.titlebar, cx)), ); @@ -259,16 +261,22 @@ impl CollabTitlebarItem { .with_child( Stack::new() .with_child( - MouseEventHandler::::new(0, cx, |mouse_state, _| { - let style = git_style.in_state(self.branch_popover.is_some()).style_for(mouse_state); - Label::new(git_branch, style.text.clone()) - .contained() - .with_style(style.container.clone()) - .with_margin_right(item_spacing) - .aligned() - .left() - .into_any_named("title-project-branch") - }) + MouseEventHandler::::new( + 0, + cx, + |mouse_state, _| { + let style = git_style + .in_state(self.branch_popover.is_some()) + .style_for(mouse_state); + Label::new(git_branch, style.text.clone()) + .contained() + .with_style(style.container.clone()) + .with_margin_right(item_spacing) + .aligned() + .left() + .into_any_named("title-project-branch") + }, + ) .with_cursor_style(CursorStyle::PointingHand) .on_down(MouseButton::Left, move |_, this, cx| { this.toggle_vcs_menu(&Default::default(), cx) From 6a15ae9c01dcc771c2ed71b9eb14dfe05cc2a98f Mon Sep 17 00:00:00 2001 From: "Joseph T. Lyons" Date: Wed, 5 Jul 2023 14:17:37 -0400 Subject: [PATCH 080/104] v0.95.x dev --- Cargo.lock | 2 +- crates/zed/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7e1407f2c0360b2a07186cacb0ce1ff8bd0d00c0..a4fd323fe0e6fdd0c3ec635b3b1a8bb167103db5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9339,7 +9339,7 @@ dependencies = [ [[package]] name = "zed" -version = "0.94.0" +version = "0.95.0" dependencies = [ "activity_indicator", "ai", diff --git a/crates/zed/Cargo.toml b/crates/zed/Cargo.toml index 97d7f717ce41c6281b8d34760d9c380a04016db4..d016525af40a9e247517dc1aebd64fa2c99c703c 100644 --- a/crates/zed/Cargo.toml +++ b/crates/zed/Cargo.toml @@ -3,7 +3,7 @@ authors = ["Nathan Sobo "] description = "The fast, collaborative code editor." edition = "2021" name = "zed" -version = "0.94.0" +version = "0.95.0" publish = false [lib] From 594b6e8d64b9019a42dbca7083a211fd65911b5f Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Wed, 5 Jul 2023 11:47:17 -0700 Subject: [PATCH 081/104] collab 0.16.0 --- Cargo.lock | 2 +- crates/collab/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a4fd323fe0e6fdd0c3ec635b3b1a8bb167103db5..ac089cee18e9161bb011f3135af3b619921e14cc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1401,7 +1401,7 @@ dependencies = [ [[package]] name = "collab" -version = "0.15.0" +version = "0.16.0" dependencies = [ "anyhow", "async-tungstenite", diff --git a/crates/collab/Cargo.toml b/crates/collab/Cargo.toml index cc7263aa9725f73d892cd9dc3c0b72714b4c850d..cee5fd09898882e3d5999c77522304509dcc004f 100644 --- a/crates/collab/Cargo.toml +++ b/crates/collab/Cargo.toml @@ -3,7 +3,7 @@ authors = ["Nathan Sobo "] default-run = "collab" edition = "2021" name = "collab" -version = "0.15.0" +version = "0.16.0" publish = false [[bin]] From 8b8bafef228842d56e0b9c257ec975e24889a040 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Wed, 5 Jul 2023 12:05:16 -0700 Subject: [PATCH 082/104] Remove spurious audio depedency --- Cargo.lock | 1 - crates/collab/Cargo.toml | 1 - 2 files changed, 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ac089cee18e9161bb011f3135af3b619921e14cc..c6a67d47efc36993e5da5cc8ae30561a366f09d0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1405,7 +1405,6 @@ version = "0.16.0" dependencies = [ "anyhow", "async-tungstenite", - "audio", "axum", "axum-extra", "base64 0.13.1", diff --git a/crates/collab/Cargo.toml b/crates/collab/Cargo.toml index cee5fd09898882e3d5999c77522304509dcc004f..8bd86ed9ec331ef302fbec9940028fe71a5ea771 100644 --- a/crates/collab/Cargo.toml +++ b/crates/collab/Cargo.toml @@ -14,7 +14,6 @@ name = "seed" required-features = ["seed-support"] [dependencies] -audio = { path = "../audio" } collections = { path = "../collections" } live_kit_server = { path = "../live_kit_server" } rpc = { path = "../rpc" } From 801f41e68e79e47e2c05e75d0b17c9b3734644fd Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Wed, 5 Jul 2023 12:15:56 -0700 Subject: [PATCH 083/104] Move audio dependency to dev --- Cargo.lock | 1 + crates/collab/Cargo.toml | 1 + 2 files changed, 2 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index c6a67d47efc36993e5da5cc8ae30561a366f09d0..ac089cee18e9161bb011f3135af3b619921e14cc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1405,6 +1405,7 @@ version = "0.16.0" dependencies = [ "anyhow", "async-tungstenite", + "audio", "axum", "axum-extra", "base64 0.13.1", diff --git a/crates/collab/Cargo.toml b/crates/collab/Cargo.toml index 8bd86ed9ec331ef302fbec9940028fe71a5ea771..c61fdeebfb2f8452a47accedb9643af05bcb4853 100644 --- a/crates/collab/Cargo.toml +++ b/crates/collab/Cargo.toml @@ -57,6 +57,7 @@ tracing-log = "0.1.3" tracing-subscriber = { version = "0.3.11", features = ["env-filter", "json"] } [dev-dependencies] +audio = { path = "../audio" } collections = { path = "../collections", features = ["test-support"] } gpui = { path = "../gpui", features = ["test-support"] } call = { path = "../call", features = ["test-support"] } From f6c96ec8920b529d298691eac151db90c33c959e Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 6 Jul 2023 09:53:34 +0200 Subject: [PATCH 084/104] Fix panic when saved conversations directory changes We were updating the view's state but missed a `notify`, which caused the `UniformList` responsible for rendering the saved conversations to panic when some files were deleted. --- crates/ai/src/assistant.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/ai/src/assistant.rs b/crates/ai/src/assistant.rs index 2b4f733c8053cd9ba0095f86bc02a4cfeb4bab03..4d300230e16109558ac7f2d8850132912c76f67e 100644 --- a/crates/ai/src/assistant.rs +++ b/crates/ai/src/assistant.rs @@ -147,8 +147,9 @@ impl AssistantPanel { .await .log_err() .unwrap_or_default(); - this.update(&mut cx, |this, _| { - this.saved_conversations = saved_conversations + this.update(&mut cx, |this, cx| { + this.saved_conversations = saved_conversations; + cx.notify(); }) .ok(); } From 1936bdebb36b1c4c00abbb9930287449ca0202b3 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Thu, 6 Jul 2023 11:16:39 +0300 Subject: [PATCH 085/104] Use less padding for typescript parameter hints --- crates/project/src/lsp_command.rs | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/crates/project/src/lsp_command.rs b/crates/project/src/lsp_command.rs index a3c6302e29c51ee46f3143d2374fb473f6a7d6ae..eec64beb5a3f25300d3147cde2033a58c235d53d 100644 --- a/crates/project/src/lsp_command.rs +++ b/crates/project/src/lsp_command.rs @@ -1822,11 +1822,21 @@ impl LspCommand for InlayHints { async fn response_from_lsp( self, message: Option>, - _: ModelHandle, + project: ModelHandle, buffer: ModelHandle, - _: LanguageServerId, - cx: AsyncAppContext, + server_id: LanguageServerId, + mut cx: AsyncAppContext, ) -> Result> { + let (lsp_adapter, _) = language_server_for_buffer(&project, &buffer, server_id, &mut cx)?; + // `typescript-language-server` adds padding to the left for type hints, turning + // `const foo: boolean` into `const foo : boolean` which looks odd. + // `rust-analyzer` does not have the padding for this case, and we have to accomodate both. + // + // We could trim the whole string, but being pessimistic on par with the situation above, + // there might be a hint with multiple whitespaces at the end(s) which we need to display properly. + // Hence let's use a heuristic first to handle the most awkward case and look for more. + let force_no_type_left_padding = + lsp_adapter.name.0.as_ref() == "typescript-language-server"; cx.read(|cx| { let origin_buffer = buffer.read(cx); Ok(message @@ -1840,6 +1850,12 @@ impl LspCommand for InlayHints { }); let position = origin_buffer .clip_point_utf16(point_from_lsp(lsp_hint.position), Bias::Left); + let padding_left = + if force_no_type_left_padding && kind == Some(InlayHintKind::Type) { + false + } else { + lsp_hint.padding_left.unwrap_or(false) + }; InlayHint { buffer_id: origin_buffer.remote_id(), position: if kind == Some(InlayHintKind::Parameter) { @@ -1847,7 +1863,7 @@ impl LspCommand for InlayHints { } else { origin_buffer.anchor_after(position) }, - padding_left: lsp_hint.padding_left.unwrap_or(false), + padding_left, padding_right: lsp_hint.padding_right.unwrap_or(false), label: match lsp_hint.label { lsp::InlayHintLabel::String(s) => InlayHintLabel::String(s), From 492b849ea1cec2285ac466f31dde26084021b3f6 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Thu, 6 Jul 2023 12:09:33 +0200 Subject: [PATCH 086/104] Do not render multiple hunks for the same line --- crates/editor/src/element.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 0a462b1e5d39489b6abf10d4cca380fc966d7d35..2f69781aa140a48a14befe86b89c70cc460ebce8 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -1057,6 +1057,7 @@ impl EditorElement { if layout.is_singleton && scrollbar_settings.selections { let start_anchor = Anchor::min(); let end_anchor = Anchor::max(); + let mut last_rendered_row_range = (-1., -1.); for (row, _) in &editor.background_highlights_in_range( start_anchor..end_anchor, &layout.position_map.snapshot, @@ -1069,6 +1070,11 @@ impl EditorElement { if end_y - start_y < 1. { end_y = start_y + 1.; } + if (start_y, end_y) == last_rendered_row_range { + skipped += 1; + continue; + } + last_rendered_row_range = (start_y, end_y); let bounds = RectF::from_points(vec2f(left, start_y), vec2f(right, end_y)); let color = scrollbar_theme.selections; From 0b0a161626d4d58f2afefaf24ceb9b38e1fbf8c8 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Thu, 6 Jul 2023 11:45:17 +0300 Subject: [PATCH 087/104] Show inlay hints on startup for every language server with work events Language servers such as typescript-language-servers report a single work event, ending right after server's startup. Other servers might send more similar event, also during startup. The rest of the events are diagnostic-related and we filter them out. React on such events with /refresh-like hint update, that will check only the visible part of the editor for hints and might be replaced by other /refresh requests, if needed. --- crates/editor/src/inlay_hint_cache.rs | 111 ++++++++++++++++++++++++++ crates/project/src/project.rs | 1 + 2 files changed, 112 insertions(+) diff --git a/crates/editor/src/inlay_hint_cache.rs b/crates/editor/src/inlay_hint_cache.rs index a6ea3962d28f27ff45cab2efc5f85a4a3a861d68..9ca94665c24521539fdf40b27d4cd6d9835c040d 100644 --- a/crates/editor/src/inlay_hint_cache.rs +++ b/crates/editor/src/inlay_hint_cache.rs @@ -974,6 +974,117 @@ mod tests { }); } + #[gpui::test] + async fn test_cache_update_on_lsp_completion_tasks(cx: &mut gpui::TestAppContext) { + init_test(cx, |settings| { + settings.defaults.inlay_hints = Some(InlayHintSettings { + enabled: true, + show_type_hints: true, + show_parameter_hints: true, + show_other_hints: true, + }) + }); + + let (file_with_hints, editor, fake_server) = prepare_test_objects(cx).await; + let lsp_request_count = Arc::new(AtomicU32::new(0)); + fake_server + .handle_request::(move |params, _| { + let task_lsp_request_count = Arc::clone(&lsp_request_count); + async move { + assert_eq!( + params.text_document.uri, + lsp::Url::from_file_path(file_with_hints).unwrap(), + ); + let current_call_id = + Arc::clone(&task_lsp_request_count).fetch_add(1, Ordering::SeqCst); + Ok(Some(vec![lsp::InlayHint { + position: lsp::Position::new(0, current_call_id), + label: lsp::InlayHintLabel::String(current_call_id.to_string()), + kind: None, + text_edits: None, + tooltip: None, + padding_left: None, + padding_right: None, + data: None, + }])) + } + }) + .next() + .await; + cx.foreground().run_until_parked(); + + let mut edits_made = 1; + editor.update(cx, |editor, cx| { + let expected_layers = vec!["0".to_string()]; + assert_eq!( + expected_layers, + cached_hint_labels(editor), + "Should get its first hints when opening the editor" + ); + assert_eq!(expected_layers, visible_hint_labels(editor, cx)); + let inlay_cache = editor.inlay_hint_cache(); + assert_eq!( + inlay_cache.version, edits_made, + "The editor update the cache version after every cache/view change" + ); + }); + + let progress_token = "test_progress_token"; + fake_server + .request::(lsp::WorkDoneProgressCreateParams { + token: lsp::ProgressToken::String(progress_token.to_string()), + }) + .await + .expect("work done progress create request failed"); + cx.foreground().run_until_parked(); + fake_server.notify::(lsp::ProgressParams { + token: lsp::ProgressToken::String(progress_token.to_string()), + value: lsp::ProgressParamsValue::WorkDone(lsp::WorkDoneProgress::Begin( + lsp::WorkDoneProgressBegin::default(), + )), + }); + cx.foreground().run_until_parked(); + + editor.update(cx, |editor, cx| { + let expected_layers = vec!["0".to_string()]; + assert_eq!( + expected_layers, + cached_hint_labels(editor), + "Should not update hints while the work task is running" + ); + assert_eq!(expected_layers, visible_hint_labels(editor, cx)); + let inlay_cache = editor.inlay_hint_cache(); + assert_eq!( + inlay_cache.version, edits_made, + "Should not update the cache while the work task is running" + ); + }); + + fake_server.notify::(lsp::ProgressParams { + token: lsp::ProgressToken::String(progress_token.to_string()), + value: lsp::ProgressParamsValue::WorkDone(lsp::WorkDoneProgress::End( + lsp::WorkDoneProgressEnd::default(), + )), + }); + cx.foreground().run_until_parked(); + + edits_made += 1; + editor.update(cx, |editor, cx| { + let expected_layers = vec!["1".to_string()]; + assert_eq!( + expected_layers, + cached_hint_labels(editor), + "New hints should be queried after the work task is done" + ); + assert_eq!(expected_layers, visible_hint_labels(editor, cx)); + let inlay_cache = editor.inlay_hint_cache(); + assert_eq!( + inlay_cache.version, edits_made, + "Cache version should udpate once after the work task is done" + ); + }); + } + #[gpui::test] async fn test_no_hint_updates_for_unrelated_language_files(cx: &mut gpui::TestAppContext) { let allowed_hint_kinds = HashSet::from_iter([None, Some(InlayHintKind::Type)]); diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index bbb2064da2c2d0a877168ed39d0fe2ad848eba91..d69e5cf21eb82d69f64a3d2879c9559a5788a1a2 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -3397,6 +3397,7 @@ impl Project { cx: &mut ModelContext, ) { if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) { + cx.emit(Event::RefreshInlays); status.pending_work.remove(&token); cx.notify(); } From b66453e771e0a10d467016d23704c2f0d0cd7013 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Thu, 6 Jul 2023 12:11:08 +0200 Subject: [PATCH 088/104] fixup! Do not render multiple hunks for the same line --- crates/editor/src/element.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 2f69781aa140a48a14befe86b89c70cc460ebce8..e884f4b356dc771631f69e2c573439884e4fb28b 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -1071,7 +1071,6 @@ impl EditorElement { end_y = start_y + 1.; } if (start_y, end_y) == last_rendered_row_range { - skipped += 1; continue; } last_rendered_row_range = (start_y, end_y); From 5e7d9dc718522674053f3faa3878e655595b8cf4 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Thu, 6 Jul 2023 13:31:45 +0200 Subject: [PATCH 089/104] Add hunk merging --- crates/editor/src/element.rs | 76 +++++++++++++++++++++++------------- 1 file changed, 48 insertions(+), 28 deletions(-) diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index e884f4b356dc771631f69e2c573439884e4fb28b..82fbd194dbac262040cfc085fad2de5ed3478e23 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -1057,7 +1057,35 @@ impl EditorElement { if layout.is_singleton && scrollbar_settings.selections { let start_anchor = Anchor::min(); let end_anchor = Anchor::max(); - let mut last_rendered_row_range = (-1., -1.); + let mut start_row = None; + let mut end_row = None; + let color = scrollbar_theme.selections; + let border = Border { + width: 1., + color: style.thumb.border.color, + overlay: false, + top: false, + right: true, + 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, + }) + } + }; for (row, _) in &editor.background_highlights_in_range( start_anchor..end_anchor, &layout.position_map.snapshot, @@ -1065,36 +1093,28 @@ impl EditorElement { ) { let start_display = row.start; let end_display = row.end; - let start_y = y_for_row(start_display.row() as f32); - let mut end_y = y_for_row((end_display.row()) as f32); - if end_y - start_y < 1. { - end_y = start_y + 1.; - } - if (start_y, end_y) == last_rendered_row_range { + + if start_row.is_none() { + assert_eq!(end_row, None); + start_row = Some(start_display.row()); + end_row = Some(end_display.row()); continue; } - last_rendered_row_range = (start_y, end_y); - let bounds = RectF::from_points(vec2f(left, start_y), vec2f(right, end_y)); - - let color = scrollbar_theme.selections; - - let border = Border { - width: 1., - color: style.thumb.border.color, - overlay: false, - top: false, - right: true, - bottom: false, - left: true, - }; - - scene.push_quad(Quad { - bounds, - background: Some(color), - border, - corner_radius: style.thumb.corner_radius, - }) + if let Some(current_end) = end_row.as_mut() { + if start_display.row() > *current_end + 1 { + push_region(start_row, end_row); + start_row = None; + end_row = None; + } else { + // Merge two hunks. + *current_end = end_display.row(); + } + } 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); } if layout.is_singleton && scrollbar_settings.git_diff { From 3e245fec9033331034cd054c26291c2a4c06136e Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Thu, 6 Jul 2023 13:52:03 +0200 Subject: [PATCH 090/104] Save a flushing line instead of discarding it --- crates/editor/src/element.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 82fbd194dbac262040cfc085fad2de5ed3478e23..e96f1efe9263f274d66355297e01441ce7474f03 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -1103,8 +1103,8 @@ impl EditorElement { if let Some(current_end) = end_row.as_mut() { if start_display.row() > *current_end + 1 { push_region(start_row, end_row); - start_row = None; - end_row = None; + start_row = Some(start_display.row()); + end_row = Some(end_display.row()); } else { // Merge two hunks. *current_end = end_display.row(); From 5408275c7af8429e58bfc0b4113726e14b58ecc3 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 6 Jul 2023 14:38:05 +0200 Subject: [PATCH 091/104] Filter out non-json files when loading conversations --- crates/ai/src/ai.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/ai/src/ai.rs b/crates/ai/src/ai.rs index 812fb051213f66fd8df1fb83d0b423b1f414effb..7cc5f08f7c1f30102308188865299ff8ee1af833 100644 --- a/crates/ai/src/ai.rs +++ b/crates/ai/src/ai.rs @@ -12,6 +12,7 @@ use regex::Regex; use serde::{Deserialize, Serialize}; use std::{ cmp::Reverse, + ffi::OsStr, fmt::{self, Display}, path::PathBuf, sync::Arc, @@ -80,6 +81,9 @@ impl SavedConversationMetadata { let mut conversations = Vec::::new(); while let Some(path) = paths.next().await { let path = path?; + if path.extension() != Some(OsStr::new("json")) { + continue; + } let pattern = r" - \d+.zed.json$"; let re = Regex::new(pattern).unwrap(); From 708852aa000963780f678c7189b681039a8bfcbf Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 6 Jul 2023 14:11:18 +0200 Subject: [PATCH 092/104] Clip left when finding preceding (line) boundary This fixes an issue that was causing `alt-left` to not move the cursor when it was located right after an inlay hint with a `Left` bias. --- crates/editor/src/movement.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/editor/src/movement.rs b/crates/editor/src/movement.rs index 523a0af9640aa98b3f3e3d7b9fd980768f1e4f89..e589337979bbab654c4aa63e92da51208b8fb7c2 100644 --- a/crates/editor/src/movement.rs +++ b/crates/editor/src/movement.rs @@ -263,13 +263,13 @@ pub fn find_preceding_boundary( if let Some((prev_ch, prev_point)) = prev { if is_boundary(ch, prev_ch) { - return prev_point; + return map.clip_point(prev_point, Bias::Left); } } prev = Some((ch, point)); } - DisplayPoint::zero() + map.clip_point(DisplayPoint::zero(), Bias::Left) } /// Scans for a boundary preceding the given start point `from` until a boundary is found, indicated by the @@ -292,7 +292,7 @@ pub fn find_preceding_boundary_in_line( for (ch, point) in map.reverse_chars_at(from) { if let Some((prev_ch, prev_point)) = prev { if is_boundary(ch, prev_ch) { - return prev_point; + return map.clip_point(prev_point, Bias::Left); } } @@ -303,7 +303,7 @@ pub fn find_preceding_boundary_in_line( prev = Some((ch, point)); } - prev.map(|(_, point)| point).unwrap_or(from) + map.clip_point(prev.map(|(_, point)| point).unwrap_or(from), Bias::Left) } /// Scans for a boundary following the given start point until a boundary is found, indicated by the From 11ae99fbd6d953d9e89ee3821ef7be64ac8e9219 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Thu, 6 Jul 2023 17:12:26 +0300 Subject: [PATCH 093/104] Add a test --- crates/editor/src/movement.rs | 80 ++++++++++++++++++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) diff --git a/crates/editor/src/movement.rs b/crates/editor/src/movement.rs index e589337979bbab654c4aa63e92da51208b8fb7c2..e50d7d8306992726fc47666a3bc8c2d8d3433703 100644 --- a/crates/editor/src/movement.rs +++ b/crates/editor/src/movement.rs @@ -406,8 +406,12 @@ pub fn split_display_range_by_lines( #[cfg(test)] mod tests { use super::*; - use crate::{test::marked_display_snapshot, Buffer, DisplayMap, ExcerptRange, MultiBuffer}; + use crate::{ + display_map::Inlay, test::marked_display_snapshot, Buffer, DisplayMap, ExcerptRange, + InlayId, MultiBuffer, + }; use settings::SettingsStore; + use util::post_inc; #[gpui::test] fn test_previous_word_start(cx: &mut gpui::AppContext) { @@ -505,6 +509,80 @@ mod tests { }); } + #[gpui::test] + fn test_find_preceding_boundary_with_inlays(cx: &mut gpui::AppContext) { + init_test(cx); + + let input_text = "abcdefghijklmnopqrstuvwxys"; + let family_id = cx + .font_cache() + .load_family(&["Helvetica"], &Default::default()) + .unwrap(); + let font_id = cx + .font_cache() + .select_font(family_id, &Default::default()) + .unwrap(); + let font_size = 14.0; + let buffer = MultiBuffer::build_simple(input_text, cx); + let buffer_snapshot = buffer.read(cx).snapshot(cx); + let display_map = + cx.add_model(|cx| DisplayMap::new(buffer, font_id, font_size, None, 1, 1, cx)); + + // add all kinds of inlays between two word boundaries: we should be able to cross them all, when looking for another boundary + let mut id = 0; + let inlays = (0..buffer_snapshot.len()) + .map(|offset| { + [ + Inlay { + id: InlayId::Suggestion(post_inc(&mut id)), + position: buffer_snapshot.anchor_at(offset, Bias::Left), + text: format!("test").into(), + }, + Inlay { + id: InlayId::Suggestion(post_inc(&mut id)), + position: buffer_snapshot.anchor_at(offset, Bias::Right), + text: format!("test").into(), + }, + Inlay { + id: InlayId::Hint(post_inc(&mut id)), + position: buffer_snapshot.anchor_at(offset, Bias::Left), + text: format!("test").into(), + }, + Inlay { + id: InlayId::Hint(post_inc(&mut id)), + position: buffer_snapshot.anchor_at(offset, Bias::Right), + text: format!("test").into(), + }, + ] + }) + .flatten() + .collect(); + let snapshot = display_map.update(cx, |map, cx| { + map.splice_inlays(Vec::new(), inlays, cx); + map.snapshot(cx) + }); + + assert_eq!( + find_preceding_boundary( + &snapshot, + buffer_snapshot.len().to_display_point(&snapshot), + |left, _| left == 'a', + ), + 0.to_display_point(&snapshot), + "Should not stop at inlays when looking for boundaries" + ); + + assert_eq!( + find_preceding_boundary_in_line( + &snapshot, + buffer_snapshot.len().to_display_point(&snapshot), + |left, _| left == 'a', + ), + 0.to_display_point(&snapshot), + "Should not stop at inlays when looking for boundaries in line" + ); + } + #[gpui::test] fn test_next_word_end(cx: &mut gpui::AppContext) { init_test(cx); From 793eff16957b5b20e7f98bd098c096887ed79f9c Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Thu, 6 Jul 2023 10:54:47 -0400 Subject: [PATCH 094/104] Update scrollbar selection style --- styles/src/style_tree/editor.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/styles/src/style_tree/editor.ts b/styles/src/style_tree/editor.ts index a1ba0be43d56b4a81060067b2cc743fe8c6c0562..48a2fd33e2e5fbd2380dea6f71fe1abac00c4a63 100644 --- a/styles/src/style_tree/editor.ts +++ b/styles/src/style_tree/editor.ts @@ -304,9 +304,7 @@ export default function editor(): any { ? with_opacity(theme.ramps.green(0.5).hex(), 0.8) : with_opacity(theme.ramps.green(0.4).hex(), 0.8), }, - selections: is_light - ? with_opacity(theme.ramps.blue(0.5).hex(), 0.8) - : with_opacity(theme.ramps.blue(0.4).hex(), 0.8) + selections: foreground(layer, "accent") }, composition_mark: { underline: { From fff65968bfb30bda31321a832ef2cd67d474cc8f Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Thu, 6 Jul 2023 23:08:04 +0300 Subject: [PATCH 095/104] Restart LSP server on initialization options change --- crates/project/src/project.rs | 27 ++++++++++++++++++++++----- crates/workspace/src/workspace.rs | 1 + 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index d69e5cf21eb82d69f64a3d2879c9559a5788a1a2..81db0c7ed7d3b6ffe61df7104e53796d9dd43b54 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -777,20 +777,32 @@ impl Project { } let mut language_servers_to_stop = Vec::new(); + let mut language_servers_to_restart = Vec::new(); let languages = self.languages.to_vec(); + let project_settings = settings::get::(cx).clone(); for (worktree_id, started_lsp_name) in self.language_server_ids.keys() { - let language = languages.iter().find(|l| { - l.lsp_adapters() + let language = languages.iter().find_map(|l| { + let adapter = l + .lsp_adapters() .iter() - .any(|adapter| &adapter.name == started_lsp_name) + .find(|adapter| &adapter.name == started_lsp_name)?; + Some((l, adapter)) }); - if let Some(language) = language { + if let Some((language, adapter)) = language { let worktree = self.worktree_for_id(*worktree_id, cx); - let file = worktree.and_then(|tree| { + let file = worktree.as_ref().and_then(|tree| { tree.update(cx, |tree, cx| tree.root_file(cx).map(|f| f as _)) }); if !language_settings(Some(language), file.as_ref(), cx).enable_language_server { language_servers_to_stop.push((*worktree_id, started_lsp_name.clone())); + } else if let Some(worktree) = worktree { + let new_lsp_settings = project_settings + .lsp + .get(&adapter.name.0) + .and_then(|s| s.initialization_options.as_ref()); + if adapter.initialization_options.as_ref() != new_lsp_settings { + language_servers_to_restart.push((worktree, Arc::clone(language))); + } } } } @@ -807,6 +819,11 @@ impl Project { self.start_language_servers(&worktree, worktree_path, language, cx); } + // Restart all language servers with changed initialization options. + for (worktree, language) in language_servers_to_restart { + self.restart_language_servers(worktree, language, cx); + } + if !self.copilot_enabled && Copilot::global(cx).is_some() { self.copilot_enabled = true; for buffer in self.opened_buffers.values() { diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 60aefe42134961ef31972dc2c75d19d2815b9514..01d80d141c9b38fff5e7129bd5cfcabe27b42bd7 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -4809,6 +4809,7 @@ mod tests { theme::init((), cx); language::init(cx); crate::init_settings(cx); + Project::init_settings(cx); }); } } From e6ec0af74355020bf9017f8c90a043866adf7bad Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Thu, 6 Jul 2023 23:13:29 +0300 Subject: [PATCH 096/104] Remove redundant hint kind checks in tests --- crates/collab/src/tests/integration_tests.rs | 55 ++------------------ crates/editor/src/inlay_hint_cache.rs | 51 +++++------------- 2 files changed, 17 insertions(+), 89 deletions(-) diff --git a/crates/collab/src/tests/integration_tests.rs b/crates/collab/src/tests/integration_tests.rs index b20844a065133539ba71ced8a03217b262c4a69b..66dc19d6906595583400615faf6516f791591b13 100644 --- a/crates/collab/src/tests/integration_tests.rs +++ b/crates/collab/src/tests/integration_tests.rs @@ -18,7 +18,7 @@ use gpui::{ }; use indoc::indoc; use language::{ - language_settings::{AllLanguageSettings, Formatter, InlayHintKind, InlayHintSettings}, + language_settings::{AllLanguageSettings, Formatter, InlayHintSettings}, tree_sitter_rust, Anchor, Diagnostic, DiagnosticEntry, FakeLspAdapter, Language, LanguageConfig, OffsetRangeExt, Point, Rope, }; @@ -7843,7 +7843,6 @@ async fn test_mutual_editor_inlay_hint_cache_update( }); }); }); - let allowed_hint_kinds = HashSet::from_iter([None, Some(InlayHintKind::Type)]); let mut language = Language::new( LanguageConfig { @@ -7955,10 +7954,6 @@ async fn test_mutual_editor_inlay_hint_cache_update( "Host should get its first hints when opens an editor" ); let inlay_cache = editor.inlay_hint_cache(); - assert_eq!( - inlay_cache.allowed_hint_kinds, allowed_hint_kinds, - "Cache should use editor settings to get the allowed hint kinds" - ); assert_eq!( inlay_cache.version, edits_made, "Host editor update the cache version after every cache/view change", @@ -7982,10 +7977,6 @@ async fn test_mutual_editor_inlay_hint_cache_update( "Client should get its first hints when opens an editor" ); let inlay_cache = editor.inlay_hint_cache(); - assert_eq!( - inlay_cache.allowed_hint_kinds, allowed_hint_kinds, - "Cache should use editor settings to get the allowed hint kinds" - ); assert_eq!( inlay_cache.version, edits_made, "Guest editor update the cache version after every cache/view change" @@ -8007,10 +7998,6 @@ async fn test_mutual_editor_inlay_hint_cache_update( "Host should get hints from the 1st edit and 1st LSP query" ); let inlay_cache = editor.inlay_hint_cache(); - assert_eq!( - inlay_cache.allowed_hint_kinds, allowed_hint_kinds, - "Inlay kinds settings never change during the test" - ); assert_eq!(inlay_cache.version, edits_made); }); editor_b.update(cx_b, |editor, _| { @@ -8025,10 +8012,6 @@ async fn test_mutual_editor_inlay_hint_cache_update( "Guest should get hints the 1st edit and 2nd LSP query" ); let inlay_cache = editor.inlay_hint_cache(); - assert_eq!( - inlay_cache.allowed_hint_kinds, allowed_hint_kinds, - "Inlay kinds settings never change during the test" - ); assert_eq!(inlay_cache.version, edits_made); }); @@ -8054,10 +8037,6 @@ async fn test_mutual_editor_inlay_hint_cache_update( 4th query was made by guest (but not applied) due to cache invalidation logic" ); let inlay_cache = editor.inlay_hint_cache(); - assert_eq!( - inlay_cache.allowed_hint_kinds, allowed_hint_kinds, - "Inlay kinds settings never change during the test" - ); assert_eq!(inlay_cache.version, edits_made); }); editor_b.update(cx_b, |editor, _| { @@ -8074,10 +8053,6 @@ async fn test_mutual_editor_inlay_hint_cache_update( "Guest should get hints from 3rd edit, 6th LSP query" ); let inlay_cache = editor.inlay_hint_cache(); - assert_eq!( - inlay_cache.allowed_hint_kinds, allowed_hint_kinds, - "Inlay kinds settings never change during the test" - ); assert_eq!(inlay_cache.version, edits_made); }); @@ -8103,10 +8078,6 @@ async fn test_mutual_editor_inlay_hint_cache_update( "Host should react to /refresh LSP request and get new hints from 7th LSP query" ); let inlay_cache = editor.inlay_hint_cache(); - assert_eq!( - inlay_cache.allowed_hint_kinds, allowed_hint_kinds, - "Inlay kinds settings never change during the test" - ); assert_eq!( inlay_cache.version, edits_made, "Host should accepted all edits and bump its cache version every time" @@ -8128,10 +8099,6 @@ async fn test_mutual_editor_inlay_hint_cache_update( "Guest should get a /refresh LSP request propagated by host and get new hints from 8th LSP query" ); let inlay_cache = editor.inlay_hint_cache(); - assert_eq!( - inlay_cache.allowed_hint_kinds, allowed_hint_kinds, - "Inlay kinds settings never change during the test" - ); assert_eq!( inlay_cache.version, edits_made, @@ -8164,9 +8131,9 @@ async fn test_inlay_hint_refresh_is_forwarded( store.update_user_settings::(cx, |settings| { settings.defaults.inlay_hints = Some(InlayHintSettings { enabled: false, - show_type_hints: true, + show_type_hints: false, show_parameter_hints: false, - show_other_hints: true, + show_other_hints: false, }) }); }); @@ -8177,13 +8144,12 @@ async fn test_inlay_hint_refresh_is_forwarded( settings.defaults.inlay_hints = Some(InlayHintSettings { enabled: true, show_type_hints: true, - show_parameter_hints: false, + show_parameter_hints: true, show_other_hints: true, }) }); }); }); - let allowed_hint_kinds = HashSet::from_iter([None, Some(InlayHintKind::Type)]); let mut language = Language::new( LanguageConfig { @@ -8299,10 +8265,6 @@ async fn test_inlay_hint_refresh_is_forwarded( "Host should get no hints due to them turned off" ); let inlay_cache = editor.inlay_hint_cache(); - assert_eq!( - inlay_cache.allowed_hint_kinds, allowed_hint_kinds, - "Host should have allowed hint kinds set despite hints are off" - ); assert_eq!( inlay_cache.version, 0, "Host should not increment its cache version due to no changes", @@ -8318,10 +8280,6 @@ async fn test_inlay_hint_refresh_is_forwarded( "Client should get its first hints when opens an editor" ); let inlay_cache = editor.inlay_hint_cache(); - assert_eq!( - inlay_cache.allowed_hint_kinds, allowed_hint_kinds, - "Cache should use editor settings to get the allowed hint kinds" - ); assert_eq!( inlay_cache.version, edits_made, "Guest editor update the cache version after every cache/view change" @@ -8339,7 +8297,6 @@ async fn test_inlay_hint_refresh_is_forwarded( "Host should get nop hints due to them turned off, even after the /refresh" ); let inlay_cache = editor.inlay_hint_cache(); - assert_eq!(inlay_cache.allowed_hint_kinds, allowed_hint_kinds); assert_eq!( inlay_cache.version, 0, "Host should not increment its cache version due to no changes", @@ -8355,10 +8312,6 @@ async fn test_inlay_hint_refresh_is_forwarded( "Guest should get a /refresh LSP request propagated by host despite host hints are off" ); let inlay_cache = editor.inlay_hint_cache(); - assert_eq!( - inlay_cache.allowed_hint_kinds, allowed_hint_kinds, - "Inlay kinds settings never change during the test" - ); assert_eq!( inlay_cache.version, edits_made, "Guest should accepted all edits and bump its cache version every time" diff --git a/crates/editor/src/inlay_hint_cache.rs b/crates/editor/src/inlay_hint_cache.rs index 9ca94665c24521539fdf40b27d4cd6d9835c040d..70fb3725046ccf134c1d280490b66b0cbe1437eb 100644 --- a/crates/editor/src/inlay_hint_cache.rs +++ b/crates/editor/src/inlay_hint_cache.rs @@ -833,7 +833,7 @@ mod tests { use crate::{ scroll::{autoscroll::Autoscroll, scroll_amount::ScrollAmount}, serde_json::json, - ExcerptRange, InlayHintSettings, + ExcerptRange, }; use futures::StreamExt; use gpui::{executor::Deterministic, TestAppContext, ViewHandle}; @@ -1087,13 +1087,12 @@ mod tests { #[gpui::test] async fn test_no_hint_updates_for_unrelated_language_files(cx: &mut gpui::TestAppContext) { - let allowed_hint_kinds = HashSet::from_iter([None, Some(InlayHintKind::Type)]); init_test(cx, |settings| { settings.defaults.inlay_hints = Some(InlayHintSettings { enabled: true, - show_type_hints: allowed_hint_kinds.contains(&Some(InlayHintKind::Type)), - show_parameter_hints: allowed_hint_kinds.contains(&Some(InlayHintKind::Parameter)), - show_other_hints: allowed_hint_kinds.contains(&None), + show_type_hints: true, + show_parameter_hints: true, + show_other_hints: true, }) }); @@ -1196,10 +1195,6 @@ mod tests { ); assert_eq!(expected_layers, visible_hint_labels(editor, cx)); let inlay_cache = editor.inlay_hint_cache(); - assert_eq!( - inlay_cache.allowed_hint_kinds, allowed_hint_kinds, - "Cache should use editor settings to get the allowed hint kinds" - ); assert_eq!( inlay_cache.version, 1, "Rust editor update the cache version after every cache/view change" @@ -1258,7 +1253,6 @@ mod tests { ); assert_eq!(expected_layers, visible_hint_labels(editor, cx)); let inlay_cache = editor.inlay_hint_cache(); - assert_eq!(inlay_cache.allowed_hint_kinds, allowed_hint_kinds); assert_eq!(inlay_cache.version, 1); }); @@ -1276,7 +1270,6 @@ mod tests { ); assert_eq!(expected_layers, visible_hint_labels(editor, cx)); let inlay_cache = editor.inlay_hint_cache(); - assert_eq!(inlay_cache.allowed_hint_kinds, allowed_hint_kinds); assert_eq!( inlay_cache.version, 2, "Every time hint cache changes, cache version should be incremented" @@ -1291,7 +1284,6 @@ mod tests { ); assert_eq!(expected_layers, visible_hint_labels(editor, cx)); let inlay_cache = editor.inlay_hint_cache(); - assert_eq!(inlay_cache.allowed_hint_kinds, allowed_hint_kinds); assert_eq!(inlay_cache.version, 1); }); @@ -1309,7 +1301,6 @@ mod tests { ); assert_eq!(expected_layers, visible_hint_labels(editor, cx)); let inlay_cache = editor.inlay_hint_cache(); - assert_eq!(inlay_cache.allowed_hint_kinds, allowed_hint_kinds); assert_eq!(inlay_cache.version, 2); }); rs_editor.update(cx, |editor, cx| { @@ -1321,7 +1312,6 @@ mod tests { ); assert_eq!(expected_layers, visible_hint_labels(editor, cx)); let inlay_cache = editor.inlay_hint_cache(); - assert_eq!(inlay_cache.allowed_hint_kinds, allowed_hint_kinds); assert_eq!(inlay_cache.version, 2); }); } @@ -1444,7 +1434,6 @@ mod tests { visible_hint_labels(editor, cx) ); let inlay_cache = editor.inlay_hint_cache(); - assert_eq!(inlay_cache.allowed_hint_kinds, allowed_hint_kinds); assert_eq!( inlay_cache.version, edits_made, "Should not update cache version due to new loaded hints being the same" @@ -1580,7 +1569,6 @@ mod tests { assert!(cached_hint_labels(editor).is_empty()); assert!(visible_hint_labels(editor, cx).is_empty()); let inlay_cache = editor.inlay_hint_cache(); - assert_eq!(inlay_cache.allowed_hint_kinds, another_allowed_hint_kinds); assert_eq!( inlay_cache.version, edits_made, "The editor should not update the cache version after /refresh query without updates" @@ -1654,20 +1642,18 @@ mod tests { visible_hint_labels(editor, cx), ); let inlay_cache = editor.inlay_hint_cache(); - assert_eq!(inlay_cache.allowed_hint_kinds, final_allowed_hint_kinds); assert_eq!(inlay_cache.version, edits_made); }); } #[gpui::test] async fn test_hint_request_cancellation(cx: &mut gpui::TestAppContext) { - let allowed_hint_kinds = HashSet::from_iter([None]); init_test(cx, |settings| { settings.defaults.inlay_hints = Some(InlayHintSettings { enabled: true, - show_type_hints: allowed_hint_kinds.contains(&Some(InlayHintKind::Type)), - show_parameter_hints: allowed_hint_kinds.contains(&Some(InlayHintKind::Parameter)), - show_other_hints: allowed_hint_kinds.contains(&None), + show_type_hints: true, + show_parameter_hints: true, + show_other_hints: true, }) }); @@ -1735,7 +1721,6 @@ mod tests { ); assert_eq!(expected_hints, visible_hint_labels(editor, cx)); let inlay_cache = editor.inlay_hint_cache(); - assert_eq!(inlay_cache.allowed_hint_kinds, allowed_hint_kinds); assert_eq!( inlay_cache.version, 1, "Only one update should be registered in the cache after all cancellations" @@ -1782,7 +1767,6 @@ mod tests { ); assert_eq!(expected_hints, visible_hint_labels(editor, cx)); let inlay_cache = editor.inlay_hint_cache(); - assert_eq!(inlay_cache.allowed_hint_kinds, allowed_hint_kinds); assert_eq!( inlay_cache.version, 2, "Should update the cache version once more, for the new change" @@ -1792,13 +1776,12 @@ mod tests { #[gpui::test] async fn test_large_buffer_inlay_requests_split(cx: &mut gpui::TestAppContext) { - let allowed_hint_kinds = HashSet::from_iter([None, Some(InlayHintKind::Type)]); init_test(cx, |settings| { settings.defaults.inlay_hints = Some(InlayHintSettings { enabled: true, - show_type_hints: allowed_hint_kinds.contains(&Some(InlayHintKind::Type)), - show_parameter_hints: allowed_hint_kinds.contains(&Some(InlayHintKind::Parameter)), - show_other_hints: allowed_hint_kinds.contains(&None), + show_type_hints: true, + show_parameter_hints: true, + show_other_hints: true, }) }); @@ -1904,7 +1887,6 @@ mod tests { ); assert_eq!(expected_layers, visible_hint_labels(editor, cx)); let inlay_cache = editor.inlay_hint_cache(); - assert_eq!(inlay_cache.allowed_hint_kinds, allowed_hint_kinds); assert_eq!( inlay_cache.version, 2, "Both LSP queries should've bumped the cache version" @@ -1937,7 +1919,6 @@ mod tests { "Should have hints from the new LSP response after edit"); assert_eq!(expected_layers, visible_hint_labels(editor, cx)); let inlay_cache = editor.inlay_hint_cache(); - assert_eq!(inlay_cache.allowed_hint_kinds, allowed_hint_kinds); assert_eq!(inlay_cache.version, 5, "Should update the cache for every LSP response with hints added"); }); } @@ -1947,13 +1928,12 @@ mod tests { deterministic: Arc, cx: &mut gpui::TestAppContext, ) { - let allowed_hint_kinds = HashSet::from_iter([None, Some(InlayHintKind::Type)]); init_test(cx, |settings| { settings.defaults.inlay_hints = Some(InlayHintSettings { enabled: true, - show_type_hints: allowed_hint_kinds.contains(&Some(InlayHintKind::Type)), - show_parameter_hints: allowed_hint_kinds.contains(&Some(InlayHintKind::Parameter)), - show_other_hints: allowed_hint_kinds.contains(&None), + show_type_hints: true, + show_parameter_hints: true, + show_other_hints: true, }) }); @@ -2159,7 +2139,6 @@ mod tests { ); assert_eq!(expected_layers, visible_hint_labels(editor, cx)); let inlay_cache = editor.inlay_hint_cache(); - assert_eq!(inlay_cache.allowed_hint_kinds, allowed_hint_kinds); assert_eq!(inlay_cache.version, 4, "Every visible excerpt hints should bump the verison"); }); @@ -2191,7 +2170,6 @@ mod tests { "With more scrolls of the multibuffer, more hints should be added into the cache and nothing invalidated without edits"); assert_eq!(expected_layers, visible_hint_labels(editor, cx)); let inlay_cache = editor.inlay_hint_cache(); - assert_eq!(inlay_cache.allowed_hint_kinds, allowed_hint_kinds); assert_eq!(inlay_cache.version, 9); }); @@ -2220,7 +2198,6 @@ mod tests { "After multibuffer was scrolled to the end, all hints for all excerpts should be fetched"); assert_eq!(expected_layers, visible_hint_labels(editor, cx)); let inlay_cache = editor.inlay_hint_cache(); - assert_eq!(inlay_cache.allowed_hint_kinds, allowed_hint_kinds); assert_eq!(inlay_cache.version, 12); }); @@ -2249,7 +2226,6 @@ mod tests { "After multibuffer was scrolled to the end, further scrolls up should not bring more hints"); assert_eq!(expected_layers, visible_hint_labels(editor, cx)); let inlay_cache = editor.inlay_hint_cache(); - assert_eq!(inlay_cache.allowed_hint_kinds, allowed_hint_kinds); assert_eq!(inlay_cache.version, 12, "No updates should happen during scrolling already scolled buffer"); }); @@ -2276,7 +2252,6 @@ mod tests { unedited (2nd) buffer should have the same hint"); assert_eq!(expected_layers, visible_hint_labels(editor, cx)); let inlay_cache = editor.inlay_hint_cache(); - assert_eq!(inlay_cache.allowed_hint_kinds, allowed_hint_kinds); assert_eq!(inlay_cache.version, 16); }); } From 318deed25b4bad1c0d0cfc29749a50a06a87590b Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 7 Jul 2023 12:02:08 +0200 Subject: [PATCH 097/104] Skip key down event if preceded by its key equivalent version Previously, we would only track whether the previous key down event was a key equivalent. However, this could cause issues when pressing certain keystrokes in rapid succession, e.g.: - Pressing `shift-right` (to select a character) - Pressing a character (with or without `shift` held down) This would cause GPUI to ignore the second event because it was preceded by a key equivalent event. With this commit, we track the last key equivalent event, and skip the key down event only if it matches the last key equivalent event. --- crates/gpui/src/platform/event.rs | 2 +- crates/gpui/src/platform/mac/window.rs | 59 ++++++++++---------------- 2 files changed, 24 insertions(+), 37 deletions(-) diff --git a/crates/gpui/src/platform/event.rs b/crates/gpui/src/platform/event.rs index c39c76dc34dab4af3d8521d23b6008b1af540d27..4456db9a51e1120c31fd44876ca4a148da3027a3 100644 --- a/crates/gpui/src/platform/event.rs +++ b/crates/gpui/src/platform/event.rs @@ -4,7 +4,7 @@ use pathfinder_geometry::vector::vec2f; use crate::{geometry::vector::Vector2F, keymap_matcher::Keystroke}; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Eq, PartialEq)] pub struct KeyDownEvent { pub keystroke: Keystroke, pub is_held: bool, diff --git a/crates/gpui/src/platform/mac/window.rs b/crates/gpui/src/platform/mac/window.rs index 3c825386114332870500d0eed93171064134c699..381a4fbaaacc1c45ad2ed19140e1980009857751 100644 --- a/crates/gpui/src/platform/mac/window.rs +++ b/crates/gpui/src/platform/mac/window.rs @@ -232,10 +232,6 @@ unsafe fn build_window_class(name: &'static str, superclass: &Class) -> *const C sel!(canBecomeKeyWindow), yes as extern "C" fn(&Object, Sel) -> BOOL, ); - decl.add_method( - sel!(sendEvent:), - send_event as extern "C" fn(&Object, Sel, id), - ); decl.add_method( sel!(windowDidResize:), window_did_resize as extern "C" fn(&Object, Sel, id), @@ -299,7 +295,7 @@ struct WindowState { appearance_changed_callback: Option>, input_handler: Option>, pending_key_down: Option<(KeyDownEvent, Option)>, - performed_key_equivalent: bool, + last_key_equivalent: Option, synthetic_drag_counter: usize, executor: Rc, scene_to_render: Option, @@ -521,7 +517,7 @@ impl Window { appearance_changed_callback: None, input_handler: None, pending_key_down: None, - performed_key_equivalent: false, + last_key_equivalent: None, synthetic_drag_counter: 0, executor, scene_to_render: Default::default(), @@ -965,36 +961,34 @@ extern "C" fn handle_key_event(this: &Object, native_event: id, key_equivalent: let window_height = window_state_borrow.content_size().y(); let event = unsafe { Event::from_native(native_event, Some(window_height)) }; - if let Some(event) = event { + if let Some(Event::KeyDown(event)) = event { + // For certain keystrokes, macOS will first dispatch a "key equivalent" event. + // If that event isn't handled, it will then dispatch a "key down" event. GPUI + // makes no distinction between these two types of events, so we need to ignore + // the "key down" event if we've already just processed its "key equivalent" version. if key_equivalent { - window_state_borrow.performed_key_equivalent = true; - } else if window_state_borrow.performed_key_equivalent { + window_state_borrow.last_key_equivalent = Some(event.clone()); + } else if window_state_borrow.last_key_equivalent.take().as_ref() == Some(&event) { return NO; } - let function_is_held; - window_state_borrow.pending_key_down = match event { - Event::KeyDown(event) => { - let keydown = event.keystroke.clone(); - // Ignore events from held-down keys after some of the initially-pressed keys - // were released. - if event.is_held { - if window_state_borrow.last_fresh_keydown.as_ref() != Some(&keydown) { - return YES; - } - } else { - window_state_borrow.last_fresh_keydown = Some(keydown); - } - function_is_held = event.keystroke.function; - Some((event, None)) + let keydown = event.keystroke.clone(); + let fn_modifier = keydown.function; + // Ignore events from held-down keys after some of the initially-pressed keys + // were released. + if event.is_held { + if window_state_borrow.last_fresh_keydown.as_ref() != Some(&keydown) { + return YES; } - - _ => return NO, - }; - + } else { + window_state_borrow.last_fresh_keydown = Some(keydown); + } + window_state_borrow.pending_key_down = Some((event, None)); drop(window_state_borrow); - if !function_is_held { + // Send the event to the input context for IME handling, unless the `fn` modifier is + // being pressed. + if !fn_modifier { unsafe { let input_context: id = msg_send![this, inputContext]; let _: BOOL = msg_send![input_context, handleEvent: native_event]; @@ -1143,13 +1137,6 @@ extern "C" fn cancel_operation(this: &Object, _sel: Sel, _sender: id) { } } -extern "C" fn send_event(this: &Object, _: Sel, native_event: id) { - unsafe { - let _: () = msg_send![super(this, class!(NSWindow)), sendEvent: native_event]; - get_window_state(this).borrow_mut().performed_key_equivalent = false; - } -} - extern "C" fn window_did_resize(this: &Object, _: Sel, _: id) { let window_state = unsafe { get_window_state(this) }; window_state.as_ref().borrow().move_traffic_light(); From abf3b4a54e66e0a67cc39c2b6454d89ab7295534 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Fri, 7 Jul 2023 15:07:12 +0200 Subject: [PATCH 098/104] chore: Replace lazy_static Mutex with const. (#2693) Mutex::new() is const-stable as of Rust 1.63. Release Notes: - N/A --- Cargo.lock | 2 -- crates/collab/src/db.rs | 5 +---- crates/collab/src/tests/randomized_integration_tests.rs | 4 ++-- crates/db/src/db.rs | 2 +- crates/language/src/syntax_map.rs | 5 +---- crates/live_kit_client/Cargo.toml | 3 --- crates/live_kit_client/src/test.rs | 7 ++----- crates/vim/Cargo.toml | 1 - crates/vim/src/test/neovim_connection.rs | 6 +----- 9 files changed, 8 insertions(+), 27 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ac089cee18e9161bb011f3135af3b619921e14cc..60ed830683a5f91d0c8f4806b5d6758b2afbc31e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4004,7 +4004,6 @@ dependencies = [ "gpui", "hmac 0.12.1", "jwt", - "lazy_static", "live_kit_server", "log", "media", @@ -8398,7 +8397,6 @@ dependencies = [ "indoc", "itertools", "language", - "lazy_static", "log", "nvim-rs", "parking_lot 0.11.2", diff --git a/crates/collab/src/db.rs b/crates/collab/src/db.rs index 208da22efe4b35564f756b8c481a31cf2047481b..e16fa9edb1efed6167556194acadbddd52763a07 100644 --- a/crates/collab/src/db.rs +++ b/crates/collab/src/db.rs @@ -3517,7 +3517,6 @@ pub use test::*; mod test { use super::*; use gpui::executor::Background; - use lazy_static::lazy_static; use parking_lot::Mutex; use sea_orm::ConnectionTrait; use sqlx::migrate::MigrateDatabase; @@ -3566,9 +3565,7 @@ mod test { } pub fn postgres(background: Arc) -> Self { - lazy_static! { - static ref LOCK: Mutex<()> = Mutex::new(()); - } + static LOCK: Mutex<()> = Mutex::new(()); let _guard = LOCK.lock(); let mut rng = StdRng::from_entropy(); diff --git a/crates/collab/src/tests/randomized_integration_tests.rs b/crates/collab/src/tests/randomized_integration_tests.rs index a95938f6b8dc3504256099a282462a249d695635..f5dfe17d6f34f17790f131d7b244f954a4e96e0b 100644 --- a/crates/collab/src/tests/randomized_integration_tests.rs +++ b/crates/collab/src/tests/randomized_integration_tests.rs @@ -37,9 +37,9 @@ use util::ResultExt; lazy_static::lazy_static! { static ref PLAN_LOAD_PATH: Option = path_env_var("LOAD_PLAN"); static ref PLAN_SAVE_PATH: Option = path_env_var("SAVE_PLAN"); - static ref LOADED_PLAN_JSON: Mutex>> = Default::default(); - static ref PLAN: Mutex>>> = Default::default(); } +static LOADED_PLAN_JSON: Mutex>> = Mutex::new(None); +static PLAN: Mutex>>> = Mutex::new(None); #[gpui::test(iterations = 100, on_failure = "on_failure")] async fn test_random_collaboration( diff --git a/crates/db/src/db.rs b/crates/db/src/db.rs index 5b8aca07e032ea509fbb30ffdd09f7d6e48f13ee..798dfbc17f70173095dc9671543a60c2ef381732 100644 --- a/crates/db/src/db.rs +++ b/crates/db/src/db.rs @@ -43,10 +43,10 @@ const DB_FILE_NAME: &'static str = "db.sqlite"; lazy_static::lazy_static! { // !!!!!!! CHANGE BACK TO DEFAULT FALSE BEFORE SHIPPING static ref ZED_STATELESS: bool = std::env::var("ZED_STATELESS").map_or(false, |v| !v.is_empty()); - static ref DB_FILE_OPERATIONS: Mutex<()> = Mutex::new(()); pub static ref BACKUP_DB_PATH: RwLock> = RwLock::new(None); pub static ref ALL_FILE_DB_FAILED: AtomicBool = AtomicBool::new(false); } +static DB_FILE_OPERATIONS: Mutex<()> = Mutex::new(()); /// Open or create a database at the given directory path. /// This will retry a couple times if there are failures. If opening fails once, the db directory diff --git a/crates/language/src/syntax_map.rs b/crates/language/src/syntax_map.rs index 1570baf1854154a0f40a2f3ce137a291dede5b99..b6431c228674f6076b5d4bec2a3fa59bb7795d96 100644 --- a/crates/language/src/syntax_map.rs +++ b/crates/language/src/syntax_map.rs @@ -4,7 +4,6 @@ mod syntax_map_tests; use crate::{Grammar, InjectionConfig, Language, LanguageRegistry}; use collections::HashMap; use futures::FutureExt; -use lazy_static::lazy_static; use parking_lot::Mutex; use std::{ borrow::Cow, @@ -25,9 +24,7 @@ thread_local! { static PARSER: RefCell = RefCell::new(Parser::new()); } -lazy_static! { - static ref QUERY_CURSORS: Mutex> = Default::default(); -} +static QUERY_CURSORS: Mutex> = Mutex::new(vec![]); #[derive(Default)] pub struct SyntaxMap { diff --git a/crates/live_kit_client/Cargo.toml b/crates/live_kit_client/Cargo.toml index 36087a42a371ad75936209f77aeed0c8141687cc..78f435906bc0a81d99b3bcda12e86e46d87e9cd2 100644 --- a/crates/live_kit_client/Cargo.toml +++ b/crates/live_kit_client/Cargo.toml @@ -17,7 +17,6 @@ test-support = [ "async-trait", "collections/test-support", "gpui/test-support", - "lazy_static", "live_kit_server", "nanoid", ] @@ -38,7 +37,6 @@ parking_lot.workspace = true postage.workspace = true async-trait = { workspace = true, optional = true } -lazy_static = { workspace = true, optional = true } nanoid = { version ="0.4", optional = true} [dev-dependencies] @@ -60,7 +58,6 @@ foreign-types = "0.3" futures.workspace = true hmac = "0.12" jwt = "0.16" -lazy_static.workspace = true objc = "0.2" parking_lot.workspace = true serde.workspace = true diff --git a/crates/live_kit_client/src/test.rs b/crates/live_kit_client/src/test.rs index 3fc046c5a293b105729fb756adfede6951de954b..ada864fc44492d278a34c949589af5a4d605a0d2 100644 --- a/crates/live_kit_client/src/test.rs +++ b/crates/live_kit_client/src/test.rs @@ -1,18 +1,15 @@ use anyhow::{anyhow, Result}; use async_trait::async_trait; -use collections::HashMap; +use collections::{BTreeMap, HashMap}; use futures::Stream; use gpui::executor::Background; -use lazy_static::lazy_static; use live_kit_server::token; use media::core_video::CVImageBuffer; use parking_lot::Mutex; use postage::watch; use std::{future::Future, mem, sync::Arc}; -lazy_static! { - static ref SERVERS: Mutex>> = Default::default(); -} +static SERVERS: Mutex>> = Mutex::new(BTreeMap::new()); pub struct TestServer { pub url: String, diff --git a/crates/vim/Cargo.toml b/crates/vim/Cargo.toml index 57d38213798352bf8fad6970306691182e6fb1fb..47a85f4ed314f4b20dd7fe39eda0b1814bf9bc67 100644 --- a/crates/vim/Cargo.toml +++ b/crates/vim/Cargo.toml @@ -36,7 +36,6 @@ workspace = { path = "../workspace" } [dev-dependencies] indoc.workspace = true parking_lot.workspace = true -lazy_static.workspace = true editor = { path = "../editor", features = ["test-support"] } gpui = { path = "../gpui", features = ["test-support"] } diff --git a/crates/vim/src/test/neovim_connection.rs b/crates/vim/src/test/neovim_connection.rs index c3916722ddeaad974747a63729058b73c7d7d544..aa14e4a0651b40a6f0753aed8d99a6b030c30542 100644 --- a/crates/vim/src/test/neovim_connection.rs +++ b/crates/vim/src/test/neovim_connection.rs @@ -11,8 +11,6 @@ use gpui::keymap_matcher::Keystroke; use language::Point; -#[cfg(feature = "neovim")] -use lazy_static::lazy_static; #[cfg(feature = "neovim")] use nvim_rs::{ create::tokio::new_child_cmd, error::LoopError, Handler, Neovim, UiAttachOptions, Value, @@ -32,9 +30,7 @@ use collections::VecDeque; // Neovim doesn't like to be started simultaneously from multiple threads. We use this lock // to ensure we are only constructing one neovim connection at a time. #[cfg(feature = "neovim")] -lazy_static! { - static ref NEOVIM_LOCK: ReentrantMutex<()> = ReentrantMutex::new(()); -} +static NEOVIM_LOCK: ReentrantMutex<()> = ReentrantMutex::new(()); #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub enum NeovimData { From 66bf56fc4f571c94486c5e2a1552aebf66f5f797 Mon Sep 17 00:00:00 2001 From: Julia Date: Thu, 6 Jul 2023 17:18:45 -0400 Subject: [PATCH 099/104] Prevent duplicate instances by coordinating via a socket --- crates/cli/src/main.rs | 1 + crates/zed/src/main.rs | 9 +++- crates/zed/src/only_instance.rs | 82 +++++++++++++++++++++++++++++++++ crates/zed/src/zed.rs | 1 + 4 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 crates/zed/src/only_instance.rs diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index bdf677512c4b0326cf2bc0e513a00bbb563f0a02..2f742814a8dbfdfeb7719fbe906858448d8253f8 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -201,6 +201,7 @@ impl Bundle { self.zed_version_string() ); } + Self::LocalPath { executable, .. } => { let executable_parent = executable .parent() diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index 3da8c24617909abb00cd6aa19e1d6adff6cad010..5eed301367481bb0b747631cbee7d062d9c6febe 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -57,8 +57,9 @@ use staff_mode::StaffMode; use util::{channel::RELEASE_CHANNEL, paths, ResultExt, TryFutureExt}; use workspace::{item::ItemHandle, notifications::NotifyResultExt, AppState, Workspace}; use zed::{ - assets::Assets, build_window_options, handle_keymap_file_changes, initialize_workspace, - languages, menus, + assets::Assets, + build_window_options, handle_keymap_file_changes, initialize_workspace, languages, menus, + only_instance::{ensure_only_instance, IsOnlyInstance}, }; fn main() { @@ -66,6 +67,10 @@ fn main() { init_paths(); init_logger(); + if ensure_only_instance() != IsOnlyInstance::Yes { + return; + } + log::info!("========== starting zed =========="); let mut app = gpui::App::new(Assets).unwrap(); diff --git a/crates/zed/src/only_instance.rs b/crates/zed/src/only_instance.rs new file mode 100644 index 0000000000000000000000000000000000000000..c1358f7a336ec955c19137187232d58d8bc0652c --- /dev/null +++ b/crates/zed/src/only_instance.rs @@ -0,0 +1,82 @@ +use std::{ + io::{Read, Write}, + net::{Ipv4Addr, SocketAddr, SocketAddrV4, TcpListener, TcpStream}, + thread, + time::Duration, +}; + +const PORT: u16 = 43739; +const LOCALHOST: Ipv4Addr = Ipv4Addr::new(127, 0, 0, 1); +const ADDRESS: SocketAddr = SocketAddr::V4(SocketAddrV4::new(LOCALHOST, PORT)); +const INSTANCE_HANDSHAKE: &str = "Zed Editor Instance Running"; +const CONNECT_TIMEOUT: Duration = Duration::from_millis(10); +const RECEIVE_TIMEOUT: Duration = Duration::from_millis(35); +const SEND_TIMEOUT: Duration = Duration::from_millis(20); + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum IsOnlyInstance { + Yes, + No, +} + +pub fn ensure_only_instance() -> IsOnlyInstance { + if check_got_handshake() { + return IsOnlyInstance::No; + } + + let listener = match TcpListener::bind(ADDRESS) { + Ok(listener) => listener, + + Err(err) => { + log::warn!("Error binding to single instance port: {err}"); + if check_got_handshake() { + return IsOnlyInstance::No; + } + + // Avoid failing to start when some other application by chance already has + // a claim on the port. This is sub-par as any other instance that gets launched + // will be unable to communicate with this instance and will duplicate + log::warn!("Backup handshake request failed, continuing without handshake"); + return IsOnlyInstance::Yes; + } + }; + + thread::spawn(move || { + for stream in listener.incoming() { + let mut stream = match stream { + Ok(stream) => stream, + Err(_) => return, + }; + + _ = stream.set_nodelay(true); + _ = stream.set_read_timeout(Some(SEND_TIMEOUT)); + _ = stream.write_all(INSTANCE_HANDSHAKE.as_bytes()); + } + }); + + IsOnlyInstance::Yes +} + +fn check_got_handshake() -> bool { + match TcpStream::connect_timeout(&ADDRESS, CONNECT_TIMEOUT) { + Ok(mut stream) => { + let mut buf = vec![0u8; INSTANCE_HANDSHAKE.len()]; + + stream.set_read_timeout(Some(RECEIVE_TIMEOUT)).unwrap(); + if let Err(err) = stream.read_exact(&mut buf) { + log::warn!("Connected to single instance port but failed to read: {err}"); + return false; + } + + if buf == INSTANCE_HANDSHAKE.as_bytes() { + log::info!("Got instance handshake"); + return true; + } + + log::warn!("Got wrong instance handshake value"); + false + } + + Err(_) => false, + } +} diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 0df16f4bab13fa56ed3211e462d8203be161c331..09bdbf65beef1f6f7825b112f485d0b5eec35205 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -1,6 +1,7 @@ pub mod assets; pub mod languages; pub mod menus; +pub mod only_instance; #[cfg(any(test, feature = "test-support"))] pub mod test; From b70b76029e17e1cb96d9d008755bb48fd682df5c Mon Sep 17 00:00:00 2001 From: Julia Date: Fri, 7 Jul 2023 14:18:43 -0400 Subject: [PATCH 100/104] Use different port and handshake for different release channels --- crates/db/src/db.rs | 3 +-- crates/zed/src/only_instance.rs | 33 +++++++++++++++++++++++++-------- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/crates/db/src/db.rs b/crates/db/src/db.rs index 798dfbc17f70173095dc9671543a60c2ef381732..7b4aa74a80761dad70dcca1283fdd25d1156997a 100644 --- a/crates/db/src/db.rs +++ b/crates/db/src/db.rs @@ -41,8 +41,7 @@ const FALLBACK_DB_NAME: &'static str = "FALLBACK_MEMORY_DB"; const DB_FILE_NAME: &'static str = "db.sqlite"; lazy_static::lazy_static! { - // !!!!!!! CHANGE BACK TO DEFAULT FALSE BEFORE SHIPPING - static ref ZED_STATELESS: bool = std::env::var("ZED_STATELESS").map_or(false, |v| !v.is_empty()); + pub static ref ZED_STATELESS: bool = std::env::var("ZED_STATELESS").map_or(false, |v| !v.is_empty()); pub static ref BACKUP_DB_PATH: RwLock> = RwLock::new(None); pub static ref ALL_FILE_DB_FAILED: AtomicBool = AtomicBool::new(false); } diff --git a/crates/zed/src/only_instance.rs b/crates/zed/src/only_instance.rs index c1358f7a336ec955c19137187232d58d8bc0652c..0450b5908ba30a04779c06820e79b7139e7119d7 100644 --- a/crates/zed/src/only_instance.rs +++ b/crates/zed/src/only_instance.rs @@ -5,14 +5,31 @@ use std::{ time::Duration, }; -const PORT: u16 = 43739; +use util::channel::ReleaseChannel; + const LOCALHOST: Ipv4Addr = Ipv4Addr::new(127, 0, 0, 1); -const ADDRESS: SocketAddr = SocketAddr::V4(SocketAddrV4::new(LOCALHOST, PORT)); -const INSTANCE_HANDSHAKE: &str = "Zed Editor Instance Running"; const CONNECT_TIMEOUT: Duration = Duration::from_millis(10); const RECEIVE_TIMEOUT: Duration = Duration::from_millis(35); const SEND_TIMEOUT: Duration = Duration::from_millis(20); +fn address() -> SocketAddr { + let port = match *util::channel::RELEASE_CHANNEL { + ReleaseChannel::Dev => 43737, + ReleaseChannel::Preview => 43738, + ReleaseChannel::Stable => 43739, + }; + + SocketAddr::V4(SocketAddrV4::new(LOCALHOST, port)) +} + +fn instance_handshake() -> &'static str { + match *util::channel::RELEASE_CHANNEL { + ReleaseChannel::Dev => "Zed Editor Dev Instance Running", + ReleaseChannel::Preview => "Zed Editor Preview Instance Running", + ReleaseChannel::Stable => "Zed Editor Stable Instance Running", + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum IsOnlyInstance { Yes, @@ -24,7 +41,7 @@ pub fn ensure_only_instance() -> IsOnlyInstance { return IsOnlyInstance::No; } - let listener = match TcpListener::bind(ADDRESS) { + let listener = match TcpListener::bind(address()) { Ok(listener) => listener, Err(err) => { @@ -50,7 +67,7 @@ pub fn ensure_only_instance() -> IsOnlyInstance { _ = stream.set_nodelay(true); _ = stream.set_read_timeout(Some(SEND_TIMEOUT)); - _ = stream.write_all(INSTANCE_HANDSHAKE.as_bytes()); + _ = stream.write_all(instance_handshake().as_bytes()); } }); @@ -58,9 +75,9 @@ pub fn ensure_only_instance() -> IsOnlyInstance { } fn check_got_handshake() -> bool { - match TcpStream::connect_timeout(&ADDRESS, CONNECT_TIMEOUT) { + match TcpStream::connect_timeout(&address(), CONNECT_TIMEOUT) { Ok(mut stream) => { - let mut buf = vec![0u8; INSTANCE_HANDSHAKE.len()]; + let mut buf = vec![0u8; instance_handshake().len()]; stream.set_read_timeout(Some(RECEIVE_TIMEOUT)).unwrap(); if let Err(err) = stream.read_exact(&mut buf) { @@ -68,7 +85,7 @@ fn check_got_handshake() -> bool { return false; } - if buf == INSTANCE_HANDSHAKE.as_bytes() { + if buf == instance_handshake().as_bytes() { log::info!("Got instance handshake"); return true; } From caa29d57c2d82fbbcdc2f7d7ef6ec1d39969767c Mon Sep 17 00:00:00 2001 From: Julia Date: Fri, 7 Jul 2023 14:19:13 -0400 Subject: [PATCH 101/104] Avoid checking for duplicate instance when local DB is disabled --- crates/zed/src/only_instance.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/zed/src/only_instance.rs b/crates/zed/src/only_instance.rs index 0450b5908ba30a04779c06820e79b7139e7119d7..a8c4b30816dfbbed4ae5c186d2d0e43722245293 100644 --- a/crates/zed/src/only_instance.rs +++ b/crates/zed/src/only_instance.rs @@ -37,6 +37,10 @@ pub enum IsOnlyInstance { } pub fn ensure_only_instance() -> IsOnlyInstance { + if *db::ZED_STATELESS { + return IsOnlyInstance::Yes; + } + if check_got_handshake() { return IsOnlyInstance::No; } From 52a497be21d9a19ae9136d13ab524847d3b84daf Mon Sep 17 00:00:00 2001 From: "Joseph T. Lyons" Date: Sat, 8 Jul 2023 18:03:18 -0400 Subject: [PATCH 102/104] Remove code block for GitHub release notes Discord can directly render the Markdown now. --- .github/workflows/release_actions.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/release_actions.yml b/.github/workflows/release_actions.yml index 4ccab09cbe10c56f49d43e08d6483b28846021cb..71909ae1771637ed099e532266d740dfe3361a2f 100644 --- a/.github/workflows/release_actions.yml +++ b/.github/workflows/release_actions.yml @@ -16,8 +16,4 @@ jobs: Restart your Zed or head to https://zed.dev/releases/stable/latest to grab it. - ```md - # Changelog - ${{ github.event.release.body }} - ``` From 6e24ded2bcbab2b0798c8c1ed3b88165a30c5c47 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Mon, 10 Jul 2023 14:20:12 +0200 Subject: [PATCH 103/104] collab_ui: Add tooltip to branches popover (#2695) Z-2554 Release Notes: - N/A --- crates/collab_ui/src/collab_titlebar_item.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index 73450e7c7d9974f83d78d6c0ad7b4e26ec4fefa3..ed3315ab5af9bb7c71d4c5d8abba74c0d07d92ec 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -264,7 +264,8 @@ impl CollabTitlebarItem { MouseEventHandler::::new( 0, cx, - |mouse_state, _| { + |mouse_state, cx| { + enum BranchPopoverTooltip {} let style = git_style .in_state(self.branch_popover.is_some()) .style_for(mouse_state); @@ -274,6 +275,13 @@ impl CollabTitlebarItem { .with_margin_right(item_spacing) .aligned() .left() + .with_tooltip::( + 0, + "Recent branches".into(), + None, + theme.tooltip.clone(), + cx, + ) .into_any_named("title-project-branch") }, ) From 6c8cb6b2a9f8dbebb7e31df9035940b5ffd7659f Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Wed, 5 Jul 2023 10:54:28 +0200 Subject: [PATCH 104/104] project_search: display result count on cmd-enter It also focuses the first result (just like a normal enter). --- crates/search/src/project_search.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/crates/search/src/project_search.rs b/crates/search/src/project_search.rs index 135194df6a2f5a22c1ed001a725488ae2c003437..ebd504d02c2334aa6876a478937718cb1aa4d496 100644 --- a/crates/search/src/project_search.rs +++ b/crates/search/src/project_search.rs @@ -675,6 +675,9 @@ impl ProjectSearchView { if match_ranges.is_empty() { self.active_match_index = None; } else { + self.active_match_index = Some(0); + self.select_match(Direction::Next, cx); + self.update_match_index(cx); let prev_search_id = mem::replace(&mut self.search_id, self.model.read(cx).search_id); let is_new_search = self.search_id != prev_search_id; self.results_editor.update(cx, |editor, cx| {