WIP compiling but failing with circular reference

K Simmons created

Change summary

crates/chat_panel/src/chat_panel.rs                 |   6 
crates/command_palette/src/command_palette.rs       |   5 
crates/contacts_panel/src/contact_finder.rs         |   6 
crates/contacts_panel/src/contacts_panel.rs         |   8 
crates/context_menu/src/context_menu.rs             |   4 
crates/diagnostics/src/diagnostics.rs               |   2 
crates/editor/src/editor.rs                         |   8 
crates/file_finder/src/file_finder.rs               |   6 
crates/go_to_line/src/go_to_line.rs                 |   6 
crates/gpui/grammars/context-predicate/src/parser.c | 909 +++++++-------
crates/gpui/src/app.rs                              | 149 +
crates/outline/src/outline.rs                       |   6 
crates/picker/src/picker.rs                         |   6 
crates/project_symbols/src/project_symbols.rs       |   6 
crates/search/src/buffer_search.rs                  |   6 
crates/search/src/project_search.rs                 |   8 
crates/terminal/src/connected_view.rs               |   5 
crates/terminal/src/terminal.rs                     |   7 
crates/theme_selector/src/theme_selector.rs         |   6 
crates/workspace/src/pane.rs                        |  15 
crates/workspace/src/workspace.rs                   |   2 
styles/package-lock.json                            |   1 
22 files changed, 663 insertions(+), 514 deletions(-)

Detailed changes

crates/chat_panel/src/chat_panel.rs 🔗

@@ -8,8 +8,8 @@ use gpui::{
     elements::*,
     platform::CursorStyle,
     views::{ItemType, Select, SelectStyle},
-    AppContext, Entity, ModelHandle, MouseButton, MutableAppContext, RenderContext, Subscription,
-    Task, View, ViewContext, ViewHandle,
+    AnyViewHandle, AppContext, Entity, ModelHandle, MouseButton, MutableAppContext, RenderContext,
+    Subscription, Task, View, ViewContext, ViewHandle,
 };
 use menu::Confirm;
 use postage::prelude::Stream;
@@ -397,7 +397,7 @@ impl View for ChatPanel {
         .boxed()
     }
 
-    fn on_focus(&mut self, cx: &mut ViewContext<Self>) {
+    fn on_focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
         if matches!(
             *self.rpc.status().borrow(),
             client::Status::Connected { .. }

crates/command_palette/src/command_palette.rs 🔗

@@ -4,7 +4,8 @@ use gpui::{
     actions,
     elements::{ChildView, Flex, Label, ParentElement},
     keymap::Keystroke,
-    Action, Element, Entity, MouseState, MutableAppContext, View, ViewContext, ViewHandle,
+    Action, AnyViewHandle, Element, Entity, MouseState, MutableAppContext, View, ViewContext,
+    ViewHandle,
 };
 use picker::{Picker, PickerDelegate};
 use settings::Settings;
@@ -132,7 +133,7 @@ impl View for CommandPalette {
         ChildView::new(self.picker.clone()).boxed()
     }
 
-    fn on_focus(&mut self, cx: &mut ViewContext<Self>) {
+    fn on_focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
         cx.focus(&self.picker);
     }
 }

crates/contacts_panel/src/contact_finder.rs 🔗

@@ -1,7 +1,7 @@
 use client::{ContactRequestStatus, User, UserStore};
 use gpui::{
-    actions, elements::*, Entity, ModelHandle, MouseState, MutableAppContext, RenderContext, Task,
-    View, ViewContext, ViewHandle,
+    actions, elements::*, AnyViewHandle, Entity, ModelHandle, MouseState, MutableAppContext,
+    RenderContext, Task, View, ViewContext, ViewHandle,
 };
 use picker::{Picker, PickerDelegate};
 use settings::Settings;
@@ -42,7 +42,7 @@ impl View for ContactFinder {
         ChildView::new(self.picker.clone()).boxed()
     }
 
-    fn on_focus(&mut self, cx: &mut ViewContext<Self>) {
+    fn on_focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
         cx.focus(&self.picker);
     }
 }

crates/contacts_panel/src/contacts_panel.rs 🔗

@@ -13,9 +13,9 @@ use gpui::{
     geometry::{rect::RectF, vector::vec2f},
     impl_actions, impl_internal_actions,
     platform::CursorStyle,
-    AppContext, ClipboardItem, Element, ElementBox, Entity, ModelHandle, MouseButton,
-    MutableAppContext, RenderContext, Subscription, View, ViewContext, ViewHandle, WeakModelHandle,
-    WeakViewHandle,
+    AnyViewHandle, AppContext, ClipboardItem, Element, ElementBox, Entity, ModelHandle,
+    MouseButton, MutableAppContext, RenderContext, Subscription, View, ViewContext, ViewHandle,
+    WeakModelHandle, WeakViewHandle,
 };
 use join_project_notification::JoinProjectNotification;
 use menu::{Confirm, SelectNext, SelectPrev};
@@ -1152,7 +1152,7 @@ impl View for ContactsPanel {
         .boxed()
     }
 
-    fn on_focus(&mut self, cx: &mut ViewContext<Self>) {
+    fn on_focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
         cx.focus(&self.filter_editor);
     }
 

crates/context_menu/src/context_menu.rs 🔗

@@ -1,6 +1,6 @@
 use gpui::{
     elements::*, geometry::vector::Vector2F, impl_internal_actions, keymap, platform::CursorStyle,
-    Action, AppContext, Axis, Entity, MouseButton, MutableAppContext, RenderContext,
+    Action, AnyViewHandle, AppContext, Axis, Entity, MouseButton, MutableAppContext, RenderContext,
     SizeConstraint, Subscription, View, ViewContext,
 };
 use menu::*;
@@ -106,7 +106,7 @@ impl View for ContextMenu {
             .boxed()
     }
 
-    fn on_blur(&mut self, cx: &mut ViewContext<Self>) {
+    fn on_focus_out(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
         self.reset(cx);
     }
 }

crates/diagnostics/src/diagnostics.rs 🔗

@@ -99,7 +99,7 @@ impl View for ProjectDiagnosticsEditor {
         }
     }
 
