Merge branch 'main' into document-theme

Nate Butler created

Change summary

Cargo.lock                                       |  18 
Cargo.toml                                       |   1 
crates/editor2/src/display_map.rs                | 100 +-
crates/editor2/src/editor.rs                     | 778 +++++++++--------
crates/editor2/src/element.rs                    |  85 +
crates/editor2/src/highlight_matching_bracket.rs |   2 
crates/editor2/src/movement.rs                   |   7 
crates/editor2/src/scroll.rs                     |  10 
crates/go_to_line2/Cargo.toml                    |  25 
crates/go_to_line2/src/go_to_line.rs             | 224 +++++
crates/gpui2/src/action.rs                       |   4 
crates/gpui2/src/app.rs                          |  14 
crates/gpui2/src/window.rs                       |  17 
crates/language2/src/highlight_map.rs            |   2 
crates/settings2/src/settings_file.rs            |  49 +
crates/theme2/src/colors.rs                      |   4 
crates/theme2/src/default_colors.rs              |   4 
crates/theme2/src/default_theme.rs               |   6 
crates/theme2/src/registry.rs                    |   7 
crates/theme2/src/syntax.rs                      |   4 
crates/theme2/src/theme2.rs                      |  23 
crates/theme2/src/themes/andromeda.rs            |   3 
crates/theme2/src/themes/ayu.rs                  |   3 
crates/theme2/src/themes/dracula.rs              |   3 
crates/theme2/src/themes/gruvbox.rs              |   3 
crates/theme2/src/themes/mod.rs                  |   5 
crates/theme2/src/themes/night_owl.rs            |   3 
crates/theme2/src/themes/nord.rs                 |   3 
crates/theme2/src/themes/notctis.rs              |   3 
crates/theme2/src/themes/palenight.rs            |   3 
crates/theme2/src/themes/rose_pine.rs            |   3 
crates/theme2/src/themes/solarized.rs            |   3 
crates/theme2/src/themes/synthwave_84.rs         |   3 
crates/theme_importer/src/main.rs                |  27 
crates/workspace2/src/modal_layer.rs             | 121 ++
crates/workspace2/src/workspace2.rs              |  94 -
crates/zed2/Cargo.toml                           |   2 
crates/zed2/src/main.rs                          |  30 
38 files changed, 1,116 insertions(+), 580 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -3529,6 +3529,23 @@ dependencies = [
  "workspace",
 ]
 
+[[package]]
+name = "go_to_line2"
+version = "0.1.0"
+dependencies = [
+ "editor2",
+ "gpui2",
+ "menu2",
+ "postage",
+ "serde",
+ "settings2",
+ "text2",
+ "theme2",
+ "ui2",
+ "util",
+ "workspace2",
+]
+
 [[package]]
 name = "gpui"
 version = "0.1.0"