-    fn on_focus(&mut self, cx: &mut ViewContext<Self>) {
+    fn on_focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
         if !self.path_states.is_empty() {
             cx.focus(&self.editor);
         }

crates/editor/src/editor.rs 🔗

@@ -29,8 +29,8 @@ use gpui::{
     geometry::vector::{vec2f, Vector2F},
     impl_actions, impl_internal_actions,
     platform::CursorStyle,
-    text_layout, AppContext, AsyncAppContext, ClipboardItem, Element, ElementBox, Entity,
-    ModelHandle, MouseButton, MutableAppContext, RenderContext, Subscription, Task, View,
+    text_layout, AnyViewHandle, AppContext, AsyncAppContext, ClipboardItem, Element, ElementBox,
+    Entity, ModelHandle, MouseButton, MutableAppContext, RenderContext, Subscription, Task, View,
     ViewContext, ViewHandle, WeakViewHandle,
 };
 use highlight_matching_bracket::refresh_matching_bracket_highlights;
@@ -6025,7 +6025,7 @@ impl View for Editor {
         "Editor"
     }
 
-    fn on_focus(&mut self, cx: &mut ViewContext<Self>) {
+    fn on_focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
         let focused_event = EditorFocused(cx.handle());
         cx.emit_global(focused_event);
         if let Some(rename) = self.pending_rename.as_ref() {
@@ -6046,7 +6046,7 @@ impl View for Editor {
         }
     }
 
-    fn on_blur(&mut self, cx: &mut ViewContext<Self>) {
+    fn on_focus_out(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
         let blurred_event = EditorBlurred(cx.handle());
         cx.emit_global(blurred_event);
         self.focused = false;

crates/file_finder/src/file_finder.rs 🔗

@@ -1,7 +1,7 @@
 use fuzzy::PathMatch;
 use gpui::{
-    actions, elements::*, AppContext, Entity, ModelHandle, MouseState, MutableAppContext,
-    RenderContext, Task, View, ViewContext, ViewHandle,
+    actions, elements::*, AnyViewHandle, AppContext, Entity, ModelHandle, MouseState,
+    MutableAppContext, RenderContext, Task, View, ViewContext, ViewHandle,
 };
 use picker::{Picker, PickerDelegate};
 use project::{PathMatchCandidateSet, Project, ProjectPath, WorktreeId};
@@ -53,7 +53,7 @@ impl View for FileFinder {
         ChildView::new(self.picker.clone()).boxed()
     }
 
-    fn on_focus(&mut self, cx: &mut ViewContext<Self>) {
+    fn on_focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
         cx.focus(&self.picker);
     }
 }

crates/go_to_line/src/go_to_line.rs 🔗

@@ -1,7 +1,7 @@
 use editor::{display_map::ToDisplayPoint, Autoscroll, DisplayPoint, Editor};
 use gpui::{
-    actions, elements::*, geometry::vector::Vector2F, Axis, Entity, MutableAppContext,
-    RenderContext, View, ViewContext, ViewHandle,
+    actions, elements::*, geometry::vector::Vector2F, AnyViewHandle, Axis, Entity,
+    MutableAppContext, RenderContext, View, ViewContext, ViewHandle,
 };
 use menu::{Cancel, Confirm};
 use settings::Settings;
@@ -183,7 +183,7 @@ impl View for GoToLine {
         .named("go to line")
     }
 
-    fn on_focus(&mut self, cx: &mut ViewContext<Self>) {
+    fn on_focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
         cx.focus(&self.line_editor);
     }
 }

crates/gpui/grammars/context-predicate/src/parser.c 🔗

@@ -35,115 +35,132 @@ enum {
   sym_parenthesized = 16,
 };
 
-static const char * const ts_symbol_names[] = {
-  [ts_builtin_sym_end] = "end",
-  [sym_identifier] = "identifier",
-  [anon_sym_BANG] = "!",
-  [anon_sym_AMP_AMP] = "&&",
-  [anon_sym_PIPE_PIPE] = "||",
-  [anon_sym_EQ_EQ] = "==",
-  [anon_sym_BANG_EQ] = "!=",
-  [anon_sym_LPAREN] = "(",
-  [anon_sym_RPAREN] = ")",
-  [sym_source] = "source",
-  [sym__expression] = "_expression",
-  [sym_not] = "not",
-  [sym_and] = "and",
-  [sym_or] = "or",
-  [sym_equal] = "equal",
-  [sym_not_equal] = "not_equal",
-  [sym_parenthesized] = "parenthesized",
+static const char *const ts_symbol_names[] = {
+    [ts_builtin_sym_end] = "end",
+    [sym_identifier] = "identifier",
+    [anon_sym_BANG] = "!",
+    [anon_sym_AMP_AMP] = "&&",
+    [anon_sym_PIPE_PIPE] = "||",
+    [anon_sym_EQ_EQ] = "==",
+    [anon_sym_BANG_EQ] = "!=",
+    [anon_sym_LPAREN] = "(",
+    [anon_sym_RPAREN] = ")",
+    [sym_source] = "source",
+    [sym__expression] = "_expression",
+    [sym_not] = "not",
+    [sym_and] = "and",
+    [sym_or] = "or",
+    [sym_equal] = "equal",
+    [sym_not_equal] = "not_equal",
+    [sym_parenthesized] = "parenthesized",
 };
 
 static const TSSymbol ts_symbol_map[] = {
-  [ts_builtin_sym_end] = ts_builtin_sym_end,
-  [sym_identifier] = sym_identifier,
-  [anon_sym_BANG] = anon_sym_BANG,
-  [anon_sym_AMP_AMP] = anon_sym_AMP_AMP,
-  [anon_sym_PIPE_PIPE] = anon_sym_PIPE_PIPE,
-  [anon_sym_EQ_EQ] = anon_sym_EQ_EQ,
-  [anon_sym_BANG_EQ] = anon_sym_BANG_EQ,
-  [anon_sym_LPAREN] = anon_sym_LPAREN,
-  [anon_sym_RPAREN] = anon_sym_RPAREN,
-  [sym_source] = sym_source,
-  [sym__expression] = sym__expression,
-  [sym_not] = sym_not,
-  [sym_and] = sym_and,
-  [sym_or] = sym_or,
-  [sym_equal] = sym_equal,
-  [sym_not_equal] = sym_not_equal,
-  [sym_parenthesized] = sym_parenthesized,
+    [ts_builtin_sym_end] = ts_builtin_sym_end,
+    [sym_identifier] = sym_identifier,
+    [anon_sym_BANG] = anon_sym_BANG,
+    [anon_sym_AMP_AMP] = anon_sym_AMP_AMP,
+    [anon_sym_PIPE_PIPE] = anon_sym_PIPE_PIPE,
+    [anon_sym_EQ_EQ] = anon_sym_EQ_EQ,
+    [anon_sym_BANG_EQ] = anon_sym_BANG_EQ,
+    [anon_sym_LPAREN] = anon_sym_LPAREN,
+    [anon_sym_RPAREN] = anon_sym_RPAREN,
+    [sym_source] = sym_source,
+    [sym__expression] = sym__expression,
+    [sym_not] = sym_not,
+    [sym_and] = sym_and,
+    [sym_or] = sym_or,
+    [sym_equal] = sym_equal,
+    [sym_not_equal] = sym_not_equal,
+    [sym_parenthesized] = sym_parenthesized,
 };
 
 static const TSSymbolMetadata ts_symbol_metadata[] = {
-  [ts_builtin_sym_end] = {
-    .visible = false,
-    .named = true,
-  },
-  [sym_identifier] = {
-    .visible = true,
-    .named = true,
-  },
-  [anon_sym_BANG] = {
-    .visible = true,
-    .named = false,
-  },
-  [anon_sym_AMP_AMP] = {
-    .visible = true,
-    .named = false,
-  },
-  [anon_sym_PIPE_PIPE] = {
-    .visible = true,
-    .named = false,
-  },
-  [anon_sym_EQ_EQ] = {
-    .visible = true,
-    .named = false,
-  },
-  [anon_sym_BANG_EQ] = {
-    .visible = true,
-    .named = false,
-  },
-  [anon_sym_LPAREN] = {
-    .visible = true,
-    .named = false,
-  },
-  [anon_sym_RPAREN] = {
-    .visible = true,
-    .named = false,
-  },
-  [sym_source] = {
-    .visible = true,
-    .named = true,
-  },
-  [sym__expression] = {
-    .visible = false,
-    .named = true,
-  },
-  [sym_not] = {
-    .visible = true,
-    .named = true,
-  },
-  [sym_and] = {
-    .visible = true,
-    .named = true,
-  },
-  [sym_or] = {
-    .visible = true,
-    .named = true,
-  },
-  [sym_equal] = {
-    .visible = true,
-    .named = true,
-  },
-  [sym_not_equal] = {
-    .visible = true,
-    .named = true,
-  },
-  [sym_parenthesized] = {
-    .visible = true,
-    .named = true,
-  },
+    [ts_builtin_sym_end] =
+        {
+            .visible = false,
+            .named = true,
+        },
+    [sym_identifier] =
+        {
+            .visible = true,
+            .named = true,
+        },
+    [anon_sym_BANG] =
+        {
+            .visible = true,
+            .named = false,
+        },
+    [anon_sym_AMP_AMP] =
+        {
+            .visible = true,
+            .named = false,
+        },
+    [anon_sym_PIPE_PIPE] =
+        {
+            .visible = true,
+            .named = false,
+        },
+    [anon_sym_EQ_EQ] =
+        {
+            .visible = true,
+            .named = false,
+        },
+    [anon_sym_BANG_EQ] =
+        {
+            .visible = true,
+            .named = false,
+        },
+    [anon_sym_LPAREN] =
+        {
+            .visible = true,
+            .named = false,
+        },
+    [anon_sym_RPAREN] =
+        {
+            .visible = true,
+            .named = false,
+        },
+    [sym_source] =
+        {
+            .visible = true,
+            .named = true,
+        },
+    [sym__expression] =
+        {
+            .visible = false,
+            .named = true,
+        },
+    [sym_not] =
+        {
+            .visible = true,
+            .named = true,
+        },
+    [sym_and] =
+        {
+            .visible = true,
+            .named = true,
+        },
+    [sym_or] =
+        {
+            .visible = true,
+            .named = true,
+        },
+    [sym_equal] =
+        {
+            .visible = true,
+            .named = true,
+        },
+    [sym_not_equal] =
+        {
+            .visible = true,
+            .named = true,
+        },
+    [sym_parenthesized] =
+        {
+            .visible = true,
+            .named = true,
+        },
 };
 
 enum {
@@ -152,340 +169,378 @@ enum {
   field_right = 3,
 };
 
-static const char * const ts_field_names[] = {
-  [0] = NULL,
-  [field_expression] = "expression",
-  [field_left] = "left",
-  [field_right] = "right",
+static const char *const ts_field_names[] = {
+    [0] = NULL,
+    [field_expression] = "expression",
+    [field_left] = "left",
+    [field_right] = "right",
 };
 
 static const TSFieldMapSlice ts_field_map_slices[PRODUCTION_ID_COUNT] = {
-  [1] = {.index = 0, .length = 1},
-  [2] = {.index = 1, .length = 2},
+    [1] = {.index = 0, .length = 1},
+    [2] = {.index = 1, .length = 2},
 };
 
 static const TSFieldMapEntry ts_field_map_entries[] = {
-  [0] =
-    {field_expression, 1},
-  [1] =
-    {field_left, 0},
+    [0] = {field_expression, 1},
+    [1] = {field_left, 0},
     {field_right, 2},
 };
 
-static const TSSymbol ts_alias_sequences[PRODUCTION_ID_COUNT][MAX_ALIAS_SEQUENCE_LENGTH] = {
-  [0] = {0},
+static const TSSymbol ts_alias_sequences[PRODUCTION_ID_COUNT]
+                                        [MAX_ALIAS_SEQUENCE_LENGTH] = {
+                                            [0] = {0},
 };
 
 static const uint16_t ts_non_terminal_alias_map[] = {
-  0,
+    0,
 };
 
 static bool ts_lex(TSLexer *lexer, TSStateId state) {
   START_LEXER();
   eof = lexer->eof(lexer);
   switch (state) {
-    case 0:
-      if (eof) ADVANCE(7);
-      if (lookahead == '!') ADVANCE(10);
-      if (lookahead == '&') ADVANCE(2);
-      if (lookahead == '(') ADVANCE(15);
-      if (lookahead == ')') ADVANCE(16);
-      if (lookahead == '=') ADVANCE(4);
-      if (lookahead == '|') ADVANCE(5);
-      if (lookahead == '\t' ||
-          lookahead == '\n' ||
-          lookahead == '\r' ||
-          lookahead == ' ') SKIP(0)
-      if (lookahead == '-' ||
-          ('0' <= lookahead && lookahead <= '9') ||
-          ('A' <= lookahead && lookahead <= 'Z') ||
-          lookahead == '_' ||
-          ('a' <= lookahead && lookahead <= 'z')) ADVANCE(8);
-      END_STATE();
-    case 1:
-      if (lookahead == '!') ADVANCE(9);
-      if (lookahead == '(') ADVANCE(15);
-      if (lookahead == '\t' ||
-          lookahead == '\n' ||
-          lookahead == '\r' ||
-          lookahead == ' ') SKIP(1)
-      if (lookahead == '-' ||
-          ('0' <= lookahead && lookahead <= '9') ||
-          ('A' <= lookahead && lookahead <= 'Z') ||
-          lookahead == '_' ||
-          ('a' <= lookahead && lookahead <= 'z')) ADVANCE(8);
-      END_STATE();
-    case 2:
-      if (lookahead == '&') ADVANCE(11);
-      END_STATE();
-    case 3:
-      if (lookahead == '=') ADVANCE(14);
-      END_STATE();
-    case 4:
-      if (lookahead == '=') ADVANCE(13);
-      END_STATE();
-    case 5:
-      if (lookahead == '|') ADVANCE(12);
-      END_STATE();
-    case 6:
-      if (eof) ADVANCE(7);
-      if (lookahead == '!') ADVANCE(3);
-      if (lookahead == '&') ADVANCE(2);
-      if (lookahead == ')') ADVANCE(16);
-      if (lookahead == '=') ADVANCE(4);
-      if (lookahead == '|') ADVANCE(5);
-      if (lookahead == '\t' ||
-          lookahead == '\n' ||
-          lookahead == '\r' ||
-          lookahead == ' ') SKIP(6)
-      END_STATE();
-    case 7:
-      ACCEPT_TOKEN(ts_builtin_sym_end);
-      END_STATE();
-    case 8:
-      ACCEPT_TOKEN(sym_identifier);
-      if (lookahead == '-' ||
-          ('0' <= lookahead && lookahead <= '9') ||
-          ('A' <= lookahead && lookahead <= 'Z') ||
-          lookahead == '_' ||
-          ('a' <= lookahead && lookahead <= 'z')) ADVANCE(8);
-      END_STATE();
-    case 9:
-      ACCEPT_TOKEN(anon_sym_BANG);
-      END_STATE();
-    case 10:
-      ACCEPT_TOKEN(anon_sym_BANG);
-      if (lookahead == '=') ADVANCE(14);
-      END_STATE();
-    case 11:
-      ACCEPT_TOKEN(anon_sym_AMP_AMP);
-      END_STATE();
-    case 12:
-      ACCEPT_TOKEN(anon_sym_PIPE_PIPE);
-      END_STATE();
-    case 13:
-      ACCEPT_TOKEN(anon_sym_EQ_EQ);
-      END_STATE();
-    case 14:
-      ACCEPT_TOKEN(anon_sym_BANG_EQ);
-      END_STATE();
-    case 15:
-      ACCEPT_TOKEN(anon_sym_LPAREN);
-      END_STATE();
-    case 16:
-      ACCEPT_TOKEN(anon_sym_RPAREN);
-      END_STATE();
-    default:
-      return false;
+  case 0:
+    if (eof)
+      ADVANCE(7);
+    if (lookahead == '!')
+      ADVANCE(10);
+    if (lookahead == '&')
+      ADVANCE(2);
+    if (lookahead == '(')
+      ADVANCE(15);
+    if (lookahead == ')')
+      ADVANCE(16);
+    if (lookahead == '=')
+      ADVANCE(4);
+    if (lookahead == '|')
+      ADVANCE(5);
+    if (lookahead == '\t' || lookahead == '\n' || lookahead == '\r' ||
+        lookahead == ' ')
+      SKIP(0)
+    if (lookahead == '-' || ('0' <= lookahead && lookahead <= '9') ||
+        ('A' <= lookahead && lookahead <= 'Z') || lookahead == '_' ||
+        ('a' <= lookahead && lookahead <= 'z'))
+      ADVANCE(8);
+    END_STATE();
+  case 1:
+    if (lookahead == '!')
+      ADVANCE(9);
+    if (lookahead == '(')
+      ADVANCE(15);
+    if (lookahead == '\t' || lookahead == '\n' || lookahead == '\r' ||
+        lookahead == ' ')
+      SKIP(1)
+    if (lookahead == '-' || ('0' <= lookahead && lookahead <= '9') ||
+        ('A' <= lookahead && lookahead <= 'Z') || lookahead == '_' ||
+        ('a' <= lookahead && lookahead <= 'z'))
+      ADVANCE(8);
+    END_STATE();
+  case 2:
+    if (lookahead == '&')
+      ADVANCE(11);
+    END_STATE();
+  case 3:
+    if (lookahead == '=')
+      ADVANCE(14);
+    END_STATE();
+  case 4:
+    if (lookahead == '=')
+      ADVANCE(13);
+    END_STATE();
+  case 5:
+    if (lookahead == '|')
+      ADVANCE(12);
+    END_STATE();
+  case 6:
+    if (eof)
+      ADVANCE(7);
+    if (lookahead == '!')
+      ADVANCE(3);
+    if (lookahead == '&')
+      ADVANCE(2);
+    if (lookahead == ')')
+      ADVANCE(16);
+    if (lookahead == '=')
+      ADVANCE(4);
+    if (lookahead == '|')
+      ADVANCE(5);
+    if (lookahead == '\t' || lookahead == '\n' || lookahead == '\r' ||
+        lookahead == ' ')
+      SKIP(6)
+    END_STATE();
+  case 7:
+    ACCEPT_TOKEN(ts_builtin_sym_end);
+    END_STATE();
+  case 8:
+    ACCEPT_TOKEN(sym_identifier);
+    if (lookahead == '-' || ('0' <= lookahead && lookahead <= '9') ||
+        ('A' <= lookahead && lookahead <= 'Z') || lookahead == '_' ||
+        ('a' <= lookahead && lookahead <= 'z'))
+      ADVANCE(8);
+    END_STATE();
+  case 9:
+    ACCEPT_TOKEN(anon_sym_BANG);
+    END_STATE();
+  case 10:
+    ACCEPT_TOKEN(anon_sym_BANG);
+    if (lookahead == '=')
+      ADVANCE(14);
+    END_STATE();
+  case 11:
+    ACCEPT_TOKEN(anon_sym_AMP_AMP);
+    END_STATE();
+  case 12:
+    ACCEPT_TOKEN(anon_sym_PIPE_PIPE);
+    END_STATE();
+  case 13:
+    ACCEPT_TOKEN(anon_sym_EQ_EQ);
+    END_STATE();
+  case 14:
+    ACCEPT_TOKEN(anon_sym_BANG_EQ);
+    END_STATE();
+  case 15:
+    ACCEPT_TOKEN(anon_sym_LPAREN);
+    END_STATE();
+  case 16:
+    ACCEPT_TOKEN(anon_sym_RPAREN);
+    END_STATE();
+  default:
+    return false;
   }
 }
 
 static const TSLexMode ts_lex_modes[STATE_COUNT] = {
-  [0] = {.lex_state = 0},
-  [1] = {.lex_state = 1},
-  [2] = {.lex_state = 1},
-  [3] = {.lex_state = 1},
-  [4] = {.lex_state = 1},
-  [5] = {.lex_state = 1},
-  [6] = {.lex_state = 6},
-  [7] = {.lex_state = 0},
-  [8] = {.lex_state = 0},
-  [9] = {.lex_state = 0},
-  [10] = {.lex_state = 0},
-  [11] = {.lex_state = 0},
-  [12] = {.lex_state = 0},
-  [13] = {.lex_state = 0},
-  [14] = {.lex_state = 0},
-  [15] = {.lex_state = 0},
-  [16] = {.lex_state = 0},
-  [17] = {.lex_state = 0},
+    [0] = {.lex_state = 0},  [1] = {.lex_state = 1},  [2] = {.lex_state = 1},
+    [3] = {.lex_state = 1},  [4] = {.lex_state = 1},  [5] = {.lex_state = 1},
+    [6] = {.lex_state = 6},  [7] = {.lex_state = 0},  [8] = {.lex_state = 0},
+    [9] = {.lex_state = 0},  [10] = {.lex_state = 0}, [11] = {.lex_state = 0},
+    [12] = {.lex_state = 0}, [13] = {.lex_state = 0}, [14] = {.lex_state = 0},
+    [15] = {.lex_state = 0}, [16] = {.lex_state = 0}, [17] = {.lex_state = 0},
 };
 
 static const uint16_t ts_parse_table[LARGE_STATE_COUNT][SYMBOL_COUNT] = {
-  [0] = {
-    [ts_builtin_sym_end] = ACTIONS(1),
-    [sym_identifier] = ACTIONS(1),
-    [anon_sym_BANG] = ACTIONS(1),
-    [anon_sym_AMP_AMP] = ACTIONS(1),
-    [anon_sym_PIPE_PIPE] = ACTIONS(1),
-    [anon_sym_EQ_EQ] = ACTIONS(1),
-    [anon_sym_BANG_EQ] = ACTIONS(1),
-    [anon_sym_LPAREN] = ACTIONS(1),
-    [anon_sym_RPAREN] = ACTIONS(1),
-  },
-  [1] = {
-    [sym_source] = STATE(15),
-    [sym__expression] = STATE(13),
-    [sym_not] = STATE(13),
-    [sym_and] = STATE(13),
-    [sym_or] = STATE(13),
-    [sym_equal] = STATE(13),
-    [sym_not_equal] = STATE(13),
-    [sym_parenthesized] = STATE(13),
-    [sym_identifier] = ACTIONS(3),
-    [anon_sym_BANG] = ACTIONS(5),
-    [anon_sym_LPAREN] = ACTIONS(7),
-  },
-  [2] = {
-    [sym__expression] = STATE(7),
-    [sym_not] = STATE(7),
-    [sym_and] = STATE(7),
-    [sym_or] = STATE(7),
-    [sym_equal] = STATE(7),
-    [sym_not_equal] = STATE(7),
-    [sym_parenthesized] = STATE(7),
-    [sym_identifier] = ACTIONS(3),
-    [anon_sym_BANG] = ACTIONS(5),
-    [anon_sym_LPAREN] = ACTIONS(7),
-  },
-  [3] = {
-    [sym__expression] = STATE(14),
-    [sym_not] = STATE(14),
-    [sym_and] = STATE(14),
-    [sym_or] = STATE(14),
-    [sym_equal] = STATE(14),
-    [sym_not_equal] = STATE(14),
-    [sym_parenthesized] = STATE(14),
-    [sym_identifier] = ACTIONS(3),
-    [anon_sym_BANG] = ACTIONS(5),
-    [anon_sym_LPAREN] = ACTIONS(7),
-  },
-  [4] = {
-    [sym__expression] = STATE(11),
-    [sym_not] = STATE(11),
-    [sym_and] = STATE(11),
-    [sym_or] = STATE(11),
-    [sym_equal] = STATE(11),
-    [sym_not_equal] = STATE(11),
-    [sym_parenthesized] = STATE(11),
-    [sym_identifier] = ACTIONS(3),
-    [anon_sym_BANG] = ACTIONS(5),
-    [anon_sym_LPAREN] = ACTIONS(7),
-  },
-  [5] = {
-    [sym__expression] = STATE(12),
-    [sym_not] = STATE(12),
-    [sym_and] = STATE(12),
-    [sym_or] = STATE(12),
-    [sym_equal] = STATE(12),
-    [sym_not_equal] = STATE(12),
-    [sym_parenthesized] = STATE(12),
-    [sym_identifier] = ACTIONS(3),
-    [anon_sym_BANG] = ACTIONS(5),
-    [anon_sym_LPAREN] = ACTIONS(7),
-  },
+    [0] =
+        {
+            [ts_builtin_sym_end] = ACTIONS(1),
+            [sym_identifier] = ACTIONS(1),
+            [anon_sym_BANG] = ACTIONS(1),
+            [anon_sym_AMP_AMP] = ACTIONS(1),
+            [anon_sym_PIPE_PIPE] = ACTIONS(1),
+            [anon_sym_EQ_EQ] = ACTIONS(1),
+            [anon_sym_BANG_EQ] = ACTIONS(1),
+            [anon_sym_LPAREN] = ACTIONS(1),
+            [anon_sym_RPAREN] = ACTIONS(1),
+        },
+    [1] =
+        {
+            [sym_source] = STATE(15),
+            [sym__expression] = STATE(13),
+            [sym_not] = STATE(13),
+            [sym_and] = STATE(13),
+            [sym_or] = STATE(13),
+            [sym_equal] = STATE(13),
+            [sym_not_equal] = STATE(13),
+            [sym_parenthesized] = STATE(13),
+            [sym_identifier] = ACTIONS(3),
+            [anon_sym_BANG] = ACTIONS(5),
+            [anon_sym_LPAREN] = ACTIONS(7),
+        },
+    [2] =
+        {
+            [sym__expression] = STATE(7),
+            [sym_not] = STATE(7),
+            [sym_and] = STATE(7),
+            [sym_or] = STATE(7),
+            [sym_equal] = STATE(7),
+            [sym_not_equal] = STATE(7),
+            [sym_parenthesized] = STATE(7),
+            [sym_identifier] = ACTIONS(3),
+            [anon_sym_BANG] = ACTIONS(5),
+            [anon_sym_LPAREN] = ACTIONS(7),
+        },
+    [3] =
+        {
+            [sym__expression] = STATE(14),
+            [sym_not] = STATE(14),
+            [sym_and] = STATE(14),
+            [sym_or] = STATE(14),
+            [sym_equal] = STATE(14),
+            [sym_not_equal] = STATE(14),
+            [sym_parenthesized] = STATE(14),
+            [sym_identifier] = ACTIONS(3),
+            [anon_sym_BANG] = ACTIONS(5),
+            [anon_sym_LPAREN] = ACTIONS(7),
+        },
+    [4] =
+        {
+            [sym__expression] = STATE(11),
+            [sym_not] = STATE(11),
+            [sym_and] = STATE(11),
+            [sym_or] = STATE(11),
+            [sym_equal] = STATE(11),
+            [sym_not_equal] = STATE(11),
+            [sym_parenthesized] = STATE(11),
+            [sym_identifier] = ACTIONS(3),
+            [anon_sym_BANG] = ACTIONS(5),
+            [anon_sym_LPAREN] = ACTIONS(7),
+        },
+    [5] =
+        {
+            [sym__expression] = STATE(12),
+            [sym_not] = STATE(12),
+            [sym_and] = STATE(12),
+            [sym_or] = STATE(12),
+            [sym_equal] = STATE(12),
+            [sym_not_equal] = STATE(12),
+            [sym_parenthesized] = STATE(12),
+            [sym_identifier] = ACTIONS(3),
+            [anon_sym_BANG] = ACTIONS(5),
+            [anon_sym_LPAREN] = ACTIONS(7),
+        },
 };
 
 static const uint16_t ts_small_parse_table[] = {
-  [0] = 3,
-    ACTIONS(11), 1,
-      anon_sym_EQ_EQ,
-    ACTIONS(13), 1,
-      anon_sym_BANG_EQ,
-    ACTIONS(9), 4,
-      ts_builtin_sym_end,
-      anon_sym_AMP_AMP,
-      anon_sym_PIPE_PIPE,
-      anon_sym_RPAREN,
-  [13] = 1,
-    ACTIONS(15), 4,
-      ts_builtin_sym_end,
-      anon_sym_AMP_AMP,
-      anon_sym_PIPE_PIPE,
-      anon_sym_RPAREN,
-  [20] = 1,
-    ACTIONS(17), 4,
-      ts_builtin_sym_end,
-      anon_sym_AMP_AMP,
-      anon_sym_PIPE_PIPE,
-      anon_sym_RPAREN,
-  [27] = 1,
-    ACTIONS(19), 4,
-      ts_builtin_sym_end,
-      anon_sym_AMP_AMP,
-      anon_sym_PIPE_PIPE,
-      anon_sym_RPAREN,
-  [34] = 1,
-    ACTIONS(21), 4,
-      ts_builtin_sym_end,
-      anon_sym_AMP_AMP,
-      anon_sym_PIPE_PIPE,
-      anon_sym_RPAREN,
-  [41] = 1,
-    ACTIONS(23), 4,
-      ts_builtin_sym_end,
-      anon_sym_AMP_AMP,
-      anon_sym_PIPE_PIPE,
-      anon_sym_RPAREN,
-  [48] = 2,
-    ACTIONS(27), 1,
-      anon_sym_AMP_AMP,
-    ACTIONS(25), 3,
-      ts_builtin_sym_end,
-      anon_sym_PIPE_PIPE,
-      anon_sym_RPAREN,
-  [57] = 3,
-    ACTIONS(27), 1,
-      anon_sym_AMP_AMP,
-    ACTIONS(29), 1,
-      ts_builtin_sym_end,
-    ACTIONS(31), 1,
-      anon_sym_PIPE_PIPE,
-  [67] = 3,
-    ACTIONS(27), 1,
-      anon_sym_AMP_AMP,
-    ACTIONS(31), 1,
-      anon_sym_PIPE_PIPE,
-    ACTIONS(33), 1,
-      anon_sym_RPAREN,
-  [77] = 1,
-    ACTIONS(35), 1,
-      ts_builtin_sym_end,
-  [81] = 1,
-    ACTIONS(37), 1,
-      sym_identifier,
-  [85] = 1,
-    ACTIONS(39), 1,
-      sym_identifier,
+    [0] = 3,
+    ACTIONS(11),
+    1,
+    anon_sym_EQ_EQ,
+    ACTIONS(13),
+    1,
+    anon_sym_BANG_EQ,
+    ACTIONS(9),
+    4,
+    ts_builtin_sym_end,
+    anon_sym_AMP_AMP,
+    anon_sym_PIPE_PIPE,
+    anon_sym_RPAREN,
+    [13] = 1,
+    ACTIONS(15),
+    4,
+    ts_builtin_sym_end,
+    anon_sym_AMP_AMP,
+    anon_sym_PIPE_PIPE,
+    anon_sym_RPAREN,
+    [20] = 1,
+    ACTIONS(17),
+    4,
+    ts_builtin_sym_end,
+    anon_sym_AMP_AMP,
+    anon_sym_PIPE_PIPE,
+    anon_sym_RPAREN,
+    [27] = 1,
+    ACTIONS(19),
+    4,
+    ts_builtin_sym_end,
+    anon_sym_AMP_AMP,
+    anon_sym_PIPE_PIPE,
+    anon_sym_RPAREN,
+    [34] = 1,
+    ACTIONS(21),
+    4,
+    ts_builtin_sym_end,
+    anon_sym_AMP_AMP,
+    anon_sym_PIPE_PIPE,
+    anon_sym_RPAREN,
+    [41] = 1,
+    ACTIONS(23),
+    4,
+    ts_builtin_sym_end,
+    anon_sym_AMP_AMP,
+    anon_sym_PIPE_PIPE,
+    anon_sym_RPAREN,
+    [48] = 2,
+    ACTIONS(27),
+    1,
+    anon_sym_AMP_AMP,
+    ACTIONS(25),
+    3,
+    ts_builtin_sym_end,
+    anon_sym_PIPE_PIPE,
+    anon_sym_RPAREN,
+    [57] = 3,
+    ACTIONS(27),
+    1,
+    anon_sym_AMP_AMP,
+    ACTIONS(29),
+    1,
+    ts_builtin_sym_end,
+    ACTIONS(31),
+    1,
+    anon_sym_PIPE_PIPE,
+    [67] = 3,
+    ACTIONS(27),
+    1,
+    anon_sym_AMP_AMP,
+    ACTIONS(31),
+    1,
+    anon_sym_PIPE_PIPE,
+    ACTIONS(33),
+    1,
+    anon_sym_RPAREN,
+    [77] = 1,
+    ACTIONS(35),
+    1,
+    ts_builtin_sym_end,
+    [81] = 1,
+    ACTIONS(37),
+    1,
+    sym_identifier,
+    [85] = 1,
+    ACTIONS(39),
+    1,
+    sym_identifier,
 };
 
 static const uint32_t ts_small_parse_table_map[] = {
-  [SMALL_STATE(6)] = 0,
-  [SMALL_STATE(7)] = 13,
-  [SMALL_STATE(8)] = 20,
-  [SMALL_STATE(9)] = 27,
-  [SMALL_STATE(10)] = 34,
-  [SMALL_STATE(11)] = 41,
-  [SMALL_STATE(12)] = 48,
-  [SMALL_STATE(13)] = 57,
-  [SMALL_STATE(14)] = 67,
-  [SMALL_STATE(15)] = 77,
-  [SMALL_STATE(16)] = 81,
-  [SMALL_STATE(17)] = 85,
+    [SMALL_STATE(6)] = 0,   [SMALL_STATE(7)] = 13,  [SMALL_STATE(8)] = 20,
+    [SMALL_STATE(9)] = 27,  [SMALL_STATE(10)] = 34, [SMALL_STATE(11)] = 41,
+    [SMALL_STATE(12)] = 48, [SMALL_STATE(13)] = 57, [SMALL_STATE(14)] = 67,
+    [SMALL_STATE(15)] = 77, [SMALL_STATE(16)] = 81, [SMALL_STATE(17)] = 85,
 };
 
 static const TSParseActionEntry ts_parse_actions[] = {
-  [0] = {.entry = {.count = 0, .reusable = false}},
-  [1] = {.entry = {.count = 1, .reusable = false}}, RECOVER(),
-  [3] = {.entry = {.count = 1, .reusable = true}}, SHIFT(6),
-  [5] = {.entry = {.count = 1, .reusable = true}}, SHIFT(2),
-  [7] = {.entry = {.count = 1, .reusable = true}}, SHIFT(3),
-  [9] = {.entry = {.count = 1, .reusable = true}}, REDUCE(sym__expression, 1),
-  [11] = {.entry = {.count = 1, .reusable = true}}, SHIFT(16),
-  [13] = {.entry = {.count = 1, .reusable = true}}, SHIFT(17),
-  [15] = {.entry = {.count = 1, .reusable = true}}, REDUCE(sym_not, 2, .production_id = 1),
-  [17] = {.entry = {.count = 1, .reusable = true}}, REDUCE(sym_equal, 3, .production_id = 2),
-  [19] = {.entry = {.count = 1, .reusable = true}}, REDUCE(sym_not_equal, 3, .production_id = 2),
-  [21] = {.entry = {.count = 1, .reusable = true}}, REDUCE(sym_parenthesized, 3, .production_id = 1),
-  [23] = {.entry = {.count = 1, .reusable = true}}, REDUCE(sym_and, 3, .production_id = 2),
-  [25] = {.entry = {.count = 1, .reusable = true}}, REDUCE(sym_or, 3, .production_id = 2),
-  [27] = {.entry = {.count = 1, .reusable = true}}, SHIFT(4),
-  [29] = {.entry = {.count = 1, .reusable = true}}, REDUCE(sym_source, 1),
-  [31] = {.entry = {.count = 1, .reusable = true}}, SHIFT(5),
-  [33] = {.entry = {.count = 1, .reusable = true}}, SHIFT(10),
-  [35] = {.entry = {.count = 1, .reusable = true}},  ACCEPT_INPUT(),
-  [37] = {.entry = {.count = 1, .reusable = true}}, SHIFT(8),
-  [39] = {.entry = {.count = 1, .reusable = true}}, SHIFT(9),
+    [0] = {.entry = {.count = 0, .reusable = false}},
+    [1] = {.entry = {.count = 1, .reusable = false}},
+    RECOVER(),
+    [3] = {.entry = {.count = 1, .reusable = true}},
+    SHIFT(6),
+    [5] = {.entry = {.count = 1, .reusable = true}},
+    SHIFT(2),
+    [7] = {.entry = {.count = 1, .reusable = true}},
+    SHIFT(3),
+    [9] = {.entry = {.count = 1, .reusable = true}},
+    REDUCE(sym__expression, 1),
+    [11] = {.entry = {.count = 1, .reusable = true}},
+    SHIFT(16),
+    [13] = {.entry = {.count = 1, .reusable = true}},
+    SHIFT(17),
+    [15] = {.entry = {.count = 1, .reusable = true}},
+    REDUCE(sym_not, 2, .production_id = 1),
+    [17] = {.entry = {.count = 1, .reusable = true}},
+    REDUCE(sym_equal, 3, .production_id = 2),
+    [19] = {.entry = {.count = 1, .reusable = true}},
+    REDUCE(sym_not_equal, 3, .production_id = 2),
+    [21] = {.entry = {.count = 1, .reusable = true}},
+    REDUCE(sym_parenthesized, 3, .production_id = 1),
+    [23] = {.entry = {.count = 1, .reusable = true}},
+    REDUCE(sym_and, 3, .production_id = 2),
+    [25] = {.entry = {.count = 1, .reusable = true}},
+    REDUCE(sym_or, 3, .production_id = 2),
+    [27] = {.entry = {.count = 1, .reusable = true}},
+    SHIFT(4),
+    [29] = {.entry = {.count = 1, .reusable = true}},
+    REDUCE(sym_source, 1),
+    [31] = {.entry = {.count = 1, .reusable = true}},
+    SHIFT(5),
+    [33] = {.entry = {.count = 1, .reusable = true}},
+    SHIFT(10),
+    [35] = {.entry = {.count = 1, .reusable = true}},
+    ACCEPT_INPUT(),
+    [37] = {.entry = {.count = 1, .reusable = true}},
+    SHIFT(8),
+    [39] = {.entry = {.count = 1, .reusable = true}},
+    SHIFT(9),
 };
 
 #ifdef __cplusplus
@@ -497,30 +552,30 @@ extern "C" {
 
 extern const TSLanguage *tree_sitter_context_predicate(void) {
   static const TSLanguage language = {
-    .version = LANGUAGE_VERSION,
-    .symbol_count = SYMBOL_COUNT,
-    .alias_count = ALIAS_COUNT,
-    .token_count = TOKEN_COUNT,
-    .external_token_count = EXTERNAL_TOKEN_COUNT,
-    .state_count = STATE_COUNT,
-    .large_state_count = LARGE_STATE_COUNT,
-    .production_id_count = PRODUCTION_ID_COUNT,
-    .field_count = FIELD_COUNT,
-    .max_alias_sequence_length = MAX_ALIAS_SEQUENCE_LENGTH,
-    .parse_table = &ts_parse_table[0][0],
-    .small_parse_table = ts_small_parse_table,
-    .small_parse_table_map = ts_small_parse_table_map,
-    .parse_actions = ts_parse_actions,
-    .symbol_names = ts_symbol_names,
-    .field_names = ts_field_names,
-    .field_map_slices = ts_field_map_slices,
-    .field_map_entries = ts_field_map_entries,
-    .symbol_metadata = ts_symbol_metadata,
-    .public_symbol_map = ts_symbol_map,
-    .alias_map = ts_non_terminal_alias_map,
-    .alias_sequences = &ts_alias_sequences[0][0],
-    .lex_modes = ts_lex_modes,
-    .lex_fn = ts_lex,
+      .version = LANGUAGE_VERSION,
+      .symbol_count = SYMBOL_COUNT,
+      .alias_count = ALIAS_COUNT,
+      .token_count = TOKEN_COUNT,
+      .external_token_count = EXTERNAL_TOKEN_COUNT,
+      .state_count = STATE_COUNT,
+      .large_state_count = LARGE_STATE_COUNT,
+      .production_id_count = PRODUCTION_ID_COUNT,
+      .field_count = FIELD_COUNT,
+      .max_alias_sequence_length = MAX_ALIAS_SEQUENCE_LENGTH,
+      .parse_table = &ts_parse_table[0][0],
+      .small_parse_table = ts_small_parse_table,
+      .small_parse_table_map = ts_small_parse_table_map,
+      .parse_actions = ts_parse_actions,
+      .symbol_names = ts_symbol_names,
+      .field_names = ts_field_names,
+      .field_map_slices = ts_field_map_slices,
+      .field_map_entries = ts_field_map_entries,
+      .symbol_metadata = ts_symbol_metadata,
+      .public_symbol_map = ts_symbol_map,
+      .alias_map = ts_non_terminal_alias_map,
+      .alias_sequences = &ts_alias_sequences[0][0],
+      .lex_modes = ts_lex_modes,
+      .lex_fn = ts_lex,
   };
   return &language;
 }

crates/gpui/src/app.rs 🔗

@@ -55,8 +55,8 @@ pub trait Entity: 'static {
 pub trait View: Entity + Sized {
     fn ui_name() -> &'static str;
     fn render(&mut self, cx: &mut RenderContext<'_, Self>) -> ElementBox;
-    fn on_focus(&mut self, _: &mut ViewContext<Self>) {}
-    fn on_blur(&mut self, _: &mut ViewContext<Self>) {}
+    fn on_focus_in(&mut self, _: AnyViewHandle, _: &mut ViewContext<Self>) {}
+    fn on_focus_out(&mut self, _: AnyViewHandle, _: &mut ViewContext<Self>) {}
     fn keymap_context(&self, _: &AppContext) -> keymap::Context {
         Self::default_keymap_context()
     }
@@ -1903,7 +1903,7 @@ impl MutableAppContext {
                     is_fullscreen: false,
                 },
             );
-            root_view.update(this, |view, cx| view.on_focus(cx));
+            root_view.update(this, |view, cx| view.on_focus_in(cx.handle().into(), cx));
             this.open_platform_window(window_id, window_options);
 
             (window_id, root_view)
@@ -2500,14 +2500,16 @@ impl MutableAppContext {
             window.is_active = active;
 
             //Handle focus
-            let view_id = window.focused_view_id?;
-            if let Some(mut view) = this.cx.views.remove(&(window_id, view_id)) {
-                if active {
-                    view.on_focus(this, window_id, view_id);
-                } else {
-                    view.on_blur(this, window_id, view_id);
+            let focused_id = window.focused_view_id?;
+            for view_id in this.parents(window_id, focused_id).collect::<Vec<_>>() {
+                if let Some(mut view) = this.cx.views.remove(&(window_id, view_id)) {
+                    if active {
+                        view.on_focus_in(this, window_id, view_id, focused_id);
+                    } else {
+                        view.on_focus_out(this, window_id, view_id, focused_id);
+                    }
+                    this.cx.views.insert((window_id, view_id), view);
                 }
-                this.cx.views.insert((window_id, view_id), view);
             }
 
             let mut observations = this.window_activation_observations.clone();
@@ -2537,26 +2539,45 @@ impl MutableAppContext {
                 blurred_id
             });
 
+            let blurred_parents = blurred_id
+                .map(|blurred_id| this.parents(window_id, blurred_id).collect::<Vec<_>>())
+                .unwrap_or_default();
+            let focused_parents = focused_id
+                .map(|focused_id| this.parents(window_id, focused_id).collect::<Vec<_>>())
+                .unwrap_or_default();
+
             if let Some(blurred_id) = blurred_id {
-                if let Some(mut blurred_view) = this.cx.views.remove(&(window_id, blurred_id)) {
-                    blurred_view.on_blur(this, window_id, blurred_id);
-                    this.cx.views.insert((window_id, blurred_id), blurred_view);
+                for view_id in blurred_parents.iter().copied() {
+                    // We've reached a common anscestor. Break.
+                    if focused_parents.contains(&view_id) {
+                        break;
+                    }
 
-                    let mut subscriptions = this.focus_observations.clone();
-                    subscriptions
-                        .emit_and_cleanup(blurred_id, this, |callback, this| callback(false, this));
+                    if let Some(mut view) = this.cx.views.remove(&(window_id, view_id)) {
+                        view.on_focus_out(this, window_id, view_id, blurred_id);
+                        this.cx.views.insert((window_id, view_id), view);
+                    }
                 }
+
+                let mut subscriptions = this.focus_observations.clone();
+                subscriptions
+                    .emit_and_cleanup(blurred_id, this, |callback, this| callback(false, this));
             }
 
             if let Some(focused_id) = focused_id {
-                if let Some(mut focused_view) = this.cx.views.remove(&(window_id, focused_id)) {
-                    focused_view.on_focus(this, window_id, focused_id);
-                    this.cx.views.insert((window_id, focused_id), focused_view);
-
-                    let mut subscriptions = this.focus_observations.clone();
-                    subscriptions
-                        .emit_and_cleanup(focused_id, this, |callback, this| callback(true, this));
+                for view_id in focused_parents {
+                    if blurred_parents.contains(&view_id) {
+                        break;
+                    }
+                    if let Some(mut view) = this.cx.views.remove(&(window_id, view_id)) {
+                        view.on_focus_in(this, window_id, view_id, focused_id);
+                        this.cx.views.insert((window_id, focused_id), view);
+                    }
                 }
+
+                let mut subscriptions = this.focus_observations.clone();
+                subscriptions
+                    .emit_and_cleanup(focused_id, this, |callback, this| callback(true, this));
             }
         })
     }
@@ -2742,7 +2763,7 @@ impl ReadView for MutableAppContext {
         if let Some(view) = self.cx.views.get(&(handle.window_id, handle.view_id)) {
             view.as_any().downcast_ref().expect("downcast is type safe")
         } else {
-            panic!("circular view reference");
+            panic!("circular view reference for type {}", type_name::<T>());
         }
     }
 }
@@ -3216,8 +3237,20 @@ pub trait AnyView {
     ) -> Option<Pin<Box<dyn 'static + Future<Output = ()>>>>;
     fn ui_name(&self) -> &'static str;
     fn render<'a>(&mut self, params: RenderParams, cx: &mut MutableAppContext) -> ElementBox;
-    fn on_focus(&mut self, cx: &mut MutableAppContext, window_id: usize, view_id: usize);
-    fn on_blur(&mut self, cx: &mut MutableAppContext, window_id: usize, view_id: usize);
+    fn on_focus_in(
+        &mut self,
+        cx: &mut MutableAppContext,
+        window_id: usize,
+        view_id: usize,
+        focused_id: usize,
+    );
+    fn on_focus_out(
+        &mut self,
+        cx: &mut MutableAppContext,
+        window_id: usize,
+        view_id: usize,
+        focused_id: usize,
+    );
     fn keymap_context(&self, cx: &AppContext) -> keymap::Context;
     fn debug_json(&self, cx: &AppContext) -> serde_json::Value;
 
@@ -3242,6 +3275,14 @@ pub trait AnyView {
         window_id: usize,
         view_id: usize,
     );
+    fn any_handle(&self, window_id: usize, view_id: usize, cx: &AppContext) -> AnyViewHandle {
+        AnyViewHandle::new(
+            window_id,
+            view_id,
+            self.as_any().type_id(),
+            cx.ref_counts.clone(),
+        )
+    }
 }
 
 impl<T> AnyView for T
@@ -3275,14 +3316,48 @@ where
         View::render(self, &mut RenderContext::new(params, cx))
     }
 
-    fn on_focus(&mut self, cx: &mut MutableAppContext, window_id: usize, view_id: usize) {
+    fn on_focus_in(
+        &mut self,
+        cx: &mut MutableAppContext,
+        window_id: usize,
+        view_id: usize,
+        focused_id: usize,
+    ) {
         let mut cx = ViewContext::new(cx, window_id, view_id);
-        View::on_focus(self, &mut cx);
+        let focused_view_handle: AnyViewHandle = if view_id == focused_id {
+            cx.handle().into()
+        } else {
+            let focused_type = cx
+                .views
+                .get(&(window_id, focused_id))
+                .unwrap()
+                .as_any()
+                .type_id();
+            AnyViewHandle::new(window_id, focused_id, focused_type, cx.ref_counts.clone())
+        };
+        View::on_focus_in(self, focused_view_handle, &mut cx);
     }
 
-    fn on_blur(&mut self, cx: &mut MutableAppContext, window_id: usize, view_id: usize) {
+    fn on_focus_out(
+        &mut self,
+        cx: &mut MutableAppContext,
+        window_id: usize,
+        view_id: usize,
+        blurred_id: usize,
+    ) {
         let mut cx = ViewContext::new(cx, window_id, view_id);
-        View::on_blur(self, &mut cx);
+        let blurred_view_handle: AnyViewHandle = if view_id == blurred_id {
+            cx.handle().into()
+        } else {
+            let blurred_type = cx
+                .views
+                .get(&(window_id, blurred_id))
+                .unwrap()
+                .as_any()
+                .type_id();
+            AnyViewHandle::new(window_id, blurred_id, blurred_type, cx.ref_counts.clone())
+        };
+        View::on_focus_out(self, blurred_view_handle, &mut cx);
     }
 
     fn keymap_context(&self, cx: &AppContext) -> keymap::Context {
@@ -6665,12 +6740,16 @@ mod tests {
                 "View"
             }
 
-            fn on_focus(&mut self, _: &mut ViewContext<Self>) {
-                self.events.lock().push(format!("{} focused", &self.name));
+            fn on_focus_in(&mut self, focused: AnyViewHandle, cx: &mut ViewContext<Self>) {
+                if cx.handle().id() == focused.id() {
+                    self.events.lock().push(format!("{} focused", &self.name));
+                }
             }
 
-            fn on_blur(&mut self, _: &mut ViewContext<Self>) {
-                self.events.lock().push(format!("{} blurred", &self.name));
+            fn on_focus_out(&mut self, blurred: AnyViewHandle, cx: &mut ViewContext<Self>) {
+                if cx.handle().id() == blurred.id() {
+                    self.events.lock().push(format!("{} blurred", &self.name));
+                }
             }
         }
 
@@ -7018,7 +7097,7 @@ mod tests {
 
         let (window_id, view_1) = cx.add_window(Default::default(), |_| view_1);
         let view_2 = cx.add_view(&view_1, |_| view_2);
-        let view_3 = cx.add_view(&view_2, |cx| {
+        cx.add_view(&view_2, |cx| {
             cx.focus_self();
             view_3
         });

crates/outline/src/outline.rs 🔗

@@ -4,8 +4,8 @@ use editor::{
 };
 use fuzzy::StringMatch;
 use gpui::{
-    actions, elements::*, geometry::vector::Vector2F, AppContext, Entity, MouseState,
-    MutableAppContext, RenderContext, Task, View, ViewContext, ViewHandle,
+    actions, elements::*, geometry::vector::Vector2F, AnyViewHandle, AppContext, Entity,
+    MouseState, MutableAppContext, RenderContext, Task, View, ViewContext, ViewHandle,
 };
 use language::Outline;
 use ordered_float::OrderedFloat;
@@ -52,7 +52,7 @@ impl View for OutlineView {
         ChildView::new(self.picker.clone()).boxed()
     }
 
-    fn on_focus(&mut self, cx: &mut ViewContext<Self>) {
+    fn on_focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
         cx.focus(&self.picker);
     }
 }

crates/picker/src/picker.rs 🔗

@@ -7,8 +7,8 @@ use gpui::{
     geometry::vector::{vec2f, Vector2F},
     keymap,
     platform::CursorStyle,
-    AppContext, Axis, Element, ElementBox, Entity, MouseButton, MouseState, MutableAppContext,
-    RenderContext, Task, View, ViewContext, ViewHandle, WeakViewHandle,
+    AnyViewHandle, AppContext, Axis, Element, ElementBox, Entity, MouseButton, MouseState,
+    MutableAppContext, RenderContext, Task, View, ViewContext, ViewHandle, WeakViewHandle,
 };
 use menu::{Cancel, Confirm, SelectFirst, SelectIndex, SelectLast, SelectNext, SelectPrev};
 use settings::Settings;
@@ -118,7 +118,7 @@ impl<D: PickerDelegate> View for Picker<D> {
         cx
     }
 
-    fn on_focus(&mut self, cx: &mut ViewContext<Self>) {
+    fn on_focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
         cx.focus(&self.query_editor);
     }
 }

crates/project_symbols/src/project_symbols.rs 🔗

@@ -3,8 +3,8 @@ use editor::{
 };
 use fuzzy::{StringMatch, StringMatchCandidate};
 use gpui::{
-    actions, elements::*, AppContext, Entity, ModelHandle, MouseState, MutableAppContext,
-    RenderContext, Task, View, ViewContext, ViewHandle,
+    actions, elements::*, AnyViewHandle, AppContext, Entity, ModelHandle, MouseState,
+    MutableAppContext, RenderContext, Task, View, ViewContext, ViewHandle,
 };
 use ordered_float::OrderedFloat;
 use picker::{Picker, PickerDelegate};
@@ -51,7 +51,7 @@ impl View for ProjectSymbolsView {
         ChildView::new(self.picker.clone()).boxed()
     }
 
-    fn on_focus(&mut self, cx: &mut ViewContext<Self>) {
+    fn on_focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
         cx.focus(&self.picker);
     }
 }

crates/search/src/buffer_search.rs 🔗

@@ -6,8 +6,8 @@ use crate::{
 use collections::HashMap;
 use editor::{Anchor, Autoscroll, Editor};
 use gpui::{
-    actions, elements::*, impl_actions, platform::CursorStyle, Action, AppContext, Entity,
-    MouseButton, MutableAppContext, RenderContext, Subscription, Task, View, ViewContext,
+    actions, elements::*, impl_actions, platform::CursorStyle, Action, AnyViewHandle, AppContext,
+    Entity, MouseButton, MutableAppContext, RenderContext, Subscription, Task, View, ViewContext,
     ViewHandle, WeakViewHandle,
 };
 use language::OffsetRangeExt;
@@ -80,7 +80,7 @@ impl View for BufferSearchBar {
         "BufferSearchBar"
     }
 
-    fn on_focus(&mut self, cx: &mut ViewContext<Self>) {
+    fn on_focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
         cx.focus(&self.query_editor);
     }
 

crates/search/src/project_search.rs 🔗

@@ -6,9 +6,9 @@ use crate::{
 use collections::HashMap;
 use editor::{Anchor, Autoscroll, Editor, MultiBuffer, SelectAll, MAX_TAB_TITLE_LEN};
 use gpui::{
-    actions, elements::*, platform::CursorStyle, Action, AppContext, ElementBox, Entity,
-    ModelContext, ModelHandle, MouseButton, MutableAppContext, RenderContext, Subscription, Task,
-    View, ViewContext, ViewHandle, WeakModelHandle, WeakViewHandle,
+    actions, elements::*, platform::CursorStyle, Action, AnyViewHandle, AppContext, ElementBox,
+    Entity, ModelContext, ModelHandle, MouseButton, MutableAppContext, RenderContext, Subscription,
+    Task, View, ViewContext, ViewHandle, WeakModelHandle, WeakViewHandle,
 };
 use menu::Confirm;
 use project::{search::SearchQuery, Project};
@@ -190,7 +190,7 @@ impl View for ProjectSearchView {
         }
     }
 
-    fn on_focus(&mut self, cx: &mut ViewContext<Self>) {
+    fn on_focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
         let handle = cx.weak_handle();
         cx.update_global(|state: &mut ActiveSearches, cx| {
             state

crates/terminal/src/connected_view.rs 🔗

@@ -6,7 +6,8 @@ use gpui::{
     geometry::vector::Vector2F,
     impl_internal_actions,
     keymap::Keystroke,
-    AppContext, Element, ElementBox, ModelHandle, MutableAppContext, View, ViewContext, ViewHandle,
+    AnyViewHandle, AppContext, Element, ElementBox, ModelHandle, MutableAppContext, View,
+    ViewContext, ViewHandle,
 };
 use workspace::pane;
 
@@ -190,7 +191,7 @@ impl View for ConnectedView {
             .boxed()
     }
 
-    fn on_focus(&mut self, _cx: &mut ViewContext<Self>) {
+    fn on_focus_in(&mut self, _: AnyViewHandle, _cx: &mut ViewContext<Self>) {
         self.has_new_content = false;
     }
 

crates/terminal/src/terminal.rs 🔗

@@ -161,6 +161,13 @@ impl Dimensions for TerminalSize {
     fn columns(&self) -> usize {
         self.num_columns()
     }
+
+    fn on_focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
+        cx.emit(Event::Activate);
+        cx.defer(|view, cx| {
+            cx.focus(view.content.handle());
+        });
+    }
 }
 
 #[derive(Error, Debug)]

crates/theme_selector/src/theme_selector.rs 🔗

@@ -1,7 +1,7 @@
 use fuzzy::{match_strings, StringMatch, StringMatchCandidate};
 use gpui::{
-    actions, elements::*, AppContext, Element, ElementBox, Entity, MouseState, MutableAppContext,
-    RenderContext, View, ViewContext, ViewHandle,
+    actions, elements::*, AnyViewHandle, AppContext, Element, ElementBox, Entity, MouseState,
+    MutableAppContext, RenderContext, View, ViewContext, ViewHandle,
 };
 use picker::{Picker, PickerDelegate};
 use settings::Settings;
@@ -249,7 +249,7 @@ impl View for ThemeSelector {
         ChildView::new(self.picker.clone()).boxed()
     }
 
-    fn on_focus(&mut self, cx: &mut ViewContext<Self>) {
+    fn on_focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
         cx.focus(&self.picker);
     }
 }

crates/workspace/src/pane.rs 🔗

@@ -13,9 +13,9 @@ use gpui::{
     },
     impl_actions, impl_internal_actions,
     platform::{CursorStyle, NavigationDirection},
-    AppContext, AsyncAppContext, Entity, EventContext, ModelHandle, MouseButton, MouseButtonEvent,
-    MutableAppContext, PromptLevel, Quad, RenderContext, Task, View, ViewContext, ViewHandle,
-    WeakViewHandle,
+    AnyViewHandle, AppContext, AsyncAppContext, Entity, EventContext, ModelHandle, MouseButton,
+    MouseButtonEvent, MutableAppContext, PromptLevel, Quad, RenderContext, Task, View, ViewContext,
+    ViewHandle, WeakViewHandle,
 };
 use project::{Project, ProjectEntryId, ProjectPath};
 use serde::Deserialize;
@@ -830,6 +830,7 @@ impl Pane {
     pub fn focus_active_item(&mut self, cx: &mut ViewContext<Self>) {
         if let Some(active_item) = self.active_item() {
             cx.focus(active_item);
+            self.activate(cx);
         }
     }
 
@@ -1210,8 +1211,12 @@ impl View for Pane {
             .named("pane")
     }
 
-    fn on_focus(&mut self, cx: &mut ViewContext<Self>) {
-        self.focus_active_item(cx);
+    fn on_focus_in(&mut self, focused: AnyViewHandle, cx: &mut ViewContext<Self>) {
+        if cx.handle().id() == focused.id() {
+            self.focus_active_item(cx);
+        } else {
+            self.activate(cx);
+        }
     }
 }
 

crates/workspace/src/workspace.rs 🔗

@@ -2489,7 +2489,7 @@ impl View for Workspace {
             .named("workspace")
     }
 
-    fn on_focus(&mut self, cx: &mut ViewContext<Self>) {
+    fn on_focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
         cx.focus(&self.active_pane);
     }
 }

styles/package-lock.json 🔗

@@ -5,6 +5,7 @@
   "requires": true,
   "packages": {
     "": {
+      "name": "styles",
       "version": "1.0.0",
       "license": "ISC",
       "dependencies": {