@@ -11224,6 +11241,7 @@ dependencies = [
  "fsevent",
  "futures 0.3.28",
  "fuzzy",
+ "go_to_line2",
  "gpui2",
  "ignore",
  "image",

Cargo.toml 🔗

@@ -42,6 +42,7 @@ members = [
     "crates/fuzzy2",
     "crates/git",
     "crates/go_to_line",
+    "crates/go_to_line2",
     "crates/gpui",
     "crates/gpui_macros",
     "crates/gpui2",

crates/editor2/src/display_map.rs 🔗

@@ -12,7 +12,9 @@ use crate::{
 pub use block_map::{BlockMap, BlockPoint};
 use collections::{BTreeMap, HashMap, HashSet};
 use fold_map::FoldMap;
-use gpui::{Font, FontId, HighlightStyle, Hsla, Line, Model, ModelContext, Pixels, UnderlineStyle};
+use gpui::{
+    Font, FontId, HighlightStyle, Hsla, Line, Model, ModelContext, Pixels, TextRun, UnderlineStyle,
+};
 use inlay_map::InlayMap;
 use language::{
     language_settings::language_settings, OffsetUtf16, Point, Subscription as BufferSubscription,
@@ -21,7 +23,7 @@ use lsp::DiagnosticSeverity;
 use std::{any::TypeId, borrow::Cow, fmt::Debug, num::NonZeroU32, ops::Range, sync::Arc};
 use sum_tree::{Bias, TreeMap};
 use tab_map::TabMap;
-use theme::Theme;
+use theme::{SyntaxTheme, Theme};
 use wrap_map::WrapMap;
 
 pub use block_map::{
@@ -505,18 +507,18 @@ impl DisplaySnapshot {
         &'a self,
         display_rows: Range<u32>,
         language_aware: bool,
-        theme: &'a Theme,
+        editor_style: &'a EditorStyle,
     ) -> impl Iterator<Item = HighlightedChunk<'a>> {
         self.chunks(
             display_rows,
             language_aware,
-            None, // todo!("add inlay highlight style")
-            None, // todo!("add suggestion highlight style")
+            Some(editor_style.syntax.inlay_style),
+            Some(editor_style.syntax.suggestion_style),
         )
         .map(|chunk| {
             let mut highlight_style = chunk
                 .syntax_highlight_id
-                .and_then(|id| id.style(&theme.styles.syntax));
+                .and_then(|id| id.style(&editor_style.syntax));
 
             if let Some(chunk_highlight) = chunk.highlight_style {
                 if let Some(highlight_style) = highlight_style.as_mut() {
@@ -535,7 +537,8 @@ impl DisplaySnapshot {
             if let Some(severity) = chunk.diagnostic_severity {
                 // Omit underlines for HINT/INFO diagnostics on 'unnecessary' code.
                 if severity <= DiagnosticSeverity::WARNING || !chunk.is_unnecessary {
-                    let diagnostic_color = super::diagnostic_style(severity, true, theme);
+                    let diagnostic_color =
+                        super::diagnostic_style(severity, true, &editor_style.diagnostic_style);
                     diagnostic_highlight.underline = Some(UnderlineStyle {
                         color: Some(diagnostic_color),
                         thickness: 1.0.into(),
@@ -564,53 +567,46 @@ impl DisplaySnapshot {
         TextLayoutDetails {
             text_system,
             editor_style,
+            rem_size,
         }: &TextLayoutDetails,
     ) -> Line {
-        todo!()
-        // let mut styles = Vec::new();
-        // let mut line = String::new();
-        // let mut ended_in_newline = false;
-
-        // let range = display_row..display_row + 1;
-        // for chunk in self.highlighted_chunks(range, false, editor_style) {
-        //     line.push_str(chunk.chunk);
-
-        //     let text_style = if let Some(style) = chunk.style {
-        //         editor_style
-        //             .text
-        //             .clone()
-        //             .highlight(style, text_system)
-        //             .map(Cow::Owned)
-        //             .unwrap_or_else(|_| Cow::Borrowed(&editor_style.text))
-        //     } else {
-        //         Cow::Borrowed(&editor_style.text)
-        //     };
-        //     ended_in_newline = chunk.chunk.ends_with("\n");
-
-        //     styles.push(
-        //         todo!(), // len: chunk.chunk.len(),
-        //                  // font_id: text_style.font_id,
-        //                  // color: text_style.color,
-        //                  // underline: text_style.underline,
-        //     );
-        // }
-
-        // // our pixel positioning logic assumes each line ends in \n,
-        // // this is almost always true except for the last line which
-        // // may have no trailing newline.
-        // if !ended_in_newline && display_row == self.max_point().row() {
-        //     line.push_str("\n");
-
-        //     todo!();
-        //     // styles.push(RunStyle {
-        //     //     len: "\n".len(),
-        //     //     font_id: editor_style.text.font_id,
-        //     //     color: editor_style.text_color,
-        //     //     underline: editor_style.text.underline,
-        //     // });
-        // }
-
-        // text_system.layout_text(&line, editor_style.text.font_size, &styles, None)
+        let mut runs = Vec::new();
+        let mut line = String::new();
+        let mut ended_in_newline = false;
+
+        let range = display_row..display_row + 1;
+        for chunk in self.highlighted_chunks(range, false, &editor_style) {
+            line.push_str(chunk.chunk);
+
+            let text_style = if let Some(style) = chunk.style {
+                editor_style
+                    .text
+                    .clone()
+                    .highlight(style)
+                    .map(Cow::Owned)
+                    .unwrap_or_else(|_| Cow::Borrowed(&editor_style.text))
+            } else {
+                Cow::Borrowed(&editor_style.text)
+            };
+            ended_in_newline = chunk.chunk.ends_with("\n");
+
+            runs.push(text_style.to_run(chunk.chunk.len()))
+        }
+
+        // our pixel positioning logic assumes each line ends in \n,
+        // this is almost always true except for the last line which
+        // may have no trailing newline.
+        if !ended_in_newline && display_row == self.max_point().row() {
+            line.push_str("\n");
+            runs.push(editor_style.text.to_run("\n".len()));
+        }
+
+        let font_size = editor_style.text.font_size.to_pixels(*rem_size);
+        text_system
+            .layout_text(&line, font_size, &runs, None)
+            .unwrap()
+            .pop()
+            .unwrap()
     }
 
     pub fn x_for_point(

crates/editor2/src/editor.rs 🔗

@@ -36,9 +36,10 @@ pub use element::{
 use futures::FutureExt;
 use fuzzy::{StringMatch, StringMatchCandidate};
 use gpui::{
-    div, px, AnyElement, AppContext, BackgroundExecutor, Context, Div, Element, Entity,
-    EventEmitter, FocusHandle, FontStyle, FontWeight, Hsla, Model, Pixels, Render, Styled,
-    Subscription, Task, TextStyle, View, ViewContext, VisualContext, WeakView, WindowContext,
+    actions, div, px, AnyElement, AppContext, BackgroundExecutor, Context, DispatchContext, Div,
+    Element, Entity, EventEmitter, FocusHandle, FontStyle, FontWeight, Hsla, Model, Pixels, Render,
+    Styled, Subscription, Task, TextStyle, View, ViewContext, VisualContext, WeakView,
+    WindowContext,
 };
 use highlight_matching_bracket::refresh_matching_bracket_highlights;
 use hover_popover::{hide_hover, HoverState};
@@ -54,6 +55,7 @@ use language::{
 };
 use link_go_to_definition::{GoToDefinitionLink, InlayHighlight, LinkGoToDefinitionState};
 use lsp::{DiagnosticSeverity, Documentation, LanguageServerId};
+use movement::TextLayoutDetails;
 pub use multi_buffer::{
     Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, ToOffset,
     ToPoint,
@@ -81,7 +83,9 @@ use std::{
 pub use sum_tree::Bias;
 use sum_tree::TreeMap;
 use text::Rope;
-use theme::{ActiveTheme, PlayerColor, Theme, ThemeColors, ThemeSettings};
+use theme::{
+    ActiveTheme, DiagnosticStyle, PlayerColor, SyntaxTheme, Theme, ThemeColors, ThemeSettings,
+};
 use util::{post_inc, RangeExt, ResultExt, TryFutureExt};
 use workspace::{ItemNavHistory, SplitDirection, ViewId, Workspace};
 
@@ -256,118 +260,115 @@ impl InlayId {
     }
 }
 
-// actions!(
-//     editor,
-//     [
-//         Cancel,
-//         Backspace,
-//         Delete,
-//         Newline,
-//         NewlineAbove,
-//         NewlineBelow,
-//         GoToDiagnostic,
-//         GoToPrevDiagnostic,
-//         GoToHunk,
-//         GoToPrevHunk,
-//         Indent,
-//         Outdent,
-//         DeleteLine,
-//         DeleteToPreviousWordStart,
-//         DeleteToPreviousSubwordStart,
-//         DeleteToNextWordEnd,
-//         DeleteToNextSubwordEnd,
-//         DeleteToBeginningOfLine,
-//         DeleteToEndOfLine,
-//         CutToEndOfLine,
-//         DuplicateLine,
-//         MoveLineUp,
-//         MoveLineDown,
-//         JoinLines,
-//         SortLinesCaseSensitive,
-//         SortLinesCaseInsensitive,
-//         ReverseLines,
-//         ShuffleLines,
-//         ConvertToUpperCase,
-//         ConvertToLowerCase,
-//         ConvertToTitleCase,
-//         ConvertToSnakeCase,
-//         ConvertToKebabCase,
-//         ConvertToUpperCamelCase,
-//         ConvertToLowerCamelCase,
-//         Transpose,
-//         Cut,
-//         Copy,
-//         Paste,
-//         Undo,
-//         Redo,
-//         MoveUp,
-//         PageUp,
-//         MoveDown,
-//         PageDown,
-//         MoveLeft,
-//         MoveRight,
-//         MoveToPreviousWordStart,
-//         MoveToPreviousSubwordStart,
-//         MoveToNextWordEnd,
-//         MoveToNextSubwordEnd,
-//         MoveToBeginningOfLine,
-//         MoveToEndOfLine,
-//         MoveToStartOfParagraph,
-//         MoveToEndOfParagraph,
-//         MoveToBeginning,
-//         MoveToEnd,
-//         SelectUp,
-//         SelectDown,
-//         SelectLeft,
-//         SelectRight,
-//         SelectToPreviousWordStart,
-//         SelectToPreviousSubwordStart,
-//         SelectToNextWordEnd,
-//         SelectToNextSubwordEnd,
-//         SelectToStartOfParagraph,
-//         SelectToEndOfParagraph,
-//         SelectToBeginning,
-//         SelectToEnd,
-//         SelectAll,
-//         SelectLine,
-//         SplitSelectionIntoLines,
-//         AddSelectionAbove,
-//         AddSelectionBelow,
-//         Tab,
-//         TabPrev,
-//         ShowCharacterPalette,
-//         SelectLargerSyntaxNode,
-//         SelectSmallerSyntaxNode,
-//         GoToDefinition,
-//         GoToDefinitionSplit,
-//         GoToTypeDefinition,
-//         GoToTypeDefinitionSplit,
-//         MoveToEnclosingBracket,
-//         UndoSelection,
-//         RedoSelection,
-//         FindAllReferences,
-//         Rename,
-//         ConfirmRename,
-//         Fold,
-//         UnfoldLines,
-//         FoldSelectedRanges,
-//         ShowCompletions,
-//         OpenExcerpts,
-//         RestartLanguageServer,
-//         Hover,
-//         Format,
-//         ToggleSoftWrap,
-//         ToggleInlayHints,
-//         RevealInFinder,
-//         CopyPath,
-//         CopyRelativePath,
-//         CopyHighlightJson,
-//         ContextMenuFirst,
-//         ContextMenuPrev,
-//         ContextMenuNext,
-//         ContextMenuLast,
-//     ]
-// );
+actions!(
+    Cancel,
+    Backspace,
+    Delete,
+    Newline,
+    NewlineAbove,
+    NewlineBelow,
+    GoToDiagnostic,
+    GoToPrevDiagnostic,
+    GoToHunk,
+    GoToPrevHunk,
+    Indent,
+    Outdent,
+    DeleteLine,
+    DeleteToPreviousWordStart,
+    DeleteToPreviousSubwordStart,
+    DeleteToNextWordEnd,
+    DeleteToNextSubwordEnd,
+    DeleteToBeginningOfLine,
+    DeleteToEndOfLine,
+    CutToEndOfLine,
+    DuplicateLine,
+    MoveLineUp,
+    MoveLineDown,
+    JoinLines,
+    SortLinesCaseSensitive,
+    SortLinesCaseInsensitive,
+    ReverseLines,
+    ShuffleLines,
+    ConvertToUpperCase,
+    ConvertToLowerCase,
+    ConvertToTitleCase,
+    ConvertToSnakeCase,
+    ConvertToKebabCase,
+    ConvertToUpperCamelCase,
+    ConvertToLowerCamelCase,
+    Transpose,
+    Cut,
+    Copy,
+    Paste,
+    Undo,
+    Redo,
+    MoveUp,
+    PageUp,
+    MoveDown,
+    PageDown,
+    MoveLeft,
+    MoveRight,
+    MoveToPreviousWordStart,
+    MoveToPreviousSubwordStart,
+    MoveToNextWordEnd,
+    MoveToNextSubwordEnd,
+    MoveToBeginningOfLine,
+    MoveToEndOfLine,
+    MoveToStartOfParagraph,
+    MoveToEndOfParagraph,
+    MoveToBeginning,
+    MoveToEnd,
+    SelectUp,
+    SelectDown,
+    SelectLeft,
+    SelectRight,
+    SelectToPreviousWordStart,
+    SelectToPreviousSubwordStart,
+    SelectToNextWordEnd,
+    SelectToNextSubwordEnd,
+    SelectToStartOfParagraph,
+    SelectToEndOfParagraph,
+    SelectToBeginning,
+    SelectToEnd,
+    SelectAll,
+    SelectLine,
+    SplitSelectionIntoLines,
+    AddSelectionAbove,
+    AddSelectionBelow,
+    Tab,
+    TabPrev,
+    ShowCharacterPalette,
+    SelectLargerSyntaxNode,
+    SelectSmallerSyntaxNode,
+    GoToDefinition,
+    GoToDefinitionSplit,
+    GoToTypeDefinition,
+    GoToTypeDefinitionSplit,
+    MoveToEnclosingBracket,
+    UndoSelection,
+    RedoSelection,
+    FindAllReferences,
+    Rename,
+    ConfirmRename,
+    Fold,
+    UnfoldLines,
+    FoldSelectedRanges,
+    ShowCompletions,
+    OpenExcerpts,
+    RestartLanguageServer,
+    Hover,
+    Format,
+    ToggleSoftWrap,
+    ToggleInlayHints,
+    RevealInFinder,
+    CopyPath,
+    CopyRelativePath,
+    CopyHighlightJson,
+    ContextMenuFirst,
+    ContextMenuPrev,
+    ContextMenuNext,
+    ContextMenuLast,
+);
 
 // impl_actions!(
 //     editor,
@@ -389,14 +390,6 @@ impl InlayId {
 //     ]
 // );
 
-// todo!(revisit these actions)
-pub struct ShowCompletions;
-pub struct Rename;
-pub struct GoToDefinition;
-pub struct GoToTypeDefinition;
-pub struct GoToDefinitionSplit;
-pub struct GoToTypeDefinitionSplit;
-
 enum DocumentHighlightRead {}
 enum DocumentHighlightWrite {}
 enum InputComposition {}
@@ -413,130 +406,130 @@ pub fn init_settings(cx: &mut AppContext) {
 
 pub fn init(cx: &mut AppContext) {
     init_settings(cx);
-    // cx.add_action(Editor::new_file);
-    // cx.add_action(Editor::new_file_in_direction);
-    // cx.add_action(Editor::cancel);
-    // cx.add_action(Editor::newline);
-    // cx.add_action(Editor::newline_above);
-    // cx.add_action(Editor::newline_below);
-    // cx.add_action(Editor::backspace);
-    // cx.add_action(Editor::delete);
-    // cx.add_action(Editor::tab);
-    // cx.add_action(Editor::tab_prev);
-    // cx.add_action(Editor::indent);
-    // cx.add_action(Editor::outdent);
-    // cx.add_action(Editor::delete_line);
-    // cx.add_action(Editor::join_lines);
-    // cx.add_action(Editor::sort_lines_case_sensitive);
-    // cx.add_action(Editor::sort_lines_case_insensitive);
-    // cx.add_action(Editor::reverse_lines);
-    // cx.add_action(Editor::shuffle_lines);
-    // cx.add_action(Editor::convert_to_upper_case);
-    // cx.add_action(Editor::convert_to_lower_case);
-    // cx.add_action(Editor::convert_to_title_case);
-    // cx.add_action(Editor::convert_to_snake_case);
-    // cx.add_action(Editor::convert_to_kebab_case);
-    // cx.add_action(Editor::convert_to_upper_camel_case);
-    // cx.add_action(Editor::convert_to_lower_camel_case);
-    // cx.add_action(Editor::delete_to_previous_word_start);
-    // cx.add_action(Editor::delete_to_previous_subword_start);
-    // cx.add_action(Editor::delete_to_next_word_end);
-    // cx.add_action(Editor::delete_to_next_subword_end);
-    // cx.add_action(Editor::delete_to_beginning_of_line);
-    // cx.add_action(Editor::delete_to_end_of_line);
-    // cx.add_action(Editor::cut_to_end_of_line);
-    // cx.add_action(Editor::duplicate_line);
-    // cx.add_action(Editor::move_line_up);
-    // cx.add_action(Editor::move_line_down);
-    // cx.add_action(Editor::transpose);
-    // cx.add_action(Editor::cut);
-    // cx.add_action(Editor::copy);
-    // cx.add_action(Editor::paste);
-    // cx.add_action(Editor::undo);
-    // cx.add_action(Editor::redo);
-    // cx.add_action(Editor::move_up);
-    // cx.add_action(Editor::move_page_up);
-    // cx.add_action(Editor::move_down);
-    // cx.add_action(Editor::move_page_down);
-    // cx.add_action(Editor::next_screen);
-    // cx.add_action(Editor::move_left);
-    // cx.add_action(Editor::move_right);
-    // cx.add_action(Editor::move_to_previous_word_start);
-    // cx.add_action(Editor::move_to_previous_subword_start);
-    // cx.add_action(Editor::move_to_next_word_end);
-    // cx.add_action(Editor::move_to_next_subword_end);
-    // cx.add_action(Editor::move_to_beginning_of_line);
-    // cx.add_action(Editor::move_to_end_of_line);
-    // cx.add_action(Editor::move_to_start_of_paragraph);
-    // cx.add_action(Editor::move_to_end_of_paragraph);
-    // cx.add_action(Editor::move_to_beginning);
-    // cx.add_action(Editor::move_to_end);
-    // cx.add_action(Editor::select_up);
-    // cx.add_action(Editor::select_down);
-    // cx.add_action(Editor::select_left);
-    // cx.add_action(Editor::select_right);
-    // cx.add_action(Editor::select_to_previous_word_start);
-    // cx.add_action(Editor::select_to_previous_subword_start);
-    // cx.add_action(Editor::select_to_next_word_end);
-    // cx.add_action(Editor::select_to_next_subword_end);
-    // cx.add_action(Editor::select_to_beginning_of_line);
-    // cx.add_action(Editor::select_to_end_of_line);
-    // cx.add_action(Editor::select_to_start_of_paragraph);
-    // cx.add_action(Editor::select_to_end_of_paragraph);
-    // cx.add_action(Editor::select_to_beginning);
-    // cx.add_action(Editor::select_to_end);
-    // cx.add_action(Editor::select_all);
-    // cx.add_action(Editor::select_all_matches);
-    // cx.add_action(Editor::select_line);
-    // cx.add_action(Editor::split_selection_into_lines);
-    // cx.add_action(Editor::add_selection_above);
-    // cx.add_action(Editor::add_selection_below);
-    // cx.add_action(Editor::select_next);
-    // cx.add_action(Editor::select_previous);
-    // cx.add_action(Editor::toggle_comments);
-    // cx.add_action(Editor::select_larger_syntax_node);
-    // cx.add_action(Editor::select_smaller_syntax_node);
-    // cx.add_action(Editor::move_to_enclosing_bracket);
-    // cx.add_action(Editor::undo_selection);
-    // cx.add_action(Editor::redo_selection);
-    // cx.add_action(Editor::go_to_diagnostic);
-    // cx.add_action(Editor::go_to_prev_diagnostic);
-    // cx.add_action(Editor::go_to_hunk);
-    // cx.add_action(Editor::go_to_prev_hunk);
-    // cx.add_action(Editor::go_to_definition);
-    // cx.add_action(Editor::go_to_definition_split);
-    // cx.add_action(Editor::go_to_type_definition);
-    // cx.add_action(Editor::go_to_type_definition_split);
-    // cx.add_action(Editor::fold);
-    // cx.add_action(Editor::fold_at);
-    // cx.add_action(Editor::unfold_lines);
-    // cx.add_action(Editor::unfold_at);
-    // cx.add_action(Editor::gutter_hover);
-    // cx.add_action(Editor::fold_selected_ranges);
-    // cx.add_action(Editor::show_completions);
-    // cx.add_action(Editor::toggle_code_actions);
-    // cx.add_action(Editor::open_excerpts);
-    // cx.add_action(Editor::toggle_soft_wrap);
-    // cx.add_action(Editor::toggle_inlay_hints);
-    // cx.add_action(Editor::reveal_in_finder);
-    // cx.add_action(Editor::copy_path);
-    // cx.add_action(Editor::copy_relative_path);
-    // cx.add_action(Editor::copy_highlight_json);
+    // cx.register_action_type(Editor::new_file);
+    // cx.register_action_type(Editor::new_file_in_direction);
+    // cx.register_action_type(Editor::cancel);
+    // cx.register_action_type(Editor::newline);
+    // cx.register_action_type(Editor::newline_above);
+    // cx.register_action_type(Editor::newline_below);
+    // cx.register_action_type(Editor::backspace);
+    // cx.register_action_type(Editor::delete);
+    // cx.register_action_type(Editor::tab);
+    // cx.register_action_type(Editor::tab_prev);
+    // cx.register_action_type(Editor::indent);
+    // cx.register_action_type(Editor::outdent);
+    // cx.register_action_type(Editor::delete_line);
+    // cx.register_action_type(Editor::join_lines);
+    // cx.register_action_type(Editor::sort_lines_case_sensitive);
+    // cx.register_action_type(Editor::sort_lines_case_insensitive);
+    // cx.register_action_type(Editor::reverse_lines);
+    // cx.register_action_type(Editor::shuffle_lines);
+    // cx.register_action_type(Editor::convert_to_upper_case);
+    // cx.register_action_type(Editor::convert_to_lower_case);
+    // cx.register_action_type(Editor::convert_to_title_case);
+    // cx.register_action_type(Editor::convert_to_snake_case);
+    // cx.register_action_type(Editor::convert_to_kebab_case);
+    // cx.register_action_type(Editor::convert_to_upper_camel_case);
+    // cx.register_action_type(Editor::convert_to_lower_camel_case);
+    // cx.register_action_type(Editor::delete_to_previous_word_start);
+    // cx.register_action_type(Editor::delete_to_previous_subword_start);
+    // cx.register_action_type(Editor::delete_to_next_word_end);
+    // cx.register_action_type(Editor::delete_to_next_subword_end);
+    // cx.register_action_type(Editor::delete_to_beginning_of_line);
+    // cx.register_action_type(Editor::delete_to_end_of_line);
+    // cx.register_action_type(Editor::cut_to_end_of_line);
+    // cx.register_action_type(Editor::duplicate_line);
+    // cx.register_action_type(Editor::move_line_up);
+    // cx.register_action_type(Editor::move_line_down);
+    // cx.register_action_type(Editor::transpose);
+    // cx.register_action_type(Editor::cut);
+    // cx.register_action_type(Editor::copy);
+    // cx.register_action_type(Editor::paste);
+    // cx.register_action_type(Editor::undo);
+    // cx.register_action_type(Editor::redo);
+    cx.register_action_type::<MoveUp>();
+    // cx.register_action_type(Editor::move_page_up);
+    cx.register_action_type::<MoveDown>();
+    // cx.register_action_type(Editor::move_page_down);
+    // cx.register_action_type(Editor::next_screen);
+    cx.register_action_type::<MoveLeft>();
+    cx.register_action_type::<MoveRight>();
+    // cx.register_action_type(Editor::move_to_previous_word_start);
+    // cx.register_action_type(Editor::move_to_previous_subword_start);
+    // cx.register_action_type(Editor::move_to_next_word_end);
+    // cx.register_action_type(Editor::move_to_next_subword_end);
+    // cx.register_action_type(Editor::move_to_beginning_of_line);
+    // cx.register_action_type(Editor::move_to_end_of_line);
+    // cx.register_action_type(Editor::move_to_start_of_paragraph);
+    // cx.register_action_type(Editor::move_to_end_of_paragraph);
+    // cx.register_action_type(Editor::move_to_beginning);
+    // cx.register_action_type(Editor::move_to_end);
+    // cx.register_action_type(Editor::select_up);
+    // cx.register_action_type(Editor::select_down);
+    // cx.register_action_type(Editor::select_left);
+    // cx.register_action_type(Editor::select_right);
+    // cx.register_action_type(Editor::select_to_previous_word_start);
+    // cx.register_action_type(Editor::select_to_previous_subword_start);
+    // cx.register_action_type(Editor::select_to_next_word_end);
+    // cx.register_action_type(Editor::select_to_next_subword_end);
+    // cx.register_action_type(Editor::select_to_beginning_of_line);
+    // cx.register_action_type(Editor::select_to_end_of_line);
+    // cx.register_action_type(Editor::select_to_start_of_paragraph);
+    // cx.register_action_type(Editor::select_to_end_of_paragraph);
+    // cx.register_action_type(Editor::select_to_beginning);
+    // cx.register_action_type(Editor::select_to_end);
+    // cx.register_action_type(Editor::select_all);
+    // cx.register_action_type(Editor::select_all_matches);
+    // cx.register_action_type(Editor::select_line);
+    // cx.register_action_type(Editor::split_selection_into_lines);
+    // cx.register_action_type(Editor::add_selection_above);
+    // cx.register_action_type(Editor::add_selection_below);
+    // cx.register_action_type(Editor::select_next);
+    // cx.register_action_type(Editor::select_previous);
+    // cx.register_action_type(Editor::toggle_comments);
+    // cx.register_action_type(Editor::select_larger_syntax_node);
+    // cx.register_action_type(Editor::select_smaller_syntax_node);
+    // cx.register_action_type(Editor::move_to_enclosing_bracket);
+    // cx.register_action_type(Editor::undo_selection);
+    // cx.register_action_type(Editor::redo_selection);
+    // cx.register_action_type(Editor::go_to_diagnostic);
+    // cx.register_action_type(Editor::go_to_prev_diagnostic);
+    // cx.register_action_type(Editor::go_to_hunk);
+    // cx.register_action_type(Editor::go_to_prev_hunk);
+    // cx.register_action_type(Editor::go_to_definition);
+    // cx.register_action_type(Editor::go_to_definition_split);
+    // cx.register_action_type(Editor::go_to_type_definition);
+    // cx.register_action_type(Editor::go_to_type_definition_split);
+    // cx.register_action_type(Editor::fold);
+    // cx.register_action_type(Editor::fold_at);
+    // cx.register_action_type(Editor::unfold_lines);
+    // cx.register_action_type(Editor::unfold_at);
+    // cx.register_action_type(Editor::gutter_hover);
+    // cx.register_action_type(Editor::fold_selected_ranges);
+    // cx.register_action_type(Editor::show_completions);
+    // cx.register_action_type(Editor::toggle_code_actions);
+    // cx.register_action_type(Editor::open_excerpts);
+    // cx.register_action_type(Editor::toggle_soft_wrap);
+    // cx.register_action_type(Editor::toggle_inlay_hints);
+    // cx.register_action_type(Editor::reveal_in_finder);
+    // cx.register_action_type(Editor::copy_path);
+    // cx.register_action_type(Editor::copy_relative_path);
+    // cx.register_action_type(Editor::copy_highlight_json);
     // cx.add_async_action(Editor::format);
-    // cx.add_action(Editor::restart_language_server);
-    // cx.add_action(Editor::show_character_palette);
+    // cx.register_action_type(Editor::restart_language_server);
+    // cx.register_action_type(Editor::show_character_palette);
     // cx.add_async_action(Editor::confirm_completion);
     // cx.add_async_action(Editor::confirm_code_action);
     // cx.add_async_action(Editor::rename);
     // cx.add_async_action(Editor::confirm_rename);
     // cx.add_async_action(Editor::find_all_references);
-    // cx.add_action(Editor::next_copilot_suggestion);
-    // cx.add_action(Editor::previous_copilot_suggestion);
-    // cx.add_action(Editor::copilot_suggest);
-    // cx.add_action(Editor::context_menu_first);
-    // cx.add_action(Editor::context_menu_prev);
-    // cx.add_action(Editor::context_menu_next);
-    // cx.add_action(Editor::context_menu_last);
+    // cx.register_action_type(Editor::next_copilot_suggestion);
+    // cx.register_action_type(Editor::previous_copilot_suggestion);
+    // cx.register_action_type(Editor::copilot_suggest);
+    // cx.register_action_type(Editor::context_menu_first);
+    // cx.register_action_type(Editor::context_menu_prev);
+    // cx.register_action_type(Editor::context_menu_next);
+    // cx.register_action_type(Editor::context_menu_last);
 
     hover_popover::init(cx);
     scroll::actions::init(cx);
@@ -602,6 +595,8 @@ pub struct EditorStyle {
     pub text: TextStyle,
     pub line_height_scalar: f32,
     pub scrollbar_width: Pixels,
+    pub syntax: Arc<SyntaxTheme>,
+    pub diagnostic_style: DiagnosticStyle,
 }
 
 type CompletionId = usize;
@@ -657,7 +652,7 @@ pub struct Editor {
     collapse_matches: bool,
     autoindent_mode: Option<AutoindentMode>,
     workspace: Option<(WeakView<Workspace>, i64)>,
-    // keymap_context_layers: BTreeMap<TypeId, KeymapContext>,
+    keymap_context_layers: BTreeMap<TypeId, DispatchContext>,
     input_enabled: bool,
     read_only: bool,
     leader_peer_id: Option<PeerId>,
@@ -670,6 +665,7 @@ pub struct Editor {
     next_inlay_id: usize,
     _subscriptions: Vec<Subscription>,
     pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
+    style: Option<EditorStyle>,
 }
 
 pub struct EditorSnapshot {
@@ -1965,7 +1961,7 @@ impl Editor {
             autoindent_mode: Some(AutoindentMode::EachLine),
             collapse_matches: false,
             workspace: None,
-            // keymap_context_layers: Default::default(),
+            keymap_context_layers: Default::default(),
             input_enabled: true,
             read_only: false,
             leader_peer_id: None,
@@ -1976,6 +1972,7 @@ impl Editor {
             inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
             gutter_hovered: false,
             pixel_position_of_newest_cursor: None,
+            style: None,
             _subscriptions: vec![
                 cx.observe(&buffer, Self::on_buffer_changed),
                 cx.subscribe(&buffer, Self::on_buffer_event),
@@ -2014,6 +2011,48 @@ impl Editor {
         this
     }
 
+    fn dispatch_context(&self, cx: &AppContext) -> DispatchContext {
+        let mut dispatch_context = DispatchContext::default();
+        dispatch_context.insert("Editor");
+        let mode = match self.mode {
+            EditorMode::SingleLine => "single_line",
+            EditorMode::AutoHeight { .. } => "auto_height",
+            EditorMode::Full => "full",
+        };
+        dispatch_context.set("mode", mode);
+        if self.pending_rename.is_some() {
+            dispatch_context.insert("renaming");
+        }
+        if self.context_menu_visible() {
+            match self.context_menu.read().as_ref() {
+                Some(ContextMenu::Completions(_)) => {
+                    dispatch_context.insert("menu");
+                    dispatch_context.insert("showing_completions")
+                }
+                Some(ContextMenu::CodeActions(_)) => {
+                    dispatch_context.insert("menu");
+                    dispatch_context.insert("showing_code_actions")
+                }
+                None => {}
+            }
+        }
+
+        for layer in self.keymap_context_layers.values() {
+            dispatch_context.extend(layer);
+        }
+
+        if let Some(extension) = self
+            .buffer
+            .read(cx)
+            .as_singleton()
+            .and_then(|buffer| buffer.read(cx).file()?.path().extension()?.to_str())
+        {
+            dispatch_context.set("extension", extension.to_string());
+        }
+
+        dispatch_context
+    }
+
     //     pub fn new_file(
     //         workspace: &mut Workspace,
     //         _: &workspace::NewFile,
@@ -2021,7 +2060,7 @@ impl Editor {
     //     ) {
     //         let project = workspace.project().clone();
     //         if project.read(cx).is_remote() {
-    //             cx.propagate_action();
+    //             cx.propagate();
     //         } else if let Some(buffer) = project
     //             .update(cx, |project, cx| project.create_buffer("", None, cx))
     //             .log_err()
@@ -2040,7 +2079,7 @@ impl Editor {
     //     ) {
     //         let project = workspace.project().clone();
     //         if project.read(cx).is_remote() {
-    //             cx.propagate_action();
+    //             cx.propagate();
     //         } else if let Some(buffer) = project
     //             .update(cx, |project, cx| project.create_buffer("", None, cx))
     //             .log_err()
@@ -2731,7 +2770,7 @@ impl Editor {
     //             }
     //         }
 
-    //         cx.propagate_action();
+    //         cx.propagate();
     //     }
 
     //     pub fn handle_input(&mut self, text: &str, cx: &mut ViewContext<Self>) {
@@ -3482,13 +3521,13 @@ impl Editor {
             .collect()
     }
 
-    //     pub fn text_layout_details(&self, cx: &WindowContext) -> TextLayoutDetails {
-    //         TextLayoutDetails {
-    //             font_cache: cx.font_cache().clone(),
-    //             text_layout_cache: cx.text_layout_cache().clone(),
-    //             editor_style: self.style(cx),
-    //         }
-    //     }
+    pub fn text_layout_details(&self, cx: &WindowContext) -> TextLayoutDetails {
+        TextLayoutDetails {
+            text_system: cx.text_system().clone(),
+            editor_style: self.style.clone().unwrap(),
+            rem_size: cx.rem_size(),
+        }
+    }
 
     fn splice_inlay_hints(
         &self,
@@ -4207,7 +4246,7 @@ impl Editor {
             let is_copilot_disabled = self.refresh_copilot_suggestions(false, cx).is_none();
             if is_copilot_disabled {
                 todo!();
-                // cx.propagate_action();
+                // cx.propagate();
             }
         }
     }
@@ -4429,12 +4468,14 @@ impl Editor {
     //             .collect()
     //     }
 
-    //     pub fn context_menu_visible(&self) -> bool {
-    //         self.context_menu
-    //             .read()
-    //             .as_ref()
-    //             .map_or(false, |menu| menu.visible())
-    //     }
+    pub fn context_menu_visible(&self) -> bool {
+        false
+        // todo!("context menu")
+        // self.context_menu
+        //     .read()
+        //     .as_ref()
+        //     .map_or(false, |menu| menu.visible())
+    }
 
     //     pub fn render_context_menu(
     //         &self,
@@ -5681,19 +5722,19 @@ impl Editor {
     //             .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
     //     }
 
-    //     pub fn move_left(&mut self, _: &MoveLeft, cx: &mut ViewContext<Self>) {
-    //         self.change_selections(Some(Autoscroll::fit()), cx, |s| {
-    //             let line_mode = s.line_mode;
-    //             s.move_with(|map, selection| {
-    //                 let cursor = if selection.is_empty() && !line_mode {
-    //                     movement::left(map, selection.start)
-    //                 } else {
-    //                     selection.start
-    //                 };
-    //                 selection.collapse_to(cursor, SelectionGoal::None);
-    //             });
-    //         })
-    //     }
+    pub fn move_left(&mut self, _: &MoveLeft, cx: &mut ViewContext<Self>) {
+        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
+            let line_mode = s.line_mode;
+            s.move_with(|map, selection| {
+                let cursor = if selection.is_empty() && !line_mode {
+                    movement::left(map, selection.start)
+                } else {
+                    selection.start
+                };
+                selection.collapse_to(cursor, SelectionGoal::None);
+            });
+        })
+    }
 
     //     pub fn select_left(&mut self, _: &SelectLeft, cx: &mut ViewContext<Self>) {
     //         self.change_selections(Some(Autoscroll::fit()), cx, |s| {
@@ -5701,19 +5742,19 @@ impl Editor {
     //         })
     //     }
 
-    //     pub fn move_right(&mut self, _: &MoveRight, cx: &mut ViewContext<Self>) {
-    //         self.change_selections(Some(Autoscroll::fit()), cx, |s| {
-    //             let line_mode = s.line_mode;
-    //             s.move_with(|map, selection| {
-    //                 let cursor = if selection.is_empty() && !line_mode {
-    //                     movement::right(map, selection.end)
-    //                 } else {
-    //                     selection.end
-    //                 };
-    //                 selection.collapse_to(cursor, SelectionGoal::None)
-    //             });
-    //         })
-    //     }
+    pub fn move_right(&mut self, _: &MoveRight, cx: &mut ViewContext<Self>) {
+        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
+            let line_mode = s.line_mode;
+            s.move_with(|map, selection| {
+                let cursor = if selection.is_empty() && !line_mode {
+                    movement::right(map, selection.end)
+                } else {
+                    selection.end
+                };
+                selection.collapse_to(cursor, SelectionGoal::None)
+            });
+        })
+    }
 
     //     pub fn select_right(&mut self, _: &SelectRight, cx: &mut ViewContext<Self>) {
     //         self.change_selections(Some(Autoscroll::fit()), cx, |s| {
@@ -5721,35 +5762,35 @@ impl Editor {
     //         })
     //     }
 
-    //     pub fn move_up(&mut self, _: &MoveUp, cx: &mut ViewContext<Self>) {
-    //         if self.take_rename(true, cx).is_some() {
-    //             return;
-    //         }
+    pub fn move_up(&mut self, _: &MoveUp, cx: &mut ViewContext<Self>) {
+        if self.take_rename(true, cx).is_some() {
+            return;
+        }
 
-    //         if matches!(self.mode, EditorMode::SingleLine) {
-    //             cx.propagate_action();
-    //             return;
-    //         }
+        if matches!(self.mode, EditorMode::SingleLine) {
+            cx.propagate();
+            return;
+        }
 
-    //         let text_layout_details = &self.text_layout_details(cx);
+        let text_layout_details = &self.text_layout_details(cx);
 
-    //         self.change_selections(Some(Autoscroll::fit()), cx, |s| {
-    //             let line_mode = s.line_mode;
-    //             s.move_with(|map, selection| {
-    //                 if !selection.is_empty() && !line_mode {
-    //                     selection.goal = SelectionGoal::None;
-    //                 }
-    //                 let (cursor, goal) = movement::up(
-    //                     map,
-    //                     selection.start,
-    //                     selection.goal,
-    //                     false,
-    //                     &text_layout_details,
-    //                 );
-    //                 selection.collapse_to(cursor, goal);
-    //             });
-    //         })
-    //     }
+        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
+            let line_mode = s.line_mode;
+            s.move_with(|map, selection| {
+                if !selection.is_empty() && !line_mode {
+                    selection.goal = SelectionGoal::None;
+                }
+                let (cursor, goal) = movement::up(
+                    map,
+                    selection.start,
+                    selection.goal,
+                    false,
+                    &text_layout_details,
+                );
+                selection.collapse_to(cursor, goal);
+            });
+        })
+    }
 
     //     pub fn move_page_up(&mut self, action: &MovePageUp, cx: &mut ViewContext<Self>) {
     //         if self.take_rename(true, cx).is_some() {
@@ -5757,7 +5798,7 @@ impl Editor {
     //         }
 
     //         if matches!(self.mode, EditorMode::SingleLine) {
-    //             cx.propagate_action();
+    //             cx.propagate();
     //             return;
     //         }
 
@@ -5803,32 +5844,32 @@ impl Editor {
     //         })
     //     }
 
-    //     pub fn move_down(&mut self, _: &MoveDown, cx: &mut ViewContext<Self>) {
-    //         self.take_rename(true, cx);
+    pub fn move_down(&mut self, _: &MoveDown, cx: &mut ViewContext<Self>) {
+        self.take_rename(true, cx);
 
-    //         if self.mode == EditorMode::SingleLine {
-    //             cx.propagate_action();
-    //             return;
-    //         }
+        if self.mode == EditorMode::SingleLine {
+            cx.propagate();
+            return;
+        }
 
-    //         let text_layout_details = &self.text_layout_details(cx);
-    //         self.change_selections(Some(Autoscroll::fit()), cx, |s| {
-    //             let line_mode = s.line_mode;
-    //             s.move_with(|map, selection| {
-    //                 if !selection.is_empty() && !line_mode {
-    //                     selection.goal = SelectionGoal::None;
-    //                 }
-    //                 let (cursor, goal) = movement::down(
-    //                     map,
-    //                     selection.end,
-    //                     selection.goal,
-    //                     false,
-    //                     &text_layout_details,
-    //                 );
-    //                 selection.collapse_to(cursor, goal);
-    //             });
-    //         });
-    //     }
+        let text_layout_details = &self.text_layout_details(cx);
+        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
+            let line_mode = s.line_mode;
+            s.move_with(|map, selection| {
+                if !selection.is_empty() && !line_mode {
+                    selection.goal = SelectionGoal::None;
+                }
+                let (cursor, goal) = movement::down(
+                    map,
+                    selection.end,
+                    selection.goal,
+                    false,
+                    &text_layout_details,
+                );
+                selection.collapse_to(cursor, goal);
+            });
+        });
+    }
 
     //     pub fn move_page_down(&mut self, action: &MovePageDown, cx: &mut ViewContext<Self>) {
     //         if self.take_rename(true, cx).is_some() {
@@ -5846,7 +5887,7 @@ impl Editor {
     //         }
 
     //         if matches!(self.mode, EditorMode::SingleLine) {
-    //             cx.propagate_action();
+    //             cx.propagate();
     //             return;
     //         }
 
@@ -6193,7 +6234,7 @@ impl Editor {
     //         cx: &mut ViewContext<Self>,
     //     ) {
     //         if matches!(self.mode, EditorMode::SingleLine) {
-    //             cx.propagate_action();
+    //             cx.propagate();
     //             return;
     //         }
 
@@ -6213,7 +6254,7 @@ impl Editor {
     //         cx: &mut ViewContext<Self>,
     //     ) {
     //         if matches!(self.mode, EditorMode::SingleLine) {
-    //             cx.propagate_action();
+    //             cx.propagate();
     //             return;
     //         }
 
@@ -6233,7 +6274,7 @@ impl Editor {
     //         cx: &mut ViewContext<Self>,
     //     ) {
     //         if matches!(self.mode, EditorMode::SingleLine) {
-    //             cx.propagate_action();
+    //             cx.propagate();
     //             return;
     //         }
 
@@ -6253,7 +6294,7 @@ impl Editor {
     //         cx: &mut ViewContext<Self>,
     //     ) {
     //         if matches!(self.mode, EditorMode::SingleLine) {
-    //             cx.propagate_action();
+    //             cx.propagate();
     //             return;
     //         }
 
@@ -6269,7 +6310,7 @@ impl Editor {
 
     //     pub fn move_to_beginning(&mut self, _: &MoveToBeginning, cx: &mut ViewContext<Self>) {
     //         if matches!(self.mode, EditorMode::SingleLine) {
-    //             cx.propagate_action();
+    //             cx.propagate();
     //             return;
     //         }
 
@@ -6289,7 +6330,7 @@ impl Editor {
 
     //     pub fn move_to_end(&mut self, _: &MoveToEnd, cx: &mut ViewContext<Self>) {
     //         if matches!(self.mode, EditorMode::SingleLine) {
-    //             cx.propagate_action();
+    //             cx.propagate();
     //             return;
     //         }
 
@@ -8807,14 +8848,14 @@ impl Editor {
     //         {
     //             editor
     //         } else {
-    //             cx.propagate_action();
+    //             cx.propagate();
     //             return;
     //         };
 
     //         let editor = editor_handle.read(cx);
     //         let buffer = editor.buffer.read(cx);
     //         if buffer.is_singleton() {
-    //             cx.propagate_action();
+    //             cx.propagate();
     //             return;
     //         }
 
@@ -9340,6 +9381,8 @@ impl Render for Editor {
             text: text_style,
             line_height_scalar: settings.buffer_line_height.value(),
             scrollbar_width: px(12.),
+            syntax: cx.theme().syntax().clone(),
+            diagnostic_style: cx.theme().diagnostic_style(),
         })
     }
 }
@@ -9443,46 +9486,7 @@ impl Render for Editor {
 
 //         false
 //     }
-
-//     fn update_keymap_context(&self, keymap: &mut KeymapContext, cx: &AppContext) {
-//         Self::reset_to_default_keymap_context(keymap);
-//         let mode = match self.mode {
-//             EditorMode::SingleLine => "single_line",
-//             EditorMode::AutoHeight { .. } => "auto_height",
-//             EditorMode::Full => "full",
-//         };
-//         keymap.add_key("mode", mode);
-//         if self.pending_rename.is_some() {
-//             keymap.add_identifier("renaming");
-//         }
-//         if self.context_menu_visible() {
-//             match self.context_menu.read().as_ref() {
-//                 Some(ContextMenu::Completions(_)) => {
-//                     keymap.add_identifier("menu");
-//                     keymap.add_identifier("showing_completions")
-//                 }
-//                 Some(ContextMenu::CodeActions(_)) => {
-//                     keymap.add_identifier("menu");
-//                     keymap.add_identifier("showing_code_actions")
-//                 }
-//                 None => {}
-//             }
-//         }
-
-//         for layer in self.keymap_context_layers.values() {
-//             keymap.extend(layer);
-//         }
-
-//         if let Some(extension) = self
-//             .buffer
-//             .read(cx)
-//             .as_singleton()
-//             .and_then(|buffer| buffer.read(cx).file()?.path().extension()?.to_str())
-//         {
-//             keymap.add_key("extension", extension.to_string());
-//         }
-//     }
-
+//
 //     fn text_for_range(&self, range_utf16: Range<usize>, cx: &AppContext) -> Option<String> {
 //         Some(
 //             self.buffer

crates/editor2/src/element.rs 🔗

@@ -3,15 +3,15 @@ use crate::{
     editor_settings::ShowScrollbar,
     git::{diff_hunk_to_display, DisplayDiffHunk},
     CursorShape, DisplayPoint, Editor, EditorMode, EditorSettings, EditorSnapshot, EditorStyle,
-    Point, Selection, SoftWrap, ToPoint, MAX_LINE_LEN,
+    MoveDown, Point, Selection, SoftWrap, ToPoint, MAX_LINE_LEN,
 };
 use anyhow::Result;
 use collections::{BTreeMap, HashMap};
 use gpui::{
-    black, hsla, point, px, relative, size, transparent_black, AnyElement, BorrowWindow, Bounds,
-    ContentMask, Corners, DispatchPhase, Edges, Element, ElementId, Hsla, Line, Pixels,
-    ScrollWheelEvent, ShapedGlyph, Size, StatefulInteraction, Style, TextRun, TextStyle,
-    TextSystem, ViewContext, WindowContext,
+    black, hsla, point, px, relative, size, transparent_black, Action, AnyElement, BorrowWindow,
+    Bounds, ContentMask, Corners, DispatchContext, DispatchPhase, Edges, Element, ElementId,
+    Entity, Hsla, KeyDownEvent, KeyListener, KeyMatch, Line, Pixels, ScrollWheelEvent, ShapedGlyph,
+    Size, StatefulInteraction, Style, TextRun, TextStyle, TextSystem, ViewContext, WindowContext,
 };
 use itertools::Itertools;
 use language::language_settings::ShowWhitespaceSetting;
@@ -20,6 +20,7 @@ use project::project_settings::{GitGutterSetting, ProjectSettings};
 use settings::Settings;
 use smallvec::SmallVec;
 use std::{
+    any::TypeId,
     borrow::Cow,
     cmp::{self, Ordering},
     fmt::Write,
@@ -94,14 +95,12 @@ impl SelectionLayout {
 }
 
 pub struct EditorElement {
-    style: Arc<EditorStyle>,
+    style: EditorStyle,
 }
 
 impl EditorElement {
     pub fn new(style: EditorStyle) -> Self {
-        Self {
-            style: Arc::new(style),
-        }
+        Self { style }
     }
 
     // fn attach_mouse_handlers(
@@ -1578,12 +1577,10 @@ impl EditorElement {
                 })
                 .collect()
         } else {
-            let style = &self.style;
-            let chunks = snapshot.highlighted_chunks(rows.clone(), true, cx.theme());
-
+            let chunks = snapshot.highlighted_chunks(rows.clone(), true, &self.style);
             LineWithInvisibles::from_chunks(
                 chunks,
-                &style.text,
+                &self.style.text,
                 MAX_LINE_LEN,
                 rows.len() as usize,
                 line_number_layouts,
@@ -2554,7 +2551,37 @@ impl Element<Editor> for EditorElement {
         element_state: Option<Self::ElementState>,
         cx: &mut gpui::ViewContext<Editor>,
     ) -> Self::ElementState {
-        ()
+        editor.style = Some(self.style.clone()); // Long-term, we'd like to eliminate this.
+
+        let dispatch_context = editor.dispatch_context(cx);
+        cx.with_element_id(cx.view().entity_id(), |global_id, cx| {
+            cx.with_key_dispatch_context(dispatch_context, |cx| {
+                cx.with_key_listeners(
+                    [
+                        build_action_listener(Editor::move_left),
+                        build_action_listener(Editor::move_right),
+                        build_action_listener(Editor::move_down),
+                        build_action_listener(Editor::move_up),
+                        build_key_listener(
+                            move |editor, key_down: &KeyDownEvent, dispatch_context, phase, cx| {
+                                if phase == DispatchPhase::Bubble {
+                                    if let KeyMatch::Some(action) = cx.match_keystroke(
+                                        &global_id,
+                                        &key_down.keystroke,
+                                        dispatch_context,
+                                    ) {
+                                        return Some(action);
+                                    }
+                                }
+
+                                None
+                            },
+                        ),
+                    ],
+                    |cx| cx.with_focus(editor.focus_handle.clone(), |_| {}),
+                );
+            })
+        });
     }
 
     fn layout(
@@ -4080,3 +4107,33 @@ fn scale_horizontal_mouse_autoscroll_delta(delta: f32) -> f32 {
 //             .collect()
 //     }
 // }
+
+fn build_key_listener<T: 'static>(
+    listener: impl Fn(
+            &mut Editor,
+            &T,
+            &[&DispatchContext],
+            DispatchPhase,
+            &mut ViewContext<Editor>,
+        ) -> Option<Box<dyn Action>>
+        + 'static,
+) -> (TypeId, KeyListener<Editor>) {
+    (
+        TypeId::of::<T>(),
+        Box::new(move |editor, event, dispatch_context, phase, cx| {
+            let key_event = event.downcast_ref::<T>()?;
+            listener(editor, key_event, dispatch_context, phase, cx)
+        }),
+    )
+}
+
+fn build_action_listener<T: Action>(
+    listener: impl Fn(&mut Editor, &T, &mut ViewContext<Editor>) + 'static,
+) -> (TypeId, KeyListener<Editor>) {
+    build_key_listener(move |editor, action: &T, dispatch_context, phase, cx| {
+        if phase == DispatchPhase::Bubble {
+            listener(editor, action, cx);
+        }
+        None
+    })
+}

crates/editor2/src/highlight_matching_bracket.rs 🔗

@@ -24,7 +24,7 @@ pub fn refresh_matching_bracket_highlights(editor: &mut Editor, cx: &mut ViewCon
                 opening_range.to_anchors(&snapshot.buffer_snapshot),
                 closing_range.to_anchors(&snapshot.buffer_snapshot),
             ],
-            |theme| todo!("theme.editor.document_highlight_read_background"),
+            |theme| theme.editor_document_highlight_read_background,
             cx,
         )
     }

crates/editor2/src/movement.rs 🔗

@@ -1,9 +1,9 @@
 use super::{Bias, DisplayPoint, DisplaySnapshot, SelectionGoal, ToDisplayPoint};
 use crate::{char_kind, CharKind, EditorStyle, ToOffset, ToPoint};
-use gpui::{px, TextSystem};
+use gpui::{px, Pixels, TextSystem};
 use language::Point;
 use serde::de::IntoDeserializer;
-use std::ops::Range;
+use std::{ops::Range, sync::Arc};
 
 #[derive(Debug, PartialEq)]
 pub enum FindRange {
@@ -14,8 +14,9 @@ pub enum FindRange {
 /// TextLayoutDetails encompasses everything we need to move vertically
 /// taking into account variable width characters.
 pub struct TextLayoutDetails {
-    pub text_system: TextSystem,
+    pub text_system: Arc<TextSystem>,
     pub editor_style: EditorStyle,
+    pub rem_size: Pixels,
 }
 
 pub fn left(map: &DisplaySnapshot, mut point: DisplayPoint) -> DisplayPoint {

crates/editor2/src/scroll.rs 🔗

@@ -349,10 +349,12 @@ impl Editor {
         self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
     }
 
-    //     pub fn scroll_position(&self, cx: &mut ViewContext<Self>) -> gpui::Point<Pixels> {
-    //         let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
-    //         self.scroll_manager.anchor.scroll_position(&display_map)
-    //     }
+    pub fn scroll_position(&self, cx: &mut ViewContext<Self>) -> gpui::Point<Pixels> {
+        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
+        // todo!() Should `self.scroll_manager.anchor.scroll_position()` return `Pixels`?
+        // self.scroll_manager.anchor.scroll_position(&display_map)
+        todo!()
+    }
 
     pub fn set_scroll_anchor(&mut self, scroll_anchor: ScrollAnchor, cx: &mut ViewContext<Self>) {
         hide_hover(self, cx);

crates/go_to_line2/Cargo.toml 🔗

@@ -0,0 +1,25 @@
+[package]
+name = "go_to_line2"
+version = "0.1.0"
+edition = "2021"
+publish = false
+
+[lib]
+path = "src/go_to_line.rs"
+doctest = false
+
+[dependencies]
+editor = { package = "editor2", path = "../editor2" }
+gpui = { package = "gpui2", path = "../gpui2" }
+menu = { package = "menu2", path = "../menu2" }
+serde.workspace = true
+settings = { package = "settings2", path = "../settings2" }
+text = { package = "text2", path = "../text2" }
+workspace = { package = "workspace2", path = "../workspace2" }
+postage.workspace = true
+theme = { package = "theme2", path = "../theme2" }
+ui = { package = "ui2", path = "../ui2" }
+util = { path = "../util" }
+
+[dev-dependencies]
+editor = { package = "editor2", path = "../editor2", features = ["test-support"] }

crates/go_to_line2/src/go_to_line.rs 🔗

@@ -0,0 +1,224 @@
+use gpui::{div, px, red, AppContext, Div, Render, Styled, ViewContext, VisualContext};
+use serde::Deserialize;
+use workspace::ModalRegistry;
+
+// actions!(go_to_line, [Toggle]);
+#[derive(Clone, Default, PartialEq, Deserialize)]
+struct Toggle;
+
+pub fn init(cx: &mut AppContext) {
+    cx.global_mut::<ModalRegistry>()
+        .register_modal(Toggle, |_, cx| {
+            // if let Some(editor) = workspace
+            //     .active_item(cx)
+            //     .and_then(|active_item| active_item.downcast::<Editor>())
+            // {
+            //     cx.build_view(|cx| GoToLine::new(editor, cx))
+            // }
+            let view = cx.build_view(|_| GoToLine);
+            view
+        });
+
+    // cx.add_action(GoToLine::toggle);
+    // cx.add_action(GoToLine::confirm);
+    // cx.add_action(GoToLine::cancel);
+}
+
+pub struct GoToLine;
+
+impl Render for GoToLine {
+    type Element = Div<Self>;
+
+    fn render(&mut self, _cx: &mut ViewContext<Self>) -> Self::Element {
+        dbg!("rendering GoToLine");
+        div().bg(red()).w(px(100.0)).h(px(100.0))
+    }
+}
+
+// pub struct GoToLine {
+//     //line_editor: View<Editor>,
+//     active_editor: View<Editor>,
+//     prev_scroll_position: Option<gpui::Point<Pixels>>,
+//     cursor_point: Point,
+//     max_point: Point,
+//     has_focus: bool,
+// }
+
+// pub enum Event {
+//     Dismissed,
+// }
+
+// impl GoToLine {
+//     pub fn new(active_editor: View<Editor>, cx: &mut ViewContext<Self>) -> Self {
+//         // let line_editor = cx.build_view(|cx| {
+//         //     Editor::single_line(
+//         //         Some(Arc::new(|theme| theme.picker.input_editor.clone())),
+//         //         cx,
+//         //     )
+//         // });
+//         // cx.subscribe(&line_editor, Self::on_line_editor_event)
+//         //     .detach();
+
+//         let (scroll_position, cursor_point, max_point) = active_editor.update(cx, |editor, cx| {
+//             let scroll_position = editor.scroll_position(cx);
+//             let buffer = editor.buffer().read(cx).snapshot(cx);
+//             (
+//                 Some(scroll_position),
+//                 editor.selections.newest(cx).head(),
+//                 buffer.max_point(),
+//             )
+//         });
+
+//         cx.on_release(|_, on_release| {}).detach();
+
+//         Self {
+//             //line_editor,
+//             active_editor,
+//             prev_scroll_position: scroll_position,
+//             cursor_point,
+//             max_point,
+//             has_focus: false,
+//         }
+//     }
+
+//     fn cancel(&mut self, _: &Cancel, cx: &mut ViewContext<Self>) {
+//         cx.emit(Event::Dismissed);
+//     }
+
+//     fn confirm(&mut self, _: &Confirm, cx: &mut ViewContext<Self>) {
+//         self.prev_scroll_position.take();
+//         if let Some(point) = self.point_from_query(cx) {
+//             self.active_editor.update(cx, |active_editor, cx| {
+//                 let snapshot = active_editor.snapshot(cx).display_snapshot;
+//                 let point = snapshot.buffer_snapshot.clip_point(point, Bias::Left);
+//                 active_editor.change_selections(Some(Autoscroll::center()), cx, |s| {
+//                     s.select_ranges([point..point])
+//                 });
+//             });
+//         }
+
+//         cx.emit(Event::Dismissed);
+//     }
+
+//     fn on_line_editor_event(
+//         &mut self,
+//         _: View<Editor>,
+//         event: &editor::Event,
+//         cx: &mut ViewContext<Self>,
+//     ) {
+//         match event {
+//             editor::Event::Blurred => cx.emit(Event::Dismissed),
+//             editor::Event::BufferEdited { .. } => {
+//                 if let Some(point) = self.point_from_query(cx) {
+//                     // todo!()
+//                     // self.active_editor.update(cx, |active_editor, cx| {
+//                     //     let snapshot = active_editor.snapshot(cx).display_snapshot;
+//                     //     let point = snapshot.buffer_snapshot.clip_point(point, Bias::Left);
+//                     //     let display_point = point.to_display_point(&snapshot);
+//                     //     let row = display_point.row();
+//                     //     active_editor.highlight_rows(Some(row..row + 1));
+//                     //     active_editor.request_autoscroll(Autoscroll::center(), cx);
+//                     // });
+//                     cx.notify();
+//                 }
+//             }
+//             _ => {}
+//         }
+//     }
+
+//     fn point_from_query(&self, cx: &ViewContext<Self>) -> Option<Point> {
+//         return None;
+//         // todo!()
+//         // let line_editor = self.line_editor.read(cx).text(cx);
+//         // let mut components = line_editor
+//         //     .splitn(2, FILE_ROW_COLUMN_DELIMITER)
+//         //     .map(str::trim)
+//         //     .fuse();
+//         // let row = components.next().and_then(|row| row.parse::<u32>().ok())?;
+//         // let column = components.next().and_then(|col| col.parse::<u32>().ok());
+//         // Some(Point::new(
+//         //     row.saturating_sub(1),
+//         //     column.unwrap_or(0).saturating_sub(1),
+//         // ))
+//     }
+// }
+
+// impl EventEmitter for GoToLine {
+//     type Event = Event;
+// }
+
+// impl Entity for GoToLine {
+//     fn release(&mut self, cx: &mut AppContext) {
+//         let scroll_position = self.prev_scroll_position.take();
+//         self.active_editor.window().update(cx, |cx| {
+//             self.active_editor.update(cx, |editor, cx| {
+//                 editor.highlight_rows(None);
+//                 if let Some(scroll_position) = scroll_position {
+//                     editor.set_scroll_position(scroll_position, cx);
+//                 }
+//             })
+//         });
+//     }
+// }
+
+// impl Render for GoToLine {
+//     type Element = Div<Self>;
+
+//     fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
+//         // todo!()
+//         div()
+//     }
+// }
+
+// impl View for GoToLine {
+//     fn ui_name() -> &'static str {
+//         "GoToLine"
+//     }
+
+//     fn render(&mut self, cx: &mut ViewContext<Self>) -> AnyElement<Self> {
+//         let theme = &theme::current(cx).picker;
+
+//         let label = format!(
+//             "{}{FILE_ROW_COLUMN_DELIMITER}{} of {} lines",
+//             self.cursor_point.row + 1,
+//             self.cursor_point.column + 1,
+//             self.max_point.row + 1
+//         );
+
+//         Flex::new(Axis::Vertical)
+//             .with_child(
+//                 ChildView::new(&self.line_editor, cx)
+//                     .contained()
+//                     .with_style(theme.input_editor.container),
+//             )
+//             .with_child(
+//                 Label::new(label, theme.no_matches.label.clone())
+//                     .contained()
+//                     .with_style(theme.no_matches.container),
+//             )
+//             .contained()
+//             .with_style(theme.container)
+//             .constrained()
+//             .with_max_width(500.0)
+//             .into_any_named("go to line")
+//     }
+
+//     fn focus_in(&mut self, _: AnyView, cx: &mut ViewContext<Self>) {
+//         self.has_focus = true;
+//         cx.focus(&self.line_editor);
+//     }
+
+//     fn focus_out(&mut self, _: AnyView, _: &mut ViewContext<Self>) {
+//         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)
+//     }
+// }

crates/gpui2/src/action.rs 🔗

@@ -24,12 +24,12 @@ macro_rules! actions {
 
     ( $name:ident ) => {
         #[derive(::std::clone::Clone, ::std::default::Default, ::std::fmt::Debug, ::std::cmp::PartialEq, $crate::serde::Deserialize)]
-        struct $name;
+        pub struct $name;
     };
 
     ( $name:ident { $($token:tt)* } ) => {
         #[derive(::std::clone::Clone, ::std::default::Default, ::std::fmt::Debug, ::std::cmp::PartialEq, $crate::serde::Deserialize)]
-        struct $name { $($token)* }
+        pub struct $name { $($token)* }
     };
 
     ( $name:ident, $($rest:tt)* ) => {

crates/gpui2/src/app.rs 🔗

@@ -779,11 +779,21 @@ impl AppContext {
         (build)(params)
     }
 
-    /// Halt propagation of a mouse event, keyboard event, or action. This prevents listeners
-    /// that have not yet been invoked from receiving the event.
+    /// Event handlers propagate events by default. Call this method to stop dispatching to
+    /// event handlers with a lower z-index (mouse) or higher in the tree (keyboard). This is
+    /// the opposite of [propagate]. It's also possible to cancel a call to [propagate] by
+    /// calling this method before effects are flushed.
     pub fn stop_propagation(&mut self) {
         self.propagate_event = false;
     }
+
+    /// Action handlers stop propagation by default during the bubble phase of action dispatch
+    /// dispatching to action handlers higher in the element tree. This is the opposite of
+    /// [stop_propagation]. It's also possible to cancel a call to [stop_propagate] by calling
+    /// this method before effects are flushed.
+    pub fn propagate(&mut self) {
+        self.propagate_event = true;
+    }
 }
 
 impl Context for AppContext {

crates/gpui2/src/window.rs 🔗

@@ -300,7 +300,8 @@ impl Window {
 
 /// When constructing the element tree, we maintain a stack of key dispatch frames until we
 /// find the focused element. We interleave key listeners with dispatch contexts so we can use the
-/// contexts when matching key events against the keymap.
+/// contexts when matching key events against the keymap. A key listener can be either an action
+/// handler or a [KeyDown] / [KeyUp] event listener.
 enum KeyDispatchStackFrame {
     Listener {
         event_type: TypeId,
@@ -1048,6 +1049,10 @@ impl<'a> WindowContext<'a> {
 
     /// Dispatch a mouse or keyboard event on the window.
     pub fn dispatch_event(&mut self, event: InputEvent) -> bool {
+        // Handlers may set this to false by calling `stop_propagation`
+        self.app.propagate_event = true;
+        self.window.default_prevented = false;
+
         let event = match event {
             // Track the mouse position with our own state, since accessing the platform
             // API for the mouse position can only occur on the main thread.
@@ -1101,10 +1106,6 @@ impl<'a> WindowContext<'a> {
         };
 
         if let Some(any_mouse_event) = event.mouse_event() {
-            // Handlers may set this to false by calling `stop_propagation`
-            self.app.propagate_event = true;
-            self.window.default_prevented = false;
-
             if let Some(mut handlers) = self
                 .window
                 .mouse_listeners
@@ -1314,6 +1315,7 @@ impl<'a> WindowContext<'a> {
                 } = stack_frame
                 {
                     if action_type == *event_type {
+                        self.app.propagate_event = false;
                         listener(action.as_any(), &[], DispatchPhase::Bubble, self);
                         if !self.app.propagate_event {
                             break;
@@ -1328,6 +1330,7 @@ impl<'a> WindowContext<'a> {
                 self.app.global_action_listeners.remove(&action_type)
             {
                 for listener in global_listeners.iter().rev() {
+                    self.app.propagate_event = false;
                     listener(action.as_ref(), DispatchPhase::Bubble, self);
                     if !self.app.propagate_event {
                         break;
@@ -2035,9 +2038,9 @@ impl<V> Context for ViewContext<'_, V> {
 impl<V: 'static> VisualContext for ViewContext<'_, V> {
     fn build_view<W: 'static>(
         &mut self,
-        build_view: impl FnOnce(&mut ViewContext<'_, W>) -> W,
+        build_view_state: impl FnOnce(&mut ViewContext<'_, W>) -> W,
     ) -> Self::Result<View<W>> {
-        self.window_cx.build_view(build_view)
+        self.window_cx.build_view(build_view_state)
     }
 
     fn update_view<V2: 'static, R>(

crates/language2/src/highlight_map.rs 🔗

@@ -95,6 +95,8 @@ mod tests {
             .iter()
             .map(|(name, color)| (name.to_string(), (*color).into()))
             .collect(),
+            inlay_style: HighlightStyle::default(),
+            suggestion_style: HighlightStyle::default(),
         };
 
         let capture_names = &[

crates/settings2/src/settings_file.rs 🔗

@@ -1,4 +1,4 @@
-use crate::{settings_store::SettingsStore, Settings};
+use crate::{settings_store::SettingsStore, KeymapFile, Settings};
 use anyhow::Result;
 use fs::Fs;
 use futures::{channel::mpsc, StreamExt};
@@ -117,3 +117,50 @@ pub fn update_settings_file<T: Settings>(
     })
     .detach_and_log_err(cx);
 }
+
+pub fn load_default_keymap(cx: &mut AppContext) {
+    for path in ["keymaps/default.json", "keymaps/vim.json"] {
+        KeymapFile::load_asset(path, cx).unwrap();
+    }
+
+    // todo!()
+    // if let Some(asset_path) = settings::get::<BaseKeymap>(cx).asset_path() {
+    //     KeymapFile::load_asset(asset_path, cx).unwrap();
+    // }
+}
+
+pub fn handle_keymap_file_changes(
+    mut user_keymap_file_rx: mpsc::UnboundedReceiver<String>,
+    cx: &mut AppContext,
+) {
+    cx.spawn(move |cx| async move {
+        //  let mut settings_subscription = None;
+        while let Some(user_keymap_content) = user_keymap_file_rx.next().await {
+            if let Some(keymap_content) = KeymapFile::parse(&user_keymap_content).log_err() {
+                cx.update(|cx| reload_keymaps(cx, &keymap_content)).ok();
+
+                // todo!()
+                // let mut old_base_keymap = cx.read(|cx| *settings::get::<BaseKeymap>(cx));
+                // drop(settings_subscription);
+                // settings_subscription = Some(cx.update(|cx| {
+                //     cx.observe_global::<SettingsStore, _>(move |cx| {
+                //         let new_base_keymap = *settings::get::<BaseKeymap>(cx);
+                //         if new_base_keymap != old_base_keymap {
+                //             old_base_keymap = new_base_keymap.clone();
+                //             reload_keymaps(cx, &keymap_content);
+                //         }
+                //     })
+                // }));
+            }
+        }
+    })
+    .detach();
+}
+
+fn reload_keymaps(cx: &mut AppContext, keymap_content: &KeymapFile) {
+    // todo!()
+    // cx.clear_bindings();
+    load_default_keymap(cx);
+    keymap_content.clone().add_to_cx(cx).log_err();
+    // cx.set_menus(menus::menus());
+}

crates/theme2/src/colors.rs 🔗

@@ -1,3 +1,5 @@
+use std::sync::Arc;
+
 use gpui::Hsla;
 use refineable::Refineable;
 
@@ -237,7 +239,7 @@ pub struct ThemeStyles {
     pub status: StatusColors,
     pub git: GitStatusColors,
     pub player: PlayerColors,
-    pub syntax: SyntaxTheme,
+    pub syntax: Arc<SyntaxTheme>,
 }
 
 #[cfg(test)]

crates/theme2/src/default_colors.rs 🔗

@@ -138,6 +138,8 @@ impl SyntaxTheme {
                 ("variable.special".into(), red().light().step_7().into()),
                 ("variant".into(), red().light().step_7().into()),
             ],
+            inlay_style: tomato().light().step_1().into(), // todo!("nate: use a proper style")
+            suggestion_style: orange().light().step_1().into(), // todo!("nate: use proper style")
         }
     }
 
@@ -193,6 +195,8 @@ impl SyntaxTheme {
                 ("variable.special".into(), red().dark().step_7().into()),
                 ("variant".into(), red().dark().step_7().into()),
             ],
+            inlay_style: tomato().dark().step_1().into(), // todo!("nate: use a proper style")
+            suggestion_style: orange().dark().step_1().into(), // todo!("nate: use a proper style")
         }
     }
 }

crates/theme2/src/default_theme.rs 🔗

@@ -1,3 +1,5 @@
+use std::sync::Arc;
+
 use crate::{
     colors::{GitStatusColors, PlayerColors, StatusColors, SystemColors, ThemeColors, ThemeStyles},
     default_color_scales, Appearance, SyntaxTheme, Theme, ThemeFamily,
@@ -14,7 +16,7 @@ fn zed_pro_daylight() -> Theme {
             status: StatusColors::default(),
             git: GitStatusColors::default(),
             player: PlayerColors::default(),
-            syntax: SyntaxTheme::default_light(),
+            syntax: Arc::new(SyntaxTheme::default_light()),
         },
     }
 }
@@ -30,7 +32,7 @@ pub(crate) fn zed_pro_moonlight() -> Theme {
             status: StatusColors::default(),
             git: GitStatusColors::default(),
             player: PlayerColors::default(),
-            syntax: SyntaxTheme::default_dark(),
+            syntax: Arc::new(SyntaxTheme::default_dark()),
         },
     }
 }

crates/theme2/src/registry.rs 🔗

@@ -52,7 +52,10 @@ impl ThemeRegistry {
                     status: StatusColors::default(),
                     git: GitStatusColors::default(),
                     player: PlayerColors::default(),
-                    syntax: SyntaxTheme::default_dark(),
+                    syntax: match user_theme.appearance {
+                        Appearance::Light => Arc::new(SyntaxTheme::default_light()),
+                        Appearance::Dark => Arc::new(SyntaxTheme::default_dark()),
+                    },
                 },
             }
         }));
@@ -81,7 +84,7 @@ impl Default for ThemeRegistry {
         };
 
         this.insert_theme_families([zed_pro_family()]);
-        this.insert_user_theme_familes(crate::all_imported_themes());
+        this.insert_user_theme_familes(crate::all_user_themes());
 
         this
     }

crates/theme2/src/syntax.rs 🔗

@@ -3,6 +3,8 @@ use gpui::{HighlightStyle, Hsla};
 #[derive(Clone, Default)]
 pub struct SyntaxTheme {
     pub highlights: Vec<(String, HighlightStyle)>,
+    pub inlay_style: HighlightStyle,
+    pub suggestion_style: HighlightStyle,
 }
 
 impl SyntaxTheme {
@@ -21,6 +23,8 @@ impl SyntaxTheme {
                     )
                 })
                 .collect(),
+            inlay_style: HighlightStyle::default(),
+            suggestion_style: HighlightStyle::default(),
         }
     }
 

crates/theme2/src/theme2.rs 🔗

@@ -77,7 +77,7 @@ impl Theme {
 
     /// Returns the [`SyntaxTheme`] for the theme.
     #[inline(always)]
-    pub fn syntax(&self) -> &SyntaxTheme {
+    pub fn syntax(&self) -> &Arc<SyntaxTheme> {
         &self.styles.syntax
     }
 
@@ -98,4 +98,25 @@ impl Theme {
     pub fn syntax_color(&self, name: &str) -> Hsla {
         self.syntax().color(name)
     }
+
+    /// Returns the [`StatusColors`] for the theme.
+    #[inline(always)]
+    pub fn diagnostic_style(&self) -> DiagnosticStyle {
+        DiagnosticStyle {
+            error: self.status().error,
+            warning: self.status().warning,
+            info: self.status().info,
+            hint: self.status().info,
+            ignored: self.status().ignored,
+        }
+    }
+}
+
+#[derive(Clone, Debug)]
+pub struct DiagnosticStyle {
+    pub error: Hsla,
+    pub warning: Hsla,
+    pub info: Hsla,
+    pub hint: Hsla,
+    pub ignored: Hsla,
 }

crates/theme2/src/themes/ayu.rs 🔗

@@ -1,3 +1,6 @@
+// This file was generated by the `theme_importer`.
+// Be careful when modifying it by hand.
+
 use gpui::rgba;
 
 use crate::{

crates/theme2/src/themes/mod.rs 🔗

@@ -1,3 +1,6 @@
+// This file was generated by the `theme_importer`.
+// Be careful when modifying it by hand.
+
 mod andromeda;
 mod ayu;
 mod dracula;
@@ -24,7 +27,7 @@ pub use synthwave_84::*;
 
 use crate::UserThemeFamily;
 
-pub(crate) fn all_imported_themes() -> Vec<UserThemeFamily> {
+pub(crate) fn all_user_themes() -> Vec<UserThemeFamily> {
     vec![
         rose_pine(),
         night_owl(),

crates/theme2/src/themes/nord.rs 🔗

@@ -1,3 +1,6 @@
+// This file was generated by the `theme_importer`.
+// Be careful when modifying it by hand.
+
 use gpui::rgba;
 
 use crate::{

crates/theme_importer/src/main.rs 🔗

@@ -5,6 +5,7 @@ mod vscode;
 use std::fs::{self, File};
 use std::io::Write;
 use std::path::PathBuf;
+use std::process::Command;
 use std::str::FromStr;
 
 use anyhow::{anyhow, Context, Result};
@@ -152,6 +153,9 @@ fn main() -> Result<()> {
 
         let theme_module = format!(
             r#"
+            // This file was generated by the `theme_importer`.
+            // Be careful when modifying it by hand.
+
             use gpui::rgba;
 
             use crate::{{
@@ -174,7 +178,7 @@ fn main() -> Result<()> {
         r#"
         use crate::UserThemeFamily;
 
-        pub(crate) fn all_imported_themes() -> Vec<UserThemeFamily> {{
+        pub(crate) fn all_user_themes() -> Vec<UserThemeFamily> {{
             vec![{all_themes}]
         }}
         "#,
@@ -187,6 +191,9 @@ fn main() -> Result<()> {
 
     let mod_rs_contents = format!(
         r#"
+        // This file was generated by the `theme_importer`.
+        // Be careful when modifying it by hand.
+
         {mod_statements}
 
         {use_statements}
@@ -208,5 +215,23 @@ fn main() -> Result<()> {
 
     mod_rs_file.write_all(mod_rs_contents.as_bytes())?;
 
+    println!("Formatting themes...");
+
+    let format_result = format_themes_crate()
+        // We need to format a second time to catch all of the formatting issues.
+        .and_then(|_| format_themes_crate());
+
+    if let Err(err) = format_result {
+        eprintln!("Failed to format themes: {}", err);
+    }
+
+    println!("Done!");
+
     Ok(())
 }
+
+fn format_themes_crate() -> std::io::Result<std::process::Output> {
+    Command::new("cargo")
+        .args(["fmt", "--package", "theme2"])
+        .output()
+}

crates/workspace2/src/modal_layer.rs 🔗

@@ -0,0 +1,121 @@
+use std::{any::TypeId, sync::Arc};
+
+use gpui::{
+    div, AnyView, AppContext, Component, DispatchPhase, Div, ParentElement, Render,
+    StatelessInteractive, View, ViewContext,
+};
+
+use crate::Workspace;
+
+pub struct ModalRegistry {
+    registered_modals: Vec<(TypeId, Box<dyn Fn(Div<Workspace>) -> Div<Workspace>>)>,
+}
+
+pub trait Modal {}
+
+#[derive(Clone)]
+pub struct ModalLayer {
+    open_modal: Option<AnyView>,
+}
+
+pub fn init_modal_registry(cx: &mut AppContext) {
+    cx.set_global(ModalRegistry {
+        registered_modals: Vec::new(),
+    });
+}
+
+struct ToggleModal {
+    name: String,
+}
+
+// complete change of plan?
+// on_action(ToggleModal{ name})
+// register_modal(name, |workspace, cx| { ... })
+
+impl ModalRegistry {
+    pub fn register_modal<A: 'static, V, B>(&mut self, action: A, build_view: B)
+    where
+        V: Render,
+        B: Fn(&Workspace, &mut ViewContext<Workspace>) -> View<V> + 'static,
+    {
+        let build_view = Arc::new(build_view);
+
+        dbg!("yonder");
+        self.registered_modals.push((
+            TypeId::of::<A>(),
+            Box::new(move |mut div| {
+                let build_view = build_view.clone();
+                dbg!("this point");
+
+                div.on_action(
+                    move |workspace: &mut Workspace,
+                          event: &A,
+                          phase: DispatchPhase,
+                          cx: &mut ViewContext<Workspace>| {
+                        dbg!("GOT HERE");
+                        if phase == DispatchPhase::Capture {
+                            return;
+                        }
+
+                        let new_modal = (build_view)(workspace, cx);
+                        workspace.modal_layer.update(cx, |modal_layer, _| {
+                            modal_layer.open_modal = Some(new_modal.into());
+                        });
+
+                        cx.notify();
+                    },
+                )
+            }),
+        ));
+    }
+}
+
+impl ModalLayer {
+    pub fn new() -> Self {
+        Self { open_modal: None }
+    }
+
+    pub fn render(&self, cx: &ViewContext<Workspace>) -> impl Component<Workspace> {
+        dbg!("rendering ModalLayer");
+
+        let mut div = div();
+
+        // div, c workspace.toggle_modal()div.on_action()) {
+        //
+        // }
+
+        // for (type_id, action) in cx.global::<ModalRegistry>().registered_modals.iter() {
+        //     div = div.useful_on_action(*type_id, action)
+        // }
+
+        for (_, action) in cx.global::<ModalRegistry>().registered_modals.iter() {
+            div = (action)(div);
+        }
+
+        div.children(self.open_modal.clone())
+    }
+}
+
+// impl Render for ModalLayer {
+//     type Element = Div<Self>;
+
+//     fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
+//         let mut div = div();
+//         for (type_id, build_view) in cx.global::<ModalRegistry>().registered_modals {
+//             div = div.useful_on_action(
+//                 type_id,
+//                 Box::new(|this, _: dyn Any, phase, cx: &mut ViewContext<Self>| {
+//                     if phase == DispatchPhase::Capture {
+//                         return;
+//                     }
+//                     self.workspace.update(cx, |workspace, cx| {
+//                         self.open_modal = Some(build_view(workspace, cx));
+//                     });
+//                     cx.notify();
+//                 }),
+//             )
+//         }
+
+//         div
+//     }
+// }

crates/workspace2/src/workspace2.rs 🔗

@@ -10,6 +10,7 @@ mod persistence;
 pub mod searchable;
 // todo!()
 // pub mod shared_screen;
+mod modal_layer;
 mod status_bar;
 mod toolbar;
 mod workspace_settings;
@@ -45,6 +46,8 @@ use item::{FollowableItem, FollowableItemHandle, Item, ItemHandle, ItemSettings,
 use itertools::Itertools;
 use language2::LanguageRegistry;
 use lazy_static::lazy_static;
+pub use modal_layer::ModalRegistry;
+use modal_layer::{init_modal_registry, ModalLayer};
 use node_runtime::NodeRuntime;
 use notifications::{simple_message_notification::MessageNotification, NotificationHandle};
 pub use pane::*;
@@ -81,26 +84,6 @@ lazy_static! {
         .and_then(parse_pixel_position_env_var);
 }
 
-// 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<T: Modal> ModalHandle for View<T> {
-//     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);
 
@@ -243,6 +226,7 @@ pub fn init_settings(cx: &mut AppContext) {
 
 pub fn init(app_state: Arc<AppState>, cx: &mut AppContext) {
     init_settings(cx);
+    init_modal_registry(cx);
     pane::init(cx);
     notifications::init(cx);
 
@@ -550,7 +534,6 @@ pub enum Event {
 pub struct Workspace {
     weak_self: WeakView<Self>,
     focus_handle: FocusHandle,
-    //     modal: Option<ActiveModal>,
     zoomed: Option<AnyWeakView>,
     zoomed_position: Option<DockPosition>,
     center: PaneGroup,
@@ -563,6 +546,7 @@ pub struct Workspace {
     last_active_center_pane: Option<WeakView<Pane>>,
     last_active_view_id: Option<proto::ViewId>,
     status_bar: View<StatusBar>,
+    modal_layer: View<ModalLayer>,
     //     titlebar_item: Option<AnyViewHandle>,
     notifications: Vec<(TypeId, usize, Box<dyn NotificationHandle>)>,
     project: Model<Project>,
@@ -580,11 +564,6 @@ pub struct Workspace {
     pane_history_timestamp: Arc<AtomicUsize>,
 }
 
-// struct ActiveModal {
-//     view: Box<dyn ModalHandle>,
-//     previously_focused_view_id: Option<usize>,
-// }
-
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
 pub struct ViewId {
     pub creator: PeerId,
@@ -718,6 +697,8 @@ impl Workspace {
             status_bar
         });
 
+        let modal_layer = cx.build_view(|cx| ModalLayer::new());
+
         // todo!()
         // cx.update_default_global::<DragAndDrop<Workspace>, _, _>(|drag_and_drop, _| {
         //     drag_and_drop.register_container(weak_handle.clone());
@@ -769,7 +750,6 @@ impl Workspace {
         Workspace {
             weak_self: weak_handle.clone(),
             focus_handle: cx.focus_handle(),
-            // modal: None,
             zoomed: None,
             zoomed_position: None,
             center: PaneGroup::new(center_pane.clone()),
@@ -779,6 +759,7 @@ impl Workspace {
             last_active_center_pane: Some(center_pane.downgrade()),
             last_active_view_id: None,
             status_bar,
+            modal_layer,
             // titlebar_item: None,
             notifications: Default::default(),
             left_dock,
@@ -1620,63 +1601,6 @@ impl Workspace {
         })
     }
 
-    //     /// Returns the modal that was toggled closed if it was open.
-    //     pub fn toggle_modal<V, F>(
-    //         &mut self,
-    //         cx: &mut ViewContext<Self>,
-    //         build_view: F,
-    //     ) -> Option<View<V>>
-    //     where
-    //         V: 'static + Modal,
-    //         F: FnOnce(&mut Self, &mut ViewContext<Self>) -> View<V>,
-    //     {
-    //         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.
-    //         if let Some(already_open_modal) = self
-    //             .dismiss_modal(cx)
-    //             .and_then(|modal| modal.downcast::<V>())
-    //         {
-    //             cx.focus_self();
-    //             Some(already_open_modal)
-    //         } else {
-    //             let modal = build_view(self, cx);
-    //             cx.subscribe(&modal, |this, _, event, cx| {
-    //                 if V::dismiss_on_event(event) {
-    //                     this.dismiss_modal(cx);
-    //                 }
-    //             })
-    //             .detach();
-    //             let previously_focused_view_id = cx.focused_view_id();
-    //             cx.focus(&modal);
-    //             self.modal = Some(ActiveModal {
-    //                 view: Box::new(modal),
-    //                 previously_focused_view_id,
-    //             });
-    //             None
-    //         }
-    //     }
-
-    //     pub fn modal<V: 'static + View>(&self) -> Option<View<V>> {
-    //         self.modal
-    //             .as_ref()
-    //             .and_then(|modal| modal.view.as_any().clone().downcast::<V>())
-    //     }
-
-    //     pub fn dismiss_modal(&mut self, cx: &mut ViewContext<Self>) -> Option<AnyViewHandle> {
-    //         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
-    //         }
-    //     }
-
     pub fn items<'a>(
         &'a self,
         cx: &'a AppContext,
@@ -3916,6 +3840,8 @@ impl Render for Workspace {
                               //         .on_click(Arc::new(|workspace, cx| workspace.toggle_debug(cx))),
                               // ),
             )
+            //     .child(self.modal_layer.clone())
+            .child(self.modal_layer.read(cx).render(cx))
     }
 }
 

crates/zed2/Cargo.toml 🔗

@@ -41,7 +41,7 @@ editor = { package="editor2", path = "../editor2" }
 fs = { package = "fs2", path = "../fs2" }
 fsevent = { path = "../fsevent" }
 fuzzy = { path = "../fuzzy" }
-# go_to_line = { path = "../go_to_line" }
+go_to_line = { package = "go_to_line2", path = "../go_to_line2" }
 gpui = { package = "gpui2", path = "../gpui2" }
 install_cli = { path = "../install_cli" }
 journal = { package = "journal2", path = "../journal2" }

crates/zed2/src/main.rs 🔗

@@ -20,7 +20,8 @@ use node_runtime::RealNodeRuntime;
 use parking_lot::Mutex;
 use serde::{Deserialize, Serialize};
 use settings::{
-    default_settings, handle_settings_file_changes, watch_config_file, Settings, SettingsStore,
+    default_settings, handle_keymap_file_changes, handle_settings_file_changes, watch_config_file,
+    Settings, SettingsStore,
 };
 use simplelog::ConfigBuilder;
 use smol::process::Command;
@@ -76,7 +77,7 @@ fn main() {
         fs.clone(),
         paths::SETTINGS.clone(),
     );
-    let _user_keymap_file_rx = watch_config_file(
+    let user_keymap_file_rx = watch_config_file(
         &app.background_executor(),
         fs.clone(),
         paths::KEYMAP.clone(),
@@ -116,7 +117,7 @@ fn main() {
             .unwrap();
         cx.set_global(store);
         handle_settings_file_changes(user_settings_file_rx, cx);
-        // handle_keymap_file_changes(user_keymap_file_rx, cx);
+        handle_keymap_file_changes(user_keymap_file_rx, cx);
 
         let client = client::Client::new(http.clone(), cx);
         let mut languages = LanguageRegistry::new(login_shell_env_loaded);
@@ -140,17 +141,6 @@ fn main() {
         // command_palette::init(cx);
         language::init(cx);
         editor::init(cx);
-        // go_to_line::init(cx);
-        // file_finder::init(cx);
-        // outline::init(cx);
-        // project_symbols::init(cx);
-        // project_panel::init(Assets, cx);
-        // channel::init(&client, user_store.clone(), cx);
-        // diagnostics::init(cx);
-        // search::init(cx);
-        // semantic_index::init(fs.clone(), http.clone(), languages.clone(), cx);
-        // vim::init(cx);
-        // terminal_view::init(cx);
         copilot::init(
             copilot_language_server_id,
             http.clone(),
@@ -193,6 +183,18 @@ fn main() {
         workspace::init(app_state.clone(), cx);
         // recent_projects::init(cx);
 
+        go_to_line::init(cx);
+        // file_finder::init(cx);
+        // outline::init(cx);
+        // project_symbols::init(cx);
+        // project_panel::init(Assets, cx);
+        // channel::init(&client, user_store.clone(), cx);
+        // diagnostics::init(cx);
+        // search::init(cx);
+        // semantic_index::init(fs.clone(), http.clone(), languages.clone(), cx);
+        // vim::init(cx);
+        // terminal_view::init(cx);
+
         // journal2::init(app_state.clone(), cx);
         // language_selector::init(cx);
         // theme_selector::init(cx);