Merge branch 'main' into editor-tests

Mikayla created

Change summary

Cargo.lock                                                   |   59 
Cargo.toml                                                   |    4 
assets/keymaps/jetbrains.json                                |    3 
assets/settings/default.json                                 |   12 
assets/themes/src/vscode/gruvbox/gruvbox-dark-hard.json      |   38 
assets/themes/src/vscode/gruvbox/gruvbox-dark-medium.json    |   38 
assets/themes/src/vscode/gruvbox/gruvbox-dark-soft.json      |   38 
assets/themes/src/vscode/gruvbox/gruvbox-light-hard.json     |   38 
assets/themes/src/vscode/gruvbox/gruvbox-light-medium.json   |   38 
assets/themes/src/vscode/gruvbox/gruvbox-light-soft.json     |   38 
assets/themes/src/vscode/noctis/family.json                  |  118 
assets/themes/src/vscode/rose-pine/family.json               |   38 
assets/themes/src/vscode/synthwave-84/synthwave.json         | 1659 
crates/command_palette2/Cargo.toml                           |   34 
crates/command_palette2/src/command_palette.rs               |  532 
crates/diagnostics/src/diagnostics.rs                        |    7 
crates/editor/src/editor_settings.rs                         |   12 
crates/editor/src/items.rs                                   |   44 
crates/editor2/Cargo.toml                                    |    1 
crates/editor2/src/editor.rs                                 |  644 
crates/editor2/src/editor_settings.rs                        |   10 
crates/editor2/src/element.rs                                |  207 
crates/editor2/src/inlay_hint_cache.rs                       | 5057 ++---
crates/editor2/src/items.rs                                  |   44 
crates/editor2/src/scroll/scroll_amount.rs                   |   27 
crates/go_to_line2/src/go_to_line.rs                         |   62 
crates/gpui/src/elements/flex.rs                             |   11 
crates/gpui/src/geometry.rs                                  |    6 
crates/gpui2/src/action.rs                                   |   33 
crates/gpui2/src/color.rs                                    |  127 
crates/gpui2/src/element.rs                                  |  111 
crates/gpui2/src/elements/text.rs                            |    7 
crates/gpui2/src/elements/uniform_list.rs                    |  132 
crates/gpui2/src/geometry.rs                                 |   14 
crates/gpui2/src/interactive.rs                              |    6 
crates/gpui2/src/platform/test/platform.rs                   |    3 
crates/gpui2/src/platform/test/window.rs                     |   69 
crates/gpui2/src/style.rs                                    |    6 
crates/gpui2/src/taffy.rs                                    |   31 
crates/gpui2/src/view.rs                                     |    4 
crates/gpui2/src/window.rs                                   |  120 
crates/language/src/buffer_tests.rs                          |   54 
crates/language2/src/buffer_tests.rs                         |   54 
crates/picker2/Cargo.toml                                    |    1 
crates/picker2/src/picker2.rs                                |   42 
crates/prettier/src/prettier.rs                              |  153 
crates/prettier2/src/prettier2.rs                            |  154 
crates/project/src/project.rs                                |   16 
crates/project2/src/project2.rs                              |   16 
crates/refineable/derive_refineable/src/derive_refineable.rs |   33 
crates/theme2/Cargo.toml                                     |    1 
crates/theme2/src/colors.rs                                  |   10 
crates/theme2/src/default_colors.rs                          |  141 
crates/theme2/src/registry.rs                                |   39 
crates/theme2/src/scale.rs                                   |    2 
crates/theme2/src/theme2.rs                                  |    2 
crates/theme2/src/themes/andromeda.rs                        |  226 
crates/theme2/src/themes/ayu.rs                              |  679 
crates/theme2/src/themes/dracula.rs                          |  129 
crates/theme2/src/themes/gruvbox.rs                          |  922 +
crates/theme2/src/themes/mod.rs                              |    6 
crates/theme2/src/themes/night_owl.rs                        |  292 
crates/theme2/src/themes/noctis.rs                           | 2428 ++
crates/theme2/src/themes/nord.rs                             |  149 
crates/theme2/src/themes/notctis.rs                          |  446 
crates/theme2/src/themes/palenight.rs                        |  508 
crates/theme2/src/themes/rose_pine.rs                        |  396 
crates/theme2/src/themes/solarized.rs                        |  302 
crates/theme2/src/themes/synthwave_84.rs                     |  143 
crates/theme2/src/user_theme.rs                              |   74 
crates/theme_importer/Cargo.toml                             |    5 
crates/theme_importer/src/main.rs                            |   12 
crates/theme_importer/src/theme_printer.rs                   |  119 
crates/theme_importer/src/vscode.rs                          |  575 
crates/theme_importer/src/vscode/converter.rs                |  372 
crates/theme_importer/src/vscode/syntax.rs                   |  218 
crates/theme_importer/src/vscode/theme.rs                    |  412 
crates/ui2/src/components.rs                                 |    2 
crates/ui2/src/components/divider.rs                         |   46 
crates/ui2/src/components/elevated_surface.rs                |    2 
crates/ui2/src/components/icon_button.rs                     |    1 
crates/ui2/src/components/list.rs                            |    2 
crates/ui2/src/components/tooltip.rs                         |    4 
crates/ui2/src/elevation.md                                  |    4 
crates/ui2/src/elevation.rs                                  |   38 
crates/ui2/src/styled_ext.rs                                 |   75 
crates/workspace2/src/modal_layer.rs                         |  163 
crates/workspace2/src/workspace2.rs                          |  349 
crates/zed/src/languages/javascript/overrides.scm            |    7 
crates/zed/src/languages/tsx/overrides.scm                   |    7 
crates/zed/src/languages/typescript.rs                       |   21 
crates/zed2/Cargo.toml                                       |    4 
crates/zed2/src/languages/javascript/overrides.scm           |    7 
crates/zed2/src/languages/tsx/overrides.scm                  |    7 
crates/zed2/src/languages/typescript.rs                      |   21 
crates/zed2/src/main.rs                                      |    4 
crates/zed_actions2/Cargo.toml                               |   11 
crates/zed_actions2/src/lib.rs                               |   34 
script/eula/eula.md                                          |    2 
script/eula/eula.rtf                                         |    2 
100 files changed, 13,623 insertions(+), 5,803 deletions(-)

Detailed changes

Cargo.lock πŸ”—

@@ -1275,11 +1275,10 @@ dependencies = [
 
 [[package]]
 name = "cc"
-version = "1.0.83"
+version = "1.0.84"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
+checksum = "0f8e7c90afad890484a21653d08b6e209ae34770fb5ee298f9c699fcc1e5c856"
 dependencies = [
- "jobserver",
  "libc",
 ]
 
@@ -1880,6 +1879,30 @@ dependencies = [
  "zed-actions",
 ]
 
+[[package]]
+name = "command_palette2"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "collections",
+ "ctor",
+ "editor2",
+ "env_logger 0.9.3",
+ "fuzzy2",
+ "gpui2",
+ "language2",
+ "picker2",
+ "project2",
+ "serde",
+ "serde_json",
+ "settings2",
+ "theme2",
+ "ui2",
+ "util",
+ "workspace2",
+ "zed_actions2",
+]
+
 [[package]]
 name = "component_test"
 version = "0.1.0"
@@ -2781,6 +2804,7 @@ dependencies = [
  "tree-sitter-html",
  "tree-sitter-rust",
  "tree-sitter-typescript",
+ "ui2",
  "unindent",
  "util",
  "workspace2",
@@ -4370,15 +4394,6 @@ version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
 
-[[package]]
-name = "jobserver"
-version = "0.1.26"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2"
-dependencies = [
- "libc",
-]
-
 [[package]]
 name = "journal"
 version = "0.1.0"
@@ -4433,6 +4448,12 @@ dependencies = [
  "wasm-bindgen",
 ]
 
+[[package]]
+name = "json_comments"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9dbbfed4e59ba9750e15ba154fdfd9329cee16ff3df539c2666b70f58cc32105"
+
 [[package]]
 name = "jwt"
 version = "0.16.0"
@@ -6129,6 +6150,7 @@ dependencies = [
  "serde_json",
  "settings2",
  "theme2",
+ "ui2",
  "util",
 ]
 
@@ -9155,10 +9177,13 @@ dependencies = [
  "anyhow",
  "convert_case 0.6.0",
  "gpui2",
+ "indexmap 1.9.3",
+ "json_comments",
  "log",
  "rust-embed",
  "serde",
  "simplelog",
+ "strum",
  "theme2",
  "uuid 1.4.1",
 ]
@@ -11362,6 +11387,7 @@ dependencies = [
  "cli",
  "client2",
  "collections",
+ "command_palette2",
  "copilot2",
  "ctor",
  "db2",
@@ -11448,6 +11474,15 @@ dependencies = [
  "util",
  "uuid 1.4.1",
  "workspace2",
+ "zed_actions2",
+]
+
+[[package]]
+name = "zed_actions2"
+version = "0.1.0"
+dependencies = [
+ "gpui2",
+ "serde",
 ]
 
 [[package]]

Cargo.toml πŸ”—

@@ -20,6 +20,7 @@ members = [
     "crates/collab_ui",
     "crates/collections",
     "crates/command_palette",
+    "crates/command_palette2",
     "crates/component_test",
     "crates/context_menu",
     "crates/copilot",
@@ -110,7 +111,8 @@ members = [
     "crates/xtask",
     "crates/zed",
     "crates/zed2",
-    "crates/zed-actions"
+    "crates/zed-actions",
+    "crates/zed_actions2"
 ]
 default-members = ["crates/zed"]
 resolver = "2"

assets/keymaps/jetbrains.json πŸ”—

@@ -10,6 +10,7 @@
     "bindings": {
       "ctrl->": "zed::IncreaseBufferFontSize",
       "ctrl-<": "zed::DecreaseBufferFontSize",
+      "ctrl-shift-j": "editor::JoinLines",
       "cmd-d": "editor::DuplicateLine",
       "cmd-backspace": "editor::DeleteLine",
       "cmd-pagedown": "editor::MovePageDown",
@@ -18,7 +19,7 @@
       "cmd-alt-enter": "editor::NewlineAbove",
       "shift-enter": "editor::NewlineBelow",
       "cmd--": "editor::Fold",
-      "cmd-=": "editor::UnfoldLines",
+      "cmd-+": "editor::UnfoldLines",
       "alt-shift-g": "editor::SplitSelectionIntoLines",
       "ctrl-g": [
         "editor::SelectNext",

assets/settings/default.json πŸ”—

@@ -102,6 +102,16 @@
     "selections": true
   },
   "relative_line_numbers": false,
+  // When to populate a new search's query based on the text under the cursor.
+  // This setting can take the following three values:
+  //
+  // 1. Always populate the search query with the word under the cursor (default).
+  //    "always"
+  // 2. Only populate the search query when there is text selected
+  //    "selection"
+  // 3. Never populate the search query
+  //    "never"
+  "seed_search_query_from_cursor": "always",
   // Inlay hint related settings
   "inlay_hints": {
     // Global switch to toggle hints on and off, switched off by default.
@@ -199,7 +209,7 @@
   "ensure_final_newline_on_save": true,
   // Whether or not to perform a buffer format before saving
   "format_on_save": "on",
-  // How to perform a buffer format. This setting can take two values:
+  // How to perform a buffer format. This setting can take 4 values:
   //
   // 1. Format code using the current language server:
   //     "formatter": "language_server"

assets/themes/src/vscode/gruvbox/gruvbox-dark-hard.json πŸ”—

@@ -423,7 +423,10 @@
             }
         },
         {
-            "scope": ["string.interpolated.dollar.shell", "string.interpolated.backtick.shell"],
+            "scope": [
+                "string.interpolated.dollar.shell",
+                "string.interpolated.backtick.shell"
+            ],
             "settings": {
                 "foreground": "#8ec07c"
             }
@@ -489,13 +492,19 @@
 
         {
             "name": "coloring of the Java import and package identifiers",
-            "scope": ["storage.modifier.import.java", "storage.modifier.package.java"],
+            "scope": [
+                "storage.modifier.import.java",
+                "storage.modifier.package.java"
+            ],
             "settings": {
                 "foreground": "#bdae93"
             }
         },
         {
-            "scope": ["keyword.other.import.java", "keyword.other.package.java"],
+            "scope": [
+                "keyword.other.import.java",
+                "keyword.other.package.java"
+            ],
             "settings": {
                 "foreground": "#8ec07c"
             }
@@ -628,7 +637,9 @@
         },
         {
             "name": "JSON Level 0",
-            "scope": ["source.json meta.structure.dictionary.json support.type.property-name.json"],
+            "scope": [
+                "source.json meta.structure.dictionary.json support.type.property-name.json"
+            ],
             "settings": {
                 "foreground": "#b8bb26"
             }
@@ -761,7 +772,10 @@
             }
         },
         {
-            "scope": ["source.go keyword.interface", "source.go keyword.struct"],
+            "scope": [
+                "source.go keyword.interface",
+                "source.go keyword.struct"
+            ],
             "settings": {
                 "foreground": "#83a598"
             }
@@ -788,7 +802,10 @@
 
         {
             "name": "ReasonML String",
-            "scope": ["source.reason string.double", "source.reason string.regexp"],
+            "scope": [
+                "source.reason string.double",
+                "source.reason string.regexp"
+            ],
             "settings": {
                 "foreground": "#b8bb26"
             }
@@ -809,7 +826,10 @@
         },
         {
             "name": "ReasonML property",
-            "scope": ["source.reason support.property-value", "source.reason entity.name.filename"],
+            "scope": [
+                "source.reason support.property-value",
+                "source.reason entity.name.filename"
+            ],
             "settings": {
                 "foreground": "#fe8019"
             }
@@ -831,7 +851,9 @@
         },
         {
             "name": "Powershell function attribute",
-            "scope": ["source.powershell support.function.attribute.powershell"],
+            "scope": [
+                "source.powershell support.function.attribute.powershell"
+            ],
             "settings": {
                 "foreground": "#bdae93"
             }

assets/themes/src/vscode/gruvbox/gruvbox-dark-medium.json πŸ”—

@@ -423,7 +423,10 @@
             }
         },
         {
-            "scope": ["string.interpolated.dollar.shell", "string.interpolated.backtick.shell"],
+            "scope": [
+                "string.interpolated.dollar.shell",
+                "string.interpolated.backtick.shell"
+            ],
             "settings": {
                 "foreground": "#8ec07c"
             }
@@ -489,13 +492,19 @@
 
         {
             "name": "coloring of the Java import and package identifiers",
-            "scope": ["storage.modifier.import.java", "storage.modifier.package.java"],
+            "scope": [
+                "storage.modifier.import.java",
+                "storage.modifier.package.java"
+            ],
             "settings": {
                 "foreground": "#bdae93"
             }
         },
         {
-            "scope": ["keyword.other.import.java", "keyword.other.package.java"],
+            "scope": [
+                "keyword.other.import.java",
+                "keyword.other.package.java"
+            ],
             "settings": {
                 "foreground": "#8ec07c"
             }
@@ -628,7 +637,9 @@
         },
         {
             "name": "JSON Level 0",
-            "scope": ["source.json meta.structure.dictionary.json support.type.property-name.json"],
+            "scope": [
+                "source.json meta.structure.dictionary.json support.type.property-name.json"
+            ],
             "settings": {
                 "foreground": "#b8bb26"
             }
@@ -761,7 +772,10 @@
             }
         },
         {
-            "scope": ["source.go keyword.interface", "source.go keyword.struct"],
+            "scope": [
+                "source.go keyword.interface",
+                "source.go keyword.struct"
+            ],
             "settings": {
                 "foreground": "#83a598"
             }
@@ -788,7 +802,10 @@
 
         {
             "name": "ReasonML String",
-            "scope": ["source.reason string.double", "source.reason string.regexp"],
+            "scope": [
+                "source.reason string.double",
+                "source.reason string.regexp"
+            ],
             "settings": {
                 "foreground": "#b8bb26"
             }
@@ -809,7 +826,10 @@
         },
         {
             "name": "ReasonML property",
-            "scope": ["source.reason support.property-value", "source.reason entity.name.filename"],
+            "scope": [
+                "source.reason support.property-value",
+                "source.reason entity.name.filename"
+            ],
             "settings": {
                 "foreground": "#fe8019"
             }
@@ -831,7 +851,9 @@
         },
         {
             "name": "Powershell function attribute",
-            "scope": ["source.powershell support.function.attribute.powershell"],
+            "scope": [
+                "source.powershell support.function.attribute.powershell"
+            ],
             "settings": {
                 "foreground": "#bdae93"
             }

assets/themes/src/vscode/gruvbox/gruvbox-dark-soft.json πŸ”—

@@ -423,7 +423,10 @@
             }
         },
         {
-            "scope": ["string.interpolated.dollar.shell", "string.interpolated.backtick.shell"],
+            "scope": [
+                "string.interpolated.dollar.shell",
+                "string.interpolated.backtick.shell"
+            ],
             "settings": {
                 "foreground": "#8ec07c"
             }
@@ -489,13 +492,19 @@
 
         {
             "name": "coloring of the Java import and package identifiers",
-            "scope": ["storage.modifier.import.java", "storage.modifier.package.java"],
+            "scope": [
+                "storage.modifier.import.java",
+                "storage.modifier.package.java"
+            ],
             "settings": {
                 "foreground": "#bdae93"
             }
         },
         {
-            "scope": ["keyword.other.import.java", "keyword.other.package.java"],
+            "scope": [
+                "keyword.other.import.java",
+                "keyword.other.package.java"
+            ],
             "settings": {
                 "foreground": "#8ec07c"
             }
@@ -628,7 +637,9 @@
         },
         {
             "name": "JSON Level 0",
-            "scope": ["source.json meta.structure.dictionary.json support.type.property-name.json"],
+            "scope": [
+                "source.json meta.structure.dictionary.json support.type.property-name.json"
+            ],
             "settings": {
                 "foreground": "#b8bb26"
             }
@@ -761,7 +772,10 @@
             }
         },
         {
-            "scope": ["source.go keyword.interface", "source.go keyword.struct"],
+            "scope": [
+                "source.go keyword.interface",
+                "source.go keyword.struct"
+            ],
             "settings": {
                 "foreground": "#83a598"
             }
@@ -788,7 +802,10 @@
 
         {
             "name": "ReasonML String",
-            "scope": ["source.reason string.double", "source.reason string.regexp"],
+            "scope": [
+                "source.reason string.double",
+                "source.reason string.regexp"
+            ],
             "settings": {
                 "foreground": "#b8bb26"
             }
@@ -809,7 +826,10 @@
         },
         {
             "name": "ReasonML property",
-            "scope": ["source.reason support.property-value", "source.reason entity.name.filename"],
+            "scope": [
+                "source.reason support.property-value",
+                "source.reason entity.name.filename"
+            ],
             "settings": {
                 "foreground": "#fe8019"
             }
@@ -831,7 +851,9 @@
         },
         {
             "name": "Powershell function attribute",
-            "scope": ["source.powershell support.function.attribute.powershell"],
+            "scope": [
+                "source.powershell support.function.attribute.powershell"
+            ],
             "settings": {
                 "foreground": "#bdae93"
             }

assets/themes/src/vscode/gruvbox/gruvbox-light-hard.json πŸ”—

@@ -422,7 +422,10 @@
             }
         },
         {
-            "scope": ["string.interpolated.dollar.shell", "string.interpolated.backtick.shell"],
+            "scope": [
+                "string.interpolated.dollar.shell",
+                "string.interpolated.backtick.shell"
+            ],
             "settings": {
                 "foreground": "#427b58"
             }
@@ -488,13 +491,19 @@
 
         {
             "name": "coloring of the Java import and package identifiers",
-            "scope": ["storage.modifier.import.java", "storage.modifier.package.java"],
+            "scope": [
+                "storage.modifier.import.java",
+                "storage.modifier.package.java"
+            ],
             "settings": {
                 "foreground": "#665c54"
             }
         },
         {
-            "scope": ["keyword.other.import.java", "keyword.other.package.java"],
+            "scope": [
+                "keyword.other.import.java",
+                "keyword.other.package.java"
+            ],
             "settings": {
                 "foreground": "#427b58"
             }
@@ -627,7 +636,9 @@
         },
         {
             "name": "JSON Level 0",
-            "scope": ["source.json meta.structure.dictionary.json support.type.property-name.json"],
+            "scope": [
+                "source.json meta.structure.dictionary.json support.type.property-name.json"
+            ],
             "settings": {
                 "foreground": "#79740e"
             }
@@ -760,7 +771,10 @@
             }
         },
         {
-            "scope": ["source.go keyword.interface", "source.go keyword.struct"],
+            "scope": [
+                "source.go keyword.interface",
+                "source.go keyword.struct"
+            ],
             "settings": {
                 "foreground": "#076678"
             }
@@ -787,7 +801,10 @@
 
         {
             "name": "ReasonML String",
-            "scope": ["source.reason string.double", "source.reason string.regexp"],
+            "scope": [
+                "source.reason string.double",
+                "source.reason string.regexp"
+            ],
             "settings": {
                 "foreground": "#79740e"
             }
@@ -808,7 +825,10 @@
         },
         {
             "name": "ReasonML property",
-            "scope": ["source.reason support.property-value", "source.reason entity.name.filename"],
+            "scope": [
+                "source.reason support.property-value",
+                "source.reason entity.name.filename"
+            ],
             "settings": {
                 "foreground": "#af3a03"
             }
@@ -830,7 +850,9 @@
         },
         {
             "name": "Powershell function attribute",
-            "scope": ["source.powershell support.function.attribute.powershell"],
+            "scope": [
+                "source.powershell support.function.attribute.powershell"
+            ],
             "settings": {
                 "foreground": "#665c54"
             }

assets/themes/src/vscode/gruvbox/gruvbox-light-medium.json πŸ”—

@@ -422,7 +422,10 @@
             }
         },
         {
-            "scope": ["string.interpolated.dollar.shell", "string.interpolated.backtick.shell"],
+            "scope": [
+                "string.interpolated.dollar.shell",
+                "string.interpolated.backtick.shell"
+            ],
             "settings": {
                 "foreground": "#427b58"
             }
@@ -488,13 +491,19 @@
 
         {
             "name": "coloring of the Java import and package identifiers",
-            "scope": ["storage.modifier.import.java", "storage.modifier.package.java"],
+            "scope": [
+                "storage.modifier.import.java",
+                "storage.modifier.package.java"
+            ],
             "settings": {
                 "foreground": "#665c54"
             }
         },
         {
-            "scope": ["keyword.other.import.java", "keyword.other.package.java"],
+            "scope": [
+                "keyword.other.import.java",
+                "keyword.other.package.java"
+            ],
             "settings": {
                 "foreground": "#427b58"
             }
@@ -627,7 +636,9 @@
         },
         {
             "name": "JSON Level 0",
-            "scope": ["source.json meta.structure.dictionary.json support.type.property-name.json"],
+            "scope": [
+                "source.json meta.structure.dictionary.json support.type.property-name.json"
+            ],
             "settings": {
                 "foreground": "#79740e"
             }
@@ -760,7 +771,10 @@
             }
         },
         {
-            "scope": ["source.go keyword.interface", "source.go keyword.struct"],
+            "scope": [
+                "source.go keyword.interface",
+                "source.go keyword.struct"
+            ],
             "settings": {
                 "foreground": "#076678"
             }
@@ -787,7 +801,10 @@
 
         {
             "name": "ReasonML String",
-            "scope": ["source.reason string.double", "source.reason string.regexp"],
+            "scope": [
+                "source.reason string.double",
+                "source.reason string.regexp"
+            ],
             "settings": {
                 "foreground": "#79740e"
             }
@@ -808,7 +825,10 @@
         },
         {
             "name": "ReasonML property",
-            "scope": ["source.reason support.property-value", "source.reason entity.name.filename"],
+            "scope": [
+                "source.reason support.property-value",
+                "source.reason entity.name.filename"
+            ],
             "settings": {
                 "foreground": "#af3a03"
             }
@@ -830,7 +850,9 @@
         },
         {
             "name": "Powershell function attribute",
-            "scope": ["source.powershell support.function.attribute.powershell"],
+            "scope": [
+                "source.powershell support.function.attribute.powershell"
+            ],
             "settings": {
                 "foreground": "#665c54"
             }

assets/themes/src/vscode/gruvbox/gruvbox-light-soft.json πŸ”—

@@ -422,7 +422,10 @@
             }
         },
         {
-            "scope": ["string.interpolated.dollar.shell", "string.interpolated.backtick.shell"],
+            "scope": [
+                "string.interpolated.dollar.shell",
+                "string.interpolated.backtick.shell"
+            ],
             "settings": {
                 "foreground": "#427b58"
             }
@@ -488,13 +491,19 @@
 
         {
             "name": "coloring of the Java import and package identifiers",
-            "scope": ["storage.modifier.import.java", "storage.modifier.package.java"],
+            "scope": [
+                "storage.modifier.import.java",
+                "storage.modifier.package.java"
+            ],
             "settings": {
                 "foreground": "#665c54"
             }
         },
         {
-            "scope": ["keyword.other.import.java", "keyword.other.package.java"],
+            "scope": [
+                "keyword.other.import.java",
+                "keyword.other.package.java"
+            ],
             "settings": {
                 "foreground": "#427b58"
             }
@@ -627,7 +636,9 @@
         },
         {
             "name": "JSON Level 0",
-            "scope": ["source.json meta.structure.dictionary.json support.type.property-name.json"],
+            "scope": [
+                "source.json meta.structure.dictionary.json support.type.property-name.json"
+            ],
             "settings": {
                 "foreground": "#79740e"
             }
@@ -760,7 +771,10 @@
             }
         },
         {
-            "scope": ["source.go keyword.interface", "source.go keyword.struct"],
+            "scope": [
+                "source.go keyword.interface",
+                "source.go keyword.struct"
+            ],
             "settings": {
                 "foreground": "#076678"
             }
@@ -787,7 +801,10 @@
 
         {
             "name": "ReasonML String",
-            "scope": ["source.reason string.double", "source.reason string.regexp"],
+            "scope": [
+                "source.reason string.double",
+                "source.reason string.regexp"
+            ],
             "settings": {
                 "foreground": "#79740e"
             }
@@ -808,7 +825,10 @@
         },
         {
             "name": "ReasonML property",
-            "scope": ["source.reason support.property-value", "source.reason entity.name.filename"],
+            "scope": [
+                "source.reason support.property-value",
+                "source.reason entity.name.filename"
+            ],
             "settings": {
                 "foreground": "#af3a03"
             }
@@ -830,7 +850,9 @@
         },
         {
             "name": "Powershell function attribute",
-            "scope": ["source.powershell support.function.attribute.powershell"],
+            "scope": [
+                "source.powershell support.function.attribute.powershell"
+            ],
             "settings": {
                 "foreground": "#665c54"
             }

assets/themes/src/vscode/noctis/family.json πŸ”—

@@ -1,61 +1,61 @@
 {
-    "name": "Notctis",
-    "author": "Liviu Schera (liviuschera)",
-    "themes": [
-        {
-            "name": "Noctis Azureus",
-            "file_name": "azureus.json",
-            "appearance": "dark"
-        },
-        {
-            "name": "Noctis Bordo",
-            "file_name": "bordo.json",
-            "appearance": "dark"
-        },
-        {
-            "name": "Noctus Hibernus",
-            "file_name": "hibernus.json",
-            "appearance": "light"
-        },
-        {
-            "name": "Noctis Lilac",
-            "file_name": "lilac.json",
-            "appearance": "dark"
-        },
-        {
-            "name": "Noctis Lux",
-            "file_name": "lux.json",
-            "appearance": "light"
-        },
-        {
-            "name": "Noctis Minimus",
-            "file_name": "minimus.json",
-            "appearance": "dark"
-        },
-        {
-            "name": "Noctis",
-            "file_name": "noctis.json",
-            "appearance": "dark"
-        },
-        {
-            "name": "Noctis Obscuro",
-            "file_name": "obscuro.json",
-            "appearance": "dark"
-        },
-        {
-            "name": "Noctis Sereno",
-            "file_name": "obscuro.json",
-            "appearance": "dark"
-        },
-        {
-            "name": "Noctis Uva",
-            "file_name": "uva.json",
-            "appearance": "dark"
-        },
-        {
-            "name": "Noctis Viola",
-            "file_name": "viola.json",
-            "appearance": "dark"
-        }
-    ]
+  "name": "Noctis",
+  "author": "Liviu Schera (liviuschera)",
+  "themes": [
+    {
+      "name": "Noctis Azureus",
+      "file_name": "azureus.json",
+      "appearance": "dark"
+    },
+    {
+      "name": "Noctis Bordo",
+      "file_name": "bordo.json",
+      "appearance": "dark"
+    },
+    {
+      "name": "Noctus Hibernus",
+      "file_name": "hibernus.json",
+      "appearance": "light"
+    },
+    {
+      "name": "Noctis Lilac",
+      "file_name": "lilac.json",
+      "appearance": "dark"
+    },
+    {
+      "name": "Noctis Lux",
+      "file_name": "lux.json",
+      "appearance": "light"
+    },
+    {
+      "name": "Noctis Minimus",
+      "file_name": "minimus.json",
+      "appearance": "dark"
+    },
+    {
+      "name": "Noctis",
+      "file_name": "noctis.json",
+      "appearance": "dark"
+    },
+    {
+      "name": "Noctis Obscuro",
+      "file_name": "obscuro.json",
+      "appearance": "dark"
+    },
+    {
+      "name": "Noctis Sereno",
+      "file_name": "obscuro.json",
+      "appearance": "dark"
+    },
+    {
+      "name": "Noctis Uva",
+      "file_name": "uva.json",
+      "appearance": "dark"
+    },
+    {
+      "name": "Noctis Viola",
+      "file_name": "viola.json",
+      "appearance": "dark"
+    }
+  ]
 }

assets/themes/src/vscode/rose-pine/family.json πŸ”—

@@ -1,21 +1,21 @@
 {
-    "name": "Rose Pine",
-    "author": "RosΓ© Pine",
-    "themes": [
-        {
-            "name": "Rose Pine",
-            "file_name": "rose-pine.json",
-            "appearance": "dark"
-        },
-        {
-            "name": "Rose Moon",
-            "file_name": "rose-pine-moon.json",
-            "appearance": "dark"
-        },
-        {
-            "name": "Rose Pine Dawn",
-            "file_name": "rose-pine-dawn.json",
-            "appearance": "light"
-        }
-    ]
+  "name": "Rose Pine",
+  "author": "RosΓ© Pine",
+  "themes": [
+    {
+      "name": "Rose Pine",
+      "file_name": "rose-pine.json",
+      "appearance": "dark"
+    },
+    {
+      "name": "Rose Pine Moon",
+      "file_name": "rose-pine-moon.json",
+      "appearance": "dark"
+    },
+    {
+      "name": "Rose Pine Dawn",
+      "file_name": "rose-pine-dawn.json",
+      "appearance": "light"
+    }
+  ]
 }

assets/themes/src/vscode/synthwave-84/synthwave.json πŸ”—

@@ -1,822 +1,841 @@
 {
-    "name": "SynthWave 84",
-    "type": "dark",
-    "semanticHighlighting": true,
-    "colors": {
-        "focusBorder": "#1f212b",
-        "foreground": "#ffffff",
-        "widget.shadow": "#2a2139",
-        "selection.background": "#ffffff20",
-        "errorForeground": "#fe4450",
-        "textLink.activeForeground": "#ff7edb",
-        "textLink.foreground": "#f97e72",
-        "button.background": "#614D85",
-        "dropdown.background": "#232530",
-        "dropdown.listBackground": "#2a2139",
-        "input.background": "#2a2139",
-        "inputOption.activeBorder": "#ff7edb99",
-        "inputValidation.errorBackground": "#fe445080",
-        "inputValidation.errorBorder": "#fe445000",
-        "scrollbar.shadow": "#2a2139",
-        "scrollbarSlider.activeBackground": "#9d8bca20",
-        "scrollbarSlider.background": "#9d8bca30",
-        "scrollbarSlider.hoverBackground": "#9d8bca50",
-        "badge.foreground": "#ffffff",
-        "badge.background": "#2a2139",
-        "progressBar.background": "#f97e72",
-        "list.activeSelectionBackground": "#ffffff20",
-        "list.activeSelectionForeground": "#ffffff",
-        "list.dropBackground": "#34294f66",
-        "list.focusBackground": "#ffffff20",
-        "list.focusForeground": "#ffffff",
-        "list.highlightForeground": "#f97e72",
-        "list.hoverBackground": "#37294d99",
-        "list.hoverForeground": "#ffffff",
-        "list.inactiveSelectionBackground": "#ffffff20",
-        "list.inactiveSelectionForeground": "#ffffff",
-        "list.inactiveFocusBackground": "#2a213999",
-        "list.errorForeground": "#fe4450E6",
-        "list.warningForeground": "#72f1b8bb",
-        "activityBar.background": "#171520",
-        "activityBar.dropBackground": "#34294f66",
-        "activityBar.foreground": "#ffffffCC",
-        "activityBarBadge.background": "#f97e72",
-        "activityBarBadge.foreground": "#2a2139",
-        "sideBar.background": "#241b2f",
-        "sideBar.foreground": "#ffffff99",
-        "sideBar.dropBackground": "#34294f4c",
-        "sideBarSectionHeader.background": "#241b2f",
-        "sideBarSectionHeader.foreground": "#ffffffca",
-        "menu.background": "#463465",
-        "editorGroup.border": "#495495",
-        "editorGroup.dropBackground": "#4954954a",
-        "editorGroupHeader.tabsBackground": "#241b2f",
-        "tab.border": "#241b2f00",
-        "tab.activeBorder": "#880088",
-        "tab.inactiveBackground": "#262335",
-        "editor.background": "#262335",
-        "editorLineNumber.foreground": "#ffffff73",
-        "editorLineNumber.activeForeground": "#ffffffcc",
-        "editorCursor.background": "#241b2f",
-        "editorCursor.foreground": "#f97e72",
-        "editor.selectionBackground": "#ffffff20",
-        "editor.selectionHighlightBackground": "#ffffff20",
-        "editor.wordHighlightBackground": "#34294f88",
-        "editor.wordHighlightStrongBackground": "#34294f88",
-        "editor.findMatchBackground": "#D18616bb",
-        "editor.findMatchHighlightBackground": "#D1861655",
-        "editor.findRangeHighlightBackground": "#34294f1a",
-        "editor.hoverHighlightBackground": "#463564",
-        "editor.lineHighlightBorder": "#7059AB66",
-        "editor.rangeHighlightBackground": "#49549539",
-        "editorIndentGuide.background": "#444251",
-        "editorIndentGuide.activeBackground": "#A148AB80",
-        "editorRuler.foreground": "#A148AB80",
-        "editorCodeLens.foreground": "#ffffff7c",
-        "editorBracketMatch.background": "#34294f66",
-        "editorBracketMatch.border": "#495495",
-        "editorOverviewRuler.border": "#34294fb3",
-        "editorOverviewRuler.findMatchForeground": "#D1861699",
-        "editorOverviewRuler.modifiedForeground": "#b893ce99",
-        "editorOverviewRuler.addedForeground": "#09f7a099",
-        "editorOverviewRuler.deletedForeground": "#fe445099",
-        "editorOverviewRuler.errorForeground": "#fe4450dd",
-        "editorOverviewRuler.warningForeground": "#72f1b8cc",
-        "editorError.foreground": "#fe4450",
-        "editorWarning.foreground": "#72f1b8cc",
-        "editorGutter.modifiedBackground": "#b893ce8f",
-        "editorGutter.addedBackground": "#206d4bd6",
-        "editorGutter.deletedBackground": "#fa2e46a4",
-        "diffEditor.insertedTextBackground": "#0beb9935",
-        "diffEditor.removedTextBackground": "#fe445035",
-        "editorWidget.background": "#171520DC",
-        "editorWidget.border": "#ffffff22",
-        "editorWidget.resizeBorder": "#ffffff44",
-        "editorSuggestWidget.highlightForeground": "#f97e72",
-        "editorSuggestWidget.selectedBackground": "#ffffff36",
-        "peekView.border": "#495495",
-        "peekViewEditor.background": "#232530",
-        "peekViewEditor.matchHighlightBackground": "#D18616bb",
-        "peekViewResult.background": "#232530",
-        "peekViewResult.matchHighlightBackground": "#D1861655",
-        "peekViewResult.selectionBackground": "#2a213980",
-        "peekViewTitle.background": "#232530",
-        "panelTitle.activeBorder": "#f97e72",
-        "statusBar.background": "#241b2f",
-        "statusBar.foreground": "#ffffff80",
-        "statusBar.debuggingBackground": "#f97e72",
-        "statusBar.debuggingForeground": "#08080f",
-        "statusBar.noFolderBackground": "#241b2f",
-        "statusBarItem.prominentBackground": "#2a2139",
-        "statusBarItem.prominentHoverBackground": "#34294f",
-        "titleBar.activeBackground": "#241b2f",
-        "titleBar.inactiveBackground": "#241b2f",
-        "extensionButton.prominentBackground": "#f97e72",
-        "extensionButton.prominentHoverBackground": "#ff7edb",
-        "pickerGroup.foreground": "#f97e72ea",
-        "terminal.foreground": "#ffffff",
-        "terminal.ansiBlue": "#03edf9",
-        "terminal.ansiBrightBlue": "#03edf9",
-        "terminal.ansiBrightCyan": "#03edf9",
-        "terminal.ansiBrightGreen": "#72f1b8",
-        "terminal.ansiBrightMagenta": "#ff7edb",
-        "terminal.ansiBrightRed": "#fe4450",
-        "terminal.ansiBrightYellow": "#fede5d",
-        "terminal.ansiCyan": "#03edf9",
-        "terminal.ansiGreen": "#72f1b8",
-        "terminal.ansiMagenta": "#ff7edb",
-        "terminal.ansiRed": "#fe4450",
-        "terminal.ansiYellow": "#f3e70f",
-        "terminal.selectionBackground": "#ffffff20",
-        "terminalCursor.background": "#ffffff",
-        "terminalCursor.foreground": "#03edf9",
-        "debugToolBar.background": "#463465",
-        "walkThrough.embeddedEditorBackground": "#232530",
-        "gitDecoration.modifiedResourceForeground": "#b893ceee",
-        "gitDecoration.deletedResourceForeground": "#fe4450",
-        "gitDecoration.addedResourceForeground": "#72f1b8cc",
-        "gitDecoration.untrackedResourceForeground": "#72f1b8",
-        "gitDecoration.ignoredResourceForeground": "#ffffff59",
-        "minimapGutter.addedBackground": "#09f7a099",
-        "minimapGutter.modifiedBackground": "#b893ce",
-        "minimapGutter.deletedBackground": "#fe4450",
-        "breadcrumbPicker.background": "#232530"
-    },
-    "tokenColors": [
-        {
-            "name": "Comment",
-            "scope": [
-                "comment",
-                "string.quoted.docstring.multi.python",
-                "string.quoted.docstring.multi.python punctuation.definition.string.begin.python",
-                "string.quoted.docstring.multi.python punctuation.definition.string.end.python"
-            ],
-            "settings": {
-                "foreground": "#848bbd",
-                "fontStyle": "italic"
-            }
-        },
-        {
-            "name": "String",
-            "scope": ["string.quoted", "string.template", "punctuation.definition.string"],
-            "settings": {
-                "foreground": "#ff8b39"
-            }
-        },
-        {
-            "name": "Punctuation within templates",
-            "scope": "string.template meta.embedded.line",
-            "settings": {
-                "foreground": "#b6b1b1"
-            }
-        },
-        {
-            "name": "Variable",
-            "scope": ["variable", "entity.name.variable"],
-            "settings": {
-                "foreground": "#ff7edb"
-            }
-        },
-        {
-            "name": "Language variable",
-            "scope": "variable.language",
-            "settings": {
-                "foreground": "#fe4450",
-                "fontStyle": "bold"
-            }
-        },
-        {
-            "name": "Parameter",
-            "scope": "variable.parameter",
-            "settings": {
-                "fontStyle": "italic"
-            }
-        },
-        {
-            "name": "Storage (declaration or modifier keyword)",
-            "scope": ["storage.type", "storage.modifier"],
-            "settings": {
-                "foreground": "#fede5d"
-            }
-        },
-        {
-            "name": "Constant",
-            "scope": "constant",
-            "settings": {
-                "foreground": "#f97e72"
-            }
-        },
-        {
-            "name": "Regex",
-            "scope": "string.regexp",
-            "settings": {
-                "foreground": "#f97e72"
-            }
-        },
-        {
-            "name": "Number",
-            "scope": "constant.numeric",
-            "settings": {
-                "foreground": "#f97e72"
-            }
-        },
-        {
-            "name": "Language constant (boolean, null)",
-            "scope": "constant.language",
-            "settings": {
-                "foreground": "#f97e72"
-            }
-        },
-        {
-            "name": "Character escape",
-            "scope": "constant.character.escape",
-            "settings": {
-                "foreground": "#36f9f6"
-            }
-        },
-        {
-            "name": "Entity",
-            "scope": "entity.name",
-            "settings": {
-                "foreground": "#fe4450"
-            }
-        },
-        {
-            "name": "HTML or XML tag",
-            "scope": "entity.name.tag",
-            "settings": {
-                "foreground": "#72f1b8"
-            }
-        },
-        {
-            "name": "HTML or XML tag brackets",
-            "scope": ["punctuation.definition.tag"],
-            "settings": {
-                "foreground": "#36f9f6"
-            }
-        },
-        {
-            "name": "Tag attribute",
-            "scope": "entity.other.attribute-name",
-            "settings": {
-                "foreground": "#fede5d"
-            }
-        },
-        {
-            "name": "Tag attribute HTML",
-            "scope": "entity.other.attribute-name.html",
-            "settings": {
-                "foreground": "#fede5d",
-                "fontStyle": "italic"
-            }
-        },
-        {
-            "name": "Class",
-            "scope": ["entity.name.type", "meta.attribute.class.html"],
-            "settings": {
-                "foreground": "#fe4450"
-            }
-        },
-        {
-            "name": "Inherited class",
-            "scope": "entity.other.inherited-class",
-            "settings": {
-                "foreground": "#D50"
-            }
-        },
-        {
-            "name": "Function",
-            "scope": ["entity.name.function", "variable.function"],
-            "settings": {
-                "foreground": "#36f9f6"
-            }
-        },
-        {
-            "name": "JS Export",
-            "scope": ["keyword.control.export.js", "keyword.control.import.js"],
-            "settings": {
-                "foreground": "#72f1b8"
-            }
-        },
-        {
-            "name": "JS Numerics",
-            "scope": ["constant.numeric.decimal.js"],
-            "settings": {
-                "foreground": "#2EE2FA"
-            }
-        },
-        {
-            "name": "Keyword",
-            "scope": "keyword",
-            "settings": {
-                "foreground": "#fede5d"
-            }
-        },
-        {
-            "name": "Control keyword",
-            "scope": "keyword.control",
-            "settings": {
-                "foreground": "#fede5d"
-            }
-        },
-        {
-            "name": "Operator",
-            "scope": "keyword.operator",
-            "settings": {
-                "foreground": "#fede5d"
-            }
-        },
-        {
-            "name": "Special operator",
-            "scope": [
-                "keyword.operator.new",
-                "keyword.operator.expression",
-                "keyword.operator.logical"
-            ],
-            "settings": {
-                "foreground": "#fede5d"
-            }
-        },
-        {
-            "name": "Unit",
-            "scope": "keyword.other.unit",
-            "settings": {
-                "foreground": "#f97e72"
-            }
-        },
-        {
-            "name": "Support",
-            "scope": "support",
-            "settings": {
-                "foreground": "#fe4450"
-            }
-        },
-        {
-            "name": "Support function",
-            "scope": "support.function",
-            "settings": {
-                "foreground": "#36f9f6"
-            }
-        },
-        {
-            "name": "Support variable",
-            "scope": "support.variable",
-            "settings": {
-                "foreground": "#ff7edb"
-            }
-        },
-        {
-            "name": "Object literal key / property",
-            "scope": ["meta.object-literal.key", "support.type.property-name"],
-            "settings": {
-                "foreground": "#ff7edb"
-            }
-        },
-        {
-            "name": "Key-value separator",
-            "scope": "punctuation.separator.key-value",
-            "settings": {
-                "foreground": "#b6b1b1"
-            }
-        },
-        {
-            "name": "Embedded punctuation",
-            "scope": "punctuation.section.embedded",
-            "settings": {
-                "foreground": "#fede5d"
-            }
-        },
-        {
-            "name": "Template expression",
-            "scope": [
-                "punctuation.definition.template-expression.begin",
-                "punctuation.definition.template-expression.end"
-            ],
-            "settings": {
-                "foreground": "#72f1b8"
-            }
-        },
-        {
-            "name": "CSS property",
-            "scope": ["support.type.property-name.css", "support.type.property-name.json"],
-            "settings": {
-                "foreground": "#72f1b8"
-            }
-        },
-        {
-            "name": "JS Switch control",
-            "scope": "switch-block.expr.js",
-            "settings": {
-                "foreground": "#72f1b8"
-            }
-        },
-        {
-            "name": "JS object path",
-            "scope": "variable.other.constant.property.js, variable.other.property.js",
-            "settings": {
-                "foreground": "#2ee2fa"
-            }
-        },
-        {
-            "name": "Color",
-            "scope": "constant.other.color",
-            "settings": {
-                "foreground": "#f97e72"
-            }
-        },
-        {
-            "name": "Font names",
-            "scope": "support.constant.font-name",
-            "settings": {
-                "foreground": "#f97e72"
-            }
-        },
-        {
-            "name": "CSS #id",
-            "scope": "entity.other.attribute-name.id",
-            "settings": {
-                "foreground": "#36f9f6"
-            }
-        },
-        {
-            "name": "Pseudo CSS",
-            "scope": [
-                "entity.other.attribute-name.pseudo-element",
-                "entity.other.attribute-name.pseudo-class"
-            ],
-            "settings": {
-                "foreground": "#D50"
-            }
-        },
-        {
-            "name": "CSS support functions (rgb)",
-            "scope": "support.function.misc.css",
-            "settings": {
-                "foreground": "#fe4450"
-            }
-        },
-        {
-            "name": "Markup heading",
-            "scope": ["markup.heading", "entity.name.section"],
-            "settings": {
-                "foreground": "#ff7edb"
-            }
-        },
-        {
-            "name": "Markup text",
-            "scope": ["text.html", "keyword.operator.assignment"],
-            "settings": {
-                "foreground": "#ffffffee"
-            }
-        },
-        {
-            "name": "Markup quote",
-            "scope": "markup.quote",
-            "settings": {
-                "foreground": "#b6b1b1cc",
-                "fontStyle": "italic"
-            }
-        },
-        {
-            "name": "Markup list",
-            "scope": "beginning.punctuation.definition.list",
-            "settings": {
-                "foreground": "#ff7edb"
-            }
-        },
-        {
-            "name": "Markup link",
-            "scope": "markup.underline.link",
-            "settings": {
-                "foreground": "#D50"
-            }
-        },
-        {
-            "name": "Markup link description",
-            "scope": "string.other.link.description",
-            "settings": {
-                "foreground": "#f97e72"
-            }
-        },
-        {
-            "name": "Python function call",
-            "scope": "meta.function-call.generic.python",
-            "settings": {
-                "foreground": "#36f9f6"
-            }
-        },
-        {
-            "name": "Python variable params",
-            "scope": "variable.parameter.function-call.python",
-            "settings": {
-                "foreground": "#72f1b8"
-            }
-        },
-        {
-            "name": "C# storage type",
-            "scope": "storage.type.cs",
-            "settings": {
-                "foreground": "#fe4450"
-            }
-        },
-        {
-            "name": "C# local variable",
-            "scope": "entity.name.variable.local.cs",
-            "settings": {
-                "foreground": "#ff7edb"
-            }
-        },
-        {
-            "name": "C# properties and fields",
-            "scope": ["entity.name.variable.field.cs", "entity.name.variable.property.cs"],
-            "settings": {
-                "foreground": "#ff7edb"
-            }
-        },
-        {
-            "name": "C placeholder",
-            "scope": "constant.other.placeholder.c",
-            "settings": {
-                "foreground": "#72f1b8",
-                "fontStyle": "italic"
-            }
-        },
-        {
-            "name": "C preprocessors",
-            "scope": ["keyword.control.directive.include.c", "keyword.control.directive.define.c"],
-            "settings": {
-                "foreground": "#72f1b8"
-            }
-        },
-        {
-            "name": "C storage modifier",
-            "scope": "storage.modifier.c",
-            "settings": {
-                "foreground": "#fe4450"
-            }
-        },
-        {
-            "name": "C++ operators",
-            "scope": "source.cpp keyword.operator",
-            "settings": {
-                "foreground": "#fede5d"
-            }
-        },
-        {
-            "name": "C++ placeholder",
-            "scope": "constant.other.placeholder.cpp",
-            "settings": {
-                "foreground": "#72f1b8",
-                "fontStyle": "italic"
-            }
-        },
-        {
-            "name": "C++ include",
-            "scope": [
-                "keyword.control.directive.include.cpp",
-                "keyword.control.directive.define.cpp"
-            ],
-            "settings": {
-                "foreground": "#72f1b8"
-            }
-        },
-        {
-            "name": "C++ constant modifier",
-            "scope": "storage.modifier.specifier.const.cpp",
-            "settings": {
-                "foreground": "#fe4450"
-            }
-        },
-        {
-            "name": "Elixir Classes",
-            "scope": [
-                "source.elixir support.type.elixir",
-                "source.elixir meta.module.elixir entity.name.class.elixir"
-            ],
-            "settings": {
-                "foreground": "#36f9f6"
-            }
-        },
-        {
-            "name": "Elixir Functions",
-            "scope": "source.elixir entity.name.function",
-            "settings": {
-                "foreground": "#72f1b8"
-            }
-        },
-        {
-            "name": "Elixir Constants",
-            "scope": [
-                "source.elixir constant.other.symbol.elixir",
-                "source.elixir constant.other.keywords.elixir"
-            ],
-            "settings": {
-                "foreground": "#36f9f6"
-            }
-        },
-        {
-            "name": "Elixir String Punctuation",
-            "scope": "source.elixir punctuation.definition.string",
-            "settings": {
-                "foreground": "#72f1b8"
-            }
-        },
-        {
-            "name": "Elixir",
-            "scope": [
-                "source.elixir variable.other.readwrite.module.elixir",
-                "source.elixir variable.other.readwrite.module.elixir punctuation.definition.variable.elixir"
-            ],
-            "settings": {
-                "foreground": "#72f1b8"
-            }
-        },
-        {
-            "name": "Elixir Binary Punctuation",
-            "scope": "source.elixir .punctuation.binary.elixir",
-            "settings": {
-                "foreground": "#ff7edb",
-                "fontStyle": "italic"
-            }
-        },
-        {
-            "name": "Clojure Globals",
-            "scope": ["entity.global.clojure"],
-            "settings": {
-                "foreground": "#36f9f6",
-                "fontStyle": "bold"
-            }
-        },
-        {
-            "name": "Clojure Storage",
-            "scope": ["storage.control.clojure"],
-            "settings": {
-                "foreground": "#36f9f6",
-                "fontStyle": "italic"
-            }
-        },
-        {
-            "name": "Clojure Metadata",
-            "scope": ["meta.metadata.simple.clojure", "meta.metadata.map.clojure"],
-            "settings": {
-                "foreground": "#fe4450",
-                "fontStyle": "italic"
-            }
-        },
-        {
-            "name": "Clojure Macros, Quoted",
-            "scope": ["meta.quoted-expression.clojure"],
-            "settings": {
-                "fontStyle": "italic"
-            }
-        },
-        {
-            "name": "Clojure Symbols",
-            "scope": ["meta.symbol.clojure"],
-            "settings": {
-                "foreground": "#ff7edbff"
-            }
-        },
-        {
-            "name": "Go basic",
-            "scope": "source.go",
-            "settings": {
-                "foreground": "#ff7edbff"
-            }
-        },
-        {
-            "name": "Go Function Calls",
-            "scope": "source.go meta.function-call.go",
-            "settings": {
-                "foreground": "#36f9f6"
-            }
-        },
-        {
-            "name": "Go Keywords",
-            "scope": [
-                "source.go keyword.package.go",
-                "source.go keyword.import.go",
-                "source.go keyword.function.go",
-                "source.go keyword.type.go",
-                "source.go keyword.const.go",
-                "source.go keyword.var.go",
-                "source.go keyword.map.go",
-                "source.go keyword.channel.go",
-                "source.go keyword.control.go"
-            ],
-            "settings": {
-                "foreground": "#fede5d"
-            }
-        },
-        {
-            "name": "Go interfaces",
-            "scope": [
-                "source.go storage.type",
-                "source.go keyword.struct.go",
-                "source.go keyword.interface.go"
-            ],
-            "settings": {
-                "foreground": "#72f1b8"
-            }
-        },
-        {
-            "name": "Go Constants e.g. nil, string format (%s, %d, etc.)",
-            "scope": [
-                "source.go constant.language.go",
-                "source.go constant.other.placeholder.go",
-                "source.go variable"
-            ],
-            "settings": {
-                "foreground": "#2EE2FA"
-            }
-        },
-        {
-            "name": "Markdown links and image paths",
-            "scope": ["markup.underline.link.markdown", "markup.inline.raw.string.markdown"],
-            "settings": {
-                "foreground": "#72f1b8",
-                "fontStyle": "italic"
-            }
-        },
-        {
-            "name": "Markdown links and image paths",
-            "scope": ["string.other.link.title.markdown"],
-            "settings": {
-                "foreground": "#fede5d"
-            }
-        },
-        {
-            "name": "Markdown headings",
-            "scope": ["markup.heading.markdown", "entity.name.section.markdown"],
-            "settings": {
-                "foreground": "#ff7edb",
-                "fontStyle": "bold"
-            }
-        },
-        {
-            "name": "Markdown italic",
-            "scope": ["markup.italic.markdown"],
-            "settings": {
-                "foreground": "#2EE2FA",
-                "fontStyle": "italic"
-            }
-        },
-        {
-            "name": "Markdown bold",
-            "scope": ["markup.bold.markdown"],
-            "settings": {
-                "foreground": "#2EE2FA",
-                "fontStyle": "bold"
-            }
-        },
-        {
-            "name": "Markdown quotes",
-            "scope": ["punctuation.definition.quote.begin.markdown", "markup.quote.markdown"],
-            "settings": {
-                "foreground": "#72f1b8"
-            }
-        },
-        {
-            "name": "Basic source colours",
-            "scope": ["source.dart", "source.python", "source.scala"],
-            "settings": {
-                "foreground": "#ff7edbff"
-            }
-        },
-        {
-            "name": "Dart strings",
-            "scope": ["string.interpolated.single.dart"],
-            "settings": {
-                "foreground": "#f97e72"
-            }
-        },
-        {
-            "name": "Dart variable params",
-            "scope": ["variable.parameter.dart"],
-            "settings": {
-                "foreground": "#72f1b8"
-            }
-        },
-        {
-            "name": "Dart numerics",
-            "scope": ["constant.numeric.dart"],
-            "settings": {
-                "foreground": "#2EE2FA"
-            }
-        },
-        {
-            "name": "Scala variable params",
-            "scope": ["variable.parameter.scala"],
-            "settings": {
-                "foreground": "#2EE2FA"
-            }
-        },
-        {
-            "name": "Scala",
-            "scope": ["meta.template.expression.scala"],
-            "settings": {
-                "foreground": "#72f1b8"
-            }
-        }
-    ]
+  "name": "SynthWave 84",
+  "type": "dark",
+  "semanticHighlighting": true,
+  "colors": {
+    "focusBorder": "#1f212b",
+    "foreground": "#ffffff",
+    "widget.shadow": "#2a2139",
+    "selection.background": "#ffffff20",
+    "errorForeground": "#fe4450",
+    "textLink.activeForeground": "#ff7edb",
+    "textLink.foreground": "#f97e72",
+    "button.background": "#614D85",
+    "dropdown.background": "#232530",
+    "dropdown.listBackground": "#2a2139",
+    "input.background": "#2a2139",
+    "inputOption.activeBorder": "#ff7edb99",
+    "inputValidation.errorBackground": "#fe445080",
+    "inputValidation.errorBorder": "#fe445000",
+    "scrollbar.shadow": "#2a2139",
+    "scrollbarSlider.activeBackground": "#9d8bca20",
+    "scrollbarSlider.background": "#9d8bca30",
+    "scrollbarSlider.hoverBackground": "#9d8bca50",
+    "badge.foreground": "#ffffff",
+    "badge.background": "#2a2139",
+    "progressBar.background": "#f97e72",
+    "list.activeSelectionBackground": "#ffffff20",
+    "list.activeSelectionForeground": "#ffffff",
+    "list.dropBackground": "#34294f66",
+    "list.focusBackground": "#ffffff20",
+    "list.focusForeground": "#ffffff",
+    "list.highlightForeground": "#f97e72",
+    "list.hoverBackground": "#37294d99",
+    "list.hoverForeground": "#ffffff",
+    "list.inactiveSelectionBackground": "#ffffff20",
+    "list.inactiveSelectionForeground": "#ffffff",
+    "list.inactiveFocusBackground": "#2a213999",
+    "list.errorForeground": "#fe4450E6",
+    "list.warningForeground": "#72f1b8bb",
+    "activityBar.background": "#171520",
+    "activityBar.dropBackground": "#34294f66",
+    "activityBar.foreground": "#ffffffCC",
+    "activityBarBadge.background": "#f97e72",
+    "activityBarBadge.foreground": "#2a2139",
+    "sideBar.background": "#241b2f",
+    "sideBar.foreground": "#ffffff99",
+    "sideBar.dropBackground": "#34294f4c",
+    "sideBarSectionHeader.background": "#241b2f",
+    "sideBarSectionHeader.foreground": "#ffffffca",
+    "menu.background": "#463465",
+    "editorGroup.border": "#495495",
+    "editorGroup.dropBackground": "#4954954a",
+    "editorGroupHeader.tabsBackground": "#241b2f",
+    "tab.border": "#241b2f00",
+    "tab.activeBorder": "#880088",
+    "tab.inactiveBackground": "#262335",
+    "editor.background": "#262335",
+    "editorLineNumber.foreground": "#ffffff73",
+    "editorLineNumber.activeForeground": "#ffffffcc",
+    "editorCursor.background": "#241b2f",
+    "editorCursor.foreground": "#f97e72",
+    "editor.selectionBackground": "#ffffff20",
+    "editor.selectionHighlightBackground": "#ffffff20",
+    "editor.wordHighlightBackground": "#34294f88",
+    "editor.wordHighlightStrongBackground": "#34294f88",
+    "editor.findMatchBackground": "#D18616bb",
+    "editor.findMatchHighlightBackground": "#D1861655",
+    "editor.findRangeHighlightBackground": "#34294f1a",
+    "editor.hoverHighlightBackground": "#463564",
+    "editor.lineHighlightBorder": "#7059AB66",
+    "editor.rangeHighlightBackground": "#49549539",
+    "editorIndentGuide.background": "#444251",
+    "editorIndentGuide.activeBackground": "#A148AB80",
+    "editorRuler.foreground": "#A148AB80",
+    "editorCodeLens.foreground": "#ffffff7c",
+    "editorBracketMatch.background": "#34294f66",
+    "editorBracketMatch.border": "#495495",
+    "editorOverviewRuler.border": "#34294fb3",
+    "editorOverviewRuler.findMatchForeground": "#D1861699",
+    "editorOverviewRuler.modifiedForeground": "#b893ce99",
+    "editorOverviewRuler.addedForeground": "#09f7a099",
+    "editorOverviewRuler.deletedForeground": "#fe445099",
+    "editorOverviewRuler.errorForeground": "#fe4450dd",
+    "editorOverviewRuler.warningForeground": "#72f1b8cc",
+    "editorError.foreground": "#fe4450",
+    "editorWarning.foreground": "#72f1b8cc",
+    "editorGutter.modifiedBackground": "#b893ce8f",
+    "editorGutter.addedBackground": "#206d4bd6",
+    "editorGutter.deletedBackground": "#fa2e46a4",
+    "diffEditor.insertedTextBackground": "#0beb9935",
+    "diffEditor.removedTextBackground": "#fe445035",
+    "editorWidget.background": "#171520DC",
+    "editorWidget.border": "#ffffff22",
+    "editorWidget.resizeBorder": "#ffffff44",
+    "editorSuggestWidget.highlightForeground": "#f97e72",
+    "editorSuggestWidget.selectedBackground": "#ffffff36",
+    "peekView.border": "#495495",
+    "peekViewEditor.background": "#232530",
+    "peekViewEditor.matchHighlightBackground": "#D18616bb",
+    "peekViewResult.background": "#232530",
+    "peekViewResult.matchHighlightBackground": "#D1861655",
+    "peekViewResult.selectionBackground": "#2a213980",
+    "peekViewTitle.background": "#232530",
+    "panelTitle.activeBorder": "#f97e72",
+    "statusBar.background": "#241b2f",
+    "statusBar.foreground": "#ffffff80",
+    "statusBar.debuggingBackground": "#f97e72",
+    "statusBar.debuggingForeground": "#08080f",
+    "statusBar.noFolderBackground": "#241b2f",
+    "statusBarItem.prominentBackground": "#2a2139",
+    "statusBarItem.prominentHoverBackground": "#34294f",
+    "titleBar.activeBackground": "#241b2f",
+    "titleBar.inactiveBackground": "#241b2f",
+    "extensionButton.prominentBackground": "#f97e72",
+    "extensionButton.prominentHoverBackground": "#ff7edb",
+    "pickerGroup.foreground": "#f97e72ea",
+    "terminal.foreground": "#ffffff",
+    "terminal.ansiBlue": "#03edf9",
+    "terminal.ansiBrightBlue": "#03edf9",
+    "terminal.ansiBrightCyan": "#03edf9",
+    "terminal.ansiBrightGreen": "#72f1b8",
+    "terminal.ansiBrightMagenta": "#ff7edb",
+    "terminal.ansiBrightRed": "#fe4450",
+    "terminal.ansiBrightYellow": "#fede5d",
+    "terminal.ansiCyan": "#03edf9",
+    "terminal.ansiGreen": "#72f1b8",
+    "terminal.ansiMagenta": "#ff7edb",
+    "terminal.ansiRed": "#fe4450",
+    "terminal.ansiYellow": "#f3e70f",
+    "terminal.selectionBackground": "#ffffff20",
+    "terminalCursor.background": "#ffffff",
+    "terminalCursor.foreground": "#03edf9",
+    "debugToolBar.background": "#463465",
+    "walkThrough.embeddedEditorBackground": "#232530",
+    "gitDecoration.modifiedResourceForeground": "#b893ceee",
+    "gitDecoration.deletedResourceForeground": "#fe4450",
+    "gitDecoration.addedResourceForeground": "#72f1b8cc",
+    "gitDecoration.untrackedResourceForeground": "#72f1b8",
+    "gitDecoration.ignoredResourceForeground": "#ffffff59",
+    "minimapGutter.addedBackground": "#09f7a099",
+    "minimapGutter.modifiedBackground": "#b893ce",
+    "minimapGutter.deletedBackground": "#fe4450",
+    "breadcrumbPicker.background": "#232530"
+  },
+  "tokenColors": [
+    {
+      "name": "Comment",
+      "scope": [
+        "comment",
+        "string.quoted.docstring.multi.python",
+        "string.quoted.docstring.multi.python punctuation.definition.string.begin.python",
+        "string.quoted.docstring.multi.python punctuation.definition.string.end.python"
+      ],
+      "settings": {
+        "foreground": "#848bbd",
+        "fontStyle": "italic"
+      }
+    },
+    {
+      "name": "String",
+      "scope": [
+        "string.quoted",
+        "string.template",
+        "punctuation.definition.string"
+      ],
+      "settings": {
+        "foreground": "#ff8b39"
+      }
+    },
+    {
+      "name": "Punctuation within templates",
+      "scope": "string.template meta.embedded.line",
+      "settings": {
+        "foreground": "#b6b1b1"
+      }
+    },
+    {
+      "name": "Variable",
+      "scope": ["variable", "entity.name.variable"],
+      "settings": {
+        "foreground": "#ff7edb"
+      }
+    },
+    {
+      "name": "Language variable",
+      "scope": "variable.language",
+      "settings": {
+        "foreground": "#fe4450",
+        "fontStyle": "bold"
+      }
+    },
+    {
+      "name": "Parameter",
+      "scope": "variable.parameter",
+      "settings": {
+        "fontStyle": "italic"
+      }
+    },
+    {
+      "name": "Storage (declaration or modifier keyword)",
+      "scope": ["storage.type", "storage.modifier"],
+      "settings": {
+        "foreground": "#fede5d"
+      }
+    },
+    {
+      "name": "Constant",
+      "scope": "constant",
+      "settings": {
+        "foreground": "#f97e72"
+      }
+    },
+    {
+      "name": "Regex",
+      "scope": "string.regexp",
+      "settings": {
+        "foreground": "#f97e72"
+      }
+    },
+    {
+      "name": "Number",
+      "scope": "constant.numeric",
+      "settings": {
+        "foreground": "#f97e72"
+      }
+    },
+    {
+      "name": "Language constant (boolean, null)",
+      "scope": "constant.language",
+      "settings": {
+        "foreground": "#f97e72"
+      }
+    },
+    {
+      "name": "Character escape",
+      "scope": "constant.character.escape",
+      "settings": {
+        "foreground": "#36f9f6"
+      }
+    },
+    {
+      "name": "Entity",
+      "scope": "entity.name",
+      "settings": {
+        "foreground": "#fe4450"
+      }
+    },
+    {
+      "name": "HTML or XML tag",
+      "scope": "entity.name.tag",
+      "settings": {
+        "foreground": "#72f1b8"
+      }
+    },
+    {
+      "name": "HTML or XML tag brackets",
+      "scope": ["punctuation.definition.tag"],
+      "settings": {
+        "foreground": "#36f9f6"
+      }
+    },
+    {
+      "name": "Tag attribute",
+      "scope": "entity.other.attribute-name",
+      "settings": {
+        "foreground": "#fede5d"
+      }
+    },
+    {
+      "name": "Tag attribute HTML",
+      "scope": "entity.other.attribute-name.html",
+      "settings": {
+        "foreground": "#fede5d",
+        "fontStyle": "italic"
+      }
+    },
+    {
+      "name": "Class",
+      "scope": ["entity.name.type", "meta.attribute.class.html"],
+      "settings": {
+        "foreground": "#fe4450"
+      }
+    },
+    {
+      "name": "Inherited class",
+      "scope": "entity.other.inherited-class",
+      "settings": {
+        "foreground": "#D50"
+      }
+    },
+    {
+      "name": "Function",
+      "scope": ["entity.name.function", "variable.function"],
+      "settings": {
+        "foreground": "#36f9f6"
+      }
+    },
+    {
+      "name": "JS Export",
+      "scope": ["keyword.control.export.js", "keyword.control.import.js"],
+      "settings": {
+        "foreground": "#72f1b8"
+      }
+    },
+    {
+      "name": "JS Numerics",
+      "scope": ["constant.numeric.decimal.js"],
+      "settings": {
+        "foreground": "#2EE2FA"
+      }
+    },
+    {
+      "name": "Keyword",
+      "scope": "keyword",
+      "settings": {
+        "foreground": "#fede5d"
+      }
+    },
+    {
+      "name": "Control keyword",
+      "scope": "keyword.control",
+      "settings": {
+        "foreground": "#fede5d"
+      }
+    },
+    {
+      "name": "Operator",
+      "scope": "keyword.operator",
+      "settings": {
+        "foreground": "#fede5d"
+      }
+    },
+    {
+      "name": "Special operator",
+      "scope": [
+        "keyword.operator.new",
+        "keyword.operator.expression",
+        "keyword.operator.logical"
+      ],
+      "settings": {
+        "foreground": "#fede5d"
+      }
+    },
+    {
+      "name": "Unit",
+      "scope": "keyword.other.unit",
+      "settings": {
+        "foreground": "#f97e72"
+      }
+    },
+    {
+      "name": "Support",
+      "scope": "support",
+      "settings": {
+        "foreground": "#fe4450"
+      }
+    },
+    {
+      "name": "Support function",
+      "scope": "support.function",
+      "settings": {
+        "foreground": "#36f9f6"
+      }
+    },
+    {
+      "name": "Support variable",
+      "scope": "support.variable",
+      "settings": {
+        "foreground": "#ff7edb"
+      }
+    },
+    {
+      "name": "Object literal key / property",
+      "scope": ["meta.object-literal.key", "support.type.property-name"],
+      "settings": {
+        "foreground": "#ff7edb"
+      }
+    },
+    {
+      "name": "Key-value separator",
+      "scope": "punctuation.separator.key-value",
+      "settings": {
+        "foreground": "#b6b1b1"
+      }
+    },
+    {
+      "name": "Embedded punctuation",
+      "scope": "punctuation.section.embedded",
+      "settings": {
+        "foreground": "#fede5d"
+      }
+    },
+    {
+      "name": "Template expression",
+      "scope": [
+        "punctuation.definition.template-expression.begin",
+        "punctuation.definition.template-expression.end"
+      ],
+      "settings": {
+        "foreground": "#72f1b8"
+      }
+    },
+    {
+      "name": "CSS property",
+      "scope": [
+        "support.type.property-name.css",
+        "support.type.property-name.json"
+      ],
+      "settings": {
+        "foreground": "#72f1b8"
+      }
+    },
+    {
+      "name": "JS Switch control",
+      "scope": "switch-block.expr.js",
+      "settings": {
+        "foreground": "#72f1b8"
+      }
+    },
+    {
+      "name": "JS object path",
+      "scope": "variable.other.constant.property.js, variable.other.property.js",
+      "settings": {
+        "foreground": "#2ee2fa"
+      }
+    },
+    {
+      "name": "Color",
+      "scope": "constant.other.color",
+      "settings": {
+        "foreground": "#f97e72"
+      }
+    },
+    {
+      "name": "Font names",
+      "scope": "support.constant.font-name",
+      "settings": {
+        "foreground": "#f97e72"
+      }
+    },
+    {
+      "name": "CSS #id",
+      "scope": "entity.other.attribute-name.id",
+      "settings": {
+        "foreground": "#36f9f6"
+      }
+    },
+    {
+      "name": "Pseudo CSS",
+      "scope": [
+        "entity.other.attribute-name.pseudo-element",
+        "entity.other.attribute-name.pseudo-class"
+      ],
+      "settings": {
+        "foreground": "#D50"
+      }
+    },
+    {
+      "name": "CSS support functions (rgb)",
+      "scope": "support.function.misc.css",
+      "settings": {
+        "foreground": "#fe4450"
+      }
+    },
+    {
+      "name": "Markup heading",
+      "scope": ["markup.heading", "entity.name.section"],
+      "settings": {
+        "foreground": "#ff7edb"
+      }
+    },
+    {
+      "name": "Markup text",
+      "scope": ["text.html", "keyword.operator.assignment"],
+      "settings": {
+        "foreground": "#ffffffee"
+      }
+    },
+    {
+      "name": "Markup quote",
+      "scope": "markup.quote",
+      "settings": {
+        "foreground": "#b6b1b1cc",
+        "fontStyle": "italic"
+      }
+    },
+    {
+      "name": "Markup list",
+      "scope": "beginning.punctuation.definition.list",
+      "settings": {
+        "foreground": "#ff7edb"
+      }
+    },
+    {
+      "name": "Markup link",
+      "scope": "markup.underline.link",
+      "settings": {
+        "foreground": "#D50"
+      }
+    },
+    {
+      "name": "Markup link description",
+      "scope": "string.other.link.description",
+      "settings": {
+        "foreground": "#f97e72"
+      }
+    },
+    {
+      "name": "Python function call",
+      "scope": "meta.function-call.generic.python",
+      "settings": {
+        "foreground": "#36f9f6"
+      }
+    },
+    {
+      "name": "Python variable params",
+      "scope": "variable.parameter.function-call.python",
+      "settings": {
+        "foreground": "#72f1b8"
+      }
+    },
+    {
+      "name": "C# storage type",
+      "scope": "storage.type.cs",
+      "settings": {
+        "foreground": "#fe4450"
+      }
+    },
+    {
+      "name": "C# local variable",
+      "scope": "entity.name.variable.local.cs",
+      "settings": {
+        "foreground": "#ff7edb"
+      }
+    },
+    {
+      "name": "C# properties and fields",
+      "scope": [
+        "entity.name.variable.field.cs",
+        "entity.name.variable.property.cs"
+      ],
+      "settings": {
+        "foreground": "#ff7edb"
+      }
+    },
+    {
+      "name": "C placeholder",
+      "scope": "constant.other.placeholder.c",
+      "settings": {
+        "foreground": "#72f1b8",
+        "fontStyle": "italic"
+      }
+    },
+    {
+      "name": "C preprocessors",
+      "scope": [
+        "keyword.control.directive.include.c",
+        "keyword.control.directive.define.c"
+      ],
+      "settings": {
+        "foreground": "#72f1b8"
+      }
+    },
+    {
+      "name": "C storage modifier",
+      "scope": "storage.modifier.c",
+      "settings": {
+        "foreground": "#fe4450"
+      }
+    },
+    {
+      "name": "C++ operators",
+      "scope": "source.cpp keyword.operator",
+      "settings": {
+        "foreground": "#fede5d"
+      }
+    },
+    {
+      "name": "C++ placeholder",
+      "scope": "constant.other.placeholder.cpp",
+      "settings": {
+        "foreground": "#72f1b8",
+        "fontStyle": "italic"
+      }
+    },
+    {
+      "name": "C++ include",
+      "scope": [
+        "keyword.control.directive.include.cpp",
+        "keyword.control.directive.define.cpp"
+      ],
+      "settings": {
+        "foreground": "#72f1b8"
+      }
+    },
+    {
+      "name": "C++ constant modifier",
+      "scope": "storage.modifier.specifier.const.cpp",
+      "settings": {
+        "foreground": "#fe4450"
+      }
+    },
+    {
+      "name": "Elixir Classes",
+      "scope": [
+        "source.elixir support.type.elixir",
+        "source.elixir meta.module.elixir entity.name.class.elixir"
+      ],
+      "settings": {
+        "foreground": "#36f9f6"
+      }
+    },
+    {
+      "name": "Elixir Functions",
+      "scope": "source.elixir entity.name.function",
+      "settings": {
+        "foreground": "#72f1b8"
+      }
+    },
+    {
+      "name": "Elixir Constants",
+      "scope": [
+        "source.elixir constant.other.symbol.elixir",
+        "source.elixir constant.other.keywords.elixir"
+      ],
+      "settings": {
+        "foreground": "#36f9f6"
+      }
+    },
+    {
+      "name": "Elixir String Punctuation",
+      "scope": "source.elixir punctuation.definition.string",
+      "settings": {
+        "foreground": "#72f1b8"
+      }
+    },
+    {
+      "name": "Elixir",
+      "scope": [
+        "source.elixir variable.other.readwrite.module.elixir",
+        "source.elixir variable.other.readwrite.module.elixir punctuation.definition.variable.elixir"
+      ],
+      "settings": {
+        "foreground": "#72f1b8"
+      }
+    },
+    {
+      "name": "Elixir Binary Punctuation",
+      "scope": "source.elixir .punctuation.binary.elixir",
+      "settings": {
+        "foreground": "#ff7edb",
+        "fontStyle": "italic"
+      }
+    },
+    {
+      "name": "Clojure Globals",
+      "scope": ["entity.global.clojure"],
+      "settings": {
+        "foreground": "#36f9f6",
+        "fontStyle": "bold"
+      }
+    },
+    {
+      "name": "Clojure Storage",
+      "scope": ["storage.control.clojure"],
+      "settings": {
+        "foreground": "#36f9f6",
+        "fontStyle": "italic"
+      }
+    },
+    {
+      "name": "Clojure Metadata",
+      "scope": ["meta.metadata.simple.clojure", "meta.metadata.map.clojure"],
+      "settings": {
+        "foreground": "#fe4450",
+        "fontStyle": "italic"
+      }
+    },
+    {
+      "name": "Clojure Macros, Quoted",
+      "scope": ["meta.quoted-expression.clojure"],
+      "settings": {
+        "fontStyle": "italic"
+      }
+    },
+    {
+      "name": "Clojure Symbols",
+      "scope": ["meta.symbol.clojure"],
+      "settings": {
+        "foreground": "#ff7edbff"
+      }
+    },
+    {
+      "name": "Go basic",
+      "scope": "source.go",
+      "settings": {
+        "foreground": "#ff7edbff"
+      }
+    },
+    {
+      "name": "Go Function Calls",
+      "scope": "source.go meta.function-call.go",
+      "settings": {
+        "foreground": "#36f9f6"
+      }
+    },
+    {
+      "name": "Go Keywords",
+      "scope": [
+        "source.go keyword.package.go",
+        "source.go keyword.import.go",
+        "source.go keyword.function.go",
+        "source.go keyword.type.go",
+        "source.go keyword.const.go",
+        "source.go keyword.var.go",
+        "source.go keyword.map.go",
+        "source.go keyword.channel.go",
+        "source.go keyword.control.go"
+      ],
+      "settings": {
+        "foreground": "#fede5d"
+      }
+    },
+    {
+      "name": "Go interfaces",
+      "scope": [
+        "source.go storage.type",
+        "source.go keyword.struct.go",
+        "source.go keyword.interface.go"
+      ],
+      "settings": {
+        "foreground": "#72f1b8"
+      }
+    },
+    {
+      "name": "Go Constants e.g. nil, string format (%s, %d, etc.)",
+      "scope": [
+        "source.go constant.language.go",
+        "source.go constant.other.placeholder.go",
+        "source.go variable"
+      ],
+      "settings": {
+        "foreground": "#2EE2FA"
+      }
+    },
+    {
+      "name": "Markdown links and image paths",
+      "scope": [
+        "markup.underline.link.markdown",
+        "markup.inline.raw.string.markdown"
+      ],
+      "settings": {
+        "foreground": "#72f1b8",
+        "fontStyle": "italic"
+      }
+    },
+    {
+      "name": "Markdown links and image paths",
+      "scope": ["string.other.link.title.markdown"],
+      "settings": {
+        "foreground": "#fede5d"
+      }
+    },
+    {
+      "name": "Markdown headings",
+      "scope": ["markup.heading.markdown", "entity.name.section.markdown"],
+      "settings": {
+        "foreground": "#ff7edb",
+        "fontStyle": "bold"
+      }
+    },
+    {
+      "name": "Markdown italic",
+      "scope": ["markup.italic.markdown"],
+      "settings": {
+        "foreground": "#2EE2FA",
+        "fontStyle": "italic"
+      }
+    },
+    {
+      "name": "Markdown bold",
+      "scope": ["markup.bold.markdown"],
+      "settings": {
+        "foreground": "#2EE2FA",
+        "fontStyle": "bold"
+      }
+    },
+    {
+      "name": "Markdown quotes",
+      "scope": [
+        "punctuation.definition.quote.begin.markdown",
+        "markup.quote.markdown"
+      ],
+      "settings": {
+        "foreground": "#72f1b8"
+      }
+    },
+    {
+      "name": "Basic source colours",
+      "scope": ["source.dart", "source.python", "source.scala"],
+      "settings": {
+        "foreground": "#ff7edbff"
+      }
+    },
+    {
+      "name": "Dart strings",
+      "scope": ["string.interpolated.single.dart"],
+      "settings": {
+        "foreground": "#f97e72"
+      }
+    },
+    {
+      "name": "Dart variable params",
+      "scope": ["variable.parameter.dart"],
+      "settings": {
+        "foreground": "#72f1b8"
+      }
+    },
+    {
+      "name": "Dart numerics",
+      "scope": ["constant.numeric.dart"],
+      "settings": {
+        "foreground": "#2EE2FA"
+      }
+    },
+    {
+      "name": "Scala variable params",
+      "scope": ["variable.parameter.scala"],
+      "settings": {
+        "foreground": "#2EE2FA"
+      }
+    },
+    {
+      "name": "Scala",
+      "scope": ["meta.template.expression.scala"],
+      "settings": {
+        "foreground": "#72f1b8"
+      }
+    }
+  ]
 }

crates/command_palette2/Cargo.toml πŸ”—

@@ -0,0 +1,34 @@
+[package]
+name = "command_palette2"
+version = "0.1.0"
+edition = "2021"
+publish = false
+
+[lib]
+path = "src/command_palette.rs"
+doctest = false
+
+[dependencies]
+collections = { path = "../collections" }
+editor = { package = "editor2", path = "../editor2" }
+fuzzy = { package = "fuzzy2", path = "../fuzzy2" }
+gpui = { package = "gpui2", path = "../gpui2" }
+picker = { package = "picker2", path = "../picker2" }
+project = { package = "project2", path = "../project2" }
+settings = { package = "settings2", path = "../settings2" }
+ui = { package = "ui2", path = "../ui2" }
+util = { path = "../util" }
+theme = { package = "theme2", path = "../theme2" }
+workspace = { package="workspace2", path = "../workspace2" }
+zed_actions = { package = "zed_actions2", path = "../zed_actions2" }
+anyhow.workspace = true
+serde.workspace = true
+[dev-dependencies]
+gpui = { package = "gpui2", path = "../gpui2", features = ["test-support"] }
+editor = { package = "editor2", path = "../editor2", features = ["test-support"] }
+language = { package="language2", path = "../language2", features = ["test-support"] }
+project = { package="project2", path = "../project2", features = ["test-support"] }
+serde_json.workspace = true
+workspace = { package="workspace2", path = "../workspace2", features = ["test-support"] }
+ctor.workspace = true
+env_logger.workspace = true

crates/command_palette2/src/command_palette.rs πŸ”—

@@ -0,0 +1,532 @@
+use collections::{CommandPaletteFilter, HashMap};
+use fuzzy::{StringMatch, StringMatchCandidate};
+use gpui::{
+    actions, div, Action, AppContext, Component, Div, EventEmitter, FocusHandle, Keystroke,
+    ParentElement, Render, StatelessInteractive, Styled, View, ViewContext, VisualContext,
+    WeakView, WindowContext,
+};
+use picker::{Picker, PickerDelegate};
+use std::cmp::{self, Reverse};
+use theme::ActiveTheme;
+use ui::{v_stack, Label, StyledExt};
+use util::{
+    channel::{parse_zed_link, ReleaseChannel, RELEASE_CHANNEL},
+    ResultExt,
+};
+use workspace::{Modal, ModalEvent, Workspace};
+use zed_actions::OpenZedURL;
+
+actions!(Toggle);
+
+pub fn init(cx: &mut AppContext) {
+    cx.set_global(HitCounts::default());
+    cx.observe_new_views(CommandPalette::register).detach();
+}
+
+pub struct CommandPalette {
+    picker: View<Picker<CommandPaletteDelegate>>,
+}
+
+impl CommandPalette {
+    fn register(workspace: &mut Workspace, _: &mut ViewContext<Workspace>) {
+        workspace.register_action(|workspace, _: &Toggle, cx| {
+            let Some(previous_focus_handle) = cx.focused() else {
+                return;
+            };
+            workspace.toggle_modal(cx, move |cx| CommandPalette::new(previous_focus_handle, cx));
+        });
+    }
+
+    fn new(previous_focus_handle: FocusHandle, cx: &mut ViewContext<Self>) -> Self {
+        let filter = cx.try_global::<CommandPaletteFilter>();
+
+        let commands = cx
+            .available_actions()
+            .into_iter()
+            .filter_map(|action| {
+                let name = action.name();
+                let namespace = name.split("::").next().unwrap_or("malformed action name");
+                if filter.is_some_and(|f| f.filtered_namespaces.contains(namespace)) {
+                    return None;
+                }
+
+                Some(Command {
+                    name: humanize_action_name(&name),
+                    action,
+                    keystrokes: vec![], // todo!()
+                })
+            })
+            .collect();
+
+        let delegate =
+            CommandPaletteDelegate::new(cx.view().downgrade(), commands, previous_focus_handle);
+
+        let picker = cx.build_view(|cx| Picker::new(delegate, cx));
+        Self { picker }
+    }
+}
+
+impl EventEmitter<ModalEvent> for CommandPalette {}
+impl Modal for CommandPalette {
+    fn focus(&self, cx: &mut WindowContext) {
+        self.picker.update(cx, |picker, cx| picker.focus(cx));
+    }
+}
+
+impl Render for CommandPalette {
+    type Element = Div<Self>;
+
+    fn render(&mut self, _cx: &mut ViewContext<Self>) -> Self::Element {
+        v_stack().w_96().child(self.picker.clone())
+    }
+}
+
+pub type CommandPaletteInterceptor =
+    Box<dyn Fn(&str, &AppContext) -> Option<CommandInterceptResult>>;
+
+pub struct CommandInterceptResult {
+    pub action: Box<dyn Action>,
+    pub string: String,
+    pub positions: Vec<usize>,
+}
+
+pub struct CommandPaletteDelegate {
+    command_palette: WeakView<CommandPalette>,
+    commands: Vec<Command>,
+    matches: Vec<StringMatch>,
+    selected_ix: usize,
+    previous_focus_handle: FocusHandle,
+}
+
+struct Command {
+    name: String,
+    action: Box<dyn Action>,
+    keystrokes: Vec<Keystroke>,
+}
+
+impl Clone for Command {
+    fn clone(&self) -> Self {
+        Self {
+            name: self.name.clone(),
+            action: self.action.boxed_clone(),
+            keystrokes: self.keystrokes.clone(),
+        }
+    }
+}
+/// Hit count for each command in the palette.
+/// We only account for commands triggered directly via command palette and not by e.g. keystrokes because
+/// if an user already knows a keystroke for a command, they are unlikely to use a command palette to look for it.
+#[derive(Default)]
+struct HitCounts(HashMap<String, usize>);
+
+impl CommandPaletteDelegate {
+    fn new(
+        command_palette: WeakView<CommandPalette>,
+        commands: Vec<Command>,
+        previous_focus_handle: FocusHandle,
+    ) -> Self {
+        Self {
+            command_palette,
+            matches: commands
+                .iter()
+                .enumerate()
+                .map(|(i, command)| StringMatch {
+                    candidate_id: i,
+                    string: command.name.clone(),
+                    positions: Vec::new(),
+                    score: 0.0,
+                })
+                .collect(),
+            commands,
+            selected_ix: 0,
+            previous_focus_handle,
+        }
+    }
+}
+
+impl PickerDelegate for CommandPaletteDelegate {
+    type ListItem = Div<Picker<Self>>;
+
+    fn match_count(&self) -> usize {
+        self.matches.len()
+    }
+
+    fn selected_index(&self) -> usize {
+        self.selected_ix
+    }
+
+    fn set_selected_index(&mut self, ix: usize, _: &mut ViewContext<Picker<Self>>) {
+        self.selected_ix = ix;
+    }
+
+    fn update_matches(
+        &mut self,
+        query: String,
+        cx: &mut ViewContext<Picker<Self>>,
+    ) -> gpui::Task<()> {
+        let mut commands = self.commands.clone();
+
+        cx.spawn(move |picker, mut cx| async move {
+            cx.read_global::<HitCounts, _>(|hit_counts, _| {
+                commands.sort_by_key(|action| {
+                    (
+                        Reverse(hit_counts.0.get(&action.name).cloned()),
+                        action.name.clone(),
+                    )
+                });
+            })
+            .ok();
+
+            let candidates = commands
+                .iter()
+                .enumerate()
+                .map(|(ix, command)| StringMatchCandidate {
+                    id: ix,
+                    string: command.name.to_string(),
+                    char_bag: command.name.chars().collect(),
+                })
+                .collect::<Vec<_>>();
+            let mut matches = if query.is_empty() {
+                candidates
+                    .into_iter()
+                    .enumerate()
+                    .map(|(index, candidate)| StringMatch {
+                        candidate_id: index,
+                        string: candidate.string,
+                        positions: Vec::new(),
+                        score: 0.0,
+                    })
+                    .collect()
+            } else {
+                fuzzy::match_strings(
+                    &candidates,
+                    &query,
+                    true,
+                    10000,
+                    &Default::default(),
+                    cx.background_executor().clone(),
+                )
+                .await
+            };
+
+            let mut intercept_result = cx
+                .try_read_global(|interceptor: &CommandPaletteInterceptor, cx| {
+                    (interceptor)(&query, cx)
+                })
+                .flatten();
+
+            if *RELEASE_CHANNEL == ReleaseChannel::Dev {
+                if parse_zed_link(&query).is_some() {
+                    intercept_result = Some(CommandInterceptResult {
+                        action: OpenZedURL { url: query.clone() }.boxed_clone(),
+                        string: query.clone(),
+                        positions: vec![],
+                    })
+                }
+            }
+            if let Some(CommandInterceptResult {
+                action,
+                string,
+                positions,
+            }) = intercept_result
+            {
+                if let Some(idx) = matches
+                    .iter()
+                    .position(|m| commands[m.candidate_id].action.type_id() == action.type_id())
+                {
+                    matches.remove(idx);
+                }
+                commands.push(Command {
+                    name: string.clone(),
+                    action,
+                    keystrokes: vec![],
+                });
+                matches.insert(
+                    0,
+                    StringMatch {
+                        candidate_id: commands.len() - 1,
+                        string,
+                        positions,
+                        score: 0.0,
+                    },
+                )
+            }
+            picker
+                .update(&mut cx, |picker, _| {
+                    let delegate = &mut picker.delegate;
+                    delegate.commands = commands;
+                    delegate.matches = matches;
+                    if delegate.matches.is_empty() {
+                        delegate.selected_ix = 0;
+                    } else {
+                        delegate.selected_ix =
+                            cmp::min(delegate.selected_ix, delegate.matches.len() - 1);
+                    }
+                })
+                .log_err();
+        })
+    }
+
+    fn dismissed(&mut self, cx: &mut ViewContext<Picker<Self>>) {
+        self.command_palette
+            .update(cx, |_, cx| cx.emit(ModalEvent::Dismissed))
+            .log_err();
+    }
+
+    fn confirm(&mut self, _: bool, cx: &mut ViewContext<Picker<Self>>) {
+        if self.matches.is_empty() {
+            self.dismissed(cx);
+            return;
+        }
+        let action_ix = self.matches[self.selected_ix].candidate_id;
+        let command = self.commands.swap_remove(action_ix);
+        cx.update_global(|hit_counts: &mut HitCounts, _| {
+            *hit_counts.0.entry(command.name).or_default() += 1;
+        });
+        let action = command.action;
+        cx.focus(&self.previous_focus_handle);
+        cx.dispatch_action(action);
+        self.dismissed(cx);
+    }
+
+    fn render_match(
+        &self,
+        ix: usize,
+        selected: bool,
+        cx: &mut ViewContext<Picker<Self>>,
+    ) -> Self::ListItem {
+        let colors = cx.theme().colors();
+        let Some(command) = self
+            .matches
+            .get(ix)
+            .and_then(|m| self.commands.get(m.candidate_id))
+        else {
+            return div();
+        };
+
+        div()
+            .px_1()
+            .text_color(colors.text)
+            .text_ui()
+            .bg(colors.ghost_element_background)
+            .rounded_md()
+            .when(selected, |this| this.bg(colors.ghost_element_selected))
+            .hover(|this| this.bg(colors.ghost_element_hover))
+            .child(Label::new(command.name.clone()))
+    }
+
+    // fn render_match(
+    //     &self,
+    //     ix: usize,
+    //     mouse_state: &mut MouseState,
+    //     selected: bool,
+    //     cx: &gpui::AppContext,
+    // ) -> AnyElement<Picker<Self>> {
+    //     let mat = &self.matches[ix];
+    //     let command = &self.actions[mat.candidate_id];
+    //     let theme = theme::current(cx);
+    //     let style = theme.picker.item.in_state(selected).style_for(mouse_state);
+    //     let key_style = &theme.command_palette.key.in_state(selected);
+    //     let keystroke_spacing = theme.command_palette.keystroke_spacing;
+
+    //     Flex::row()
+    //         .with_child(
+    //             Label::new(mat.string.clone(), style.label.clone())
+    //                 .with_highlights(mat.positions.clone()),
+    //         )
+    //         .with_children(command.keystrokes.iter().map(|keystroke| {
+    //             Flex::row()
+    //                 .with_children(
+    //                     [
+    //                         (keystroke.ctrl, "^"),
+    //                         (keystroke.alt, "βŒ₯"),
+    //                         (keystroke.cmd, "⌘"),
+    //                         (keystroke.shift, "⇧"),
+    //                     ]
+    //                     .into_iter()
+    //                     .filter_map(|(modifier, label)| {
+    //                         if modifier {
+    //                             Some(
+    //                                 Label::new(label, key_style.label.clone())
+    //                                     .contained()
+    //                                     .with_style(key_style.container),
+    //                             )
+    //                         } else {
+    //                             None
+    //                         }
+    //                     }),
+    //                 )
+    //                 .with_child(
+    //                     Label::new(keystroke.key.clone(), key_style.label.clone())
+    //                         .contained()
+    //                         .with_style(key_style.container),
+    //                 )
+    //                 .contained()
+    //                 .with_margin_left(keystroke_spacing)
+    //                 .flex_float()
+    //         }))
+    //         .contained()
+    //         .with_style(style.container)
+    //         .into_any()
+    // }
+}
+
+fn humanize_action_name(name: &str) -> String {
+    let capacity = name.len() + name.chars().filter(|c| c.is_uppercase()).count();
+    let mut result = String::with_capacity(capacity);
+    for char in name.chars() {
+        if char == ':' {
+            if result.ends_with(':') {
+                result.push(' ');
+            } else {
+                result.push(':');
+            }
+        } else if char == '_' {
+            result.push(' ');
+        } else if char.is_uppercase() {
+            if !result.ends_with(' ') {
+                result.push(' ');
+            }
+            result.extend(char.to_lowercase());
+        } else {
+            result.push(char);
+        }
+    }
+    result
+}
+
+impl std::fmt::Debug for Command {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        f.debug_struct("Command")
+            .field("name", &self.name)
+            .field("keystrokes", &self.keystrokes)
+            .finish()
+    }
+}
+
+// #[cfg(test)]
+// mod tests {
+//     use std::sync::Arc;
+
+//     use super::*;
+//     use editor::Editor;
+//     use gpui::{executor::Deterministic, TestAppContext};
+//     use project::Project;
+//     use workspace::{AppState, Workspace};
+
+//     #[test]
+//     fn test_humanize_action_name() {
+//         assert_eq!(
+//             humanize_action_name("editor::GoToDefinition"),
+//             "editor: go to definition"
+//         );
+//         assert_eq!(
+//             humanize_action_name("editor::Backspace"),
+//             "editor: backspace"
+//         );
+//         assert_eq!(
+//             humanize_action_name("go_to_line::Deploy"),
+//             "go to line: deploy"
+//         );
+//     }
+
+//     #[gpui::test]
+//     async fn test_command_palette(deterministic: Arc<Deterministic>, cx: &mut TestAppContext) {
+//         let app_state = init_test(cx);
+
+//         let project = Project::test(app_state.fs.clone(), [], cx).await;
+//         let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
+//         let workspace = window.root(cx);
+//         let editor = window.add_view(cx, |cx| {
+//             let mut editor = Editor::single_line(None, cx);
+//             editor.set_text("abc", cx);
+//             editor
+//         });
+
+//         workspace.update(cx, |workspace, cx| {
+//             cx.focus(&editor);
+//             workspace.add_item(Box::new(editor.clone()), cx)
+//         });
+
+//         workspace.update(cx, |workspace, cx| {
+//             toggle_command_palette(workspace, &Toggle, cx);
+//         });
+
+//         let palette = workspace.read_with(cx, |workspace, _| {
+//             workspace.modal::<CommandPalette>().unwrap()
+//         });
+
+//         palette
+//             .update(cx, |palette, cx| {
+//                 // Fill up palette's command list by running an empty query;
+//                 // we only need it to subsequently assert that the palette is initially
+//                 // sorted by command's name.
+//                 palette.delegate_mut().update_matches("".to_string(), cx)
+//             })
+//             .await;
+
+//         palette.update(cx, |palette, _| {
+//             let is_sorted =
+//                 |actions: &[Command]| actions.windows(2).all(|pair| pair[0].name <= pair[1].name);
+//             assert!(is_sorted(&palette.delegate().actions));
+//         });
+
+//         palette
+//             .update(cx, |palette, cx| {
+//                 palette
+//                     .delegate_mut()
+//                     .update_matches("bcksp".to_string(), cx)
+//             })
+//             .await;
+
+//         palette.update(cx, |palette, cx| {
+//             assert_eq!(palette.delegate().matches[0].string, "editor: backspace");
+//             palette.confirm(&Default::default(), cx);
+//         });
+//         deterministic.run_until_parked();
+//         editor.read_with(cx, |editor, cx| {
+//             assert_eq!(editor.text(cx), "ab");
+//         });
+
+//         // Add namespace filter, and redeploy the palette
+//         cx.update(|cx| {
+//             cx.update_default_global::<CommandPaletteFilter, _, _>(|filter, _| {
+//                 filter.filtered_namespaces.insert("editor");
+//             })
+//         });
+
+//         workspace.update(cx, |workspace, cx| {
+//             toggle_command_palette(workspace, &Toggle, cx);
+//         });
+
+//         // Assert editor command not present
+//         let palette = workspace.read_with(cx, |workspace, _| {
+//             workspace.modal::<CommandPalette>().unwrap()
+//         });
+
+//         palette
+//             .update(cx, |palette, cx| {
+//                 palette
+//                     .delegate_mut()
+//                     .update_matches("bcksp".to_string(), cx)
+//             })
+//             .await;
+
+//         palette.update(cx, |palette, _| {
+//             assert!(palette.delegate().matches.is_empty())
+//         });
+//     }
+
+//     fn init_test(cx: &mut TestAppContext) -> Arc<AppState> {
+//         cx.update(|cx| {
+//             let app_state = AppState::test(cx);
+//             theme::init(cx);
+//             language::init(cx);
+//             editor::init(cx);
+//             workspace::init(app_state.clone(), cx);
+//             init(cx);
+//             Project::init_settings(cx);
+//             app_state
+//         })
+//     }
+// }

crates/diagnostics/src/diagnostics.rs πŸ”—

@@ -171,10 +171,9 @@ impl ProjectDiagnosticsEditor {
                         .entry(*language_server_id)
                         .or_default()
                         .insert(path.clone());
-                    let no_multiselections = this.editor.update(cx, |editor, cx| {
-                        editor.selections.all::<usize>(cx).len() <= 1
-                    });
-                    if no_multiselections && !this.is_dirty(cx) {
+                    if this.editor.read(cx).selections.all::<usize>(cx).is_empty()
+                        && !this.is_dirty(cx)
+                    {
                         this.update_excerpts(Some(*language_server_id), cx);
                     }
                 }

crates/editor/src/editor_settings.rs πŸ”—

@@ -2,7 +2,7 @@ use schemars::JsonSchema;
 use serde::{Deserialize, Serialize};
 use settings::Setting;
 
-#[derive(Deserialize)]
+#[derive(Clone, Deserialize)]
 pub struct EditorSettings {
     pub cursor_blink: bool,
     pub hover_popover_enabled: bool,
@@ -11,6 +11,15 @@ pub struct EditorSettings {
     pub use_on_type_format: bool,
     pub scrollbar: Scrollbar,
     pub relative_line_numbers: bool,
+    pub seed_search_query_from_cursor: SeedQuerySetting,
+}
+
+#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
+#[serde(rename_all = "snake_case")]
+pub enum SeedQuerySetting {
+    Always,
+    Selection,
+    Never,
 }
 
 #[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
@@ -38,6 +47,7 @@ pub struct EditorSettingsContent {
     pub use_on_type_format: Option<bool>,
     pub scrollbar: Option<ScrollbarContent>,
     pub relative_line_numbers: Option<bool>,
+    pub seed_search_query_from_cursor: Option<SeedQuerySetting>,
 }
 
 #[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]

crates/editor/src/items.rs πŸ”—

@@ -1,7 +1,7 @@
 use crate::{
-    display_map::ToDisplayPoint, link_go_to_definition::hide_link_definition,
-    movement::surrounding_word, persistence::DB, scroll::ScrollAnchor, Anchor, Autoscroll, Editor,
-    Event, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, NavigationData, ToPoint as _,
+    editor_settings::SeedQuerySetting, link_go_to_definition::hide_link_definition,
+    persistence::DB, scroll::ScrollAnchor, Anchor, Autoscroll, Editor, EditorSettings, Event,
+    ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, NavigationData, ToPoint as _,
 };
 use anyhow::{Context, Result};
 use collections::HashSet;
@@ -13,8 +13,8 @@ use gpui::{
     ViewHandle, WeakViewHandle,
 };
 use language::{
-    proto::serialize_anchor as serialize_text_anchor, Bias, Buffer, OffsetRangeExt, Point,
-    SelectionGoal,
+    proto::serialize_anchor as serialize_text_anchor, Bias, Buffer, CharKind, OffsetRangeExt,
+    Point, SelectionGoal,
 };
 use project::{search::SearchQuery, FormatTrigger, Item as _, Project, ProjectPath};
 use rpc::proto::{self, update_view, PeerId};
@@ -937,24 +937,28 @@ impl SearchableItem for Editor {
     }
 
     fn query_suggestion(&mut self, cx: &mut ViewContext<Self>) -> String {
-        let display_map = self.snapshot(cx).display_snapshot;
+        let setting = settings::get::<EditorSettings>(cx).seed_search_query_from_cursor;
+        let snapshot = &self.snapshot(cx).buffer_snapshot;
         let selection = self.selections.newest::<usize>(cx);
-        if selection.start == selection.end {
-            let point = selection.start.to_display_point(&display_map);
-            let range = surrounding_word(&display_map, point);
-            let range = range.start.to_offset(&display_map, Bias::Left)
-                ..range.end.to_offset(&display_map, Bias::Right);
-            let text: String = display_map.buffer_snapshot.text_for_range(range).collect();
-            if text.trim().is_empty() {
+
+        match setting {
+            SeedQuerySetting::Never => String::new(),
+            SeedQuerySetting::Selection | SeedQuerySetting::Always if !selection.is_empty() => {
+                snapshot
+                    .text_for_range(selection.start..selection.end)
+                    .collect()
+            }
+            SeedQuerySetting::Selection => String::new(),
+            SeedQuerySetting::Always => {
+                let (range, kind) = snapshot.surrounding_word(selection.start);
+                if kind == Some(CharKind::Word) {
+                    let text: String = snapshot.text_for_range(range).collect();
+                    if !text.trim().is_empty() {
+                        return text;
+                    }
+                }
                 String::new()
-            } else {
-                text
             }
-        } else {
-            display_map
-                .buffer_snapshot
-                .text_for_range(selection.start..selection.end)
-                .collect()
         }
     }
 

crates/editor2/Cargo.toml πŸ”—

@@ -44,6 +44,7 @@ snippet = { path = "../snippet" }
 sum_tree = { path = "../sum_tree" }
 text = { package="text2", path = "../text2" }
 theme = { package="theme2", path = "../theme2" }
+ui = { package = "ui2", path = "../ui2" }
 util = { path = "../util" }
 sqlez = { path = "../sqlez" }
 workspace = { package = "workspace2", path = "../workspace2" }

crates/editor2/src/editor.rs πŸ”—

@@ -39,10 +39,12 @@ use futures::FutureExt;
 use fuzzy::{StringMatch, StringMatchCandidate};
 use git::diff_hunk_to_display;
 use gpui::{
-    action, actions, point, px, relative, rems, size, AnyElement, AppContext, BackgroundExecutor,
-    Bounds, ClipboardItem, Context, DispatchContext, EventEmitter, FocusHandle, FontFeatures,
-    FontStyle, FontWeight, HighlightStyle, Hsla, InputHandler, Model, Pixels, Render, Subscription,
-    Task, TextStyle, View, ViewContext, VisualContext, WeakView, WindowContext,
+    action, actions, div, point, px, relative, rems, size, uniform_list, AnyElement, AppContext,
+    AsyncWindowContext, BackgroundExecutor, Bounds, ClipboardItem, Component, Context,
+    DispatchContext, EventEmitter, FocusHandle, FontFeatures, FontStyle, FontWeight,
+    HighlightStyle, Hsla, InputHandler, Model, MouseButton, ParentElement, Pixels, Render,
+    StatelessInteractive, Styled, Subscription, Task, TextStyle, UniformListScrollHandle, View,
+    ViewContext, VisualContext, WeakView, WindowContext,
 };
 use highlight_matching_bracket::refresh_matching_bracket_highlights;
 use hover_popover::{hide_hover, HoverState};
@@ -67,7 +69,7 @@ pub use multi_buffer::{
 };
 use ordered_float::OrderedFloat;
 use parking_lot::{Mutex, RwLock};
-use project::{FormatTrigger, Location, Project};
+use project::{FormatTrigger, Location, Project, ProjectTransaction};
 use rand::prelude::*;
 use rpc::proto::*;
 use scroll::{
@@ -95,6 +97,7 @@ use text::{OffsetUtf16, Rope};
 use theme::{
     ActiveTheme, DiagnosticStyle, PlayerColor, SyntaxTheme, Theme, ThemeColors, ThemeSettings,
 };
+use ui::{IconButton, StyledExt};
 use util::{post_inc, RangeExt, ResultExt, TryFutureExt};
 use workspace::{
     item::ItemEvent, searchable::SearchEvent, ItemNavHistory, SplitDirection, ViewId, Workspace,
@@ -384,26 +387,6 @@ actions!(
     UnfoldLines,
 );
 
-// impl_actions!(
-//     editor,
-//     [
-//         SelectNext,
-//         SelectPrevious,
-//         SelectAllMatches,
-//         SelectToBeginningOfLine,
-//         SelectToEndOfLine,
-//         ToggleCodeActions,
-//         MovePageUp,
-//         MovePageDown,
-//         ConfirmCompletion,
-//         ConfirmCodeAction,
-//         ToggleComments,
-//         FoldAt,
-//         UnfoldAt,
-//         GutterHover
-//     ]
-// );
-
 enum DocumentHighlightRead {}
 enum DocumentHighlightWrite {}
 enum InputComposition {}
@@ -919,15 +902,14 @@ impl ContextMenu {
     fn render(
         &self,
         cursor_position: DisplayPoint,
-        style: EditorStyle,
+        style: &EditorStyle,
         workspace: Option<WeakView<Workspace>>,
         cx: &mut ViewContext<Editor>,
     ) -> (DisplayPoint, AnyElement<Editor>) {
-        todo!()
-        // match self {
-        //     ContextMenu::Completions(menu) => (cursor_position, menu.render(style, workspace, cx)),
-        //     ContextMenu::CodeActions(menu) => menu.render(cursor_position, style, cx),
-        // }
+        match self {
+            ContextMenu::Completions(menu) => (cursor_position, menu.render(style, workspace, cx)),
+            ContextMenu::CodeActions(menu) => menu.render(cursor_position, style, cx),
+        }
     }
 }
 
@@ -940,29 +922,13 @@ struct CompletionsMenu {
     match_candidates: Arc<[StringMatchCandidate]>,
     matches: Arc<[StringMatch]>,
     selected_item: usize,
-    list: UniformListState,
-}
-
-// todo!(this is fake)
-#[derive(Clone, Default)]
-struct UniformListState;
-
-// todo!(this is fake)
-impl UniformListState {
-    pub fn scroll_to(&mut self, target: ScrollTarget) {}
-}
-
-// todo!(this is somewhat fake)
-#[derive(Debug)]
-pub enum ScrollTarget {
-    Show(usize),
-    Center(usize),
+    scroll_handle: UniformListScrollHandle,
 }
 
 impl CompletionsMenu {
     fn select_first(&mut self, project: Option<&Model<Project>>, cx: &mut ViewContext<Editor>) {
         self.selected_item = 0;
-        self.list.scroll_to(ScrollTarget::Show(self.selected_item));
+        self.scroll_handle.scroll_to_item(self.selected_item);
         self.attempt_resolve_selected_completion_documentation(project, cx);
         cx.notify();
     }
@@ -973,7 +939,7 @@ impl CompletionsMenu {
         } else {
             self.selected_item = self.matches.len() - 1;
         }
-        self.list.scroll_to(ScrollTarget::Show(self.selected_item));
+        self.scroll_handle.scroll_to_item(self.selected_item);
         self.attempt_resolve_selected_completion_documentation(project, cx);
         cx.notify();
     }
@@ -984,14 +950,14 @@ impl CompletionsMenu {
         } else {
             self.selected_item = 0;
         }
-        self.list.scroll_to(ScrollTarget::Show(self.selected_item));
+        self.scroll_handle.scroll_to_item(self.selected_item);
         self.attempt_resolve_selected_completion_documentation(project, cx);
         cx.notify();
     }
 
     fn select_last(&mut self, project: Option<&Model<Project>>, cx: &mut ViewContext<Editor>) {
         self.selected_item = self.matches.len() - 1;
-        self.list.scroll_to(ScrollTarget::Show(self.selected_item));
+        self.scroll_handle.scroll_to_item(self.selected_item);
         self.attempt_resolve_selected_completion_documentation(project, cx);
         cx.notify();
     }
@@ -1252,13 +1218,13 @@ impl CompletionsMenu {
 
     fn render(
         &self,
-        style: EditorStyle,
+        style: &EditorStyle,
         workspace: Option<WeakView<Workspace>>,
         cx: &mut ViewContext<Editor>,
-    ) {
+    ) -> AnyElement<Editor> {
         todo!("old implementation below")
     }
-    // ) -> AnyElement<Editor> {
+
     //     enum CompletionTag {}
 
     //     let settings = EditorSettings>(cx);
@@ -1527,14 +1493,14 @@ struct CodeActionsMenu {
     actions: Arc<[CodeAction]>,
     buffer: Model<Buffer>,
     selected_item: usize,
-    list: UniformListState,
+    scroll_handle: UniformListScrollHandle,
     deployed_from_indicator: bool,
 }
 
 impl CodeActionsMenu {
     fn select_first(&mut self, cx: &mut ViewContext<Editor>) {
         self.selected_item = 0;
-        self.list.scroll_to(ScrollTarget::Show(self.selected_item));
+        self.scroll_handle.scroll_to_item(self.selected_item);
         cx.notify()
     }
 
@@ -1544,7 +1510,7 @@ impl CodeActionsMenu {
         } else {
             self.selected_item = self.actions.len() - 1;
         }
-        self.list.scroll_to(ScrollTarget::Show(self.selected_item));
+        self.scroll_handle.scroll_to_item(self.selected_item);
         cx.notify();
     }
 
@@ -1554,13 +1520,13 @@ impl CodeActionsMenu {
         } else {
             self.selected_item = 0;
         }
-        self.list.scroll_to(ScrollTarget::Show(self.selected_item));
+        self.scroll_handle.scroll_to_item(self.selected_item);
         cx.notify();
     }
 
     fn select_last(&mut self, cx: &mut ViewContext<Editor>) {
         self.selected_item = self.actions.len() - 1;
-        self.list.scroll_to(ScrollTarget::Show(self.selected_item));
+        self.scroll_handle.scroll_to_item(self.selected_item);
         cx.notify()
     }
 
@@ -1571,83 +1537,70 @@ impl CodeActionsMenu {
     fn render(
         &self,
         mut cursor_position: DisplayPoint,
-        style: EditorStyle,
+        style: &EditorStyle,
         cx: &mut ViewContext<Editor>,
     ) -> (DisplayPoint, AnyElement<Editor>) {
-        todo!("old version below")
-    }
-    //     enum ActionTag {}
+        let actions = self.actions.clone();
+        let selected_item = self.selected_item;
+        let element = uniform_list(
+            "code_actions_menu",
+            self.actions.len(),
+            move |editor, range, cx| {
+                actions[range.clone()]
+                    .iter()
+                    .enumerate()
+                    .map(|(ix, action)| {
+                        let item_ix = range.start + ix;
+                        let selected = selected_item == item_ix;
+                        let colors = cx.theme().colors();
+                        div()
+                            .px_2()
+                            .text_ui()
+                            .text_color(colors.text)
+                            .when(selected, |style| {
+                                style
+                                    .bg(colors.element_active)
+                                    .text_color(colors.text_accent)
+                            })
+                            .hover(|style| {
+                                style
+                                    .bg(colors.element_hover)
+                                    .text_color(colors.text_accent)
+                            })
+                            .on_mouse_down(MouseButton::Left, move |editor: &mut Editor, _, cx| {
+                                cx.stop_propagation();
+                                editor
+                                    .confirm_code_action(
+                                        &ConfirmCodeAction {
+                                            item_ix: Some(item_ix),
+                                        },
+                                        cx,
+                                    )
+                                    .map(|task| task.detach_and_log_err(cx));
+                            })
+                            .child(action.lsp_action.title.clone())
+                    })
+                    .collect()
+            },
+        )
+        .elevation_1(cx)
+        .px_2()
+        .py_1()
+        .with_width_from_item(
+            self.actions
+                .iter()
+                .enumerate()
+                .max_by_key(|(_, action)| action.lsp_action.title.chars().count())
+                .map(|(ix, _)| ix),
+        )
+        .render();
 
-    //     let container_style = style.autocomplete.container;
-    //     let actions = self.actions.clone();
-    //     let selected_item = self.selected_item;
-    //     let element = UniformList::new(
-    //         self.list.clone(),
-    //         actions.len(),
-    //         cx,
-    //         move |_, range, items, cx| {
-    //             let start_ix = range.start;
-    //             for (ix, action) in actions[range].iter().enumerate() {
-    //                 let item_ix = start_ix + ix;
-    //                 items.push(
-    //                     MouseEventHandler::new::<ActionTag, _>(item_ix, cx, |state, _| {
-    //                         let item_style = if item_ix == selected_item {
-    //                             style.autocomplete.selected_item
-    //                         } else if state.hovered() {
-    //                             style.autocomplete.hovered_item
-    //                         } else {
-    //                             style.autocomplete.item
-    //                         };
-
-    //                         Text::new(action.lsp_action.title.clone(), style.text.clone())
-    //                             .with_soft_wrap(false)
-    //                             .contained()
-    //                             .with_style(item_style)
-    //                     })
-    //                     .with_cursor_style(CursorStyle::PointingHand)
-    //                     .on_down(MouseButton::Left, move |_, this, cx| {
-    //                         let workspace = this
-    //                             .workspace
-    //                             .as_ref()
-    //                             .and_then(|(workspace, _)| workspace.upgrade(cx));
-    //                         cx.window_context().defer(move |cx| {
-    //                             if let Some(workspace) = workspace {
-    //                                 workspace.update(cx, |workspace, cx| {
-    //                                     if let Some(task) = Editor::confirm_code_action(
-    //                                         workspace,
-    //                                         &ConfirmCodeAction {
-    //                                             item_ix: Some(item_ix),
-    //                                         },
-    //                                         cx,
-    //                                     ) {
-    //                                         task.detach_and_log_err(cx);
-    //                                     }
-    //                                 });
-    //                             }
-    //                         });
-    //                     })
-    //                     .into_any(),
-    //                 );
-    //             }
-    //         },
-    //     )
-    //     .with_width_from_item(
-    //         self.actions
-    //             .iter()
-    //             .enumerate()
-    //             .max_by_key(|(_, action)| action.lsp_action.title.chars().count())
-    //             .map(|(ix, _)| ix),
-    //     )
-    //     .contained()
-    //     .with_style(container_style)
-    //     .into_any();
-
-    //     if self.deployed_from_indicator {
-    //         *cursor_position.column_mut() = 0;
-    //     }
+        if self.deployed_from_indicator {
+            *cursor_position.column_mut() = 0;
+        }
 
-    //     (cursor_position, element)
-    // }
+        (cursor_position, element)
+    }
 }
 
 pub struct CopilotState {
@@ -3660,7 +3613,7 @@ impl Editor {
                         completions: Arc::new(RwLock::new(completions.into())),
                         matches: Vec::new().into(),
                         selected_item: 0,
-                        list: Default::default(),
+                        scroll_handle: UniformListScrollHandle::new(),
                     };
                     menu.filter(query.as_deref(), cx.background_executor().clone())
                         .await;
@@ -3846,156 +3799,161 @@ impl Editor {
     //         }))
     //     }
 
-    //     pub fn toggle_code_actions(&mut self, action: &ToggleCodeActions, cx: &mut ViewContext<Self>) {
-    //         let mut context_menu = self.context_menu.write();
-    //         if matches!(context_menu.as_ref(), Some(ContextMenu::CodeActions(_))) {
-    //             *context_menu = None;
-    //             cx.notify();
-    //             return;
-    //         }
-    //         drop(context_menu);
-
-    //         let deployed_from_indicator = action.deployed_from_indicator;
-    //         let mut task = self.code_actions_task.take();
-    //         cx.spawn(|this, mut cx| async move {
-    //             while let Some(prev_task) = task {
-    //                 prev_task.await;
-    //                 task = this.update(&mut cx, |this, _| this.code_actions_task.take())?;
-    //             }
+    pub fn toggle_code_actions(&mut self, action: &ToggleCodeActions, cx: &mut ViewContext<Self>) {
+        let mut context_menu = self.context_menu.write();
+        if matches!(context_menu.as_ref(), Some(ContextMenu::CodeActions(_))) {
+            *context_menu = None;
+            cx.notify();
+            return;
+        }
+        drop(context_menu);
 
-    //             this.update(&mut cx, |this, cx| {
-    //                 if this.focused {
-    //                     if let Some((buffer, actions)) = this.available_code_actions.clone() {
-    //                         this.completion_tasks.clear();
-    //                         this.discard_copilot_suggestion(cx);
-    //                         *this.context_menu.write() =
-    //                             Some(ContextMenu::CodeActions(CodeActionsMenu {
-    //                                 buffer,
-    //                                 actions,
-    //                                 selected_item: Default::default(),
-    //                                 list: Default::default(),
-    //                                 deployed_from_indicator,
-    //                             }));
-    //                     }
-    //                 }
-    //             })?;
+        let deployed_from_indicator = action.deployed_from_indicator;
+        let mut task = self.code_actions_task.take();
+        cx.spawn(|this, mut cx| async move {
+            while let Some(prev_task) = task {
+                prev_task.await;
+                task = this.update(&mut cx, |this, _| this.code_actions_task.take())?;
+            }
 
-    //             Ok::<_, anyhow::Error>(())
-    //         })
-    //         .detach_and_log_err(cx);
-    //     }
+            this.update(&mut cx, |this, cx| {
+                if this.focus_handle.is_focused(cx) {
+                    if let Some((buffer, actions)) = this.available_code_actions.clone() {
+                        this.completion_tasks.clear();
+                        this.discard_copilot_suggestion(cx);
+                        *this.context_menu.write() =
+                            Some(ContextMenu::CodeActions(CodeActionsMenu {
+                                buffer,
+                                actions,
+                                selected_item: Default::default(),
+                                scroll_handle: UniformListScrollHandle::default(),
+                                deployed_from_indicator,
+                            }));
+                        cx.notify();
+                    }
+                }
+            })?;
 
-    //     pub fn confirm_code_action(
-    //         workspace: &mut Workspace,
-    //         action: &ConfirmCodeAction,
-    //         cx: &mut ViewContext<Workspace>,
-    //     ) -> Option<Task<Result<()>>> {
-    //         let editor = workspace.active_item(cx)?.act_as::<Editor>(cx)?;
-    //         let actions_menu = if let ContextMenu::CodeActions(menu) =
-    //             editor.update(cx, |editor, cx| editor.hide_context_menu(cx))?
-    //         {
-    //             menu
-    //         } else {
-    //             return None;
-    //         };
-    //         let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
-    //         let action = actions_menu.actions.get(action_ix)?.clone();
-    //         let title = action.lsp_action.title.clone();
-    //         let buffer = actions_menu.buffer;
+            Ok::<_, anyhow::Error>(())
+        })
+        .detach_and_log_err(cx);
+    }
 
-    //         let apply_code_actions = workspace.project().clone().update(cx, |project, cx| {
-    //             project.apply_code_action(buffer, action, true, cx)
-    //         });
-    //         let editor = editor.downgrade();
-    //         Some(cx.spawn(|workspace, cx| async move {
-    //             let project_transaction = apply_code_actions.await?;
-    //             Self::open_project_transaction(&editor, workspace, project_transaction, title, cx).await
-    //         }))
-    //     }
+    pub fn confirm_code_action(
+        &mut self,
+        action: &ConfirmCodeAction,
+        cx: &mut ViewContext<Self>,
+    ) -> Option<Task<Result<()>>> {
+        let actions_menu = if let ContextMenu::CodeActions(menu) = self.hide_context_menu(cx)? {
+            menu
+        } else {
+            return None;
+        };
+        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
+        let action = actions_menu.actions.get(action_ix)?.clone();
+        let title = action.lsp_action.title.clone();
+        let buffer = actions_menu.buffer;
+        let workspace = self.workspace()?;
 
-    //     async fn open_project_transaction(
-    //         this: &WeakViewHandle<Editor
-    //         workspace: WeakViewHandle<Workspace
-    //         transaction: ProjectTransaction,
-    //         title: String,
-    //         mut cx: AsyncAppContext,
-    //     ) -> Result<()> {
-    //         let replica_id = this.read_with(&cx, |this, cx| this.replica_id(cx))?;
-
-    //         let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
-    //         entries.sort_unstable_by_key(|(buffer, _)| {
-    //             buffer.read_with(&cx, |buffer, _| buffer.file().map(|f| f.path().clone()))
-    //         });
+        let apply_code_actions = workspace
+            .read(cx)
+            .project()
+            .clone()
+            .update(cx, |project, cx| {
+                project.apply_code_action(buffer, action, true, cx)
+            });
+        let workspace = workspace.downgrade();
+        Some(cx.spawn(|editor, cx| async move {
+            let project_transaction = apply_code_actions.await?;
+            Self::open_project_transaction(&editor, workspace, project_transaction, title, cx).await
+        }))
+    }
 
-    //         // If the project transaction's edits are all contained within this editor, then
-    //         // avoid opening a new editor to display them.
+    async fn open_project_transaction(
+        this: &WeakView<Editor>,
+        workspace: WeakView<Workspace>,
+        transaction: ProjectTransaction,
+        title: String,
+        mut cx: AsyncWindowContext,
+    ) -> Result<()> {
+        let replica_id = this.update(&mut cx, |this, cx| this.replica_id(cx))?;
 
-    //         if let Some((buffer, transaction)) = entries.first() {
-    //             if entries.len() == 1 {
-    //                 let excerpt = this.read_with(&cx, |editor, cx| {
-    //                     editor
-    //                         .buffer()
-    //                         .read(cx)
-    //                         .excerpt_containing(editor.selections.newest_anchor().head(), cx)
-    //                 })?;
-    //                 if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
-    //                     if excerpted_buffer == *buffer {
-    //                         let all_edits_within_excerpt = buffer.read_with(&cx, |buffer, _| {
-    //                             let excerpt_range = excerpt_range.to_offset(buffer);
-    //                             buffer
-    //                                 .edited_ranges_for_transaction::<usize>(transaction)
-    //                                 .all(|range| {
-    //                                     excerpt_range.start <= range.start
-    //                                         && excerpt_range.end >= range.end
-    //                                 })
-    //                         });
-
-    //                         if all_edits_within_excerpt {
-    //                             return Ok(());
-    //                         }
-    //                     }
-    //                 }
-    //             }
-    //         } else {
-    //             return Ok(());
-    //         }
+        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
+        cx.update(|_, cx| {
+            entries.sort_unstable_by_key(|(buffer, _)| {
+                buffer.read(cx).file().map(|f| f.path().clone())
+            });
+        })?;
+
+        // If the project transaction's edits are all contained within this editor, then
+        // avoid opening a new editor to display them.
+
+        if let Some((buffer, transaction)) = entries.first() {
+            if entries.len() == 1 {
+                let excerpt = this.update(&mut cx, |editor, cx| {
+                    editor
+                        .buffer()
+                        .read(cx)
+                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
+                })?;
+                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
+                    if excerpted_buffer == *buffer {
+                        let all_edits_within_excerpt = buffer.read_with(&cx, |buffer, _| {
+                            let excerpt_range = excerpt_range.to_offset(buffer);
+                            buffer
+                                .edited_ranges_for_transaction::<usize>(transaction)
+                                .all(|range| {
+                                    excerpt_range.start <= range.start
+                                        && excerpt_range.end >= range.end
+                                })
+                        })?;
 
-    //         let mut ranges_to_highlight = Vec::new();
-    //         let excerpt_buffer = cx.build_model(|cx| {
-    //             let mut multibuffer = MultiBuffer::new(replica_id).with_title(title);
-    //             for (buffer_handle, transaction) in &entries {
-    //                 let buffer = buffer_handle.read(cx);
-    //                 ranges_to_highlight.extend(
-    //                     multibuffer.push_excerpts_with_context_lines(
-    //                         buffer_handle.clone(),
-    //                         buffer
-    //                             .edited_ranges_for_transaction::<usize>(transaction)
-    //                             .collect(),
-    //                         1,
-    //                         cx,
-    //                     ),
-    //                 );
-    //             }
-    //             multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
-    //             multibuffer
-    //         });
+                        if all_edits_within_excerpt {
+                            return Ok(());
+                        }
+                    }
+                }
+            }
+        } else {
+            return Ok(());
+        }
 
-    //         workspace.update(&mut cx, |workspace, cx| {
-    //             let project = workspace.project().clone();
-    //             let editor =
-    //                 cx.add_view(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), cx));
-    //             workspace.add_item(Box::new(editor.clone()), cx);
-    //             editor.update(cx, |editor, cx| {
-    //                 editor.highlight_background::<Self>(
-    //                     ranges_to_highlight,
-    //                     |theme| theme.editor.highlighted_line_background,
-    //                     cx,
-    //                 );
-    //             });
-    //         })?;
+        let mut ranges_to_highlight = Vec::new();
+        let excerpt_buffer = cx.build_model(|cx| {
+            let mut multibuffer = MultiBuffer::new(replica_id).with_title(title);
+            for (buffer_handle, transaction) in &entries {
+                let buffer = buffer_handle.read(cx);
+                ranges_to_highlight.extend(
+                    multibuffer.push_excerpts_with_context_lines(
+                        buffer_handle.clone(),
+                        buffer
+                            .edited_ranges_for_transaction::<usize>(transaction)
+                            .collect(),
+                        1,
+                        cx,
+                    ),
+                );
+            }
+            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
+            multibuffer
+        })?;
+
+        workspace.update(&mut cx, |workspace, cx| {
+            let project = workspace.project().clone();
+            let editor =
+                cx.build_view(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), cx));
+            workspace.add_item(Box::new(editor.clone()), cx);
+            editor.update(cx, |editor, cx| {
+                editor.highlight_background::<Self>(
+                    ranges_to_highlight,
+                    |theme| theme.editor_highlighted_line_background,
+                    cx,
+                );
+            });
+        })?;
 
-    //         Ok(())
-    //     }
+        Ok(())
+    }
 
     fn refresh_code_actions(&mut self, cx: &mut ViewContext<Self>) -> Option<()> {
         let project = self.project.clone()?;
@@ -4390,41 +4348,29 @@ impl Editor {
         self.discard_copilot_suggestion(cx);
     }
 
-    //     pub fn render_code_actions_indicator(
-    //         &self,
-    //         style: &EditorStyle,
-    //         is_active: bool,
-    //         cx: &mut ViewContext<Self>,
-    //     ) -> Option<AnyElement<Self>> {
-    //         if self.available_code_actions.is_some() {
-    //             enum CodeActions {}
-    //             Some(
-    //                 MouseEventHandler::new::<CodeActions, _>(0, cx, |state, _| {
-    //                     Svg::new("icons/bolt.svg").with_color(
-    //                         style
-    //                             .code_actions
-    //                             .indicator
-    //                             .in_state(is_active)
-    //                             .style_for(state)
-    //                             .color,
-    //                     )
-    //                 })
-    //                 .with_cursor_style(CursorStyle::PointingHand)
-    //                 .with_padding(Padding::uniform(3.))
-    //                 .on_down(MouseButton::Left, |_, this, cx| {
-    //                     this.toggle_code_actions(
-    //                         &ToggleCodeActions {
-    //                             deployed_from_indicator: true,
-    //                         },
-    //                         cx,
-    //                     );
-    //                 })
-    //                 .into_any(),
-    //             )
-    //         } else {
-    //             None
-    //         }
-    //     }
+    pub fn render_code_actions_indicator(
+        &self,
+        style: &EditorStyle,
+        is_active: bool,
+        cx: &mut ViewContext<Self>,
+    ) -> Option<AnyElement<Self>> {
+        if self.available_code_actions.is_some() {
+            Some(
+                IconButton::new("code_actions_indicator", ui::Icon::Bolt)
+                    .on_click(|editor: &mut Editor, cx| {
+                        editor.toggle_code_actions(
+                            &ToggleCodeActions {
+                                deployed_from_indicator: true,
+                            },
+                            cx,
+                        );
+                    })
+                    .render(),
+            )
+        } else {
+            None
+        }
+    }
 
     //     pub fn render_fold_indicators(
     //         &self,
@@ -4491,29 +4437,27 @@ impl Editor {
     //     }
 
     pub fn context_menu_visible(&self) -> bool {
-        false
-        // todo!("context menu")
-        // self.context_menu
-        //     .read()
-        //     .as_ref()
-        //     .map_or(false, |menu| menu.visible())
+        self.context_menu
+            .read()
+            .as_ref()
+            .map_or(false, |menu| menu.visible())
     }
 
-    //     pub fn render_context_menu(
-    //         &self,
-    //         cursor_position: DisplayPoint,
-    //         style: EditorStyle,
-    //         cx: &mut ViewContext<Editor>,
-    //     ) -> Option<(DisplayPoint, AnyElement<Editor>)> {
-    //         self.context_menu.read().as_ref().map(|menu| {
-    //             menu.render(
-    //                 cursor_position,
-    //                 style,
-    //                 self.workspace.as_ref().map(|(w, _)| w.clone()),
-    //                 cx,
-    //             )
-    //         })
-    //     }
+    pub fn render_context_menu(
+        &self,
+        cursor_position: DisplayPoint,
+        style: &EditorStyle,
+        cx: &mut ViewContext<Editor>,
+    ) -> Option<(DisplayPoint, AnyElement<Editor>)> {
+        self.context_menu.read().as_ref().map(|menu| {
+            menu.render(
+                cursor_position,
+                style,
+                self.workspace.as_ref().map(|(w, _)| w.clone()),
+                cx,
+            )
+        })
+    }
 
     fn hide_context_menu(&mut self, cx: &mut ViewContext<Self>) -> Option<ContextMenu> {
         cx.notify();
@@ -5954,29 +5898,29 @@ impl Editor {
         });
     }
 
-    //     pub fn context_menu_first(&mut self, _: &ContextMenuFirst, cx: &mut ViewContext<Self>) {
-    //         if let Some(context_menu) = self.context_menu.write().as_mut() {
-    //             context_menu.select_first(self.project.as_ref(), cx);
-    //         }
-    //     }
+    pub fn context_menu_first(&mut self, _: &ContextMenuFirst, cx: &mut ViewContext<Self>) {
+        if let Some(context_menu) = self.context_menu.write().as_mut() {
+            context_menu.select_first(self.project.as_ref(), cx);
+        }
+    }
 
-    //     pub fn context_menu_prev(&mut self, _: &ContextMenuPrev, cx: &mut ViewContext<Self>) {
-    //         if let Some(context_menu) = self.context_menu.write().as_mut() {
-    //             context_menu.select_prev(self.project.as_ref(), cx);
-    //         }
-    //     }
+    pub fn context_menu_prev(&mut self, _: &ContextMenuPrev, cx: &mut ViewContext<Self>) {
+        if let Some(context_menu) = self.context_menu.write().as_mut() {
+            context_menu.select_prev(self.project.as_ref(), cx);
+        }
+    }
 
-    //     pub fn context_menu_next(&mut self, _: &ContextMenuNext, cx: &mut ViewContext<Self>) {
-    //         if let Some(context_menu) = self.context_menu.write().as_mut() {
-    //             context_menu.select_next(self.project.as_ref(), cx);
-    //         }
-    //     }
+    pub fn context_menu_next(&mut self, _: &ContextMenuNext, cx: &mut ViewContext<Self>) {
+        if let Some(context_menu) = self.context_menu.write().as_mut() {
+            context_menu.select_next(self.project.as_ref(), cx);
+        }
+    }
 
-    //     pub fn context_menu_last(&mut self, _: &ContextMenuLast, cx: &mut ViewContext<Self>) {
-    //         if let Some(context_menu) = self.context_menu.write().as_mut() {
-    //             context_menu.select_last(self.project.as_ref(), cx);
-    //         }
-    //     }
+    pub fn context_menu_last(&mut self, _: &ContextMenuLast, cx: &mut ViewContext<Self>) {
+        if let Some(context_menu) = self.context_menu.write().as_mut() {
+            context_menu.select_last(self.project.as_ref(), cx);
+        }
+    }
 
     pub fn move_to_previous_word_start(
         &mut self,

crates/editor2/src/editor_settings.rs πŸ”—

@@ -11,6 +11,15 @@ pub struct EditorSettings {
     pub use_on_type_format: bool,
     pub scrollbar: Scrollbar,
     pub relative_line_numbers: bool,
+    pub seed_search_query_from_cursor: SeedQuerySetting,
+}
+
+#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
+#[serde(rename_all = "snake_case")]
+pub enum SeedQuerySetting {
+    Always,
+    Selection,
+    Never,
 }
 
 #[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
@@ -38,6 +47,7 @@ pub struct EditorSettingsContent {
     pub use_on_type_format: Option<bool>,
     pub scrollbar: Option<ScrollbarContent>,
     pub relative_line_numbers: Option<bool>,
+    pub seed_search_query_from_cursor: Option<SeedQuerySetting>,
 }
 
 #[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]

crates/editor2/src/element.rs πŸ”—

@@ -15,7 +15,7 @@ use crate::{
 use anyhow::Result;
 use collections::{BTreeMap, HashMap};
 use gpui::{
-    black, hsla, point, px, relative, size, transparent_black, Action, AnyElement,
+    black, hsla, point, px, relative, size, transparent_black, Action, AnyElement, AvailableSpace,
     BorrowAppContext, BorrowWindow, Bounds, ContentMask, Corners, DispatchContext, DispatchPhase,
     Edges, Element, ElementId, ElementInputHandler, Entity, FocusHandle, GlobalElementId, Hsla,
     InputHandler, KeyDownEvent, KeyListener, KeyMatch, Line, LineLayout, Modifiers, MouseButton,
@@ -447,7 +447,7 @@ impl EditorElement {
     fn paint_gutter(
         &mut self,
         bounds: Bounds<Pixels>,
-        layout: &LayoutState,
+        layout: &mut LayoutState,
         editor: &mut Editor,
         cx: &mut ViewContext<Editor>,
     ) {
@@ -495,14 +495,21 @@ impl EditorElement {
         //     }
         // }
 
-        // todo!("code actions indicator")
-        // if let Some((row, indicator)) = layout.code_actions_indicator.as_mut() {
-        //     let mut x = 0.;
-        //     let mut y = *row as f32 * line_height - scroll_top;
-        //     x += ((layout.gutter_padding + layout.gutter_margin) - indicator.size().x) / 2.;
-        //     y += (line_height - indicator.size().y) / 2.;
-        //     indicator.paint(bounds.origin + point(x, y), visible_bounds, editor, cx);
-        // }
+        if let Some(indicator) = layout.code_actions_indicator.as_mut() {
+            let available_space = size(
+                AvailableSpace::MinContent,
+                AvailableSpace::Definite(line_height),
+            );
+            let indicator_size = indicator.element.measure(available_space, editor, cx);
+            let mut x = Pixels::ZERO;
+            let mut y = indicator.row as f32 * line_height - scroll_top;
+            // Center indicator.
+            x += ((layout.gutter_padding + layout.gutter_margin) - indicator_size.width) / 2.;
+            y += (line_height - indicator_size.height) / 2.;
+            indicator
+                .element
+                .draw(bounds.origin + point(x, y), available_space, editor, cx);
+        }
     }
 
     fn paint_diff_hunks(
@@ -596,7 +603,7 @@ impl EditorElement {
     fn paint_text(
         &mut self,
         bounds: Bounds<Pixels>,
-        layout: &LayoutState,
+        layout: &mut LayoutState,
         editor: &mut Editor,
         cx: &mut ViewContext<Editor>,
     ) {
@@ -787,48 +794,46 @@ impl EditorElement {
                 )
             }
 
-            cx.stack(0, |cx| {
+            cx.with_z_index(0, |cx| {
                 for cursor in cursors {
                     cursor.paint(content_origin, cx);
                 }
             });
-            // cx.scene().push_layer(Some(bounds));
-
-            // cx.scene().pop_layer();
 
-            // if let Some((position, context_menu)) = layout.context_menu.as_mut() {
-            //     cx.scene().push_stacking_context(None, None);
-            //     let cursor_row_layout =
-            //         &layout.position_map.line_layouts[(position.row() - start_row) as usize].line;
-            //     let x = cursor_row_layout.x_for_index(position.column() as usize) - scroll_left;
-            //     let y = (position.row() + 1) as f32 * layout.position_map.line_height - scroll_top;
-            //     let mut list_origin = content_origin + point(x, y);
-            //     let list_width = context_menu.size().x;
-            //     let list_height = context_menu.size().y;
-
-            //     // Snap the right edge of the list to the right edge of the window if
-            //     // its horizontal bounds overflow.
-            //     if list_origin.x + list_width > cx.window_size().x {
-            //         list_origin.set_x((cx.window_size().x - list_width).max(0.));
-            //     }
-
-            //     if list_origin.y + list_height > bounds.max_y {
-            //         list_origin
-            //             .set_y(list_origin.y - layout.position_map.line_height - list_height);
-            //     }
+            if let Some((position, context_menu)) = layout.context_menu.as_mut() {
+                cx.with_z_index(1, |cx| {
+                    let line_height = self.style.text.line_height_in_pixels(cx.rem_size());
+                    let available_space = size(
+                        AvailableSpace::MinContent,
+                        AvailableSpace::Definite(
+                            (12. * line_height).min((bounds.size.height - line_height) / 2.),
+                        ),
+                    );
+                    let context_menu_size = context_menu.measure(available_space, editor, cx);
+
+                    let cursor_row_layout = &layout.position_map.line_layouts
+                        [(position.row() - start_row) as usize]
+                        .line;
+                    let x = cursor_row_layout.x_for_index(position.column() as usize) - scroll_left;
+                    let y =
+                        (position.row() + 1) as f32 * layout.position_map.line_height - scroll_top;
+                    let mut list_origin = content_origin + point(x, y);
+                    let list_width = context_menu_size.width;
+                    let list_height = context_menu_size.height;
+
+                    // Snap the right edge of the list to the right edge of the window if
+                    // its horizontal bounds overflow.
+                    if list_origin.x + list_width > cx.viewport_size().width {
+                        list_origin.x = (cx.viewport_size().width - list_width).max(Pixels::ZERO);
+                    }
 
-            //     context_menu.paint(
-            //         list_origin,
-            //         Bounds::<Pixels>::from_points(
-            //             gpui::Point::<Pixels>::zero(),
-            //             point(f32::MAX, f32::MAX),
-            //         ), // Let content bleed outside of editor
-            //         editor,
-            //         cx,
-            //     );
+                    if list_origin.y + list_height > bounds.lower_right().y {
+                        list_origin.y -= layout.position_map.line_height - list_height;
+                    }
 
-            //     cx.scene().pop_stacking_context();
-            // }
+                    context_menu.draw(list_origin, available_space, editor, cx);
+                })
+            }
 
             // if let Some((position, hover_popovers)) = layout.hover_popovers.as_mut() {
             //     cx.scene().push_stacking_context(None, None);
@@ -1774,26 +1779,28 @@ impl EditorElement {
             snapshot = editor.snapshot(cx);
         }
 
-        // todo!("context menu")
-        // let mut context_menu = None;
-        // let mut code_actions_indicator = None;
-        // if let Some(newest_selection_head) = newest_selection_head {
-        //     if (start_row..end_row).contains(&newest_selection_head.row()) {
-        //         if editor.context_menu_visible() {
-        //             context_menu =
-        //                 editor.render_context_menu(newest_selection_head, style.clone(), cx);
-        //         }
+        let mut context_menu = None;
+        let mut code_actions_indicator = None;
+        if let Some(newest_selection_head) = newest_selection_head {
+            if (start_row..end_row).contains(&newest_selection_head.row()) {
+                if editor.context_menu_visible() {
+                    context_menu =
+                        editor.render_context_menu(newest_selection_head, &self.style, cx);
+                }
 
-        //         let active = matches!(
-        //             editor.context_menu.read().as_ref(),
-        //             Some(crate::ContextMenu::CodeActions(_))
-        //         );
+                let active = matches!(
+                    editor.context_menu.read().as_ref(),
+                    Some(crate::ContextMenu::CodeActions(_))
+                );
 
-        //         code_actions_indicator = editor
-        //             .render_code_actions_indicator(&style, active, cx)
-        //             .map(|indicator| (newest_selection_head.row(), indicator));
-        //     }
-        // }
+                code_actions_indicator = editor
+                    .render_code_actions_indicator(&style, active, cx)
+                    .map(|element| CodeActionsIndicator {
+                        row: newest_selection_head.row(),
+                        element,
+                    });
+            }
+        }
 
         let visible_rows = start_row..start_row + line_layouts.len() as u32;
         // todo!("hover")
@@ -1831,18 +1838,6 @@ impl EditorElement {
         //     );
         // }
 
-        // todo!("code actions")
-        // if let Some((_, indicator)) = code_actions_indicator.as_mut() {
-        //     indicator.layout(
-        //         SizeConstraint::strict_along(
-        //             Axis::Vertical,
-        //             line_height * style.code_actions.vertical_scale,
-        //         ),
-        //         editor,
-        //         cx,
-        //     );
-        // }
-
         // todo!("fold indicators")
         // for fold_indicator in fold_indicators.iter_mut() {
         //     if let Some(indicator) = fold_indicator.as_mut() {
@@ -1941,8 +1936,8 @@ impl EditorElement {
             display_hunks,
             // blocks,
             selections,
-            // context_menu,
-            // code_actions_indicator,
+            context_menu,
+            code_actions_indicator,
             // fold_indicators,
             tab_invisible,
             space_invisible,
@@ -2493,7 +2488,7 @@ impl Element<Editor> for EditorElement {
         element_state: &mut Self::ElementState,
         cx: &mut gpui::ViewContext<Editor>,
     ) {
-        let layout = self.compute_layout(editor, cx, bounds);
+        let mut layout = self.compute_layout(editor, cx, bounds);
         let gutter_bounds = Bounds {
             origin: bounds.origin,
             size: layout.gutter_size,
@@ -2503,21 +2498,24 @@ impl Element<Editor> for EditorElement {
             size: layout.text_size,
         };
 
-        cx.with_content_mask(ContentMask { bounds }, |cx| {
-            self.paint_mouse_listeners(
-                bounds,
-                gutter_bounds,
-                text_bounds,
-                &layout.position_map,
-                cx,
-            );
-            self.paint_background(gutter_bounds, text_bounds, &layout, cx);
-            if layout.gutter_size.width > Pixels::ZERO {
-                self.paint_gutter(gutter_bounds, &layout, editor, cx);
-            }
-            self.paint_text(text_bounds, &layout, editor, cx);
-            let input_handler = ElementInputHandler::new(bounds, cx);
-            cx.handle_input(&editor.focus_handle, input_handler);
+        // We call with_z_index to establish a new stacking context.
+        cx.with_z_index(0, |cx| {
+            cx.with_content_mask(ContentMask { bounds }, |cx| {
+                self.paint_mouse_listeners(
+                    bounds,
+                    gutter_bounds,
+                    text_bounds,
+                    &layout.position_map,
+                    cx,
+                );
+                self.paint_background(gutter_bounds, text_bounds, &layout, cx);
+                if layout.gutter_size.width > Pixels::ZERO {
+                    self.paint_gutter(gutter_bounds, &mut layout, editor, cx);
+                }
+                self.paint_text(text_bounds, &mut layout, editor, cx);
+                let input_handler = ElementInputHandler::new(bounds, cx);
+                cx.handle_input(&editor.focus_handle, input_handler);
+            });
         });
     }
 }
@@ -3143,14 +3141,19 @@ pub struct LayoutState {
     show_scrollbars: bool,
     is_singleton: bool,
     max_row: u32,
-    // context_menu: Option<(DisplayPoint, AnyElement<Editor>)>,
-    // code_actions_indicator: Option<(u32, AnyElement<Editor>)>,
+    context_menu: Option<(DisplayPoint, AnyElement<Editor>)>,
+    code_actions_indicator: Option<CodeActionsIndicator>,
     // hover_popovers: Option<(DisplayPoint, Vec<AnyElement<Editor>>)>,
     // fold_indicators: Vec<Option<AnyElement<Editor>>>,
     tab_invisible: Line,
     space_invisible: Line,
 }
 
+struct CodeActionsIndicator {
+    row: u32,
+    element: AnyElement<Editor>,
+}
+
 struct PositionMap {
     size: Size<Pixels>,
     line_height: Pixels,
@@ -4123,7 +4126,7 @@ fn build_key_listeners(
         build_action_listener(Editor::unfold_at),
         build_action_listener(Editor::fold_selected_ranges),
         build_action_listener(Editor::show_completions),
-        // build_action_listener(Editor::toggle_code_actions), todo!()
+        build_action_listener(Editor::toggle_code_actions),
         // build_action_listener(Editor::open_excerpts), todo!()
         build_action_listener(Editor::toggle_soft_wrap),
         build_action_listener(Editor::toggle_inlay_hints),
@@ -4139,13 +4142,21 @@ fn build_key_listeners(
         build_action_listener(Editor::restart_language_server),
         build_action_listener(Editor::show_character_palette),
         // build_action_listener(Editor::confirm_completion), todo!()
-        // build_action_listener(Editor::confirm_code_action), todo!()
+        build_action_listener(|editor, action, cx| {
+            editor
+                .confirm_code_action(action, cx)
+                .map(|task| task.detach_and_log_err(cx));
+        }),
         // build_action_listener(Editor::rename), todo!()
         // build_action_listener(Editor::confirm_rename), todo!()
         // build_action_listener(Editor::find_all_references), todo!()
         build_action_listener(Editor::next_copilot_suggestion),
         build_action_listener(Editor::previous_copilot_suggestion),
         build_action_listener(Editor::copilot_suggest),
+        build_action_listener(Editor::context_menu_first),
+        build_action_listener(Editor::context_menu_prev),
+        build_action_listener(Editor::context_menu_next),
+        build_action_listener(Editor::context_menu_last),
         build_key_listener(
             move |editor, key_down: &KeyDownEvent, dispatch_context, phase, cx| {
                 if phase == DispatchPhase::Bubble {

crates/editor2/src/inlay_hint_cache.rs πŸ”—

@@ -553,18 +553,17 @@ impl InlayHintCache {
                             let mut resolved_hint =
                                 resolved_hint_task.await.context("hint resolve task")?;
                             editor.update(&mut cx, |editor, _| {
-                                todo!()
-                                // if let Some(excerpt_hints) =
-                                //     editor.inlay_hint_cache.hints.get(&excerpt_id)
-                                // {
-                                //     let mut guard = excerpt_hints.write();
-                                //     if let Some(cached_hint) = guard.hints_by_id.get_mut(&id) {
-                                //         if cached_hint.resolve_state == ResolveState::Resolving {
-                                //             resolved_hint.resolve_state = ResolveState::Resolved;
-                                //             *cached_hint = resolved_hint;
-                                //         }
-                                //     }
-                                // }
+                                if let Some(excerpt_hints) =
+                                    editor.inlay_hint_cache.hints.get(&excerpt_id)
+                                {
+                                    let mut guard = excerpt_hints.write();
+                                    if let Some(cached_hint) = guard.hints_by_id.get_mut(&id) {
+                                        if cached_hint.resolve_state == ResolveState::Resolving {
+                                            resolved_hint.resolve_state = ResolveState::Resolved;
+                                            *cached_hint = resolved_hint;
+                                        }
+                                    }
+                                }
                             })?;
                         }
 
@@ -585,91 +584,89 @@ fn spawn_new_update_tasks(
     update_cache_version: usize,
     cx: &mut ViewContext<'_, Editor>,
 ) {
-    todo!("old version below");
+    let visible_hints = Arc::new(editor.visible_inlay_hints(cx));
+    for (excerpt_id, (excerpt_buffer, new_task_buffer_version, excerpt_visible_range)) in
+        excerpts_to_query
+    {
+        if excerpt_visible_range.is_empty() {
+            continue;
+        }
+        let buffer = excerpt_buffer.read(cx);
+        let buffer_id = buffer.remote_id();
+        let buffer_snapshot = buffer.snapshot();
+        if buffer_snapshot
+            .version()
+            .changed_since(&new_task_buffer_version)
+        {
+            continue;
+        }
+
+        let cached_excerpt_hints = editor.inlay_hint_cache.hints.get(&excerpt_id).cloned();
+        if let Some(cached_excerpt_hints) = &cached_excerpt_hints {
+            let cached_excerpt_hints = cached_excerpt_hints.read();
+            let cached_buffer_version = &cached_excerpt_hints.buffer_version;
+            if cached_excerpt_hints.version > update_cache_version
+                || cached_buffer_version.changed_since(&new_task_buffer_version)
+            {
+                continue;
+            }
+        };
+
+        let (multi_buffer_snapshot, Some(query_ranges)) =
+            editor.buffer.update(cx, |multi_buffer, cx| {
+                (
+                    multi_buffer.snapshot(cx),
+                    determine_query_ranges(
+                        multi_buffer,
+                        excerpt_id,
+                        &excerpt_buffer,
+                        excerpt_visible_range,
+                        cx,
+                    ),
+                )
+            })
+        else {
+            return;
+        };
+        let query = ExcerptQuery {
+            buffer_id,
+            excerpt_id,
+            cache_version: update_cache_version,
+            invalidate,
+            reason,
+        };
+
+        let new_update_task = |query_ranges| {
+            new_update_task(
+                query,
+                query_ranges,
+                multi_buffer_snapshot,
+                buffer_snapshot.clone(),
+                Arc::clone(&visible_hints),
+                cached_excerpt_hints,
+                Arc::clone(&editor.inlay_hint_cache.lsp_request_limiter),
+                cx,
+            )
+        };
+
+        match editor.inlay_hint_cache.update_tasks.entry(excerpt_id) {
+            hash_map::Entry::Occupied(mut o) => {
+                o.get_mut().update_cached_tasks(
+                    &buffer_snapshot,
+                    query_ranges,
+                    invalidate,
+                    new_update_task,
+                );
+            }
+            hash_map::Entry::Vacant(v) => {
+                v.insert(TasksForRanges::new(
+                    query_ranges.clone(),
+                    new_update_task(query_ranges),
+                ));
+            }
+        }
+    }
 }
-//     let visible_hints = Arc::new(editor.visible_inlay_hints(cx));
-//     for (excerpt_id, (excerpt_buffer, new_task_buffer_version, excerpt_visible_range)) in
-//         excerpts_to_query
-//     {
-//         if excerpt_visible_range.is_empty() {
-//             continue;
-//         }
-//         let buffer = excerpt_buffer.read(cx);
-//         let buffer_id = buffer.remote_id();
-//         let buffer_snapshot = buffer.snapshot();
-//         if buffer_snapshot
-//             .version()
-//             .changed_since(&new_task_buffer_version)
-//         {
-//             continue;
-//         }
-
-//         let cached_excerpt_hints = editor.inlay_hint_cache.hints.get(&excerpt_id).cloned();
-//         if let Some(cached_excerpt_hints) = &cached_excerpt_hints {
-//             let cached_excerpt_hints = cached_excerpt_hints.read();
-//             let cached_buffer_version = &cached_excerpt_hints.buffer_version;
-//             if cached_excerpt_hints.version > update_cache_version
-//                 || cached_buffer_version.changed_since(&new_task_buffer_version)
-//             {
-//                 continue;
-//             }
-//         };
-
-//         let (multi_buffer_snapshot, Some(query_ranges)) =
-//             editor.buffer.update(cx, |multi_buffer, cx| {
-//                 (
-//                     multi_buffer.snapshot(cx),
-//                     determine_query_ranges(
-//                         multi_buffer,
-//                         excerpt_id,
-//                         &excerpt_buffer,
-//                         excerpt_visible_range,
-//                         cx,
-//                     ),
-//                 )
-//             })
-//         else {
-//             return;
-//         };
-//         let query = ExcerptQuery {
-//             buffer_id,
-//             excerpt_id,
-//             cache_version: update_cache_version,
-//             invalidate,
-//             reason,
-//         };
-
-//         let new_update_task = |query_ranges| {
-//             new_update_task(
-//                 query,
-//                 query_ranges,
-//                 multi_buffer_snapshot,
-//                 buffer_snapshot.clone(),
-//                 Arc::clone(&visible_hints),
-//                 cached_excerpt_hints,
-//                 Arc::clone(&editor.inlay_hint_cache.lsp_request_limiter),
-//                 cx,
-//             )
-//         };
-
-//         match editor.inlay_hint_cache.update_tasks.entry(excerpt_id) {
-//             hash_map::Entry::Occupied(mut o) => {
-//                 o.get_mut().update_cached_tasks(
-//                     &buffer_snapshot,
-//                     query_ranges,
-//                     invalidate,
-//                     new_update_task,
-//                 );
-//             }
-//             hash_map::Entry::Vacant(v) => {
-//                 v.insert(TasksForRanges::new(
-//                     query_ranges.clone(),
-//                     new_update_task(query_ranges),
-//                 ));
-//             }
-//         }
-//     }
-// }
 
 #[derive(Debug, Clone)]
 struct QueryRanges {
@@ -765,209 +762,208 @@ fn new_update_task(
     lsp_request_limiter: Arc<Semaphore>,
     cx: &mut ViewContext<'_, Editor>,
 ) -> Task<()> {
-    todo!()
-    // cx.spawn(|editor, mut cx| async move {
-    //     let closure_cx = cx.clone();
-    //     let fetch_and_update_hints = |invalidate, range| {
-    //         fetch_and_update_hints(
-    //             editor.clone(),
-    //             multi_buffer_snapshot.clone(),
-    //             buffer_snapshot.clone(),
-    //             Arc::clone(&visible_hints),
-    //             cached_excerpt_hints.as_ref().map(Arc::clone),
-    //             query,
-    //             invalidate,
-    //             range,
-    //             Arc::clone(&lsp_request_limiter),
-    //             closure_cx.clone(),
-    //         )
-    //     };
-    //     let visible_range_update_results = future::join_all(query_ranges.visible.into_iter().map(
-    //         |visible_range| async move {
-    //             (
-    //                 visible_range.clone(),
-    //                 fetch_and_update_hints(query.invalidate.should_invalidate(), visible_range)
-    //                     .await,
-    //             )
-    //         },
-    //     ))
-    //     .await;
-
-    //     let hint_delay = cx.background().timer(Duration::from_millis(
-    //         INVISIBLE_RANGES_HINTS_REQUEST_DELAY_MILLIS,
-    //     ));
-
-    //     let mut query_range_failed = |range: &Range<language::Anchor>, e: anyhow::Error| {
-    //         log::error!("inlay hint update task for range {range:?} failed: {e:#}");
-    //         editor
-    //             .update(&mut cx, |editor, _| {
-    //                 if let Some(task_ranges) = editor
-    //                     .inlay_hint_cache
-    //                     .update_tasks
-    //                     .get_mut(&query.excerpt_id)
-    //                 {
-    //                     task_ranges.invalidate_range(&buffer_snapshot, &range);
-    //                 }
-    //             })
-    //             .ok()
-    //     };
-
-    //     for (range, result) in visible_range_update_results {
-    //         if let Err(e) = result {
-    //             query_range_failed(&range, e);
-    //         }
-    //     }
-
-    //     hint_delay.await;
-    //     let invisible_range_update_results = future::join_all(
-    //         query_ranges
-    //             .before_visible
-    //             .into_iter()
-    //             .chain(query_ranges.after_visible.into_iter())
-    //             .map(|invisible_range| async move {
-    //                 (
-    //                     invisible_range.clone(),
-    //                     fetch_and_update_hints(false, invisible_range).await,
-    //                 )
-    //             }),
-    //     )
-    //     .await;
-    //     for (range, result) in invisible_range_update_results {
-    //         if let Err(e) = result {
-    //             query_range_failed(&range, e);
-    //         }
-    //     }
-    // })
+    cx.spawn(|editor, mut cx| async move {
+        let closure_cx = cx.clone();
+        let fetch_and_update_hints = |invalidate, range| {
+            fetch_and_update_hints(
+                editor.clone(),
+                multi_buffer_snapshot.clone(),
+                buffer_snapshot.clone(),
+                Arc::clone(&visible_hints),
+                cached_excerpt_hints.as_ref().map(Arc::clone),
+                query,
+                invalidate,
+                range,
+                Arc::clone(&lsp_request_limiter),
+                closure_cx.clone(),
+            )
+        };
+        let visible_range_update_results = future::join_all(query_ranges.visible.into_iter().map(
+            |visible_range| async move {
+                (
+                    visible_range.clone(),
+                    fetch_and_update_hints(query.invalidate.should_invalidate(), visible_range)
+                        .await,
+                )
+            },
+        ))
+        .await;
+
+        let hint_delay = cx.background_executor().timer(Duration::from_millis(
+            INVISIBLE_RANGES_HINTS_REQUEST_DELAY_MILLIS,
+        ));
+
+        let mut query_range_failed = |range: &Range<language::Anchor>, e: anyhow::Error| {
+            log::error!("inlay hint update task for range {range:?} failed: {e:#}");
+            editor
+                .update(&mut cx, |editor, _| {
+                    if let Some(task_ranges) = editor
+                        .inlay_hint_cache
+                        .update_tasks
+                        .get_mut(&query.excerpt_id)
+                    {
+                        task_ranges.invalidate_range(&buffer_snapshot, &range);
+                    }
+                })
+                .ok()
+        };
+
+        for (range, result) in visible_range_update_results {
+            if let Err(e) = result {
+                query_range_failed(&range, e);
+            }
+        }
+
+        hint_delay.await;
+        let invisible_range_update_results = future::join_all(
+            query_ranges
+                .before_visible
+                .into_iter()
+                .chain(query_ranges.after_visible.into_iter())
+                .map(|invisible_range| async move {
+                    (
+                        invisible_range.clone(),
+                        fetch_and_update_hints(false, invisible_range).await,
+                    )
+                }),
+        )
+        .await;
+        for (range, result) in invisible_range_update_results {
+            if let Err(e) = result {
+                query_range_failed(&range, e);
+            }
+        }
+    })
 }
 
-// async fn fetch_and_update_hints(
-//     editor: gpui::WeakView<Editor>,
-//     multi_buffer_snapshot: MultiBufferSnapshot,
-//     buffer_snapshot: BufferSnapshot,
-//     visible_hints: Arc<Vec<Inlay>>,
-//     cached_excerpt_hints: Option<Arc<RwLock<CachedExcerptHints>>>,
-//     query: ExcerptQuery,
-//     invalidate: bool,
-//     fetch_range: Range<language::Anchor>,
-//     lsp_request_limiter: Arc<Semaphore>,
-//     mut cx: gpui::AsyncAppContext,
-// ) -> anyhow::Result<()> {
-//     let (lsp_request_guard, got_throttled) = if query.invalidate.should_invalidate() {
-//         (None, false)
-//     } else {
-//         match lsp_request_limiter.try_acquire() {
-//             Some(guard) => (Some(guard), false),
-//             None => (Some(lsp_request_limiter.acquire().await), true),
-//         }
-//     };
-//     let fetch_range_to_log =
-//         fetch_range.start.to_point(&buffer_snapshot)..fetch_range.end.to_point(&buffer_snapshot);
-//     let inlay_hints_fetch_task = editor
-//         .update(&mut cx, |editor, cx| {
-//             if got_throttled {
-//                 let query_not_around_visible_range = match editor.excerpt_visible_offsets(None, cx).remove(&query.excerpt_id) {
-//                     Some((_, _, current_visible_range)) => {
-//                         let visible_offset_length = current_visible_range.len();
-//                         let double_visible_range = current_visible_range
-//                             .start
-//                             .saturating_sub(visible_offset_length)
-//                             ..current_visible_range
-//                                 .end
-//                                 .saturating_add(visible_offset_length)
-//                                 .min(buffer_snapshot.len());
-//                         !double_visible_range
-//                             .contains(&fetch_range.start.to_offset(&buffer_snapshot))
-//                             && !double_visible_range
-//                                 .contains(&fetch_range.end.to_offset(&buffer_snapshot))
-//                     },
-//                     None => true,
-//                 };
-//                 if query_not_around_visible_range {
-//                     log::trace!("Fetching inlay hints for range {fetch_range_to_log:?} got throttled and fell off the current visible range, skipping.");
-//                     if let Some(task_ranges) = editor
-//                         .inlay_hint_cache
-//                         .update_tasks
-//                         .get_mut(&query.excerpt_id)
-//                     {
-//                         task_ranges.invalidate_range(&buffer_snapshot, &fetch_range);
-//                     }
-//                     return None;
-//                 }
-//             }
-//             editor
-//                 .buffer()
-//                 .read(cx)
-//                 .buffer(query.buffer_id)
-//                 .and_then(|buffer| {
-//                     let project = editor.project.as_ref()?;
-//                     Some(project.update(cx, |project, cx| {
-//                         project.inlay_hints(buffer, fetch_range.clone(), cx)
-//                     }))
-//                 })
-//         })
-//         .ok()
-//         .flatten();
-//     let new_hints = match inlay_hints_fetch_task {
-//         Some(fetch_task) => {
-//             log::debug!(
-//                 "Fetching inlay hints for range {fetch_range_to_log:?}, reason: {query_reason}, invalidate: {invalidate}",
-//                 query_reason = query.reason,
-//             );
-//             log::trace!(
-//                 "Currently visible hints: {visible_hints:?}, cached hints present: {}",
-//                 cached_excerpt_hints.is_some(),
-//             );
-//             fetch_task.await.context("inlay hint fetch task")?
-//         }
-//         None => return Ok(()),
-//     };
-//     drop(lsp_request_guard);
-//     log::debug!(
-//         "Fetched {} hints for range {fetch_range_to_log:?}",
-//         new_hints.len()
-//     );
-//     log::trace!("Fetched hints: {new_hints:?}");
-
-//     let background_task_buffer_snapshot = buffer_snapshot.clone();
-//     let backround_fetch_range = fetch_range.clone();
-//     let new_update = cx
-//         .background()
-//         .spawn(async move {
-//             calculate_hint_updates(
-//                 query.excerpt_id,
-//                 invalidate,
-//                 backround_fetch_range,
-//                 new_hints,
-//                 &background_task_buffer_snapshot,
-//                 cached_excerpt_hints,
-//                 &visible_hints,
-//             )
-//         })
-//         .await;
-//     if let Some(new_update) = new_update {
-//         log::debug!(
-//             "Applying update for range {fetch_range_to_log:?}: remove from editor: {}, remove from cache: {}, add to cache: {}",
-//             new_update.remove_from_visible.len(),
-//             new_update.remove_from_cache.len(),
-//             new_update.add_to_cache.len()
-//         );
-//         log::trace!("New update: {new_update:?}");
-//         editor
-//             .update(&mut cx, |editor, cx| {
-//                 apply_hint_update(
-//                     editor,
-//                     new_update,
-//                     query,
-//                     invalidate,
-//                     buffer_snapshot,
-//                     multi_buffer_snapshot,
-//                     cx,
-//                 );
-//             })
-//             .ok();
-//     }
-//     Ok(())
-// }
+async fn fetch_and_update_hints(
+    editor: gpui::WeakView<Editor>,
+    multi_buffer_snapshot: MultiBufferSnapshot,
+    buffer_snapshot: BufferSnapshot,
+    visible_hints: Arc<Vec<Inlay>>,
+    cached_excerpt_hints: Option<Arc<RwLock<CachedExcerptHints>>>,
+    query: ExcerptQuery,
+    invalidate: bool,
+    fetch_range: Range<language::Anchor>,
+    lsp_request_limiter: Arc<Semaphore>,
+    mut cx: gpui::AsyncWindowContext,
+) -> anyhow::Result<()> {
+    let (lsp_request_guard, got_throttled) = if query.invalidate.should_invalidate() {
+        (None, false)
+    } else {
+        match lsp_request_limiter.try_acquire() {
+            Some(guard) => (Some(guard), false),
+            None => (Some(lsp_request_limiter.acquire().await), true),
+        }
+    };
+    let fetch_range_to_log =
+        fetch_range.start.to_point(&buffer_snapshot)..fetch_range.end.to_point(&buffer_snapshot);
+    let inlay_hints_fetch_task = editor
+        .update(&mut cx, |editor, cx| {
+            if got_throttled {
+                let query_not_around_visible_range = match editor.excerpt_visible_offsets(None, cx).remove(&query.excerpt_id) {
+                    Some((_, _, current_visible_range)) => {
+                        let visible_offset_length = current_visible_range.len();
+                        let double_visible_range = current_visible_range
+                            .start
+                            .saturating_sub(visible_offset_length)
+                            ..current_visible_range
+                                .end
+                                .saturating_add(visible_offset_length)
+                                .min(buffer_snapshot.len());
+                        !double_visible_range
+                            .contains(&fetch_range.start.to_offset(&buffer_snapshot))
+                            && !double_visible_range
+                                .contains(&fetch_range.end.to_offset(&buffer_snapshot))
+                    },
+                    None => true,
+                };
+                if query_not_around_visible_range {
+                    log::trace!("Fetching inlay hints for range {fetch_range_to_log:?} got throttled and fell off the current visible range, skipping.");
+                    if let Some(task_ranges) = editor
+                        .inlay_hint_cache
+                        .update_tasks
+                        .get_mut(&query.excerpt_id)
+                    {
+                        task_ranges.invalidate_range(&buffer_snapshot, &fetch_range);
+                    }
+                    return None;
+                }
+            }
+            editor
+                .buffer()
+                .read(cx)
+                .buffer(query.buffer_id)
+                .and_then(|buffer| {
+                    let project = editor.project.as_ref()?;
+                    Some(project.update(cx, |project, cx| {
+                        project.inlay_hints(buffer, fetch_range.clone(), cx)
+                    }))
+                })
+        })
+        .ok()
+        .flatten();
+    let new_hints = match inlay_hints_fetch_task {
+        Some(fetch_task) => {
+            log::debug!(
+                "Fetching inlay hints for range {fetch_range_to_log:?}, reason: {query_reason}, invalidate: {invalidate}",
+                query_reason = query.reason,
+            );
+            log::trace!(
+                "Currently visible hints: {visible_hints:?}, cached hints present: {}",
+                cached_excerpt_hints.is_some(),
+            );
+            fetch_task.await.context("inlay hint fetch task")?
+        }
+        None => return Ok(()),
+    };
+    drop(lsp_request_guard);
+    log::debug!(
+        "Fetched {} hints for range {fetch_range_to_log:?}",
+        new_hints.len()
+    );
+    log::trace!("Fetched hints: {new_hints:?}");
+
+    let background_task_buffer_snapshot = buffer_snapshot.clone();
+    let backround_fetch_range = fetch_range.clone();
+    let new_update = cx
+        .background_executor()
+        .spawn(async move {
+            calculate_hint_updates(
+                query.excerpt_id,
+                invalidate,
+                backround_fetch_range,
+                new_hints,
+                &background_task_buffer_snapshot,
+                cached_excerpt_hints,
+                &visible_hints,
+            )
+        })
+        .await;
+    if let Some(new_update) = new_update {
+        log::debug!(
+            "Applying update for range {fetch_range_to_log:?}: remove from editor: {}, remove from cache: {}, add to cache: {}",
+            new_update.remove_from_visible.len(),
+            new_update.remove_from_cache.len(),
+            new_update.add_to_cache.len()
+        );
+        log::trace!("New update: {new_update:?}");
+        editor
+            .update(&mut cx, |editor, cx| {
+                apply_hint_update(
+                    editor,
+                    new_update,
+                    query,
+                    invalidate,
+                    buffer_snapshot,
+                    multi_buffer_snapshot,
+                    cx,
+                );
+            })
+            .ok();
+    }
+    Ok(())
+}
 
 fn calculate_hint_updates(
     excerpt_id: ExcerptId,
@@ -1077,2279 +1073,2196 @@ fn apply_hint_update(
     multi_buffer_snapshot: MultiBufferSnapshot,
     cx: &mut ViewContext<'_, Editor>,
 ) {
-    todo!("old implementation commented below")
+    let cached_excerpt_hints = editor
+        .inlay_hint_cache
+        .hints
+        .entry(new_update.excerpt_id)
+        .or_insert_with(|| {
+            Arc::new(RwLock::new(CachedExcerptHints {
+                version: query.cache_version,
+                buffer_version: buffer_snapshot.version().clone(),
+                buffer_id: query.buffer_id,
+                ordered_hints: Vec::new(),
+                hints_by_id: HashMap::default(),
+            }))
+        });
+    let mut cached_excerpt_hints = cached_excerpt_hints.write();
+    match query.cache_version.cmp(&cached_excerpt_hints.version) {
+        cmp::Ordering::Less => return,
+        cmp::Ordering::Greater | cmp::Ordering::Equal => {
+            cached_excerpt_hints.version = query.cache_version;
+        }
+    }
+
+    let mut cached_inlays_changed = !new_update.remove_from_cache.is_empty();
+    cached_excerpt_hints
+        .ordered_hints
+        .retain(|hint_id| !new_update.remove_from_cache.contains(hint_id));
+    cached_excerpt_hints
+        .hints_by_id
+        .retain(|hint_id, _| !new_update.remove_from_cache.contains(hint_id));
+    let mut splice = InlaySplice {
+        to_remove: new_update.remove_from_visible,
+        to_insert: Vec::new(),
+    };
+    for new_hint in new_update.add_to_cache {
+        let insert_position = match cached_excerpt_hints
+            .ordered_hints
+            .binary_search_by(|probe| {
+                cached_excerpt_hints.hints_by_id[probe]
+                    .position
+                    .cmp(&new_hint.position, &buffer_snapshot)
+            }) {
+            Ok(i) => {
+                let mut insert_position = Some(i);
+                for id in &cached_excerpt_hints.ordered_hints[i..] {
+                    let cached_hint = &cached_excerpt_hints.hints_by_id[id];
+                    if new_hint
+                        .position
+                        .cmp(&cached_hint.position, &buffer_snapshot)
+                        .is_gt()
+                    {
+                        break;
+                    }
+                    if cached_hint.text() == new_hint.text() {
+                        insert_position = None;
+                        break;
+                    }
+                }
+                insert_position
+            }
+            Err(i) => Some(i),
+        };
+
+        if let Some(insert_position) = insert_position {
+            let new_inlay_id = post_inc(&mut editor.next_inlay_id);
+            if editor
+                .inlay_hint_cache
+                .allowed_hint_kinds
+                .contains(&new_hint.kind)
+            {
+                let new_hint_position =
+                    multi_buffer_snapshot.anchor_in_excerpt(query.excerpt_id, new_hint.position);
+                splice
+                    .to_insert
+                    .push(Inlay::hint(new_inlay_id, new_hint_position, &new_hint));
+            }
+            let new_id = InlayId::Hint(new_inlay_id);
+            cached_excerpt_hints.hints_by_id.insert(new_id, new_hint);
+            cached_excerpt_hints
+                .ordered_hints
+                .insert(insert_position, new_id);
+            cached_inlays_changed = true;
+        }
+    }
+    cached_excerpt_hints.buffer_version = buffer_snapshot.version().clone();
+    drop(cached_excerpt_hints);
+
+    if invalidate {
+        let mut outdated_excerpt_caches = HashSet::default();
+        for (excerpt_id, excerpt_hints) in &editor.inlay_hint_cache().hints {
+            let excerpt_hints = excerpt_hints.read();
+            if excerpt_hints.buffer_id == query.buffer_id
+                && excerpt_id != &query.excerpt_id
+                && buffer_snapshot
+                    .version()
+                    .changed_since(&excerpt_hints.buffer_version)
+            {
+                outdated_excerpt_caches.insert(*excerpt_id);
+                splice
+                    .to_remove
+                    .extend(excerpt_hints.ordered_hints.iter().copied());
+            }
+        }
+        cached_inlays_changed |= !outdated_excerpt_caches.is_empty();
+        editor
+            .inlay_hint_cache
+            .hints
+            .retain(|excerpt_id, _| !outdated_excerpt_caches.contains(excerpt_id));
+    }
+
+    let InlaySplice {
+        to_remove,
+        to_insert,
+    } = splice;
+    let displayed_inlays_changed = !to_remove.is_empty() || !to_insert.is_empty();
+    if cached_inlays_changed || displayed_inlays_changed {
+        editor.inlay_hint_cache.version += 1;
+    }
+    if displayed_inlays_changed {
+        editor.splice_inlay_hints(to_remove, to_insert, cx)
+    }
+}
+
+#[cfg(test)]
+pub mod tests {
+    use std::sync::atomic::{AtomicBool, AtomicU32, AtomicUsize, Ordering};
+
+    use crate::{
+        scroll::{autoscroll::Autoscroll, scroll_amount::ScrollAmount},
+        ExcerptRange,
+    };
+    use futures::StreamExt;
+    use gpui::{Context, TestAppContext, View, WindowHandle};
+    use itertools::Itertools;
+    use language::{
+        language_settings::AllLanguageSettingsContent, FakeLspAdapter, Language, LanguageConfig,
+    };
+    use lsp::FakeLanguageServer;
+    use parking_lot::Mutex;
+    use project::{FakeFs, Project};
+    use serde_json::json;
+    use settings::SettingsStore;
+    use text::{Point, ToPoint};
+    use workspace::Workspace;
+
+    use crate::editor_tests::update_test_language_settings;
+
+    use super::*;
+
+    #[gpui::test]
+    async fn test_basic_cache_update_with_duplicate_hints(cx: &mut gpui::TestAppContext) {
+        let allowed_hint_kinds = HashSet::from_iter([None, Some(InlayHintKind::Type)]);
+        init_test(cx, |settings| {
+            settings.defaults.inlay_hints = Some(InlayHintSettings {
+                enabled: true,
+                show_type_hints: allowed_hint_kinds.contains(&Some(InlayHintKind::Type)),
+                show_parameter_hints: allowed_hint_kinds.contains(&Some(InlayHintKind::Parameter)),
+                show_other_hints: allowed_hint_kinds.contains(&None),
+            })
+        });
+
+        let (file_with_hints, editor, fake_server) = prepare_test_objects(cx).await;
+        let lsp_request_count = Arc::new(AtomicU32::new(0));
+        fake_server
+            .handle_request::<lsp::request::InlayHintRequest, _, _>(move |params, _| {
+                let task_lsp_request_count = Arc::clone(&lsp_request_count);
+                async move {
+                    assert_eq!(
+                        params.text_document.uri,
+                        lsp::Url::from_file_path(file_with_hints).unwrap(),
+                    );
+                    let current_call_id =
+                        Arc::clone(&task_lsp_request_count).fetch_add(1, Ordering::SeqCst);
+                    let mut new_hints = Vec::with_capacity(2 * current_call_id as usize);
+                    for _ in 0..2 {
+                        let mut i = current_call_id;
+                        loop {
+                            new_hints.push(lsp::InlayHint {
+                                position: lsp::Position::new(0, i),
+                                label: lsp::InlayHintLabel::String(i.to_string()),
+                                kind: None,
+                                text_edits: None,
+                                tooltip: None,
+                                padding_left: None,
+                                padding_right: None,
+                                data: None,
+                            });
+                            if i == 0 {
+                                break;
+                            }
+                            i -= 1;
+                        }
+                    }
+
+                    Ok(Some(new_hints))
+                }
+            })
+            .next()
+            .await;
+        cx.executor().run_until_parked();
+
+        let mut edits_made = 1;
+        editor.update(cx, |editor, cx| {
+            let expected_hints = vec!["0".to_string()];
+            assert_eq!(
+                expected_hints,
+                cached_hint_labels(editor),
+                "Should get its first hints when opening the editor"
+            );
+            assert_eq!(expected_hints, visible_hint_labels(editor, cx));
+            let inlay_cache = editor.inlay_hint_cache();
+            assert_eq!(
+                inlay_cache.allowed_hint_kinds, allowed_hint_kinds,
+                "Cache should use editor settings to get the allowed hint kinds"
+            );
+            assert_eq!(
+                inlay_cache.version, edits_made,
+                "The editor update the cache version after every cache/view change"
+            );
+        });
+
+        editor.update(cx, |editor, cx| {
+            editor.change_selections(None, cx, |s| s.select_ranges([13..13]));
+            editor.handle_input("some change", cx);
+            edits_made += 1;
+        });
+        cx.executor().run_until_parked();
+        editor.update(cx, |editor, cx| {
+            let expected_hints = vec!["0".to_string(), "1".to_string()];
+            assert_eq!(
+                expected_hints,
+                cached_hint_labels(editor),
+                "Should get new hints after an edit"
+            );
+            assert_eq!(expected_hints, visible_hint_labels(editor, cx));
+            let inlay_cache = editor.inlay_hint_cache();
+            assert_eq!(
+                inlay_cache.allowed_hint_kinds, allowed_hint_kinds,
+                "Cache should use editor settings to get the allowed hint kinds"
+            );
+            assert_eq!(
+                inlay_cache.version, edits_made,
+                "The editor update the cache version after every cache/view change"
+            );
+        });
+
+        fake_server
+            .request::<lsp::request::InlayHintRefreshRequest>(())
+            .await
+            .expect("inlay refresh request failed");
+        edits_made += 1;
+        cx.executor().run_until_parked();
+        editor.update(cx, |editor, cx| {
+            let expected_hints = vec!["0".to_string(), "1".to_string(), "2".to_string()];
+            assert_eq!(
+                expected_hints,
+                cached_hint_labels(editor),
+                "Should get new hints after hint refresh/ request"
+            );
+            assert_eq!(expected_hints, visible_hint_labels(editor, cx));
+            let inlay_cache = editor.inlay_hint_cache();
+            assert_eq!(
+                inlay_cache.allowed_hint_kinds, allowed_hint_kinds,
+                "Cache should use editor settings to get the allowed hint kinds"
+            );
+            assert_eq!(
+                inlay_cache.version, edits_made,
+                "The editor update the cache version after every cache/view change"
+            );
+        });
+    }
+
+    #[gpui::test]
+    async fn test_cache_update_on_lsp_completion_tasks(cx: &mut gpui::TestAppContext) {
+        init_test(cx, |settings| {
+            settings.defaults.inlay_hints = Some(InlayHintSettings {
+                enabled: true,
+                show_type_hints: true,
+                show_parameter_hints: true,
+                show_other_hints: true,
+            })
+        });
+
+        let (file_with_hints, editor, fake_server) = prepare_test_objects(cx).await;
+        let lsp_request_count = Arc::new(AtomicU32::new(0));
+        fake_server
+            .handle_request::<lsp::request::InlayHintRequest, _, _>(move |params, _| {
+                let task_lsp_request_count = Arc::clone(&lsp_request_count);
+                async move {
+                    assert_eq!(
+                        params.text_document.uri,
+                        lsp::Url::from_file_path(file_with_hints).unwrap(),
+                    );
+                    let current_call_id =
+                        Arc::clone(&task_lsp_request_count).fetch_add(1, Ordering::SeqCst);
+                    Ok(Some(vec![lsp::InlayHint {
+                        position: lsp::Position::new(0, current_call_id),
+                        label: lsp::InlayHintLabel::String(current_call_id.to_string()),
+                        kind: None,
+                        text_edits: None,
+                        tooltip: None,
+                        padding_left: None,
+                        padding_right: None,
+                        data: None,
+                    }]))
+                }
+            })
+            .next()
+            .await;
+        cx.executor().run_until_parked();
+
+        let mut edits_made = 1;
+        editor.update(cx, |editor, cx| {
+            let expected_hints = vec!["0".to_string()];
+            assert_eq!(
+                expected_hints,
+                cached_hint_labels(editor),
+                "Should get its first hints when opening the editor"
+            );
+            assert_eq!(expected_hints, visible_hint_labels(editor, cx));
+            assert_eq!(
+                editor.inlay_hint_cache().version,
+                edits_made,
+                "The editor update the cache version after every cache/view change"
+            );
+        });
+
+        let progress_token = "test_progress_token";
+        fake_server
+            .request::<lsp::request::WorkDoneProgressCreate>(lsp::WorkDoneProgressCreateParams {
+                token: lsp::ProgressToken::String(progress_token.to_string()),
+            })
+            .await
+            .expect("work done progress create request failed");
+        cx.executor().run_until_parked();
+        fake_server.notify::<lsp::notification::Progress>(lsp::ProgressParams {
+            token: lsp::ProgressToken::String(progress_token.to_string()),
+            value: lsp::ProgressParamsValue::WorkDone(lsp::WorkDoneProgress::Begin(
+                lsp::WorkDoneProgressBegin::default(),
+            )),
+        });
+        cx.executor().run_until_parked();
+
+        editor.update(cx, |editor, cx| {
+            let expected_hints = vec!["0".to_string()];
+            assert_eq!(
+                expected_hints,
+                cached_hint_labels(editor),
+                "Should not update hints while the work task is running"
+            );
+            assert_eq!(expected_hints, visible_hint_labels(editor, cx));
+            assert_eq!(
+                editor.inlay_hint_cache().version,
+                edits_made,
+                "Should not update the cache while the work task is running"
+            );
+        });
+
+        fake_server.notify::<lsp::notification::Progress>(lsp::ProgressParams {
+            token: lsp::ProgressToken::String(progress_token.to_string()),
+            value: lsp::ProgressParamsValue::WorkDone(lsp::WorkDoneProgress::End(
+                lsp::WorkDoneProgressEnd::default(),
+            )),
+        });
+        cx.executor().run_until_parked();
+
+        edits_made += 1;
+        editor.update(cx, |editor, cx| {
+            let expected_hints = vec!["1".to_string()];
+            assert_eq!(
+                expected_hints,
+                cached_hint_labels(editor),
+                "New hints should be queried after the work task is done"
+            );
+            assert_eq!(expected_hints, visible_hint_labels(editor, cx));
+            assert_eq!(
+                editor.inlay_hint_cache().version,
+                edits_made,
+                "Cache version should udpate once after the work task is done"
+            );
+        });
+    }
+
+    #[gpui::test]
+    async fn test_no_hint_updates_for_unrelated_language_files(cx: &mut gpui::TestAppContext) {
+        init_test(cx, |settings| {
+            settings.defaults.inlay_hints = Some(InlayHintSettings {
+                enabled: true,
+                show_type_hints: true,
+                show_parameter_hints: true,
+                show_other_hints: true,
+            })
+        });
+
+        let fs = FakeFs::new(cx.background_executor.clone());
+        fs.insert_tree(
+                    "/a",
+                    json!({
+                        "main.rs": "fn main() { a } // and some long comment to ensure inlays are not trimmed out",
+                        "other.md": "Test md file with some text",
+                    }),
+                )
+                .await;
+        let project = Project::test(fs, ["/a".as_ref()], cx).await;
+
+        let mut rs_fake_servers = None;
+        let mut md_fake_servers = None;
+        for (name, path_suffix) in [("Rust", "rs"), ("Markdown", "md")] {
+            let mut language = Language::new(
+                LanguageConfig {
+                    name: name.into(),
+                    path_suffixes: vec![path_suffix.to_string()],
+                    ..Default::default()
+                },
+                Some(tree_sitter_rust::language()),
+            );
+            let fake_servers = language
+                .set_fake_lsp_adapter(Arc::new(FakeLspAdapter {
+                    name,
+                    capabilities: lsp::ServerCapabilities {
+                        inlay_hint_provider: Some(lsp::OneOf::Left(true)),
+                        ..Default::default()
+                    },
+                    ..Default::default()
+                }))
+                .await;
+            match name {
+                "Rust" => rs_fake_servers = Some(fake_servers),
+                "Markdown" => md_fake_servers = Some(fake_servers),
+                _ => unreachable!(),
+            }
+            project.update(cx, |project, _| {
+                project.languages().add(Arc::new(language));
+            });
+        }
+
+        let rs_buffer = project
+            .update(cx, |project, cx| {
+                project.open_local_buffer("/a/main.rs", cx)
+            })
+            .await
+            .unwrap();
+        cx.executor().run_until_parked();
+        cx.executor().start_waiting();
+        let rs_fake_server = rs_fake_servers.unwrap().next().await.unwrap();
+        let rs_editor =
+            cx.add_window(|cx| Editor::for_buffer(rs_buffer, Some(project.clone()), cx));
+        let rs_lsp_request_count = Arc::new(AtomicU32::new(0));
+        rs_fake_server
+            .handle_request::<lsp::request::InlayHintRequest, _, _>(move |params, _| {
+                let task_lsp_request_count = Arc::clone(&rs_lsp_request_count);
+                async move {
+                    assert_eq!(
+                        params.text_document.uri,
+                        lsp::Url::from_file_path("/a/main.rs").unwrap(),
+                    );
+                    let i = Arc::clone(&task_lsp_request_count).fetch_add(1, Ordering::SeqCst);
+                    Ok(Some(vec![lsp::InlayHint {
+                        position: lsp::Position::new(0, i),
+                        label: lsp::InlayHintLabel::String(i.to_string()),
+                        kind: None,
+                        text_edits: None,
+                        tooltip: None,
+                        padding_left: None,
+                        padding_right: None,
+                        data: None,
+                    }]))
+                }
+            })
+            .next()
+            .await;
+        cx.executor().run_until_parked();
+        rs_editor.update(cx, |editor, cx| {
+            let expected_hints = vec!["0".to_string()];
+            assert_eq!(
+                expected_hints,
+                cached_hint_labels(editor),
+                "Should get its first hints when opening the editor"
+            );
+            assert_eq!(expected_hints, visible_hint_labels(editor, cx));
+            assert_eq!(
+                editor.inlay_hint_cache().version,
+                1,
+                "Rust editor update the cache version after every cache/view change"
+            );
+        });
+
+        cx.executor().run_until_parked();
+        let md_buffer = project
+            .update(cx, |project, cx| {
+                project.open_local_buffer("/a/other.md", cx)
+            })
+            .await
+            .unwrap();
+        cx.executor().run_until_parked();
+        cx.executor().start_waiting();
+        let md_fake_server = md_fake_servers.unwrap().next().await.unwrap();
+        let md_editor = cx.add_window(|cx| Editor::for_buffer(md_buffer, Some(project), cx));
+        let md_lsp_request_count = Arc::new(AtomicU32::new(0));
+        md_fake_server
+            .handle_request::<lsp::request::InlayHintRequest, _, _>(move |params, _| {
+                let task_lsp_request_count = Arc::clone(&md_lsp_request_count);
+                async move {
+                    assert_eq!(
+                        params.text_document.uri,
+                        lsp::Url::from_file_path("/a/other.md").unwrap(),
+                    );
+                    let i = Arc::clone(&task_lsp_request_count).fetch_add(1, Ordering::SeqCst);
+                    Ok(Some(vec![lsp::InlayHint {
+                        position: lsp::Position::new(0, i),
+                        label: lsp::InlayHintLabel::String(i.to_string()),
+                        kind: None,
+                        text_edits: None,
+                        tooltip: None,
+                        padding_left: None,
+                        padding_right: None,
+                        data: None,
+                    }]))
+                }
+            })
+            .next()
+            .await;
+        cx.executor().run_until_parked();
+        md_editor.update(cx, |editor, cx| {
+            let expected_hints = vec!["0".to_string()];
+            assert_eq!(
+                expected_hints,
+                cached_hint_labels(editor),
+                "Markdown editor should have a separate verison, repeating Rust editor rules"
+            );
+            assert_eq!(expected_hints, visible_hint_labels(editor, cx));
+            assert_eq!(editor.inlay_hint_cache().version, 1);
+        });
+
+        rs_editor.update(cx, |editor, cx| {
+            editor.change_selections(None, cx, |s| s.select_ranges([13..13]));
+            editor.handle_input("some rs change", cx);
+        });
+        cx.executor().run_until_parked();
+        rs_editor.update(cx, |editor, cx| {
+            let expected_hints = vec!["1".to_string()];
+            assert_eq!(
+                expected_hints,
+                cached_hint_labels(editor),
+                "Rust inlay cache should change after the edit"
+            );
+            assert_eq!(expected_hints, visible_hint_labels(editor, cx));
+            assert_eq!(
+                editor.inlay_hint_cache().version,
+                2,
+                "Every time hint cache changes, cache version should be incremented"
+            );
+        });
+        md_editor.update(cx, |editor, cx| {
+            let expected_hints = vec!["0".to_string()];
+            assert_eq!(
+                expected_hints,
+                cached_hint_labels(editor),
+                "Markdown editor should not be affected by Rust editor changes"
+            );
+            assert_eq!(expected_hints, visible_hint_labels(editor, cx));
+            assert_eq!(editor.inlay_hint_cache().version, 1);
+        });
+
+        md_editor.update(cx, |editor, cx| {
+            editor.change_selections(None, cx, |s| s.select_ranges([13..13]));
+            editor.handle_input("some md change", cx);
+        });
+        cx.executor().run_until_parked();
+        md_editor.update(cx, |editor, cx| {
+            let expected_hints = vec!["1".to_string()];
+            assert_eq!(
+                expected_hints,
+                cached_hint_labels(editor),
+                "Rust editor should not be affected by Markdown editor changes"
+            );
+            assert_eq!(expected_hints, visible_hint_labels(editor, cx));
+            assert_eq!(editor.inlay_hint_cache().version, 2);
+        });
+        rs_editor.update(cx, |editor, cx| {
+            let expected_hints = vec!["1".to_string()];
+            assert_eq!(
+                expected_hints,
+                cached_hint_labels(editor),
+                "Markdown editor should also change independently"
+            );
+            assert_eq!(expected_hints, visible_hint_labels(editor, cx));
+            assert_eq!(editor.inlay_hint_cache().version, 2);
+        });
+    }
+
+    #[gpui::test]
+    async fn test_hint_setting_changes(cx: &mut gpui::TestAppContext) {
+        let allowed_hint_kinds = HashSet::from_iter([None, Some(InlayHintKind::Type)]);
+        init_test(cx, |settings| {
+            settings.defaults.inlay_hints = Some(InlayHintSettings {
+                enabled: true,
+                show_type_hints: allowed_hint_kinds.contains(&Some(InlayHintKind::Type)),
+                show_parameter_hints: allowed_hint_kinds.contains(&Some(InlayHintKind::Parameter)),
+                show_other_hints: allowed_hint_kinds.contains(&None),
+            })
+        });
+
+        let (file_with_hints, editor, fake_server) = prepare_test_objects(cx).await;
+        let lsp_request_count = Arc::new(AtomicU32::new(0));
+        let another_lsp_request_count = Arc::clone(&lsp_request_count);
+        fake_server
+            .handle_request::<lsp::request::InlayHintRequest, _, _>(move |params, _| {
+                let task_lsp_request_count = Arc::clone(&another_lsp_request_count);
+                async move {
+                    Arc::clone(&task_lsp_request_count).fetch_add(1, Ordering::SeqCst);
+                    assert_eq!(
+                        params.text_document.uri,
+                        lsp::Url::from_file_path(file_with_hints).unwrap(),
+                    );
+                    Ok(Some(vec![
+                        lsp::InlayHint {
+                            position: lsp::Position::new(0, 1),
+                            label: lsp::InlayHintLabel::String("type hint".to_string()),
+                            kind: Some(lsp::InlayHintKind::TYPE),
+                            text_edits: None,
+                            tooltip: None,
+                            padding_left: None,
+                            padding_right: None,
+                            data: None,
+                        },
+                        lsp::InlayHint {
+                            position: lsp::Position::new(0, 2),
+                            label: lsp::InlayHintLabel::String("parameter hint".to_string()),
+                            kind: Some(lsp::InlayHintKind::PARAMETER),
+                            text_edits: None,
+                            tooltip: None,
+                            padding_left: None,
+                            padding_right: None,
+                            data: None,
+                        },
+                        lsp::InlayHint {
+                            position: lsp::Position::new(0, 3),
+                            label: lsp::InlayHintLabel::String("other hint".to_string()),
+                            kind: None,
+                            text_edits: None,
+                            tooltip: None,
+                            padding_left: None,
+                            padding_right: None,
+                            data: None,
+                        },
+                    ]))
+                }
+            })
+            .next()
+            .await;
+        cx.executor().run_until_parked();
+
+        let mut edits_made = 1;
+        editor.update(cx, |editor, cx| {
+            assert_eq!(
+                lsp_request_count.load(Ordering::Relaxed),
+                1,
+                "Should query new hints once"
+            );
+            assert_eq!(
+                vec![
+                    "other hint".to_string(),
+                    "parameter hint".to_string(),
+                    "type hint".to_string(),
+                ],
+                cached_hint_labels(editor),
+                "Should get its first hints when opening the editor"
+            );
+            assert_eq!(
+                vec!["other hint".to_string(), "type hint".to_string()],
+                visible_hint_labels(editor, cx)
+            );
+            let inlay_cache = editor.inlay_hint_cache();
+            assert_eq!(
+                inlay_cache.allowed_hint_kinds, allowed_hint_kinds,
+                "Cache should use editor settings to get the allowed hint kinds"
+            );
+            assert_eq!(
+                inlay_cache.version, edits_made,
+                "The editor update the cache version after every cache/view change"
+            );
+        });
+
+        fake_server
+            .request::<lsp::request::InlayHintRefreshRequest>(())
+            .await
+            .expect("inlay refresh request failed");
+        cx.executor().run_until_parked();
+        editor.update(cx, |editor, cx| {
+            assert_eq!(
+                lsp_request_count.load(Ordering::Relaxed),
+                2,
+                "Should load new hints twice"
+            );
+            assert_eq!(
+                vec![
+                    "other hint".to_string(),
+                    "parameter hint".to_string(),
+                    "type hint".to_string(),
+                ],
+                cached_hint_labels(editor),
+                "Cached hints should not change due to allowed hint kinds settings update"
+            );
+            assert_eq!(
+                vec!["other hint".to_string(), "type hint".to_string()],
+                visible_hint_labels(editor, cx)
+            );
+            assert_eq!(
+                editor.inlay_hint_cache().version,
+                edits_made,
+                "Should not update cache version due to new loaded hints being the same"
+            );
+        });
+
+        for (new_allowed_hint_kinds, expected_visible_hints) in [
+            (HashSet::from_iter([None]), vec!["other hint".to_string()]),
+            (
+                HashSet::from_iter([Some(InlayHintKind::Type)]),
+                vec!["type hint".to_string()],
+            ),
+            (
+                HashSet::from_iter([Some(InlayHintKind::Parameter)]),
+                vec!["parameter hint".to_string()],
+            ),
+            (
+                HashSet::from_iter([None, Some(InlayHintKind::Type)]),
+                vec!["other hint".to_string(), "type hint".to_string()],
+            ),
+            (
+                HashSet::from_iter([None, Some(InlayHintKind::Parameter)]),
+                vec!["other hint".to_string(), "parameter hint".to_string()],
+            ),
+            (
+                HashSet::from_iter([Some(InlayHintKind::Type), Some(InlayHintKind::Parameter)]),
+                vec!["parameter hint".to_string(), "type hint".to_string()],
+            ),
+            (
+                HashSet::from_iter([
+                    None,
+                    Some(InlayHintKind::Type),
+                    Some(InlayHintKind::Parameter),
+                ]),
+                vec![
+                    "other hint".to_string(),
+                    "parameter hint".to_string(),
+                    "type hint".to_string(),
+                ],
+            ),
+        ] {
+            edits_made += 1;
+            update_test_language_settings(cx, |settings| {
+                settings.defaults.inlay_hints = Some(InlayHintSettings {
+                    enabled: true,
+                    show_type_hints: new_allowed_hint_kinds.contains(&Some(InlayHintKind::Type)),
+                    show_parameter_hints: new_allowed_hint_kinds
+                        .contains(&Some(InlayHintKind::Parameter)),
+                    show_other_hints: new_allowed_hint_kinds.contains(&None),
+                })
+            });
+            cx.executor().run_until_parked();
+            editor.update(cx, |editor, cx| {
+                assert_eq!(
+                    lsp_request_count.load(Ordering::Relaxed),
+                    2,
+                    "Should not load new hints on allowed hint kinds change for hint kinds {new_allowed_hint_kinds:?}"
+                );
+                assert_eq!(
+                    vec![
+                        "other hint".to_string(),
+                        "parameter hint".to_string(),
+                        "type hint".to_string(),
+                    ],
+                    cached_hint_labels(editor),
+                    "Should get its cached hints unchanged after the settings change for hint kinds {new_allowed_hint_kinds:?}"
+                );
+                assert_eq!(
+                    expected_visible_hints,
+                    visible_hint_labels(editor, cx),
+                    "Should get its visible hints filtered after the settings change for hint kinds {new_allowed_hint_kinds:?}"
+                );
+                let inlay_cache = editor.inlay_hint_cache();
+                assert_eq!(
+                    inlay_cache.allowed_hint_kinds, new_allowed_hint_kinds,
+                    "Cache should use editor settings to get the allowed hint kinds for hint kinds {new_allowed_hint_kinds:?}"
+                );
+                assert_eq!(
+                    inlay_cache.version, edits_made,
+                    "The editor should update the cache version after every cache/view change for hint kinds {new_allowed_hint_kinds:?} due to visible hints change"
+                );
+            });
+        }
+
+        edits_made += 1;
+        let another_allowed_hint_kinds = HashSet::from_iter([Some(InlayHintKind::Type)]);
+        update_test_language_settings(cx, |settings| {
+            settings.defaults.inlay_hints = Some(InlayHintSettings {
+                enabled: false,
+                show_type_hints: another_allowed_hint_kinds.contains(&Some(InlayHintKind::Type)),
+                show_parameter_hints: another_allowed_hint_kinds
+                    .contains(&Some(InlayHintKind::Parameter)),
+                show_other_hints: another_allowed_hint_kinds.contains(&None),
+            })
+        });
+        cx.executor().run_until_parked();
+        editor.update(cx, |editor, cx| {
+            assert_eq!(
+                lsp_request_count.load(Ordering::Relaxed),
+                2,
+                "Should not load new hints when hints got disabled"
+            );
+            assert!(
+                cached_hint_labels(editor).is_empty(),
+                "Should clear the cache when hints got disabled"
+            );
+            assert!(
+                visible_hint_labels(editor, cx).is_empty(),
+                "Should clear visible hints when hints got disabled"
+            );
+            let inlay_cache = editor.inlay_hint_cache();
+            assert_eq!(
+                inlay_cache.allowed_hint_kinds, another_allowed_hint_kinds,
+                "Should update its allowed hint kinds even when hints got disabled"
+            );
+            assert_eq!(
+                inlay_cache.version, edits_made,
+                "The editor should update the cache version after hints got disabled"
+            );
+        });
+
+        fake_server
+            .request::<lsp::request::InlayHintRefreshRequest>(())
+            .await
+            .expect("inlay refresh request failed");
+        cx.executor().run_until_parked();
+        editor.update(cx, |editor, cx| {
+            assert_eq!(
+                lsp_request_count.load(Ordering::Relaxed),
+                2,
+                "Should not load new hints when they got disabled"
+            );
+            assert!(cached_hint_labels(editor).is_empty());
+            assert!(visible_hint_labels(editor, cx).is_empty());
+            assert_eq!(
+                editor.inlay_hint_cache().version, edits_made,
+                "The editor should not update the cache version after /refresh query without updates"
+            );
+        });
+
+        let final_allowed_hint_kinds = HashSet::from_iter([Some(InlayHintKind::Parameter)]);
+        edits_made += 1;
+        update_test_language_settings(cx, |settings| {
+            settings.defaults.inlay_hints = Some(InlayHintSettings {
+                enabled: true,
+                show_type_hints: final_allowed_hint_kinds.contains(&Some(InlayHintKind::Type)),
+                show_parameter_hints: final_allowed_hint_kinds
+                    .contains(&Some(InlayHintKind::Parameter)),
+                show_other_hints: final_allowed_hint_kinds.contains(&None),
+            })
+        });
+        cx.executor().run_until_parked();
+        editor.update(cx, |editor, cx| {
+            assert_eq!(
+                lsp_request_count.load(Ordering::Relaxed),
+                3,
+                "Should query for new hints when they got reenabled"
+            );
+            assert_eq!(
+                vec![
+                    "other hint".to_string(),
+                    "parameter hint".to_string(),
+                    "type hint".to_string(),
+                ],
+                cached_hint_labels(editor),
+                "Should get its cached hints fully repopulated after the hints got reenabled"
+            );
+            assert_eq!(
+                vec!["parameter hint".to_string()],
+                visible_hint_labels(editor, cx),
+                "Should get its visible hints repopulated and filtered after the h"
+            );
+            let inlay_cache = editor.inlay_hint_cache();
+            assert_eq!(
+                inlay_cache.allowed_hint_kinds, final_allowed_hint_kinds,
+                "Cache should update editor settings when hints got reenabled"
+            );
+            assert_eq!(
+                inlay_cache.version, edits_made,
+                "Cache should update its version after hints got reenabled"
+            );
+        });
+
+        fake_server
+            .request::<lsp::request::InlayHintRefreshRequest>(())
+            .await
+            .expect("inlay refresh request failed");
+        cx.executor().run_until_parked();
+        editor.update(cx, |editor, cx| {
+            assert_eq!(
+                lsp_request_count.load(Ordering::Relaxed),
+                4,
+                "Should query for new hints again"
+            );
+            assert_eq!(
+                vec![
+                    "other hint".to_string(),
+                    "parameter hint".to_string(),
+                    "type hint".to_string(),
+                ],
+                cached_hint_labels(editor),
+            );
+            assert_eq!(
+                vec!["parameter hint".to_string()],
+                visible_hint_labels(editor, cx),
+            );
+            assert_eq!(editor.inlay_hint_cache().version, edits_made);
+        });
+    }
+
+    #[gpui::test]
+    async fn test_hint_request_cancellation(cx: &mut gpui::TestAppContext) {
+        init_test(cx, |settings| {
+            settings.defaults.inlay_hints = Some(InlayHintSettings {
+                enabled: true,
+                show_type_hints: true,
+                show_parameter_hints: true,
+                show_other_hints: true,
+            })
+        });
+
+        let (file_with_hints, editor, fake_server) = prepare_test_objects(cx).await;
+        let fake_server = Arc::new(fake_server);
+        let lsp_request_count = Arc::new(AtomicU32::new(0));
+        let another_lsp_request_count = Arc::clone(&lsp_request_count);
+        fake_server
+            .handle_request::<lsp::request::InlayHintRequest, _, _>(move |params, _| {
+                let task_lsp_request_count = Arc::clone(&another_lsp_request_count);
+                async move {
+                    let i = Arc::clone(&task_lsp_request_count).fetch_add(1, Ordering::SeqCst) + 1;
+                    assert_eq!(
+                        params.text_document.uri,
+                        lsp::Url::from_file_path(file_with_hints).unwrap(),
+                    );
+                    Ok(Some(vec![lsp::InlayHint {
+                        position: lsp::Position::new(0, i),
+                        label: lsp::InlayHintLabel::String(i.to_string()),
+                        kind: None,
+                        text_edits: None,
+                        tooltip: None,
+                        padding_left: None,
+                        padding_right: None,
+                        data: None,
+                    }]))
+                }
+            })
+            .next()
+            .await;
+
+        let mut expected_changes = Vec::new();
+        for change_after_opening in [
+            "initial change #1",
+            "initial change #2",
+            "initial change #3",
+        ] {
+            editor.update(cx, |editor, cx| {
+                editor.change_selections(None, cx, |s| s.select_ranges([13..13]));
+                editor.handle_input(change_after_opening, cx);
+            });
+            expected_changes.push(change_after_opening);
+        }
+
+        cx.executor().run_until_parked();
+
+        editor.update(cx, |editor, cx| {
+            let current_text = editor.text(cx);
+            for change in &expected_changes {
+                assert!(
+                    current_text.contains(change),
+                    "Should apply all changes made"
+                );
+            }
+            assert_eq!(
+                lsp_request_count.load(Ordering::Relaxed),
+                2,
+                "Should query new hints twice: for editor init and for the last edit that interrupted all others"
+            );
+            let expected_hints = vec!["2".to_string()];
+            assert_eq!(
+                expected_hints,
+                cached_hint_labels(editor),
+                "Should get hints from the last edit landed only"
+            );
+            assert_eq!(expected_hints, visible_hint_labels(editor, cx));
+            assert_eq!(
+                editor.inlay_hint_cache().version, 1,
+                "Only one update should be registered in the cache after all cancellations"
+            );
+        });
+
+        let mut edits = Vec::new();
+        for async_later_change in [
+            "another change #1",
+            "another change #2",
+            "another change #3",
+        ] {
+            expected_changes.push(async_later_change);
+            let task_editor = editor.clone();
+            edits.push(cx.spawn(|mut cx| async move {
+                task_editor.update(&mut cx, |editor, cx| {
+                    editor.change_selections(None, cx, |s| s.select_ranges([13..13]));
+                    editor.handle_input(async_later_change, cx);
+                });
+            }));
+        }
+        let _ = future::join_all(edits).await;
+        cx.executor().run_until_parked();
+
+        editor.update(cx, |editor, cx| {
+            let current_text = editor.text(cx);
+            for change in &expected_changes {
+                assert!(
+                    current_text.contains(change),
+                    "Should apply all changes made"
+                );
+            }
+            assert_eq!(
+                lsp_request_count.load(Ordering::SeqCst),
+                3,
+                "Should query new hints one more time, for the last edit only"
+            );
+            let expected_hints = vec!["3".to_string()];
+            assert_eq!(
+                expected_hints,
+                cached_hint_labels(editor),
+                "Should get hints from the last edit landed only"
+            );
+            assert_eq!(expected_hints, visible_hint_labels(editor, cx));
+            assert_eq!(
+                editor.inlay_hint_cache().version,
+                2,
+                "Should update the cache version once more, for the new change"
+            );
+        });
+    }
+
+    #[gpui::test(iterations = 10)]
+    async fn test_large_buffer_inlay_requests_split(cx: &mut gpui::TestAppContext) {
+        init_test(cx, |settings| {
+            settings.defaults.inlay_hints = Some(InlayHintSettings {
+                enabled: true,
+                show_type_hints: true,
+                show_parameter_hints: true,
+                show_other_hints: true,
+            })
+        });
+
+        let mut language = Language::new(
+            LanguageConfig {
+                name: "Rust".into(),
+                path_suffixes: vec!["rs".to_string()],
+                ..Default::default()
+            },
+            Some(tree_sitter_rust::language()),
+        );
+        let mut fake_servers = language
+            .set_fake_lsp_adapter(Arc::new(FakeLspAdapter {
+                capabilities: lsp::ServerCapabilities {
+                    inlay_hint_provider: Some(lsp::OneOf::Left(true)),
+                    ..Default::default()
+                },
+                ..Default::default()
+            }))
+            .await;
+        let fs = FakeFs::new(cx.background_executor.clone());
+        fs.insert_tree(
+            "/a",
+            json!({
+                "main.rs": format!("fn main() {{\n{}\n}}", "let i = 5;\n".repeat(500)),
+                "other.rs": "// Test file",
+            }),
+        )
+        .await;
+        let project = Project::test(fs, ["/a".as_ref()], cx).await;
+        project.update(cx, |project, _| project.languages().add(Arc::new(language)));
+        let buffer = project
+            .update(cx, |project, cx| {
+                project.open_local_buffer("/a/main.rs", cx)
+            })
+            .await
+            .unwrap();
+        cx.executor().run_until_parked();
+        cx.executor().start_waiting();
+        let fake_server = fake_servers.next().await.unwrap();
+        let editor = cx.add_window(|cx| Editor::for_buffer(buffer, Some(project), cx));
+        let lsp_request_ranges = Arc::new(Mutex::new(Vec::new()));
+        let lsp_request_count = Arc::new(AtomicUsize::new(0));
+        let closure_lsp_request_ranges = Arc::clone(&lsp_request_ranges);
+        let closure_lsp_request_count = Arc::clone(&lsp_request_count);
+        fake_server
+            .handle_request::<lsp::request::InlayHintRequest, _, _>(move |params, _| {
+                let task_lsp_request_ranges = Arc::clone(&closure_lsp_request_ranges);
+                let task_lsp_request_count = Arc::clone(&closure_lsp_request_count);
+                async move {
+                    assert_eq!(
+                        params.text_document.uri,
+                        lsp::Url::from_file_path("/a/main.rs").unwrap(),
+                    );
+
+                    task_lsp_request_ranges.lock().push(params.range);
+                    let i = Arc::clone(&task_lsp_request_count).fetch_add(1, Ordering::Release) + 1;
+                    Ok(Some(vec![lsp::InlayHint {
+                        position: params.range.end,
+                        label: lsp::InlayHintLabel::String(i.to_string()),
+                        kind: None,
+                        text_edits: None,
+                        tooltip: None,
+                        padding_left: None,
+                        padding_right: None,
+                        data: None,
+                    }]))
+                }
+            })
+            .next()
+            .await;
+
+        fn editor_visible_range(
+            editor: &WindowHandle<Editor>,
+            cx: &mut gpui::TestAppContext,
+        ) -> Range<Point> {
+            let ranges = editor
+                .update(cx, |editor, cx| editor.excerpt_visible_offsets(None, cx))
+                .unwrap();
+            assert_eq!(
+                ranges.len(),
+                1,
+                "Single buffer should produce a single excerpt with visible range"
+            );
+            let (_, (excerpt_buffer, _, excerpt_visible_range)) =
+                ranges.into_iter().next().unwrap();
+            excerpt_buffer.update(cx, |buffer, _| {
+                let snapshot = buffer.snapshot();
+                let start = buffer
+                    .anchor_before(excerpt_visible_range.start)
+                    .to_point(&snapshot);
+                let end = buffer
+                    .anchor_after(excerpt_visible_range.end)
+                    .to_point(&snapshot);
+                start..end
+            })
+        }
+
+        // in large buffers, requests are made for more than visible range of a buffer.
+        // invisible parts are queried later, to avoid excessive requests on quick typing.
+        // wait the timeout needed to get all requests.
+        cx.executor().advance_clock(Duration::from_millis(
+            INVISIBLE_RANGES_HINTS_REQUEST_DELAY_MILLIS + 100,
+        ));
+        cx.executor().run_until_parked();
+        let initial_visible_range = editor_visible_range(&editor, cx);
+        let lsp_initial_visible_range = lsp::Range::new(
+            lsp::Position::new(
+                initial_visible_range.start.row,
+                initial_visible_range.start.column,
+            ),
+            lsp::Position::new(
+                initial_visible_range.end.row,
+                initial_visible_range.end.column,
+            ),
+        );
+        let expected_initial_query_range_end =
+            lsp::Position::new(initial_visible_range.end.row * 2, 2);
+        let mut expected_invisible_query_start = lsp_initial_visible_range.end;
+        expected_invisible_query_start.character += 1;
+        editor.update(cx, |editor, cx| {
+            let ranges = lsp_request_ranges.lock().drain(..).collect::<Vec<_>>();
+            assert_eq!(ranges.len(), 2,
+                "When scroll is at the edge of a big document, its visible part and the same range further should be queried in order, but got: {ranges:?}");
+            let visible_query_range = &ranges[0];
+            assert_eq!(visible_query_range.start, lsp_initial_visible_range.start);
+            assert_eq!(visible_query_range.end, lsp_initial_visible_range.end);
+            let invisible_query_range = &ranges[1];
+
+            assert_eq!(invisible_query_range.start, expected_invisible_query_start, "Should initially query visible edge of the document");
+            assert_eq!(invisible_query_range.end, expected_initial_query_range_end, "Should initially query visible edge of the document");
+
+            let requests_count = lsp_request_count.load(Ordering::Acquire);
+            assert_eq!(requests_count, 2, "Visible + invisible request");
+            let expected_hints = vec!["1".to_string(), "2".to_string()];
+            assert_eq!(
+                expected_hints,
+                cached_hint_labels(editor),
+                "Should have hints from both LSP requests made for a big file"
+            );
+            assert_eq!(expected_hints, visible_hint_labels(editor, cx), "Should display only hints from the visible range");
+            assert_eq!(
+                editor.inlay_hint_cache().version, requests_count,
+                "LSP queries should've bumped the cache version"
+            );
+        });
+
+        editor.update(cx, |editor, cx| {
+            editor.scroll_screen(&ScrollAmount::Page(1.0), cx);
+            editor.scroll_screen(&ScrollAmount::Page(1.0), cx);
+        });
+        cx.executor().advance_clock(Duration::from_millis(
+            INVISIBLE_RANGES_HINTS_REQUEST_DELAY_MILLIS + 100,
+        ));
+        cx.executor().run_until_parked();
+        let visible_range_after_scrolls = editor_visible_range(&editor, cx);
+        let visible_line_count = editor
+            .update(cx, |editor, _| editor.visible_line_count().unwrap())
+            .unwrap();
+        let selection_in_cached_range = editor
+            .update(cx, |editor, cx| {
+                let ranges = lsp_request_ranges
+                    .lock()
+                    .drain(..)
+                    .sorted_by_key(|r| r.start)
+                    .collect::<Vec<_>>();
+                assert_eq!(
+                    ranges.len(),
+                    2,
+                    "Should query 2 ranges after both scrolls, but got: {ranges:?}"
+                );
+                let first_scroll = &ranges[0];
+                let second_scroll = &ranges[1];
+                assert_eq!(
+                    first_scroll.end, second_scroll.start,
+                    "Should query 2 adjacent ranges after the scrolls, but got: {ranges:?}"
+                );
+                assert_eq!(
+                first_scroll.start, expected_initial_query_range_end,
+                "First scroll should start the query right after the end of the original scroll",
+            );
+                assert_eq!(
+                second_scroll.end,
+                lsp::Position::new(
+                    visible_range_after_scrolls.end.row
+                        + visible_line_count.ceil() as u32,
+                    1,
+                ),
+                "Second scroll should query one more screen down after the end of the visible range"
+            );
+
+                let lsp_requests = lsp_request_count.load(Ordering::Acquire);
+                assert_eq!(lsp_requests, 4, "Should query for hints after every scroll");
+                let expected_hints = vec![
+                    "1".to_string(),
+                    "2".to_string(),
+                    "3".to_string(),
+                    "4".to_string(),
+                ];
+                assert_eq!(
+                    expected_hints,
+                    cached_hint_labels(editor),
+                    "Should have hints from the new LSP response after the edit"
+                );
+                assert_eq!(expected_hints, visible_hint_labels(editor, cx));
+                assert_eq!(
+                    editor.inlay_hint_cache().version,
+                    lsp_requests,
+                    "Should update the cache for every LSP response with hints added"
+                );
+
+                let mut selection_in_cached_range = visible_range_after_scrolls.end;
+                selection_in_cached_range.row -= visible_line_count.ceil() as u32;
+                selection_in_cached_range
+            })
+            .unwrap();
+
+        editor.update(cx, |editor, cx| {
+            editor.change_selections(Some(Autoscroll::center()), cx, |s| {
+                s.select_ranges([selection_in_cached_range..selection_in_cached_range])
+            });
+        });
+        cx.executor().advance_clock(Duration::from_millis(
+            INVISIBLE_RANGES_HINTS_REQUEST_DELAY_MILLIS + 100,
+        ));
+        cx.executor().run_until_parked();
+        editor.update(cx, |_, _| {
+            let ranges = lsp_request_ranges
+                .lock()
+                .drain(..)
+                .sorted_by_key(|r| r.start)
+                .collect::<Vec<_>>();
+            assert!(ranges.is_empty(), "No new ranges or LSP queries should be made after returning to the selection with cached hints");
+            assert_eq!(lsp_request_count.load(Ordering::Acquire), 4);
+        });
+
+        editor.update(cx, |editor, cx| {
+            editor.handle_input("++++more text++++", cx);
+        });
+        cx.executor().advance_clock(Duration::from_millis(
+            INVISIBLE_RANGES_HINTS_REQUEST_DELAY_MILLIS + 100,
+        ));
+        cx.executor().run_until_parked();
+        editor.update(cx, |editor, cx| {
+            let mut ranges = lsp_request_ranges.lock().drain(..).collect::<Vec<_>>();
+            ranges.sort_by_key(|r| r.start);
+
+            assert_eq!(ranges.len(), 3,
+                "On edit, should scroll to selection and query a range around it: visible + same range above and below. Instead, got query ranges {ranges:?}");
+            let above_query_range = &ranges[0];
+            let visible_query_range = &ranges[1];
+            let below_query_range = &ranges[2];
+            assert!(above_query_range.end.character < visible_query_range.start.character || above_query_range.end.line + 1 == visible_query_range.start.line,
+                "Above range {above_query_range:?} should be before visible range {visible_query_range:?}");
+            assert!(visible_query_range.end.character < below_query_range.start.character || visible_query_range.end.line  + 1 == below_query_range.start.line,
+                "Visible range {visible_query_range:?} should be before below range {below_query_range:?}");
+            assert!(above_query_range.start.line < selection_in_cached_range.row,
+                "Hints should be queried with the selected range after the query range start");
+            assert!(below_query_range.end.line > selection_in_cached_range.row,
+                "Hints should be queried with the selected range before the query range end");
+            assert!(above_query_range.start.line <= selection_in_cached_range.row - (visible_line_count * 3.0 / 2.0) as u32,
+                "Hints query range should contain one more screen before");
+            assert!(below_query_range.end.line >= selection_in_cached_range.row + (visible_line_count * 3.0 / 2.0) as u32,
+                "Hints query range should contain one more screen after");
+
+            let lsp_requests = lsp_request_count.load(Ordering::Acquire);
+            assert_eq!(lsp_requests, 7, "There should be a visible range and two ranges above and below it queried");
+            let expected_hints = vec!["5".to_string(), "6".to_string(), "7".to_string()];
+            assert_eq!(expected_hints, cached_hint_labels(editor),
+                "Should have hints from the new LSP response after the edit");
+            assert_eq!(expected_hints, visible_hint_labels(editor, cx));
+            assert_eq!(editor.inlay_hint_cache().version, lsp_requests, "Should update the cache for every LSP response with hints added");
+        });
+    }
+
+    #[gpui::test(iterations = 10)]
+    async fn test_multiple_excerpts_large_multibuffer(cx: &mut gpui::TestAppContext) {
+        init_test(cx, |settings| {
+            settings.defaults.inlay_hints = Some(InlayHintSettings {
+                enabled: true,
+                show_type_hints: true,
+                show_parameter_hints: true,
+                show_other_hints: true,
+            })
+        });
+
+        let mut language = Language::new(
+            LanguageConfig {
+                name: "Rust".into(),
+                path_suffixes: vec!["rs".to_string()],
+                ..Default::default()
+            },
+            Some(tree_sitter_rust::language()),
+        );
+        let mut fake_servers = language
+            .set_fake_lsp_adapter(Arc::new(FakeLspAdapter {
+                capabilities: lsp::ServerCapabilities {
+                    inlay_hint_provider: Some(lsp::OneOf::Left(true)),
+                    ..Default::default()
+                },
+                ..Default::default()
+            }))
+            .await;
+        let language = Arc::new(language);
+        let fs = FakeFs::new(cx.background_executor.clone());
+        fs.insert_tree(
+            "/a",
+            json!({
+                "main.rs": format!("fn main() {{\n{}\n}}", (0..501).map(|i| format!("let i = {i};\n")).collect::<Vec<_>>().join("")),
+                "other.rs": format!("fn main() {{\n{}\n}}", (0..501).map(|j| format!("let j = {j};\n")).collect::<Vec<_>>().join("")),
+            }),
+        )
+        .await;
+        let project = Project::test(fs, ["/a".as_ref()], cx).await;
+        project.update(cx, |project, _| {
+            project.languages().add(Arc::clone(&language))
+        });
+        let worktree_id = project.update(cx, |project, cx| {
+            project.worktrees().next().unwrap().read(cx).id()
+        });
+
+        let buffer_1 = project
+            .update(cx, |project, cx| {
+                project.open_buffer((worktree_id, "main.rs"), cx)
+            })
+            .await
+            .unwrap();
+        let buffer_2 = project
+            .update(cx, |project, cx| {
+                project.open_buffer((worktree_id, "other.rs"), cx)
+            })
+            .await
+            .unwrap();
+        let multibuffer = cx.build_model(|cx| {
+            let mut multibuffer = MultiBuffer::new(0);
+            multibuffer.push_excerpts(
+                buffer_1.clone(),
+                [
+                    ExcerptRange {
+                        context: Point::new(0, 0)..Point::new(2, 0),
+                        primary: None,
+                    },
+                    ExcerptRange {
+                        context: Point::new(4, 0)..Point::new(11, 0),
+                        primary: None,
+                    },
+                    ExcerptRange {
+                        context: Point::new(22, 0)..Point::new(33, 0),
+                        primary: None,
+                    },
+                    ExcerptRange {
+                        context: Point::new(44, 0)..Point::new(55, 0),
+                        primary: None,
+                    },
+                    ExcerptRange {
+                        context: Point::new(56, 0)..Point::new(66, 0),
+                        primary: None,
+                    },
+                    ExcerptRange {
+                        context: Point::new(67, 0)..Point::new(77, 0),
+                        primary: None,
+                    },
+                ],
+                cx,
+            );
+            multibuffer.push_excerpts(
+                buffer_2.clone(),
+                [
+                    ExcerptRange {
+                        context: Point::new(0, 1)..Point::new(2, 1),
+                        primary: None,
+                    },
+                    ExcerptRange {
+                        context: Point::new(4, 1)..Point::new(11, 1),
+                        primary: None,
+                    },
+                    ExcerptRange {
+                        context: Point::new(22, 1)..Point::new(33, 1),
+                        primary: None,
+                    },
+                    ExcerptRange {
+                        context: Point::new(44, 1)..Point::new(55, 1),
+                        primary: None,
+                    },
+                    ExcerptRange {
+                        context: Point::new(56, 1)..Point::new(66, 1),
+                        primary: None,
+                    },
+                    ExcerptRange {
+                        context: Point::new(67, 1)..Point::new(77, 1),
+                        primary: None,
+                    },
+                ],
+                cx,
+            );
+            multibuffer
+        });
+
+        cx.executor().run_until_parked();
+        let editor =
+            cx.add_window(|cx| Editor::for_multibuffer(multibuffer, Some(project.clone()), cx));
+        let editor_edited = Arc::new(AtomicBool::new(false));
+        let fake_server = fake_servers.next().await.unwrap();
+        let closure_editor_edited = Arc::clone(&editor_edited);
+        fake_server
+            .handle_request::<lsp::request::InlayHintRequest, _, _>(move |params, _| {
+                let task_editor_edited = Arc::clone(&closure_editor_edited);
+                async move {
+                    let hint_text = if params.text_document.uri
+                        == lsp::Url::from_file_path("/a/main.rs").unwrap()
+                    {
+                        "main hint"
+                    } else if params.text_document.uri
+                        == lsp::Url::from_file_path("/a/other.rs").unwrap()
+                    {
+                        "other hint"
+                    } else {
+                        panic!("unexpected uri: {:?}", params.text_document.uri);
+                    };
+
+                    // one hint per excerpt
+                    let positions = [
+                        lsp::Position::new(0, 2),
+                        lsp::Position::new(4, 2),
+                        lsp::Position::new(22, 2),
+                        lsp::Position::new(44, 2),
+                        lsp::Position::new(56, 2),
+                        lsp::Position::new(67, 2),
+                    ];
+                    let out_of_range_hint = lsp::InlayHint {
+                        position: lsp::Position::new(
+                            params.range.start.line + 99,
+                            params.range.start.character + 99,
+                        ),
+                        label: lsp::InlayHintLabel::String(
+                            "out of excerpt range, should be ignored".to_string(),
+                        ),
+                        kind: None,
+                        text_edits: None,
+                        tooltip: None,
+                        padding_left: None,
+                        padding_right: None,
+                        data: None,
+                    };
+
+                    let edited = task_editor_edited.load(Ordering::Acquire);
+                    Ok(Some(
+                        std::iter::once(out_of_range_hint)
+                            .chain(positions.into_iter().enumerate().map(|(i, position)| {
+                                lsp::InlayHint {
+                                    position,
+                                    label: lsp::InlayHintLabel::String(format!(
+                                        "{hint_text}{} #{i}",
+                                        if edited { "(edited)" } else { "" },
+                                    )),
+                                    kind: None,
+                                    text_edits: None,
+                                    tooltip: None,
+                                    padding_left: None,
+                                    padding_right: None,
+                                    data: None,
+                                }
+                            }))
+                            .collect(),
+                    ))
+                }
+            })
+            .next()
+            .await;
+        cx.executor().run_until_parked();
+
+        editor.update(cx, |editor, cx| {
+            let expected_hints = vec![
+                "main hint #0".to_string(),
+                "main hint #1".to_string(),
+                "main hint #2".to_string(),
+                "main hint #3".to_string(),
+                // todo!() there used to be no these hints, but new gpui2 presumably scrolls a bit farther
+                // (or renders less?) note that tests below pass
+                "main hint #4".to_string(),
+                "main hint #5".to_string(),
+            ];
+            assert_eq!(
+                expected_hints,
+                cached_hint_labels(editor),
+                "When scroll is at the edge of a multibuffer, its visible excerpts only should be queried for inlay hints"
+            );
+            assert_eq!(expected_hints, visible_hint_labels(editor, cx));
+            assert_eq!(editor.inlay_hint_cache().version, expected_hints.len(), "Every visible excerpt hints should bump the verison");
+        });
+
+        editor.update(cx, |editor, cx| {
+            editor.change_selections(Some(Autoscroll::Next), cx, |s| {
+                s.select_ranges([Point::new(4, 0)..Point::new(4, 0)])
+            });
+            editor.change_selections(Some(Autoscroll::Next), cx, |s| {
+                s.select_ranges([Point::new(22, 0)..Point::new(22, 0)])
+            });
+            editor.change_selections(Some(Autoscroll::Next), cx, |s| {
+                s.select_ranges([Point::new(50, 0)..Point::new(50, 0)])
+            });
+        });
+        cx.executor().run_until_parked();
+        editor.update(cx, |editor, cx| {
+            let expected_hints = vec![
+                "main hint #0".to_string(),
+                "main hint #1".to_string(),
+                "main hint #2".to_string(),
+                "main hint #3".to_string(),
+                "main hint #4".to_string(),
+                "main hint #5".to_string(),
+                "other hint #0".to_string(),
+                "other hint #1".to_string(),
+                "other hint #2".to_string(),
+            ];
+            assert_eq!(expected_hints, cached_hint_labels(editor),
+                "With more scrolls of the multibuffer, more hints should be added into the cache and nothing invalidated without edits");
+            assert_eq!(expected_hints, visible_hint_labels(editor, cx));
+            assert_eq!(editor.inlay_hint_cache().version, expected_hints.len(),
+                "Due to every excerpt having one hint, we update cache per new excerpt scrolled");
+        });
+
+        editor.update(cx, |editor, cx| {
+            editor.change_selections(Some(Autoscroll::Next), cx, |s| {
+                s.select_ranges([Point::new(100, 0)..Point::new(100, 0)])
+            });
+        });
+        cx.executor().advance_clock(Duration::from_millis(
+            INVISIBLE_RANGES_HINTS_REQUEST_DELAY_MILLIS + 100,
+        ));
+        cx.executor().run_until_parked();
+        let last_scroll_update_version = editor.update(cx, |editor, cx| {
+            let expected_hints = vec![
+                "main hint #0".to_string(),
+                "main hint #1".to_string(),
+                "main hint #2".to_string(),
+                "main hint #3".to_string(),
+                "main hint #4".to_string(),
+                "main hint #5".to_string(),
+                "other hint #0".to_string(),
+                "other hint #1".to_string(),
+                "other hint #2".to_string(),
+                "other hint #3".to_string(),
+                "other hint #4".to_string(),
+                "other hint #5".to_string(),
+            ];
+            assert_eq!(expected_hints, cached_hint_labels(editor),
+                "After multibuffer was scrolled to the end, all hints for all excerpts should be fetched");
+            assert_eq!(expected_hints, visible_hint_labels(editor, cx));
+            assert_eq!(editor.inlay_hint_cache().version, expected_hints.len());
+            expected_hints.len()
+        }).unwrap();
+
+        editor.update(cx, |editor, cx| {
+            editor.change_selections(Some(Autoscroll::Next), cx, |s| {
+                s.select_ranges([Point::new(4, 0)..Point::new(4, 0)])
+            });
+        });
+        cx.executor().run_until_parked();
+        editor.update(cx, |editor, cx| {
+            let expected_hints = vec![
+                "main hint #0".to_string(),
+                "main hint #1".to_string(),
+                "main hint #2".to_string(),
+                "main hint #3".to_string(),
+                "main hint #4".to_string(),
+                "main hint #5".to_string(),
+                "other hint #0".to_string(),
+                "other hint #1".to_string(),
+                "other hint #2".to_string(),
+                "other hint #3".to_string(),
+                "other hint #4".to_string(),
+                "other hint #5".to_string(),
+            ];
+            assert_eq!(expected_hints, cached_hint_labels(editor),
+                "After multibuffer was scrolled to the end, further scrolls up should not bring more hints");
+            assert_eq!(expected_hints, visible_hint_labels(editor, cx));
+            assert_eq!(editor.inlay_hint_cache().version, last_scroll_update_version, "No updates should happen during scrolling already scolled buffer");
+        });
+
+        editor_edited.store(true, Ordering::Release);
+        editor.update(cx, |editor, cx| {
+            editor.change_selections(None, cx, |s| {
+                s.select_ranges([Point::new(56, 0)..Point::new(56, 0)])
+            });
+            editor.handle_input("++++more text++++", cx);
+        });
+        cx.executor().run_until_parked();
+        editor.update(cx, |editor, cx| {
+            let expected_hints = vec![
+                "main hint(edited) #0".to_string(),
+                "main hint(edited) #1".to_string(),
+                "main hint(edited) #2".to_string(),
+                "main hint(edited) #3".to_string(),
+                "main hint(edited) #4".to_string(),
+                "main hint(edited) #5".to_string(),
+                "other hint(edited) #0".to_string(),
+                "other hint(edited) #1".to_string(),
+            ];
+            assert_eq!(
+                expected_hints,
+                cached_hint_labels(editor),
+                "After multibuffer edit, editor gets scolled back to the last selection; \
+all hints should be invalidated and requeried for all of its visible excerpts"
+            );
+            assert_eq!(expected_hints, visible_hint_labels(editor, cx));
+
+            let current_cache_version = editor.inlay_hint_cache().version;
+            let minimum_expected_version = last_scroll_update_version + expected_hints.len();
+            assert!(
+                current_cache_version == minimum_expected_version || current_cache_version == minimum_expected_version + 1,
+                "Due to every excerpt having one hint, cache should update per new excerpt received + 1 potential sporadic update"
+            );
+        });
+    }
+
+    #[gpui::test]
+    async fn test_excerpts_removed(cx: &mut gpui::TestAppContext) {
+        init_test(cx, |settings| {
+            settings.defaults.inlay_hints = Some(InlayHintSettings {
+                enabled: true,
+                show_type_hints: false,
+                show_parameter_hints: false,
+                show_other_hints: false,
+            })
+        });
+
+        let mut language = Language::new(
+            LanguageConfig {
+                name: "Rust".into(),
+                path_suffixes: vec!["rs".to_string()],
+                ..Default::default()
+            },
+            Some(tree_sitter_rust::language()),
+        );
+        let mut fake_servers = language
+            .set_fake_lsp_adapter(Arc::new(FakeLspAdapter {
+                capabilities: lsp::ServerCapabilities {
+                    inlay_hint_provider: Some(lsp::OneOf::Left(true)),
+                    ..Default::default()
+                },
+                ..Default::default()
+            }))
+            .await;
+        let language = Arc::new(language);
+        let fs = FakeFs::new(cx.background_executor.clone());
+        fs.insert_tree(
+            "/a",
+            json!({
+                "main.rs": format!("fn main() {{\n{}\n}}", (0..501).map(|i| format!("let i = {i};\n")).collect::<Vec<_>>().join("")),
+                "other.rs": format!("fn main() {{\n{}\n}}", (0..501).map(|j| format!("let j = {j};\n")).collect::<Vec<_>>().join("")),
+            }),
+        )
+        .await;
+        let project = Project::test(fs, ["/a".as_ref()], cx).await;
+        project.update(cx, |project, _| {
+            project.languages().add(Arc::clone(&language))
+        });
+        let worktree_id = project.update(cx, |project, cx| {
+            project.worktrees().next().unwrap().read(cx).id()
+        });
+
+        let buffer_1 = project
+            .update(cx, |project, cx| {
+                project.open_buffer((worktree_id, "main.rs"), cx)
+            })
+            .await
+            .unwrap();
+        let buffer_2 = project
+            .update(cx, |project, cx| {
+                project.open_buffer((worktree_id, "other.rs"), cx)
+            })
+            .await
+            .unwrap();
+        let multibuffer = cx.build_model(|_| MultiBuffer::new(0));
+        let (buffer_1_excerpts, buffer_2_excerpts) = multibuffer.update(cx, |multibuffer, cx| {
+            let buffer_1_excerpts = multibuffer.push_excerpts(
+                buffer_1.clone(),
+                [ExcerptRange {
+                    context: Point::new(0, 0)..Point::new(2, 0),
+                    primary: None,
+                }],
+                cx,
+            );
+            let buffer_2_excerpts = multibuffer.push_excerpts(
+                buffer_2.clone(),
+                [ExcerptRange {
+                    context: Point::new(0, 1)..Point::new(2, 1),
+                    primary: None,
+                }],
+                cx,
+            );
+            (buffer_1_excerpts, buffer_2_excerpts)
+        });
+
+        assert!(!buffer_1_excerpts.is_empty());
+        assert!(!buffer_2_excerpts.is_empty());
+
+        cx.executor().run_until_parked();
+        let editor =
+            cx.add_window(|cx| Editor::for_multibuffer(multibuffer, Some(project.clone()), cx));
+        let editor_edited = Arc::new(AtomicBool::new(false));
+        let fake_server = fake_servers.next().await.unwrap();
+        let closure_editor_edited = Arc::clone(&editor_edited);
+        fake_server
+            .handle_request::<lsp::request::InlayHintRequest, _, _>(move |params, _| {
+                let task_editor_edited = Arc::clone(&closure_editor_edited);
+                async move {
+                    let hint_text = if params.text_document.uri
+                        == lsp::Url::from_file_path("/a/main.rs").unwrap()
+                    {
+                        "main hint"
+                    } else if params.text_document.uri
+                        == lsp::Url::from_file_path("/a/other.rs").unwrap()
+                    {
+                        "other hint"
+                    } else {
+                        panic!("unexpected uri: {:?}", params.text_document.uri);
+                    };
+
+                    let positions = [
+                        lsp::Position::new(0, 2),
+                        lsp::Position::new(4, 2),
+                        lsp::Position::new(22, 2),
+                        lsp::Position::new(44, 2),
+                        lsp::Position::new(56, 2),
+                        lsp::Position::new(67, 2),
+                    ];
+                    let out_of_range_hint = lsp::InlayHint {
+                        position: lsp::Position::new(
+                            params.range.start.line + 99,
+                            params.range.start.character + 99,
+                        ),
+                        label: lsp::InlayHintLabel::String(
+                            "out of excerpt range, should be ignored".to_string(),
+                        ),
+                        kind: None,
+                        text_edits: None,
+                        tooltip: None,
+                        padding_left: None,
+                        padding_right: None,
+                        data: None,
+                    };
+
+                    let edited = task_editor_edited.load(Ordering::Acquire);
+                    Ok(Some(
+                        std::iter::once(out_of_range_hint)
+                            .chain(positions.into_iter().enumerate().map(|(i, position)| {
+                                lsp::InlayHint {
+                                    position,
+                                    label: lsp::InlayHintLabel::String(format!(
+                                        "{hint_text}{} #{i}",
+                                        if edited { "(edited)" } else { "" },
+                                    )),
+                                    kind: None,
+                                    text_edits: None,
+                                    tooltip: None,
+                                    padding_left: None,
+                                    padding_right: None,
+                                    data: None,
+                                }
+                            }))
+                            .collect(),
+                    ))
+                }
+            })
+            .next()
+            .await;
+        cx.executor().run_until_parked();
+
+        editor.update(cx, |editor, cx| {
+            assert_eq!(
+                vec!["main hint #0".to_string(), "other hint #0".to_string()],
+                cached_hint_labels(editor),
+                "Cache should update for both excerpts despite hints display was disabled"
+            );
+            assert!(
+                visible_hint_labels(editor, cx).is_empty(),
+                "All hints are disabled and should not be shown despite being present in the cache"
+            );
+            assert_eq!(
+                editor.inlay_hint_cache().version,
+                2,
+                "Cache should update once per excerpt query"
+            );
+        });
+
+        editor.update(cx, |editor, cx| {
+            editor.buffer().update(cx, |multibuffer, cx| {
+                multibuffer.remove_excerpts(buffer_2_excerpts, cx)
+            })
+        });
+        cx.executor().run_until_parked();
+        editor.update(cx, |editor, cx| {
+            assert_eq!(
+                vec!["main hint #0".to_string()],
+                cached_hint_labels(editor),
+                "For the removed excerpt, should clean corresponding cached hints"
+            );
+            assert!(
+                visible_hint_labels(editor, cx).is_empty(),
+                "All hints are disabled and should not be shown despite being present in the cache"
+            );
+            assert_eq!(
+                editor.inlay_hint_cache().version,
+                3,
+                "Excerpt removal should trigger a cache update"
+            );
+        });
+
+        update_test_language_settings(cx, |settings| {
+            settings.defaults.inlay_hints = Some(InlayHintSettings {
+                enabled: true,
+                show_type_hints: true,
+                show_parameter_hints: true,
+                show_other_hints: true,
+            })
+        });
+        cx.executor().run_until_parked();
+        editor.update(cx, |editor, cx| {
+            let expected_hints = vec!["main hint #0".to_string()];
+            assert_eq!(
+                expected_hints,
+                cached_hint_labels(editor),
+                "Hint display settings change should not change the cache"
+            );
+            assert_eq!(
+                expected_hints,
+                visible_hint_labels(editor, cx),
+                "Settings change should make cached hints visible"
+            );
+            assert_eq!(
+                editor.inlay_hint_cache().version,
+                4,
+                "Settings change should trigger a cache update"
+            );
+        });
+    }
+
+    #[gpui::test]
+    async fn test_inside_char_boundary_range_hints(cx: &mut gpui::TestAppContext) {
+        init_test(cx, |settings| {
+            settings.defaults.inlay_hints = Some(InlayHintSettings {
+                enabled: true,
+                show_type_hints: true,
+                show_parameter_hints: true,
+                show_other_hints: true,
+            })
+        });
+
+        let mut language = Language::new(
+            LanguageConfig {
+                name: "Rust".into(),
+                path_suffixes: vec!["rs".to_string()],
+                ..Default::default()
+            },
+            Some(tree_sitter_rust::language()),
+        );
+        let mut fake_servers = language
+            .set_fake_lsp_adapter(Arc::new(FakeLspAdapter {
+                capabilities: lsp::ServerCapabilities {
+                    inlay_hint_provider: Some(lsp::OneOf::Left(true)),
+                    ..Default::default()
+                },
+                ..Default::default()
+            }))
+            .await;
+        let fs = FakeFs::new(cx.background_executor.clone());
+        fs.insert_tree(
+            "/a",
+            json!({
+                "main.rs": format!(r#"fn main() {{\n{}\n}}"#, format!("let i = {};\n", "√".repeat(10)).repeat(500)),
+                "other.rs": "// Test file",
+            }),
+        )
+        .await;
+        let project = Project::test(fs, ["/a".as_ref()], cx).await;
+        project.update(cx, |project, _| project.languages().add(Arc::new(language)));
+        let buffer = project
+            .update(cx, |project, cx| {
+                project.open_local_buffer("/a/main.rs", cx)
+            })
+            .await
+            .unwrap();
+        cx.executor().run_until_parked();
+        cx.executor().start_waiting();
+        let fake_server = fake_servers.next().await.unwrap();
+        let editor = cx.add_window(|cx| Editor::for_buffer(buffer, Some(project), cx));
+        let lsp_request_count = Arc::new(AtomicU32::new(0));
+        let closure_lsp_request_count = Arc::clone(&lsp_request_count);
+        fake_server
+            .handle_request::<lsp::request::InlayHintRequest, _, _>(move |params, _| {
+                let task_lsp_request_count = Arc::clone(&closure_lsp_request_count);
+                async move {
+                    assert_eq!(
+                        params.text_document.uri,
+                        lsp::Url::from_file_path("/a/main.rs").unwrap(),
+                    );
+                    let query_start = params.range.start;
+                    let i = Arc::clone(&task_lsp_request_count).fetch_add(1, Ordering::Release) + 1;
+                    Ok(Some(vec![lsp::InlayHint {
+                        position: query_start,
+                        label: lsp::InlayHintLabel::String(i.to_string()),
+                        kind: None,
+                        text_edits: None,
+                        tooltip: None,
+                        padding_left: None,
+                        padding_right: None,
+                        data: None,
+                    }]))
+                }
+            })
+            .next()
+            .await;
+
+        cx.executor().run_until_parked();
+        editor.update(cx, |editor, cx| {
+            editor.change_selections(None, cx, |s| {
+                s.select_ranges([Point::new(10, 0)..Point::new(10, 0)])
+            })
+        });
+        cx.executor().run_until_parked();
+        editor.update(cx, |editor, cx| {
+            let expected_hints = vec!["1".to_string()];
+            assert_eq!(expected_hints, cached_hint_labels(editor));
+            assert_eq!(expected_hints, visible_hint_labels(editor, cx));
+            assert_eq!(editor.inlay_hint_cache().version, 1);
+        });
+    }
+
+    #[gpui::test]
+    async fn test_toggle_inlay_hints(cx: &mut gpui::TestAppContext) {
+        init_test(cx, |settings| {
+            settings.defaults.inlay_hints = Some(InlayHintSettings {
+                enabled: false,
+                show_type_hints: true,
+                show_parameter_hints: true,
+                show_other_hints: true,
+            })
+        });
+
+        let (file_with_hints, editor, fake_server) = prepare_test_objects(cx).await;
+
+        editor.update(cx, |editor, cx| {
+            editor.toggle_inlay_hints(&crate::ToggleInlayHints, cx)
+        });
+        cx.executor().start_waiting();
+        let lsp_request_count = Arc::new(AtomicU32::new(0));
+        let closure_lsp_request_count = Arc::clone(&lsp_request_count);
+        fake_server
+            .handle_request::<lsp::request::InlayHintRequest, _, _>(move |params, _| {
+                let task_lsp_request_count = Arc::clone(&closure_lsp_request_count);
+                async move {
+                    assert_eq!(
+                        params.text_document.uri,
+                        lsp::Url::from_file_path(file_with_hints).unwrap(),
+                    );
+
+                    let i = Arc::clone(&task_lsp_request_count).fetch_add(1, Ordering::SeqCst) + 1;
+                    Ok(Some(vec![lsp::InlayHint {
+                        position: lsp::Position::new(0, i),
+                        label: lsp::InlayHintLabel::String(i.to_string()),
+                        kind: None,
+                        text_edits: None,
+                        tooltip: None,
+                        padding_left: None,
+                        padding_right: None,
+                        data: None,
+                    }]))
+                }
+            })
+            .next()
+            .await;
+        cx.executor().run_until_parked();
+        editor.update(cx, |editor, cx| {
+            let expected_hints = vec!["1".to_string()];
+            assert_eq!(
+                expected_hints,
+                cached_hint_labels(editor),
+                "Should display inlays after toggle despite them disabled in settings"
+            );
+            assert_eq!(expected_hints, visible_hint_labels(editor, cx));
+            assert_eq!(
+                editor.inlay_hint_cache().version,
+                1,
+                "First toggle should be cache's first update"
+            );
+        });
+
+        editor.update(cx, |editor, cx| {
+            editor.toggle_inlay_hints(&crate::ToggleInlayHints, cx)
+        });
+        cx.executor().run_until_parked();
+        editor.update(cx, |editor, cx| {
+            assert!(
+                cached_hint_labels(editor).is_empty(),
+                "Should clear hints after 2nd toggle"
+            );
+            assert!(visible_hint_labels(editor, cx).is_empty());
+            assert_eq!(editor.inlay_hint_cache().version, 2);
+        });
+
+        update_test_language_settings(cx, |settings| {
+            settings.defaults.inlay_hints = Some(InlayHintSettings {
+                enabled: true,
+                show_type_hints: true,
+                show_parameter_hints: true,
+                show_other_hints: true,
+            })
+        });
+        cx.executor().run_until_parked();
+        editor.update(cx, |editor, cx| {
+            let expected_hints = vec!["2".to_string()];
+            assert_eq!(
+                expected_hints,
+                cached_hint_labels(editor),
+                "Should query LSP hints for the 2nd time after enabling hints in settings"
+            );
+            assert_eq!(expected_hints, visible_hint_labels(editor, cx));
+            assert_eq!(editor.inlay_hint_cache().version, 3);
+        });
+
+        editor.update(cx, |editor, cx| {
+            editor.toggle_inlay_hints(&crate::ToggleInlayHints, cx)
+        });
+        cx.executor().run_until_parked();
+        editor.update(cx, |editor, cx| {
+            assert!(
+                cached_hint_labels(editor).is_empty(),
+                "Should clear hints after enabling in settings and a 3rd toggle"
+            );
+            assert!(visible_hint_labels(editor, cx).is_empty());
+            assert_eq!(editor.inlay_hint_cache().version, 4);
+        });
+
+        editor.update(cx, |editor, cx| {
+            editor.toggle_inlay_hints(&crate::ToggleInlayHints, cx)
+        });
+        cx.executor().run_until_parked();
+        editor.update(cx, |editor, cx| {
+            let expected_hints = vec!["3".to_string()];
+            assert_eq!(
+                expected_hints,
+                cached_hint_labels(editor),
+                "Should query LSP hints for the 3rd time after enabling hints in settings and toggling them back on"
+            );
+            assert_eq!(expected_hints, visible_hint_labels(editor, cx));
+            assert_eq!(editor.inlay_hint_cache().version, 5);
+        });
+    }
+
+    pub(crate) fn init_test(cx: &mut TestAppContext, f: impl Fn(&mut AllLanguageSettingsContent)) {
+        cx.update(|cx| {
+            let settings_store = SettingsStore::test(cx);
+            cx.set_global(settings_store);
+            theme::init(cx);
+            client::init_settings(cx);
+            language::init(cx);
+            Project::init_settings(cx);
+            workspace::init_settings(cx);
+            crate::init(cx);
+        });
+
+        update_test_language_settings(cx, f);
+    }
+
+    async fn prepare_test_objects(
+        cx: &mut TestAppContext,
+    ) -> (&'static str, WindowHandle<Editor>, FakeLanguageServer) {
+        let mut language = Language::new(
+            LanguageConfig {
+                name: "Rust".into(),
+                path_suffixes: vec!["rs".to_string()],
+                ..Default::default()
+            },
+            Some(tree_sitter_rust::language()),
+        );
+        let mut fake_servers = language
+            .set_fake_lsp_adapter(Arc::new(FakeLspAdapter {
+                capabilities: lsp::ServerCapabilities {
+                    inlay_hint_provider: Some(lsp::OneOf::Left(true)),
+                    ..Default::default()
+                },
+                ..Default::default()
+            }))
+            .await;
+
+        let fs = FakeFs::new(cx.background_executor.clone());
+        fs.insert_tree(
+            "/a",
+            json!({
+                "main.rs": "fn main() { a } // and some long comment to ensure inlays are not trimmed out",
+                "other.rs": "// Test file",
+            }),
+        )
+        .await;
+
+        let project = Project::test(fs, ["/a".as_ref()], cx).await;
+        project.update(cx, |project, _| project.languages().add(Arc::new(language)));
+        let buffer = project
+            .update(cx, |project, cx| {
+                project.open_local_buffer("/a/main.rs", cx)
+            })
+            .await
+            .unwrap();
+        cx.executor().run_until_parked();
+        cx.executor().start_waiting();
+        let fake_server = fake_servers.next().await.unwrap();
+        let editor = cx.add_window(|cx| Editor::for_buffer(buffer, Some(project), cx));
+
+        editor.update(cx, |editor, cx| {
+            assert!(cached_hint_labels(editor).is_empty());
+            assert!(visible_hint_labels(editor, cx).is_empty());
+            assert_eq!(editor.inlay_hint_cache().version, 0);
+        });
+
+        ("/a/main.rs", editor, fake_server)
+    }
+
+    pub fn cached_hint_labels(editor: &Editor) -> Vec<String> {
+        let mut labels = Vec::new();
+        for (_, excerpt_hints) in &editor.inlay_hint_cache().hints {
+            let excerpt_hints = excerpt_hints.read();
+            for id in &excerpt_hints.ordered_hints {
+                labels.push(excerpt_hints.hints_by_id[id].text());
+            }
+        }
+
+        labels.sort();
+        labels
+    }
+
+    pub fn visible_hint_labels(editor: &Editor, cx: &ViewContext<'_, Editor>) -> Vec<String> {
+        let mut hints = editor
+            .visible_inlay_hints(cx)
+            .into_iter()
+            .map(|hint| hint.text.to_string())
+            .collect::<Vec<_>>();
+        hints.sort();
+        hints
+    }
 }
-//     let cached_excerpt_hints = editor
-//         .inlay_hint_cache
-//         .hints
-//         .entry(new_update.excerpt_id)
-//         .or_insert_with(|| {
-//             Arc::new(RwLock::new(CachedExcerptHints {
-//                 version: query.cache_version,
-//                 buffer_version: buffer_snapshot.version().clone(),
-//                 buffer_id: query.buffer_id,
-//                 ordered_hints: Vec::new(),
-//                 hints_by_id: HashMap::default(),
-//             }))
-//         });
-//     let mut cached_excerpt_hints = cached_excerpt_hints.write();
-//     match query.cache_version.cmp(&cached_excerpt_hints.version) {
-//         cmp::Ordering::Less => return,
-//         cmp::Ordering::Greater | cmp::Ordering::Equal => {
-//             cached_excerpt_hints.version = query.cache_version;
-//         }
-//     }
-
-//     let mut cached_inlays_changed = !new_update.remove_from_cache.is_empty();
-//     cached_excerpt_hints
-//         .ordered_hints
-//         .retain(|hint_id| !new_update.remove_from_cache.contains(hint_id));
-//     cached_excerpt_hints
-//         .hints_by_id
-//         .retain(|hint_id, _| !new_update.remove_from_cache.contains(hint_id));
-//     let mut splice = InlaySplice {
-//         to_remove: new_update.remove_from_visible,
-//         to_insert: Vec::new(),
-//     };
-//     for new_hint in new_update.add_to_cache {
-//         let insert_position = match cached_excerpt_hints
-//             .ordered_hints
-//             .binary_search_by(|probe| {
-//                 cached_excerpt_hints.hints_by_id[probe]
-//                     .position
-//                     .cmp(&new_hint.position, &buffer_snapshot)
-//             }) {
-//             Ok(i) => {
-//                 let mut insert_position = Some(i);
-//                 for id in &cached_excerpt_hints.ordered_hints[i..] {
-//                     let cached_hint = &cached_excerpt_hints.hints_by_id[id];
-//                     if new_hint
-//                         .position
-//                         .cmp(&cached_hint.position, &buffer_snapshot)
-//                         .is_gt()
-//                     {
-//                         break;
-//                     }
-//                     if cached_hint.text() == new_hint.text() {
-//                         insert_position = None;
-//                         break;
-//                     }
-//                 }
-//                 insert_position
-//             }
-//             Err(i) => Some(i),
-//         };
-
-//         if let Some(insert_position) = insert_position {
-//             let new_inlay_id = post_inc(&mut editor.next_inlay_id);
-//             if editor
-//                 .inlay_hint_cache
-//                 .allowed_hint_kinds
-//                 .contains(&new_hint.kind)
-//             {
-//                 let new_hint_position =
-//                     multi_buffer_snapshot.anchor_in_excerpt(query.excerpt_id, new_hint.position);
-//                 splice
-//                     .to_insert
-//                     .push(Inlay::hint(new_inlay_id, new_hint_position, &new_hint));
-//             }
-//             let new_id = InlayId::Hint(new_inlay_id);
-//             cached_excerpt_hints.hints_by_id.insert(new_id, new_hint);
-//             cached_excerpt_hints
-//                 .ordered_hints
-//                 .insert(insert_position, new_id);
-//             cached_inlays_changed = true;
-//         }
-//     }
-//     cached_excerpt_hints.buffer_version = buffer_snapshot.version().clone();
-//     drop(cached_excerpt_hints);
-
-//     if invalidate {
-//         let mut outdated_excerpt_caches = HashSet::default();
-//         for (excerpt_id, excerpt_hints) in &editor.inlay_hint_cache().hints {
-//             let excerpt_hints = excerpt_hints.read();
-//             if excerpt_hints.buffer_id == query.buffer_id
-//                 && excerpt_id != &query.excerpt_id
-//                 && buffer_snapshot
-//                     .version()
-//                     .changed_since(&excerpt_hints.buffer_version)
-//             {
-//                 outdated_excerpt_caches.insert(*excerpt_id);
-//                 splice
-//                     .to_remove
-//                     .extend(excerpt_hints.ordered_hints.iter().copied());
-//             }
-//         }
-//         cached_inlays_changed |= !outdated_excerpt_caches.is_empty();
-//         editor
-//             .inlay_hint_cache
-//             .hints
-//             .retain(|excerpt_id, _| !outdated_excerpt_caches.contains(excerpt_id));
-//     }
-
-//     let InlaySplice {
-//         to_remove,
-//         to_insert,
-//     } = splice;
-//     let displayed_inlays_changed = !to_remove.is_empty() || !to_insert.is_empty();
-//     if cached_inlays_changed || displayed_inlays_changed {
-//         editor.inlay_hint_cache.version += 1;
-//     }
-//     if displayed_inlays_changed {
-//         editor.splice_inlay_hints(to_remove, to_insert, cx)
-//     }
-// }
-
-// #[cfg(test)]
-// pub mod tests {
-//     use std::sync::atomic::{AtomicBool, AtomicU32, AtomicUsize, Ordering};
-
-//     use crate::{
-//         scroll::{autoscroll::Autoscroll, scroll_amount::ScrollAmount},
-//         serde_json::json,
-//         ExcerptRange,
-//     };
-//     use futures::StreamExt;
-//     use gpui::{executor::Deterministic, TestAppContext, View};
-//     use itertools::Itertools;
-//     use language::{
-//         language_settings::AllLanguageSettingsContent, FakeLspAdapter, Language, LanguageConfig,
-//     };
-//     use lsp::FakeLanguageServer;
-//     use parking_lot::Mutex;
-//     use project::{FakeFs, Project};
-//     use settings::SettingsStore;
-//     use text::{Point, ToPoint};
-//     use workspace::Workspace;
-
-//     use crate::editor_tests::update_test_language_settings;
-
-//     use super::*;
-
-//     #[gpui::test]
-//     async fn test_basic_cache_update_with_duplicate_hints(cx: &mut gpui::TestAppContext) {
-//         let allowed_hint_kinds = HashSet::from_iter([None, Some(InlayHintKind::Type)]);
-//         init_test(cx, |settings| {
-//             settings.defaults.inlay_hints = Some(InlayHintSettings {
-//                 enabled: true,
-//                 show_type_hints: allowed_hint_kinds.contains(&Some(InlayHintKind::Type)),
-//                 show_parameter_hints: allowed_hint_kinds.contains(&Some(InlayHintKind::Parameter)),
-//                 show_other_hints: allowed_hint_kinds.contains(&None),
-//             })
-//         });
-
-//         let (file_with_hints, editor, fake_server) = prepare_test_objects(cx).await;
-//         let lsp_request_count = Arc::new(AtomicU32::new(0));
-//         fake_server
-//             .handle_request::<lsp::request::InlayHintRequest, _, _>(move |params, _| {
-//                 let task_lsp_request_count = Arc::clone(&lsp_request_count);
-//                 async move {
-//                     assert_eq!(
-//                         params.text_document.uri,
-//                         lsp::Url::from_file_path(file_with_hints).unwrap(),
-//                     );
-//                     let current_call_id =
-//                         Arc::clone(&task_lsp_request_count).fetch_add(1, Ordering::SeqCst);
-//                     let mut new_hints = Vec::with_capacity(2 * current_call_id as usize);
-//                     for _ in 0..2 {
-//                         let mut i = current_call_id;
-//                         loop {
-//                             new_hints.push(lsp::InlayHint {
-//                                 position: lsp::Position::new(0, i),
-//                                 label: lsp::InlayHintLabel::String(i.to_string()),
-//                                 kind: None,
-//                                 text_edits: None,
-//                                 tooltip: None,
-//                                 padding_left: None,
-//                                 padding_right: None,
-//                                 data: None,
-//                             });
-//                             if i == 0 {
-//                                 break;
-//                             }
-//                             i -= 1;
-//                         }
-//                     }
-
-//                     Ok(Some(new_hints))
-//                 }
-//             })
-//             .next()
-//             .await;
-//         cx.foreground().run_until_parked();
-
-//         let mut edits_made = 1;
-//         editor.update(cx, |editor, cx| {
-//             let expected_hints = vec!["0".to_string()];
-//             assert_eq!(
-//                 expected_hints,
-//                 cached_hint_labels(editor),
-//                 "Should get its first hints when opening the editor"
-//             );
-//             assert_eq!(expected_hints, visible_hint_labels(editor, cx));
-//             let inlay_cache = editor.inlay_hint_cache();
-//             assert_eq!(
-//                 inlay_cache.allowed_hint_kinds, allowed_hint_kinds,
-//                 "Cache should use editor settings to get the allowed hint kinds"
-//             );
-//             assert_eq!(
-//                 inlay_cache.version, edits_made,
-//                 "The editor update the cache version after every cache/view change"
-//             );
-//         });
-
-//         editor.update(cx, |editor, cx| {
-//             editor.change_selections(None, cx, |s| s.select_ranges([13..13]));
-//             editor.handle_input("some change", cx);
-//             edits_made += 1;
-//         });
-//         cx.foreground().run_until_parked();
-//         editor.update(cx, |editor, cx| {
-//             let expected_hints = vec!["0".to_string(), "1".to_string()];
-//             assert_eq!(
-//                 expected_hints,
-//                 cached_hint_labels(editor),
-//                 "Should get new hints after an edit"
-//             );
-//             assert_eq!(expected_hints, visible_hint_labels(editor, cx));
-//             let inlay_cache = editor.inlay_hint_cache();
-//             assert_eq!(
-//                 inlay_cache.allowed_hint_kinds, allowed_hint_kinds,
-//                 "Cache should use editor settings to get the allowed hint kinds"
-//             );
-//             assert_eq!(
-//                 inlay_cache.version, edits_made,
-//                 "The editor update the cache version after every cache/view change"
-//             );
-//         });
-
-//         fake_server
-//             .request::<lsp::request::InlayHintRefreshRequest>(())
-//             .await
-//             .expect("inlay refresh request failed");
-//         edits_made += 1;
-//         cx.foreground().run_until_parked();
-//         editor.update(cx, |editor, cx| {
-//             let expected_hints = vec!["0".to_string(), "1".to_string(), "2".to_string()];
-//             assert_eq!(
-//                 expected_hints,
-//                 cached_hint_labels(editor),
-//                 "Should get new hints after hint refresh/ request"
-//             );
-//             assert_eq!(expected_hints, visible_hint_labels(editor, cx));
-//             let inlay_cache = editor.inlay_hint_cache();
-//             assert_eq!(
-//                 inlay_cache.allowed_hint_kinds, allowed_hint_kinds,
-//                 "Cache should use editor settings to get the allowed hint kinds"
-//             );
-//             assert_eq!(
-//                 inlay_cache.version, edits_made,
-//                 "The editor update the cache version after every cache/view change"
-//             );
-//         });
-//     }
-
-//     #[gpui::test]
-//     async fn test_cache_update_on_lsp_completion_tasks(cx: &mut gpui::TestAppContext) {
-//         init_test(cx, |settings| {
-//             settings.defaults.inlay_hints = Some(InlayHintSettings {
-//                 enabled: true,
-//                 show_type_hints: true,
-//                 show_parameter_hints: true,
-//                 show_other_hints: true,
-//             })
-//         });
-
-//         let (file_with_hints, editor, fake_server) = prepare_test_objects(cx).await;
-//         let lsp_request_count = Arc::new(AtomicU32::new(0));
-//         fake_server
-//             .handle_request::<lsp::request::InlayHintRequest, _, _>(move |params, _| {
-//                 let task_lsp_request_count = Arc::clone(&lsp_request_count);
-//                 async move {
-//                     assert_eq!(
-//                         params.text_document.uri,
-//                         lsp::Url::from_file_path(file_with_hints).unwrap(),
-//                     );
-//                     let current_call_id =
-//                         Arc::clone(&task_lsp_request_count).fetch_add(1, Ordering::SeqCst);
-//                     Ok(Some(vec![lsp::InlayHint {
-//                         position: lsp::Position::new(0, current_call_id),
-//                         label: lsp::InlayHintLabel::String(current_call_id.to_string()),
-//                         kind: None,
-//                         text_edits: None,
-//                         tooltip: None,
-//                         padding_left: None,
-//                         padding_right: None,
-//                         data: None,
-//                     }]))
-//                 }
-//             })
-//             .next()
-//             .await;
-//         cx.foreground().run_until_parked();
-
-//         let mut edits_made = 1;
-//         editor.update(cx, |editor, cx| {
-//             let expected_hints = vec!["0".to_string()];
-//             assert_eq!(
-//                 expected_hints,
-//                 cached_hint_labels(editor),
-//                 "Should get its first hints when opening the editor"
-//             );
-//             assert_eq!(expected_hints, visible_hint_labels(editor, cx));
-//             assert_eq!(
-//                 editor.inlay_hint_cache().version,
-//                 edits_made,
-//                 "The editor update the cache version after every cache/view change"
-//             );
-//         });
-
-//         let progress_token = "test_progress_token";
-//         fake_server
-//             .request::<lsp::request::WorkDoneProgressCreate>(lsp::WorkDoneProgressCreateParams {
-//                 token: lsp::ProgressToken::String(progress_token.to_string()),
-//             })
-//             .await
-//             .expect("work done progress create request failed");
-//         cx.foreground().run_until_parked();
-//         fake_server.notify::<lsp::notification::Progress>(lsp::ProgressParams {
-//             token: lsp::ProgressToken::String(progress_token.to_string()),
-//             value: lsp::ProgressParamsValue::WorkDone(lsp::WorkDoneProgress::Begin(
-//                 lsp::WorkDoneProgressBegin::default(),
-//             )),
-//         });
-//         cx.foreground().run_until_parked();
-
-//         editor.update(cx, |editor, cx| {
-//             let expected_hints = vec!["0".to_string()];
-//             assert_eq!(
-//                 expected_hints,
-//                 cached_hint_labels(editor),
-//                 "Should not update hints while the work task is running"
-//             );
-//             assert_eq!(expected_hints, visible_hint_labels(editor, cx));
-//             assert_eq!(
-//                 editor.inlay_hint_cache().version,
-//                 edits_made,
-//                 "Should not update the cache while the work task is running"
-//             );
-//         });
-
-//         fake_server.notify::<lsp::notification::Progress>(lsp::ProgressParams {
-//             token: lsp::ProgressToken::String(progress_token.to_string()),
-//             value: lsp::ProgressParamsValue::WorkDone(lsp::WorkDoneProgress::End(
-//                 lsp::WorkDoneProgressEnd::default(),
-//             )),
-//         });
-//         cx.foreground().run_until_parked();
-
-//         edits_made += 1;
-//         editor.update(cx, |editor, cx| {
-//             let expected_hints = vec!["1".to_string()];
-//             assert_eq!(
-//                 expected_hints,
-//                 cached_hint_labels(editor),
-//                 "New hints should be queried after the work task is done"
-//             );
-//             assert_eq!(expected_hints, visible_hint_labels(editor, cx));
-//             assert_eq!(
-//                 editor.inlay_hint_cache().version,
-//                 edits_made,
-//                 "Cache version should udpate once after the work task is done"
-//             );
-//         });
-//     }
-
-//     #[gpui::test]
-//     async fn test_no_hint_updates_for_unrelated_language_files(cx: &mut gpui::TestAppContext) {
-//         init_test(cx, |settings| {
-//             settings.defaults.inlay_hints = Some(InlayHintSettings {
-//                 enabled: true,
-//                 show_type_hints: true,
-//                 show_parameter_hints: true,
-//                 show_other_hints: true,
-//             })
-//         });
-
-//         let fs = FakeFs::new(cx.background());
-//         fs.insert_tree(
-//                     "/a",
-//                     json!({
-//                         "main.rs": "fn main() { a } // and some long comment to ensure inlays are not trimmed out",
-//                         "other.md": "Test md file with some text",
-//                     }),
-//                 )
-//                 .await;
-//         let project = Project::test(fs, ["/a".as_ref()], cx).await;
-//         let workspace = cx
-//             .add_window(|cx| Workspace::test_new(project.clone(), cx))
-//             .root(cx);
-//         let worktree_id = workspace.update(cx, |workspace, cx| {
-//             workspace.project().read_with(cx, |project, cx| {
-//                 project.worktrees(cx).next().unwrap().read(cx).id()
-//             })
-//         });
-
-//         let mut rs_fake_servers = None;
-//         let mut md_fake_servers = None;
-//         for (name, path_suffix) in [("Rust", "rs"), ("Markdown", "md")] {
-//             let mut language = Language::new(
-//                 LanguageConfig {
-//                     name: name.into(),
-//                     path_suffixes: vec![path_suffix.to_string()],
-//                     ..Default::default()
-//                 },
-//                 Some(tree_sitter_rust::language()),
-//             );
-//             let fake_servers = language
-//                 .set_fake_lsp_adapter(Arc::new(FakeLspAdapter {
-//                     name,
-//                     capabilities: lsp::ServerCapabilities {
-//                         inlay_hint_provider: Some(lsp::OneOf::Left(true)),
-//                         ..Default::default()
-//                     },
-//                     ..Default::default()
-//                 }))
-//                 .await;
-//             match name {
-//                 "Rust" => rs_fake_servers = Some(fake_servers),
-//                 "Markdown" => md_fake_servers = Some(fake_servers),
-//                 _ => unreachable!(),
-//             }
-//             project.update(cx, |project, _| {
-//                 project.languages().add(Arc::new(language));
-//             });
-//         }
-
-//         let _rs_buffer = project
-//             .update(cx, |project, cx| {
-//                 project.open_local_buffer("/a/main.rs", cx)
-//             })
-//             .await
-//             .unwrap();
-//         cx.foreground().run_until_parked();
-//         cx.foreground().start_waiting();
-//         let rs_fake_server = rs_fake_servers.unwrap().next().await.unwrap();
-//         let rs_editor = workspace
-//             .update(cx, |workspace, cx| {
-//                 workspace.open_path((worktree_id, "main.rs"), None, true, cx)
-//             })
-//             .await
-//             .unwrap()
-//             .downcast::<Editor>()
-//             .unwrap();
-//         let rs_lsp_request_count = Arc::new(AtomicU32::new(0));
-//         rs_fake_server
-//             .handle_request::<lsp::request::InlayHintRequest, _, _>(move |params, _| {
-//                 let task_lsp_request_count = Arc::clone(&rs_lsp_request_count);
-//                 async move {
-//                     assert_eq!(
-//                         params.text_document.uri,
-//                         lsp::Url::from_file_path("/a/main.rs").unwrap(),
-//                     );
-//                     let i = Arc::clone(&task_lsp_request_count).fetch_add(1, Ordering::SeqCst);
-//                     Ok(Some(vec![lsp::InlayHint {
-//                         position: lsp::Position::new(0, i),
-//                         label: lsp::InlayHintLabel::String(i.to_string()),
-//                         kind: None,
-//                         text_edits: None,
-//                         tooltip: None,
-//                         padding_left: None,
-//                         padding_right: None,
-//                         data: None,
-//                     }]))
-//                 }
-//             })
-//             .next()
-//             .await;
-//         cx.foreground().run_until_parked();
-//         rs_editor.update(cx, |editor, cx| {
-//             let expected_hints = vec!["0".to_string()];
-//             assert_eq!(
-//                 expected_hints,
-//                 cached_hint_labels(editor),
-//                 "Should get its first hints when opening the editor"
-//             );
-//             assert_eq!(expected_hints, visible_hint_labels(editor, cx));
-//             assert_eq!(
-//                 editor.inlay_hint_cache().version,
-//                 1,
-//                 "Rust editor update the cache version after every cache/view change"
-//             );
-//         });
-
-//         cx.foreground().run_until_parked();
-//         let _md_buffer = project
-//             .update(cx, |project, cx| {
-//                 project.open_local_buffer("/a/other.md", cx)
-//             })
-//             .await
-//             .unwrap();
-//         cx.foreground().run_until_parked();
-//         cx.foreground().start_waiting();
-//         let md_fake_server = md_fake_servers.unwrap().next().await.unwrap();
-//         let md_editor = workspace
-//             .update(cx, |workspace, cx| {
-//                 workspace.open_path((worktree_id, "other.md"), None, true, cx)
-//             })
-//             .await
-//             .unwrap()
-//             .downcast::<Editor>()
-//             .unwrap();
-//         let md_lsp_request_count = Arc::new(AtomicU32::new(0));
-//         md_fake_server
-//             .handle_request::<lsp::request::InlayHintRequest, _, _>(move |params, _| {
-//                 let task_lsp_request_count = Arc::clone(&md_lsp_request_count);
-//                 async move {
-//                     assert_eq!(
-//                         params.text_document.uri,
-//                         lsp::Url::from_file_path("/a/other.md").unwrap(),
-//                     );
-//                     let i = Arc::clone(&task_lsp_request_count).fetch_add(1, Ordering::SeqCst);
-//                     Ok(Some(vec![lsp::InlayHint {
-//                         position: lsp::Position::new(0, i),
-//                         label: lsp::InlayHintLabel::String(i.to_string()),
-//                         kind: None,
-//                         text_edits: None,
-//                         tooltip: None,
-//                         padding_left: None,
-//                         padding_right: None,
-//                         data: None,
-//                     }]))
-//                 }
-//             })
-//             .next()
-//             .await;
-//         cx.foreground().run_until_parked();
-//         md_editor.update(cx, |editor, cx| {
-//             let expected_hints = vec!["0".to_string()];
-//             assert_eq!(
-//                 expected_hints,
-//                 cached_hint_labels(editor),
-//                 "Markdown editor should have a separate verison, repeating Rust editor rules"
-//             );
-//             assert_eq!(expected_hints, visible_hint_labels(editor, cx));
-//             assert_eq!(editor.inlay_hint_cache().version, 1);
-//         });
-
-//         rs_editor.update(cx, |editor, cx| {
-//             editor.change_selections(None, cx, |s| s.select_ranges([13..13]));
-//             editor.handle_input("some rs change", cx);
-//         });
-//         cx.foreground().run_until_parked();
-//         rs_editor.update(cx, |editor, cx| {
-//             let expected_hints = vec!["1".to_string()];
-//             assert_eq!(
-//                 expected_hints,
-//                 cached_hint_labels(editor),
-//                 "Rust inlay cache should change after the edit"
-//             );
-//             assert_eq!(expected_hints, visible_hint_labels(editor, cx));
-//             assert_eq!(
-//                 editor.inlay_hint_cache().version,
-//                 2,
-//                 "Every time hint cache changes, cache version should be incremented"
-//             );
-//         });
-//         md_editor.update(cx, |editor, cx| {
-//             let expected_hints = vec!["0".to_string()];
-//             assert_eq!(
-//                 expected_hints,
-//                 cached_hint_labels(editor),
-//                 "Markdown editor should not be affected by Rust editor changes"
-//             );
-//             assert_eq!(expected_hints, visible_hint_labels(editor, cx));
-//             assert_eq!(editor.inlay_hint_cache().version, 1);
-//         });
-
-//         md_editor.update(cx, |editor, cx| {
-//             editor.change_selections(None, cx, |s| s.select_ranges([13..13]));
-//             editor.handle_input("some md change", cx);
-//         });
-//         cx.foreground().run_until_parked();
-//         md_editor.update(cx, |editor, cx| {
-//             let expected_hints = vec!["1".to_string()];
-//             assert_eq!(
-//                 expected_hints,
-//                 cached_hint_labels(editor),
-//                 "Rust editor should not be affected by Markdown editor changes"
-//             );
-//             assert_eq!(expected_hints, visible_hint_labels(editor, cx));
-//             assert_eq!(editor.inlay_hint_cache().version, 2);
-//         });
-//         rs_editor.update(cx, |editor, cx| {
-//             let expected_hints = vec!["1".to_string()];
-//             assert_eq!(
-//                 expected_hints,
-//                 cached_hint_labels(editor),
-//                 "Markdown editor should also change independently"
-//             );
-//             assert_eq!(expected_hints, visible_hint_labels(editor, cx));
-//             assert_eq!(editor.inlay_hint_cache().version, 2);
-//         });
-//     }
-
-//     #[gpui::test]
-//     async fn test_hint_setting_changes(cx: &mut gpui::TestAppContext) {
-//         let allowed_hint_kinds = HashSet::from_iter([None, Some(InlayHintKind::Type)]);
-//         init_test(cx, |settings| {
-//             settings.defaults.inlay_hints = Some(InlayHintSettings {
-//                 enabled: true,
-//                 show_type_hints: allowed_hint_kinds.contains(&Some(InlayHintKind::Type)),
-//                 show_parameter_hints: allowed_hint_kinds.contains(&Some(InlayHintKind::Parameter)),
-//                 show_other_hints: allowed_hint_kinds.contains(&None),
-//             })
-//         });
-
-//         let (file_with_hints, editor, fake_server) = prepare_test_objects(cx).await;
-//         let lsp_request_count = Arc::new(AtomicU32::new(0));
-//         let another_lsp_request_count = Arc::clone(&lsp_request_count);
-//         fake_server
-//             .handle_request::<lsp::request::InlayHintRequest, _, _>(move |params, _| {
-//                 let task_lsp_request_count = Arc::clone(&another_lsp_request_count);
-//                 async move {
-//                     Arc::clone(&task_lsp_request_count).fetch_add(1, Ordering::SeqCst);
-//                     assert_eq!(
-//                         params.text_document.uri,
-//                         lsp::Url::from_file_path(file_with_hints).unwrap(),
-//                     );
-//                     Ok(Some(vec![
-//                         lsp::InlayHint {
-//                             position: lsp::Position::new(0, 1),
-//                             label: lsp::InlayHintLabel::String("type hint".to_string()),
-//                             kind: Some(lsp::InlayHintKind::TYPE),
-//                             text_edits: None,
-//                             tooltip: None,
-//                             padding_left: None,
-//                             padding_right: None,
-//                             data: None,
-//                         },
-//                         lsp::InlayHint {
-//                             position: lsp::Position::new(0, 2),
-//                             label: lsp::InlayHintLabel::String("parameter hint".to_string()),
-//                             kind: Some(lsp::InlayHintKind::PARAMETER),
-//                             text_edits: None,
-//                             tooltip: None,
-//                             padding_left: None,
-//                             padding_right: None,
-//                             data: None,
-//                         },
-//                         lsp::InlayHint {
-//                             position: lsp::Position::new(0, 3),
-//                             label: lsp::InlayHintLabel::String("other hint".to_string()),
-//                             kind: None,
-//                             text_edits: None,
-//                             tooltip: None,
-//                             padding_left: None,
-//                             padding_right: None,
-//                             data: None,
-//                         },
-//                     ]))
-//                 }
-//             })
-//             .next()
-//             .await;
-//         cx.foreground().run_until_parked();
-
-//         let mut edits_made = 1;
-//         editor.update(cx, |editor, cx| {
-//             assert_eq!(
-//                 lsp_request_count.load(Ordering::Relaxed),
-//                 1,
-//                 "Should query new hints once"
-//             );
-//             assert_eq!(
-//                 vec![
-//                     "other hint".to_string(),
-//                     "parameter hint".to_string(),
-//                     "type hint".to_string(),
-//                 ],
-//                 cached_hint_labels(editor),
-//                 "Should get its first hints when opening the editor"
-//             );
-//             assert_eq!(
-//                 vec!["other hint".to_string(), "type hint".to_string()],
-//                 visible_hint_labels(editor, cx)
-//             );
-//             let inlay_cache = editor.inlay_hint_cache();
-//             assert_eq!(
-//                 inlay_cache.allowed_hint_kinds, allowed_hint_kinds,
-//                 "Cache should use editor settings to get the allowed hint kinds"
-//             );
-//             assert_eq!(
-//                 inlay_cache.version, edits_made,
-//                 "The editor update the cache version after every cache/view change"
-//             );
-//         });
-
-//         fake_server
-//             .request::<lsp::request::InlayHintRefreshRequest>(())
-//             .await
-//             .expect("inlay refresh request failed");
-//         cx.foreground().run_until_parked();
-//         editor.update(cx, |editor, cx| {
-//             assert_eq!(
-//                 lsp_request_count.load(Ordering::Relaxed),
-//                 2,
-//                 "Should load new hints twice"
-//             );
-//             assert_eq!(
-//                 vec![
-//                     "other hint".to_string(),
-//                     "parameter hint".to_string(),
-//                     "type hint".to_string(),
-//                 ],
-//                 cached_hint_labels(editor),
-//                 "Cached hints should not change due to allowed hint kinds settings update"
-//             );
-//             assert_eq!(
-//                 vec!["other hint".to_string(), "type hint".to_string()],
-//                 visible_hint_labels(editor, cx)
-//             );
-//             assert_eq!(
-//                 editor.inlay_hint_cache().version,
-//                 edits_made,
-//                 "Should not update cache version due to new loaded hints being the same"
-//             );
-//         });
-
-//         for (new_allowed_hint_kinds, expected_visible_hints) in [
-//             (HashSet::from_iter([None]), vec!["other hint".to_string()]),
-//             (
-//                 HashSet::from_iter([Some(InlayHintKind::Type)]),
-//                 vec!["type hint".to_string()],
-//             ),
-//             (
-//                 HashSet::from_iter([Some(InlayHintKind::Parameter)]),
-//                 vec!["parameter hint".to_string()],
-//             ),
-//             (
-//                 HashSet::from_iter([None, Some(InlayHintKind::Type)]),
-//                 vec!["other hint".to_string(), "type hint".to_string()],
-//             ),
-//             (
-//                 HashSet::from_iter([None, Some(InlayHintKind::Parameter)]),
-//                 vec!["other hint".to_string(), "parameter hint".to_string()],
-//             ),
-//             (
-//                 HashSet::from_iter([Some(InlayHintKind::Type), Some(InlayHintKind::Parameter)]),
-//                 vec!["parameter hint".to_string(), "type hint".to_string()],
-//             ),
-//             (
-//                 HashSet::from_iter([
-//                     None,
-//                     Some(InlayHintKind::Type),
-//                     Some(InlayHintKind::Parameter),
-//                 ]),
-//                 vec![
-//                     "other hint".to_string(),
-//                     "parameter hint".to_string(),
-//                     "type hint".to_string(),
-//                 ],
-//             ),
-//         ] {
-//             edits_made += 1;
-//             update_test_language_settings(cx, |settings| {
-//                 settings.defaults.inlay_hints = Some(InlayHintSettings {
-//                     enabled: true,
-//                     show_type_hints: new_allowed_hint_kinds.contains(&Some(InlayHintKind::Type)),
-//                     show_parameter_hints: new_allowed_hint_kinds
-//                         .contains(&Some(InlayHintKind::Parameter)),
-//                     show_other_hints: new_allowed_hint_kinds.contains(&None),
-//                 })
-//             });
-//             cx.foreground().run_until_parked();
-//             editor.update(cx, |editor, cx| {
-//                 assert_eq!(
-//                     lsp_request_count.load(Ordering::Relaxed),
-//                     2,
-//                     "Should not load new hints on allowed hint kinds change for hint kinds {new_allowed_hint_kinds:?}"
-//                 );
-//                 assert_eq!(
-//                     vec![
-//                         "other hint".to_string(),
-//                         "parameter hint".to_string(),
-//                         "type hint".to_string(),
-//                     ],
-//                     cached_hint_labels(editor),
-//                     "Should get its cached hints unchanged after the settings change for hint kinds {new_allowed_hint_kinds:?}"
-//                 );
-//                 assert_eq!(
-//                     expected_visible_hints,
-//                     visible_hint_labels(editor, cx),
-//                     "Should get its visible hints filtered after the settings change for hint kinds {new_allowed_hint_kinds:?}"
-//                 );
-//                 let inlay_cache = editor.inlay_hint_cache();
-//                 assert_eq!(
-//                     inlay_cache.allowed_hint_kinds, new_allowed_hint_kinds,
-//                     "Cache should use editor settings to get the allowed hint kinds for hint kinds {new_allowed_hint_kinds:?}"
-//                 );
-//                 assert_eq!(
-//                     inlay_cache.version, edits_made,
-//                     "The editor should update the cache version after every cache/view change for hint kinds {new_allowed_hint_kinds:?} due to visible hints change"
-//                 );
-//             });
-//         }
-
-//         edits_made += 1;
-//         let another_allowed_hint_kinds = HashSet::from_iter([Some(InlayHintKind::Type)]);
-//         update_test_language_settings(cx, |settings| {
-//             settings.defaults.inlay_hints = Some(InlayHintSettings {
-//                 enabled: false,
-//                 show_type_hints: another_allowed_hint_kinds.contains(&Some(InlayHintKind::Type)),
-//                 show_parameter_hints: another_allowed_hint_kinds
-//                     .contains(&Some(InlayHintKind::Parameter)),
-//                 show_other_hints: another_allowed_hint_kinds.contains(&None),
-//             })
-//         });
-//         cx.foreground().run_until_parked();
-//         editor.update(cx, |editor, cx| {
-//             assert_eq!(
-//                 lsp_request_count.load(Ordering::Relaxed),
-//                 2,
-//                 "Should not load new hints when hints got disabled"
-//             );
-//             assert!(
-//                 cached_hint_labels(editor).is_empty(),
-//                 "Should clear the cache when hints got disabled"
-//             );
-//             assert!(
-//                 visible_hint_labels(editor, cx).is_empty(),
-//                 "Should clear visible hints when hints got disabled"
-//             );
-//             let inlay_cache = editor.inlay_hint_cache();
-//             assert_eq!(
-//                 inlay_cache.allowed_hint_kinds, another_allowed_hint_kinds,
-//                 "Should update its allowed hint kinds even when hints got disabled"
-//             );
-//             assert_eq!(
-//                 inlay_cache.version, edits_made,
-//                 "The editor should update the cache version after hints got disabled"
-//             );
-//         });
-
-//         fake_server
-//             .request::<lsp::request::InlayHintRefreshRequest>(())
-//             .await
-//             .expect("inlay refresh request failed");
-//         cx.foreground().run_until_parked();
-//         editor.update(cx, |editor, cx| {
-//             assert_eq!(
-//                 lsp_request_count.load(Ordering::Relaxed),
-//                 2,
-//                 "Should not load new hints when they got disabled"
-//             );
-//             assert!(cached_hint_labels(editor).is_empty());
-//             assert!(visible_hint_labels(editor, cx).is_empty());
-//             assert_eq!(
-//                 editor.inlay_hint_cache().version, edits_made,
-//                 "The editor should not update the cache version after /refresh query without updates"
-//             );
-//         });
-
-//         let final_allowed_hint_kinds = HashSet::from_iter([Some(InlayHintKind::Parameter)]);
-//         edits_made += 1;
-//         update_test_language_settings(cx, |settings| {
-//             settings.defaults.inlay_hints = Some(InlayHintSettings {
-//                 enabled: true,
-//                 show_type_hints: final_allowed_hint_kinds.contains(&Some(InlayHintKind::Type)),
-//                 show_parameter_hints: final_allowed_hint_kinds
-//                     .contains(&Some(InlayHintKind::Parameter)),
-//                 show_other_hints: final_allowed_hint_kinds.contains(&None),
-//             })
-//         });
-//         cx.foreground().run_until_parked();
-//         editor.update(cx, |editor, cx| {
-//             assert_eq!(
-//                 lsp_request_count.load(Ordering::Relaxed),
-//                 3,
-//                 "Should query for new hints when they got reenabled"
-//             );
-//             assert_eq!(
-//                 vec![
-//                     "other hint".to_string(),
-//                     "parameter hint".to_string(),
-//                     "type hint".to_string(),
-//                 ],
-//                 cached_hint_labels(editor),
-//                 "Should get its cached hints fully repopulated after the hints got reenabled"
-//             );
-//             assert_eq!(
-//                 vec!["parameter hint".to_string()],
-//                 visible_hint_labels(editor, cx),
-//                 "Should get its visible hints repopulated and filtered after the h"
-//             );
-//             let inlay_cache = editor.inlay_hint_cache();
-//             assert_eq!(
-//                 inlay_cache.allowed_hint_kinds, final_allowed_hint_kinds,
-//                 "Cache should update editor settings when hints got reenabled"
-//             );
-//             assert_eq!(
-//                 inlay_cache.version, edits_made,
-//                 "Cache should update its version after hints got reenabled"
-//             );
-//         });
-
-//         fake_server
-//             .request::<lsp::request::InlayHintRefreshRequest>(())
-//             .await
-//             .expect("inlay refresh request failed");
-//         cx.foreground().run_until_parked();
-//         editor.update(cx, |editor, cx| {
-//             assert_eq!(
-//                 lsp_request_count.load(Ordering::Relaxed),
-//                 4,
-//                 "Should query for new hints again"
-//             );
-//             assert_eq!(
-//                 vec![
-//                     "other hint".to_string(),
-//                     "parameter hint".to_string(),
-//                     "type hint".to_string(),
-//                 ],
-//                 cached_hint_labels(editor),
-//             );
-//             assert_eq!(
-//                 vec!["parameter hint".to_string()],
-//                 visible_hint_labels(editor, cx),
-//             );
-//             assert_eq!(editor.inlay_hint_cache().version, edits_made);
-//         });
-//     }
-
-//     #[gpui::test]
-//     async fn test_hint_request_cancellation(cx: &mut gpui::TestAppContext) {
-//         init_test(cx, |settings| {
-//             settings.defaults.inlay_hints = Some(InlayHintSettings {
-//                 enabled: true,
-//                 show_type_hints: true,
-//                 show_parameter_hints: true,
-//                 show_other_hints: true,
-//             })
-//         });
-
-//         let (file_with_hints, editor, fake_server) = prepare_test_objects(cx).await;
-//         let fake_server = Arc::new(fake_server);
-//         let lsp_request_count = Arc::new(AtomicU32::new(0));
-//         let another_lsp_request_count = Arc::clone(&lsp_request_count);
-//         fake_server
-//             .handle_request::<lsp::request::InlayHintRequest, _, _>(move |params, _| {
-//                 let task_lsp_request_count = Arc::clone(&another_lsp_request_count);
-//                 async move {
-//                     let i = Arc::clone(&task_lsp_request_count).fetch_add(1, Ordering::SeqCst) + 1;
-//                     assert_eq!(
-//                         params.text_document.uri,
-//                         lsp::Url::from_file_path(file_with_hints).unwrap(),
-//                     );
-//                     Ok(Some(vec![lsp::InlayHint {
-//                         position: lsp::Position::new(0, i),
-//                         label: lsp::InlayHintLabel::String(i.to_string()),
-//                         kind: None,
-//                         text_edits: None,
-//                         tooltip: None,
-//                         padding_left: None,
-//                         padding_right: None,
-//                         data: None,
-//                     }]))
-//                 }
-//             })
-//             .next()
-//             .await;
-
-//         let mut expected_changes = Vec::new();
-//         for change_after_opening in [
-//             "initial change #1",
-//             "initial change #2",
-//             "initial change #3",
-//         ] {
-//             editor.update(cx, |editor, cx| {
-//                 editor.change_selections(None, cx, |s| s.select_ranges([13..13]));
-//                 editor.handle_input(change_after_opening, cx);
-//             });
-//             expected_changes.push(change_after_opening);
-//         }
-
-//         cx.foreground().run_until_parked();
-
-//         editor.update(cx, |editor, cx| {
-//             let current_text = editor.text(cx);
-//             for change in &expected_changes {
-//                 assert!(
-//                     current_text.contains(change),
-//                     "Should apply all changes made"
-//                 );
-//             }
-//             assert_eq!(
-//                 lsp_request_count.load(Ordering::Relaxed),
-//                 2,
-//                 "Should query new hints twice: for editor init and for the last edit that interrupted all others"
-//             );
-//             let expected_hints = vec!["2".to_string()];
-//             assert_eq!(
-//                 expected_hints,
-//                 cached_hint_labels(editor),
-//                 "Should get hints from the last edit landed only"
-//             );
-//             assert_eq!(expected_hints, visible_hint_labels(editor, cx));
-//             assert_eq!(
-//                 editor.inlay_hint_cache().version, 1,
-//                 "Only one update should be registered in the cache after all cancellations"
-//             );
-//         });
-
-//         let mut edits = Vec::new();
-//         for async_later_change in [
-//             "another change #1",
-//             "another change #2",
-//             "another change #3",
-//         ] {
-//             expected_changes.push(async_later_change);
-//             let task_editor = editor.clone();
-//             let mut task_cx = cx.clone();
-//             edits.push(cx.foreground().spawn(async move {
-//                 task_editor.update(&mut task_cx, |editor, cx| {
-//                     editor.change_selections(None, cx, |s| s.select_ranges([13..13]));
-//                     editor.handle_input(async_later_change, cx);
-//                 });
-//             }));
-//         }
-//         let _ = future::join_all(edits).await;
-//         cx.foreground().run_until_parked();
-
-//         editor.update(cx, |editor, cx| {
-//             let current_text = editor.text(cx);
-//             for change in &expected_changes {
-//                 assert!(
-//                     current_text.contains(change),
-//                     "Should apply all changes made"
-//                 );
-//             }
-//             assert_eq!(
-//                 lsp_request_count.load(Ordering::SeqCst),
-//                 3,
-//                 "Should query new hints one more time, for the last edit only"
-//             );
-//             let expected_hints = vec!["3".to_string()];
-//             assert_eq!(
-//                 expected_hints,
-//                 cached_hint_labels(editor),
-//                 "Should get hints from the last edit landed only"
-//             );
-//             assert_eq!(expected_hints, visible_hint_labels(editor, cx));
-//             assert_eq!(
-//                 editor.inlay_hint_cache().version,
-//                 2,
-//                 "Should update the cache version once more, for the new change"
-//             );
-//         });
-//     }
-
-//     #[gpui::test(iterations = 10)]
-//     async fn test_large_buffer_inlay_requests_split(cx: &mut gpui::TestAppContext) {
-//         init_test(cx, |settings| {
-//             settings.defaults.inlay_hints = Some(InlayHintSettings {
-//                 enabled: true,
-//                 show_type_hints: true,
-//                 show_parameter_hints: true,
-//                 show_other_hints: true,
-//             })
-//         });
-
-//         let mut language = Language::new(
-//             LanguageConfig {
-//                 name: "Rust".into(),
-//                 path_suffixes: vec!["rs".to_string()],
-//                 ..Default::default()
-//             },
-//             Some(tree_sitter_rust::language()),
-//         );
-//         let mut fake_servers = language
-//             .set_fake_lsp_adapter(Arc::new(FakeLspAdapter {
-//                 capabilities: lsp::ServerCapabilities {
-//                     inlay_hint_provider: Some(lsp::OneOf::Left(true)),
-//                     ..Default::default()
-//                 },
-//                 ..Default::default()
-//             }))
-//             .await;
-//         let fs = FakeFs::new(cx.background());
-//         fs.insert_tree(
-//             "/a",
-//             json!({
-//                 "main.rs": format!("fn main() {{\n{}\n}}", "let i = 5;\n".repeat(500)),
-//                 "other.rs": "// Test file",
-//             }),
-//         )
-//         .await;
-//         let project = Project::test(fs, ["/a".as_ref()], cx).await;
-//         project.update(cx, |project, _| project.languages().add(Arc::new(language)));
-//         let workspace = cx
-//             .add_window(|cx| Workspace::test_new(project.clone(), cx))
-//             .root(cx);
-//         let worktree_id = workspace.update(cx, |workspace, cx| {
-//             workspace.project().read_with(cx, |project, cx| {
-//                 project.worktrees(cx).next().unwrap().read(cx).id()
-//             })
-//         });
-
-//         let _buffer = project
-//             .update(cx, |project, cx| {
-//                 project.open_local_buffer("/a/main.rs", cx)
-//             })
-//             .await
-//             .unwrap();
-//         cx.foreground().run_until_parked();
-//         cx.foreground().start_waiting();
-//         let fake_server = fake_servers.next().await.unwrap();
-//         let editor = workspace
-//             .update(cx, |workspace, cx| {
-//                 workspace.open_path((worktree_id, "main.rs"), None, true, cx)
-//             })
-//             .await
-//             .unwrap()
-//             .downcast::<Editor>()
-//             .unwrap();
-//         let lsp_request_ranges = Arc::new(Mutex::new(Vec::new()));
-//         let lsp_request_count = Arc::new(AtomicUsize::new(0));
-//         let closure_lsp_request_ranges = Arc::clone(&lsp_request_ranges);
-//         let closure_lsp_request_count = Arc::clone(&lsp_request_count);
-//         fake_server
-//             .handle_request::<lsp::request::InlayHintRequest, _, _>(move |params, _| {
-//                 let task_lsp_request_ranges = Arc::clone(&closure_lsp_request_ranges);
-//                 let task_lsp_request_count = Arc::clone(&closure_lsp_request_count);
-//                 async move {
-//                     assert_eq!(
-//                         params.text_document.uri,
-//                         lsp::Url::from_file_path("/a/main.rs").unwrap(),
-//                     );
-
-//                     task_lsp_request_ranges.lock().push(params.range);
-//                     let i = Arc::clone(&task_lsp_request_count).fetch_add(1, Ordering::Release) + 1;
-//                     Ok(Some(vec![lsp::InlayHint {
-//                         position: params.range.end,
-//                         label: lsp::InlayHintLabel::String(i.to_string()),
-//                         kind: None,
-//                         text_edits: None,
-//                         tooltip: None,
-//                         padding_left: None,
-//                         padding_right: None,
-//                         data: None,
-//                     }]))
-//                 }
-//             })
-//             .next()
-//             .await;
-//         fn editor_visible_range(
-//             editor: &ViewHandle<Editor>,
-//             cx: &mut gpui::TestAppContext,
-//         ) -> Range<Point> {
-//             let ranges = editor.update(cx, |editor, cx| editor.excerpt_visible_offsets(None, cx));
-//             assert_eq!(
-//                 ranges.len(),
-//                 1,
-//                 "Single buffer should produce a single excerpt with visible range"
-//             );
-//             let (_, (excerpt_buffer, _, excerpt_visible_range)) =
-//                 ranges.into_iter().next().unwrap();
-//             excerpt_buffer.update(cx, |buffer, _| {
-//                 let snapshot = buffer.snapshot();
-//                 let start = buffer
-//                     .anchor_before(excerpt_visible_range.start)
-//                     .to_point(&snapshot);
-//                 let end = buffer
-//                     .anchor_after(excerpt_visible_range.end)
-//                     .to_point(&snapshot);
-//                 start..end
-//             })
-//         }
-
-//         // in large buffers, requests are made for more than visible range of a buffer.
-//         // invisible parts are queried later, to avoid excessive requests on quick typing.
-//         // wait the timeout needed to get all requests.
-//         cx.foreground().advance_clock(Duration::from_millis(
-//             INVISIBLE_RANGES_HINTS_REQUEST_DELAY_MILLIS + 100,
-//         ));
-//         cx.foreground().run_until_parked();
-//         let initial_visible_range = editor_visible_range(&editor, cx);
-//         let lsp_initial_visible_range = lsp::Range::new(
-//             lsp::Position::new(
-//                 initial_visible_range.start.row,
-//                 initial_visible_range.start.column,
-//             ),
-//             lsp::Position::new(
-//                 initial_visible_range.end.row,
-//                 initial_visible_range.end.column,
-//             ),
-//         );
-//         let expected_initial_query_range_end =
-//             lsp::Position::new(initial_visible_range.end.row * 2, 2);
-//         let mut expected_invisible_query_start = lsp_initial_visible_range.end;
-//         expected_invisible_query_start.character += 1;
-//         editor.update(cx, |editor, cx| {
-//             let ranges = lsp_request_ranges.lock().drain(..).collect::<Vec<_>>();
-//             assert_eq!(ranges.len(), 2,
-//                 "When scroll is at the edge of a big document, its visible part and the same range further should be queried in order, but got: {ranges:?}");
-//             let visible_query_range = &ranges[0];
-//             assert_eq!(visible_query_range.start, lsp_initial_visible_range.start);
-//             assert_eq!(visible_query_range.end, lsp_initial_visible_range.end);
-//             let invisible_query_range = &ranges[1];
-
-//             assert_eq!(invisible_query_range.start, expected_invisible_query_start, "Should initially query visible edge of the document");
-//             assert_eq!(invisible_query_range.end, expected_initial_query_range_end, "Should initially query visible edge of the document");
-
-//             let requests_count = lsp_request_count.load(Ordering::Acquire);
-//             assert_eq!(requests_count, 2, "Visible + invisible request");
-//             let expected_hints = vec!["1".to_string(), "2".to_string()];
-//             assert_eq!(
-//                 expected_hints,
-//                 cached_hint_labels(editor),
-//                 "Should have hints from both LSP requests made for a big file"
-//             );
-//             assert_eq!(expected_hints, visible_hint_labels(editor, cx), "Should display only hints from the visible range");
-//             assert_eq!(
-//                 editor.inlay_hint_cache().version, requests_count,
-//                 "LSP queries should've bumped the cache version"
-//             );
-//         });
-
-//         editor.update(cx, |editor, cx| {
-//             editor.scroll_screen(&ScrollAmount::Page(1.0), cx);
-//             editor.scroll_screen(&ScrollAmount::Page(1.0), cx);
-//         });
-//         cx.foreground().advance_clock(Duration::from_millis(
-//             INVISIBLE_RANGES_HINTS_REQUEST_DELAY_MILLIS + 100,
-//         ));
-//         cx.foreground().run_until_parked();
-//         let visible_range_after_scrolls = editor_visible_range(&editor, cx);
-//         let visible_line_count =
-//             editor.update(cx, |editor, _| editor.visible_line_count().unwrap());
-//         let selection_in_cached_range = editor.update(cx, |editor, cx| {
-//             let ranges = lsp_request_ranges
-//                 .lock()
-//                 .drain(..)
-//                 .sorted_by_key(|r| r.start)
-//                 .collect::<Vec<_>>();
-//             assert_eq!(
-//                 ranges.len(),
-//                 2,
-//                 "Should query 2 ranges after both scrolls, but got: {ranges:?}"
-//             );
-//             let first_scroll = &ranges[0];
-//             let second_scroll = &ranges[1];
-//             assert_eq!(
-//                 first_scroll.end, second_scroll.start,
-//                 "Should query 2 adjacent ranges after the scrolls, but got: {ranges:?}"
-//             );
-//             assert_eq!(
-//                 first_scroll.start, expected_initial_query_range_end,
-//                 "First scroll should start the query right after the end of the original scroll",
-//             );
-//             assert_eq!(
-//                 second_scroll.end,
-//                 lsp::Position::new(
-//                     visible_range_after_scrolls.end.row
-//                         + visible_line_count.ceil() as u32,
-//                     1,
-//                 ),
-//                 "Second scroll should query one more screen down after the end of the visible range"
-//             );
-
-//             let lsp_requests = lsp_request_count.load(Ordering::Acquire);
-//             assert_eq!(lsp_requests, 4, "Should query for hints after every scroll");
-//             let expected_hints = vec![
-//                 "1".to_string(),
-//                 "2".to_string(),
-//                 "3".to_string(),
-//                 "4".to_string(),
-//             ];
-//             assert_eq!(
-//                 expected_hints,
-//                 cached_hint_labels(editor),
-//                 "Should have hints from the new LSP response after the edit"
-//             );
-//             assert_eq!(expected_hints, visible_hint_labels(editor, cx));
-//             assert_eq!(
-//                 editor.inlay_hint_cache().version,
-//                 lsp_requests,
-//                 "Should update the cache for every LSP response with hints added"
-//             );
-
-//             let mut selection_in_cached_range = visible_range_after_scrolls.end;
-//             selection_in_cached_range.row -= visible_line_count.ceil() as u32;
-//             selection_in_cached_range
-//         });
-
-//         editor.update(cx, |editor, cx| {
-//             editor.change_selections(Some(Autoscroll::center()), cx, |s| {
-//                 s.select_ranges([selection_in_cached_range..selection_in_cached_range])
-//             });
-//         });
-//         cx.foreground().advance_clock(Duration::from_millis(
-//             INVISIBLE_RANGES_HINTS_REQUEST_DELAY_MILLIS + 100,
-//         ));
-//         cx.foreground().run_until_parked();
-//         editor.update(cx, |_, _| {
-//             let ranges = lsp_request_ranges
-//                 .lock()
-//                 .drain(..)
-//                 .sorted_by_key(|r| r.start)
-//                 .collect::<Vec<_>>();
-//             assert!(ranges.is_empty(), "No new ranges or LSP queries should be made after returning to the selection with cached hints");
-//             assert_eq!(lsp_request_count.load(Ordering::Acquire), 4);
-//         });
-
-//         editor.update(cx, |editor, cx| {
-//             editor.handle_input("++++more text++++", cx);
-//         });
-//         cx.foreground().advance_clock(Duration::from_millis(
-//             INVISIBLE_RANGES_HINTS_REQUEST_DELAY_MILLIS + 100,
-//         ));
-//         cx.foreground().run_until_parked();
-//         editor.update(cx, |editor, cx| {
-//             let mut ranges = lsp_request_ranges.lock().drain(..).collect::<Vec<_>>();
-//             ranges.sort_by_key(|r| r.start);
-
-//             assert_eq!(ranges.len(), 3,
-//                 "On edit, should scroll to selection and query a range around it: visible + same range above and below. Instead, got query ranges {ranges:?}");
-//             let above_query_range = &ranges[0];
-//             let visible_query_range = &ranges[1];
-//             let below_query_range = &ranges[2];
-//             assert!(above_query_range.end.character < visible_query_range.start.character || above_query_range.end.line + 1 == visible_query_range.start.line,
-//                 "Above range {above_query_range:?} should be before visible range {visible_query_range:?}");
-//             assert!(visible_query_range.end.character < below_query_range.start.character || visible_query_range.end.line  + 1 == below_query_range.start.line,
-//                 "Visible range {visible_query_range:?} should be before below range {below_query_range:?}");
-//             assert!(above_query_range.start.line < selection_in_cached_range.row,
-//                 "Hints should be queried with the selected range after the query range start");
-//             assert!(below_query_range.end.line > selection_in_cached_range.row,
-//                 "Hints should be queried with the selected range before the query range end");
-//             assert!(above_query_range.start.line <= selection_in_cached_range.row - (visible_line_count * 3.0 / 2.0) as u32,
-//                 "Hints query range should contain one more screen before");
-//             assert!(below_query_range.end.line >= selection_in_cached_range.row + (visible_line_count * 3.0 / 2.0) as u32,
-//                 "Hints query range should contain one more screen after");
-
-//             let lsp_requests = lsp_request_count.load(Ordering::Acquire);
-//             assert_eq!(lsp_requests, 7, "There should be a visible range and two ranges above and below it queried");
-//             let expected_hints = vec!["5".to_string(), "6".to_string(), "7".to_string()];
-//             assert_eq!(expected_hints, cached_hint_labels(editor),
-//                 "Should have hints from the new LSP response after the edit");
-//             assert_eq!(expected_hints, visible_hint_labels(editor, cx));
-//             assert_eq!(editor.inlay_hint_cache().version, lsp_requests, "Should update the cache for every LSP response with hints added");
-//         });
-//     }
-
-//     #[gpui::test(iterations = 10)]
-//     async fn test_multiple_excerpts_large_multibuffer(
-//         deterministic: Arc<Deterministic>,
-//         cx: &mut gpui::TestAppContext,
-//     ) {
-//         init_test(cx, |settings| {
-//             settings.defaults.inlay_hints = Some(InlayHintSettings {
-//                 enabled: true,
-//                 show_type_hints: true,
-//                 show_parameter_hints: true,
-//                 show_other_hints: true,
-//             })
-//         });
-
-//         let mut language = Language::new(
-//             LanguageConfig {
-//                 name: "Rust".into(),
-//                 path_suffixes: vec!["rs".to_string()],
-//                 ..Default::default()
-//             },
-//             Some(tree_sitter_rust::language()),
-//         );
-//         let mut fake_servers = language
-//             .set_fake_lsp_adapter(Arc::new(FakeLspAdapter {
-//                 capabilities: lsp::ServerCapabilities {
-//                     inlay_hint_provider: Some(lsp::OneOf::Left(true)),
-//                     ..Default::default()
-//                 },
-//                 ..Default::default()
-//             }))
-//             .await;
-//         let language = Arc::new(language);
-//         let fs = FakeFs::new(cx.background());
-//         fs.insert_tree(
-//             "/a",
-//             json!({
-//                 "main.rs": format!("fn main() {{\n{}\n}}", (0..501).map(|i| format!("let i = {i};\n")).collect::<Vec<_>>().join("")),
-//                 "other.rs": format!("fn main() {{\n{}\n}}", (0..501).map(|j| format!("let j = {j};\n")).collect::<Vec<_>>().join("")),
-//             }),
-//         )
-//         .await;
-//         let project = Project::test(fs, ["/a".as_ref()], cx).await;
-//         project.update(cx, |project, _| {
-//             project.languages().add(Arc::clone(&language))
-//         });
-//         let workspace = cx
-//             .add_window(|cx| Workspace::test_new(project.clone(), cx))
-//             .root(cx);
-//         let worktree_id = workspace.update(cx, |workspace, cx| {
-//             workspace.project().read_with(cx, |project, cx| {
-//                 project.worktrees(cx).next().unwrap().read(cx).id()
-//             })
-//         });
-
-//         let buffer_1 = project
-//             .update(cx, |project, cx| {
-//                 project.open_buffer((worktree_id, "main.rs"), cx)
-//             })
-//             .await
-//             .unwrap();
-//         let buffer_2 = project
-//             .update(cx, |project, cx| {
-//                 project.open_buffer((worktree_id, "other.rs"), cx)
-//             })
-//             .await
-//             .unwrap();
-//         let multibuffer = cx.add_model(|cx| {
-//             let mut multibuffer = MultiBuffer::new(0);
-//             multibuffer.push_excerpts(
-//                 buffer_1.clone(),
-//                 [
-//                     ExcerptRange {
-//                         context: Point::new(0, 0)..Point::new(2, 0),
-//                         primary: None,
-//                     },
-//                     ExcerptRange {
-//                         context: Point::new(4, 0)..Point::new(11, 0),
-//                         primary: None,
-//                     },
-//                     ExcerptRange {
-//                         context: Point::new(22, 0)..Point::new(33, 0),
-//                         primary: None,
-//                     },
-//                     ExcerptRange {
-//                         context: Point::new(44, 0)..Point::new(55, 0),
-//                         primary: None,
-//                     },
-//                     ExcerptRange {
-//                         context: Point::new(56, 0)..Point::new(66, 0),
-//                         primary: None,
-//                     },
-//                     ExcerptRange {
-//                         context: Point::new(67, 0)..Point::new(77, 0),
-//                         primary: None,
-//                     },
-//                 ],
-//                 cx,
-//             );
-//             multibuffer.push_excerpts(
-//                 buffer_2.clone(),
-//                 [
-//                     ExcerptRange {
-//                         context: Point::new(0, 1)..Point::new(2, 1),
-//                         primary: None,
-//                     },
-//                     ExcerptRange {
-//                         context: Point::new(4, 1)..Point::new(11, 1),
-//                         primary: None,
-//                     },
-//                     ExcerptRange {
-//                         context: Point::new(22, 1)..Point::new(33, 1),
-//                         primary: None,
-//                     },
-//                     ExcerptRange {
-//                         context: Point::new(44, 1)..Point::new(55, 1),
-//                         primary: None,
-//                     },
-//                     ExcerptRange {
-//                         context: Point::new(56, 1)..Point::new(66, 1),
-//                         primary: None,
-//                     },
-//                     ExcerptRange {
-//                         context: Point::new(67, 1)..Point::new(77, 1),
-//                         primary: None,
-//                     },
-//                 ],
-//                 cx,
-//             );
-//             multibuffer
-//         });
-
-//         deterministic.run_until_parked();
-//         cx.foreground().run_until_parked();
-//         let editor = cx
-//             .add_window(|cx| Editor::for_multibuffer(multibuffer, Some(project.clone()), cx))
-//             .root(cx);
-//         let editor_edited = Arc::new(AtomicBool::new(false));
-//         let fake_server = fake_servers.next().await.unwrap();
-//         let closure_editor_edited = Arc::clone(&editor_edited);
-//         fake_server
-//             .handle_request::<lsp::request::InlayHintRequest, _, _>(move |params, _| {
-//                 let task_editor_edited = Arc::clone(&closure_editor_edited);
-//                 async move {
-//                     let hint_text = if params.text_document.uri
-//                         == lsp::Url::from_file_path("/a/main.rs").unwrap()
-//                     {
-//                         "main hint"
-//                     } else if params.text_document.uri
-//                         == lsp::Url::from_file_path("/a/other.rs").unwrap()
-//                     {
-//                         "other hint"
-//                     } else {
-//                         panic!("unexpected uri: {:?}", params.text_document.uri);
-//                     };
-
-//                     // one hint per excerpt
-//                     let positions = [
-//                         lsp::Position::new(0, 2),
-//                         lsp::Position::new(4, 2),
-//                         lsp::Position::new(22, 2),
-//                         lsp::Position::new(44, 2),
-//                         lsp::Position::new(56, 2),
-//                         lsp::Position::new(67, 2),
-//                     ];
-//                     let out_of_range_hint = lsp::InlayHint {
-//                         position: lsp::Position::new(
-//                             params.range.start.line + 99,
-//                             params.range.start.character + 99,
-//                         ),
-//                         label: lsp::InlayHintLabel::String(
-//                             "out of excerpt range, should be ignored".to_string(),
-//                         ),
-//                         kind: None,
-//                         text_edits: None,
-//                         tooltip: None,
-//                         padding_left: None,
-//                         padding_right: None,
-//                         data: None,
-//                     };
-
-//                     let edited = task_editor_edited.load(Ordering::Acquire);
-//                     Ok(Some(
-//                         std::iter::once(out_of_range_hint)
-//                             .chain(positions.into_iter().enumerate().map(|(i, position)| {
-//                                 lsp::InlayHint {
-//                                     position,
-//                                     label: lsp::InlayHintLabel::String(format!(
-//                                         "{hint_text}{} #{i}",
-//                                         if edited { "(edited)" } else { "" },
-//                                     )),
-//                                     kind: None,
-//                                     text_edits: None,
-//                                     tooltip: None,
-//                                     padding_left: None,
-//                                     padding_right: None,
-//                                     data: None,
-//                                 }
-//                             }))
-//                             .collect(),
-//                     ))
-//                 }
-//             })
-//             .next()
-//             .await;
-//         cx.foreground().run_until_parked();
-
-//         editor.update(cx, |editor, cx| {
-//             let expected_hints = vec![
-//                 "main hint #0".to_string(),
-//                 "main hint #1".to_string(),
-//                 "main hint #2".to_string(),
-//                 "main hint #3".to_string(),
-//             ];
-//             assert_eq!(
-//                 expected_hints,
-//                 cached_hint_labels(editor),
-//                 "When scroll is at the edge of a multibuffer, its visible excerpts only should be queried for inlay hints"
-//             );
-//             assert_eq!(expected_hints, visible_hint_labels(editor, cx));
-//             assert_eq!(editor.inlay_hint_cache().version, expected_hints.len(), "Every visible excerpt hints should bump the verison");
-//         });
-
-//         editor.update(cx, |editor, cx| {
-//             editor.change_selections(Some(Autoscroll::Next), cx, |s| {
-//                 s.select_ranges([Point::new(4, 0)..Point::new(4, 0)])
-//             });
-//             editor.change_selections(Some(Autoscroll::Next), cx, |s| {
-//                 s.select_ranges([Point::new(22, 0)..Point::new(22, 0)])
-//             });
-//             editor.change_selections(Some(Autoscroll::Next), cx, |s| {
-//                 s.select_ranges([Point::new(50, 0)..Point::new(50, 0)])
-//             });
-//         });
-//         cx.foreground().run_until_parked();
-//         editor.update(cx, |editor, cx| {
-//             let expected_hints = vec![
-//                 "main hint #0".to_string(),
-//                 "main hint #1".to_string(),
-//                 "main hint #2".to_string(),
-//                 "main hint #3".to_string(),
-//                 "main hint #4".to_string(),
-//                 "main hint #5".to_string(),
-//                 "other hint #0".to_string(),
-//                 "other hint #1".to_string(),
-//                 "other hint #2".to_string(),
-//             ];
-//             assert_eq!(expected_hints, cached_hint_labels(editor),
-//                 "With more scrolls of the multibuffer, more hints should be added into the cache and nothing invalidated without edits");
-//             assert_eq!(expected_hints, visible_hint_labels(editor, cx));
-//             assert_eq!(editor.inlay_hint_cache().version, expected_hints.len(),
-//                 "Due to every excerpt having one hint, we update cache per new excerpt scrolled");
-//         });
-
-//         editor.update(cx, |editor, cx| {
-//             editor.change_selections(Some(Autoscroll::Next), cx, |s| {
-//                 s.select_ranges([Point::new(100, 0)..Point::new(100, 0)])
-//             });
-//         });
-//         cx.foreground().advance_clock(Duration::from_millis(
-//             INVISIBLE_RANGES_HINTS_REQUEST_DELAY_MILLIS + 100,
-//         ));
-//         cx.foreground().run_until_parked();
-//         let last_scroll_update_version = editor.update(cx, |editor, cx| {
-//             let expected_hints = vec![
-//                 "main hint #0".to_string(),
-//                 "main hint #1".to_string(),
-//                 "main hint #2".to_string(),
-//                 "main hint #3".to_string(),
-//                 "main hint #4".to_string(),
-//                 "main hint #5".to_string(),
-//                 "other hint #0".to_string(),
-//                 "other hint #1".to_string(),
-//                 "other hint #2".to_string(),
-//                 "other hint #3".to_string(),
-//                 "other hint #4".to_string(),
-//                 "other hint #5".to_string(),
-//             ];
-//             assert_eq!(expected_hints, cached_hint_labels(editor),
-//                 "After multibuffer was scrolled to the end, all hints for all excerpts should be fetched");
-//             assert_eq!(expected_hints, visible_hint_labels(editor, cx));
-//             assert_eq!(editor.inlay_hint_cache().version, expected_hints.len());
-//             expected_hints.len()
-//         });
-
-//         editor.update(cx, |editor, cx| {
-//             editor.change_selections(Some(Autoscroll::Next), cx, |s| {
-//                 s.select_ranges([Point::new(4, 0)..Point::new(4, 0)])
-//             });
-//         });
-//         cx.foreground().run_until_parked();
-//         editor.update(cx, |editor, cx| {
-//             let expected_hints = vec![
-//                 "main hint #0".to_string(),
-//                 "main hint #1".to_string(),
-//                 "main hint #2".to_string(),
-//                 "main hint #3".to_string(),
-//                 "main hint #4".to_string(),
-//                 "main hint #5".to_string(),
-//                 "other hint #0".to_string(),
-//                 "other hint #1".to_string(),
-//                 "other hint #2".to_string(),
-//                 "other hint #3".to_string(),
-//                 "other hint #4".to_string(),
-//                 "other hint #5".to_string(),
-//             ];
-//             assert_eq!(expected_hints, cached_hint_labels(editor),
-//                 "After multibuffer was scrolled to the end, further scrolls up should not bring more hints");
-//             assert_eq!(expected_hints, visible_hint_labels(editor, cx));
-//             assert_eq!(editor.inlay_hint_cache().version, last_scroll_update_version, "No updates should happen during scrolling already scolled buffer");
-//         });
-
-//         editor_edited.store(true, Ordering::Release);
-//         editor.update(cx, |editor, cx| {
-//             editor.change_selections(None, cx, |s| {
-//                 s.select_ranges([Point::new(56, 0)..Point::new(56, 0)])
-//             });
-//             editor.handle_input("++++more text++++", cx);
-//         });
-//         cx.foreground().run_until_parked();
-//         editor.update(cx, |editor, cx| {
-//             let expected_hints = vec![
-//                 "main hint(edited) #0".to_string(),
-//                 "main hint(edited) #1".to_string(),
-//                 "main hint(edited) #2".to_string(),
-//                 "main hint(edited) #3".to_string(),
-//                 "main hint(edited) #4".to_string(),
-//                 "main hint(edited) #5".to_string(),
-//                 "other hint(edited) #0".to_string(),
-//                 "other hint(edited) #1".to_string(),
-//             ];
-//             assert_eq!(
-//                 expected_hints,
-//                 cached_hint_labels(editor),
-//                 "After multibuffer edit, editor gets scolled back to the last selection; \
-// all hints should be invalidated and requeried for all of its visible excerpts"
-//             );
-//             assert_eq!(expected_hints, visible_hint_labels(editor, cx));
-
-//             let current_cache_version = editor.inlay_hint_cache().version;
-//             let minimum_expected_version = last_scroll_update_version + expected_hints.len();
-//             assert!(
-//                 current_cache_version == minimum_expected_version || current_cache_version == minimum_expected_version + 1,
-//                 "Due to every excerpt having one hint, cache should update per new excerpt received + 1 potential sporadic update"
-//             );
-//         });
-//     }
-
-//     #[gpui::test]
-//     async fn test_excerpts_removed(
-//         deterministic: Arc<Deterministic>,
-//         cx: &mut gpui::TestAppContext,
-//     ) {
-//         init_test(cx, |settings| {
-//             settings.defaults.inlay_hints = Some(InlayHintSettings {
-//                 enabled: true,
-//                 show_type_hints: false,
-//                 show_parameter_hints: false,
-//                 show_other_hints: false,
-//             })
-//         });
-
-//         let mut language = Language::new(
-//             LanguageConfig {
-//                 name: "Rust".into(),
-//                 path_suffixes: vec!["rs".to_string()],
-//                 ..Default::default()
-//             },
-//             Some(tree_sitter_rust::language()),
-//         );
-//         let mut fake_servers = language
-//             .set_fake_lsp_adapter(Arc::new(FakeLspAdapter {
-//                 capabilities: lsp::ServerCapabilities {
-//                     inlay_hint_provider: Some(lsp::OneOf::Left(true)),
-//                     ..Default::default()
-//                 },
-//                 ..Default::default()
-//             }))
-//             .await;
-//         let language = Arc::new(language);
-//         let fs = FakeFs::new(cx.background());
-//         fs.insert_tree(
-//             "/a",
-//             json!({
-//                 "main.rs": format!("fn main() {{\n{}\n}}", (0..501).map(|i| format!("let i = {i};\n")).collect::<Vec<_>>().join("")),
-//                 "other.rs": format!("fn main() {{\n{}\n}}", (0..501).map(|j| format!("let j = {j};\n")).collect::<Vec<_>>().join("")),
-//             }),
-//         )
-//         .await;
-//         let project = Project::test(fs, ["/a".as_ref()], cx).await;
-//         project.update(cx, |project, _| {
-//             project.languages().add(Arc::clone(&language))
-//         });
-//         let workspace = cx
-//             .add_window(|cx| Workspace::test_new(project.clone(), cx))
-//             .root(cx);
-//         let worktree_id = workspace.update(cx, |workspace, cx| {
-//             workspace.project().read_with(cx, |project, cx| {
-//                 project.worktrees(cx).next().unwrap().read(cx).id()
-//             })
-//         });
-
-//         let buffer_1 = project
-//             .update(cx, |project, cx| {
-//                 project.open_buffer((worktree_id, "main.rs"), cx)
-//             })
-//             .await
-//             .unwrap();
-//         let buffer_2 = project
-//             .update(cx, |project, cx| {
-//                 project.open_buffer((worktree_id, "other.rs"), cx)
-//             })
-//             .await
-//             .unwrap();
-//         let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
-//         let (buffer_1_excerpts, buffer_2_excerpts) = multibuffer.update(cx, |multibuffer, cx| {
-//             let buffer_1_excerpts = multibuffer.push_excerpts(
-//                 buffer_1.clone(),
-//                 [ExcerptRange {
-//                     context: Point::new(0, 0)..Point::new(2, 0),
-//                     primary: None,
-//                 }],
-//                 cx,
-//             );
-//             let buffer_2_excerpts = multibuffer.push_excerpts(
-//                 buffer_2.clone(),
-//                 [ExcerptRange {
-//                     context: Point::new(0, 1)..Point::new(2, 1),
-//                     primary: None,
-//                 }],
-//                 cx,
-//             );
-//             (buffer_1_excerpts, buffer_2_excerpts)
-//         });
-
-//         assert!(!buffer_1_excerpts.is_empty());
-//         assert!(!buffer_2_excerpts.is_empty());
-
-//         deterministic.run_until_parked();
-//         cx.foreground().run_until_parked();
-//         let editor = cx
-//             .add_window(|cx| Editor::for_multibuffer(multibuffer, Some(project.clone()), cx))
-//             .root(cx);
-//         let editor_edited = Arc::new(AtomicBool::new(false));
-//         let fake_server = fake_servers.next().await.unwrap();
-//         let closure_editor_edited = Arc::clone(&editor_edited);
-//         fake_server
-//             .handle_request::<lsp::request::InlayHintRequest, _, _>(move |params, _| {
-//                 let task_editor_edited = Arc::clone(&closure_editor_edited);
-//                 async move {
-//                     let hint_text = if params.text_document.uri
-//                         == lsp::Url::from_file_path("/a/main.rs").unwrap()
-//                     {
-//                         "main hint"
-//                     } else if params.text_document.uri
-//                         == lsp::Url::from_file_path("/a/other.rs").unwrap()
-//                     {
-//                         "other hint"
-//                     } else {
-//                         panic!("unexpected uri: {:?}", params.text_document.uri);
-//                     };
-
-//                     let positions = [
-//                         lsp::Position::new(0, 2),
-//                         lsp::Position::new(4, 2),
-//                         lsp::Position::new(22, 2),
-//                         lsp::Position::new(44, 2),
-//                         lsp::Position::new(56, 2),
-//                         lsp::Position::new(67, 2),
-//                     ];
-//                     let out_of_range_hint = lsp::InlayHint {
-//                         position: lsp::Position::new(
-//                             params.range.start.line + 99,
-//                             params.range.start.character + 99,
-//                         ),
-//                         label: lsp::InlayHintLabel::String(
-//                             "out of excerpt range, should be ignored".to_string(),
-//                         ),
-//                         kind: None,
-//                         text_edits: None,
-//                         tooltip: None,
-//                         padding_left: None,
-//                         padding_right: None,
-//                         data: None,
-//                     };
-
-//                     let edited = task_editor_edited.load(Ordering::Acquire);
-//                     Ok(Some(
-//                         std::iter::once(out_of_range_hint)
-//                             .chain(positions.into_iter().enumerate().map(|(i, position)| {
-//                                 lsp::InlayHint {
-//                                     position,
-//                                     label: lsp::InlayHintLabel::String(format!(
-//                                         "{hint_text}{} #{i}",
-//                                         if edited { "(edited)" } else { "" },
-//                                     )),
-//                                     kind: None,
-//                                     text_edits: None,
-//                                     tooltip: None,
-//                                     padding_left: None,
-//                                     padding_right: None,
-//                                     data: None,
-//                                 }
-//                             }))
-//                             .collect(),
-//                     ))
-//                 }
-//             })
-//             .next()
-//             .await;
-//         cx.foreground().run_until_parked();
-
-//         editor.update(cx, |editor, cx| {
-//             assert_eq!(
-//                 vec!["main hint #0".to_string(), "other hint #0".to_string()],
-//                 cached_hint_labels(editor),
-//                 "Cache should update for both excerpts despite hints display was disabled"
-//             );
-//             assert!(
-//                 visible_hint_labels(editor, cx).is_empty(),
-//                 "All hints are disabled and should not be shown despite being present in the cache"
-//             );
-//             assert_eq!(
-//                 editor.inlay_hint_cache().version,
-//                 2,
-//                 "Cache should update once per excerpt query"
-//             );
-//         });
-
-//         editor.update(cx, |editor, cx| {
-//             editor.buffer().update(cx, |multibuffer, cx| {
-//                 multibuffer.remove_excerpts(buffer_2_excerpts, cx)
-//             })
-//         });
-//         cx.foreground().run_until_parked();
-//         editor.update(cx, |editor, cx| {
-//             assert_eq!(
-//                 vec!["main hint #0".to_string()],
-//                 cached_hint_labels(editor),
-//                 "For the removed excerpt, should clean corresponding cached hints"
-//             );
-//             assert!(
-//                 visible_hint_labels(editor, cx).is_empty(),
-//                 "All hints are disabled and should not be shown despite being present in the cache"
-//             );
-//             assert_eq!(
-//                 editor.inlay_hint_cache().version,
-//                 3,
-//                 "Excerpt removal should trigger a cache update"
-//             );
-//         });
-
-//         update_test_language_settings(cx, |settings| {
-//             settings.defaults.inlay_hints = Some(InlayHintSettings {
-//                 enabled: true,
-//                 show_type_hints: true,
-//                 show_parameter_hints: true,
-//                 show_other_hints: true,
-//             })
-//         });
-//         cx.foreground().run_until_parked();
-//         editor.update(cx, |editor, cx| {
-//             let expected_hints = vec!["main hint #0".to_string()];
-//             assert_eq!(
-//                 expected_hints,
-//                 cached_hint_labels(editor),
-//                 "Hint display settings change should not change the cache"
-//             );
-//             assert_eq!(
-//                 expected_hints,
-//                 visible_hint_labels(editor, cx),
-//                 "Settings change should make cached hints visible"
-//             );
-//             assert_eq!(
-//                 editor.inlay_hint_cache().version,
-//                 4,
-//                 "Settings change should trigger a cache update"
-//             );
-//         });
-//     }
-
-//     #[gpui::test]
-//     async fn test_inside_char_boundary_range_hints(cx: &mut gpui::TestAppContext) {
-//         init_test(cx, |settings| {
-//             settings.defaults.inlay_hints = Some(InlayHintSettings {
-//                 enabled: true,
-//                 show_type_hints: true,
-//                 show_parameter_hints: true,
-//                 show_other_hints: true,
-//             })
-//         });
-
-//         let mut language = Language::new(
-//             LanguageConfig {
-//                 name: "Rust".into(),
-//                 path_suffixes: vec!["rs".to_string()],
-//                 ..Default::default()
-//             },
-//             Some(tree_sitter_rust::language()),
-//         );
-//         let mut fake_servers = language
-//             .set_fake_lsp_adapter(Arc::new(FakeLspAdapter {
-//                 capabilities: lsp::ServerCapabilities {
-//                     inlay_hint_provider: Some(lsp::OneOf::Left(true)),
-//                     ..Default::default()
-//                 },
-//                 ..Default::default()
-//             }))
-//             .await;
-//         let fs = FakeFs::new(cx.background());
-//         fs.insert_tree(
-//             "/a",
-//             json!({
-//                 "main.rs": format!(r#"fn main() {{\n{}\n}}"#, format!("let i = {};\n", "√".repeat(10)).repeat(500)),
-//                 "other.rs": "// Test file",
-//             }),
-//         )
-//         .await;
-//         let project = Project::test(fs, ["/a".as_ref()], cx).await;
-//         project.update(cx, |project, _| project.languages().add(Arc::new(language)));
-//         let workspace = cx
-//             .add_window(|cx| Workspace::test_new(project.clone(), cx))
-//             .root(cx);
-//         let worktree_id = workspace.update(cx, |workspace, cx| {
-//             workspace.project().read_with(cx, |project, cx| {
-//                 project.worktrees(cx).next().unwrap().read(cx).id()
-//             })
-//         });
-
-//         let _buffer = project
-//             .update(cx, |project, cx| {
-//                 project.open_local_buffer("/a/main.rs", cx)
-//             })
-//             .await
-//             .unwrap();
-//         cx.foreground().run_until_parked();
-//         cx.foreground().start_waiting();
-//         let fake_server = fake_servers.next().await.unwrap();
-//         let editor = workspace
-//             .update(cx, |workspace, cx| {
-//                 workspace.open_path((worktree_id, "main.rs"), None, true, cx)
-//             })
-//             .await
-//             .unwrap()
-//             .downcast::<Editor>()
-//             .unwrap();
-//         let lsp_request_count = Arc::new(AtomicU32::new(0));
-//         let closure_lsp_request_count = Arc::clone(&lsp_request_count);
-//         fake_server
-//             .handle_request::<lsp::request::InlayHintRequest, _, _>(move |params, _| {
-//                 let task_lsp_request_count = Arc::clone(&closure_lsp_request_count);
-//                 async move {
-//                     assert_eq!(
-//                         params.text_document.uri,
-//                         lsp::Url::from_file_path("/a/main.rs").unwrap(),
-//                     );
-//                     let query_start = params.range.start;
-//                     let i = Arc::clone(&task_lsp_request_count).fetch_add(1, Ordering::Release) + 1;
-//                     Ok(Some(vec![lsp::InlayHint {
-//                         position: query_start,
-//                         label: lsp::InlayHintLabel::String(i.to_string()),
-//                         kind: None,
-//                         text_edits: None,
-//                         tooltip: None,
-//                         padding_left: None,
-//                         padding_right: None,
-//                         data: None,
-//                     }]))
-//                 }
-//             })
-//             .next()
-//             .await;
-
-//         cx.foreground().run_until_parked();
-//         editor.update(cx, |editor, cx| {
-//             editor.change_selections(None, cx, |s| {
-//                 s.select_ranges([Point::new(10, 0)..Point::new(10, 0)])
-//             })
-//         });
-//         cx.foreground().run_until_parked();
-//         editor.update(cx, |editor, cx| {
-//             let expected_hints = vec!["1".to_string()];
-//             assert_eq!(expected_hints, cached_hint_labels(editor));
-//             assert_eq!(expected_hints, visible_hint_labels(editor, cx));
-//             assert_eq!(editor.inlay_hint_cache().version, 1);
-//         });
-//     }
-
-//     #[gpui::test]
-//     async fn test_toggle_inlay_hints(cx: &mut gpui::TestAppContext) {
-//         init_test(cx, |settings| {
-//             settings.defaults.inlay_hints = Some(InlayHintSettings {
-//                 enabled: false,
-//                 show_type_hints: true,
-//                 show_parameter_hints: true,
-//                 show_other_hints: true,
-//             })
-//         });
-
-//         let (file_with_hints, editor, fake_server) = prepare_test_objects(cx).await;
-
-//         editor.update(cx, |editor, cx| {
-//             editor.toggle_inlay_hints(&crate::ToggleInlayHints, cx)
-//         });
-//         cx.foreground().start_waiting();
-//         let lsp_request_count = Arc::new(AtomicU32::new(0));
-//         let closure_lsp_request_count = Arc::clone(&lsp_request_count);
-//         fake_server
-//             .handle_request::<lsp::request::InlayHintRequest, _, _>(move |params, _| {
-//                 let task_lsp_request_count = Arc::clone(&closure_lsp_request_count);
-//                 async move {
-//                     assert_eq!(
-//                         params.text_document.uri,
-//                         lsp::Url::from_file_path(file_with_hints).unwrap(),
-//                     );
-
-//                     let i = Arc::clone(&task_lsp_request_count).fetch_add(1, Ordering::SeqCst) + 1;
-//                     Ok(Some(vec![lsp::InlayHint {
-//                         position: lsp::Position::new(0, i),
-//                         label: lsp::InlayHintLabel::String(i.to_string()),
-//                         kind: None,
-//                         text_edits: None,
-//                         tooltip: None,
-//                         padding_left: None,
-//                         padding_right: None,
-//                         data: None,
-//                     }]))
-//                 }
-//             })
-//             .next()
-//             .await;
-//         cx.foreground().run_until_parked();
-//         editor.update(cx, |editor, cx| {
-//             let expected_hints = vec!["1".to_string()];
-//             assert_eq!(
-//                 expected_hints,
-//                 cached_hint_labels(editor),
-//                 "Should display inlays after toggle despite them disabled in settings"
-//             );
-//             assert_eq!(expected_hints, visible_hint_labels(editor, cx));
-//             assert_eq!(
-//                 editor.inlay_hint_cache().version,
-//                 1,
-//                 "First toggle should be cache's first update"
-//             );
-//         });
-
-//         editor.update(cx, |editor, cx| {
-//             editor.toggle_inlay_hints(&crate::ToggleInlayHints, cx)
-//         });
-//         cx.foreground().run_until_parked();
-//         editor.update(cx, |editor, cx| {
-//             assert!(
-//                 cached_hint_labels(editor).is_empty(),
-//                 "Should clear hints after 2nd toggle"
-//             );
-//             assert!(visible_hint_labels(editor, cx).is_empty());
-//             assert_eq!(editor.inlay_hint_cache().version, 2);
-//         });
-
-//         update_test_language_settings(cx, |settings| {
-//             settings.defaults.inlay_hints = Some(InlayHintSettings {
-//                 enabled: true,
-//                 show_type_hints: true,
-//                 show_parameter_hints: true,
-//                 show_other_hints: true,
-//             })
-//         });
-//         cx.foreground().run_until_parked();
-//         editor.update(cx, |editor, cx| {
-//             let expected_hints = vec!["2".to_string()];
-//             assert_eq!(
-//                 expected_hints,
-//                 cached_hint_labels(editor),
-//                 "Should query LSP hints for the 2nd time after enabling hints in settings"
-//             );
-//             assert_eq!(expected_hints, visible_hint_labels(editor, cx));
-//             assert_eq!(editor.inlay_hint_cache().version, 3);
-//         });
-
-//         editor.update(cx, |editor, cx| {
-//             editor.toggle_inlay_hints(&crate::ToggleInlayHints, cx)
-//         });
-//         cx.foreground().run_until_parked();
-//         editor.update(cx, |editor, cx| {
-//             assert!(
-//                 cached_hint_labels(editor).is_empty(),
-//                 "Should clear hints after enabling in settings and a 3rd toggle"
-//             );
-//             assert!(visible_hint_labels(editor, cx).is_empty());
-//             assert_eq!(editor.inlay_hint_cache().version, 4);
-//         });
-
-//         editor.update(cx, |editor, cx| {
-//             editor.toggle_inlay_hints(&crate::ToggleInlayHints, cx)
-//         });
-//         cx.foreground().run_until_parked();
-//         editor.update(cx, |editor, cx| {
-//             let expected_hints = vec!["3".to_string()];
-//             assert_eq!(
-//                 expected_hints,
-//                 cached_hint_labels(editor),
-//                 "Should query LSP hints for the 3rd time after enabling hints in settings and toggling them back on"
-//             );
-//             assert_eq!(expected_hints, visible_hint_labels(editor, cx));
-//             assert_eq!(editor.inlay_hint_cache().version, 5);
-//         });
-//     }
-
-//     pub(crate) fn init_test(cx: &mut TestAppContext, f: impl Fn(&mut AllLanguageSettingsContent)) {
-//         cx.foreground().forbid_parking();
-
-//         cx.update(|cx| {
-//             cx.set_global(SettingsStore::test(cx));
-//             theme::init(cx);
-//             client::init_settings(cx);
-//             language::init(cx);
-//             Project::init_settings(cx);
-//             workspace::init_settings(cx);
-//             crate::init(cx);
-//         });
-
-//         update_test_language_settings(cx, f);
-//     }
-
-//     async fn prepare_test_objects(
-//         cx: &mut TestAppContext,
-//     ) -> (&'static str, ViewHandle<Editor>, FakeLanguageServer) {
-//         let mut language = Language::new(
-//             LanguageConfig {
-//                 name: "Rust".into(),
-//                 path_suffixes: vec!["rs".to_string()],
-//                 ..Default::default()
-//             },
-//             Some(tree_sitter_rust::language()),
-//         );
-//         let mut fake_servers = language
-//             .set_fake_lsp_adapter(Arc::new(FakeLspAdapter {
-//                 capabilities: lsp::ServerCapabilities {
-//                     inlay_hint_provider: Some(lsp::OneOf::Left(true)),
-//                     ..Default::default()
-//                 },
-//                 ..Default::default()
-//             }))
-//             .await;
-
-//         let fs = FakeFs::new(cx.background());
-//         fs.insert_tree(
-//             "/a",
-//             json!({
-//                 "main.rs": "fn main() { a } // and some long comment to ensure inlays are not trimmed out",
-//                 "other.rs": "// Test file",
-//             }),
-//         )
-//         .await;
-
-//         let project = Project::test(fs, ["/a".as_ref()], cx).await;
-//         project.update(cx, |project, _| project.languages().add(Arc::new(language)));
-//         let workspace = cx
-//             .add_window(|cx| Workspace::test_new(project.clone(), cx))
-//             .root(cx);
-//         let worktree_id = workspace.update(cx, |workspace, cx| {
-//             workspace.project().read_with(cx, |project, cx| {
-//                 project.worktrees(cx).next().unwrap().read(cx).id()
-//             })
-//         });
-
-//         let _buffer = project
-//             .update(cx, |project, cx| {
-//                 project.open_local_buffer("/a/main.rs", cx)
-//             })
-//             .await
-//             .unwrap();
-//         cx.foreground().run_until_parked();
-//         cx.foreground().start_waiting();
-//         let fake_server = fake_servers.next().await.unwrap();
-//         let editor = workspace
-//             .update(cx, |workspace, cx| {
-//                 workspace.open_path((worktree_id, "main.rs"), None, true, cx)
-//             })
-//             .await
-//             .unwrap()
-//             .downcast::<Editor>()
-//             .unwrap();
-
-//         editor.update(cx, |editor, cx| {
-//             assert!(cached_hint_labels(editor).is_empty());
-//             assert!(visible_hint_labels(editor, cx).is_empty());
-//             assert_eq!(editor.inlay_hint_cache().version, 0);
-//         });
-
-//         ("/a/main.rs", editor, fake_server)
-//     }
-
-//     pub fn cached_hint_labels(editor: &Editor) -> Vec<String> {
-//         let mut labels = Vec::new();
-//         for (_, excerpt_hints) in &editor.inlay_hint_cache().hints {
-//             let excerpt_hints = excerpt_hints.read();
-//             for id in &excerpt_hints.ordered_hints {
-//                 labels.push(excerpt_hints.hints_by_id[id].text());
-//             }
-//         }
-
-//         labels.sort();
-//         labels
-//     }
-
-//     pub fn visible_hint_labels(editor: &Editor, cx: &ViewContext<'_, '_, Editor>) -> Vec<String> {
-//         let mut hints = editor
-//             .visible_inlay_hints(cx)
-//             .into_iter()
-//             .map(|hint| hint.text.to_string())
-//             .collect::<Vec<_>>();
-//         hints.sort();
-//         hints
-//     }
-// }

crates/editor2/src/items.rs πŸ”—

@@ -1,7 +1,8 @@
 use crate::{
-    display_map::ToDisplayPoint, link_go_to_definition::hide_link_definition,
+    editor_settings::SeedQuerySetting, link_go_to_definition::hide_link_definition,
     movement::surrounding_word, persistence::DB, scroll::ScrollAnchor, Anchor, Autoscroll, Editor,
-    Event, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, NavigationData, ToPoint as _,
+    EditorSettings, Event, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot,
+    NavigationData, ToPoint as _,
 };
 use anyhow::{anyhow, Context, Result};
 use collections::HashSet;
@@ -12,11 +13,12 @@ use gpui::{
     ViewContext, VisualContext, WeakView,
 };
 use language::{
-    proto::serialize_anchor as serialize_text_anchor, Bias, Buffer, OffsetRangeExt, Point,
-    SelectionGoal,
+    proto::serialize_anchor as serialize_text_anchor, Bias, Buffer, CharKind, OffsetRangeExt,
+    Point, SelectionGoal,
 };
 use project::{search::SearchQuery, FormatTrigger, Item as _, Project, ProjectPath};
 use rpc::proto::{self, update_view, PeerId};
+use settings::Settings;
 use smallvec::SmallVec;
 use std::{
     borrow::Cow,
@@ -918,24 +920,28 @@ impl SearchableItem for Editor {
     }
 
     fn query_suggestion(&mut self, cx: &mut ViewContext<Self>) -> String {
-        let display_map = self.snapshot(cx).display_snapshot;
+        let setting = EditorSettings::get_global(cx).seed_search_query_from_cursor;
+        let snapshot = &self.snapshot(cx).buffer_snapshot;
         let selection = self.selections.newest::<usize>(cx);
-        if selection.start == selection.end {
-            let point = selection.start.to_display_point(&display_map);
-            let range = surrounding_word(&display_map, point);
-            let range = range.start.to_offset(&display_map, Bias::Left)
-                ..range.end.to_offset(&display_map, Bias::Right);
-            let text: String = display_map.buffer_snapshot.text_for_range(range).collect();
-            if text.trim().is_empty() {
+
+        match setting {
+            SeedQuerySetting::Never => String::new(),
+            SeedQuerySetting::Selection | SeedQuerySetting::Always if !selection.is_empty() => {
+                snapshot
+                    .text_for_range(selection.start..selection.end)
+                    .collect()
+            }
+            SeedQuerySetting::Selection => String::new(),
+            SeedQuerySetting::Always => {
+                let (range, kind) = snapshot.surrounding_word(selection.start);
+                if kind == Some(CharKind::Word) {
+                    let text: String = snapshot.text_for_range(range).collect();
+                    if !text.trim().is_empty() {
+                        return text;
+                    }
+                }
                 String::new()
-            } else {
-                text
             }
-        } else {
-            display_map
-                .buffer_snapshot
-                .text_for_range(selection.start..selection.end)
-                .collect()
         }
     }
 

crates/editor2/src/scroll/scroll_amount.rs πŸ”—

@@ -11,19 +11,18 @@ pub enum ScrollAmount {
 
 impl ScrollAmount {
     pub fn lines(&self, editor: &mut Editor) -> f32 {
-        todo!()
-        // match self {
-        //     Self::Line(count) => *count,
-        //     Self::Page(count) => editor
-        //         .visible_line_count()
-        //         .map(|mut l| {
-        //             // for full pages subtract one to leave an anchor line
-        //             if count.abs() == 1.0 {
-        //                 l -= 1.0
-        //             }
-        //             (l * count).trunc()
-        //         })
-        //         .unwrap_or(0.),
-        // }
+        match self {
+            Self::Line(count) => *count,
+            Self::Page(count) => editor
+                .visible_line_count()
+                .map(|mut l| {
+                    // for full pages subtract one to leave an anchor line
+                    if count.abs() == 1.0 {
+                        l -= 1.0
+                    }
+                    (l * count).trunc()
+                })
+                .unwrap_or(0.),
+        }
     }
 }

crates/go_to_line2/src/go_to_line.rs πŸ”—

@@ -8,25 +8,12 @@ use text::{Bias, Point};
 use theme::ActiveTheme;
 use ui::{h_stack, modal, v_stack, Label, LabelColor};
 use util::paths::FILE_ROW_COLUMN_DELIMITER;
-use workspace::{ModalEvent, Workspace};
+use workspace::{Modal, ModalEvent, Workspace};
 
 actions!(Toggle);
 
 pub fn init(cx: &mut AppContext) {
-    cx.observe_new_views(
-        |workspace: &mut Workspace, _: &mut ViewContext<Workspace>| {
-            workspace
-                .modal_layer()
-                .register_modal(Toggle, |workspace, cx| {
-                    let editor = workspace
-                        .active_item(cx)
-                        .and_then(|active_item| active_item.downcast::<Editor>())?;
-
-                    Some(cx.build_view(|cx| GoToLine::new(editor, cx)))
-                });
-        },
-    )
-    .detach();
+    cx.observe_new_views(GoToLine::register).detach();
 }
 
 pub struct GoToLine {
@@ -37,21 +24,29 @@ pub struct GoToLine {
     _subscriptions: Vec<Subscription>,
 }
 
-pub enum Event {
-    Dismissed,
-}
-
-impl EventEmitter<Event> for GoToLine {}
-
 impl EventEmitter<ModalEvent> for GoToLine {}
+impl Modal for GoToLine {
+    fn focus(&self, cx: &mut WindowContext) {
+        self.line_editor.update(cx, |editor, cx| editor.focus(cx))
+    }
+}
 
 impl GoToLine {
-    pub fn new(active_editor: View<Editor>, cx: &mut ViewContext<Self>) -> Self {
-        let line_editor = cx.build_view(|cx| {
-            let editor = Editor::single_line(cx);
-            editor.focus(cx);
-            editor
+    fn register(workspace: &mut Workspace, _: &mut ViewContext<Workspace>) {
+        workspace.register_action(|workspace, _: &Toggle, cx| {
+            let Some(editor) = workspace
+                .active_item(cx)
+                .and_then(|active_item| active_item.downcast::<Editor>())
+            else {
+                return;
+            };
+
+            workspace.toggle_modal(cx, move |cx| GoToLine::new(editor, cx));
         });
+    }
+
+    pub fn new(active_editor: View<Editor>, cx: &mut ViewContext<Self>) -> Self {
+        let line_editor = cx.build_view(|cx| Editor::single_line(cx));
         let line_editor_change = cx.subscribe(&line_editor, Self::on_line_editor_event);
 
         let editor = active_editor.read(cx);
@@ -78,7 +73,6 @@ impl GoToLine {
     fn release(&mut self, cx: &mut WindowContext) {
         let scroll_position = self.prev_scroll_position.take();
         self.active_editor.update(cx, |editor, cx| {
-            editor.focus(cx);
             editor.highlight_rows(None);
             if let Some(scroll_position) = scroll_position {
                 editor.set_scroll_position(scroll_position, cx);
@@ -95,7 +89,7 @@ impl GoToLine {
     ) {
         match event {
             // todo!() this isn't working...
-            editor::Event::Blurred => cx.emit(Event::Dismissed),
+            editor::Event::Blurred => cx.emit(ModalEvent::Dismissed),
             editor::Event::BufferEdited { .. } => self.highlight_current_line(cx),
             _ => {}
         }
@@ -130,22 +124,24 @@ impl GoToLine {
     }
 
     fn cancel(&mut self, _: &menu::Cancel, cx: &mut ViewContext<Self>) {
-        cx.emit(Event::Dismissed);
+        cx.emit(ModalEvent::Dismissed);
     }
 
     fn confirm(&mut self, _: &menu::Confirm, cx: &mut ViewContext<Self>) {
         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;
+            self.active_editor.update(cx, |editor, cx| {
+                let snapshot = editor.snapshot(cx).display_snapshot;
                 let point = snapshot.buffer_snapshot.clip_point(point, Bias::Left);
-                active_editor.change_selections(Some(Autoscroll::center()), cx, |s| {
+                editor.change_selections(Some(Autoscroll::center()), cx, |s| {
                     s.select_ranges([point..point])
                 });
+                editor.focus(cx);
+                cx.notify();
             });
             self.prev_scroll_position.take();
         }
 
-        cx.emit(Event::Dismissed);
+        cx.emit(ModalEvent::Dismissed);
     }
 }
 

crates/gpui/src/elements/flex.rs πŸ”—

@@ -67,14 +67,21 @@ impl<V: 'static> Flex<V> {
     where
         Tag: 'static,
     {
+        // Don't assume that this initialization is what scroll_state really is in other panes:
+        // `element_state` is shared and there could be init races.
         let scroll_state = cx.element_state::<Tag, Rc<ScrollState>>(
             element_id,
             Rc::new(ScrollState {
-                scroll_to: Cell::new(scroll_to),
-                scroll_position: Default::default(),
                 type_tag: TypeTag::new::<Tag>(),
+                scroll_to: Default::default(),
+                scroll_position: Default::default(),
             }),
         );
+        // Set scroll_to separately, because the default state is already picked as `None` by other panes
+        // by the time we start setting it here, hence update all others' state too.
+        scroll_state.update(cx, |this, _| {
+            this.scroll_to.set(scroll_to);
+        });
         self.scroll_state = Some((scroll_state, cx.handle().id()));
         self
     }

crates/gpui/src/geometry.rs πŸ”—

@@ -136,7 +136,7 @@ impl ToJson for RectF {
 }
 
 #[derive(Refineable, Debug)]
-#[refineable(debug)]
+#[refineable(Debug)]
 pub struct Point<T: Clone + Default + Debug> {
     pub x: T,
     pub y: T,
@@ -161,7 +161,7 @@ impl<T: Clone + Default + Debug> Into<taffy::geometry::Point<T>> for Point<T> {
 }
 
 #[derive(Refineable, Clone, Debug)]
-#[refineable(debug)]
+#[refineable(Debug)]
 pub struct Size<T: Clone + Default + Debug> {
     pub width: T,
     pub height: T,
@@ -227,7 +227,7 @@ impl Size<Length> {
 }
 
 #[derive(Clone, Default, Refineable, Debug)]
-#[refineable(debug)]
+#[refineable(Debug)]
 pub struct Edges<T: Clone + Default + Debug> {
     pub top: T,
     pub right: T,

crates/gpui2/src/action.rs πŸ”—

@@ -4,7 +4,7 @@ use collections::{HashMap, HashSet};
 use lazy_static::lazy_static;
 use parking_lot::{MappedRwLockReadGuard, RwLock, RwLockReadGuard};
 use serde::Deserialize;
-use std::any::{type_name, Any};
+use std::any::{type_name, Any, TypeId};
 
 /// Actions are used to implement keyboard-driven UI.
 /// When you declare an action, you can bind keys to the action in the keymap and
@@ -100,6 +100,21 @@ where
     }
 }
 
+impl dyn Action {
+    pub fn type_id(&self) -> TypeId {
+        self.as_any().type_id()
+    }
+
+    pub fn name(&self) -> SharedString {
+        ACTION_REGISTRY
+            .read()
+            .names_by_type_id
+            .get(&self.type_id())
+            .expect("type is not a registered action")
+            .clone()
+    }
+}
+
 type ActionBuilder = fn(json: Option<serde_json::Value>) -> anyhow::Result<Box<dyn Action>>;
 
 lazy_static! {
@@ -109,6 +124,7 @@ lazy_static! {
 #[derive(Default)]
 struct ActionRegistry {
     builders_by_name: HashMap<SharedString, ActionBuilder>,
+    names_by_type_id: HashMap<TypeId, SharedString>,
     all_names: Vec<SharedString>, // So we can return a static slice.
 }
 
@@ -117,9 +133,24 @@ pub fn register_action<A: Action>() {
     let name = A::qualified_name();
     let mut lock = ACTION_REGISTRY.write();
     lock.builders_by_name.insert(name.clone(), A::build);
+    lock.names_by_type_id
+        .insert(TypeId::of::<A>(), name.clone());
     lock.all_names.push(name);
 }
 
+/// Construct an action based on its name and optional JSON parameters sourced from the keymap.
+pub fn build_action_from_type(type_id: &TypeId) -> Result<Box<dyn Action>> {
+    let lock = ACTION_REGISTRY.read();
+    let name = lock
+        .names_by_type_id
+        .get(type_id)
+        .ok_or_else(|| anyhow!("no action type registered for {:?}", type_id))?
+        .clone();
+    drop(lock);
+
+    build_action(&name, None)
+}
+
 /// Construct an action based on its name and optional JSON parameters sourced from the keymap.
 pub fn build_action(name: &str, params: Option<serde_json::Value>) -> Result<Box<dyn Action>> {
     let lock = ACTION_REGISTRY.read();

crates/gpui2/src/color.rs πŸ”—

@@ -1,8 +1,8 @@
 #![allow(dead_code)]
 
+use anyhow::bail;
 use serde::de::{self, Deserialize, Deserializer, Visitor};
 use std::fmt;
-use std::num::ParseIntError;
 
 pub fn rgb<C: From<Rgba>>(hex: u32) -> C {
     let r = ((hex >> 16) & 0xFF) as f32 / 255.0;
@@ -19,7 +19,7 @@ pub fn rgba(hex: u32) -> Rgba {
     Rgba { r, g, b, a }
 }
 
-#[derive(Clone, Copy, Default)]
+#[derive(PartialEq, Clone, Copy, Default)]
 pub struct Rgba {
     pub r: f32,
     pub g: f32,
@@ -70,21 +70,7 @@ impl<'de> Visitor<'de> for RgbaVisitor {
     }
 
     fn visit_str<E: de::Error>(self, value: &str) -> Result<Rgba, E> {
-        if value.len() == 7 || value.len() == 9 {
-            let r = u8::from_str_radix(&value[1..3], 16).unwrap() as f32 / 255.0;
-            let g = u8::from_str_radix(&value[3..5], 16).unwrap() as f32 / 255.0;
-            let b = u8::from_str_radix(&value[5..7], 16).unwrap() as f32 / 255.0;
-            let a = if value.len() == 9 {
-                u8::from_str_radix(&value[7..9], 16).unwrap() as f32 / 255.0
-            } else {
-                1.0
-            };
-            Ok(Rgba { r, g, b, a })
-        } else {
-            Err(E::custom(
-                "Bad format for RGBA. Expected #rrggbb or #rrggbbaa.",
-            ))
-        }
+        Rgba::try_from(value).map_err(E::custom)
     }
 }
 
@@ -125,19 +111,59 @@ impl From<Hsla> for Rgba {
 }
 
 impl TryFrom<&'_ str> for Rgba {
-    type Error = ParseIntError;
+    type Error = anyhow::Error;
 
     fn try_from(value: &'_ str) -> Result<Self, Self::Error> {
-        let r = u8::from_str_radix(&value[1..3], 16)? as f32 / 255.0;
-        let g = u8::from_str_radix(&value[3..5], 16)? as f32 / 255.0;
-        let b = u8::from_str_radix(&value[5..7], 16)? as f32 / 255.0;
-        let a = if value.len() > 7 {
-            u8::from_str_radix(&value[7..9], 16)? as f32 / 255.0
-        } else {
-            1.0
+        const RGB: usize = "rgb".len();
+        const RGBA: usize = "rgba".len();
+        const RRGGBB: usize = "rrggbb".len();
+        const RRGGBBAA: usize = "rrggbbaa".len();
+
+        const EXPECTED_FORMATS: &'static str = "Expected #rgb, #rgba, #rrggbb, or #rrggbbaa";
+
+        let Some(("", hex)) = value.trim().split_once('#') else {
+            bail!("invalid RGBA hex color: '{value}'. {EXPECTED_FORMATS}");
+        };
+
+        let (r, g, b, a) = match hex.len() {
+            RGB | RGBA => {
+                let r = u8::from_str_radix(&hex[0..1], 16)?;
+                let g = u8::from_str_radix(&hex[1..2], 16)?;
+                let b = u8::from_str_radix(&hex[2..3], 16)?;
+                let a = if hex.len() == RGBA {
+                    u8::from_str_radix(&hex[3..4], 16)?
+                } else {
+                    0xf
+                };
+
+                /// Duplicates a given hex digit.
+                /// E.g., `0xf` -> `0xff`.
+                const fn duplicate(value: u8) -> u8 {
+                    value << 4 | value
+                }
+
+                (duplicate(r), duplicate(g), duplicate(b), duplicate(a))
+            }
+            RRGGBB | RRGGBBAA => {
+                let r = u8::from_str_radix(&hex[0..2], 16)?;
+                let g = u8::from_str_radix(&hex[2..4], 16)?;
+                let b = u8::from_str_radix(&hex[4..6], 16)?;
+                let a = if hex.len() == RRGGBBAA {
+                    u8::from_str_radix(&hex[6..8], 16)?
+                } else {
+                    0xff
+                };
+                (r, g, b, a)
+            }
+            _ => bail!("invalid RGBA hex color: '{value}'. {EXPECTED_FORMATS}"),
         };
 
-        Ok(Rgba { r, g, b, a })
+        Ok(Rgba {
+            r: r as f32 / 255.,
+            g: g as f32 / 255.,
+            b: b as f32 / 255.,
+            a: a as f32 / 255.,
+        })
     }
 }
 
@@ -344,3 +370,52 @@ impl<'de> Deserialize<'de> for Hsla {
         Ok(Hsla::from(rgba))
     }
 }
+
+#[cfg(test)]
+mod tests {
+    use serde_json::json;
+
+    use super::*;
+
+    #[test]
+    fn test_deserialize_three_value_hex_to_rgba() {
+        let actual: Rgba = serde_json::from_value(json!("#f09")).unwrap();
+
+        assert_eq!(actual, rgba(0xff0099ff))
+    }
+
+    #[test]
+    fn test_deserialize_four_value_hex_to_rgba() {
+        let actual: Rgba = serde_json::from_value(json!("#f09f")).unwrap();
+
+        assert_eq!(actual, rgba(0xff0099ff))
+    }
+
+    #[test]
+    fn test_deserialize_six_value_hex_to_rgba() {
+        let actual: Rgba = serde_json::from_value(json!("#ff0099")).unwrap();
+
+        assert_eq!(actual, rgba(0xff0099ff))
+    }
+
+    #[test]
+    fn test_deserialize_eight_value_hex_to_rgba() {
+        let actual: Rgba = serde_json::from_value(json!("#ff0099ff")).unwrap();
+
+        assert_eq!(actual, rgba(0xff0099ff))
+    }
+
+    #[test]
+    fn test_deserialize_eight_value_hex_with_padding_to_rgba() {
+        let actual: Rgba = serde_json::from_value(json!(" #f5f5f5ff   ")).unwrap();
+
+        assert_eq!(actual, rgba(0xf5f5f5ff))
+    }
+
+    #[test]
+    fn test_deserialize_eight_value_hex_with_mixed_case_to_rgba() {
+        let actual: Rgba = serde_json::from_value(json!("#DeAdbEeF")).unwrap();
+
+        assert_eq!(actual, rgba(0xdeadbeef))
+    }
+}

crates/gpui2/src/element.rs πŸ”—

@@ -1,4 +1,6 @@
-use crate::{BorrowWindow, Bounds, ElementId, LayoutId, Pixels, ViewContext};
+use crate::{
+    AvailableSpace, BorrowWindow, Bounds, ElementId, LayoutId, Pixels, Point, Size, ViewContext,
+};
 use derive_more::{Deref, DerefMut};
 pub(crate) use smallvec::SmallVec;
 use std::{any::Any, mem};
@@ -61,6 +63,19 @@ trait ElementObject<V> {
     fn initialize(&mut self, view_state: &mut V, cx: &mut ViewContext<V>);
     fn layout(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) -> LayoutId;
     fn paint(&mut self, view_state: &mut V, cx: &mut ViewContext<V>);
+    fn measure(
+        &mut self,
+        available_space: Size<AvailableSpace>,
+        view_state: &mut V,
+        cx: &mut ViewContext<V>,
+    ) -> Size<Pixels>;
+    fn draw(
+        &mut self,
+        origin: Point<Pixels>,
+        available_space: Size<AvailableSpace>,
+        view_state: &mut V,
+        cx: &mut ViewContext<V>,
+    );
 }
 
 struct RenderedElement<V: 'static, E: Element<V>> {
@@ -79,6 +94,11 @@ enum ElementRenderPhase<V> {
         layout_id: LayoutId,
         frame_state: Option<V>,
     },
+    LayoutComputed {
+        layout_id: LayoutId,
+        available_space: Size<AvailableSpace>,
+        frame_state: Option<V>,
+    },
     Painted,
 }
 
@@ -135,7 +155,9 @@ where
                 }
             }
             ElementRenderPhase::Start => panic!("must call initialize before layout"),
-            ElementRenderPhase::LayoutRequested { .. } | ElementRenderPhase::Painted => {
+            ElementRenderPhase::LayoutRequested { .. }
+            | ElementRenderPhase::LayoutComputed { .. }
+            | ElementRenderPhase::Painted => {
                 panic!("element rendered twice")
             }
         };
@@ -152,6 +174,11 @@ where
             ElementRenderPhase::LayoutRequested {
                 layout_id,
                 mut frame_state,
+            }
+            | ElementRenderPhase::LayoutComputed {
+                layout_id,
+                mut frame_state,
+                ..
             } => {
                 let bounds = cx.layout_bounds(layout_id);
                 if let Some(id) = self.element.id() {
@@ -171,6 +198,65 @@ where
             _ => panic!("must call layout before paint"),
         };
     }
+
+    fn measure(
+        &mut self,
+        available_space: Size<AvailableSpace>,
+        view_state: &mut V,
+        cx: &mut ViewContext<V>,
+    ) -> Size<Pixels> {
+        if matches!(&self.phase, ElementRenderPhase::Start) {
+            self.initialize(view_state, cx);
+        }
+
+        if matches!(&self.phase, ElementRenderPhase::Initialized { .. }) {
+            self.layout(view_state, cx);
+        }
+
+        let layout_id = match &mut self.phase {
+            ElementRenderPhase::LayoutRequested {
+                layout_id,
+                frame_state,
+            } => {
+                cx.compute_layout(*layout_id, available_space);
+                let layout_id = *layout_id;
+                self.phase = ElementRenderPhase::LayoutComputed {
+                    layout_id,
+                    available_space,
+                    frame_state: frame_state.take(),
+                };
+                layout_id
+            }
+            ElementRenderPhase::LayoutComputed {
+                layout_id,
+                available_space: prev_available_space,
+                ..
+            } => {
+                if available_space != *prev_available_space {
+                    cx.compute_layout(*layout_id, available_space);
+                    *prev_available_space = available_space;
+                }
+                *layout_id
+            }
+            _ => panic!("cannot measure after painting"),
+        };
+
+        cx.layout_bounds(layout_id).size
+    }
+
+    fn draw(
+        &mut self,
+        mut origin: Point<Pixels>,
+        available_space: Size<AvailableSpace>,
+        view_state: &mut V,
+        cx: &mut ViewContext<V>,
+    ) {
+        self.measure(available_space, view_state, cx);
+        // Ignore the element offset when drawing this element, as the origin is already specified
+        // in absolute terms.
+        origin -= cx.element_offset();
+        cx.with_element_offset(Some(origin), |cx| self.paint(view_state, cx))
+    }
 }
 
 pub struct AnyElement<V>(Box<dyn ElementObject<V>>);
@@ -196,6 +282,27 @@ impl<V> AnyElement<V> {
     pub fn paint(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) {
         self.0.paint(view_state, cx)
     }
+
+    /// Initializes this element and performs layout within the given available space to determine its size.
+    pub fn measure(
+        &mut self,
+        available_space: Size<AvailableSpace>,
+        view_state: &mut V,
+        cx: &mut ViewContext<V>,
+    ) -> Size<Pixels> {
+        self.0.measure(available_space, view_state, cx)
+    }
+
+    /// Initializes this element and performs layout in the available space, then paints it at the given origin.
+    pub fn draw(
+        &mut self,
+        origin: Point<Pixels>,
+        available_space: Size<AvailableSpace>,
+        view_state: &mut V,
+        cx: &mut ViewContext<V>,
+    ) {
+        self.0.draw(origin, available_space, view_state, cx)
+    }
 }
 
 pub trait Component<V> {

crates/gpui2/src/elements/text.rs πŸ”—

@@ -101,7 +101,12 @@ impl<V: 'static> Element<V> for Text<V> {
                     .map(|line| line.wrap_count() + 1)
                     .sum::<usize>();
                 let size = Size {
-                    width: lines.iter().map(|line| line.layout.width).max().unwrap(),
+                    width: lines
+                        .iter()
+                        .map(|line| line.layout.width)
+                        .max()
+                        .unwrap()
+                        .ceil(),
                     height: line_height * line_count,
                 };
 

crates/gpui2/src/elements/uniform_list.rs πŸ”—

@@ -1,6 +1,6 @@
 use crate::{
-    point, px, AnyElement, AvailableSpace, BorrowWindow, Bounds, Component, Element, ElementId,
-    ElementInteractivity, InteractiveElementState, LayoutId, Pixels, Point, Size,
+    point, px, size, AnyElement, AvailableSpace, BorrowWindow, Bounds, Component, Element,
+    ElementId, ElementInteractivity, InteractiveElementState, LayoutId, Pixels, Point, Size,
     StatefulInteractive, StatefulInteractivity, StatelessInteractive, StatelessInteractivity,
     StyleRefinement, Styled, ViewContext,
 };
@@ -9,6 +9,9 @@ use smallvec::SmallVec;
 use std::{cmp, ops::Range, sync::Arc};
 use taffy::style::Overflow;
 
+/// uniform_list provides lazy rendering for a set of items that are of uniform height.
+/// When rendered into a container with overflow-y: hidden and a fixed (or max) height,
+/// uniform_list will only render the visibile subset of items.
 pub fn uniform_list<Id, V, C>(
     id: Id,
     item_count: usize,
@@ -20,10 +23,14 @@ where
     C: Component<V>,
 {
     let id = id.into();
+    let mut style = StyleRefinement::default();
+    style.overflow.y = Some(Overflow::Hidden);
+
     UniformList {
         id: id.clone(),
-        style: Default::default(),
+        style,
         item_count,
+        item_to_measure_index: 0,
         render_items: Box::new(move |view, visible_range, cx| {
             f(view, visible_range, cx)
                 .into_iter()
@@ -39,6 +46,7 @@ pub struct UniformList<V: 'static> {
     id: ElementId,
     style: StyleRefinement,
     item_count: usize,
+    item_to_measure_index: usize,
     render_items: Box<
         dyn for<'a> Fn(
             &'a mut V,
@@ -50,7 +58,7 @@ pub struct UniformList<V: 'static> {
     scroll_handle: Option<UniformListScrollHandle>,
 }
 
-#[derive(Clone)]
+#[derive(Clone, Default)]
 pub struct UniformListScrollHandle(Arc<Mutex<Option<ScrollHandleState>>>);
 
 #[derive(Clone, Debug)]
@@ -86,8 +94,14 @@ impl<V: 'static> Styled for UniformList<V> {
     }
 }
 
+#[derive(Default)]
+pub struct UniformListState {
+    interactive: InteractiveElementState,
+    item_size: Size<Pixels>,
+}
+
 impl<V: 'static> Element<V> for UniformList<V> {
-    type ElementState = InteractiveElementState;
+    type ElementState = UniformListState;
 
     fn id(&self) -> Option<crate::ElementId> {
         Some(self.id.clone())
@@ -95,20 +109,47 @@ impl<V: 'static> Element<V> for UniformList<V> {
 
     fn initialize(
         &mut self,
-        _: &mut V,
+        view_state: &mut V,
         element_state: Option<Self::ElementState>,
-        _: &mut ViewContext<V>,
+        cx: &mut ViewContext<V>,
     ) -> Self::ElementState {
-        element_state.unwrap_or_default()
+        element_state.unwrap_or_else(|| {
+            let item_size = self.measure_item(view_state, None, cx);
+            UniformListState {
+                interactive: InteractiveElementState::default(),
+                item_size,
+            }
+        })
     }
 
     fn layout(
         &mut self,
         _view_state: &mut V,
-        _element_state: &mut Self::ElementState,
+        element_state: &mut Self::ElementState,
         cx: &mut ViewContext<V>,
     ) -> LayoutId {
-        cx.request_layout(&self.computed_style(), None)
+        let max_items = self.item_count;
+        let item_size = element_state.item_size;
+        let rem_size = cx.rem_size();
+
+        cx.request_measured_layout(
+            self.computed_style(),
+            rem_size,
+            move |known_dimensions: Size<Option<Pixels>>, available_space: Size<AvailableSpace>| {
+                let desired_height = item_size.height * max_items;
+                let width = known_dimensions
+                    .width
+                    .unwrap_or(match available_space.width {
+                        AvailableSpace::Definite(x) => x,
+                        AvailableSpace::MinContent | AvailableSpace::MaxContent => item_size.width,
+                    });
+                let height = match available_space.height {
+                    AvailableSpace::Definite(x) => desired_height.min(x),
+                    AvailableSpace::MinContent | AvailableSpace::MaxContent => desired_height,
+                };
+                size(width, height)
+            },
+        )
     }
 
     fn paint(
@@ -119,7 +160,6 @@ impl<V: 'static> Element<V> for UniformList<V> {
         cx: &mut ViewContext<V>,
     ) {
         let style = self.computed_style();
-        style.paint(bounds, cx);
 
         let border = style.border_widths.to_pixels(cx.rem_size());
         let padding = style.padding.to_pixels(bounds.size.into(), cx.rem_size());
@@ -131,14 +171,18 @@ impl<V: 'static> Element<V> for UniformList<V> {
         );
 
         cx.with_z_index(style.z_index.unwrap_or(0), |cx| {
+            style.paint(bounds, cx);
+
             let content_size;
             if self.item_count > 0 {
-                let item_height = self.measure_item_height(view_state, padded_bounds, cx);
+                let item_height = self
+                    .measure_item(view_state, Some(padded_bounds.size.width), cx)
+                    .height;
                 if let Some(scroll_handle) = self.scroll_handle.clone() {
                     scroll_handle.0.lock().replace(ScrollHandleState {
                         item_height,
                         list_height: padded_bounds.size.height,
-                        scroll_offset: element_state.track_scroll_offset(),
+                        scroll_offset: element_state.interactive.track_scroll_offset(),
                     });
                 }
                 let visible_item_count = if item_height > px(0.) {
@@ -147,6 +191,7 @@ impl<V: 'static> Element<V> for UniformList<V> {
                     0
                 };
                 let scroll_offset = element_state
+                    .interactive
                     .scroll_offset()
                     .map_or((0.0).into(), |offset| offset.y);
                 let first_visible_element_ix = (-scroll_offset / item_height).floor() as usize;
@@ -165,19 +210,13 @@ impl<V: 'static> Element<V> for UniformList<V> {
 
                 cx.with_z_index(1, |cx| {
                     for (item, ix) in items.iter_mut().zip(visible_range) {
-                        item.initialize(view_state, cx);
-
-                        let layout_id = item.layout(view_state, cx);
-                        cx.compute_layout(
-                            layout_id,
-                            Size {
-                                width: AvailableSpace::Definite(bounds.size.width),
-                                height: AvailableSpace::Definite(item_height),
-                            },
-                        );
-                        let offset =
+                        let item_origin =
                             padded_bounds.origin + point(px(0.), item_height * ix + scroll_offset);
-                        cx.with_element_offset(Some(offset), |cx| item.paint(view_state, cx))
+                        let available_space = size(
+                            AvailableSpace::Definite(padded_bounds.size.width),
+                            AvailableSpace::Definite(item_height),
+                        );
+                        item.draw(item_origin, available_space, view_state, cx);
                     }
                 });
             } else {
@@ -190,33 +229,44 @@ impl<V: 'static> Element<V> for UniformList<V> {
             let overflow = point(style.overflow.x, Overflow::Scroll);
 
             cx.with_z_index(0, |cx| {
-                self.interactivity
-                    .paint(bounds, content_size, overflow, element_state, cx);
+                self.interactivity.paint(
+                    bounds,
+                    content_size,
+                    overflow,
+                    &mut element_state.interactive,
+                    cx,
+                );
             });
         })
     }
 }
 
 impl<V> UniformList<V> {
-    fn measure_item_height(
+    pub fn with_width_from_item(mut self, item_index: Option<usize>) -> Self {
+        self.item_to_measure_index = item_index.unwrap_or(0);
+        self
+    }
+
+    fn measure_item(
         &self,
         view_state: &mut V,
-        list_bounds: Bounds<Pixels>,
+        list_width: Option<Pixels>,
         cx: &mut ViewContext<V>,
-    ) -> Pixels {
-        let mut items = (self.render_items)(view_state, 0..1, cx);
-        debug_assert!(items.len() == 1);
+    ) -> Size<Pixels> {
+        if self.item_count == 0 {
+            return Size::default();
+        }
+
+        let item_ix = cmp::min(self.item_to_measure_index, self.item_count - 1);
+        let mut items = (self.render_items)(view_state, item_ix..item_ix + 1, cx);
         let mut item_to_measure = items.pop().unwrap();
-        item_to_measure.initialize(view_state, cx);
-        let layout_id = item_to_measure.layout(view_state, cx);
-        cx.compute_layout(
-            layout_id,
-            Size {
-                width: AvailableSpace::Definite(list_bounds.size.width),
-                height: AvailableSpace::MinContent,
-            },
+        let available_space = size(
+            list_width.map_or(AvailableSpace::MinContent, |width| {
+                AvailableSpace::Definite(width)
+            }),
+            AvailableSpace::MinContent,
         );
-        cx.layout_bounds(layout_id).size.height
+        item_to_measure.measure(available_space, view_state, cx)
     }
 
     pub fn track_scroll(mut self, handle: UniformListScrollHandle) -> Self {

crates/gpui2/src/geometry.rs πŸ”—

@@ -9,7 +9,7 @@ use std::{
 };
 
 #[derive(Refineable, Default, Add, AddAssign, Sub, SubAssign, Copy, Debug, PartialEq, Eq, Hash)]
-#[refineable(debug)]
+#[refineable(Debug)]
 #[repr(C)]
 pub struct Point<T: Default + Clone + Debug> {
     pub x: T,
@@ -140,7 +140,7 @@ impl<T: Clone + Default + Debug> Clone for Point<T> {
 }
 
 #[derive(Refineable, Default, Clone, Copy, PartialEq, Div, Hash, Serialize, Deserialize)]
-#[refineable(debug)]
+#[refineable(Debug)]
 #[repr(C)]
 pub struct Size<T: Clone + Default + Debug> {
     pub width: T,
@@ -313,7 +313,7 @@ impl Size<Length> {
 }
 
 #[derive(Refineable, Clone, Default, Debug, Eq, PartialEq)]
-#[refineable(debug)]
+#[refineable(Debug)]
 #[repr(C)]
 pub struct Bounds<T: Clone + Default + Debug> {
     pub origin: Point<T>,
@@ -477,7 +477,7 @@ impl Bounds<Pixels> {
 impl<T: Clone + Debug + Copy + Default> Copy for Bounds<T> {}
 
 #[derive(Refineable, Clone, Default, Debug, Eq, PartialEq)]
-#[refineable(debug)]
+#[refineable(Debug)]
 #[repr(C)]
 pub struct Edges<T: Clone + Default + Debug> {
     pub top: T,
@@ -619,7 +619,7 @@ impl Edges<Pixels> {
 }
 
 #[derive(Refineable, Clone, Default, Debug, Eq, PartialEq)]
-#[refineable(debug)]
+#[refineable(Debug)]
 #[repr(C)]
 pub struct Corners<T: Clone + Default + Debug> {
     pub top_left: T,
@@ -785,6 +785,10 @@ impl Pixels {
         Self(self.0.round())
     }
 
+    pub fn ceil(&self) -> Self {
+        Self(self.0.ceil())
+    }
+
     pub fn scale(&self, factor: f32) -> ScaledPixels {
         ScaledPixels(self.0 * factor)
     }

crates/gpui2/src/interactive.rs πŸ”—

@@ -94,7 +94,6 @@ pub trait StatelessInteractive<V: 'static>: Element<V> {
 
     fn on_mouse_down_out(
         mut self,
-        button: MouseButton,
         handler: impl Fn(&mut V, &MouseDownEvent, &mut ViewContext<V>) + 'static,
     ) -> Self
     where
@@ -103,10 +102,7 @@ pub trait StatelessInteractive<V: 'static>: Element<V> {
         self.stateless_interactivity()
             .mouse_down_listeners
             .push(Box::new(move |view, event, bounds, phase, cx| {
-                if phase == DispatchPhase::Capture
-                    && event.button == button
-                    && !bounds.contains_point(&event.position)
-                {
+                if phase == DispatchPhase::Capture && !bounds.contains_point(&event.position) {
                     handler(view, event, cx)
                 }
             }));

crates/gpui2/src/platform/test/platform.rs πŸ”—

@@ -182,7 +182,8 @@ impl Platform for TestPlatform {
     }
 
     fn should_auto_hide_scrollbars(&self) -> bool {
-        unimplemented!()
+        // todo()
+        true
     }
 
     fn write_to_clipboard(&self, _item: crate::ClipboardItem) {

crates/gpui2/src/platform/test/window.rs πŸ”—

@@ -1,10 +1,14 @@
-use std::{rc::Rc, sync::Arc};
+use std::{
+    rc::Rc,
+    sync::{self, Arc},
+};
 
+use collections::HashMap;
 use parking_lot::Mutex;
 
 use crate::{
-    px, Pixels, PlatformAtlas, PlatformDisplay, PlatformWindow, Point, Scene, Size,
-    WindowAppearance, WindowBounds, WindowOptions,
+    px, AtlasKey, AtlasTextureId, AtlasTile, Pixels, PlatformAtlas, PlatformDisplay,
+    PlatformWindow, Point, Scene, Size, TileId, WindowAppearance, WindowBounds, WindowOptions,
 };
 
 #[derive(Default)]
@@ -30,7 +34,7 @@ impl TestWindow {
             current_scene: Default::default(),
             display,
 
-            sprite_atlas: Arc::new(TestAtlas),
+            sprite_atlas: Arc::new(TestAtlas::new()),
             handlers: Default::default(),
         }
     }
@@ -154,26 +158,71 @@ impl PlatformWindow for TestWindow {
         self.current_scene.lock().replace(scene);
     }
 
-    fn sprite_atlas(&self) -> std::sync::Arc<dyn crate::PlatformAtlas> {
+    fn sprite_atlas(&self) -> sync::Arc<dyn crate::PlatformAtlas> {
         self.sprite_atlas.clone()
     }
 }
 
-pub struct TestAtlas;
+pub struct TestAtlasState {
+    next_id: u32,
+    tiles: HashMap<AtlasKey, AtlasTile>,
+}
+
+pub struct TestAtlas(Mutex<TestAtlasState>);
+
+impl TestAtlas {
+    pub fn new() -> Self {
+        TestAtlas(Mutex::new(TestAtlasState {
+            next_id: 0,
+            tiles: HashMap::default(),
+        }))
+    }
+}
 
 impl PlatformAtlas for TestAtlas {
     fn get_or_insert_with<'a>(
         &self,
-        _key: &crate::AtlasKey,
-        _build: &mut dyn FnMut() -> anyhow::Result<(
+        key: &crate::AtlasKey,
+        build: &mut dyn FnMut() -> anyhow::Result<(
             Size<crate::DevicePixels>,
             std::borrow::Cow<'a, [u8]>,
         )>,
     ) -> anyhow::Result<crate::AtlasTile> {
-        todo!()
+        let mut state = self.0.lock();
+        if let Some(tile) = state.tiles.get(key) {
+            return Ok(tile.clone());
+        }
+
+        state.next_id += 1;
+        let texture_id = state.next_id;
+        state.next_id += 1;
+        let tile_id = state.next_id;
+
+        drop(state);
+        let (size, _) = build()?;
+        let mut state = self.0.lock();
+
+        state.tiles.insert(
+            key.clone(),
+            crate::AtlasTile {
+                texture_id: AtlasTextureId {
+                    index: texture_id,
+                    kind: crate::AtlasTextureKind::Path,
+                },
+                tile_id: TileId(tile_id),
+                bounds: crate::Bounds {
+                    origin: Point::zero(),
+                    size,
+                },
+            },
+        );
+
+        Ok(state.tiles[key].clone())
     }
 
     fn clear(&self) {
-        todo!()
+        let mut state = self.0.lock();
+        state.tiles = HashMap::default();
+        state.next_id = 0;
     }
 }

crates/gpui2/src/style.rs πŸ”—

@@ -14,7 +14,7 @@ pub use taffy::style::{
 pub type StyleCascade = Cascade<Style>;
 
 #[derive(Clone, Refineable, Debug)]
-#[refineable(debug)]
+#[refineable(Debug)]
 pub struct Style {
     /// What layout strategy should be used?
     pub display: Display,
@@ -129,7 +129,7 @@ pub struct BoxShadow {
 }
 
 #[derive(Refineable, Clone, Debug)]
-#[refineable(debug)]
+#[refineable(Debug)]
 pub struct TextStyle {
     pub color: Hsla,
     pub font_family: SharedString,
@@ -353,7 +353,7 @@ impl Default for Style {
 }
 
 #[derive(Refineable, Copy, Clone, Default, Debug, PartialEq, Eq)]
-#[refineable(debug)]
+#[refineable(Debug)]
 pub struct UnderlineStyle {
     pub thickness: Pixels,
     pub color: Option<Hsla>,

crates/gpui2/src/taffy.rs πŸ”—

@@ -1,5 +1,6 @@
 use super::{AbsoluteLength, Bounds, DefiniteLength, Edges, Length, Pixels, Point, Size, Style};
-use collections::HashMap;
+use collections::{HashMap, HashSet};
+use smallvec::SmallVec;
 use std::fmt::Debug;
 use taffy::{
     geometry::{Point as TaffyPoint, Rect as TaffyRect, Size as TaffySize},
@@ -12,6 +13,7 @@ pub struct TaffyLayoutEngine {
     taffy: Taffy,
     children_to_parents: HashMap<LayoutId, LayoutId>,
     absolute_layout_bounds: HashMap<LayoutId, Bounds<Pixels>>,
+    computed_layouts: HashSet<LayoutId>,
 }
 
 static EXPECT_MESSAGE: &'static str =
@@ -23,9 +25,17 @@ impl TaffyLayoutEngine {
             taffy: Taffy::new(),
             children_to_parents: HashMap::default(),
             absolute_layout_bounds: HashMap::default(),
+            computed_layouts: HashSet::default(),
         }
     }
 
+    pub fn clear(&mut self) {
+        self.taffy.clear();
+        self.children_to_parents.clear();
+        self.absolute_layout_bounds.clear();
+        self.computed_layouts.clear();
+    }
+
     pub fn request_layout(
         &mut self,
         style: &Style,
@@ -115,6 +125,7 @@ impl TaffyLayoutEngine {
     }
 
     pub fn compute_layout(&mut self, id: LayoutId, available_space: Size<AvailableSpace>) {
+        // Leaving this here until we have a better instrumentation approach.
         // println!("Laying out {} children", self.count_all_children(id)?);
         // println!("Max layout depth: {}", self.max_depth(0, id)?);
 
@@ -124,6 +135,22 @@ impl TaffyLayoutEngine {
         //     println!("N{} --> N{}", u64::from(a), u64::from(b));
         // }
         // println!("");
+        //
+
+        if !self.computed_layouts.insert(id) {
+            let mut stack = SmallVec::<[LayoutId; 64]>::new();
+            stack.push(id);
+            while let Some(id) = stack.pop() {
+                self.absolute_layout_bounds.remove(&id);
+                stack.extend(
+                    self.taffy
+                        .children(id.into())
+                        .expect(EXPECT_MESSAGE)
+                        .into_iter()
+                        .map(Into::into),
+                );
+            }
+        }
 
         // let started_at = std::time::Instant::now();
         self.taffy
@@ -397,7 +424,7 @@ where
     }
 }
 
-#[derive(Copy, Clone, Default, Debug)]
+#[derive(Copy, Clone, Default, Debug, Eq, PartialEq)]
 pub enum AvailableSpace {
     /// The amount of space available is the specified number of pixels
     Definite(Pixels),

crates/gpui2/src/view.rs πŸ”—

@@ -184,6 +184,10 @@ impl AnyView {
             .compute_layout(layout_id, available_space);
         (self.paint)(self, &mut rendered_element, cx);
     }
+
+    pub(crate) fn draw_dispatch_stack(&self, cx: &mut WindowContext) {
+        (self.initialize)(self, cx);
+    }
 }
 
 impl<V: 'static> Component<V> for AnyView {

crates/gpui2/src/window.rs πŸ”—

@@ -1,14 +1,15 @@
 use crate::{
-    px, size, Action, AnyBox, AnyDrag, AnyView, AppContext, AsyncWindowContext, AvailableSpace,
-    Bounds, BoxShadow, Context, Corners, CursorStyle, DevicePixels, DispatchContext, DisplayId,
-    Edges, Effect, Entity, EntityId, EventEmitter, FileDropEvent, FocusEvent, FontId,
-    GlobalElementId, GlyphId, Hsla, ImageData, InputEvent, IsZero, KeyListener, KeyMatch,
-    KeyMatcher, Keystroke, LayoutId, Model, ModelContext, Modifiers, MonochromeSprite, MouseButton,
-    MouseDownEvent, MouseMoveEvent, MouseUpEvent, Path, Pixels, PlatformAtlas, PlatformDisplay,
-    PlatformInputHandler, PlatformWindow, Point, PolychromeSprite, PromptLevel, Quad, Render,
-    RenderGlyphParams, RenderImageParams, RenderSvgParams, ScaledPixels, SceneBuilder, Shadow,
-    SharedString, Size, Style, SubscriberSet, Subscription, TaffyLayoutEngine, Task, Underline,
-    UnderlineStyle, View, VisualContext, WeakView, WindowBounds, WindowOptions, SUBPIXEL_VARIANTS,
+    build_action_from_type, px, size, Action, AnyBox, AnyDrag, AnyView, AppContext,
+    AsyncWindowContext, AvailableSpace, Bounds, BoxShadow, Context, Corners, CursorStyle,
+    DevicePixels, DispatchContext, DisplayId, Edges, Effect, Entity, EntityId, EventEmitter,
+    FileDropEvent, FocusEvent, FontId, GlobalElementId, GlyphId, Hsla, ImageData, InputEvent,
+    IsZero, KeyListener, KeyMatch, KeyMatcher, Keystroke, LayoutId, Model, ModelContext, Modifiers,
+    MonochromeSprite, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Path, Pixels,
+    PlatformAtlas, PlatformDisplay, PlatformInputHandler, PlatformWindow, Point, PolychromeSprite,
+    PromptLevel, Quad, Render, RenderGlyphParams, RenderImageParams, RenderSvgParams, ScaledPixels,
+    SceneBuilder, Shadow, SharedString, Size, Style, SubscriberSet, Subscription,
+    TaffyLayoutEngine, Task, Underline, UnderlineStyle, View, VisualContext, WeakView,
+    WindowBounds, WindowOptions, SUBPIXEL_VARIANTS,
 };
 use anyhow::{anyhow, Context as _, Result};
 use collections::HashMap;
@@ -145,6 +146,11 @@ impl FocusHandle {
         }
     }
 
+    /// Moves the focus to the element associated with this handle.
+    pub fn focus(&self, cx: &mut WindowContext) {
+        cx.focus(self)
+    }
+
     /// Obtains whether the element associated with this handle is currently focused.
     pub fn is_focused(&self, cx: &WindowContext) -> bool {
         self.id.is_focused(cx)
@@ -200,7 +206,7 @@ pub struct Window {
     display_id: DisplayId,
     sprite_atlas: Arc<dyn PlatformAtlas>,
     rem_size: Pixels,
-    content_size: Size<Pixels>,
+    viewport_size: Size<Pixels>,
     pub(crate) layout_engine: TaffyLayoutEngine,
     pub(crate) root_view: Option<AnyView>,
     pub(crate) element_id_stack: GlobalElementId,
@@ -227,7 +233,7 @@ pub(crate) struct Frame {
     key_matchers: HashMap<GlobalElementId, KeyMatcher>,
     mouse_listeners: HashMap<TypeId, Vec<(StackingOrder, AnyListener)>>,
     pub(crate) focus_listeners: Vec<AnyFocusListener>,
-    key_dispatch_stack: Vec<KeyDispatchStackFrame>,
+    pub(crate) key_dispatch_stack: Vec<KeyDispatchStackFrame>,
     freeze_key_dispatch_stack: bool,
     focus_parents_by_child: HashMap<FocusId, FocusId>,
     pub(crate) scene_builder: SceneBuilder,
@@ -299,7 +305,7 @@ impl Window {
             display_id,
             sprite_atlas,
             rem_size: px(16.),
-            content_size,
+            viewport_size: content_size,
             layout_engine: TaffyLayoutEngine::new(),
             root_view: None,
             element_id_stack: GlobalElementId::default(),
@@ -326,7 +332,7 @@ impl Window {
 /// find the focused element. We interleave key listeners with dispatch contexts so we can use the
 /// 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 {
+pub(crate) enum KeyDispatchStackFrame {
     Listener {
         event_type: TypeId,
         listener: AnyKeyListener,
@@ -401,11 +407,18 @@ impl<'a> WindowContext<'a> {
 
     /// Move focus to the element associated with the given `FocusHandle`.
     pub fn focus(&mut self, handle: &FocusHandle) {
+        if self.window.focus == Some(handle.id) {
+            return;
+        }
+
         if self.window.last_blur.is_none() {
             self.window.last_blur = Some(self.window.focus);
         }
 
         self.window.focus = Some(handle.id);
+
+        // self.window.current_frame.key_dispatch_stack.clear()
+        // self.window.root_view.initialize()
         self.app.push_effect(Effect::FocusChanged {
             window_handle: self.window.handle,
             focused: Some(handle.id),
@@ -427,6 +440,14 @@ impl<'a> WindowContext<'a> {
         self.notify();
     }
 
+    pub fn dispatch_action(&mut self, action: Box<dyn Action>) {
+        self.defer(|cx| {
+            cx.app.propagate_event = true;
+            let stack = cx.dispatch_stack();
+            cx.dispatch_action_internal(action, &stack[..])
+        })
+    }
+
     /// Schedules the given function to be run at the end of the current effect cycle, allowing entities
     /// that are currently on the stack to be returned to the app.
     pub fn defer(&mut self, f: impl FnOnce(&mut WindowContext) + 'static) {
@@ -609,7 +630,7 @@ impl<'a> WindowContext<'a> {
 
     fn window_bounds_changed(&mut self) {
         self.window.scale_factor = self.window.platform_window.scale_factor();
-        self.window.content_size = self.window.platform_window.content_size();
+        self.window.viewport_size = self.window.platform_window.content_size();
         self.window.bounds = self.window.platform_window.bounds();
         self.window.display_id = self.window.platform_window.display().id();
         self.window.dirty = true;
@@ -624,6 +645,10 @@ impl<'a> WindowContext<'a> {
         self.window.bounds
     }
 
+    pub fn viewport_size(&self) -> Size<Pixels> {
+        self.window.viewport_size
+    }
+
     pub fn is_window_active(&self) -> bool {
         self.window.active
     }
@@ -717,7 +742,7 @@ impl<'a> WindowContext<'a> {
 
     /// Called during painting to invoke the given closure in a new stacking context. The given
     /// z-index is interpreted relative to the previous call to `stack`.
-    pub fn stack<R>(&mut self, z_index: u32, f: impl FnOnce(&mut Self) -> R) -> R {
+    pub fn with_z_index<R>(&mut self, z_index: u32, f: impl FnOnce(&mut Self) -> R) -> R {
         self.window.current_frame.z_index_stack.push(z_index);
         let result = f(self);
         self.window.current_frame.z_index_stack.pop();
@@ -1015,13 +1040,13 @@ impl<'a> WindowContext<'a> {
 
         self.start_frame();
 
-        self.stack(0, |cx| {
-            let available_space = cx.window.content_size.map(Into::into);
+        self.with_z_index(0, |cx| {
+            let available_space = cx.window.viewport_size.map(Into::into);
             root_view.draw(available_space, cx);
         });
 
         if let Some(active_drag) = self.app.active_drag.take() {
-            self.stack(1, |cx| {
+            self.with_z_index(1, |cx| {
                 let offset = cx.mouse_position() - active_drag.cursor_offset;
                 cx.with_element_offset(Some(offset), |cx| {
                     let available_space =
@@ -1031,7 +1056,7 @@ impl<'a> WindowContext<'a> {
                 });
             });
         } else if let Some(active_tooltip) = self.app.active_tooltip.take() {
-            self.stack(1, |cx| {
+            self.with_z_index(1, |cx| {
                 cx.with_element_offset(Some(active_tooltip.cursor_offset), |cx| {
                     let available_space =
                         size(AvailableSpace::MinContent, AvailableSpace::MinContent);
@@ -1054,12 +1079,34 @@ impl<'a> WindowContext<'a> {
         self.window.dirty = false;
     }
 
+    pub(crate) fn dispatch_stack(&mut self) -> Vec<KeyDispatchStackFrame> {
+        let root_view = self.window.root_view.take().unwrap();
+        let window = &mut *self.window;
+        let mut spare_frame = Frame::default();
+        mem::swap(&mut spare_frame, &mut window.previous_frame);
+
+        self.start_frame();
+
+        root_view.draw_dispatch_stack(self);
+
+        let window = &mut *self.window;
+        // restore the old values of current and previous frame,
+        // putting the new frame into spare_frame.
+        mem::swap(&mut window.current_frame, &mut window.previous_frame);
+        mem::swap(&mut spare_frame, &mut window.previous_frame);
+        self.window.root_view = Some(root_view);
+
+        spare_frame.key_dispatch_stack
+    }
+
     /// Rotate the current frame and the previous frame, then clear the current frame.
     /// We repopulate all state in the current frame during each paint.
     fn start_frame(&mut self) {
         self.text_system().start_frame();
 
         let window = &mut *self.window;
+        window.layout_engine.clear();
+
         mem::swap(&mut window.previous_frame, &mut window.current_frame);
         let frame = &mut window.current_frame;
         frame.element_states.clear();
@@ -1196,7 +1243,7 @@ impl<'a> WindowContext<'a> {
                                 DispatchPhase::Capture,
                                 self,
                             ) {
-                                self.dispatch_action(action, &key_dispatch_stack[..ix]);
+                                self.dispatch_action_internal(action, &key_dispatch_stack[..ix]);
                             }
                             if !self.app.propagate_event {
                                 break;
@@ -1223,7 +1270,10 @@ impl<'a> WindowContext<'a> {
                                     DispatchPhase::Bubble,
                                     self,
                                 ) {
-                                    self.dispatch_action(action, &key_dispatch_stack[..ix]);
+                                    self.dispatch_action_internal(
+                                        action,
+                                        &key_dispatch_stack[..ix],
+                                    );
                                 }
 
                                 if !self.app.propagate_event {
@@ -1295,7 +1345,29 @@ impl<'a> WindowContext<'a> {
         self.window.platform_window.prompt(level, msg, answers)
     }
 
-    fn dispatch_action(
+    pub fn available_actions(&self) -> impl Iterator<Item = Box<dyn Action>> + '_ {
+        let key_dispatch_stack = &self.window.previous_frame.key_dispatch_stack;
+        key_dispatch_stack.iter().filter_map(|frame| {
+            match frame {
+                // todo!factor out a KeyDispatchStackFrame::Action
+                KeyDispatchStackFrame::Listener {
+                    event_type,
+                    listener: _,
+                } => {
+                    match build_action_from_type(event_type) {
+                        Ok(action) => Some(action),
+                        Err(err) => {
+                            dbg!(err);
+                            None
+                        } // we'll hit his if TypeId == KeyDown
+                    }
+                }
+                KeyDispatchStackFrame::Context(_) => None,
+            }
+        })
+    }
+
+    pub(crate) fn dispatch_action_internal(
         &mut self,
         action: Box<dyn Action>,
         dispatch_stack: &[KeyDispatchStackFrame],
@@ -1706,7 +1778,7 @@ pub trait BorrowWindow: BorrowMut<Window> + BorrowMut<AppContext> {
             .unwrap_or_else(|| ContentMask {
                 bounds: Bounds {
                     origin: Point::default(),
-                    size: self.window().content_size,
+                    size: self.window().viewport_size,
                 },
             })
     }

crates/language/src/buffer_tests.rs πŸ”—

@@ -1692,14 +1692,25 @@ fn test_language_scope_at_with_javascript(cx: &mut AppContext) {
             r#"
                 (jsx_element) @element
                 (string) @string
+                [
+                    (jsx_opening_element)
+                    (jsx_closing_element)
+                    (jsx_expression)
+                ] @default
             "#,
         )
         .unwrap();
 
-        let text = r#"a["b"] = <C d="e"></C>;"#;
+        let text = r#"
+            a["b"] = <C d="e">
+                <F></F>
+                { g() }
+            </C>;
+        "#
+        .unindent();
 
         let buffer =
-            Buffer::new(0, cx.model_id() as u64, text).with_language(Arc::new(language), cx);
+            Buffer::new(0, cx.model_id() as u64, &text).with_language(Arc::new(language), cx);
         let snapshot = buffer.snapshot();
 
         let config = snapshot.language_scope_at(0).unwrap();
@@ -1710,7 +1721,9 @@ fn test_language_scope_at_with_javascript(cx: &mut AppContext) {
             &[true, true]
         );
 
-        let string_config = snapshot.language_scope_at(3).unwrap();
+        let string_config = snapshot
+            .language_scope_at(text.find("b\"").unwrap())
+            .unwrap();
         assert_eq!(string_config.line_comment_prefix().unwrap().as_ref(), "// ");
         // Second bracket pair is disabled
         assert_eq!(
@@ -1718,18 +1731,49 @@ fn test_language_scope_at_with_javascript(cx: &mut AppContext) {
             &[true, false]
         );
 
-        let element_config = snapshot.language_scope_at(10).unwrap();
+        // In between JSX tags: use the `element` override.
+        let element_config = snapshot
+            .language_scope_at(text.find("<F>").unwrap())
+            .unwrap();
         assert_eq!(element_config.line_comment_prefix(), None);
         assert_eq!(
             element_config.block_comment_delimiters(),
             Some((&"{/*".into(), &"*/}".into()))
         );
-        // Both bracket pairs are enabled
         assert_eq!(
             element_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
             &[true, true]
         );
 
+        // Within a JSX tag: use the default config.
+        let tag_config = snapshot
+            .language_scope_at(text.find(" d=").unwrap() + 1)
+            .unwrap();
+        assert_eq!(tag_config.line_comment_prefix().unwrap().as_ref(), "// ");
+        assert_eq!(
+            tag_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
+            &[true, true]
+        );
+
+        // In a JSX expression: use the default config.
+        let expression_in_element_config = snapshot
+            .language_scope_at(text.find("{").unwrap() + 1)
+            .unwrap();
+        assert_eq!(
+            expression_in_element_config
+                .line_comment_prefix()
+                .unwrap()
+                .as_ref(),
+            "// "
+        );
+        assert_eq!(
+            expression_in_element_config
+                .brackets()
+                .map(|e| e.1)
+                .collect::<Vec<_>>(),
+            &[true, true]
+        );
+
         buffer
     });
 }

crates/language2/src/buffer_tests.rs πŸ”—

@@ -1696,14 +1696,25 @@ fn test_language_scope_at_with_javascript(cx: &mut AppContext) {
             r#"
                 (jsx_element) @element
                 (string) @string
+                [
+                    (jsx_opening_element)
+                    (jsx_closing_element)
+                    (jsx_expression)
+                ] @default
             "#,
         )
         .unwrap();
 
-        let text = r#"a["b"] = <C d="e"></C>;"#;
+        let text = r#"
+            a["b"] = <C d="e">
+                <F></F>
+                { g() }
+            </C>;
+        "#
+        .unindent();
 
         let buffer =
-            Buffer::new(0, cx.entity_id().as_u64(), text).with_language(Arc::new(language), cx);
+            Buffer::new(0, cx.entity_id().as_u64(), &text).with_language(Arc::new(language), cx);
         let snapshot = buffer.snapshot();
 
         let config = snapshot.language_scope_at(0).unwrap();
@@ -1714,7 +1725,9 @@ fn test_language_scope_at_with_javascript(cx: &mut AppContext) {
             &[true, true]
         );
 
-        let string_config = snapshot.language_scope_at(3).unwrap();
+        let string_config = snapshot
+            .language_scope_at(text.find("b\"").unwrap())
+            .unwrap();
         assert_eq!(string_config.line_comment_prefix().unwrap().as_ref(), "// ");
         // Second bracket pair is disabled
         assert_eq!(
@@ -1722,18 +1735,49 @@ fn test_language_scope_at_with_javascript(cx: &mut AppContext) {
             &[true, false]
         );
 
-        let element_config = snapshot.language_scope_at(10).unwrap();
+        // In between JSX tags: use the `element` override.
+        let element_config = snapshot
+            .language_scope_at(text.find("<F>").unwrap())
+            .unwrap();
         assert_eq!(element_config.line_comment_prefix(), None);
         assert_eq!(
             element_config.block_comment_delimiters(),
             Some((&"{/*".into(), &"*/}".into()))
         );
-        // Both bracket pairs are enabled
         assert_eq!(
             element_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
             &[true, true]
         );
 
+        // Within a JSX tag: use the default config.
+        let tag_config = snapshot
+            .language_scope_at(text.find(" d=").unwrap() + 1)
+            .unwrap();
+        assert_eq!(tag_config.line_comment_prefix().unwrap().as_ref(), "// ");
+        assert_eq!(
+            tag_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
+            &[true, true]
+        );
+
+        // In a JSX expression: use the default config.
+        let expression_in_element_config = snapshot
+            .language_scope_at(text.find("{").unwrap() + 1)
+            .unwrap();
+        assert_eq!(
+            expression_in_element_config
+                .line_comment_prefix()
+                .unwrap()
+                .as_ref(),
+            "// "
+        );
+        assert_eq!(
+            expression_in_element_config
+                .brackets()
+                .map(|e| e.1)
+                .collect::<Vec<_>>(),
+            &[true, true]
+        );
+
         buffer
     });
 }

crates/picker2/Cargo.toml πŸ”—

@@ -10,6 +10,7 @@ doctest = false
 
 [dependencies]
 editor = { package = "editor2", path = "../editor2" }
+ui = { package = "ui2", path = "../ui2" }
 gpui = { package = "gpui2", path = "../gpui2" }
 menu = { package = "menu2", path = "../menu2" }
 settings = { package = "settings2", path = "../settings2" }

crates/picker2/src/picker2.rs πŸ”—

@@ -5,6 +5,7 @@ use gpui::{
     WindowContext,
 };
 use std::cmp;
+use ui::{prelude::*, v_stack, Divider};
 
 pub struct Picker<D: PickerDelegate> {
     pub delegate: D,
@@ -57,6 +58,7 @@ impl<D: PickerDelegate> Picker<D> {
             let ix = cmp::min(index + 1, count - 1);
             self.delegate.set_selected_index(ix, cx);
             self.scroll_handle.scroll_to_item(ix);
+            cx.notify();
         }
     }
 
@@ -67,6 +69,7 @@ impl<D: PickerDelegate> Picker<D> {
             let ix = index.saturating_sub(1);
             self.delegate.set_selected_index(ix, cx);
             self.scroll_handle.scroll_to_item(ix);
+            cx.notify();
         }
     }
 
@@ -75,6 +78,7 @@ impl<D: PickerDelegate> Picker<D> {
         if count > 0 {
             self.delegate.set_selected_index(0, cx);
             self.scroll_handle.scroll_to_item(0);
+            cx.notify();
         }
     }
 
@@ -83,6 +87,7 @@ impl<D: PickerDelegate> Picker<D> {
         if count > 0 {
             self.delegate.set_selected_index(count - 1, cx);
             self.scroll_handle.scroll_to_item(count - 1);
+            cx.notify();
         }
     }
 
@@ -133,12 +138,13 @@ impl<D: PickerDelegate> Picker<D> {
 impl<D: PickerDelegate> Render for Picker<D> {
     type Element = Div<Self, StatefulInteractivity<Self>, FocusEnabled<Self>>;
 
-    fn render(&mut self, _cx: &mut ViewContext<Self>) -> Self::Element {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
         div()
             .context("picker")
             .id("picker-container")
             .focusable()
             .size_full()
+            .elevation_2(cx)
             .on_action(Self::select_next)
             .on_action(Self::select_prev)
             .on_action(Self::select_first)
@@ -146,18 +152,30 @@ impl<D: PickerDelegate> Render for Picker<D> {
             .on_action(Self::cancel)
             .on_action(Self::confirm)
             .on_action(Self::secondary_confirm)
-            .child(self.editor.clone())
             .child(
-                uniform_list("candidates", self.delegate.match_count(), {
-                    move |this: &mut Self, visible_range, cx| {
-                        let selected_ix = this.delegate.selected_index();
-                        visible_range
-                            .map(|ix| this.delegate.render_match(ix, ix == selected_ix, cx))
-                            .collect()
-                    }
-                })
-                .track_scroll(self.scroll_handle.clone())
-                .size_full(),
+                v_stack()
+                    .py_0p5()
+                    .px_1()
+                    .child(div().px_1().py_0p5().child(self.editor.clone())),
+            )
+            .child(Divider::horizontal())
+            .child(
+                v_stack()
+                    .p_1()
+                    .grow()
+                    .child(
+                        uniform_list("candidates", self.delegate.match_count(), {
+                            move |this: &mut Self, visible_range, cx| {
+                                let selected_ix = this.delegate.selected_index();
+                                visible_range
+                                    .map(|ix| this.delegate.render_match(ix, ix == selected_ix, cx))
+                                    .collect()
+                            }
+                        })
+                        .track_scroll(self.scroll_handle.clone()),
+                    )
+                    .max_h_72()
+                    .overflow_hidden(),
             )
     }
 }

crates/prettier/src/prettier.rs πŸ”—

@@ -1,3 +1,4 @@
+use std::ops::ControlFlow;
 use std::path::{Path, PathBuf};
 use std::sync::Arc;
 
@@ -58,11 +59,17 @@ impl Prettier {
         fs: &dyn Fs,
         installed_prettiers: &HashSet<PathBuf>,
         locate_from: &Path,
-    ) -> anyhow::Result<Option<PathBuf>> {
+    ) -> anyhow::Result<ControlFlow<(), Option<PathBuf>>> {
         let mut path_to_check = locate_from
             .components()
             .take_while(|component| component.as_os_str().to_string_lossy() != "node_modules")
             .collect::<PathBuf>();
+        if path_to_check != locate_from {
+            log::debug!(
+                "Skipping prettier location for path {path_to_check:?} that is inside node_modules"
+            );
+            return Ok(ControlFlow::Break(()));
+        }
         let path_to_check_metadata = fs
             .metadata(&path_to_check)
             .await
@@ -76,14 +83,14 @@ impl Prettier {
         loop {
             if installed_prettiers.contains(&path_to_check) {
                 log::debug!("Found prettier path {path_to_check:?} in installed prettiers");
-                return Ok(Some(path_to_check));
+                return Ok(ControlFlow::Continue(Some(path_to_check)));
             } else if let Some(package_json_contents) =
                 read_package_json(fs, &path_to_check).await?
             {
                 if has_prettier_in_package_json(&package_json_contents) {
                     if has_prettier_in_node_modules(fs, &path_to_check).await? {
                         log::debug!("Found prettier path {path_to_check:?} in both package.json and node_modules");
-                        return Ok(Some(path_to_check));
+                        return Ok(ControlFlow::Continue(Some(path_to_check)));
                     } else if project_path_with_prettier_dependency.is_none() {
                         project_path_with_prettier_dependency = Some(path_to_check.clone());
                     }
@@ -109,7 +116,7 @@ impl Prettier {
                                     }) {
                                         anyhow::ensure!(has_prettier_in_node_modules(fs, &path_to_check).await?, "Found prettier path {path_to_check:?} in the workspace root for project in {project_path_with_prettier_dependency:?}, but it's not installed into workspace root's node_modules");
                                         log::info!("Found prettier path {path_to_check:?} in the workspace root for project in {project_path_with_prettier_dependency:?}");
-                                        return Ok(Some(path_to_check));
+                                        return Ok(ControlFlow::Continue(Some(path_to_check)));
                                     } else {
                                         log::warn!("Skipping path {path_to_check:?} that has prettier in its 'node_modules' subdirectory, but is not included in its package.json workspaces {workspaces:?}");
                                     }
@@ -132,7 +139,7 @@ impl Prettier {
                     }
                     None => {
                         log::debug!("Found no prettier in ancestors of {locate_from:?}");
-                        return Ok(None);
+                        return Ok(ControlFlow::Continue(None));
                     }
                 }
             }
@@ -497,37 +504,40 @@ mod tests {
         .await;
 
         assert!(
-            Prettier::locate_prettier_installation(
-                fs.as_ref(),
-                &HashSet::default(),
-                Path::new("/root/.config/zed/settings.json"),
-            )
-            .await
-            .unwrap()
-            .is_none(),
+            matches!(
+                Prettier::locate_prettier_installation(
+                    fs.as_ref(),
+                    &HashSet::default(),
+                    Path::new("/root/.config/zed/settings.json"),
+                )
+                .await,
+                Ok(ControlFlow::Continue(None))
+            ),
             "Should successfully find no prettier for path hierarchy without it"
         );
         assert!(
-            Prettier::locate_prettier_installation(
-                fs.as_ref(),
-                &HashSet::default(),
-                Path::new("/root/work/project/src/index.js")
-            )
-            .await
-            .unwrap()
-            .is_none(),
+            matches!(
+                Prettier::locate_prettier_installation(
+                    fs.as_ref(),
+                    &HashSet::default(),
+                    Path::new("/root/work/project/src/index.js")
+                )
+                .await,
+                Ok(ControlFlow::Continue(None))
+            ),
             "Should successfully find no prettier for path hierarchy that has node_modules with prettier, but no package.json mentions of it"
         );
         assert!(
-            Prettier::locate_prettier_installation(
-                fs.as_ref(),
-                &HashSet::default(),
-                Path::new("/root/work/project/node_modules/expect/build/print.js")
-            )
-            .await
-            .unwrap()
-            .is_none(),
-            "Even though it has package.json with prettier in it and no prettier on node_modules along the path, nothing should fail since declared inside node_modules"
+            matches!(
+                Prettier::locate_prettier_installation(
+                    fs.as_ref(),
+                    &HashSet::default(),
+                    Path::new("/root/work/project/node_modules/expect/build/print.js")
+                )
+                .await,
+                Ok(ControlFlow::Break(()))
+            ),
+            "Should not format files inside node_modules/"
         );
     }
 
@@ -580,7 +590,7 @@ mod tests {
             )
             .await
             .unwrap(),
-            Some(PathBuf::from("/root/web_blog")),
+            ControlFlow::Continue(Some(PathBuf::from("/root/web_blog"))),
             "Should find a preinstalled prettier in the project root"
         );
         assert_eq!(
@@ -591,8 +601,8 @@ mod tests {
             )
             .await
             .unwrap(),
-            Some(PathBuf::from("/root/web_blog")),
-            "Should find a preinstalled prettier in the project root even for node_modules files"
+            ControlFlow::Break(()),
+            "Should not allow formatting node_modules/ contents"
         );
     }
 
@@ -604,6 +614,18 @@ mod tests {
             json!({
                 "work": {
                     "web_blog": {
+                        "node_modules": {
+                            "expect": {
+                                "build": {
+                                    "print.js": "// print.js file contents",
+                                },
+                                "package.json": r#"{
+                                    "devDependencies": {
+                                        "prettier": "2.5.1"
+                                    }
+                                }"#,
+                            },
+                        },
                         "pages": {
                             "[slug].tsx": "// [slug].tsx file contents",
                         },
@@ -624,33 +646,55 @@ mod tests {
         )
         .await;
 
-        let path = "/root/work/web_blog/node_modules/pages/[slug].tsx";
         match Prettier::locate_prettier_installation(
             fs.as_ref(),
             &HashSet::default(),
-            Path::new(path)
+            Path::new("/root/work/web_blog/pages/[slug].tsx")
         )
         .await {
             Ok(path) => panic!("Expected to fail for prettier in package.json but not in node_modules found, but got path {path:?}"),
             Err(e) => {
                 let message = e.to_string();
-                assert!(message.contains(path), "Error message should mention which start file was used for location");
-                assert!(message.contains("/root/work/web_blog"), "Error message should mention potential candidates without prettier node_modules contents");
+                assert!(message.contains("/root/work/web_blog"), "Error message should mention which project had prettier defined");
             },
         };
+        assert_eq!(
+            Prettier::locate_prettier_installation(
+                fs.as_ref(),
+                &HashSet::from_iter(
+                    [PathBuf::from("/root"), PathBuf::from("/root/work")].into_iter()
+                ),
+                Path::new("/root/work/web_blog/pages/[slug].tsx")
+            )
+            .await
+            .unwrap(),
+            ControlFlow::Continue(Some(PathBuf::from("/root/work"))),
+            "Should return closest cached value found without path checks"
+        );
 
+        assert_eq!(
+            Prettier::locate_prettier_installation(
+                fs.as_ref(),
+                &HashSet::default(),
+                Path::new("/root/work/web_blog/node_modules/expect/build/print.js")
+            )
+            .await
+            .unwrap(),
+            ControlFlow::Break(()),
+            "Should not allow formatting files inside node_modules/"
+        );
         assert_eq!(
             Prettier::locate_prettier_installation(
                 fs.as_ref(),
                 &HashSet::from_iter(
                     [PathBuf::from("/root"), PathBuf::from("/root/work")].into_iter()
                 ),
-                Path::new("/root/work/web_blog/node_modules/pages/[slug].tsx")
+                Path::new("/root/work/web_blog/node_modules/expect/build/print.js")
             )
             .await
             .unwrap(),
-            Some(PathBuf::from("/root/work")),
-            "Should return first cached value found without path checks"
+            ControlFlow::Break(()),
+            "Should ignore cache lookup for files inside node_modules/"
         );
     }
 
@@ -674,7 +718,9 @@ mod tests {
                                             },
                                         },
                                     },
-                                    "node_modules": {},
+                                    "node_modules": {
+                                        "test.js": "// test.js contents",
+                                    },
                                     "package.json": r#"{
                                         "devDependencies": {
                                             "prettier": "^3.0.3"
@@ -703,9 +749,32 @@ mod tests {
                 &HashSet::default(),
                 Path::new("/root/work/full-stack-foundations/exercises/03.loading/01.problem.loader/app/routes/users+/$username_+/notes.tsx"),
             ).await.unwrap(),
-            Some(PathBuf::from("/root/work/full-stack-foundations")),
+            ControlFlow::Continue(Some(PathBuf::from("/root/work/full-stack-foundations"))),
             "Should ascend to the multi-workspace root and find the prettier there",
         );
+
+        assert_eq!(
+            Prettier::locate_prettier_installation(
+                fs.as_ref(),
+                &HashSet::default(),
+                Path::new("/root/work/full-stack-foundations/node_modules/prettier/index.js")
+            )
+            .await
+            .unwrap(),
+            ControlFlow::Break(()),
+            "Should not allow formatting files inside root node_modules/"
+        );
+        assert_eq!(
+            Prettier::locate_prettier_installation(
+                fs.as_ref(),
+                &HashSet::default(),
+                Path::new("/root/work/full-stack-foundations/exercises/03.loading/01.problem.loader/node_modules/test.js")
+            )
+            .await
+            .unwrap(),
+            ControlFlow::Break(()),
+            "Should not allow formatting files inside submodule's node_modules/"
+        );
     }
 
     #[gpui::test]

crates/prettier2/src/prettier2.rs πŸ”—

@@ -7,6 +7,7 @@ use lsp::{LanguageServer, LanguageServerId};
 use node_runtime::NodeRuntime;
 use serde::{Deserialize, Serialize};
 use std::{
+    ops::ControlFlow,
     path::{Path, PathBuf},
     sync::Arc,
 };
@@ -58,11 +59,17 @@ impl Prettier {
         fs: &dyn Fs,
         installed_prettiers: &HashSet<PathBuf>,
         locate_from: &Path,
-    ) -> anyhow::Result<Option<PathBuf>> {
+    ) -> anyhow::Result<ControlFlow<(), Option<PathBuf>>> {
         let mut path_to_check = locate_from
             .components()
             .take_while(|component| component.as_os_str().to_string_lossy() != "node_modules")
             .collect::<PathBuf>();
+        if path_to_check != locate_from {
+            log::debug!(
+                "Skipping prettier location for path {path_to_check:?} that is inside node_modules"
+            );
+            return Ok(ControlFlow::Break(()));
+        }
         let path_to_check_metadata = fs
             .metadata(&path_to_check)
             .await
@@ -76,14 +83,14 @@ impl Prettier {
         loop {
             if installed_prettiers.contains(&path_to_check) {
                 log::debug!("Found prettier path {path_to_check:?} in installed prettiers");
-                return Ok(Some(path_to_check));
+                return Ok(ControlFlow::Continue(Some(path_to_check)));
             } else if let Some(package_json_contents) =
                 read_package_json(fs, &path_to_check).await?
             {
                 if has_prettier_in_package_json(&package_json_contents) {
                     if has_prettier_in_node_modules(fs, &path_to_check).await? {
                         log::debug!("Found prettier path {path_to_check:?} in both package.json and node_modules");
-                        return Ok(Some(path_to_check));
+                        return Ok(ControlFlow::Continue(Some(path_to_check)));
                     } else if project_path_with_prettier_dependency.is_none() {
                         project_path_with_prettier_dependency = Some(path_to_check.clone());
                     }
@@ -109,7 +116,7 @@ impl Prettier {
                                         }) {
                                             anyhow::ensure!(has_prettier_in_node_modules(fs, &path_to_check).await?, "Found prettier path {path_to_check:?} in the workspace root for project in {project_path_with_prettier_dependency:?}, but it's not installed into workspace root's node_modules");
                                             log::info!("Found prettier path {path_to_check:?} in the workspace root for project in {project_path_with_prettier_dependency:?}");
-                                            return Ok(Some(path_to_check));
+                                            return Ok(ControlFlow::Continue(Some(path_to_check)));
                                         } else {
                                             log::warn!("Skipping path {path_to_check:?} that has prettier in its 'node_modules' subdirectory, but is not included in its package.json workspaces {workspaces:?}");
                                         }
@@ -132,7 +139,7 @@ impl Prettier {
                     }
                     None => {
                         log::debug!("Found no prettier in ancestors of {locate_from:?}");
-                        return Ok(None);
+                        return Ok(ControlFlow::Continue(None));
                     }
                 }
             }
@@ -527,37 +534,40 @@ mod tests {
         .await;
 
         assert!(
-            Prettier::locate_prettier_installation(
-                fs.as_ref(),
-                &HashSet::default(),
-                Path::new("/root/.config/zed/settings.json"),
-            )
-            .await
-            .unwrap()
-            .is_none(),
+            matches!(
+                Prettier::locate_prettier_installation(
+                    fs.as_ref(),
+                    &HashSet::default(),
+                    Path::new("/root/.config/zed/settings.json"),
+                )
+                .await,
+                Ok(ControlFlow::Continue(None))
+            ),
             "Should successfully find no prettier for path hierarchy without it"
         );
         assert!(
-            Prettier::locate_prettier_installation(
-                fs.as_ref(),
-                &HashSet::default(),
-                Path::new("/root/work/project/src/index.js")
-            )
-            .await
-            .unwrap()
-            .is_none(),
+            matches!(
+                Prettier::locate_prettier_installation(
+                    fs.as_ref(),
+                    &HashSet::default(),
+                    Path::new("/root/work/project/src/index.js")
+                )
+                .await,
+                Ok(ControlFlow::Continue(None))
+            ),
             "Should successfully find no prettier for path hierarchy that has node_modules with prettier, but no package.json mentions of it"
         );
         assert!(
-            Prettier::locate_prettier_installation(
-                fs.as_ref(),
-                &HashSet::default(),
-                Path::new("/root/work/project/node_modules/expect/build/print.js")
-            )
-            .await
-            .unwrap()
-            .is_none(),
-            "Even though it has package.json with prettier in it and no prettier on node_modules along the path, nothing should fail since declared inside node_modules"
+            matches!(
+                Prettier::locate_prettier_installation(
+                    fs.as_ref(),
+                    &HashSet::default(),
+                    Path::new("/root/work/project/node_modules/expect/build/print.js")
+                )
+                .await,
+                Ok(ControlFlow::Break(()))
+            ),
+            "Should not format files inside node_modules/"
         );
     }
 
@@ -610,7 +620,7 @@ mod tests {
             )
             .await
             .unwrap(),
-            Some(PathBuf::from("/root/web_blog")),
+            ControlFlow::Continue(Some(PathBuf::from("/root/web_blog"))),
             "Should find a preinstalled prettier in the project root"
         );
         assert_eq!(
@@ -621,8 +631,8 @@ mod tests {
             )
             .await
             .unwrap(),
-            Some(PathBuf::from("/root/web_blog")),
-            "Should find a preinstalled prettier in the project root even for node_modules files"
+            ControlFlow::Break(()),
+            "Should not allow formatting node_modules/ contents"
         );
     }
 
@@ -634,6 +644,18 @@ mod tests {
             json!({
                 "work": {
                     "web_blog": {
+                        "node_modules": {
+                            "expect": {
+                                "build": {
+                                    "print.js": "// print.js file contents",
+                                },
+                                "package.json": r#"{
+                                    "devDependencies": {
+                                        "prettier": "2.5.1"
+                                    }
+                                }"#,
+                            },
+                        },
                         "pages": {
                             "[slug].tsx": "// [slug].tsx file contents",
                         },
@@ -654,18 +676,16 @@ mod tests {
         )
         .await;
 
-        let path = "/root/work/web_blog/node_modules/pages/[slug].tsx";
         match Prettier::locate_prettier_installation(
             fs.as_ref(),
             &HashSet::default(),
-            Path::new(path)
+            Path::new("/root/work/web_blog/pages/[slug].tsx")
         )
         .await {
             Ok(path) => panic!("Expected to fail for prettier in package.json but not in node_modules found, but got path {path:?}"),
             Err(e) => {
                 let message = e.to_string();
-                assert!(message.contains(path), "Error message should mention which start file was used for location");
-                assert!(message.contains("/root/work/web_blog"), "Error message should mention potential candidates without prettier node_modules contents");
+                assert!(message.contains("/root/work/web_blog"), "Error message should mention which project had prettier defined");
             },
         };
 
@@ -675,12 +695,37 @@ mod tests {
                 &HashSet::from_iter(
                     [PathBuf::from("/root"), PathBuf::from("/root/work")].into_iter()
                 ),
-                Path::new("/root/work/web_blog/node_modules/pages/[slug].tsx")
+                Path::new("/root/work/web_blog/pages/[slug].tsx")
+            )
+            .await
+            .unwrap(),
+            ControlFlow::Continue(Some(PathBuf::from("/root/work"))),
+            "Should return closest cached value found without path checks"
+        );
+
+        assert_eq!(
+            Prettier::locate_prettier_installation(
+                fs.as_ref(),
+                &HashSet::default(),
+                Path::new("/root/work/web_blog/node_modules/expect/build/print.js")
+            )
+            .await
+            .unwrap(),
+            ControlFlow::Break(()),
+            "Should not allow formatting files inside node_modules/"
+        );
+        assert_eq!(
+            Prettier::locate_prettier_installation(
+                fs.as_ref(),
+                &HashSet::from_iter(
+                    [PathBuf::from("/root"), PathBuf::from("/root/work")].into_iter()
+                ),
+                Path::new("/root/work/web_blog/node_modules/expect/build/print.js")
             )
             .await
             .unwrap(),
-            Some(PathBuf::from("/root/work")),
-            "Should return first cached value found without path checks"
+            ControlFlow::Break(()),
+            "Should ignore cache lookup for files inside node_modules/"
         );
     }
 
@@ -704,7 +749,9 @@ mod tests {
                                             },
                                         },
                                     },
-                                    "node_modules": {},
+                                    "node_modules": {
+                                        "test.js": "// test.js contents",
+                                    },
                                     "package.json": r#"{
                                         "devDependencies": {
                                             "prettier": "^3.0.3"
@@ -733,9 +780,32 @@ mod tests {
                 &HashSet::default(),
                 Path::new("/root/work/full-stack-foundations/exercises/03.loading/01.problem.loader/app/routes/users+/$username_+/notes.tsx"),
             ).await.unwrap(),
-            Some(PathBuf::from("/root/work/full-stack-foundations")),
+            ControlFlow::Continue(Some(PathBuf::from("/root/work/full-stack-foundations"))),
             "Should ascend to the multi-workspace root and find the prettier there",
         );
+
+        assert_eq!(
+            Prettier::locate_prettier_installation(
+                fs.as_ref(),
+                &HashSet::default(),
+                Path::new("/root/work/full-stack-foundations/node_modules/prettier/index.js")
+            )
+            .await
+            .unwrap(),
+            ControlFlow::Break(()),
+            "Should not allow formatting files inside root node_modules/"
+        );
+        assert_eq!(
+            Prettier::locate_prettier_installation(
+                fs.as_ref(),
+                &HashSet::default(),
+                Path::new("/root/work/full-stack-foundations/exercises/03.loading/01.problem.loader/node_modules/test.js")
+            )
+            .await
+            .unwrap(),
+            ControlFlow::Break(()),
+            "Should not allow formatting files inside submodule's node_modules/"
+        );
     }
 
     #[gpui::test]

crates/project/src/project.rs πŸ”—

@@ -69,7 +69,7 @@ use std::{
     hash::Hash,
     mem,
     num::NonZeroU32,
-    ops::Range,
+    ops::{ControlFlow, Range},
     path::{self, Component, Path, PathBuf},
     process::Stdio,
     str,
@@ -8442,7 +8442,10 @@ impl Project {
                             })
                             .await
                         {
-                            Ok(None) => {
+                            Ok(ControlFlow::Break(())) => {
+                                return None;
+                            }
+                            Ok(ControlFlow::Continue(None)) => {
                                 let started_default_prettier =
                                     project.update(&mut cx, |project, _| {
                                         project
@@ -8466,7 +8469,7 @@ impl Project {
                                     }
                                 }
                             }
-                            Ok(Some(prettier_dir)) => {
+                            Ok(ControlFlow::Continue(Some(prettier_dir))) => {
                                 project.update(&mut cx, |project, _| {
                                     project
                                         .prettiers_per_worktree
@@ -8593,7 +8596,7 @@ impl Project {
                     .await
                 })
             }
-            None => Task::ready(Ok(None)),
+            None => Task::ready(Ok(ControlFlow::Break(()))),
         };
         let mut plugins_to_install = prettier_plugins;
         let previous_installation_process =
@@ -8622,8 +8625,9 @@ impl Project {
                     .context("locate prettier installation")
                     .map_err(Arc::new)?
                 {
-                    Some(_non_default_prettier) => return Ok(()),
-                    None => {
+                    ControlFlow::Break(()) => return Ok(()),
+                    ControlFlow::Continue(Some(_non_default_prettier)) => return Ok(()),
+                    ControlFlow::Continue(None) => {
                         let mut needs_install = match previous_installation_process {
                             Some(previous_installation_process) => {
                                 previous_installation_process.await.is_err()

crates/project2/src/project2.rs πŸ”—

@@ -69,7 +69,7 @@ use std::{
     hash::Hash,
     mem,
     num::NonZeroU32,
-    ops::Range,
+    ops::{ControlFlow, Range},
     path::{self, Component, Path, PathBuf},
     process::Stdio,
     str,
@@ -8488,7 +8488,10 @@ impl Project {
                             })
                             .await
                         {
-                            Ok(None) => {
+                            Ok(ControlFlow::Break(())) => {
+                                return None;
+                            }
+                            Ok(ControlFlow::Continue(None)) => {
                                 match project.update(&mut cx, |project, _| {
                                     project
                                         .prettiers_per_worktree
@@ -8520,7 +8523,7 @@ impl Project {
                                         .shared())),
                                 }
                             }
-                            Ok(Some(prettier_dir)) => {
+                            Ok(ControlFlow::Continue(Some(prettier_dir))) => {
                                 match project.update(&mut cx, |project, _| {
                                     project
                                         .prettiers_per_worktree
@@ -8662,7 +8665,7 @@ impl Project {
                     .await
                 })
             }
-            None => Task::ready(Ok(None)),
+            None => Task::ready(Ok(ControlFlow::Break(()))),
         };
         let mut plugins_to_install = prettier_plugins;
         let previous_installation_process =
@@ -8692,8 +8695,9 @@ impl Project {
                     .context("locate prettier installation")
                     .map_err(Arc::new)?
                 {
-                    Some(_non_default_prettier) => return Ok(()),
-                    None => {
+                    ControlFlow::Break(()) => return Ok(()),
+                    ControlFlow::Continue(Some(_non_default_prettier)) => return Ok(()),
+                    ControlFlow::Continue(None) => {
                         let mut needs_install = match previous_installation_process {
                             Some(previous_installation_process) => {
                                 previous_installation_process.await.is_err()

crates/refineable/derive_refineable/src/derive_refineable.rs πŸ”—

@@ -19,8 +19,7 @@ pub fn derive_refineable(input: TokenStream) -> TokenStream {
     let refineable_attr = attrs.iter().find(|attr| attr.path.is_ident("refineable"));
 
     let mut impl_debug_on_refinement = false;
-    let mut derive_serialize_on_refinement = false;
-    let mut derive_deserialize_on_refinement = false;
+    let mut refinement_traits_to_derive = vec![];
 
     if let Some(refineable_attr) = refineable_attr {
         if let Ok(syn::Meta::List(meta_list)) = refineable_attr.parse_meta() {
@@ -29,16 +28,10 @@ pub fn derive_refineable(input: TokenStream) -> TokenStream {
                     continue;
                 };
 
-                if path.is_ident("debug") {
+                if path.is_ident("Debug") {
                     impl_debug_on_refinement = true;
-                }
-
-                if path.is_ident("serialize") {
-                    derive_serialize_on_refinement = true;
-                }
-
-                if path.is_ident("deserialize") {
-                    derive_deserialize_on_refinement = true;
+                } else {
+                    refinement_traits_to_derive.push(path);
                 }
             }
         }
@@ -259,22 +252,14 @@ pub fn derive_refineable(input: TokenStream) -> TokenStream {
         quote! {}
     };
 
-    let derive_serialize = if derive_serialize_on_refinement {
-        quote! { #[derive(serde::Serialize)]}
-    } else {
-        quote! {}
-    };
-
-    let derive_deserialize = if derive_deserialize_on_refinement {
-        quote! { #[derive(serde::Deserialize)]}
-    } else {
-        quote! {}
-    };
+    let mut derive_stream = quote! {};
+    for trait_to_derive in refinement_traits_to_derive {
+        derive_stream.extend(quote! { #[derive(#trait_to_derive)] })
+    }
 
     let gen = quote! {
         #[derive(Clone)]
-        #derive_serialize
-        #derive_deserialize
+        #derive_stream
         pub struct #refinement_ident #impl_generics {
             #( #field_visibilities #field_names: #wrapped_types ),*
         }

crates/theme2/Cargo.toml πŸ”—

@@ -6,6 +6,7 @@ publish = false
 
 [features]
 default = ["stories"]
+importing-themes = []
 stories = ["dep:itertools"]
 test-support = [
     "gpui/test-support",

crates/theme2/src/colors.rs πŸ”—

@@ -1,9 +1,7 @@
-use std::sync::Arc;
-
+use crate::{PlayerColors, SyntaxTheme};
 use gpui::Hsla;
 use refineable::Refineable;
-
-use crate::{PlayerColors, SyntaxTheme};
+use std::sync::Arc;
 
 #[derive(Clone)]
 pub struct SystemColors {
@@ -14,7 +12,7 @@ pub struct SystemColors {
 }
 
 #[derive(Refineable, Clone, Debug)]
-#[refineable(debug)]
+#[refineable(Debug, serde::Deserialize)]
 pub struct StatusColors {
     pub conflict: Hsla,
     pub created: Hsla,
@@ -30,7 +28,7 @@ pub struct StatusColors {
 }
 
 #[derive(Refineable, Clone, Debug)]
-#[refineable(debug, deserialize)]
+#[refineable(Debug, serde::Deserialize)]
 pub struct ThemeColors {
     pub border: Hsla,
     /// Border color. Used for deemphasized borders, like a visual divider between two sections

crates/theme2/src/default_colors.rs πŸ”—

@@ -1,5 +1,3 @@
-use std::num::ParseIntError;
-
 use gpui::{hsla, Hsla, Rgba};
 
 use crate::colors::{StatusColors, SystemColors, ThemeColors};
@@ -142,24 +140,24 @@ impl SyntaxTheme {
                 ("boolean".into(), tomato().light().step_11().into()),
                 ("comment".into(), neutral().light().step_11().into()),
                 ("comment.doc".into(), iris().light().step_12().into()),
-                ("constant".into(), red().light().step_7().into()),
-                ("constructor".into(), red().light().step_7().into()),
-                ("embedded".into(), red().light().step_7().into()),
-                ("emphasis".into(), red().light().step_7().into()),
-                ("emphasis.strong".into(), red().light().step_7().into()),
-                ("enum".into(), red().light().step_7().into()),
-                ("function".into(), red().light().step_7().into()),
-                ("hint".into(), red().light().step_7().into()),
+                ("constant".into(), red().light().step_9().into()),
+                ("constructor".into(), red().light().step_9().into()),
+                ("embedded".into(), red().light().step_9().into()),
+                ("emphasis".into(), red().light().step_9().into()),
+                ("emphasis.strong".into(), red().light().step_9().into()),
+                ("enum".into(), red().light().step_9().into()),
+                ("function".into(), red().light().step_9().into()),
+                ("hint".into(), red().light().step_9().into()),
                 ("keyword".into(), orange().light().step_11().into()),
-                ("label".into(), red().light().step_7().into()),
-                ("link_text".into(), red().light().step_7().into()),
-                ("link_uri".into(), red().light().step_7().into()),
-                ("number".into(), red().light().step_7().into()),
-                ("operator".into(), red().light().step_7().into()),
-                ("predictive".into(), red().light().step_7().into()),
-                ("preproc".into(), red().light().step_7().into()),
-                ("primary".into(), red().light().step_7().into()),
-                ("property".into(), red().light().step_7().into()),
+                ("label".into(), red().light().step_9().into()),
+                ("link_text".into(), red().light().step_9().into()),
+                ("link_uri".into(), red().light().step_9().into()),
+                ("number".into(), red().light().step_9().into()),
+                ("operator".into(), red().light().step_9().into()),
+                ("predictive".into(), red().light().step_9().into()),
+                ("preproc".into(), red().light().step_9().into()),
+                ("primary".into(), red().light().step_9().into()),
+                ("property".into(), red().light().step_9().into()),
                 ("punctuation".into(), neutral().light().step_11().into()),
                 (
                     "punctuation.bracket".into(),
@@ -173,22 +171,22 @@ impl SyntaxTheme {
                     "punctuation.list_marker".into(),
                     blue().light().step_11().into(),
                 ),
-                ("punctuation.special".into(), red().light().step_7().into()),
+                ("punctuation.special".into(), red().light().step_9().into()),
                 ("string".into(), jade().light().step_11().into()),
-                ("string.escape".into(), red().light().step_7().into()),
+                ("string.escape".into(), red().light().step_9().into()),
                 ("string.regex".into(), tomato().light().step_11().into()),
-                ("string.special".into(), red().light().step_7().into()),
+                ("string.special".into(), red().light().step_9().into()),
                 (
                     "string.special.symbol".into(),
-                    red().light().step_7().into(),
+                    red().light().step_9().into(),
                 ),
-                ("tag".into(), red().light().step_7().into()),
-                ("text.literal".into(), red().light().step_7().into()),
-                ("title".into(), red().light().step_7().into()),
-                ("type".into(), red().light().step_7().into()),
-                ("variable".into(), red().light().step_7().into()),
-                ("variable.special".into(), red().light().step_7().into()),
-                ("variant".into(), red().light().step_7().into()),
+                ("tag".into(), red().light().step_9().into()),
+                ("text.literal".into(), red().light().step_9().into()),
+                ("title".into(), red().light().step_9().into()),
+                ("type".into(), red().light().step_9().into()),
+                ("variable".into(), red().light().step_9().into()),
+                ("variable.special".into(), red().light().step_9().into()),
+                ("variant".into(), red().light().step_9().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")
@@ -198,28 +196,28 @@ impl SyntaxTheme {
     pub fn default_dark() -> Self {
         Self {
             highlights: vec![
-                ("attribute".into(), cyan().dark().step_11().into()),
+                ("attribute".into(), tomato().dark().step_11().into()),
                 ("boolean".into(), tomato().dark().step_11().into()),
                 ("comment".into(), neutral().dark().step_11().into()),
                 ("comment.doc".into(), iris().dark().step_12().into()),
-                ("constant".into(), red().dark().step_7().into()),
-                ("constructor".into(), red().dark().step_7().into()),
-                ("embedded".into(), red().dark().step_7().into()),
-                ("emphasis".into(), red().dark().step_7().into()),
-                ("emphasis.strong".into(), red().dark().step_7().into()),
-                ("enum".into(), red().dark().step_7().into()),
-                ("function".into(), red().dark().step_7().into()),
-                ("hint".into(), red().dark().step_7().into()),
-                ("keyword".into(), orange().dark().step_11().into()),
-                ("label".into(), red().dark().step_7().into()),
-                ("link_text".into(), red().dark().step_7().into()),
-                ("link_uri".into(), red().dark().step_7().into()),
-                ("number".into(), red().dark().step_7().into()),
-                ("operator".into(), red().dark().step_7().into()),
-                ("predictive".into(), red().dark().step_7().into()),
-                ("preproc".into(), red().dark().step_7().into()),
-                ("primary".into(), red().dark().step_7().into()),
-                ("property".into(), red().dark().step_7().into()),
+                ("constant".into(), orange().dark().step_11().into()),
+                ("constructor".into(), gold().dark().step_11().into()),
+                ("embedded".into(), red().dark().step_11().into()),
+                ("emphasis".into(), red().dark().step_11().into()),
+                ("emphasis.strong".into(), red().dark().step_11().into()),
+                ("enum".into(), yellow().dark().step_11().into()),
+                ("function".into(), blue().dark().step_11().into()),
+                ("hint".into(), indigo().dark().step_11().into()),
+                ("keyword".into(), plum().dark().step_11().into()),
+                ("label".into(), red().dark().step_11().into()),
+                ("link_text".into(), red().dark().step_11().into()),
+                ("link_uri".into(), red().dark().step_11().into()),
+                ("number".into(), red().dark().step_11().into()),
+                ("operator".into(), red().dark().step_11().into()),
+                ("predictive".into(), red().dark().step_11().into()),
+                ("preproc".into(), red().dark().step_11().into()),
+                ("primary".into(), red().dark().step_11().into()),
+                ("property".into(), red().dark().step_11().into()),
                 ("punctuation".into(), neutral().dark().step_11().into()),
                 (
                     "punctuation.bracket".into(),
@@ -233,22 +231,25 @@ impl SyntaxTheme {
                     "punctuation.list_marker".into(),
                     blue().dark().step_11().into(),
                 ),
-                ("punctuation.special".into(), red().dark().step_7().into()),
-                ("string".into(), jade().dark().step_11().into()),
-                ("string.escape".into(), red().dark().step_7().into()),
+                ("punctuation.special".into(), red().dark().step_11().into()),
+                ("string".into(), lime().dark().step_11().into()),
+                ("string.escape".into(), orange().dark().step_11().into()),
                 ("string.regex".into(), tomato().dark().step_11().into()),
-                ("string.special".into(), red().dark().step_7().into()),
-                ("string.special.symbol".into(), red().dark().step_7().into()),
-                ("tag".into(), red().dark().step_7().into()),
-                ("text.literal".into(), red().dark().step_7().into()),
-                ("title".into(), red().dark().step_7().into()),
-                ("type".into(), red().dark().step_7().into()),
-                ("variable".into(), red().dark().step_7().into()),
-                ("variable.special".into(), red().dark().step_7().into()),
-                ("variant".into(), red().dark().step_7().into()),
+                ("string.special".into(), red().dark().step_11().into()),
+                (
+                    "string.special.symbol".into(),
+                    red().dark().step_11().into(),
+                ),
+                ("tag".into(), red().dark().step_11().into()),
+                ("text.literal".into(), purple().dark().step_11().into()),
+                ("title".into(), sky().dark().step_11().into()),
+                ("type".into(), mint().dark().step_11().into()),
+                ("variable".into(), red().dark().step_11().into()),
+                ("variable.special".into(), red().dark().step_11().into()),
+                ("variant".into(), red().dark().step_11().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")
+            inlay_style: neutral().dark().step_11().into(), // todo!("nate: use a proper style")
+            suggestion_style: orange().dark().step_11().into(), // todo!("nate: use a proper style")
         }
     }
 }
@@ -278,7 +279,7 @@ impl ThemeColors {
             ghost_element_active: neutral().light().step_5(),
             ghost_element_selected: neutral().light().step_5(),
             ghost_element_disabled: neutral().light_alpha().step_3(),
-            text: neutral().light().step_12(),
+            text: yellow().light().step_9(),
             text_muted: neutral().light().step_11(),
             text_placeholder: neutral().light().step_10(),
             text_disabled: neutral().light().step_9(),
@@ -367,11 +368,11 @@ impl ThemeColors {
             tab_active_background: neutral().dark().step_1(),
             tab_inactive_background: neutral().dark().step_2(),
             editor_background: neutral().dark().step_1(),
-            editor_gutter_background: neutral().dark().step_1(), // todo!("pick the right colors")
-            editor_subheader_background: neutral().dark().step_2(),
+            editor_gutter_background: neutral().dark().step_1(),
+            editor_subheader_background: neutral().dark().step_3(),
             editor_active_line_background: neutral().dark_alpha().step_3(),
-            editor_line_number: neutral().dark_alpha().step_3(), // todo!("pick the right colors")
-            editor_active_line_number: neutral().dark_alpha().step_3(), // todo!("pick the right colors")
+            editor_line_number: neutral().dark_alpha().step_10(),
+            editor_active_line_number: neutral().dark_alpha().step_12(),
             editor_highlighted_line_background: neutral().dark_alpha().step_4(), // todo!("pick the right colors")
             editor_invisible: neutral().dark_alpha().step_4(), // todo!("pick the right colors")
             editor_wrap_guide: neutral().dark_alpha().step_4(), // todo!("pick the right colors")
@@ -410,10 +411,10 @@ struct StaticColorScaleSet {
 }
 
 impl TryFrom<StaticColorScaleSet> for ColorScaleSet {
-    type Error = ParseIntError;
+    type Error = anyhow::Error;
 
     fn try_from(value: StaticColorScaleSet) -> Result<Self, Self::Error> {
-        fn to_color_scale(scale: StaticColorScale) -> Result<ColorScale, ParseIntError> {
+        fn to_color_scale(scale: StaticColorScale) -> Result<ColorScale, anyhow::Error> {
             scale
                 .into_iter()
                 .map(|color| Rgba::try_from(color).map(Hsla::from))

crates/theme2/src/registry.rs πŸ”—

@@ -2,7 +2,7 @@ use std::collections::HashMap;
 use std::sync::Arc;
 
 use anyhow::{anyhow, Result};
-use gpui::SharedString;
+use gpui::{HighlightStyle, SharedString};
 use refineable::Refineable;
 
 use crate::{
@@ -27,21 +27,47 @@ impl ThemeRegistry {
         }
     }
 
+    #[allow(unused)]
     fn insert_user_theme_familes(&mut self, families: impl IntoIterator<Item = UserThemeFamily>) {
         for family in families.into_iter() {
             self.insert_user_themes(family.themes);
         }
     }
 
+    #[allow(unused)]
     fn insert_user_themes(&mut self, themes: impl IntoIterator<Item = UserTheme>) {
         self.insert_themes(themes.into_iter().map(|user_theme| {
             let mut theme_colors = match user_theme.appearance {
                 Appearance::Light => ThemeColors::default_light(),
                 Appearance::Dark => ThemeColors::default_dark(),
             };
-
             theme_colors.refine(&user_theme.styles.colors);
 
+            let mut status_colors = StatusColors::default();
+            status_colors.refine(&user_theme.styles.status);
+
+            let mut syntax_colors = match user_theme.appearance {
+                Appearance::Light => SyntaxTheme::default_light(),
+                Appearance::Dark => SyntaxTheme::default_dark(),
+            };
+            if let Some(user_syntax) = user_theme.styles.syntax {
+                syntax_colors.highlights = user_syntax
+                    .highlights
+                    .iter()
+                    .map(|(syntax_token, highlight)| {
+                        (
+                            syntax_token.clone(),
+                            HighlightStyle {
+                                color: highlight.color,
+                                font_style: highlight.font_style.map(Into::into),
+                                font_weight: highlight.font_weight.map(Into::into),
+                                ..Default::default()
+                            },
+                        )
+                    })
+                    .collect::<Vec<_>>();
+            }
+
             Theme {
                 id: uuid::Uuid::new_v4().to_string(),
                 name: user_theme.name.into(),
@@ -49,12 +75,9 @@ impl ThemeRegistry {
                 styles: ThemeStyles {
                     system: SystemColors::default(),
                     colors: theme_colors,
-                    status: StatusColors::default(),
+                    status: status_colors,
                     player: PlayerColors::default(),
-                    syntax: match user_theme.appearance {
-                        Appearance::Light => Arc::new(SyntaxTheme::default_light()),
-                        Appearance::Dark => Arc::new(SyntaxTheme::default_dark()),
-                    },
+                    syntax: Arc::new(syntax_colors),
                 },
             }
         }));
@@ -83,6 +106,8 @@ impl Default for ThemeRegistry {
         };
 
         this.insert_theme_families([zed_pro_family()]);
+
+        #[cfg(not(feature = "importing-themes"))]
         this.insert_user_theme_familes(crate::all_user_themes());
 
         this

crates/theme2/src/scale.rs πŸ”—

@@ -128,6 +128,8 @@ impl ColorScale {
     }
 
     /// `Step 10` - Used for hovered or active solid backgrounds, particularly when `Step 9` is their normal state.
+    ///
+    /// May also be used for extremely low contrast text. This should be used sparingly, as it may be difficult to read.
     #[inline]
     pub fn step_10(&self) -> Hsla {
         self.step(ColorScaleStep::TEN)

crates/theme2/src/theme2.rs πŸ”—

@@ -6,6 +6,7 @@ mod registry;
 mod scale;
 mod settings;
 mod syntax;
+#[cfg(not(feature = "importing-themes"))]
 mod themes;
 mod user_theme;
 
@@ -20,6 +21,7 @@ pub use registry::*;
 pub use scale::*;
 pub use settings::*;
 pub use syntax::*;
+#[cfg(not(feature = "importing-themes"))]
 pub use themes::*;
 pub use user_theme::*;
 

crates/theme2/src/themes/andromeda.rs πŸ”—

@@ -3,8 +3,10 @@
 
 use gpui::rgba;
 
+#[allow(unused)]
 use crate::{
-    Appearance, ThemeColorsRefinement, UserTheme, UserThemeFamily, UserThemeStylesRefinement,
+    Appearance, StatusColorsRefinement, ThemeColorsRefinement, UserFontStyle, UserFontWeight,
+    UserHighlightStyle, UserSyntaxTheme, UserTheme, UserThemeFamily, UserThemeStylesRefinement,
 };
 
 pub fn andromeda() -> UserThemeFamily {
@@ -19,7 +21,7 @@ pub fn andromeda() -> UserThemeFamily {
                     colors: ThemeColorsRefinement {
                         border: Some(rgba(0x1b1d23ff).into()),
                         border_variant: Some(rgba(0x1b1d23ff).into()),
-                        border_focused: Some(rgba(0x1b1d23ff).into()),
+                        border_focused: Some(rgba(0x746f77ff).into()),
                         border_selected: Some(rgba(0x1b1d23ff).into()),
                         border_transparent: Some(rgba(0x1b1d23ff).into()),
                         border_disabled: Some(rgba(0x1b1d23ff).into()),
@@ -27,9 +29,17 @@ pub fn andromeda() -> UserThemeFamily {
                         surface_background: Some(rgba(0x23262eff).into()),
                         background: Some(rgba(0x23262eff).into()),
                         element_background: Some(rgba(0x00e8c5cc).into()),
+                        element_hover: Some(rgba(0x23262eff).into()),
+                        element_selected: Some(rgba(0x23262eff).into()),
+                        drop_target_background: Some(rgba(0x3a404eff).into()),
+                        ghost_element_hover: Some(rgba(0x23262eff).into()),
                         text: Some(rgba(0xd4cdd8ff).into()),
                         tab_inactive_background: Some(rgba(0x23262eff).into()),
                         tab_active_background: Some(rgba(0x23262eff).into()),
+                        editor_background: Some(rgba(0x23262eff).into()),
+                        editor_gutter_background: Some(rgba(0x23262eff).into()),
+                        editor_line_number: Some(rgba(0x746f77ff).into()),
+                        editor_active_line_number: Some(rgba(0xd4cdd8ff).into()),
                         terminal_ansi_bright_red: Some(rgba(0xee5d42ff).into()),
                         terminal_ansi_bright_green: Some(rgba(0x95e072ff).into()),
                         terminal_ansi_bright_yellow: Some(rgba(0xffe66dff).into()),
@@ -44,6 +54,107 @@ pub fn andromeda() -> UserThemeFamily {
                         terminal_ansi_cyan: Some(rgba(0x00e8c6ff).into()),
                         ..Default::default()
                     },
+                    status: StatusColorsRefinement {
+                        deleted: Some(rgba(0xfc634cff).into()),
+                        error: Some(rgba(0xfc634cff).into()),
+                        hidden: Some(rgba(0x746f77ff).into()),
+                        ..Default::default()
+                    },
+                    syntax: Some(UserSyntaxTheme {
+                        highlights: vec![
+                            (
+                                "attribute".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xf39c11ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "comment".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x9fa0a6cc).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "emphasis".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xc64dedff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "emphasis.strong".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xf39c11ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "function".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xffe66dff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "keyword".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xc64dedff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "number".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xf39c11ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "operator".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xee5d42ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x95e072ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "tag".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xf92571ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "text.literal".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x95e072ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "type".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xffe66dff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x00e8c6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                        ],
+                    }),
                 },
             },
             UserTheme {
@@ -53,7 +164,7 @@ pub fn andromeda() -> UserThemeFamily {
                     colors: ThemeColorsRefinement {
                         border: Some(rgba(0x1b1d23ff).into()),
                         border_variant: Some(rgba(0x1b1d23ff).into()),
-                        border_focused: Some(rgba(0x1b1d23ff).into()),
+                        border_focused: Some(rgba(0x746f77ff).into()),
                         border_selected: Some(rgba(0x1b1d23ff).into()),
                         border_transparent: Some(rgba(0x1b1d23ff).into()),
                         border_disabled: Some(rgba(0x1b1d23ff).into()),
@@ -61,9 +172,17 @@ pub fn andromeda() -> UserThemeFamily {
                         surface_background: Some(rgba(0x23262eff).into()),
                         background: Some(rgba(0x262933ff).into()),
                         element_background: Some(rgba(0x00e8c5cc).into()),
+                        element_hover: Some(rgba(0x23262eff).into()),
+                        element_selected: Some(rgba(0x23262eff).into()),
+                        drop_target_background: Some(rgba(0x3a404eff).into()),
+                        ghost_element_hover: Some(rgba(0x23262eff).into()),
                         text: Some(rgba(0xd4cdd8ff).into()),
                         tab_inactive_background: Some(rgba(0x23262eff).into()),
                         tab_active_background: Some(rgba(0x262933ff).into()),
+                        editor_background: Some(rgba(0x262933ff).into()),
+                        editor_gutter_background: Some(rgba(0x262933ff).into()),
+                        editor_line_number: Some(rgba(0x746f77ff).into()),
+                        editor_active_line_number: Some(rgba(0xd4cdd8ff).into()),
                         terminal_ansi_bright_red: Some(rgba(0xee5d42ff).into()),
                         terminal_ansi_bright_green: Some(rgba(0x95e072ff).into()),
                         terminal_ansi_bright_yellow: Some(rgba(0xffe66dff).into()),
@@ -78,6 +197,107 @@ pub fn andromeda() -> UserThemeFamily {
                         terminal_ansi_cyan: Some(rgba(0x00e8c6ff).into()),
                         ..Default::default()
                     },
+                    status: StatusColorsRefinement {
+                        deleted: Some(rgba(0xfc634cff).into()),
+                        error: Some(rgba(0xfc634cff).into()),
+                        hidden: Some(rgba(0x746f77ff).into()),
+                        ..Default::default()
+                    },
+                    syntax: Some(UserSyntaxTheme {
+                        highlights: vec![
+                            (
+                                "attribute".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xf39c11ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "comment".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x9fa0a6cc).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "emphasis".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xc64dedff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "emphasis.strong".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xf39c11ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "function".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xffe66dff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "keyword".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xc64dedff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "number".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xf39c11ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "operator".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xee5d42ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x95e072ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "tag".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xf92571ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "text.literal".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x95e072ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "type".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xffe66dff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x00e8c6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                        ],
+                    }),
                 },
             },
         ],

crates/theme2/src/themes/ayu.rs πŸ”—

@@ -3,8 +3,10 @@
 
 use gpui::rgba;
 
+#[allow(unused)]
 use crate::{
-    Appearance, ThemeColorsRefinement, UserTheme, UserThemeFamily, UserThemeStylesRefinement,
+    Appearance, StatusColorsRefinement, ThemeColorsRefinement, UserFontStyle, UserFontWeight,
+    UserHighlightStyle, UserSyntaxTheme, UserTheme, UserThemeFamily, UserThemeStylesRefinement,
 };
 
 pub fn ayu() -> UserThemeFamily {
@@ -19,7 +21,7 @@ pub fn ayu() -> UserThemeFamily {
                     colors: ThemeColorsRefinement {
                         border: Some(rgba(0x6b7d8f1f).into()),
                         border_variant: Some(rgba(0x6b7d8f1f).into()),
-                        border_focused: Some(rgba(0x6b7d8f1f).into()),
+                        border_focused: Some(rgba(0xffaa32b3).into()),
                         border_selected: Some(rgba(0x6b7d8f1f).into()),
                         border_transparent: Some(rgba(0x6b7d8f1f).into()),
                         border_disabled: Some(rgba(0x6b7d8f1f).into()),
@@ -27,9 +29,16 @@ pub fn ayu() -> UserThemeFamily {
                         surface_background: Some(rgba(0xf8f9faff).into()),
                         background: Some(rgba(0xf8f9faff).into()),
                         element_background: Some(rgba(0xffaa32ff).into()),
+                        element_hover: Some(rgba(0x55728f1f).into()),
+                        element_selected: Some(rgba(0x55728f1f).into()),
+                        ghost_element_hover: Some(rgba(0x55728f1f).into()),
                         text: Some(rgba(0x8a9199ff).into()),
                         tab_inactive_background: Some(rgba(0xf8f9faff).into()),
                         tab_active_background: Some(rgba(0xf8f9faff).into()),
+                        editor_background: Some(rgba(0xf8f9faff).into()),
+                        editor_gutter_background: Some(rgba(0xf8f9faff).into()),
+                        editor_line_number: Some(rgba(0x8a919966).into()),
+                        editor_active_line_number: Some(rgba(0x5c6166ff).into()),
                         terminal_background: Some(rgba(0xf8f9faff).into()),
                         terminal_ansi_bright_black: Some(rgba(0x686868ff).into()),
                         terminal_ansi_bright_red: Some(rgba(0xef7070ff).into()),
@@ -49,6 +58,222 @@ pub fn ayu() -> UserThemeFamily {
                         terminal_ansi_white: Some(rgba(0xc7c7c7ff).into()),
                         ..Default::default()
                     },
+                    status: StatusColorsRefinement {
+                        deleted: Some(rgba(0xe65050ff).into()),
+                        error: Some(rgba(0xe65050ff).into()),
+                        hidden: Some(rgba(0x8a9199ff).into()),
+                        ..Default::default()
+                    },
+                    syntax: Some(UserSyntaxTheme {
+                        highlights: vec![
+                            (
+                                "attribute".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xf2ad48ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "boolean".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xa37accff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "comment".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x787b8099).into()),
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "constant".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x4bbf98ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "embedded".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x5c6166ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "emphasis".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xef7070ff).into()),
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "emphasis.strong".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xef7070ff).into()),
+                                    font_weight: Some(UserFontWeight(700.0)),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "function".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xf2ad48ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "keyword".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xfa8d3eff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "label".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x86b300ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "link_text".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x55b4d3ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "link_uri".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x55b4d3ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "number".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xa37accff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "operator".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xed9365ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "property".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xef7070ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "punctuation".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x5c6166b3).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "punctuation.bracket".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x55b4d380).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "punctuation.delimiter".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x5c6166b3).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "punctuation.list_marker".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xf2ad48ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x86b300ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string.escape".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x4bbf98ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string.special".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x86b300ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string.special.symbol".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x86b300ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "tag".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x55b4d3ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "text.literal".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x86b300ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "title".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x389ee6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "type".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x55b4d3ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x5c6166ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable.special".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xef7070ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                        ],
+                    }),
                 },
             },
             UserTheme {
@@ -58,7 +283,7 @@ pub fn ayu() -> UserThemeFamily {
                     colors: ThemeColorsRefinement {
                         border: Some(rgba(0x171a24ff).into()),
                         border_variant: Some(rgba(0x171a24ff).into()),
-                        border_focused: Some(rgba(0x171a24ff).into()),
+                        border_focused: Some(rgba(0xffcb65b3).into()),
                         border_selected: Some(rgba(0x171a24ff).into()),
                         border_transparent: Some(rgba(0x171a24ff).into()),
                         border_disabled: Some(rgba(0x171a24ff).into()),
@@ -66,9 +291,16 @@ pub fn ayu() -> UserThemeFamily {
                         surface_background: Some(rgba(0x1f2430ff).into()),
                         background: Some(rgba(0x1f2430ff).into()),
                         element_background: Some(rgba(0xffcb65ff).into()),
+                        element_hover: Some(rgba(0x63759926).into()),
+                        element_selected: Some(rgba(0x63759926).into()),
+                        ghost_element_hover: Some(rgba(0x63759926).into()),
                         text: Some(rgba(0x707a8cff).into()),
                         tab_inactive_background: Some(rgba(0x1f2430ff).into()),
                         tab_active_background: Some(rgba(0x1f2430ff).into()),
+                        editor_background: Some(rgba(0x1f2430ff).into()),
+                        editor_gutter_background: Some(rgba(0x1f2430ff).into()),
+                        editor_line_number: Some(rgba(0x8a919966).into()),
+                        editor_active_line_number: Some(rgba(0xcccac2ff).into()),
                         terminal_background: Some(rgba(0x1f2430ff).into()),
                         terminal_ansi_bright_black: Some(rgba(0x686868ff).into()),
                         terminal_ansi_bright_red: Some(rgba(0xf18678ff).into()),
@@ -88,6 +320,222 @@ pub fn ayu() -> UserThemeFamily {
                         terminal_ansi_white: Some(rgba(0xc7c7c7ff).into()),
                         ..Default::default()
                     },
+                    status: StatusColorsRefinement {
+                        deleted: Some(rgba(0xff6565ff).into()),
+                        error: Some(rgba(0xff6565ff).into()),
+                        hidden: Some(rgba(0x707a8cff).into()),
+                        ..Default::default()
+                    },
+                    syntax: Some(UserSyntaxTheme {
+                        highlights: vec![
+                            (
+                                "attribute".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xffd173ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "boolean".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xdfbfffff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "comment".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xb8cfe680).into()),
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "constant".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x95e6cbff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "embedded".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xcccac2ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "emphasis".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xf18678ff).into()),
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "emphasis.strong".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xf18678ff).into()),
+                                    font_weight: Some(UserFontWeight(700.0)),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "function".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xffd173ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "keyword".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xffad65ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "label".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xd4fe7fff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "link_text".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x5ccfe6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "link_uri".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x5ccfe6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "number".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xdfbfffff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "operator".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xf29e74ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "property".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xf18678ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "punctuation".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xcccac2b3).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "punctuation.bracket".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x5ccfe680).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "punctuation.delimiter".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xcccac2b3).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "punctuation.list_marker".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xffd173ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xd4fe7fff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string.escape".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x95e6cbff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string.special".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xd4fe7fff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string.special.symbol".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xd4fe7fff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "tag".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x5ccfe6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "text.literal".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xd4fe7fff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "title".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x73cfffff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "type".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x5ccfe6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xcccac2ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable.special".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xf18678ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                        ],
+                    }),
                 },
             },
             UserTheme {
@@ -97,7 +545,7 @@ pub fn ayu() -> UserThemeFamily {
                     colors: ThemeColorsRefinement {
                         border: Some(rgba(0x1e232bff).into()),
                         border_variant: Some(rgba(0x1e232bff).into()),
-                        border_focused: Some(rgba(0x1e232bff).into()),
+                        border_focused: Some(rgba(0xe6b450b3).into()),
                         border_selected: Some(rgba(0x1e232bff).into()),
                         border_transparent: Some(rgba(0x1e232bff).into()),
                         border_disabled: Some(rgba(0x1e232bff).into()),
@@ -105,9 +553,16 @@ pub fn ayu() -> UserThemeFamily {
                         surface_background: Some(rgba(0x0b0e14ff).into()),
                         background: Some(rgba(0x0b0e14ff).into()),
                         element_background: Some(rgba(0xe6b450ff).into()),
+                        element_hover: Some(rgba(0x47526640).into()),
+                        element_selected: Some(rgba(0x47526640).into()),
+                        ghost_element_hover: Some(rgba(0x47526640).into()),
                         text: Some(rgba(0x565b66ff).into()),
                         tab_inactive_background: Some(rgba(0x0b0e14ff).into()),
                         tab_active_background: Some(rgba(0x0b0e14ff).into()),
+                        editor_background: Some(rgba(0x0b0e14ff).into()),
+                        editor_gutter_background: Some(rgba(0x0b0e14ff).into()),
+                        editor_line_number: Some(rgba(0x6c738099).into()),
+                        editor_active_line_number: Some(rgba(0xbfbdb6ff).into()),
                         terminal_background: Some(rgba(0x0b0e14ff).into()),
                         terminal_ansi_bright_black: Some(rgba(0x686868ff).into()),
                         terminal_ansi_bright_red: Some(rgba(0xef7077ff).into()),
@@ -127,6 +582,222 @@ pub fn ayu() -> UserThemeFamily {
                         terminal_ansi_white: Some(rgba(0xc7c7c7ff).into()),
                         ..Default::default()
                     },
+                    status: StatusColorsRefinement {
+                        deleted: Some(rgba(0xd95757ff).into()),
+                        error: Some(rgba(0xd95757ff).into()),
+                        hidden: Some(rgba(0x565b66ff).into()),
+                        ..Default::default()
+                    },
+                    syntax: Some(UserSyntaxTheme {
+                        highlights: vec![
+                            (
+                                "attribute".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xffb353ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "boolean".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xd2a6ffff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "comment".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xabb5be8c).into()),
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "constant".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x95e6cbff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "embedded".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xbfbdb6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "emphasis".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xef7077ff).into()),
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "emphasis.strong".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xef7077ff).into()),
+                                    font_weight: Some(UserFontWeight(700.0)),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "function".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xffb353ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "keyword".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xff8f3fff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "label".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xa9d94bff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "link_text".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x38b9e6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "link_uri".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x38b9e6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "number".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xd2a6ffff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "operator".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xf29668ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "property".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xef7077ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "punctuation".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xbfbdb6b3).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "punctuation.bracket".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x38b9e680).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "punctuation.delimiter".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xbfbdb6b3).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "punctuation.list_marker".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xffb353ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xa9d94bff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string.escape".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x95e6cbff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string.special".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xa9d94bff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string.special.symbol".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xa9d94bff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "tag".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x38b9e6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "text.literal".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xa9d94bff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "title".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x59c2ffff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "type".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x38b9e6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xbfbdb6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable.special".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xef7077ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                        ],
+                    }),
                 },
             },
         ],

crates/theme2/src/themes/dracula.rs πŸ”—

@@ -3,8 +3,10 @@
 
 use gpui::rgba;
 
+#[allow(unused)]
 use crate::{
-    Appearance, ThemeColorsRefinement, UserTheme, UserThemeFamily, UserThemeStylesRefinement,
+    Appearance, StatusColorsRefinement, ThemeColorsRefinement, UserFontStyle, UserFontWeight,
+    UserHighlightStyle, UserSyntaxTheme, UserTheme, UserThemeFamily, UserThemeStylesRefinement,
 };
 
 pub fn dracula() -> UserThemeFamily {
@@ -18,7 +20,7 @@ pub fn dracula() -> UserThemeFamily {
                 colors: ThemeColorsRefinement {
                     border: Some(rgba(0xbd93f9ff).into()),
                     border_variant: Some(rgba(0xbd93f9ff).into()),
-                    border_focused: Some(rgba(0xbd93f9ff).into()),
+                    border_focused: Some(rgba(0x6272a4ff).into()),
                     border_selected: Some(rgba(0xbd93f9ff).into()),
                     border_transparent: Some(rgba(0xbd93f9ff).into()),
                     border_disabled: Some(rgba(0xbd93f9ff).into()),
@@ -26,9 +28,17 @@ pub fn dracula() -> UserThemeFamily {
                     surface_background: Some(rgba(0x282a35ff).into()),
                     background: Some(rgba(0x282a35ff).into()),
                     element_background: Some(rgba(0x44475aff).into()),
+                    element_hover: Some(rgba(0x44475a75).into()),
+                    element_selected: Some(rgba(0x44475aff).into()),
+                    drop_target_background: Some(rgba(0x44475aff).into()),
+                    ghost_element_hover: Some(rgba(0x44475a75).into()),
                     text: Some(rgba(0xf8f8f2ff).into()),
                     tab_inactive_background: Some(rgba(0x21222cff).into()),
                     tab_active_background: Some(rgba(0x282a35ff).into()),
+                    editor_background: Some(rgba(0x282a35ff).into()),
+                    editor_gutter_background: Some(rgba(0x282a35ff).into()),
+                    editor_line_number: Some(rgba(0x6272a4ff).into()),
+                    editor_active_line_number: Some(rgba(0xf8f8f2ff).into()),
                     terminal_background: Some(rgba(0x282a35ff).into()),
                     terminal_ansi_bright_black: Some(rgba(0x6272a4ff).into()),
                     terminal_ansi_bright_red: Some(rgba(0xff6d6dff).into()),
@@ -48,6 +58,121 @@ pub fn dracula() -> UserThemeFamily {
                     terminal_ansi_white: Some(rgba(0xf8f8f2ff).into()),
                     ..Default::default()
                 },
+                status: StatusColorsRefinement {
+                    deleted: Some(rgba(0xff5555ff).into()),
+                    error: Some(rgba(0xff5555ff).into()),
+                    hidden: Some(rgba(0x6272a4ff).into()),
+                    warning: Some(rgba(0xffb76bff).into()),
+                    ..Default::default()
+                },
+                syntax: Some(UserSyntaxTheme {
+                    highlights: vec![
+                        (
+                            "attribute".into(),
+                            UserHighlightStyle {
+                                color: Some(rgba(0x50fa7bff).into()),
+                                font_style: Some(UserFontStyle::Italic),
+                                ..Default::default()
+                            },
+                        ),
+                        (
+                            "comment".into(),
+                            UserHighlightStyle {
+                                color: Some(rgba(0x6272a4ff).into()),
+                                ..Default::default()
+                            },
+                        ),
+                        (
+                            "emphasis".into(),
+                            UserHighlightStyle {
+                                color: Some(rgba(0xf1fa8cff).into()),
+                                font_style: Some(UserFontStyle::Italic),
+                                ..Default::default()
+                            },
+                        ),
+                        (
+                            "emphasis.strong".into(),
+                            UserHighlightStyle {
+                                color: Some(rgba(0xffb76bff).into()),
+                                font_weight: Some(UserFontWeight(700.0)),
+                                ..Default::default()
+                            },
+                        ),
+                        (
+                            "function".into(),
+                            UserHighlightStyle {
+                                color: Some(rgba(0x50fa7bff).into()),
+                                ..Default::default()
+                            },
+                        ),
+                        (
+                            "keyword".into(),
+                            UserHighlightStyle {
+                                color: Some(rgba(0xff79c6ff).into()),
+                                ..Default::default()
+                            },
+                        ),
+                        (
+                            "link_text".into(),
+                            UserHighlightStyle {
+                                color: Some(rgba(0x8be9fdff).into()),
+                                ..Default::default()
+                            },
+                        ),
+                        (
+                            "link_uri".into(),
+                            UserHighlightStyle {
+                                color: Some(rgba(0x8be9fdff).into()),
+                                ..Default::default()
+                            },
+                        ),
+                        (
+                            "string".into(),
+                            UserHighlightStyle {
+                                color: Some(rgba(0xf1fa8cff).into()),
+                                ..Default::default()
+                            },
+                        ),
+                        (
+                            "tag".into(),
+                            UserHighlightStyle {
+                                color: Some(rgba(0xff79c6ff).into()),
+                                ..Default::default()
+                            },
+                        ),
+                        (
+                            "text.literal".into(),
+                            UserHighlightStyle {
+                                color: Some(rgba(0xf1fa8cff).into()),
+                                ..Default::default()
+                            },
+                        ),
+                        (
+                            "type".into(),
+                            UserHighlightStyle {
+                                color: Some(rgba(0x8be9fdff).into()),
+                                font_style: Some(UserFontStyle::Italic),
+                                ..Default::default()
+                            },
+                        ),
+                        (
+                            "variable".into(),
+                            UserHighlightStyle {
+                                color: Some(rgba(0xbd93f9ff).into()),
+                                font_style: Some(UserFontStyle::Italic),
+                                ..Default::default()
+                            },
+                        ),
+                        (
+                            "variable.special".into(),
+                            UserHighlightStyle {
+                                color: Some(rgba(0xbd93f9ff).into()),
+                                font_style: Some(UserFontStyle::Italic),
+                                ..Default::default()
+                            },
+                        ),
+                    ],
+                }),
             },
         }],
     }

crates/theme2/src/themes/gruvbox.rs πŸ”—

@@ -3,8 +3,10 @@
 
 use gpui::rgba;
 
+#[allow(unused)]
 use crate::{
-    Appearance, ThemeColorsRefinement, UserTheme, UserThemeFamily, UserThemeStylesRefinement,
+    Appearance, StatusColorsRefinement, ThemeColorsRefinement, UserFontStyle, UserFontWeight,
+    UserHighlightStyle, UserSyntaxTheme, UserTheme, UserThemeFamily, UserThemeStylesRefinement,
 };
 
 pub fn gruvbox() -> UserThemeFamily {
@@ -25,9 +27,17 @@ pub fn gruvbox() -> UserThemeFamily {
                         border_disabled: Some(rgba(0x3c3836ff).into()),
                         background: Some(rgba(0x1d2021ff).into()),
                         element_background: Some(rgba(0x44858780).into()),
+                        element_hover: Some(rgba(0x3c383680).into()),
+                        element_selected: Some(rgba(0x3c383680).into()),
+                        drop_target_background: Some(rgba(0x3c3836ff).into()),
+                        ghost_element_hover: Some(rgba(0x3c383680).into()),
                         text: Some(rgba(0xebdbb2ff).into()),
                         tab_inactive_background: Some(rgba(0x1d2021ff).into()),
                         tab_active_background: Some(rgba(0x32302fff).into()),
+                        editor_background: Some(rgba(0x1d2021ff).into()),
+                        editor_gutter_background: Some(rgba(0x1d2021ff).into()),
+                        editor_line_number: Some(rgba(0x665c54ff).into()),
+                        editor_active_line_number: Some(rgba(0xebdbb2ff).into()),
                         terminal_background: Some(rgba(0x1d2021ff).into()),
                         terminal_ansi_bright_black: Some(rgba(0x928374ff).into()),
                         terminal_ansi_bright_red: Some(rgba(0xfb4833ff).into()),
@@ -47,6 +57,151 @@ pub fn gruvbox() -> UserThemeFamily {
                         terminal_ansi_white: Some(rgba(0xa89984ff).into()),
                         ..Default::default()
                     },
+                    status: StatusColorsRefinement {
+                        deleted: Some(rgba(0xfb4833ff).into()),
+                        error: Some(rgba(0xfb4833ff).into()),
+                        hidden: Some(rgba(0xa89984ff).into()),
+                        ..Default::default()
+                    },
+                    syntax: Some(UserSyntaxTheme {
+                        highlights: vec![
+                            (
+                                "attribute".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xfabd2eff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "comment".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x928374ff).into()),
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "emphasis".into(),
+                                UserHighlightStyle {
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "emphasis.strong".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xfe7f18ff).into()),
+                                    font_weight: Some(UserFontWeight(700.0)),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "function".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xfabd2eff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "keyword".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xfb4833ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "label".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xfabd2eff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "link_text".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xd3869bff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "link_uri".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xd3869bff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "operator".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x8ec07cff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "property".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x679d6aff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "punctuation".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xa89984ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xb8bb25ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string.escape".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xfb4833ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "tag".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x8ec07cff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "text.literal".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xb8bb25ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "title".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xfabd2eff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "type".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xfabd2eff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x83a598ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                        ],
+                    }),
                 },
             },
             UserTheme {
@@ -62,9 +217,17 @@ pub fn gruvbox() -> UserThemeFamily {
                         border_disabled: Some(rgba(0x3c3836ff).into()),
                         background: Some(rgba(0x282828ff).into()),
                         element_background: Some(rgba(0x44858780).into()),
+                        element_hover: Some(rgba(0x3c383680).into()),
+                        element_selected: Some(rgba(0x3c383680).into()),
+                        drop_target_background: Some(rgba(0x3c3836ff).into()),
+                        ghost_element_hover: Some(rgba(0x3c383680).into()),
                         text: Some(rgba(0xebdbb2ff).into()),
                         tab_inactive_background: Some(rgba(0x282828ff).into()),
                         tab_active_background: Some(rgba(0x3c3836ff).into()),
+                        editor_background: Some(rgba(0x282828ff).into()),
+                        editor_gutter_background: Some(rgba(0x282828ff).into()),
+                        editor_line_number: Some(rgba(0x665c54ff).into()),
+                        editor_active_line_number: Some(rgba(0xebdbb2ff).into()),
                         terminal_background: Some(rgba(0x282828ff).into()),
                         terminal_ansi_bright_black: Some(rgba(0x928374ff).into()),
                         terminal_ansi_bright_red: Some(rgba(0xfb4833ff).into()),
@@ -84,6 +247,151 @@ pub fn gruvbox() -> UserThemeFamily {
                         terminal_ansi_white: Some(rgba(0xa89984ff).into()),
                         ..Default::default()
                     },
+                    status: StatusColorsRefinement {
+                        deleted: Some(rgba(0xfb4833ff).into()),
+                        error: Some(rgba(0xfb4833ff).into()),
+                        hidden: Some(rgba(0xa89984ff).into()),
+                        ..Default::default()
+                    },
+                    syntax: Some(UserSyntaxTheme {
+                        highlights: vec![
+                            (
+                                "attribute".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xfabd2eff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "comment".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x928374ff).into()),
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "emphasis".into(),
+                                UserHighlightStyle {
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "emphasis.strong".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xfe7f18ff).into()),
+                                    font_weight: Some(UserFontWeight(700.0)),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "function".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xfabd2eff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "keyword".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xfb4833ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "label".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xfabd2eff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "link_text".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xd3869bff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "link_uri".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xd3869bff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "operator".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x8ec07cff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "property".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x679d6aff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "punctuation".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xa89984ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xb8bb25ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string.escape".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xfb4833ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "tag".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x8ec07cff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "text.literal".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xb8bb25ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "title".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xfabd2eff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "type".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xfabd2eff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x83a598ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                        ],
+                    }),
                 },
             },
             UserTheme {
@@ -99,9 +407,17 @@ pub fn gruvbox() -> UserThemeFamily {
                         border_disabled: Some(rgba(0x3c3836ff).into()),
                         background: Some(rgba(0x32302fff).into()),
                         element_background: Some(rgba(0x44858780).into()),
+                        element_hover: Some(rgba(0x3c383680).into()),
+                        element_selected: Some(rgba(0x3c383680).into()),
+                        drop_target_background: Some(rgba(0x3c3836ff).into()),
+                        ghost_element_hover: Some(rgba(0x3c383680).into()),
                         text: Some(rgba(0xebdbb2ff).into()),
                         tab_inactive_background: Some(rgba(0x32302fff).into()),
                         tab_active_background: Some(rgba(0x504945ff).into()),
+                        editor_background: Some(rgba(0x32302fff).into()),
+                        editor_gutter_background: Some(rgba(0x32302fff).into()),
+                        editor_line_number: Some(rgba(0x665c54ff).into()),
+                        editor_active_line_number: Some(rgba(0xebdbb2ff).into()),
                         terminal_background: Some(rgba(0x32302fff).into()),
                         terminal_ansi_bright_black: Some(rgba(0x928374ff).into()),
                         terminal_ansi_bright_red: Some(rgba(0xfb4833ff).into()),
@@ -121,6 +437,151 @@ pub fn gruvbox() -> UserThemeFamily {
                         terminal_ansi_white: Some(rgba(0xa89984ff).into()),
                         ..Default::default()
                     },
+                    status: StatusColorsRefinement {
+                        deleted: Some(rgba(0xfb4833ff).into()),
+                        error: Some(rgba(0xfb4833ff).into()),
+                        hidden: Some(rgba(0xa89984ff).into()),
+                        ..Default::default()
+                    },
+                    syntax: Some(UserSyntaxTheme {
+                        highlights: vec![
+                            (
+                                "attribute".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xfabd2eff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "comment".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x928374ff).into()),
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "emphasis".into(),
+                                UserHighlightStyle {
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "emphasis.strong".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xfe7f18ff).into()),
+                                    font_weight: Some(UserFontWeight(700.0)),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "function".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xfabd2eff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "keyword".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xfb4833ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "label".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xfabd2eff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "link_text".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xd3869bff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "link_uri".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xd3869bff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "operator".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x8ec07cff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "property".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x679d6aff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "punctuation".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xa89984ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xb8bb25ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string.escape".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xfb4833ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "tag".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x8ec07cff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "text.literal".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xb8bb25ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "title".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xfabd2eff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "type".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xfabd2eff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x83a598ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                        ],
+                    }),
                 },
             },
             UserTheme {
@@ -136,9 +597,17 @@ pub fn gruvbox() -> UserThemeFamily {
                         border_disabled: Some(rgba(0xebdbb2ff).into()),
                         background: Some(rgba(0xf9f5d7ff).into()),
                         element_background: Some(rgba(0x44858780).into()),
+                        element_hover: Some(rgba(0xebdbb280).into()),
+                        element_selected: Some(rgba(0xebdbb280).into()),
+                        drop_target_background: Some(rgba(0xebdbb2ff).into()),
+                        ghost_element_hover: Some(rgba(0xebdbb280).into()),
                         text: Some(rgba(0x3c3836ff).into()),
                         tab_inactive_background: Some(rgba(0xf9f5d7ff).into()),
                         tab_active_background: Some(rgba(0xf2e5bcff).into()),
+                        editor_background: Some(rgba(0xf9f5d7ff).into()),
+                        editor_gutter_background: Some(rgba(0xf9f5d7ff).into()),
+                        editor_line_number: Some(rgba(0xbdae93ff).into()),
+                        editor_active_line_number: Some(rgba(0x3c3836ff).into()),
                         terminal_background: Some(rgba(0xf9f5d7ff).into()),
                         terminal_ansi_bright_black: Some(rgba(0x928374ff).into()),
                         terminal_ansi_bright_red: Some(rgba(0x9d0006ff).into()),
@@ -158,6 +627,151 @@ pub fn gruvbox() -> UserThemeFamily {
                         terminal_ansi_white: Some(rgba(0x7c6f64ff).into()),
                         ..Default::default()
                     },
+                    status: StatusColorsRefinement {
+                        deleted: Some(rgba(0x9d0006ff).into()),
+                        error: Some(rgba(0x9d0006ff).into()),
+                        hidden: Some(rgba(0x7c6f64ff).into()),
+                        ..Default::default()
+                    },
+                    syntax: Some(UserSyntaxTheme {
+                        highlights: vec![
+                            (
+                                "attribute".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xb57613ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "comment".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x928374ff).into()),
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "emphasis".into(),
+                                UserHighlightStyle {
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "emphasis.strong".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xaf3a02ff).into()),
+                                    font_weight: Some(UserFontWeight(700.0)),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "function".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xb57613ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "keyword".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x9d0006ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "label".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xb57613ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "link_text".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x8f3e71ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "link_uri".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x8f3e71ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "operator".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x427b58ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "property".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x679d6aff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "punctuation".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x7c6f64ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x79740eff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string.escape".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x9d0006ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "tag".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x427b58ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "text.literal".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x79740eff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "title".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xb57613ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "type".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xb57613ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x066578ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                        ],
+                    }),
                 },
             },
             UserTheme {
@@ -173,9 +787,17 @@ pub fn gruvbox() -> UserThemeFamily {
                         border_disabled: Some(rgba(0xebdbb2ff).into()),
                         background: Some(rgba(0xfbf1c7ff).into()),
                         element_background: Some(rgba(0x44858780).into()),
+                        element_hover: Some(rgba(0xebdbb280).into()),
+                        element_selected: Some(rgba(0xebdbb280).into()),
+                        drop_target_background: Some(rgba(0xebdbb2ff).into()),
+                        ghost_element_hover: Some(rgba(0xebdbb280).into()),
                         text: Some(rgba(0x3c3836ff).into()),
                         tab_inactive_background: Some(rgba(0xfbf1c7ff).into()),
                         tab_active_background: Some(rgba(0xebdbb2ff).into()),
+                        editor_background: Some(rgba(0xfbf1c7ff).into()),
+                        editor_gutter_background: Some(rgba(0xfbf1c7ff).into()),
+                        editor_line_number: Some(rgba(0xbdae93ff).into()),
+                        editor_active_line_number: Some(rgba(0x3c3836ff).into()),
                         terminal_background: Some(rgba(0xfbf1c7ff).into()),
                         terminal_ansi_bright_black: Some(rgba(0x928374ff).into()),
                         terminal_ansi_bright_red: Some(rgba(0x9d0006ff).into()),
@@ -195,6 +817,151 @@ pub fn gruvbox() -> UserThemeFamily {
                         terminal_ansi_white: Some(rgba(0x7c6f64ff).into()),
                         ..Default::default()
                     },
+                    status: StatusColorsRefinement {
+                        deleted: Some(rgba(0x9d0006ff).into()),
+                        error: Some(rgba(0x9d0006ff).into()),
+                        hidden: Some(rgba(0x7c6f64ff).into()),
+                        ..Default::default()
+                    },
+                    syntax: Some(UserSyntaxTheme {
+                        highlights: vec![
+                            (
+                                "attribute".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xb57613ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "comment".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x928374ff).into()),
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "emphasis".into(),
+                                UserHighlightStyle {
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "emphasis.strong".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xaf3a02ff).into()),
+                                    font_weight: Some(UserFontWeight(700.0)),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "function".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xb57613ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "keyword".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x9d0006ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "label".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xb57613ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "link_text".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x8f3e71ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "link_uri".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x8f3e71ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "operator".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x427b58ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "property".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x679d6aff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "punctuation".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x7c6f64ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x79740eff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string.escape".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x9d0006ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "tag".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x427b58ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "text.literal".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x79740eff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "title".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xb57613ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "type".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xb57613ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x066578ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                        ],
+                    }),
                 },
             },
             UserTheme {
@@ -210,9 +977,17 @@ pub fn gruvbox() -> UserThemeFamily {
                         border_disabled: Some(rgba(0xebdbb2ff).into()),
                         background: Some(rgba(0xf2e5bcff).into()),
                         element_background: Some(rgba(0x44858780).into()),
+                        element_hover: Some(rgba(0xebdbb280).into()),
+                        element_selected: Some(rgba(0xebdbb280).into()),
+                        drop_target_background: Some(rgba(0xebdbb2ff).into()),
+                        ghost_element_hover: Some(rgba(0xebdbb280).into()),
                         text: Some(rgba(0x3c3836ff).into()),
                         tab_inactive_background: Some(rgba(0xf2e5bcff).into()),
                         tab_active_background: Some(rgba(0xd5c4a1ff).into()),
+                        editor_background: Some(rgba(0xf2e5bcff).into()),
+                        editor_gutter_background: Some(rgba(0xf2e5bcff).into()),
+                        editor_line_number: Some(rgba(0xbdae93ff).into()),
+                        editor_active_line_number: Some(rgba(0x3c3836ff).into()),
                         terminal_background: Some(rgba(0xf2e5bcff).into()),
                         terminal_ansi_bright_black: Some(rgba(0x928374ff).into()),
                         terminal_ansi_bright_red: Some(rgba(0x9d0006ff).into()),
@@ -232,6 +1007,151 @@ pub fn gruvbox() -> UserThemeFamily {
                         terminal_ansi_white: Some(rgba(0x7c6f64ff).into()),
                         ..Default::default()
                     },
+                    status: StatusColorsRefinement {
+                        deleted: Some(rgba(0x9d0006ff).into()),
+                        error: Some(rgba(0x9d0006ff).into()),
+                        hidden: Some(rgba(0x7c6f64ff).into()),
+                        ..Default::default()
+                    },
+                    syntax: Some(UserSyntaxTheme {
+                        highlights: vec![
+                            (
+                                "attribute".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xb57613ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "comment".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x928374ff).into()),
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "emphasis".into(),
+                                UserHighlightStyle {
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "emphasis.strong".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xaf3a02ff).into()),
+                                    font_weight: Some(UserFontWeight(700.0)),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "function".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xb57613ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "keyword".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x9d0006ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "label".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xb57613ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "link_text".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x8f3e71ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "link_uri".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x8f3e71ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "operator".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x427b58ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "property".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x679d6aff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "punctuation".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x7c6f64ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x79740eff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string.escape".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x9d0006ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "tag".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x427b58ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "text.literal".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x79740eff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "title".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xb57613ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "type".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xb57613ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x066578ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                        ],
+                    }),
                 },
             },
         ],

crates/theme2/src/themes/mod.rs πŸ”—

@@ -6,8 +6,8 @@ mod ayu;
 mod dracula;
 mod gruvbox;
 mod night_owl;
+mod noctis;
 mod nord;
-mod notctis;
 mod palenight;
 mod rose_pine;
 mod solarized;
@@ -18,8 +18,8 @@ pub use ayu::*;
 pub use dracula::*;
 pub use gruvbox::*;
 pub use night_owl::*;
+pub use noctis::*;
 pub use nord::*;
-pub use notctis::*;
 pub use palenight::*;
 pub use rose_pine::*;
 pub use solarized::*;
@@ -37,7 +37,7 @@ pub(crate) fn all_user_themes() -> Vec<UserThemeFamily> {
         dracula(),
         solarized(),
         nord(),
-        notctis(),
+        noctis(),
         ayu(),
         gruvbox(),
     ]

crates/theme2/src/themes/night_owl.rs πŸ”—

@@ -3,8 +3,10 @@
 
 use gpui::rgba;
 
+#[allow(unused)]
 use crate::{
-    Appearance, ThemeColorsRefinement, UserTheme, UserThemeFamily, UserThemeStylesRefinement,
+    Appearance, StatusColorsRefinement, ThemeColorsRefinement, UserFontStyle, UserFontWeight,
+    UserHighlightStyle, UserSyntaxTheme, UserTheme, UserThemeFamily, UserThemeStylesRefinement,
 };
 
 pub fn night_owl() -> UserThemeFamily {
@@ -19,7 +21,7 @@ pub fn night_owl() -> UserThemeFamily {
                     colors: ThemeColorsRefinement {
                         border: Some(rgba(0x5f7e97ff).into()),
                         border_variant: Some(rgba(0x5f7e97ff).into()),
-                        border_focused: Some(rgba(0x5f7e97ff).into()),
+                        border_focused: Some(rgba(0x122d42ff).into()),
                         border_selected: Some(rgba(0x5f7e97ff).into()),
                         border_transparent: Some(rgba(0x5f7e97ff).into()),
                         border_disabled: Some(rgba(0x5f7e97ff).into()),
@@ -27,9 +29,17 @@ pub fn night_owl() -> UserThemeFamily {
                         surface_background: Some(rgba(0x011526ff).into()),
                         background: Some(rgba(0x011526ff).into()),
                         element_background: Some(rgba(0x7d56c1cc).into()),
+                        element_hover: Some(rgba(0x011526ff).into()),
+                        element_selected: Some(rgba(0x234c708c).into()),
+                        drop_target_background: Some(rgba(0x011526ff).into()),
+                        ghost_element_hover: Some(rgba(0x011526ff).into()),
                         text: Some(rgba(0xd6deebff).into()),
                         tab_inactive_background: Some(rgba(0x01101cff).into()),
                         tab_active_background: Some(rgba(0x0a2842ff).into()),
+                        editor_background: Some(rgba(0x011526ff).into()),
+                        editor_gutter_background: Some(rgba(0x011526ff).into()),
+                        editor_line_number: Some(rgba(0x4b6479ff).into()),
+                        editor_active_line_number: Some(rgba(0xd6deebff).into()),
                         terminal_ansi_bright_black: Some(rgba(0x575656ff).into()),
                         terminal_ansi_bright_red: Some(rgba(0xef524fff).into()),
                         terminal_ansi_bright_green: Some(rgba(0x21da6eff).into()),
@@ -48,6 +58,140 @@ pub fn night_owl() -> UserThemeFamily {
                         terminal_ansi_white: Some(rgba(0xffffffff).into()),
                         ..Default::default()
                     },
+                    status: StatusColorsRefinement {
+                        deleted: Some(rgba(0xef524fff).into()),
+                        error: Some(rgba(0xef524fff).into()),
+                        hidden: Some(rgba(0x5f7e97ff).into()),
+                        ..Default::default()
+                    },
+                    syntax: Some(UserSyntaxTheme {
+                        highlights: vec![
+                            (
+                                "attribute".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xc5e478ff).into()),
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "boolean".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x82aaffff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "comment".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x637777ff).into()),
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "constant".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x82aaffff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "function".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xc792eaff).into()),
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "keyword".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xc792eaff).into()),
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "number".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xf78b6bff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "operator".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x7fdbcaff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "property".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x7fcac3ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "punctuation".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xc792eaff).into()),
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xecc48dff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string.escape".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x82aaffff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "tag".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xcaece6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "text.literal".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xecc48dff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "type".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xc5e478ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xc5e478ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable.special".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x7fdbcaff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                        ],
+                    }),
                 },
             },
             UserTheme {
@@ -57,7 +201,7 @@ pub fn night_owl() -> UserThemeFamily {
                     colors: ThemeColorsRefinement {
                         border: Some(rgba(0xd9d9d9ff).into()),
                         border_variant: Some(rgba(0xd9d9d9ff).into()),
-                        border_focused: Some(rgba(0xd9d9d9ff).into()),
+                        border_focused: Some(rgba(0x93a1a1ff).into()),
                         border_selected: Some(rgba(0xd9d9d9ff).into()),
                         border_transparent: Some(rgba(0xd9d9d9ff).into()),
                         border_disabled: Some(rgba(0xd9d9d9ff).into()),
@@ -65,9 +209,16 @@ pub fn night_owl() -> UserThemeFamily {
                         surface_background: Some(rgba(0xf0f0f0ff).into()),
                         background: Some(rgba(0xfbfbfbff).into()),
                         element_background: Some(rgba(0x29a298ff).into()),
+                        element_hover: Some(rgba(0xd3e7f8ff).into()),
+                        element_selected: Some(rgba(0xd3e7f8ff).into()),
+                        ghost_element_hover: Some(rgba(0xd3e7f8ff).into()),
                         text: Some(rgba(0x403f53ff).into()),
                         tab_inactive_background: Some(rgba(0xf0f0f0ff).into()),
                         tab_active_background: Some(rgba(0xf6f6f6ff).into()),
+                        editor_background: Some(rgba(0xfbfbfbff).into()),
+                        editor_gutter_background: Some(rgba(0xfbfbfbff).into()),
+                        editor_line_number: Some(rgba(0x90a7b2ff).into()),
+                        editor_active_line_number: Some(rgba(0x403f53ff).into()),
                         terminal_background: Some(rgba(0xf6f6f6ff).into()),
                         terminal_ansi_bright_black: Some(rgba(0x403f53ff).into()),
                         terminal_ansi_bright_red: Some(rgba(0xde3c3aff).into()),
@@ -87,6 +238,141 @@ pub fn night_owl() -> UserThemeFamily {
                         terminal_ansi_white: Some(rgba(0xf0f0f0ff).into()),
                         ..Default::default()
                     },
+                    status: StatusColorsRefinement {
+                        deleted: Some(rgba(0x403f53ff).into()),
+                        error: Some(rgba(0x403f53ff).into()),
+                        hidden: Some(rgba(0x403f53ff).into()),
+                        warning: Some(rgba(0xdaa900ff).into()),
+                        ..Default::default()
+                    },
+                    syntax: Some(UserSyntaxTheme {
+                        highlights: vec![
+                            (
+                                "attribute".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x4876d6ff).into()),
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "boolean".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x4876d6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "comment".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x989fb1ff).into()),
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "constant".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x4876d6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "function".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x994bc3ff).into()),
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "keyword".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x994bc3ff).into()),
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "number".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xaa0881ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "operator".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x0b969bff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "property".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x0b969bff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "punctuation".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x994bc3ff).into()),
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x4876d6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string.escape".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x4876d6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "tag".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x994bc3ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "text.literal".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x4876d6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "type".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x4876d6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x4876d6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable.special".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x0b969bff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                        ],
+                    }),
                 },
             },
         ],

crates/theme2/src/themes/noctis.rs πŸ”—

@@ -0,0 +1,2428 @@
+// This file was generated by the `theme_importer`.
+// Be careful when modifying it by hand.
+
+use gpui::rgba;
+
+#[allow(unused)]
+use crate::{
+    Appearance, StatusColorsRefinement, ThemeColorsRefinement, UserFontStyle, UserFontWeight,
+    UserHighlightStyle, UserSyntaxTheme, UserTheme, UserThemeFamily, UserThemeStylesRefinement,
+};
+
+pub fn noctis() -> UserThemeFamily {
+    UserThemeFamily {
+        name: "Noctis".into(),
+        author: "Liviu Schera (liviuschera)".into(),
+        themes: vec![
+            UserTheme {
+                name: "Noctis Azureus".into(),
+                appearance: Appearance::Dark,
+                styles: UserThemeStylesRefinement {
+                    colors: ThemeColorsRefinement {
+                        border: Some(rgba(0x1579b6ff).into()),
+                        border_variant: Some(rgba(0x1579b6ff).into()),
+                        border_focused: Some(rgba(0x08324eff).into()),
+                        border_selected: Some(rgba(0x1579b6ff).into()),
+                        border_transparent: Some(rgba(0x1579b6ff).into()),
+                        border_disabled: Some(rgba(0x1579b6ff).into()),
+                        elevated_surface_background: Some(rgba(0x051b28ff).into()),
+                        surface_background: Some(rgba(0x051b28ff).into()),
+                        background: Some(rgba(0x07263aff).into()),
+                        element_background: Some(rgba(0x007e99ff).into()),
+                        element_hover: Some(rgba(0x00558a65).into()),
+                        element_selected: Some(rgba(0x0b3f5fff).into()),
+                        drop_target_background: Some(rgba(0x00294dff).into()),
+                        ghost_element_hover: Some(rgba(0x00558a65).into()),
+                        text: Some(rgba(0xbecfdaff).into()),
+                        tab_inactive_background: Some(rgba(0x08324eff).into()),
+                        tab_active_background: Some(rgba(0x07263aff).into()),
+                        editor_background: Some(rgba(0x07263aff).into()),
+                        editor_gutter_background: Some(rgba(0x07263aff).into()),
+                        editor_line_number: Some(rgba(0x4c6b7fff).into()),
+                        editor_active_line_number: Some(rgba(0xbecfdaff).into()),
+                        terminal_background: Some(rgba(0x051b28ff).into()),
+                        terminal_ansi_bright_black: Some(rgba(0x475e6cff).into()),
+                        terminal_ansi_bright_red: Some(rgba(0xe97749ff).into()),
+                        terminal_ansi_bright_green: Some(rgba(0x5febb1ff).into()),
+                        terminal_ansi_bright_yellow: Some(rgba(0xe69532ff).into()),
+                        terminal_ansi_bright_blue: Some(rgba(0x5fb5ebff).into()),
+                        terminal_ansi_bright_magenta: Some(rgba(0xe697b2ff).into()),
+                        terminal_ansi_bright_cyan: Some(rgba(0x5fdaebff).into()),
+                        terminal_ansi_bright_white: Some(rgba(0xbecfdaff).into()),
+                        terminal_ansi_black: Some(rgba(0x28343dff).into()),
+                        terminal_ansi_red: Some(rgba(0xe66432ff).into()),
+                        terminal_ansi_green: Some(rgba(0x49e9a6ff).into()),
+                        terminal_ansi_yellow: Some(rgba(0xe4b781ff).into()),
+                        terminal_ansi_blue: Some(rgba(0x49ace9ff).into()),
+                        terminal_ansi_magenta: Some(rgba(0xdf759aff).into()),
+                        terminal_ansi_cyan: Some(rgba(0x49d5e9ff).into()),
+                        terminal_ansi_white: Some(rgba(0xaec3d0ff).into()),
+                        ..Default::default()
+                    },
+                    status: StatusColorsRefinement {
+                        deleted: Some(rgba(0xe34d1bff).into()),
+                        error: Some(rgba(0xe34d1bff).into()),
+                        hidden: Some(rgba(0x9fb6c6ff).into()),
+                        warning: Some(rgba(0xffa857ff).into()),
+                        ..Default::default()
+                    },
+                    syntax: Some(UserSyntaxTheme {
+                        highlights: vec![
+                            (
+                                "boolean".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x705febff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "comment".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x5888a5ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "constant".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xbecfdaff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "constructor".into(),
+                                UserHighlightStyle {
+                                    font_weight: Some(UserFontWeight(700.0)),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "emphasis".into(),
+                                UserHighlightStyle {
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "function".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x15a2b6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "keyword".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xdf759aff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "label".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x49d5e9ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "link_text".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x15a2b6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "link_uri".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x15a2b6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "number".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x705febff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "operator".into(),
+                                UserHighlightStyle {
+                                    font_weight: Some(UserFontWeight(700.0)),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "property".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x15a2b6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "punctuation".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x5888a5ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "punctuation.delimiter".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xbecfdaff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x49e9a6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string.escape".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xbecfdaff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "tag".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xdf759aff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "text.literal".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x49e9a6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "title".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x49d5e9ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "type".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x49d5e9ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xe4b781ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable.special".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xe66432ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                        ],
+                    }),
+                },
+            },
+            UserTheme {
+                name: "Noctis Bordo".into(),
+                appearance: Appearance::Dark,
+                styles: UserThemeStylesRefinement {
+                    colors: ThemeColorsRefinement {
+                        border: Some(rgba(0x997582ff).into()),
+                        border_variant: Some(rgba(0x997582ff).into()),
+                        border_focused: Some(rgba(0x413036ff).into()),
+                        border_selected: Some(rgba(0x997582ff).into()),
+                        border_transparent: Some(rgba(0x997582ff).into()),
+                        border_disabled: Some(rgba(0x997582ff).into()),
+                        elevated_surface_background: Some(rgba(0x272022ff).into()),
+                        surface_background: Some(rgba(0x272022ff).into()),
+                        background: Some(rgba(0x322a2dff).into()),
+                        element_background: Some(rgba(0x007e99ff).into()),
+                        element_hover: Some(rgba(0x533641ff).into()),
+                        element_selected: Some(rgba(0x5c2e3e99).into()),
+                        drop_target_background: Some(rgba(0x38292eff).into()),
+                        ghost_element_hover: Some(rgba(0x533641ff).into()),
+                        text: Some(rgba(0xcbbec2ff).into()),
+                        tab_inactive_background: Some(rgba(0x413036ff).into()),
+                        tab_active_background: Some(rgba(0x322a2dff).into()),
+                        editor_background: Some(rgba(0x322a2dff).into()),
+                        editor_gutter_background: Some(rgba(0x322a2dff).into()),
+                        editor_line_number: Some(rgba(0x715b63ff).into()),
+                        editor_active_line_number: Some(rgba(0xcbbec2ff).into()),
+                        terminal_background: Some(rgba(0x272022ff).into()),
+                        terminal_ansi_bright_black: Some(rgba(0x69545bff).into()),
+                        terminal_ansi_bright_red: Some(rgba(0xe97749ff).into()),
+                        terminal_ansi_bright_green: Some(rgba(0x5febb1ff).into()),
+                        terminal_ansi_bright_yellow: Some(rgba(0xe69532ff).into()),
+                        terminal_ansi_bright_blue: Some(rgba(0x5fb5ebff).into()),
+                        terminal_ansi_bright_magenta: Some(rgba(0xe697b2ff).into()),
+                        terminal_ansi_bright_cyan: Some(rgba(0x5fdaebff).into()),
+                        terminal_ansi_bright_white: Some(rgba(0xcbbec2ff).into()),
+                        terminal_ansi_black: Some(rgba(0x47393eff).into()),
+                        terminal_ansi_red: Some(rgba(0xe66432ff).into()),
+                        terminal_ansi_green: Some(rgba(0x49e9a6ff).into()),
+                        terminal_ansi_yellow: Some(rgba(0xe4b781ff).into()),
+                        terminal_ansi_blue: Some(rgba(0x49ace9ff).into()),
+                        terminal_ansi_magenta: Some(rgba(0xdf759aff).into()),
+                        terminal_ansi_cyan: Some(rgba(0x49d5e9ff).into()),
+                        terminal_ansi_white: Some(rgba(0xb9acb0ff).into()),
+                        ..Default::default()
+                    },
+                    status: StatusColorsRefinement {
+                        deleted: Some(rgba(0xe34d1bff).into()),
+                        error: Some(rgba(0xe34d1bff).into()),
+                        hidden: Some(rgba(0xbbaab0ff).into()),
+                        warning: Some(rgba(0xffa857ff).into()),
+                        ..Default::default()
+                    },
+                    syntax: Some(UserSyntaxTheme {
+                        highlights: vec![
+                            (
+                                "boolean".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x705febff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "comment".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x8b737bff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "constant".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xcbbec2ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "constructor".into(),
+                                UserHighlightStyle {
+                                    font_weight: Some(UserFontWeight(700.0)),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "emphasis".into(),
+                                UserHighlightStyle {
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "function".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x15a2b6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "keyword".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xdf759aff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "label".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x49d5e9ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "link_text".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x15a2b6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "link_uri".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x15a2b6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "number".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x705febff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "operator".into(),
+                                UserHighlightStyle {
+                                    font_weight: Some(UserFontWeight(700.0)),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "property".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x15a2b6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "punctuation".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x8b737bff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "punctuation.delimiter".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xcbbec2ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x49e9a6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string.escape".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xcbbec2ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "tag".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xdf759aff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "text.literal".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x49e9a6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "title".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x49d5e9ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "type".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x49d5e9ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xe4b781ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable.special".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xe66432ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                        ],
+                    }),
+                },
+            },
+            UserTheme {
+                name: "Noctus Hibernus".into(),
+                appearance: Appearance::Light,
+                styles: UserThemeStylesRefinement {
+                    colors: ThemeColorsRefinement {
+                        border: Some(rgba(0x00c6e0ff).into()),
+                        border_variant: Some(rgba(0x00c6e0ff).into()),
+                        border_focused: Some(rgba(0xe0eff1ff).into()),
+                        border_selected: Some(rgba(0x00c6e0ff).into()),
+                        border_transparent: Some(rgba(0x00c6e0ff).into()),
+                        border_disabled: Some(rgba(0x00c6e0ff).into()),
+                        elevated_surface_background: Some(rgba(0xe1eeefff).into()),
+                        surface_background: Some(rgba(0xe1eeefff).into()),
+                        background: Some(rgba(0xf4f6f6ff).into()),
+                        element_background: Some(rgba(0x089099ff).into()),
+                        element_hover: Some(rgba(0xd1eafaff).into()),
+                        element_selected: Some(rgba(0xb6e1e7ff).into()),
+                        drop_target_background: Some(rgba(0xb1c9ccff).into()),
+                        ghost_element_hover: Some(rgba(0xd1eafaff).into()),
+                        text: Some(rgba(0x005661ff).into()),
+                        tab_inactive_background: Some(rgba(0xcaedf2ff).into()),
+                        tab_active_background: Some(rgba(0xf4f6f6ff).into()),
+                        editor_background: Some(rgba(0xf4f6f6ff).into()),
+                        editor_gutter_background: Some(rgba(0xf4f6f6ff).into()),
+                        editor_line_number: Some(rgba(0xa0abacff).into()),
+                        editor_active_line_number: Some(rgba(0x005661ff).into()),
+                        terminal_background: Some(rgba(0xe1eeefff).into()),
+                        terminal_ansi_bright_black: Some(rgba(0x004d57ff).into()),
+                        terminal_ansi_bright_red: Some(rgba(0xff3f00ff).into()),
+                        terminal_ansi_bright_green: Some(rgba(0x00d17aff).into()),
+                        terminal_ansi_bright_yellow: Some(rgba(0xff8c00ff).into()),
+                        terminal_ansi_bright_blue: Some(rgba(0x0ea3ffff).into()),
+                        terminal_ansi_bright_magenta: Some(rgba(0xff6b9eff).into()),
+                        terminal_ansi_bright_cyan: Some(rgba(0x00cae6ff).into()),
+                        terminal_ansi_bright_white: Some(rgba(0xbbc3c4ff).into()),
+                        terminal_ansi_black: Some(rgba(0x003b41ff).into()),
+                        terminal_ansi_red: Some(rgba(0xe34d1bff).into()),
+                        terminal_ansi_green: Some(rgba(0x00b368ff).into()),
+                        terminal_ansi_yellow: Some(rgba(0xf49724ff).into()),
+                        terminal_ansi_blue: Some(rgba(0x0094f0ff).into()),
+                        terminal_ansi_magenta: Some(rgba(0xff5792ff).into()),
+                        terminal_ansi_cyan: Some(rgba(0x00bdd6ff).into()),
+                        terminal_ansi_white: Some(rgba(0x8ca6a6ff).into()),
+                        ..Default::default()
+                    },
+                    status: StatusColorsRefinement {
+                        deleted: Some(rgba(0xff3f00ff).into()),
+                        error: Some(rgba(0xff3f00ff).into()),
+                        hidden: Some(rgba(0x70838dff).into()),
+                        warning: Some(rgba(0xe07a52ff).into()),
+                        ..Default::default()
+                    },
+                    syntax: Some(UserSyntaxTheme {
+                        highlights: vec![
+                            (
+                                "boolean".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x5841ffff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "comment".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x8ca6a6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "constant".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x004d57ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "constructor".into(),
+                                UserHighlightStyle {
+                                    font_weight: Some(UserFontWeight(700.0)),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "emphasis".into(),
+                                UserHighlightStyle {
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "function".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x0094a8ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "keyword".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xff5792ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "label".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x00bdd6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "link_text".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x0094a8ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "link_uri".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x0094a8ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "number".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x5841ffff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "operator".into(),
+                                UserHighlightStyle {
+                                    font_weight: Some(UserFontWeight(700.0)),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "property".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x0094a8ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "punctuation".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x8ca6a6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "punctuation.delimiter".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x004d57ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x00b368ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string.escape".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x004d57ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "tag".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xff5792ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "text.literal".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x00b368ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "title".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x00bdd6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "type".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x00bdd6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xfa8900ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable.special".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xe64100ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                        ],
+                    }),
+                },
+            },
+            UserTheme {
+                name: "Noctis Lilac".into(),
+                appearance: Appearance::Dark,
+                styles: UserThemeStylesRefinement {
+                    colors: ThemeColorsRefinement {
+                        border: Some(rgba(0xaea4f4ff).into()),
+                        border_variant: Some(rgba(0xaea4f4ff).into()),
+                        border_focused: Some(rgba(0xdedbf5ff).into()),
+                        border_selected: Some(rgba(0xaea4f4ff).into()),
+                        border_transparent: Some(rgba(0xaea4f4ff).into()),
+                        border_disabled: Some(rgba(0xaea4f4ff).into()),
+                        elevated_surface_background: Some(rgba(0xe9e7f3ff).into()),
+                        surface_background: Some(rgba(0xe9e7f3ff).into()),
+                        background: Some(rgba(0xf2f1f8ff).into()),
+                        element_background: Some(rgba(0x8d7ffeff).into()),
+                        element_hover: Some(rgba(0xd1cbfeff).into()),
+                        element_selected: Some(rgba(0xbcb6e7ff).into()),
+                        drop_target_background: Some(rgba(0xafaad4aa).into()),
+                        ghost_element_hover: Some(rgba(0xd1cbfeff).into()),
+                        text: Some(rgba(0x0c006bff).into()),
+                        tab_inactive_background: Some(rgba(0xe2dff6ff).into()),
+                        tab_active_background: Some(rgba(0xf2f1f8ff).into()),
+                        editor_background: Some(rgba(0xf2f1f8ff).into()),
+                        editor_gutter_background: Some(rgba(0xf2f1f8ff).into()),
+                        editor_line_number: Some(rgba(0x9c99b0ff).into()),
+                        editor_active_line_number: Some(rgba(0x0c006bff).into()),
+                        terminal_background: Some(rgba(0xe9e7f3ff).into()),
+                        terminal_ansi_bright_black: Some(rgba(0x0f0080ff).into()),
+                        terminal_ansi_bright_red: Some(rgba(0xff3f00ff).into()),
+                        terminal_ansi_bright_green: Some(rgba(0x00d17aff).into()),
+                        terminal_ansi_bright_yellow: Some(rgba(0xff8c00ff).into()),
+                        terminal_ansi_bright_blue: Some(rgba(0x0ea3ffff).into()),
+                        terminal_ansi_bright_magenta: Some(rgba(0xff6b9eff).into()),
+                        terminal_ansi_bright_cyan: Some(rgba(0x00cae6ff).into()),
+                        terminal_ansi_bright_white: Some(rgba(0xbbc3c4ff).into()),
+                        terminal_ansi_black: Some(rgba(0x0c006bff).into()),
+                        terminal_ansi_red: Some(rgba(0xe34d1bff).into()),
+                        terminal_ansi_green: Some(rgba(0x00b368ff).into()),
+                        terminal_ansi_yellow: Some(rgba(0xf49724ff).into()),
+                        terminal_ansi_blue: Some(rgba(0x0094f0ff).into()),
+                        terminal_ansi_magenta: Some(rgba(0xff5792ff).into()),
+                        terminal_ansi_cyan: Some(rgba(0x00bdd6ff).into()),
+                        terminal_ansi_white: Some(rgba(0x8ca6a6ff).into()),
+                        ..Default::default()
+                    },
+                    status: StatusColorsRefinement {
+                        deleted: Some(rgba(0xff3f00ff).into()),
+                        error: Some(rgba(0xff3f00ff).into()),
+                        hidden: Some(rgba(0x74708dff).into()),
+                        warning: Some(rgba(0xe07a52ff).into()),
+                        ..Default::default()
+                    },
+                    syntax: Some(UserSyntaxTheme {
+                        highlights: vec![
+                            (
+                                "boolean".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x5841ffff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "comment".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x9995b7ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "constant".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x0c006bff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "constructor".into(),
+                                UserHighlightStyle {
+                                    font_weight: Some(UserFontWeight(700.0)),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "emphasis".into(),
+                                UserHighlightStyle {
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "function".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x0094a8ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "keyword".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xff5792ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "label".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x00bdd6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "link_text".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x0094a8ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "link_uri".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x0094a8ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "number".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x5841ffff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "operator".into(),
+                                UserHighlightStyle {
+                                    font_weight: Some(UserFontWeight(700.0)),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "property".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x0094a8ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "punctuation".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x9995b7ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "punctuation.delimiter".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x0c006bff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x00b368ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string.escape".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x0c006bff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "tag".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xff5792ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "text.literal".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x00b368ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "title".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x00bdd6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "type".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x00bdd6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xfa8900ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable.special".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xe64100ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                        ],
+                    }),
+                },
+            },
+            UserTheme {
+                name: "Noctis Lux".into(),
+                appearance: Appearance::Light,
+                styles: UserThemeStylesRefinement {
+                    colors: ThemeColorsRefinement {
+                        border: Some(rgba(0x00c6e0ff).into()),
+                        border_variant: Some(rgba(0x00c6e0ff).into()),
+                        border_focused: Some(rgba(0xf2eddeff).into()),
+                        border_selected: Some(rgba(0x00c6e0ff).into()),
+                        border_transparent: Some(rgba(0x00c6e0ff).into()),
+                        border_disabled: Some(rgba(0x00c6e0ff).into()),
+                        elevated_surface_background: Some(rgba(0xf6eddaff).into()),
+                        surface_background: Some(rgba(0xf6eddaff).into()),
+                        background: Some(rgba(0xfef8ecff).into()),
+                        element_background: Some(rgba(0x089099ff).into()),
+                        element_hover: Some(rgba(0xd1f2f8ff).into()),
+                        element_selected: Some(rgba(0xb6e1e7ff).into()),
+                        drop_target_background: Some(rgba(0xcccab1ff).into()),
+                        ghost_element_hover: Some(rgba(0xd1f2f8ff).into()),
+                        text: Some(rgba(0x005661ff).into()),
+                        tab_inactive_background: Some(rgba(0xf0e9d6ff).into()),
+                        tab_active_background: Some(rgba(0xfef8ecff).into()),
+                        editor_background: Some(rgba(0xfef8ecff).into()),
+                        editor_gutter_background: Some(rgba(0xfef8ecff).into()),
+                        editor_line_number: Some(rgba(0xa0abacff).into()),
+                        editor_active_line_number: Some(rgba(0x005661ff).into()),
+                        terminal_background: Some(rgba(0xf6eddaff).into()),
+                        terminal_ansi_bright_black: Some(rgba(0x004d57ff).into()),
+                        terminal_ansi_bright_red: Some(rgba(0xff3f00ff).into()),
+                        terminal_ansi_bright_green: Some(rgba(0x00d17aff).into()),
+                        terminal_ansi_bright_yellow: Some(rgba(0xff8c00ff).into()),
+                        terminal_ansi_bright_blue: Some(rgba(0x0ea3ffff).into()),
+                        terminal_ansi_bright_magenta: Some(rgba(0xff6b9eff).into()),
+                        terminal_ansi_bright_cyan: Some(rgba(0x00cae6ff).into()),
+                        terminal_ansi_bright_white: Some(rgba(0xbbc3c4ff).into()),
+                        terminal_ansi_black: Some(rgba(0x003b41ff).into()),
+                        terminal_ansi_red: Some(rgba(0xe34d1bff).into()),
+                        terminal_ansi_green: Some(rgba(0x00b368ff).into()),
+                        terminal_ansi_yellow: Some(rgba(0xf49724ff).into()),
+                        terminal_ansi_blue: Some(rgba(0x0094f0ff).into()),
+                        terminal_ansi_magenta: Some(rgba(0xff5792ff).into()),
+                        terminal_ansi_cyan: Some(rgba(0x00bdd6ff).into()),
+                        terminal_ansi_white: Some(rgba(0x8ca6a6ff).into()),
+                        ..Default::default()
+                    },
+                    status: StatusColorsRefinement {
+                        deleted: Some(rgba(0xff3f00ff).into()),
+                        error: Some(rgba(0xff3f00ff).into()),
+                        hidden: Some(rgba(0x878476ff).into()),
+                        warning: Some(rgba(0xe07a52ff).into()),
+                        ..Default::default()
+                    },
+                    syntax: Some(UserSyntaxTheme {
+                        highlights: vec![
+                            (
+                                "boolean".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x5841ffff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "comment".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x8ca6a6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "constant".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x004d57ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "constructor".into(),
+                                UserHighlightStyle {
+                                    font_weight: Some(UserFontWeight(700.0)),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "emphasis".into(),
+                                UserHighlightStyle {
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "function".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x0094a8ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "keyword".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xff5792ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "label".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x00bdd6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "link_text".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x0094a8ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "link_uri".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x0094a8ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "number".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x5841ffff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "operator".into(),
+                                UserHighlightStyle {
+                                    font_weight: Some(UserFontWeight(700.0)),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "property".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x0094a8ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "punctuation".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x8ca6a6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "punctuation.delimiter".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x004d57ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x00b368ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string.escape".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x004d57ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "tag".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xff5792ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "text.literal".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x00b368ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "title".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x00bdd6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "type".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x00bdd6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xfa8900ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable.special".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xe64100ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                        ],
+                    }),
+                },
+            },
+            UserTheme {
+                name: "Noctis Minimus".into(),
+                appearance: Appearance::Dark,
+                styles: UserThemeStylesRefinement {
+                    colors: ThemeColorsRefinement {
+                        border: Some(rgba(0x496c83ff).into()),
+                        border_variant: Some(rgba(0x496c83ff).into()),
+                        border_focused: Some(rgba(0x202d37ff).into()),
+                        border_selected: Some(rgba(0x496c83ff).into()),
+                        border_transparent: Some(rgba(0x496c83ff).into()),
+                        border_disabled: Some(rgba(0x496c83ff).into()),
+                        elevated_surface_background: Some(rgba(0x0e1920ff).into()),
+                        surface_background: Some(rgba(0x0e1920ff).into()),
+                        background: Some(rgba(0x1b2932ff).into()),
+                        element_background: Some(rgba(0x2e616bff).into()),
+                        element_hover: Some(rgba(0x00558aff).into()),
+                        element_selected: Some(rgba(0x2c414eff).into()),
+                        drop_target_background: Some(rgba(0x152836ff).into()),
+                        ghost_element_hover: Some(rgba(0x00558aff).into()),
+                        text: Some(rgba(0xc5cdd3ff).into()),
+                        tab_inactive_background: Some(rgba(0x202d37ff).into()),
+                        tab_active_background: Some(rgba(0x1b2932ff).into()),
+                        editor_background: Some(rgba(0x1b2932ff).into()),
+                        editor_gutter_background: Some(rgba(0x1b2932ff).into()),
+                        editor_line_number: Some(rgba(0x5d6e79ff).into()),
+                        editor_active_line_number: Some(rgba(0xc5cdd3ff).into()),
+                        terminal_background: Some(rgba(0x0e1920ff).into()),
+                        terminal_ansi_bright_black: Some(rgba(0x425866ff).into()),
+                        terminal_ansi_bright_red: Some(rgba(0xca8468ff).into()),
+                        terminal_ansi_bright_green: Some(rgba(0x84c8abff).into()),
+                        terminal_ansi_bright_yellow: Some(rgba(0xd1aa7bff).into()),
+                        terminal_ansi_bright_blue: Some(rgba(0x68a4caff).into()),
+                        terminal_ansi_bright_magenta: Some(rgba(0xc88da2ff).into()),
+                        terminal_ansi_bright_cyan: Some(rgba(0x84bfc8ff).into()),
+                        terminal_ansi_bright_white: Some(rgba(0xc5d1d3ff).into()),
+                        terminal_ansi_black: Some(rgba(0x182935ff).into()),
+                        terminal_ansi_red: Some(rgba(0xc08872ff).into()),
+                        terminal_ansi_green: Some(rgba(0x72c09fff).into()),
+                        terminal_ansi_yellow: Some(rgba(0xc8a984ff).into()),
+                        terminal_ansi_blue: Some(rgba(0x6095b7ff).into()),
+                        terminal_ansi_magenta: Some(rgba(0xc28097ff).into()),
+                        terminal_ansi_cyan: Some(rgba(0x72b7c0ff).into()),
+                        terminal_ansi_white: Some(rgba(0xc5cdd3ff).into()),
+                        ..Default::default()
+                    },
+                    status: StatusColorsRefinement {
+                        deleted: Some(rgba(0xb96245ff).into()),
+                        error: Some(rgba(0xb96245ff).into()),
+                        hidden: Some(rgba(0x96a8b6ff).into()),
+                        warning: Some(rgba(0xffa857ff).into()),
+                        ..Default::default()
+                    },
+                    syntax: Some(UserSyntaxTheme {
+                        highlights: vec![
+                            (
+                                "boolean".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x7067b1ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "comment".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x5d7787ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "constant".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xc5cdd3ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "constructor".into(),
+                                UserHighlightStyle {
+                                    font_weight: Some(UserFontWeight(700.0)),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "emphasis".into(),
+                                UserHighlightStyle {
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "function".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x3e848dff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "keyword".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xc88da2ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "label".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x72b7c0ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "link_text".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x3e848dff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "link_uri".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x3e848dff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "number".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x7067b1ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "operator".into(),
+                                UserHighlightStyle {
+                                    font_weight: Some(UserFontWeight(700.0)),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "property".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x3e848dff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "punctuation".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x5d7787ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "punctuation.delimiter".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xc5cdd3ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x72c09fff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string.escape".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xc5cdd3ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "tag".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xc88da2ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "text.literal".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x72c09fff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "title".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x72b7c0ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "type".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x72b7c0ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xd3b692ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable.special".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xc37455ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                        ],
+                    }),
+                },
+            },
+            UserTheme {
+                name: "Noctis".into(),
+                appearance: Appearance::Dark,
+                styles: UserThemeStylesRefinement {
+                    colors: ThemeColorsRefinement {
+                        border: Some(rgba(0x0d6571ff).into()),
+                        border_variant: Some(rgba(0x0d6571ff).into()),
+                        border_focused: Some(rgba(0x063940ff).into()),
+                        border_selected: Some(rgba(0x0d6571ff).into()),
+                        border_transparent: Some(rgba(0x0d6571ff).into()),
+                        border_disabled: Some(rgba(0x0d6571ff).into()),
+                        elevated_surface_background: Some(rgba(0x03181aff).into()),
+                        surface_background: Some(rgba(0x03181aff).into()),
+                        background: Some(rgba(0x052428ff).into()),
+                        element_background: Some(rgba(0x089099ff).into()),
+                        element_hover: Some(rgba(0x0b505aff).into()),
+                        element_selected: Some(rgba(0x0d6571ff).into()),
+                        drop_target_background: Some(rgba(0x00404dff).into()),
+                        ghost_element_hover: Some(rgba(0x0b505aff).into()),
+                        text: Some(rgba(0xb1c9ccff).into()),
+                        tab_inactive_background: Some(rgba(0x052e32ff).into()),
+                        tab_active_background: Some(rgba(0x052428ff).into()),
+                        editor_background: Some(rgba(0x052428ff).into()),
+                        editor_gutter_background: Some(rgba(0x052428ff).into()),
+                        editor_line_number: Some(rgba(0x4e6b6eff).into()),
+                        editor_active_line_number: Some(rgba(0xb1c9ccff).into()),
+                        terminal_background: Some(rgba(0x03181aff).into()),
+                        terminal_ansi_bright_black: Some(rgba(0x47686cff).into()),
+                        terminal_ansi_bright_red: Some(rgba(0xe97749ff).into()),
+                        terminal_ansi_bright_green: Some(rgba(0x5febb1ff).into()),
+                        terminal_ansi_bright_yellow: Some(rgba(0xe69532ff).into()),
+                        terminal_ansi_bright_blue: Some(rgba(0x5fb5ebff).into()),
+                        terminal_ansi_bright_magenta: Some(rgba(0xe697b2ff).into()),
+                        terminal_ansi_bright_cyan: Some(rgba(0x5fdaebff).into()),
+                        terminal_ansi_bright_white: Some(rgba(0xc1d4d7ff).into()),
+                        terminal_ansi_black: Some(rgba(0x324a4dff).into()),
+                        terminal_ansi_red: Some(rgba(0xe66432ff).into()),
+                        terminal_ansi_green: Some(rgba(0x49e9a6ff).into()),
+                        terminal_ansi_yellow: Some(rgba(0xe4b781ff).into()),
+                        terminal_ansi_blue: Some(rgba(0x49ace9ff).into()),
+                        terminal_ansi_magenta: Some(rgba(0xdf759aff).into()),
+                        terminal_ansi_cyan: Some(rgba(0x49d5e9ff).into()),
+                        terminal_ansi_white: Some(rgba(0xb1c9ccff).into()),
+                        ..Default::default()
+                    },
+                    status: StatusColorsRefinement {
+                        deleted: Some(rgba(0xe34d1bff).into()),
+                        error: Some(rgba(0xe34d1bff).into()),
+                        hidden: Some(rgba(0x87a7abff).into()),
+                        warning: Some(rgba(0xffa487ff).into()),
+                        ..Default::default()
+                    },
+                    syntax: Some(UserSyntaxTheme {
+                        highlights: vec![
+                            (
+                                "boolean".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x705febff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "comment".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x5b858bff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "constant".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xb1c9ccff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "constructor".into(),
+                                UserHighlightStyle {
+                                    font_weight: Some(UserFontWeight(700.0)),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "emphasis".into(),
+                                UserHighlightStyle {
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "function".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x15a2b6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "keyword".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xdf759aff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "label".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x49d5e9ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "link_text".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x15a2b6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "link_uri".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x15a2b6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "number".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x705febff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "operator".into(),
+                                UserHighlightStyle {
+                                    font_weight: Some(UserFontWeight(700.0)),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "property".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x15a2b6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "punctuation".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x5b858bff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "punctuation.delimiter".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xb1c9ccff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x49e9a6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string.escape".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xb1c9ccff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "tag".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xdf759aff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "text.literal".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x49e9a6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "title".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x49d5e9ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "type".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x49d5e9ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xe4b781ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable.special".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xe66432ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                        ],
+                    }),
+                },
+            },
+            UserTheme {
+                name: "Noctis Obscuro".into(),
+                appearance: Appearance::Dark,
+                styles: UserThemeStylesRefinement {
+                    colors: ThemeColorsRefinement {
+                        border: Some(rgba(0x0d6571ff).into()),
+                        border_variant: Some(rgba(0x0d6571ff).into()),
+                        border_focused: Some(rgba(0x052e32ff).into()),
+                        border_selected: Some(rgba(0x0d6571ff).into()),
+                        border_transparent: Some(rgba(0x0d6571ff).into()),
+                        border_disabled: Some(rgba(0x0d6571ff).into()),
+                        elevated_surface_background: Some(rgba(0x020c0eff).into()),
+                        surface_background: Some(rgba(0x020c0eff).into()),
+                        background: Some(rgba(0x031316ff).into()),
+                        element_background: Some(rgba(0x089099ff).into()),
+                        element_hover: Some(rgba(0x0b505aff).into()),
+                        element_selected: Some(rgba(0x0d6571ff).into()),
+                        drop_target_background: Some(rgba(0x00404dff).into()),
+                        ghost_element_hover: Some(rgba(0x0b505aff).into()),
+                        text: Some(rgba(0xb1c9ccff).into()),
+                        tab_inactive_background: Some(rgba(0x052e32ff).into()),
+                        tab_active_background: Some(rgba(0x031316ff).into()),
+                        editor_background: Some(rgba(0x031316ff).into()),
+                        editor_gutter_background: Some(rgba(0x031316ff).into()),
+                        editor_line_number: Some(rgba(0x4e6b6eff).into()),
+                        editor_active_line_number: Some(rgba(0xb1c9ccff).into()),
+                        terminal_background: Some(rgba(0x020c0eff).into()),
+                        terminal_ansi_bright_black: Some(rgba(0x47686cff).into()),
+                        terminal_ansi_bright_red: Some(rgba(0xe97749ff).into()),
+                        terminal_ansi_bright_green: Some(rgba(0x5febb1ff).into()),
+                        terminal_ansi_bright_yellow: Some(rgba(0xe69532ff).into()),
+                        terminal_ansi_bright_blue: Some(rgba(0x5fb5ebff).into()),
+                        terminal_ansi_bright_magenta: Some(rgba(0xe697b2ff).into()),
+                        terminal_ansi_bright_cyan: Some(rgba(0x5fdaebff).into()),
+                        terminal_ansi_bright_white: Some(rgba(0xc1d4d7ff).into()),
+                        terminal_ansi_black: Some(rgba(0x324a4dff).into()),
+                        terminal_ansi_red: Some(rgba(0xe66432ff).into()),
+                        terminal_ansi_green: Some(rgba(0x49e9a6ff).into()),
+                        terminal_ansi_yellow: Some(rgba(0xe4b781ff).into()),
+                        terminal_ansi_blue: Some(rgba(0x49ace9ff).into()),
+                        terminal_ansi_magenta: Some(rgba(0xdf759aff).into()),
+                        terminal_ansi_cyan: Some(rgba(0x49d5e9ff).into()),
+                        terminal_ansi_white: Some(rgba(0xb1c9ccff).into()),
+                        ..Default::default()
+                    },
+                    status: StatusColorsRefinement {
+                        deleted: Some(rgba(0xe34d1bff).into()),
+                        error: Some(rgba(0xe34d1bff).into()),
+                        hidden: Some(rgba(0x87a7abff).into()),
+                        warning: Some(rgba(0xffa487ff).into()),
+                        ..Default::default()
+                    },
+                    syntax: Some(UserSyntaxTheme {
+                        highlights: vec![
+                            (
+                                "boolean".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x705febff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "comment".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x5b858bff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "constant".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xb1c9ccff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "constructor".into(),
+                                UserHighlightStyle {
+                                    font_weight: Some(UserFontWeight(700.0)),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "emphasis".into(),
+                                UserHighlightStyle {
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "function".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x15a2b6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "keyword".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xdf759aff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "label".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x49d5e9ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "link_text".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x15a2b6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "link_uri".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x15a2b6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "number".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x705febff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "operator".into(),
+                                UserHighlightStyle {
+                                    font_weight: Some(UserFontWeight(700.0)),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "property".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x15a2b6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "punctuation".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x5b858bff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "punctuation.delimiter".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xb1c9ccff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x49e9a6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string.escape".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xb1c9ccff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "tag".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xdf759aff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "text.literal".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x49e9a6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "title".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x49d5e9ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "type".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x49d5e9ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xe4b781ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable.special".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xe66432ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                        ],
+                    }),
+                },
+            },
+            UserTheme {
+                name: "Noctis Sereno".into(),
+                appearance: Appearance::Dark,
+                styles: UserThemeStylesRefinement {
+                    colors: ThemeColorsRefinement {
+                        border: Some(rgba(0x0d6571ff).into()),
+                        border_variant: Some(rgba(0x0d6571ff).into()),
+                        border_focused: Some(rgba(0x052e32ff).into()),
+                        border_selected: Some(rgba(0x0d6571ff).into()),
+                        border_transparent: Some(rgba(0x0d6571ff).into()),
+                        border_disabled: Some(rgba(0x0d6571ff).into()),
+                        elevated_surface_background: Some(rgba(0x020c0eff).into()),
+                        surface_background: Some(rgba(0x020c0eff).into()),
+                        background: Some(rgba(0x031316ff).into()),
+                        element_background: Some(rgba(0x089099ff).into()),
+                        element_hover: Some(rgba(0x0b505aff).into()),
+                        element_selected: Some(rgba(0x0d6571ff).into()),
+                        drop_target_background: Some(rgba(0x00404dff).into()),
+                        ghost_element_hover: Some(rgba(0x0b505aff).into()),
+                        text: Some(rgba(0xb1c9ccff).into()),
+                        tab_inactive_background: Some(rgba(0x052e32ff).into()),
+                        tab_active_background: Some(rgba(0x031316ff).into()),
+                        editor_background: Some(rgba(0x031316ff).into()),
+                        editor_gutter_background: Some(rgba(0x031316ff).into()),
+                        editor_line_number: Some(rgba(0x4e6b6eff).into()),
+                        editor_active_line_number: Some(rgba(0xb1c9ccff).into()),
+                        terminal_background: Some(rgba(0x020c0eff).into()),
+                        terminal_ansi_bright_black: Some(rgba(0x47686cff).into()),
+                        terminal_ansi_bright_red: Some(rgba(0xe97749ff).into()),
+                        terminal_ansi_bright_green: Some(rgba(0x5febb1ff).into()),
+                        terminal_ansi_bright_yellow: Some(rgba(0xe69532ff).into()),
+                        terminal_ansi_bright_blue: Some(rgba(0x5fb5ebff).into()),
+                        terminal_ansi_bright_magenta: Some(rgba(0xe697b2ff).into()),
+                        terminal_ansi_bright_cyan: Some(rgba(0x5fdaebff).into()),
+                        terminal_ansi_bright_white: Some(rgba(0xc1d4d7ff).into()),
+                        terminal_ansi_black: Some(rgba(0x324a4dff).into()),
+                        terminal_ansi_red: Some(rgba(0xe66432ff).into()),
+                        terminal_ansi_green: Some(rgba(0x49e9a6ff).into()),
+                        terminal_ansi_yellow: Some(rgba(0xe4b781ff).into()),
+                        terminal_ansi_blue: Some(rgba(0x49ace9ff).into()),
+                        terminal_ansi_magenta: Some(rgba(0xdf759aff).into()),
+                        terminal_ansi_cyan: Some(rgba(0x49d5e9ff).into()),
+                        terminal_ansi_white: Some(rgba(0xb1c9ccff).into()),
+                        ..Default::default()
+                    },
+                    status: StatusColorsRefinement {
+                        deleted: Some(rgba(0xe34d1bff).into()),
+                        error: Some(rgba(0xe34d1bff).into()),
+                        hidden: Some(rgba(0x87a7abff).into()),
+                        warning: Some(rgba(0xffa487ff).into()),
+                        ..Default::default()
+                    },
+                    syntax: Some(UserSyntaxTheme {
+                        highlights: vec![
+                            (
+                                "boolean".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x705febff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "comment".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x5b858bff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "constant".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xb1c9ccff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "constructor".into(),
+                                UserHighlightStyle {
+                                    font_weight: Some(UserFontWeight(700.0)),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "emphasis".into(),
+                                UserHighlightStyle {
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "function".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x15a2b6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "keyword".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xdf759aff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "label".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x49d5e9ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "link_text".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x15a2b6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "link_uri".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x15a2b6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "number".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x705febff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "operator".into(),
+                                UserHighlightStyle {
+                                    font_weight: Some(UserFontWeight(700.0)),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "property".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x15a2b6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "punctuation".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x5b858bff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "punctuation.delimiter".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xb1c9ccff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x49e9a6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string.escape".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xb1c9ccff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "tag".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xdf759aff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "text.literal".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x49e9a6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "title".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x49d5e9ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "type".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x49d5e9ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xe4b781ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable.special".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xe66432ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                        ],
+                    }),
+                },
+            },
+            UserTheme {
+                name: "Noctis Uva".into(),
+                appearance: Appearance::Dark,
+                styles: UserThemeStylesRefinement {
+                    colors: ThemeColorsRefinement {
+                        border: Some(rgba(0x6d66a7ff).into()),
+                        border_variant: Some(rgba(0x6d66a7ff).into()),
+                        border_focused: Some(rgba(0x2f2c49ff).into()),
+                        border_selected: Some(rgba(0x6d66a7ff).into()),
+                        border_transparent: Some(rgba(0x6d66a7ff).into()),
+                        border_disabled: Some(rgba(0x6d66a7ff).into()),
+                        elevated_surface_background: Some(rgba(0x1f1d30ff).into()),
+                        surface_background: Some(rgba(0x1f1d30ff).into()),
+                        background: Some(rgba(0x292640ff).into()),
+                        element_background: Some(rgba(0x007e99ff).into()),
+                        element_hover: Some(rgba(0x383866ff).into()),
+                        element_selected: Some(rgba(0x322e5cff).into()),
+                        drop_target_background: Some(rgba(0x202040ff).into()),
+                        ghost_element_hover: Some(rgba(0x383866ff).into()),
+                        text: Some(rgba(0xc5c2d6ff).into()),
+                        tab_inactive_background: Some(rgba(0x2f2c49ff).into()),
+                        tab_active_background: Some(rgba(0x292640ff).into()),
+                        editor_background: Some(rgba(0x292640ff).into()),
+                        editor_gutter_background: Some(rgba(0x292640ff).into()),
+                        editor_line_number: Some(rgba(0x5c5973ff).into()),
+                        editor_active_line_number: Some(rgba(0xc5c2d6ff).into()),
+                        terminal_background: Some(rgba(0x1f1d30ff).into()),
+                        terminal_ansi_bright_black: Some(rgba(0x504e65ff).into()),
+                        terminal_ansi_bright_red: Some(rgba(0xe97749ff).into()),
+                        terminal_ansi_bright_green: Some(rgba(0x5febb1ff).into()),
+                        terminal_ansi_bright_yellow: Some(rgba(0xe69532ff).into()),
+                        terminal_ansi_bright_blue: Some(rgba(0x5fb5ebff).into()),
+                        terminal_ansi_bright_magenta: Some(rgba(0xe697b2ff).into()),
+                        terminal_ansi_bright_cyan: Some(rgba(0x5fdaebff).into()),
+                        terminal_ansi_bright_white: Some(rgba(0xc5c2d6ff).into()),
+                        terminal_ansi_black: Some(rgba(0x302f3dff).into()),
+                        terminal_ansi_red: Some(rgba(0xe66432ff).into()),
+                        terminal_ansi_green: Some(rgba(0x49e9a6ff).into()),
+                        terminal_ansi_yellow: Some(rgba(0xe4b781ff).into()),
+                        terminal_ansi_blue: Some(rgba(0x49ace9ff).into()),
+                        terminal_ansi_magenta: Some(rgba(0xdf759aff).into()),
+                        terminal_ansi_cyan: Some(rgba(0x49d5e9ff).into()),
+                        terminal_ansi_white: Some(rgba(0xb6b3ccff).into()),
+                        ..Default::default()
+                    },
+                    status: StatusColorsRefinement {
+                        deleted: Some(rgba(0xe34d1bff).into()),
+                        error: Some(rgba(0xe34d1bff).into()),
+                        hidden: Some(rgba(0xa9a5c0ff).into()),
+                        warning: Some(rgba(0xffa857ff).into()),
+                        ..Default::default()
+                    },
+                    syntax: Some(UserSyntaxTheme {
+                        highlights: vec![
+                            (
+                                "boolean".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x705febff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "comment".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x716b93ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "constant".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xc5c2d6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "constructor".into(),
+                                UserHighlightStyle {
+                                    font_weight: Some(UserFontWeight(700.0)),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "emphasis".into(),
+                                UserHighlightStyle {
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "function".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x15a2b6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "keyword".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xdf759aff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "label".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x49d5e9ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "link_text".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x15a2b6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "link_uri".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x15a2b6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "number".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x705febff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "operator".into(),
+                                UserHighlightStyle {
+                                    font_weight: Some(UserFontWeight(700.0)),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "property".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x15a2b6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "punctuation".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x716b93ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "punctuation.delimiter".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xc5c2d6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x49e9a6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string.escape".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xc5c2d6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "tag".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xdf759aff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "text.literal".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x49e9a6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "title".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x49d5e9ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "type".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x49d5e9ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xe4b781ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable.special".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xe66432ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                        ],
+                    }),
+                },
+            },
+            UserTheme {
+                name: "Noctis Viola".into(),
+                appearance: Appearance::Dark,
+                styles: UserThemeStylesRefinement {
+                    colors: ThemeColorsRefinement {
+                        border: Some(rgba(0x8666a7ff).into()),
+                        border_variant: Some(rgba(0x8666a7ff).into()),
+                        border_focused: Some(rgba(0x3d2e4dff).into()),
+                        border_selected: Some(rgba(0x8666a7ff).into()),
+                        border_transparent: Some(rgba(0x8666a7ff).into()),
+                        border_disabled: Some(rgba(0x8666a7ff).into()),
+                        elevated_surface_background: Some(rgba(0x291d35ff).into()),
+                        surface_background: Some(rgba(0x291d35ff).into()),
+                        background: Some(rgba(0x30243dff).into()),
+                        element_background: Some(rgba(0x007e99ff).into()),
+                        element_hover: Some(rgba(0x69438dff).into()),
+                        element_selected: Some(rgba(0x472e60ff).into()),
+                        drop_target_background: Some(rgba(0x302040ff).into()),
+                        ghost_element_hover: Some(rgba(0x69438dff).into()),
+                        text: Some(rgba(0xccbfd9ff).into()),
+                        tab_inactive_background: Some(rgba(0x3d2e4dff).into()),
+                        tab_active_background: Some(rgba(0x30243dff).into()),
+                        editor_background: Some(rgba(0x30243dff).into()),
+                        editor_gutter_background: Some(rgba(0x30243dff).into()),
+                        editor_line_number: Some(rgba(0x665973ff).into()),
+                        editor_active_line_number: Some(rgba(0xccbfd9ff).into()),
+                        terminal_background: Some(rgba(0x291d35ff).into()),
+                        terminal_ansi_bright_black: Some(rgba(0x594e65ff).into()),
+                        terminal_ansi_bright_red: Some(rgba(0xe97749ff).into()),
+                        terminal_ansi_bright_green: Some(rgba(0x5febb1ff).into()),
+                        terminal_ansi_bright_yellow: Some(rgba(0xe69532ff).into()),
+                        terminal_ansi_bright_blue: Some(rgba(0x5fb5ebff).into()),
+                        terminal_ansi_bright_magenta: Some(rgba(0xe697b2ff).into()),
+                        terminal_ansi_bright_cyan: Some(rgba(0x5fdaebff).into()),
+                        terminal_ansi_bright_white: Some(rgba(0xccbfd9ff).into()),
+                        terminal_ansi_black: Some(rgba(0x362f3dff).into()),
+                        terminal_ansi_red: Some(rgba(0xe66432ff).into()),
+                        terminal_ansi_green: Some(rgba(0x49e9a6ff).into()),
+                        terminal_ansi_yellow: Some(rgba(0xe4b781ff).into()),
+                        terminal_ansi_blue: Some(rgba(0x49ace9ff).into()),
+                        terminal_ansi_magenta: Some(rgba(0xdf759aff).into()),
+                        terminal_ansi_cyan: Some(rgba(0x49d5e9ff).into()),
+                        terminal_ansi_white: Some(rgba(0xbfafcfff).into()),
+                        ..Default::default()
+                    },
+                    status: StatusColorsRefinement {
+                        deleted: Some(rgba(0xe34d1bff).into()),
+                        error: Some(rgba(0xe34d1bff).into()),
+                        hidden: Some(rgba(0xb3a5c0ff).into()),
+                        warning: Some(rgba(0xffa857ff).into()),
+                        ..Default::default()
+                    },
+                    syntax: Some(UserSyntaxTheme {
+                        highlights: vec![
+                            (
+                                "boolean".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x705febff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "comment".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x7e6499ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "constant".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xccbfd9ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "constructor".into(),
+                                UserHighlightStyle {
+                                    font_weight: Some(UserFontWeight(700.0)),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "emphasis".into(),
+                                UserHighlightStyle {
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "function".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x15a2b6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "keyword".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xdf759aff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "label".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x49d5e9ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "link_text".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x15a2b6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "link_uri".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x15a2b6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "number".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x705febff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "operator".into(),
+                                UserHighlightStyle {
+                                    font_weight: Some(UserFontWeight(700.0)),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "property".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x15a2b6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "punctuation".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x7e6499ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "punctuation.delimiter".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xccbfd9ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x49e9a6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string.escape".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xccbfd9ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "tag".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xdf759aff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "text.literal".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x49e9a6ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "title".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x49d5e9ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "type".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x49d5e9ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xe4b781ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable.special".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xe66432ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                        ],
+                    }),
+                },
+            },
+        ],
+    }
+}

crates/theme2/src/themes/nord.rs πŸ”—

@@ -3,8 +3,10 @@
 
 use gpui::rgba;
 
+#[allow(unused)]
 use crate::{
-    Appearance, ThemeColorsRefinement, UserTheme, UserThemeFamily, UserThemeStylesRefinement,
+    Appearance, StatusColorsRefinement, ThemeColorsRefinement, UserFontStyle, UserFontWeight,
+    UserHighlightStyle, UserSyntaxTheme, UserTheme, UserThemeFamily, UserThemeStylesRefinement,
 };
 
 pub fn nord() -> UserThemeFamily {
@@ -26,9 +28,17 @@ pub fn nord() -> UserThemeFamily {
                     surface_background: Some(rgba(0x2e3440ff).into()),
                     background: Some(rgba(0x2e3440ff).into()),
                     element_background: Some(rgba(0x88bfd0ee).into()),
+                    element_hover: Some(rgba(0x3b4252ff).into()),
+                    element_selected: Some(rgba(0x88bfd0ff).into()),
+                    drop_target_background: Some(rgba(0x88bfd099).into()),
+                    ghost_element_hover: Some(rgba(0x3b4252ff).into()),
                     text: Some(rgba(0xd8dee9ff).into()),
                     tab_inactive_background: Some(rgba(0x2e3440ff).into()),
                     tab_active_background: Some(rgba(0x3b4252ff).into()),
+                    editor_background: Some(rgba(0x2e3440ff).into()),
+                    editor_gutter_background: Some(rgba(0x2e3440ff).into()),
+                    editor_line_number: Some(rgba(0x4c566aff).into()),
+                    editor_active_line_number: Some(rgba(0xd8dee9ff).into()),
                     terminal_background: Some(rgba(0x2e3440ff).into()),
                     terminal_ansi_bright_black: Some(rgba(0x4c566aff).into()),
                     terminal_ansi_bright_red: Some(rgba(0xbf616aff).into()),
@@ -48,6 +58,143 @@ pub fn nord() -> UserThemeFamily {
                     terminal_ansi_white: Some(rgba(0xe5e9f0ff).into()),
                     ..Default::default()
                 },
+                status: StatusColorsRefinement {
+                    deleted: Some(rgba(0xbf616aff).into()),
+                    error: Some(rgba(0xbf616aff).into()),
+                    hidden: Some(rgba(0xd8dee966).into()),
+                    warning: Some(rgba(0xebcb8bff).into()),
+                    ..Default::default()
+                },
+                syntax: Some(UserSyntaxTheme {
+                    highlights: vec![
+                        (
+                            "attribute".into(),
+                            UserHighlightStyle {
+                                color: Some(rgba(0x8fbcbbff).into()),
+                                ..Default::default()
+                            },
+                        ),
+                        (
+                            "boolean".into(),
+                            UserHighlightStyle {
+                                color: Some(rgba(0x81a1c1ff).into()),
+                                ..Default::default()
+                            },
+                        ),
+                        (
+                            "comment".into(),
+                            UserHighlightStyle {
+                                color: Some(rgba(0x606e87ff).into()),
+                                ..Default::default()
+                            },
+                        ),
+                        (
+                            "constant".into(),
+                            UserHighlightStyle {
+                                color: Some(rgba(0xebcb8bff).into()),
+                                ..Default::default()
+                            },
+                        ),
+                        (
+                            "emphasis.strong".into(),
+                            UserHighlightStyle {
+                                font_weight: Some(UserFontWeight(700.0)),
+                                ..Default::default()
+                            },
+                        ),
+                        (
+                            "function".into(),
+                            UserHighlightStyle {
+                                color: Some(rgba(0x88bfd0ff).into()),
+                                ..Default::default()
+                            },
+                        ),
+                        (
+                            "keyword".into(),
+                            UserHighlightStyle {
+                                color: Some(rgba(0x81a1c1ff).into()),
+                                ..Default::default()
+                            },
+                        ),
+                        (
+                            "number".into(),
+                            UserHighlightStyle {
+                                color: Some(rgba(0xb48eacff).into()),
+                                ..Default::default()
+                            },
+                        ),
+                        (
+                            "operator".into(),
+                            UserHighlightStyle {
+                                color: Some(rgba(0x81a1c1ff).into()),
+                                ..Default::default()
+                            },
+                        ),
+                        (
+                            "punctuation".into(),
+                            UserHighlightStyle {
+                                color: Some(rgba(0xeceff4ff).into()),
+                                ..Default::default()
+                            },
+                        ),
+                        (
+                            "punctuation.delimiter".into(),
+                            UserHighlightStyle {
+                                color: Some(rgba(0x81a1c1ff).into()),
+                                ..Default::default()
+                            },
+                        ),
+                        (
+                            "string".into(),
+                            UserHighlightStyle {
+                                color: Some(rgba(0xa3be8cff).into()),
+                                ..Default::default()
+                            },
+                        ),
+                        (
+                            "string.escape".into(),
+                            UserHighlightStyle {
+                                color: Some(rgba(0xebcb8bff).into()),
+                                ..Default::default()
+                            },
+                        ),
+                        (
+                            "tag".into(),
+                            UserHighlightStyle {
+                                color: Some(rgba(0x81a1c1ff).into()),
+                                ..Default::default()
+                            },
+                        ),
+                        (
+                            "text.literal".into(),
+                            UserHighlightStyle {
+                                color: Some(rgba(0xa3be8cff).into()),
+                                ..Default::default()
+                            },
+                        ),
+                        (
+                            "type".into(),
+                            UserHighlightStyle {
+                                color: Some(rgba(0x8fbcbbff).into()),
+                                ..Default::default()
+                            },
+                        ),
+                        (
+                            "variable".into(),
+                            UserHighlightStyle {
+                                color: Some(rgba(0x81a1c1ff).into()),
+                                ..Default::default()
+                            },
+                        ),
+                        (
+                            "variable.special".into(),
+                            UserHighlightStyle {
+                                color: Some(rgba(0x81a1c1ff).into()),
+                                ..Default::default()
+                            },
+                        ),
+                    ],
+                }),
             },
         }],
     }

crates/theme2/src/themes/notctis.rs πŸ”—

@@ -1,446 +0,0 @@
-// This file was generated by the `theme_importer`.
-// Be careful when modifying it by hand.
-
-use gpui::rgba;
-
-use crate::{
-    Appearance, ThemeColorsRefinement, UserTheme, UserThemeFamily, UserThemeStylesRefinement,
-};
-
-pub fn notctis() -> UserThemeFamily {
-    UserThemeFamily {
-        name: "Notctis".into(),
-        author: "Liviu Schera (liviuschera)".into(),
-        themes: vec![
-            UserTheme {
-                name: "Noctis Azureus".into(),
-                appearance: Appearance::Dark,
-                styles: UserThemeStylesRefinement {
-                    colors: ThemeColorsRefinement {
-                        border: Some(rgba(0x1579b6ff).into()),
-                        border_variant: Some(rgba(0x1579b6ff).into()),
-                        border_focused: Some(rgba(0x1579b6ff).into()),
-                        border_selected: Some(rgba(0x1579b6ff).into()),
-                        border_transparent: Some(rgba(0x1579b6ff).into()),
-                        border_disabled: Some(rgba(0x1579b6ff).into()),
-                        elevated_surface_background: Some(rgba(0x051b28ff).into()),
-                        surface_background: Some(rgba(0x051b28ff).into()),
-                        background: Some(rgba(0x07263aff).into()),
-                        element_background: Some(rgba(0x007e99ff).into()),
-                        text: Some(rgba(0xbecfdaff).into()),
-                        tab_inactive_background: Some(rgba(0x08324eff).into()),
-                        tab_active_background: Some(rgba(0x07263aff).into()),
-                        terminal_background: Some(rgba(0x051b28ff).into()),
-                        terminal_ansi_bright_black: Some(rgba(0x475e6cff).into()),
-                        terminal_ansi_bright_red: Some(rgba(0xe97749ff).into()),
-                        terminal_ansi_bright_green: Some(rgba(0x5febb1ff).into()),
-                        terminal_ansi_bright_yellow: Some(rgba(0xe69532ff).into()),
-                        terminal_ansi_bright_blue: Some(rgba(0x5fb5ebff).into()),
-                        terminal_ansi_bright_magenta: Some(rgba(0xe697b2ff).into()),
-                        terminal_ansi_bright_cyan: Some(rgba(0x5fdaebff).into()),
-                        terminal_ansi_bright_white: Some(rgba(0xbecfdaff).into()),
-                        terminal_ansi_black: Some(rgba(0x28343dff).into()),
-                        terminal_ansi_red: Some(rgba(0xe66432ff).into()),
-                        terminal_ansi_green: Some(rgba(0x49e9a6ff).into()),
-                        terminal_ansi_yellow: Some(rgba(0xe4b781ff).into()),
-                        terminal_ansi_blue: Some(rgba(0x49ace9ff).into()),
-                        terminal_ansi_magenta: Some(rgba(0xdf759aff).into()),
-                        terminal_ansi_cyan: Some(rgba(0x49d5e9ff).into()),
-                        terminal_ansi_white: Some(rgba(0xaec3d0ff).into()),
-                        ..Default::default()
-                    },
-                },
-            },
-            UserTheme {
-                name: "Noctis Bordo".into(),
-                appearance: Appearance::Dark,
-                styles: UserThemeStylesRefinement {
-                    colors: ThemeColorsRefinement {
-                        border: Some(rgba(0x997582ff).into()),
-                        border_variant: Some(rgba(0x997582ff).into()),
-                        border_focused: Some(rgba(0x997582ff).into()),
-                        border_selected: Some(rgba(0x997582ff).into()),
-                        border_transparent: Some(rgba(0x997582ff).into()),
-                        border_disabled: Some(rgba(0x997582ff).into()),
-                        elevated_surface_background: Some(rgba(0x272022ff).into()),
-                        surface_background: Some(rgba(0x272022ff).into()),
-                        background: Some(rgba(0x322a2dff).into()),
-                        element_background: Some(rgba(0x007e99ff).into()),
-                        text: Some(rgba(0xcbbec2ff).into()),
-                        tab_inactive_background: Some(rgba(0x413036ff).into()),
-                        tab_active_background: Some(rgba(0x322a2dff).into()),
-                        terminal_background: Some(rgba(0x272022ff).into()),
-                        terminal_ansi_bright_black: Some(rgba(0x69545bff).into()),
-                        terminal_ansi_bright_red: Some(rgba(0xe97749ff).into()),
-                        terminal_ansi_bright_green: Some(rgba(0x5febb1ff).into()),
-                        terminal_ansi_bright_yellow: Some(rgba(0xe69532ff).into()),
-                        terminal_ansi_bright_blue: Some(rgba(0x5fb5ebff).into()),
-                        terminal_ansi_bright_magenta: Some(rgba(0xe697b2ff).into()),
-                        terminal_ansi_bright_cyan: Some(rgba(0x5fdaebff).into()),
-                        terminal_ansi_bright_white: Some(rgba(0xcbbec2ff).into()),
-                        terminal_ansi_black: Some(rgba(0x47393eff).into()),
-                        terminal_ansi_red: Some(rgba(0xe66432ff).into()),
-                        terminal_ansi_green: Some(rgba(0x49e9a6ff).into()),
-                        terminal_ansi_yellow: Some(rgba(0xe4b781ff).into()),
-                        terminal_ansi_blue: Some(rgba(0x49ace9ff).into()),
-                        terminal_ansi_magenta: Some(rgba(0xdf759aff).into()),
-                        terminal_ansi_cyan: Some(rgba(0x49d5e9ff).into()),
-                        terminal_ansi_white: Some(rgba(0xb9acb0ff).into()),
-                        ..Default::default()
-                    },
-                },
-            },
-            UserTheme {
-                name: "Noctus Hibernus".into(),
-                appearance: Appearance::Light,
-                styles: UserThemeStylesRefinement {
-                    colors: ThemeColorsRefinement {
-                        border: Some(rgba(0x00c6e0ff).into()),
-                        border_variant: Some(rgba(0x00c6e0ff).into()),
-                        border_focused: Some(rgba(0x00c6e0ff).into()),
-                        border_selected: Some(rgba(0x00c6e0ff).into()),
-                        border_transparent: Some(rgba(0x00c6e0ff).into()),
-                        border_disabled: Some(rgba(0x00c6e0ff).into()),
-                        elevated_surface_background: Some(rgba(0xe1eeefff).into()),
-                        surface_background: Some(rgba(0xe1eeefff).into()),
-                        background: Some(rgba(0xf4f6f6ff).into()),
-                        element_background: Some(rgba(0x089099ff).into()),
-                        text: Some(rgba(0x005661ff).into()),
-                        tab_inactive_background: Some(rgba(0xcaedf2ff).into()),
-                        tab_active_background: Some(rgba(0xf4f6f6ff).into()),
-                        terminal_background: Some(rgba(0xe1eeefff).into()),
-                        terminal_ansi_bright_black: Some(rgba(0x004d57ff).into()),
-                        terminal_ansi_bright_red: Some(rgba(0xff3f00ff).into()),
-                        terminal_ansi_bright_green: Some(rgba(0x00d17aff).into()),
-                        terminal_ansi_bright_yellow: Some(rgba(0xff8c00ff).into()),
-                        terminal_ansi_bright_blue: Some(rgba(0x0ea3ffff).into()),
-                        terminal_ansi_bright_magenta: Some(rgba(0xff6b9eff).into()),
-                        terminal_ansi_bright_cyan: Some(rgba(0x00cae6ff).into()),
-                        terminal_ansi_bright_white: Some(rgba(0xbbc3c4ff).into()),
-                        terminal_ansi_black: Some(rgba(0x003b41ff).into()),
-                        terminal_ansi_red: Some(rgba(0xe34d1bff).into()),
-                        terminal_ansi_green: Some(rgba(0x00b368ff).into()),
-                        terminal_ansi_yellow: Some(rgba(0xf49724ff).into()),
-                        terminal_ansi_blue: Some(rgba(0x0094f0ff).into()),
-                        terminal_ansi_magenta: Some(rgba(0xff5792ff).into()),
-                        terminal_ansi_cyan: Some(rgba(0x00bdd6ff).into()),
-                        terminal_ansi_white: Some(rgba(0x8ca6a6ff).into()),
-                        ..Default::default()
-                    },
-                },
-            },
-            UserTheme {
-                name: "Noctis Lilac".into(),
-                appearance: Appearance::Dark,
-                styles: UserThemeStylesRefinement {
-                    colors: ThemeColorsRefinement {
-                        border: Some(rgba(0xaea4f4ff).into()),
-                        border_variant: Some(rgba(0xaea4f4ff).into()),
-                        border_focused: Some(rgba(0xaea4f4ff).into()),
-                        border_selected: Some(rgba(0xaea4f4ff).into()),
-                        border_transparent: Some(rgba(0xaea4f4ff).into()),
-                        border_disabled: Some(rgba(0xaea4f4ff).into()),
-                        elevated_surface_background: Some(rgba(0xe9e7f3ff).into()),
-                        surface_background: Some(rgba(0xe9e7f3ff).into()),
-                        background: Some(rgba(0xf2f1f8ff).into()),
-                        element_background: Some(rgba(0x8d7ffeff).into()),
-                        text: Some(rgba(0x0c006bff).into()),
-                        tab_inactive_background: Some(rgba(0xe2dff6ff).into()),
-                        tab_active_background: Some(rgba(0xf2f1f8ff).into()),
-                        terminal_background: Some(rgba(0xe9e7f3ff).into()),
-                        terminal_ansi_bright_black: Some(rgba(0x0f0080ff).into()),
-                        terminal_ansi_bright_red: Some(rgba(0xff3f00ff).into()),
-                        terminal_ansi_bright_green: Some(rgba(0x00d17aff).into()),
-                        terminal_ansi_bright_yellow: Some(rgba(0xff8c00ff).into()),
-                        terminal_ansi_bright_blue: Some(rgba(0x0ea3ffff).into()),
-                        terminal_ansi_bright_magenta: Some(rgba(0xff6b9eff).into()),
-                        terminal_ansi_bright_cyan: Some(rgba(0x00cae6ff).into()),
-                        terminal_ansi_bright_white: Some(rgba(0xbbc3c4ff).into()),
-                        terminal_ansi_black: Some(rgba(0x0c006bff).into()),
-                        terminal_ansi_red: Some(rgba(0xe34d1bff).into()),
-                        terminal_ansi_green: Some(rgba(0x00b368ff).into()),
-                        terminal_ansi_yellow: Some(rgba(0xf49724ff).into()),
-                        terminal_ansi_blue: Some(rgba(0x0094f0ff).into()),
-                        terminal_ansi_magenta: Some(rgba(0xff5792ff).into()),
-                        terminal_ansi_cyan: Some(rgba(0x00bdd6ff).into()),
-                        terminal_ansi_white: Some(rgba(0x8ca6a6ff).into()),
-                        ..Default::default()
-                    },
-                },
-            },
-            UserTheme {
-                name: "Noctis Lux".into(),
-                appearance: Appearance::Light,
-                styles: UserThemeStylesRefinement {
-                    colors: ThemeColorsRefinement {
-                        border: Some(rgba(0x00c6e0ff).into()),
-                        border_variant: Some(rgba(0x00c6e0ff).into()),
-                        border_focused: Some(rgba(0x00c6e0ff).into()),
-                        border_selected: Some(rgba(0x00c6e0ff).into()),
-                        border_transparent: Some(rgba(0x00c6e0ff).into()),
-                        border_disabled: Some(rgba(0x00c6e0ff).into()),
-                        elevated_surface_background: Some(rgba(0xf6eddaff).into()),
-                        surface_background: Some(rgba(0xf6eddaff).into()),
-                        background: Some(rgba(0xfef8ecff).into()),
-                        element_background: Some(rgba(0x089099ff).into()),
-                        text: Some(rgba(0x005661ff).into()),
-                        tab_inactive_background: Some(rgba(0xf0e9d6ff).into()),
-                        tab_active_background: Some(rgba(0xfef8ecff).into()),
-                        terminal_background: Some(rgba(0xf6eddaff).into()),
-                        terminal_ansi_bright_black: Some(rgba(0x004d57ff).into()),
-                        terminal_ansi_bright_red: Some(rgba(0xff3f00ff).into()),
-                        terminal_ansi_bright_green: Some(rgba(0x00d17aff).into()),
-                        terminal_ansi_bright_yellow: Some(rgba(0xff8c00ff).into()),
-                        terminal_ansi_bright_blue: Some(rgba(0x0ea3ffff).into()),
-                        terminal_ansi_bright_magenta: Some(rgba(0xff6b9eff).into()),
-                        terminal_ansi_bright_cyan: Some(rgba(0x00cae6ff).into()),
-                        terminal_ansi_bright_white: Some(rgba(0xbbc3c4ff).into()),
-                        terminal_ansi_black: Some(rgba(0x003b41ff).into()),
-                        terminal_ansi_red: Some(rgba(0xe34d1bff).into()),
-                        terminal_ansi_green: Some(rgba(0x00b368ff).into()),
-                        terminal_ansi_yellow: Some(rgba(0xf49724ff).into()),
-                        terminal_ansi_blue: Some(rgba(0x0094f0ff).into()),
-                        terminal_ansi_magenta: Some(rgba(0xff5792ff).into()),
-                        terminal_ansi_cyan: Some(rgba(0x00bdd6ff).into()),
-                        terminal_ansi_white: Some(rgba(0x8ca6a6ff).into()),
-                        ..Default::default()
-                    },
-                },
-            },
-            UserTheme {
-                name: "Noctis Minimus".into(),
-                appearance: Appearance::Dark,
-                styles: UserThemeStylesRefinement {
-                    colors: ThemeColorsRefinement {
-                        border: Some(rgba(0x496c83ff).into()),
-                        border_variant: Some(rgba(0x496c83ff).into()),
-                        border_focused: Some(rgba(0x496c83ff).into()),
-                        border_selected: Some(rgba(0x496c83ff).into()),
-                        border_transparent: Some(rgba(0x496c83ff).into()),
-                        border_disabled: Some(rgba(0x496c83ff).into()),
-                        elevated_surface_background: Some(rgba(0x0e1920ff).into()),
-                        surface_background: Some(rgba(0x0e1920ff).into()),
-                        background: Some(rgba(0x1b2932ff).into()),
-                        element_background: Some(rgba(0x2e616bff).into()),
-                        text: Some(rgba(0xc5cdd3ff).into()),
-                        tab_inactive_background: Some(rgba(0x202d37ff).into()),
-                        tab_active_background: Some(rgba(0x1b2932ff).into()),
-                        terminal_background: Some(rgba(0x0e1920ff).into()),
-                        terminal_ansi_bright_black: Some(rgba(0x425866ff).into()),
-                        terminal_ansi_bright_red: Some(rgba(0xca8468ff).into()),
-                        terminal_ansi_bright_green: Some(rgba(0x84c8abff).into()),
-                        terminal_ansi_bright_yellow: Some(rgba(0xd1aa7bff).into()),
-                        terminal_ansi_bright_blue: Some(rgba(0x68a4caff).into()),
-                        terminal_ansi_bright_magenta: Some(rgba(0xc88da2ff).into()),
-                        terminal_ansi_bright_cyan: Some(rgba(0x84bfc8ff).into()),
-                        terminal_ansi_bright_white: Some(rgba(0xc5d1d3ff).into()),
-                        terminal_ansi_black: Some(rgba(0x182935ff).into()),
-                        terminal_ansi_red: Some(rgba(0xc08872ff).into()),
-                        terminal_ansi_green: Some(rgba(0x72c09fff).into()),
-                        terminal_ansi_yellow: Some(rgba(0xc8a984ff).into()),
-                        terminal_ansi_blue: Some(rgba(0x6095b7ff).into()),
-                        terminal_ansi_magenta: Some(rgba(0xc28097ff).into()),
-                        terminal_ansi_cyan: Some(rgba(0x72b7c0ff).into()),
-                        terminal_ansi_white: Some(rgba(0xc5cdd3ff).into()),
-                        ..Default::default()
-                    },
-                },
-            },
-            UserTheme {
-                name: "Noctis".into(),
-                appearance: Appearance::Dark,
-                styles: UserThemeStylesRefinement {
-                    colors: ThemeColorsRefinement {
-                        border: Some(rgba(0x0d6571ff).into()),
-                        border_variant: Some(rgba(0x0d6571ff).into()),
-                        border_focused: Some(rgba(0x0d6571ff).into()),
-                        border_selected: Some(rgba(0x0d6571ff).into()),
-                        border_transparent: Some(rgba(0x0d6571ff).into()),
-                        border_disabled: Some(rgba(0x0d6571ff).into()),
-                        elevated_surface_background: Some(rgba(0x03181aff).into()),
-                        surface_background: Some(rgba(0x03181aff).into()),
-                        background: Some(rgba(0x052428ff).into()),
-                        element_background: Some(rgba(0x089099ff).into()),
-                        text: Some(rgba(0xb1c9ccff).into()),
-                        tab_inactive_background: Some(rgba(0x052e32ff).into()),
-                        tab_active_background: Some(rgba(0x052428ff).into()),
-                        terminal_background: Some(rgba(0x03181aff).into()),
-                        terminal_ansi_bright_black: Some(rgba(0x47686cff).into()),
-                        terminal_ansi_bright_red: Some(rgba(0xe97749ff).into()),
-                        terminal_ansi_bright_green: Some(rgba(0x5febb1ff).into()),
-                        terminal_ansi_bright_yellow: Some(rgba(0xe69532ff).into()),
-                        terminal_ansi_bright_blue: Some(rgba(0x5fb5ebff).into()),
-                        terminal_ansi_bright_magenta: Some(rgba(0xe697b2ff).into()),
-                        terminal_ansi_bright_cyan: Some(rgba(0x5fdaebff).into()),
-                        terminal_ansi_bright_white: Some(rgba(0xc1d4d7ff).into()),
-                        terminal_ansi_black: Some(rgba(0x324a4dff).into()),
-                        terminal_ansi_red: Some(rgba(0xe66432ff).into()),
-                        terminal_ansi_green: Some(rgba(0x49e9a6ff).into()),
-                        terminal_ansi_yellow: Some(rgba(0xe4b781ff).into()),
-                        terminal_ansi_blue: Some(rgba(0x49ace9ff).into()),
-                        terminal_ansi_magenta: Some(rgba(0xdf759aff).into()),
-                        terminal_ansi_cyan: Some(rgba(0x49d5e9ff).into()),
-                        terminal_ansi_white: Some(rgba(0xb1c9ccff).into()),
-                        ..Default::default()
-                    },
-                },
-            },
-            UserTheme {
-                name: "Noctis Obscuro".into(),
-                appearance: Appearance::Dark,
-                styles: UserThemeStylesRefinement {
-                    colors: ThemeColorsRefinement {
-                        border: Some(rgba(0x0d6571ff).into()),
-                        border_variant: Some(rgba(0x0d6571ff).into()),
-                        border_focused: Some(rgba(0x0d6571ff).into()),
-                        border_selected: Some(rgba(0x0d6571ff).into()),
-                        border_transparent: Some(rgba(0x0d6571ff).into()),
-                        border_disabled: Some(rgba(0x0d6571ff).into()),
-                        elevated_surface_background: Some(rgba(0x020c0eff).into()),
-                        surface_background: Some(rgba(0x020c0eff).into()),
-                        background: Some(rgba(0x031316ff).into()),
-                        element_background: Some(rgba(0x089099ff).into()),
-                        text: Some(rgba(0xb1c9ccff).into()),
-                        tab_inactive_background: Some(rgba(0x052e32ff).into()),
-                        tab_active_background: Some(rgba(0x031316ff).into()),
-                        terminal_background: Some(rgba(0x020c0eff).into()),
-                        terminal_ansi_bright_black: Some(rgba(0x47686cff).into()),
-                        terminal_ansi_bright_red: Some(rgba(0xe97749ff).into()),
-                        terminal_ansi_bright_green: Some(rgba(0x5febb1ff).into()),
-                        terminal_ansi_bright_yellow: Some(rgba(0xe69532ff).into()),
-                        terminal_ansi_bright_blue: Some(rgba(0x5fb5ebff).into()),
-                        terminal_ansi_bright_magenta: Some(rgba(0xe697b2ff).into()),
-                        terminal_ansi_bright_cyan: Some(rgba(0x5fdaebff).into()),
-                        terminal_ansi_bright_white: Some(rgba(0xc1d4d7ff).into()),
-                        terminal_ansi_black: Some(rgba(0x324a4dff).into()),
-                        terminal_ansi_red: Some(rgba(0xe66432ff).into()),
-                        terminal_ansi_green: Some(rgba(0x49e9a6ff).into()),
-                        terminal_ansi_yellow: Some(rgba(0xe4b781ff).into()),
-                        terminal_ansi_blue: Some(rgba(0x49ace9ff).into()),
-                        terminal_ansi_magenta: Some(rgba(0xdf759aff).into()),
-                        terminal_ansi_cyan: Some(rgba(0x49d5e9ff).into()),
-                        terminal_ansi_white: Some(rgba(0xb1c9ccff).into()),
-                        ..Default::default()
-                    },
-                },
-            },
-            UserTheme {
-                name: "Noctis Sereno".into(),
-                appearance: Appearance::Dark,
-                styles: UserThemeStylesRefinement {
-                    colors: ThemeColorsRefinement {
-                        border: Some(rgba(0x0d6571ff).into()),
-                        border_variant: Some(rgba(0x0d6571ff).into()),
-                        border_focused: Some(rgba(0x0d6571ff).into()),
-                        border_selected: Some(rgba(0x0d6571ff).into()),
-                        border_transparent: Some(rgba(0x0d6571ff).into()),
-                        border_disabled: Some(rgba(0x0d6571ff).into()),
-                        elevated_surface_background: Some(rgba(0x020c0eff).into()),
-                        surface_background: Some(rgba(0x020c0eff).into()),
-                        background: Some(rgba(0x031316ff).into()),
-                        element_background: Some(rgba(0x089099ff).into()),
-                        text: Some(rgba(0xb1c9ccff).into()),
-                        tab_inactive_background: Some(rgba(0x052e32ff).into()),
-                        tab_active_background: Some(rgba(0x031316ff).into()),
-                        terminal_background: Some(rgba(0x020c0eff).into()),
-                        terminal_ansi_bright_black: Some(rgba(0x47686cff).into()),
-                        terminal_ansi_bright_red: Some(rgba(0xe97749ff).into()),
-                        terminal_ansi_bright_green: Some(rgba(0x5febb1ff).into()),
-                        terminal_ansi_bright_yellow: Some(rgba(0xe69532ff).into()),
-                        terminal_ansi_bright_blue: Some(rgba(0x5fb5ebff).into()),
-                        terminal_ansi_bright_magenta: Some(rgba(0xe697b2ff).into()),
-                        terminal_ansi_bright_cyan: Some(rgba(0x5fdaebff).into()),
-                        terminal_ansi_bright_white: Some(rgba(0xc1d4d7ff).into()),
-                        terminal_ansi_black: Some(rgba(0x324a4dff).into()),
-                        terminal_ansi_red: Some(rgba(0xe66432ff).into()),
-                        terminal_ansi_green: Some(rgba(0x49e9a6ff).into()),
-                        terminal_ansi_yellow: Some(rgba(0xe4b781ff).into()),
-                        terminal_ansi_blue: Some(rgba(0x49ace9ff).into()),
-                        terminal_ansi_magenta: Some(rgba(0xdf759aff).into()),
-                        terminal_ansi_cyan: Some(rgba(0x49d5e9ff).into()),
-                        terminal_ansi_white: Some(rgba(0xb1c9ccff).into()),
-                        ..Default::default()
-                    },
-                },
-            },
-            UserTheme {
-                name: "Noctis Uva".into(),
-                appearance: Appearance::Dark,
-                styles: UserThemeStylesRefinement {
-                    colors: ThemeColorsRefinement {
-                        border: Some(rgba(0x6d66a7ff).into()),
-                        border_variant: Some(rgba(0x6d66a7ff).into()),
-                        border_focused: Some(rgba(0x6d66a7ff).into()),
-                        border_selected: Some(rgba(0x6d66a7ff).into()),
-                        border_transparent: Some(rgba(0x6d66a7ff).into()),
-                        border_disabled: Some(rgba(0x6d66a7ff).into()),
-                        elevated_surface_background: Some(rgba(0x1f1d30ff).into()),
-                        surface_background: Some(rgba(0x1f1d30ff).into()),
-                        background: Some(rgba(0x292640ff).into()),
-                        element_background: Some(rgba(0x007e99ff).into()),
-                        text: Some(rgba(0xc5c2d6ff).into()),
-                        tab_inactive_background: Some(rgba(0x2f2c49ff).into()),
-                        tab_active_background: Some(rgba(0x292640ff).into()),
-                        terminal_background: Some(rgba(0x1f1d30ff).into()),
-                        terminal_ansi_bright_black: Some(rgba(0x504e65ff).into()),
-                        terminal_ansi_bright_red: Some(rgba(0xe97749ff).into()),
-                        terminal_ansi_bright_green: Some(rgba(0x5febb1ff).into()),
-                        terminal_ansi_bright_yellow: Some(rgba(0xe69532ff).into()),
-                        terminal_ansi_bright_blue: Some(rgba(0x5fb5ebff).into()),
-                        terminal_ansi_bright_magenta: Some(rgba(0xe697b2ff).into()),
-                        terminal_ansi_bright_cyan: Some(rgba(0x5fdaebff).into()),
-                        terminal_ansi_bright_white: Some(rgba(0xc5c2d6ff).into()),
-                        terminal_ansi_black: Some(rgba(0x302f3dff).into()),
-                        terminal_ansi_red: Some(rgba(0xe66432ff).into()),
-                        terminal_ansi_green: Some(rgba(0x49e9a6ff).into()),
-                        terminal_ansi_yellow: Some(rgba(0xe4b781ff).into()),
-                        terminal_ansi_blue: Some(rgba(0x49ace9ff).into()),
-                        terminal_ansi_magenta: Some(rgba(0xdf759aff).into()),
-                        terminal_ansi_cyan: Some(rgba(0x49d5e9ff).into()),
-                        terminal_ansi_white: Some(rgba(0xb6b3ccff).into()),
-                        ..Default::default()
-                    },
-                },
-            },
-            UserTheme {
-                name: "Noctis Viola".into(),
-                appearance: Appearance::Dark,
-                styles: UserThemeStylesRefinement {
-                    colors: ThemeColorsRefinement {
-                        border: Some(rgba(0x8666a7ff).into()),
-                        border_variant: Some(rgba(0x8666a7ff).into()),
-                        border_focused: Some(rgba(0x8666a7ff).into()),
-                        border_selected: Some(rgba(0x8666a7ff).into()),
-                        border_transparent: Some(rgba(0x8666a7ff).into()),
-                        border_disabled: Some(rgba(0x8666a7ff).into()),
-                        elevated_surface_background: Some(rgba(0x291d35ff).into()),
-                        surface_background: Some(rgba(0x291d35ff).into()),
-                        background: Some(rgba(0x30243dff).into()),
-                        element_background: Some(rgba(0x007e99ff).into()),
-                        text: Some(rgba(0xccbfd9ff).into()),
-                        tab_inactive_background: Some(rgba(0x3d2e4dff).into()),
-                        tab_active_background: Some(rgba(0x30243dff).into()),
-                        terminal_background: Some(rgba(0x291d35ff).into()),
-                        terminal_ansi_bright_black: Some(rgba(0x594e65ff).into()),
-                        terminal_ansi_bright_red: Some(rgba(0xe97749ff).into()),
-                        terminal_ansi_bright_green: Some(rgba(0x5febb1ff).into()),
-                        terminal_ansi_bright_yellow: Some(rgba(0xe69532ff).into()),
-                        terminal_ansi_bright_blue: Some(rgba(0x5fb5ebff).into()),
-                        terminal_ansi_bright_magenta: Some(rgba(0xe697b2ff).into()),
-                        terminal_ansi_bright_cyan: Some(rgba(0x5fdaebff).into()),
-                        terminal_ansi_bright_white: Some(rgba(0xccbfd9ff).into()),
-                        terminal_ansi_black: Some(rgba(0x362f3dff).into()),
-                        terminal_ansi_red: Some(rgba(0xe66432ff).into()),
-                        terminal_ansi_green: Some(rgba(0x49e9a6ff).into()),
-                        terminal_ansi_yellow: Some(rgba(0xe4b781ff).into()),
-                        terminal_ansi_blue: Some(rgba(0x49ace9ff).into()),
-                        terminal_ansi_magenta: Some(rgba(0xdf759aff).into()),
-                        terminal_ansi_cyan: Some(rgba(0x49d5e9ff).into()),
-                        terminal_ansi_white: Some(rgba(0xbfafcfff).into()),
-                        ..Default::default()
-                    },
-                },
-            },
-        ],
-    }
-}

crates/theme2/src/themes/palenight.rs πŸ”—

@@ -3,8 +3,10 @@
 
 use gpui::rgba;
 
+#[allow(unused)]
 use crate::{
-    Appearance, ThemeColorsRefinement, UserTheme, UserThemeFamily, UserThemeStylesRefinement,
+    Appearance, StatusColorsRefinement, ThemeColorsRefinement, UserFontStyle, UserFontWeight,
+    UserHighlightStyle, UserSyntaxTheme, UserTheme, UserThemeFamily, UserThemeStylesRefinement,
 };
 
 pub fn palenight() -> UserThemeFamily {
@@ -27,9 +29,17 @@ pub fn palenight() -> UserThemeFamily {
                         surface_background: Some(rgba(0x292c3eff).into()),
                         background: Some(rgba(0x292c3eff).into()),
                         element_background: Some(rgba(0x7d56c1cc).into()),
+                        element_hover: Some(rgba(0x0000001a).into()),
+                        element_selected: Some(rgba(0x7d56c1ff).into()),
+                        drop_target_background: Some(rgba(0x2e3245ff).into()),
+                        ghost_element_hover: Some(rgba(0x0000001a).into()),
                         text: Some(rgba(0xffffffff).into()),
                         tab_inactive_background: Some(rgba(0x31364aff).into()),
                         tab_active_background: Some(rgba(0x292c3eff).into()),
+                        editor_background: Some(rgba(0x292c3eff).into()),
+                        editor_gutter_background: Some(rgba(0x292c3eff).into()),
+                        editor_line_number: Some(rgba(0x4c5374ff).into()),
+                        editor_active_line_number: Some(rgba(0xbfc7d5ff).into()),
                         terminal_ansi_bright_black: Some(rgba(0x676e95ff).into()),
                         terminal_ansi_bright_red: Some(rgba(0xff5571ff).into()),
                         terminal_ansi_bright_green: Some(rgba(0xc3e88dff).into()),
@@ -48,6 +58,166 @@ pub fn palenight() -> UserThemeFamily {
                         terminal_ansi_white: Some(rgba(0xffffffff).into()),
                         ..Default::default()
                     },
+                    status: StatusColorsRefinement {
+                        deleted: Some(rgba(0xef524fff).into()),
+                        error: Some(rgba(0xef524fff).into()),
+                        hidden: Some(rgba(0x9199c8ff).into()),
+                        ..Default::default()
+                    },
+                    syntax: Some(UserSyntaxTheme {
+                        highlights: vec![
+                            (
+                                "attribute".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xffcb6bff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "boolean".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x82aaffff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "comment".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x687097ff).into()),
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "constant".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x82aaffff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "emphasis".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xc792eaff).into()),
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "emphasis.strong".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xffcb6bff).into()),
+                                    font_weight: Some(UserFontWeight(700.0)),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "function".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x82aaffff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "keyword".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xc792eaff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "link_text".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xff869aff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "link_uri".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xff869aff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "number".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xf78b6bff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "operator".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x89ddffff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "property".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x7fcac3ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "punctuation".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xc792eaff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xc3e88dff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string.escape".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x82aaffff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "tag".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xff5571ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "text.literal".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xc3e88dff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "type".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xffcb6bff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xffcb6bff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable.special".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xff5571ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                        ],
+                    }),
                 },
             },
             UserTheme {
@@ -65,9 +235,17 @@ pub fn palenight() -> UserThemeFamily {
                         surface_background: Some(rgba(0x292c3eff).into()),
                         background: Some(rgba(0x292c3eff).into()),
                         element_background: Some(rgba(0x7d56c1cc).into()),
+                        element_hover: Some(rgba(0x0000001a).into()),
+                        element_selected: Some(rgba(0x7d56c1ff).into()),
+                        drop_target_background: Some(rgba(0x2e3245ff).into()),
+                        ghost_element_hover: Some(rgba(0x0000001a).into()),
                         text: Some(rgba(0xffffffff).into()),
                         tab_inactive_background: Some(rgba(0x31364aff).into()),
                         tab_active_background: Some(rgba(0x292c3eff).into()),
+                        editor_background: Some(rgba(0x292c3eff).into()),
+                        editor_gutter_background: Some(rgba(0x292c3eff).into()),
+                        editor_line_number: Some(rgba(0x4c5374ff).into()),
+                        editor_active_line_number: Some(rgba(0xbfc7d5ff).into()),
                         terminal_ansi_bright_black: Some(rgba(0x676e95ff).into()),
                         terminal_ansi_bright_red: Some(rgba(0xff5571ff).into()),
                         terminal_ansi_bright_green: Some(rgba(0xc3e88dff).into()),
@@ -86,6 +264,166 @@ pub fn palenight() -> UserThemeFamily {
                         terminal_ansi_white: Some(rgba(0xffffffff).into()),
                         ..Default::default()
                     },
+                    status: StatusColorsRefinement {
+                        deleted: Some(rgba(0xef524fff).into()),
+                        error: Some(rgba(0xef524fff).into()),
+                        hidden: Some(rgba(0x9199c8ff).into()),
+                        ..Default::default()
+                    },
+                    syntax: Some(UserSyntaxTheme {
+                        highlights: vec![
+                            (
+                                "attribute".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xffcb6bff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "boolean".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x82aaffff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "comment".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x687097ff).into()),
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "constant".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x82aaffff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "emphasis".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xc792eaff).into()),
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "emphasis.strong".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xffcb6bff).into()),
+                                    font_weight: Some(UserFontWeight(700.0)),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "function".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x82aaffff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "keyword".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xc792eaff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "link_text".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xff869aff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "link_uri".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xff869aff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "number".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xf78b6bff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "operator".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x89ddffff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "property".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x7fcac3ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "punctuation".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xc792eaff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xc3e88dff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string.escape".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x82aaffff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "tag".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xff5571ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "text.literal".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xc3e88dff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "type".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xffcb6bff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xffcb6bff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable.special".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xff5571ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                        ],
+                    }),
                 },
             },
             UserTheme {
@@ -103,9 +441,17 @@ pub fn palenight() -> UserThemeFamily {
                         surface_background: Some(rgba(0x25283aff).into()),
                         background: Some(rgba(0x292c3eff).into()),
                         element_background: Some(rgba(0x7d56c1cc).into()),
+                        element_hover: Some(rgba(0x0000001a).into()),
+                        element_selected: Some(rgba(0x7d56c1ff).into()),
+                        drop_target_background: Some(rgba(0x2e3245ff).into()),
+                        ghost_element_hover: Some(rgba(0x0000001a).into()),
                         text: Some(rgba(0xffffffff).into()),
                         tab_inactive_background: Some(rgba(0x31364aff).into()),
                         tab_active_background: Some(rgba(0x25283aff).into()),
+                        editor_background: Some(rgba(0x292c3eff).into()),
+                        editor_gutter_background: Some(rgba(0x292c3eff).into()),
+                        editor_line_number: Some(rgba(0x4c5374ff).into()),
+                        editor_active_line_number: Some(rgba(0xbfc7d5ff).into()),
                         terminal_ansi_bright_black: Some(rgba(0x676e95ff).into()),
                         terminal_ansi_bright_red: Some(rgba(0xff5571ff).into()),
                         terminal_ansi_bright_green: Some(rgba(0xc3e88dff).into()),
@@ -124,6 +470,166 @@ pub fn palenight() -> UserThemeFamily {
                         terminal_ansi_white: Some(rgba(0xffffffff).into()),
                         ..Default::default()
                     },
+                    status: StatusColorsRefinement {
+                        deleted: Some(rgba(0xef524fff).into()),
+                        error: Some(rgba(0xef524fff).into()),
+                        hidden: Some(rgba(0x9199c8ff).into()),
+                        ..Default::default()
+                    },
+                    syntax: Some(UserSyntaxTheme {
+                        highlights: vec![
+                            (
+                                "attribute".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xffcb6bff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "boolean".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x82aaffff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "comment".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x687097ff).into()),
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "constant".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x82aaffff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "emphasis".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xc792eaff).into()),
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "emphasis.strong".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xffcb6bff).into()),
+                                    font_weight: Some(UserFontWeight(700.0)),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "function".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x82aaffff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "keyword".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xc792eaff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "link_text".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xff869aff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "link_uri".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xff869aff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "number".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xf78b6bff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "operator".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x89ddffff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "property".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x7fcac3ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "punctuation".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xc792eaff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xc3e88dff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string.escape".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x82aaffff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "tag".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xff5571ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "text.literal".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xc3e88dff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "type".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xffcb6bff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xffcb6bff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable.special".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xff5571ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                        ],
+                    }),
                 },
             },
         ],

crates/theme2/src/themes/rose_pine.rs πŸ”—

@@ -3,8 +3,10 @@
 
 use gpui::rgba;
 
+#[allow(unused)]
 use crate::{
-    Appearance, ThemeColorsRefinement, UserTheme, UserThemeFamily, UserThemeStylesRefinement,
+    Appearance, StatusColorsRefinement, ThemeColorsRefinement, UserFontStyle, UserFontWeight,
+    UserHighlightStyle, UserSyntaxTheme, UserTheme, UserThemeFamily, UserThemeStylesRefinement,
 };
 
 pub fn rose_pine() -> UserThemeFamily {
@@ -19,7 +21,7 @@ pub fn rose_pine() -> UserThemeFamily {
                     colors: ThemeColorsRefinement {
                         border: Some(rgba(0x000000ff).into()),
                         border_variant: Some(rgba(0x000000ff).into()),
-                        border_focused: Some(rgba(0x000000ff).into()),
+                        border_focused: Some(rgba(0x6e6a8633).into()),
                         border_selected: Some(rgba(0x000000ff).into()),
                         border_transparent: Some(rgba(0x000000ff).into()),
                         border_disabled: Some(rgba(0x000000ff).into()),
@@ -27,9 +29,17 @@ pub fn rose_pine() -> UserThemeFamily {
                         surface_background: Some(rgba(0x1f1d2eff).into()),
                         background: Some(rgba(0x191724ff).into()),
                         element_background: Some(rgba(0xebbcbaff).into()),
+                        element_hover: Some(rgba(0x6e6a861a).into()),
+                        element_selected: Some(rgba(0x6e6a8633).into()),
+                        drop_target_background: Some(rgba(0x1f1d2eff).into()),
+                        ghost_element_hover: Some(rgba(0x6e6a861a).into()),
                         text: Some(rgba(0xe0def4ff).into()),
                         tab_inactive_background: Some(rgba(0x000000ff).into()),
                         tab_active_background: Some(rgba(0x6e6a861a).into()),
+                        editor_background: Some(rgba(0x191724ff).into()),
+                        editor_gutter_background: Some(rgba(0x191724ff).into()),
+                        editor_line_number: Some(rgba(0x908caaff).into()),
+                        editor_active_line_number: Some(rgba(0xe0def4ff).into()),
                         terminal_ansi_bright_black: Some(rgba(0x908caaff).into()),
                         terminal_ansi_bright_red: Some(rgba(0xeb6f92ff).into()),
                         terminal_ansi_bright_green: Some(rgba(0x30738fff).into()),
@@ -48,16 +58,136 @@ pub fn rose_pine() -> UserThemeFamily {
                         terminal_ansi_white: Some(rgba(0xe0def4ff).into()),
                         ..Default::default()
                     },
+                    status: StatusColorsRefinement {
+                        deleted: Some(rgba(0xeb6f92ff).into()),
+                        error: Some(rgba(0xeb6f92ff).into()),
+                        hidden: Some(rgba(0x908caaff).into()),
+                        warning: Some(rgba(0xf5c177ff).into()),
+                        ..Default::default()
+                    },
+                    syntax: Some(UserSyntaxTheme {
+                        highlights: vec![
+                            (
+                                "attribute".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xc4a7e7ff).into()),
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "boolean".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xebbcbaff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "comment".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x6e6a86ff).into()),
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "function".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xeb6f92ff).into()),
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "keyword".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x30738fff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "label".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xebbcbaff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "number".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xebbcbaff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "punctuation".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x908caaff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xf5c177ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "tag".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x9ccfd8ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "text.literal".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xf5c177ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "title".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xebbcbaff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "type".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x9ccfd8ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xebbcbaff).into()),
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable.special".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xe0def4ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                        ],
+                    }),
                 },
             },
             UserTheme {
-                name: "Rose Moon".into(),
+                name: "Rose Pine Moon".into(),
                 appearance: Appearance::Dark,
                 styles: UserThemeStylesRefinement {
                     colors: ThemeColorsRefinement {
                         border: Some(rgba(0x000000ff).into()),
                         border_variant: Some(rgba(0x000000ff).into()),
-                        border_focused: Some(rgba(0x000000ff).into()),
+                        border_focused: Some(rgba(0x817c9c26).into()),
                         border_selected: Some(rgba(0x000000ff).into()),
                         border_transparent: Some(rgba(0x000000ff).into()),
                         border_disabled: Some(rgba(0x000000ff).into()),
@@ -65,9 +195,17 @@ pub fn rose_pine() -> UserThemeFamily {
                         surface_background: Some(rgba(0x2a273eff).into()),
                         background: Some(rgba(0x232136ff).into()),
                         element_background: Some(rgba(0xea9a97ff).into()),
+                        element_hover: Some(rgba(0x817c9c14).into()),
+                        element_selected: Some(rgba(0x817c9c26).into()),
+                        drop_target_background: Some(rgba(0x2a273eff).into()),
+                        ghost_element_hover: Some(rgba(0x817c9c14).into()),
                         text: Some(rgba(0xe0def4ff).into()),
                         tab_inactive_background: Some(rgba(0x000000ff).into()),
                         tab_active_background: Some(rgba(0x817c9c14).into()),
+                        editor_background: Some(rgba(0x232136ff).into()),
+                        editor_gutter_background: Some(rgba(0x232136ff).into()),
+                        editor_line_number: Some(rgba(0x908caaff).into()),
+                        editor_active_line_number: Some(rgba(0xe0def4ff).into()),
                         terminal_ansi_bright_black: Some(rgba(0x908caaff).into()),
                         terminal_ansi_bright_red: Some(rgba(0xeb6f92ff).into()),
                         terminal_ansi_bright_green: Some(rgba(0x3d8fb0ff).into()),
@@ -86,6 +224,126 @@ pub fn rose_pine() -> UserThemeFamily {
                         terminal_ansi_white: Some(rgba(0xe0def4ff).into()),
                         ..Default::default()
                     },
+                    status: StatusColorsRefinement {
+                        deleted: Some(rgba(0xeb6f92ff).into()),
+                        error: Some(rgba(0xeb6f92ff).into()),
+                        hidden: Some(rgba(0x908caaff).into()),
+                        warning: Some(rgba(0xf5c177ff).into()),
+                        ..Default::default()
+                    },
+                    syntax: Some(UserSyntaxTheme {
+                        highlights: vec![
+                            (
+                                "attribute".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xc4a7e7ff).into()),
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "boolean".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xea9a97ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "comment".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x6e6a86ff).into()),
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "function".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xeb6f92ff).into()),
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "keyword".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x3d8fb0ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "label".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xea9a97ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "number".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xea9a97ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "punctuation".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x908caaff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xf5c177ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "tag".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x9ccfd8ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "text.literal".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xf5c177ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "title".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xea9a97ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "type".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x9ccfd8ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xea9a97ff).into()),
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable.special".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xe0def4ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                        ],
+                    }),
                 },
             },
             UserTheme {
@@ -95,7 +353,7 @@ pub fn rose_pine() -> UserThemeFamily {
                     colors: ThemeColorsRefinement {
                         border: Some(rgba(0x000000ff).into()),
                         border_variant: Some(rgba(0x000000ff).into()),
-                        border_focused: Some(rgba(0x000000ff).into()),
+                        border_focused: Some(rgba(0x6e6a8614).into()),
                         border_selected: Some(rgba(0x000000ff).into()),
                         border_transparent: Some(rgba(0x000000ff).into()),
                         border_disabled: Some(rgba(0x000000ff).into()),
@@ -103,9 +361,17 @@ pub fn rose_pine() -> UserThemeFamily {
                         surface_background: Some(rgba(0xfffaf3ff).into()),
                         background: Some(rgba(0xfaf4edff).into()),
                         element_background: Some(rgba(0xd7827dff).into()),
+                        element_hover: Some(rgba(0x6e6a860d).into()),
+                        element_selected: Some(rgba(0x6e6a8614).into()),
+                        drop_target_background: Some(rgba(0xfffaf3ff).into()),
+                        ghost_element_hover: Some(rgba(0x6e6a860d).into()),
                         text: Some(rgba(0x575279ff).into()),
                         tab_inactive_background: Some(rgba(0x000000ff).into()),
                         tab_active_background: Some(rgba(0x6e6a860d).into()),
+                        editor_background: Some(rgba(0xfaf4edff).into()),
+                        editor_gutter_background: Some(rgba(0xfaf4edff).into()),
+                        editor_line_number: Some(rgba(0x797593ff).into()),
+                        editor_active_line_number: Some(rgba(0x575279ff).into()),
                         terminal_ansi_bright_black: Some(rgba(0x797593ff).into()),
                         terminal_ansi_bright_red: Some(rgba(0xb3627aff).into()),
                         terminal_ansi_bright_green: Some(rgba(0x276983ff).into()),
@@ -124,6 +390,126 @@ pub fn rose_pine() -> UserThemeFamily {
                         terminal_ansi_white: Some(rgba(0x575279ff).into()),
                         ..Default::default()
                     },
+                    status: StatusColorsRefinement {
+                        deleted: Some(rgba(0xb3627aff).into()),
+                        error: Some(rgba(0xb3627aff).into()),
+                        hidden: Some(rgba(0x797593ff).into()),
+                        warning: Some(rgba(0xea9d34ff).into()),
+                        ..Default::default()
+                    },
+                    syntax: Some(UserSyntaxTheme {
+                        highlights: vec![
+                            (
+                                "attribute".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x9079a9ff).into()),
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "boolean".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xd7827dff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "comment".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x9893a5ff).into()),
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "function".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xb3627aff).into()),
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "keyword".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x276983ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "label".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xd7827dff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "number".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xd7827dff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "punctuation".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x797593ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xea9d34ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "tag".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x55949fff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "text.literal".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xea9d34ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "title".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xd7827dff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "type".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x55949fff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xd7827dff).into()),
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable.special".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x575279ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                        ],
+                    }),
                 },
             },
         ],

crates/theme2/src/themes/solarized.rs πŸ”—

@@ -3,8 +3,10 @@
 
 use gpui::rgba;
 
+#[allow(unused)]
 use crate::{
-    Appearance, ThemeColorsRefinement, UserTheme, UserThemeFamily, UserThemeStylesRefinement,
+    Appearance, StatusColorsRefinement, ThemeColorsRefinement, UserFontStyle, UserFontWeight,
+    UserHighlightStyle, UserSyntaxTheme, UserTheme, UserThemeFamily, UserThemeStylesRefinement,
 };
 
 pub fn solarized() -> UserThemeFamily {
@@ -19,14 +21,22 @@ pub fn solarized() -> UserThemeFamily {
                     colors: ThemeColorsRefinement {
                         border: Some(rgba(0x003847ff).into()),
                         border_variant: Some(rgba(0x003847ff).into()),
-                        border_focused: Some(rgba(0x003847ff).into()),
+                        border_focused: Some(rgba(0x29a19899).into()),
                         border_selected: Some(rgba(0x003847ff).into()),
                         border_transparent: Some(rgba(0x003847ff).into()),
                         border_disabled: Some(rgba(0x003847ff).into()),
                         background: Some(rgba(0x002a35ff).into()),
                         element_background: Some(rgba(0x29a19899).into()),
+                        element_hover: Some(rgba(0x004353aa).into()),
+                        element_selected: Some(rgba(0x005a6fff).into()),
+                        drop_target_background: Some(rgba(0x00435388).into()),
+                        ghost_element_hover: Some(rgba(0x004353aa).into()),
+                        text: Some(rgba(0xbbbbbbff).into()),
                         tab_inactive_background: Some(rgba(0x003f51ff).into()),
                         tab_active_background: Some(rgba(0x002a36ff).into()),
+                        editor_background: Some(rgba(0x002a35ff).into()),
+                        editor_gutter_background: Some(rgba(0x002a35ff).into()),
+                        editor_line_number: Some(rgba(0x566c74ff).into()),
                         terminal_ansi_bright_black: Some(rgba(0x586e75ff).into()),
                         terminal_ansi_bright_red: Some(rgba(0xcb4b15ff).into()),
                         terminal_ansi_bright_green: Some(rgba(0x859900ff).into()),
@@ -45,6 +55,150 @@ pub fn solarized() -> UserThemeFamily {
                         terminal_ansi_white: Some(rgba(0x839496ff).into()),
                         ..Default::default()
                     },
+                    status: StatusColorsRefinement {
+                        deleted: Some(rgba(0xffeaeaff).into()),
+                        error: Some(rgba(0xffeaeaff).into()),
+                        hidden: Some(rgba(0x93a1a1ff).into()),
+                        ..Default::default()
+                    },
+                    syntax: Some(UserSyntaxTheme {
+                        highlights: vec![
+                            (
+                                "attribute".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x93a1a1ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "boolean".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xb58800ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "comment".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x657b83ff).into()),
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "constant".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xcb4b15ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "embedded".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x93a1a1ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "emphasis".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xd33582ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "emphasis.strong".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xd33582ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "function".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x258ad2ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "keyword".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x859900ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "number".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xd33582ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "property".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x839496ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "punctuation".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x657b83ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x29a198ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string.escape".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xcb4b15ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "tag".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x258ad2ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "text.literal".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x29a198ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "type".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xcb4b15ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x258ad2ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable.special".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x258ad2ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                        ],
+                    }),
                 },
             },
             UserTheme {
@@ -54,14 +208,21 @@ pub fn solarized() -> UserThemeFamily {
                     colors: ThemeColorsRefinement {
                         border: Some(rgba(0xddd6c1ff).into()),
                         border_variant: Some(rgba(0xddd6c1ff).into()),
-                        border_focused: Some(rgba(0xddd6c1ff).into()),
+                        border_focused: Some(rgba(0xd3af86ff).into()),
                         border_selected: Some(rgba(0xddd6c1ff).into()),
                         border_transparent: Some(rgba(0xddd6c1ff).into()),
                         border_disabled: Some(rgba(0xddd6c1ff).into()),
                         background: Some(rgba(0xfdf6e3ff).into()),
                         element_background: Some(rgba(0xab9d56ff).into()),
+                        element_hover: Some(rgba(0xdec98744).into()),
+                        element_selected: Some(rgba(0xdec987ff).into()),
+                        ghost_element_hover: Some(rgba(0xdec98744).into()),
+                        text: Some(rgba(0x333333ff).into()),
                         tab_inactive_background: Some(rgba(0xd3cbb7ff).into()),
                         tab_active_background: Some(rgba(0xfdf6e3ff).into()),
+                        editor_background: Some(rgba(0xfdf6e3ff).into()),
+                        editor_gutter_background: Some(rgba(0xfdf6e3ff).into()),
+                        editor_line_number: Some(rgba(0x9ca8a6ff).into()),
                         terminal_ansi_bright_black: Some(rgba(0x657b83ff).into()),
                         terminal_ansi_bright_red: Some(rgba(0xcb4b15ff).into()),
                         terminal_ansi_bright_green: Some(rgba(0x859900ff).into()),
@@ -80,6 +241,141 @@ pub fn solarized() -> UserThemeFamily {
                         terminal_ansi_white: Some(rgba(0xeee8d5ff).into()),
                         ..Default::default()
                     },
+                    status: StatusColorsRefinement {
+                        hidden: Some(rgba(0x586e75ff).into()),
+                        ..Default::default()
+                    },
+                    syntax: Some(UserSyntaxTheme {
+                        highlights: vec![
+                            (
+                                "attribute".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x93a1a1ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "boolean".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xb58800ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "comment".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x93a1a1ff).into()),
+                                    font_style: Some(UserFontStyle::Italic),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "constant".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xcb4b15ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "embedded".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x657b83ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "emphasis".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xd33582ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "emphasis.strong".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xd33582ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "function".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x258ad2ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "keyword".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x859900ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "number".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xd33582ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "punctuation.bracket".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x93a1a1ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x29a198ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "string.escape".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0xcb4b15ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "tag".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x258ad2ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "text.literal".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x29a198ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "type".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x258ad2ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x258ad2ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                            (
+                                "variable.special".into(),
+                                UserHighlightStyle {
+                                    color: Some(rgba(0x258ad2ff).into()),
+                                    ..Default::default()
+                                },
+                            ),
+                        ],
+                    }),
                 },
             },
         ],

crates/theme2/src/themes/synthwave_84.rs πŸ”—

@@ -3,8 +3,10 @@
 
 use gpui::rgba;
 
+#[allow(unused)]
 use crate::{
-    Appearance, ThemeColorsRefinement, UserTheme, UserThemeFamily, UserThemeStylesRefinement,
+    Appearance, StatusColorsRefinement, ThemeColorsRefinement, UserFontStyle, UserFontWeight,
+    UserHighlightStyle, UserSyntaxTheme, UserTheme, UserThemeFamily, UserThemeStylesRefinement,
 };
 
 pub fn synthwave_84() -> UserThemeFamily {
@@ -16,10 +18,18 @@ pub fn synthwave_84() -> UserThemeFamily {
             appearance: Appearance::Dark,
             styles: UserThemeStylesRefinement {
                 colors: ThemeColorsRefinement {
+                    border_focused: Some(rgba(0x1f212bff).into()),
                     background: Some(rgba(0x252334ff).into()),
                     element_background: Some(rgba(0x614d85ff).into()),
+                    element_hover: Some(rgba(0x37294d99).into()),
+                    element_selected: Some(rgba(0xffffff20).into()),
+                    drop_target_background: Some(rgba(0x34294f66).into()),
+                    ghost_element_hover: Some(rgba(0x37294d99).into()),
                     text: Some(rgba(0xffffffff).into()),
                     tab_inactive_background: Some(rgba(0x252334ff).into()),
+                    editor_background: Some(rgba(0x252334ff).into()),
+                    editor_gutter_background: Some(rgba(0x252334ff).into()),
+                    editor_line_number: Some(rgba(0xffffff73).into()),
                     terminal_ansi_bright_red: Some(rgba(0xfe444fff).into()),
                     terminal_ansi_bright_green: Some(rgba(0x71f1b7ff).into()),
                     terminal_ansi_bright_yellow: Some(rgba(0xfede5cff).into()),
@@ -34,6 +44,137 @@ pub fn synthwave_84() -> UserThemeFamily {
                     terminal_ansi_cyan: Some(rgba(0x02edf9ff).into()),
                     ..Default::default()
                 },
+                status: StatusColorsRefinement {
+                    deleted: Some(rgba(0xfe444fff).into()),
+                    error: Some(rgba(0xfe444fff).into()),
+                    warning: Some(rgba(0x71f1b7bb).into()),
+                    ..Default::default()
+                },
+                syntax: Some(UserSyntaxTheme {
+                    highlights: vec![
+                        (
+                            "attribute".into(),
+                            UserHighlightStyle {
+                                color: Some(rgba(0xfede5cff).into()),
+                                ..Default::default()
+                            },
+                        ),
+                        (
+                            "boolean".into(),
+                            UserHighlightStyle {
+                                color: Some(rgba(0xf97d71ff).into()),
+                                ..Default::default()
+                            },
+                        ),
+                        (
+                            "comment".into(),
+                            UserHighlightStyle {
+                                color: Some(rgba(0x848bbdff).into()),
+                                font_style: Some(UserFontStyle::Italic),
+                                ..Default::default()
+                            },
+                        ),
+                        (
+                            "function".into(),
+                            UserHighlightStyle {
+                                color: Some(rgba(0x35f9f5ff).into()),
+                                ..Default::default()
+                            },
+                        ),
+                        (
+                            "keyword".into(),
+                            UserHighlightStyle {
+                                color: Some(rgba(0xfede5cff).into()),
+                                ..Default::default()
+                            },
+                        ),
+                        (
+                            "label".into(),
+                            UserHighlightStyle {
+                                color: Some(rgba(0xfe444fff).into()),
+                                ..Default::default()
+                            },
+                        ),
+                        (
+                            "link_text".into(),
+                            UserHighlightStyle {
+                                color: Some(rgba(0xdd5500ff).into()),
+                                ..Default::default()
+                            },
+                        ),
+                        (
+                            "link_uri".into(),
+                            UserHighlightStyle {
+                                color: Some(rgba(0xdd5500ff).into()),
+                                ..Default::default()
+                            },
+                        ),
+                        (
+                            "number".into(),
+                            UserHighlightStyle {
+                                color: Some(rgba(0xf97d71ff).into()),
+                                ..Default::default()
+                            },
+                        ),
+                        (
+                            "operator".into(),
+                            UserHighlightStyle {
+                                color: Some(rgba(0xfede5cff).into()),
+                                ..Default::default()
+                            },
+                        ),
+                        (
+                            "property".into(),
+                            UserHighlightStyle {
+                                color: Some(rgba(0xff7ddaff).into()),
+                                ..Default::default()
+                            },
+                        ),
+                        (
+                            "punctuation".into(),
+                            UserHighlightStyle {
+                                color: Some(rgba(0x35f9f5ff).into()),
+                                ..Default::default()
+                            },
+                        ),
+                        (
+                            "tag".into(),
+                            UserHighlightStyle {
+                                color: Some(rgba(0x71f1b7ff).into()),
+                                ..Default::default()
+                            },
+                        ),
+                        (
+                            "title".into(),
+                            UserHighlightStyle {
+                                color: Some(rgba(0xfe444fff).into()),
+                                ..Default::default()
+                            },
+                        ),
+                        (
+                            "type".into(),
+                            UserHighlightStyle {
+                                color: Some(rgba(0xfe444fff).into()),
+                                ..Default::default()
+                            },
+                        ),
+                        (
+                            "variable".into(),
+                            UserHighlightStyle {
+                                color: Some(rgba(0xff7ddaff).into()),
+                                ..Default::default()
+                            },
+                        ),
+                        (
+                            "variable.special".into(),
+                            UserHighlightStyle {
+                                color: Some(rgba(0xfe444fff).into()),
+                                font_weight: Some(UserFontWeight(700.0)),
+                                ..Default::default()
+                            },
+                        ),
+                    ],
+                }),
             },
         }],
     }

crates/theme2/src/user_theme.rs πŸ”—

@@ -1,8 +1,8 @@
+use crate::{Appearance, StatusColors, StatusColorsRefinement, ThemeColors, ThemeColorsRefinement};
+use gpui::{FontStyle, FontWeight, Hsla};
 use refineable::Refineable;
 use serde::Deserialize;
 
-use crate::{Appearance, ThemeColors, ThemeColorsRefinement};
-
 #[derive(Deserialize)]
 pub struct UserThemeFamily {
     pub name: String,
@@ -18,8 +18,76 @@ pub struct UserTheme {
 }
 
 #[derive(Refineable, Clone)]
-#[refineable(deserialize)]
+#[refineable(Deserialize)]
 pub struct UserThemeStyles {
     #[refineable]
     pub colors: ThemeColors,
+    #[refineable]
+    pub status: StatusColors,
+    pub syntax: UserSyntaxTheme,
+}
+
+#[derive(Clone, Default, Deserialize)]
+pub struct UserSyntaxTheme {
+    pub highlights: Vec<(String, UserHighlightStyle)>,
+}
+
+#[derive(Clone, Default, Deserialize)]
+pub struct UserHighlightStyle {
+    pub color: Option<Hsla>,
+    pub font_style: Option<UserFontStyle>,
+    pub font_weight: Option<UserFontWeight>,
+}
+
+#[derive(Clone, Copy, Default, Deserialize)]
+pub struct UserFontWeight(pub f32);
+
+impl UserFontWeight {
+    /// Thin weight (100), the thinnest value.
+    pub const THIN: Self = Self(FontWeight::THIN.0);
+    /// Extra light weight (200).
+    pub const EXTRA_LIGHT: Self = Self(FontWeight::EXTRA_LIGHT.0);
+    /// Light weight (300).
+    pub const LIGHT: Self = Self(FontWeight::LIGHT.0);
+    /// Normal (400).
+    pub const NORMAL: Self = Self(FontWeight::NORMAL.0);
+    /// Medium weight (500, higher than normal).
+    pub const MEDIUM: Self = Self(FontWeight::MEDIUM.0);
+    /// Semibold weight (600).
+    pub const SEMIBOLD: Self = Self(FontWeight::SEMIBOLD.0);
+    /// Bold weight (700).
+    pub const BOLD: Self = Self(FontWeight::BOLD.0);
+    /// Extra-bold weight (800).
+    pub const EXTRA_BOLD: Self = Self(FontWeight::EXTRA_BOLD.0);
+    /// Black weight (900), the thickest value.
+    pub const BLACK: Self = Self(FontWeight::BLACK.0);
+}
+
+impl From<UserFontWeight> for FontWeight {
+    fn from(value: UserFontWeight) -> Self {
+        Self(value.0)
+    }
+}
+
+#[derive(Debug, Clone, Copy, Deserialize)]
+pub enum UserFontStyle {
+    Normal,
+    Italic,
+    Oblique,
+}
+
+impl From<UserFontStyle> for FontStyle {
+    fn from(value: UserFontStyle) -> Self {
+        match value {
+            UserFontStyle::Normal => FontStyle::Normal,
+            UserFontStyle::Italic => FontStyle::Italic,
+            UserFontStyle::Oblique => FontStyle::Oblique,
+        }
+    }
+}
+
+impl UserHighlightStyle {
+    pub fn is_empty(&self) -> bool {
+        self.color.is_none() && self.font_style.is_none() && self.font_weight.is_none()
+    }
 }

crates/theme_importer/Cargo.toml πŸ”—

@@ -10,9 +10,12 @@ publish = false
 anyhow.workspace = true
 convert_case = "0.6.0"
 gpui = { package = "gpui2", path = "../gpui2" }
+indexmap = "1.6.2"
+json_comments = "0.2.2"
 log.workspace = true
 rust-embed.workspace = true
 serde.workspace = true
 simplelog = "0.9"
-theme = { package = "theme2", path = "../theme2" }
+strum = { version = "0.25.0", features = ["derive"] }
+theme = { package = "theme2", path = "../theme2", features = ["importing-themes"] }
 uuid.workspace = true

crates/theme_importer/src/main.rs πŸ”—

@@ -11,14 +11,15 @@ use std::str::FromStr;
 use anyhow::{anyhow, Context, Result};
 use convert_case::{Case, Casing};
 use gpui::serde_json;
+use json_comments::StripComments;
 use log::LevelFilter;
 use serde::Deserialize;
 use simplelog::SimpleLogger;
 use theme::{Appearance, UserThemeFamily};
-use vscode::VsCodeThemeConverter;
 
 use crate::theme_printer::UserThemeFamilyPrinter;
 use crate::vscode::VsCodeTheme;
+use crate::vscode::VsCodeThemeConverter;
 
 #[derive(Debug, Deserialize)]
 struct FamilyMetadata {
@@ -27,7 +28,7 @@ struct FamilyMetadata {
     pub themes: Vec<ThemeMetadata>,
 }
 
-#[derive(Debug, Deserialize)]
+#[derive(Debug, Clone, Copy, Deserialize)]
 #[serde(rename_all = "snake_case")]
 pub enum ThemeAppearanceJson {
     Light,
@@ -111,7 +112,8 @@ fn main() -> Result<()> {
                 }
             };
 
-            let vscode_theme: VsCodeTheme = serde_json::from_reader(theme_file)
+            let theme_without_comments = StripComments::new(theme_file);
+            let vscode_theme: VsCodeTheme = serde_json::from_reader(theme_without_comments)
                 .context(format!("failed to parse theme {theme_file_path:?}"))?;
 
             let converter = VsCodeThemeConverter::new(vscode_theme, theme_metadata);
@@ -158,8 +160,10 @@ fn main() -> Result<()> {
 
             use gpui::rgba;
 
+            #[allow(unused)]
             use crate::{{
-                Appearance, ThemeColorsRefinement, UserTheme, UserThemeFamily, UserThemeStylesRefinement,
+                Appearance, StatusColorsRefinement, ThemeColorsRefinement, UserHighlightStyle, UserSyntaxTheme,
+                UserTheme, UserThemeFamily, UserThemeStylesRefinement, UserFontWeight, UserFontStyle
             }};
 
             pub fn {theme_family_slug}() -> UserThemeFamily {{

crates/theme_importer/src/theme_printer.rs πŸ”—

@@ -2,8 +2,9 @@ use std::fmt::{self, Debug};
 
 use gpui::{Hsla, Rgba};
 use theme::{
-    Appearance, PlayerColor, PlayerColors, StatusColors, SyntaxTheme, SystemColors,
-    ThemeColorsRefinement, UserTheme, UserThemeFamily, UserThemeStylesRefinement,
+    Appearance, PlayerColor, PlayerColors, StatusColorsRefinement, SystemColors,
+    ThemeColorsRefinement, UserHighlightStyle, UserSyntaxTheme, UserTheme, UserThemeFamily,
+    UserThemeStylesRefinement,
 };
 
 struct RawSyntaxPrinter<'a>(&'a str);
@@ -30,6 +31,17 @@ impl<'a, D: Debug> Debug for IntoPrinter<'a, D> {
     }
 }
 
+pub struct OptionPrinter<'a, T>(&'a Option<T>);
+
+impl<'a, T: Debug> Debug for OptionPrinter<'a, T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self.0 {
+            Some(value) => write!(f, "Some({:?})", value),
+            None => write!(f, "None"),
+        }
+    }
+}
+
 pub struct VecPrinter<'a, T>(&'a Vec<T>);
 
 impl<'a, T: Debug> Debug for VecPrinter<'a, T> {
@@ -92,6 +104,17 @@ impl<'a> Debug for UserThemeStylesRefinementPrinter<'a> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_struct("UserThemeStylesRefinement")
             .field("colors", &ThemeColorsRefinementPrinter(&self.0.colors))
+            .field("status", &StatusColorsRefinementPrinter(&self.0.status))
+            .field(
+                "syntax",
+                &OptionPrinter(
+                    &self
+                        .0
+                        .syntax
+                        .as_ref()
+                        .map(|syntax| UserSyntaxThemePrinter(syntax)),
+                ),
+            )
             .finish()
     }
 }
@@ -250,23 +273,39 @@ impl<'a> Debug for ThemeColorsRefinementPrinter<'a> {
     }
 }
 
-pub struct StatusColorsPrinter<'a>(&'a StatusColors);
+pub struct StatusColorsRefinementPrinter<'a>(&'a StatusColorsRefinement);
 
-impl<'a> Debug for StatusColorsPrinter<'a> {
+impl<'a> Debug for StatusColorsRefinementPrinter<'a> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_struct("StatusColors")
-            .field("conflict", &HslaPrinter(self.0.conflict))
-            .field("created", &HslaPrinter(self.0.created))
-            .field("deleted", &HslaPrinter(self.0.deleted))
-            .field("error", &HslaPrinter(self.0.error))
-            .field("hidden", &HslaPrinter(self.0.hidden))
-            .field("ignored", &HslaPrinter(self.0.ignored))
-            .field("info", &HslaPrinter(self.0.info))
-            .field("modified", &HslaPrinter(self.0.modified))
-            .field("renamed", &HslaPrinter(self.0.renamed))
-            .field("success", &HslaPrinter(self.0.success))
-            .field("warning", &HslaPrinter(self.0.warning))
-            .finish()
+        let status_colors = vec![
+            ("conflict", self.0.conflict),
+            ("created", self.0.created),
+            ("deleted", self.0.deleted),
+            ("error", self.0.error),
+            ("hidden", self.0.hidden),
+            ("ignored", self.0.ignored),
+            ("info", self.0.info),
+            ("modified", self.0.modified),
+            ("renamed", self.0.renamed),
+            ("success", self.0.success),
+            ("warning", self.0.warning),
+        ];
+
+        f.write_str("StatusColorsRefinement {")?;
+
+        for (color_name, color) in status_colors {
+            if let Some(color) = color {
+                f.write_str(color_name)?;
+                f.write_str(": ")?;
+                f.write_str("Some(")?;
+                HslaPrinter(color).fmt(f)?;
+                f.write_str(")")?;
+                f.write_str(",")?;
+            }
+        }
+
+        f.write_str("..Default::default()")?;
+        f.write_str("}")
     }
 }
 
@@ -299,11 +338,11 @@ impl<'a> Debug for PlayerColorPrinter<'a> {
     }
 }
 
-pub struct SyntaxThemePrinter<'a>(&'a SyntaxTheme);
+pub struct UserSyntaxThemePrinter<'a>(&'a UserSyntaxTheme);
 
-impl<'a> Debug for SyntaxThemePrinter<'a> {
+impl<'a> Debug for UserSyntaxThemePrinter<'a> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_struct("SyntaxTheme")
+        f.debug_struct("UserSyntaxTheme")
             .field(
                 "highlights",
                 &VecPrinter(
@@ -312,7 +351,7 @@ impl<'a> Debug for SyntaxThemePrinter<'a> {
                         .highlights
                         .iter()
                         .map(|(token, highlight)| {
-                            (IntoPrinter(token), HslaPrinter(highlight.color.unwrap()))
+                            (IntoPrinter(token), UserHighlightStylePrinter(&highlight))
                         })
                         .collect(),
                 ),
@@ -320,3 +359,41 @@ impl<'a> Debug for SyntaxThemePrinter<'a> {
             .finish()
     }
 }
+
+pub struct UserHighlightStylePrinter<'a>(&'a UserHighlightStyle);
+
+impl<'a> Debug for UserHighlightStylePrinter<'a> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.write_str("UserHighlightStyle {")?;
+
+        if let Some(color) = self.0.color {
+            f.write_str("color")?;
+            f.write_str(": ")?;
+            f.write_str("Some(")?;
+            HslaPrinter(color).fmt(f)?;
+            f.write_str(")")?;
+            f.write_str(",")?;
+        }
+
+        if let Some(font_style) = self.0.font_style {
+            f.write_str("font_style")?;
+            f.write_str(": ")?;
+            f.write_str("Some(")?;
+            write!(f, "UserFontStyle::{:?}", font_style)?;
+            f.write_str(")")?;
+            f.write_str(",")?;
+        }
+
+        if let Some(font_weight) = self.0.font_weight.as_ref() {
+            f.write_str("font_weight")?;
+            f.write_str(": ")?;
+            f.write_str("Some(")?;
+            write!(f, "UserFontWeight({:?})", font_weight.0)?;
+            f.write_str(")")?;
+            f.write_str(",")?;
+        }
+
+        f.write_str("..Default::default()")?;
+        f.write_str("}")
+    }
+}

crates/theme_importer/src/vscode.rs πŸ”—

@@ -1,570 +1,7 @@
-use anyhow::Result;
-use gpui::{Hsla, Rgba};
-use serde::Deserialize;
-use theme::{ThemeColorsRefinement, UserTheme, UserThemeStylesRefinement};
+mod converter;
+mod syntax;
+mod theme;
 
-use crate::util::Traverse;
-use crate::ThemeMetadata;
-
-#[derive(Deserialize, Debug)]
-pub struct VsCodeTheme {
-    #[serde(rename = "$schema")]
-    pub schema: Option<String>,
-    pub name: Option<String>,
-    pub author: Option<String>,
-    pub maintainers: Option<Vec<String>>,
-    #[serde(rename = "semanticClass")]
-    pub semantic_class: Option<String>,
-    #[serde(rename = "semanticHighlighting")]
-    pub semantic_highlighting: Option<bool>,
-    pub colors: VsCodeColors,
-}
-
-#[derive(Debug, Deserialize)]
-pub struct VsCodeColors {
-    #[serde(rename = "terminal.background")]
-    pub terminal_background: Option<String>,
-    #[serde(rename = "terminal.foreground")]
-    pub terminal_foreground: Option<String>,
-    #[serde(rename = "terminal.ansiBrightBlack")]
-    pub terminal_ansi_bright_black: Option<String>,
-    #[serde(rename = "terminal.ansiBrightRed")]
-    pub terminal_ansi_bright_red: Option<String>,
-    #[serde(rename = "terminal.ansiBrightGreen")]
-    pub terminal_ansi_bright_green: Option<String>,
-    #[serde(rename = "terminal.ansiBrightYellow")]
-    pub terminal_ansi_bright_yellow: Option<String>,
-    #[serde(rename = "terminal.ansiBrightBlue")]
-    pub terminal_ansi_bright_blue: Option<String>,
-    #[serde(rename = "terminal.ansiBrightMagenta")]
-    pub terminal_ansi_bright_magenta: Option<String>,
-    #[serde(rename = "terminal.ansiBrightCyan")]
-    pub terminal_ansi_bright_cyan: Option<String>,
-    #[serde(rename = "terminal.ansiBrightWhite")]
-    pub terminal_ansi_bright_white: Option<String>,
-    #[serde(rename = "terminal.ansiBlack")]
-    pub terminal_ansi_black: Option<String>,
-    #[serde(rename = "terminal.ansiRed")]
-    pub terminal_ansi_red: Option<String>,
-    #[serde(rename = "terminal.ansiGreen")]
-    pub terminal_ansi_green: Option<String>,
-    #[serde(rename = "terminal.ansiYellow")]
-    pub terminal_ansi_yellow: Option<String>,
-    #[serde(rename = "terminal.ansiBlue")]
-    pub terminal_ansi_blue: Option<String>,
-    #[serde(rename = "terminal.ansiMagenta")]
-    pub terminal_ansi_magenta: Option<String>,
-    #[serde(rename = "terminal.ansiCyan")]
-    pub terminal_ansi_cyan: Option<String>,
-    #[serde(rename = "terminal.ansiWhite")]
-    pub terminal_ansi_white: Option<String>,
-    #[serde(rename = "focusBorder")]
-    pub focus_border: Option<String>,
-    pub foreground: Option<String>,
-    #[serde(rename = "selection.background")]
-    pub selection_background: Option<String>,
-    #[serde(rename = "errorForeground")]
-    pub error_foreground: Option<String>,
-    #[serde(rename = "button.background")]
-    pub button_background: Option<String>,
-    #[serde(rename = "button.foreground")]
-    pub button_foreground: Option<String>,
-    #[serde(rename = "button.secondaryBackground")]
-    pub button_secondary_background: Option<String>,
-    #[serde(rename = "button.secondaryForeground")]
-    pub button_secondary_foreground: Option<String>,
-    #[serde(rename = "button.secondaryHoverBackground")]
-    pub button_secondary_hover_background: Option<String>,
-    #[serde(rename = "dropdown.background")]
-    pub dropdown_background: Option<String>,
-    #[serde(rename = "dropdown.border")]
-    pub dropdown_border: Option<String>,
-    #[serde(rename = "dropdown.foreground")]
-    pub dropdown_foreground: Option<String>,
-    #[serde(rename = "input.background")]
-    pub input_background: Option<String>,
-    #[serde(rename = "input.foreground")]
-    pub input_foreground: Option<String>,
-    #[serde(rename = "input.border")]
-    pub input_border: Option<String>,
-    #[serde(rename = "input.placeholderForeground")]
-    pub input_placeholder_foreground: Option<String>,
-    #[serde(rename = "inputOption.activeBorder")]
-    pub input_option_active_border: Option<String>,
-    #[serde(rename = "inputValidation.infoBorder")]
-    pub input_validation_info_border: Option<String>,
-    #[serde(rename = "inputValidation.warningBorder")]
-    pub input_validation_warning_border: Option<String>,
-    #[serde(rename = "inputValidation.errorBorder")]
-    pub input_validation_error_border: Option<String>,
-    #[serde(rename = "badge.foreground")]
-    pub badge_foreground: Option<String>,
-    #[serde(rename = "badge.background")]
-    pub badge_background: Option<String>,
-    #[serde(rename = "progressBar.background")]
-    pub progress_bar_background: Option<String>,
-    #[serde(rename = "list.activeSelectionBackground")]
-    pub list_active_selection_background: Option<String>,
-    #[serde(rename = "list.activeSelectionForeground")]
-    pub list_active_selection_foreground: Option<String>,
-    #[serde(rename = "list.dropBackground")]
-    pub list_drop_background: Option<String>,
-    #[serde(rename = "list.focusBackground")]
-    pub list_focus_background: Option<String>,
-    #[serde(rename = "list.highlightForeground")]
-    pub list_highlight_foreground: Option<String>,
-    #[serde(rename = "list.hoverBackground")]
-    pub list_hover_background: Option<String>,
-    #[serde(rename = "list.inactiveSelectionBackground")]
-    pub list_inactive_selection_background: Option<String>,
-    #[serde(rename = "list.warningForeground")]
-    pub list_warning_foreground: Option<String>,
-    #[serde(rename = "list.errorForeground")]
-    pub list_error_foreground: Option<String>,
-    #[serde(rename = "activityBar.background")]
-    pub activity_bar_background: Option<String>,
-    #[serde(rename = "activityBar.inactiveForeground")]
-    pub activity_bar_inactive_foreground: Option<String>,
-    #[serde(rename = "activityBar.foreground")]
-    pub activity_bar_foreground: Option<String>,
-    #[serde(rename = "activityBar.activeBorder")]
-    pub activity_bar_active_border: Option<String>,
-    #[serde(rename = "activityBar.activeBackground")]
-    pub activity_bar_active_background: Option<String>,
-    #[serde(rename = "activityBarBadge.background")]
-    pub activity_bar_badge_background: Option<String>,
-    #[serde(rename = "activityBarBadge.foreground")]
-    pub activity_bar_badge_foreground: Option<String>,
-    #[serde(rename = "sideBar.background")]
-    pub side_bar_background: Option<String>,
-    #[serde(rename = "sideBarTitle.foreground")]
-    pub side_bar_title_foreground: Option<String>,
-    #[serde(rename = "sideBarSectionHeader.background")]
-    pub side_bar_section_header_background: Option<String>,
-    #[serde(rename = "sideBarSectionHeader.border")]
-    pub side_bar_section_header_border: Option<String>,
-    #[serde(rename = "editorGroup.border")]
-    pub editor_group_border: Option<String>,
-    #[serde(rename = "editorGroup.dropBackground")]
-    pub editor_group_drop_background: Option<String>,
-    #[serde(rename = "editorGroupHeader.tabsBackground")]
-    pub editor_group_header_tabs_background: Option<String>,
-    #[serde(rename = "tab.activeBackground")]
-    pub tab_active_background: Option<String>,
-    #[serde(rename = "tab.activeForeground")]
-    pub tab_active_foreground: Option<String>,
-    #[serde(rename = "tab.border")]
-    pub tab_border: Option<String>,
-    #[serde(rename = "tab.activeBorderTop")]
-    pub tab_active_border_top: Option<String>,
-    #[serde(rename = "tab.inactiveBackground")]
-    pub tab_inactive_background: Option<String>,
-    #[serde(rename = "tab.inactiveForeground")]
-    pub tab_inactive_foreground: Option<String>,
-    #[serde(rename = "editor.foreground")]
-    pub editor_foreground: Option<String>,
-    #[serde(rename = "editor.background")]
-    pub editor_background: Option<String>,
-    #[serde(rename = "editorLineNumber.foreground")]
-    pub editor_line_number_foreground: Option<String>,
-    #[serde(rename = "editor.selectionBackground")]
-    pub editor_selection_background: Option<String>,
-    #[serde(rename = "editor.selectionHighlightBackground")]
-    pub editor_selection_highlight_background: Option<String>,
-    #[serde(rename = "editor.foldBackground")]
-    pub editor_fold_background: Option<String>,
-    #[serde(rename = "editor.wordHighlightBackground")]
-    pub editor_word_highlight_background: Option<String>,
-    #[serde(rename = "editor.wordHighlightStrongBackground")]
-    pub editor_word_highlight_strong_background: Option<String>,
-    #[serde(rename = "editor.findMatchBackground")]
-    pub editor_find_match_background: Option<String>,
-    #[serde(rename = "editor.findMatchHighlightBackground")]
-    pub editor_find_match_highlight_background: Option<String>,
-    #[serde(rename = "editor.findRangeHighlightBackground")]
-    pub editor_find_range_highlight_background: Option<String>,
-    #[serde(rename = "editor.hoverHighlightBackground")]
-    pub editor_hover_highlight_background: Option<String>,
-    #[serde(rename = "editor.lineHighlightBorder")]
-    pub editor_line_highlight_border: Option<String>,
-    #[serde(rename = "editorLink.activeForeground")]
-    pub editor_link_active_foreground: Option<String>,
-    #[serde(rename = "editor.rangeHighlightBackground")]
-    pub editor_range_highlight_background: Option<String>,
-    #[serde(rename = "editor.snippetTabstopHighlightBackground")]
-    pub editor_snippet_tabstop_highlight_background: Option<String>,
-    #[serde(rename = "editor.snippetTabstopHighlightBorder")]
-    pub editor_snippet_tabstop_highlight_border: Option<String>,
-    #[serde(rename = "editor.snippetFinalTabstopHighlightBackground")]
-    pub editor_snippet_final_tabstop_highlight_background: Option<String>,
-    #[serde(rename = "editor.snippetFinalTabstopHighlightBorder")]
-    pub editor_snippet_final_tabstop_highlight_border: Option<String>,
-    #[serde(rename = "editorWhitespace.foreground")]
-    pub editor_whitespace_foreground: Option<String>,
-    #[serde(rename = "editorIndentGuide.background")]
-    pub editor_indent_guide_background: Option<String>,
-    #[serde(rename = "editorIndentGuide.activeBackground")]
-    pub editor_indent_guide_active_background: Option<String>,
-    #[serde(rename = "editorRuler.foreground")]
-    pub editor_ruler_foreground: Option<String>,
-    #[serde(rename = "editorCodeLens.foreground")]
-    pub editor_code_lens_foreground: Option<String>,
-    #[serde(rename = "editorBracketHighlight.foreground1")]
-    pub editor_bracket_highlight_foreground1: Option<String>,
-    #[serde(rename = "editorBracketHighlight.foreground2")]
-    pub editor_bracket_highlight_foreground2: Option<String>,
-    #[serde(rename = "editorBracketHighlight.foreground3")]
-    pub editor_bracket_highlight_foreground3: Option<String>,
-    #[serde(rename = "editorBracketHighlight.foreground4")]
-    pub editor_bracket_highlight_foreground4: Option<String>,
-    #[serde(rename = "editorBracketHighlight.foreground5")]
-    pub editor_bracket_highlight_foreground5: Option<String>,
-    #[serde(rename = "editorBracketHighlight.foreground6")]
-    pub editor_bracket_highlight_foreground6: Option<String>,
-    #[serde(rename = "editorBracketHighlight.unexpectedBracket.foreground")]
-    pub editor_bracket_highlight_unexpected_bracket_foreground: Option<String>,
-    #[serde(rename = "editorOverviewRuler.border")]
-    pub editor_overview_ruler_border: Option<String>,
-    #[serde(rename = "editorOverviewRuler.selectionHighlightForeground")]
-    pub editor_overview_ruler_selection_highlight_foreground: Option<String>,
-    #[serde(rename = "editorOverviewRuler.wordHighlightForeground")]
-    pub editor_overview_ruler_word_highlight_foreground: Option<String>,
-    #[serde(rename = "editorOverviewRuler.wordHighlightStrongForeground")]
-    pub editor_overview_ruler_word_highlight_strong_foreground: Option<String>,
-    #[serde(rename = "editorOverviewRuler.modifiedForeground")]
-    pub editor_overview_ruler_modified_foreground: Option<String>,
-    #[serde(rename = "editorOverviewRuler.addedForeground")]
-    pub editor_overview_ruler_added_foreground: Option<String>,
-    #[serde(rename = "editorOverviewRuler.deletedForeground")]
-    pub editor_overview_ruler_deleted_foreground: Option<String>,
-    #[serde(rename = "editorOverviewRuler.errorForeground")]
-    pub editor_overview_ruler_error_foreground: Option<String>,
-    #[serde(rename = "editorOverviewRuler.warningForeground")]
-    pub editor_overview_ruler_warning_foreground: Option<String>,
-    #[serde(rename = "editorOverviewRuler.infoForeground")]
-    pub editor_overview_ruler_info_foreground: Option<String>,
-    #[serde(rename = "editorError.foreground")]
-    pub editor_error_foreground: Option<String>,
-    #[serde(rename = "editorWarning.foreground")]
-    pub editor_warning_foreground: Option<String>,
-    #[serde(rename = "editorGutter.modifiedBackground")]
-    pub editor_gutter_modified_background: Option<String>,
-    #[serde(rename = "editorGutter.addedBackground")]
-    pub editor_gutter_added_background: Option<String>,
-    #[serde(rename = "editorGutter.deletedBackground")]
-    pub editor_gutter_deleted_background: Option<String>,
-    #[serde(rename = "gitDecoration.modifiedResourceForeground")]
-    pub git_decoration_modified_resource_foreground: Option<String>,
-    #[serde(rename = "gitDecoration.deletedResourceForeground")]
-    pub git_decoration_deleted_resource_foreground: Option<String>,
-    #[serde(rename = "gitDecoration.untrackedResourceForeground")]
-    pub git_decoration_untracked_resource_foreground: Option<String>,
-    #[serde(rename = "gitDecoration.ignoredResourceForeground")]
-    pub git_decoration_ignored_resource_foreground: Option<String>,
-    #[serde(rename = "gitDecoration.conflictingResourceForeground")]
-    pub git_decoration_conflicting_resource_foreground: Option<String>,
-    #[serde(rename = "diffEditor.insertedTextBackground")]
-    pub diff_editor_inserted_text_background: Option<String>,
-    #[serde(rename = "diffEditor.removedTextBackground")]
-    pub diff_editor_removed_text_background: Option<String>,
-    #[serde(rename = "inlineChat.regionHighlight")]
-    pub inline_chat_region_highlight: Option<String>,
-    #[serde(rename = "editorWidget.background")]
-    pub editor_widget_background: Option<String>,
-    #[serde(rename = "editorSuggestWidget.background")]
-    pub editor_suggest_widget_background: Option<String>,
-    #[serde(rename = "editorSuggestWidget.foreground")]
-    pub editor_suggest_widget_foreground: Option<String>,
-    #[serde(rename = "editorSuggestWidget.selectedBackground")]
-    pub editor_suggest_widget_selected_background: Option<String>,
-    #[serde(rename = "editorHoverWidget.background")]
-    pub editor_hover_widget_background: Option<String>,
-    #[serde(rename = "editorHoverWidget.border")]
-    pub editor_hover_widget_border: Option<String>,
-    #[serde(rename = "editorMarkerNavigation.background")]
-    pub editor_marker_navigation_background: Option<String>,
-    #[serde(rename = "peekView.border")]
-    pub peek_view_border: Option<String>,
-    #[serde(rename = "peekViewEditor.background")]
-    pub peek_view_editor_background: Option<String>,
-    #[serde(rename = "peekViewEditor.matchHighlightBackground")]
-    pub peek_view_editor_match_highlight_background: Option<String>,
-    #[serde(rename = "peekViewResult.background")]
-    pub peek_view_result_background: Option<String>,
-    #[serde(rename = "peekViewResult.fileForeground")]
-    pub peek_view_result_file_foreground: Option<String>,
-    #[serde(rename = "peekViewResult.lineForeground")]
-    pub peek_view_result_line_foreground: Option<String>,
-    #[serde(rename = "peekViewResult.matchHighlightBackground")]
-    pub peek_view_result_match_highlight_background: Option<String>,
-    #[serde(rename = "peekViewResult.selectionBackground")]
-    pub peek_view_result_selection_background: Option<String>,
-    #[serde(rename = "peekViewResult.selectionForeground")]
-    pub peek_view_result_selection_foreground: Option<String>,
-    #[serde(rename = "peekViewTitle.background")]
-    pub peek_view_title_background: Option<String>,
-    #[serde(rename = "peekViewTitleDescription.foreground")]
-    pub peek_view_title_description_foreground: Option<String>,
-    #[serde(rename = "peekViewTitleLabel.foreground")]
-    pub peek_view_title_label_foreground: Option<String>,
-    #[serde(rename = "merge.currentHeaderBackground")]
-    pub merge_current_header_background: Option<String>,
-    #[serde(rename = "merge.incomingHeaderBackground")]
-    pub merge_incoming_header_background: Option<String>,
-    #[serde(rename = "editorOverviewRuler.currentContentForeground")]
-    pub editor_overview_ruler_current_content_foreground: Option<String>,
-    #[serde(rename = "editorOverviewRuler.incomingContentForeground")]
-    pub editor_overview_ruler_incoming_content_foreground: Option<String>,
-    #[serde(rename = "panel.background")]
-    pub panel_background: Option<String>,
-    #[serde(rename = "panel.border")]
-    pub panel_border: Option<String>,
-    #[serde(rename = "panelTitle.activeBorder")]
-    pub panel_title_active_border: Option<String>,
-    #[serde(rename = "panelTitle.activeForeground")]
-    pub panel_title_active_foreground: Option<String>,
-    #[serde(rename = "panelTitle.inactiveForeground")]
-    pub panel_title_inactive_foreground: Option<String>,
-    #[serde(rename = "statusBar.background")]
-    pub status_bar_background: Option<String>,
-    #[serde(rename = "statusBar.foreground")]
-    pub status_bar_foreground: Option<String>,
-    #[serde(rename = "statusBar.debuggingBackground")]
-    pub status_bar_debugging_background: Option<String>,
-    #[serde(rename = "statusBar.debuggingForeground")]
-    pub status_bar_debugging_foreground: Option<String>,
-    #[serde(rename = "statusBar.noFolderBackground")]
-    pub status_bar_no_folder_background: Option<String>,
-    #[serde(rename = "statusBar.noFolderForeground")]
-    pub status_bar_no_folder_foreground: Option<String>,
-    #[serde(rename = "statusBarItem.prominentBackground")]
-    pub status_bar_item_prominent_background: Option<String>,
-    #[serde(rename = "statusBarItem.prominentHoverBackground")]
-    pub status_bar_item_prominent_hover_background: Option<String>,
-    #[serde(rename = "statusBarItem.remoteForeground")]
-    pub status_bar_item_remote_foreground: Option<String>,
-    #[serde(rename = "statusBarItem.remoteBackground")]
-    pub status_bar_item_remote_background: Option<String>,
-    #[serde(rename = "titleBar.activeBackground")]
-    pub title_bar_active_background: Option<String>,
-    #[serde(rename = "titleBar.activeForeground")]
-    pub title_bar_active_foreground: Option<String>,
-    #[serde(rename = "titleBar.inactiveBackground")]
-    pub title_bar_inactive_background: Option<String>,
-    #[serde(rename = "titleBar.inactiveForeground")]
-    pub title_bar_inactive_foreground: Option<String>,
-    #[serde(rename = "extensionButton.prominentForeground")]
-    pub extension_button_prominent_foreground: Option<String>,
-    #[serde(rename = "extensionButton.prominentBackground")]
-    pub extension_button_prominent_background: Option<String>,
-    #[serde(rename = "extensionButton.prominentHoverBackground")]
-    pub extension_button_prominent_hover_background: Option<String>,
-    #[serde(rename = "pickerGroup.border")]
-    pub picker_group_border: Option<String>,
-    #[serde(rename = "pickerGroup.foreground")]
-    pub picker_group_foreground: Option<String>,
-    #[serde(rename = "debugToolBar.background")]
-    pub debug_tool_bar_background: Option<String>,
-    #[serde(rename = "walkThrough.embeddedEditorBackground")]
-    pub walk_through_embedded_editor_background: Option<String>,
-    #[serde(rename = "settings.headerForeground")]
-    pub settings_header_foreground: Option<String>,
-    #[serde(rename = "settings.modifiedItemIndicator")]
-    pub settings_modified_item_indicator: Option<String>,
-    #[serde(rename = "settings.dropdownBackground")]
-    pub settings_dropdown_background: Option<String>,
-    #[serde(rename = "settings.dropdownForeground")]
-    pub settings_dropdown_foreground: Option<String>,
-    #[serde(rename = "settings.dropdownBorder")]
-    pub settings_dropdown_border: Option<String>,
-    #[serde(rename = "settings.checkboxBackground")]
-    pub settings_checkbox_background: Option<String>,
-    #[serde(rename = "settings.checkboxForeground")]
-    pub settings_checkbox_foreground: Option<String>,
-    #[serde(rename = "settings.checkboxBorder")]
-    pub settings_checkbox_border: Option<String>,
-    #[serde(rename = "settings.textInputBackground")]
-    pub settings_text_input_background: Option<String>,
-    #[serde(rename = "settings.textInputForeground")]
-    pub settings_text_input_foreground: Option<String>,
-    #[serde(rename = "settings.textInputBorder")]
-    pub settings_text_input_border: Option<String>,
-    #[serde(rename = "settings.numberInputBackground")]
-    pub settings_number_input_background: Option<String>,
-    #[serde(rename = "settings.numberInputForeground")]
-    pub settings_number_input_foreground: Option<String>,
-    #[serde(rename = "settings.numberInputBorder")]
-    pub settings_number_input_border: Option<String>,
-    #[serde(rename = "breadcrumb.foreground")]
-    pub breadcrumb_foreground: Option<String>,
-    #[serde(rename = "breadcrumb.background")]
-    pub breadcrumb_background: Option<String>,
-    #[serde(rename = "breadcrumb.focusForeground")]
-    pub breadcrumb_focus_foreground: Option<String>,
-    #[serde(rename = "breadcrumb.activeSelectionForeground")]
-    pub breadcrumb_active_selection_foreground: Option<String>,
-    #[serde(rename = "breadcrumbPicker.background")]
-    pub breadcrumb_picker_background: Option<String>,
-    #[serde(rename = "listFilterWidget.background")]
-    pub list_filter_widget_background: Option<String>,
-    #[serde(rename = "listFilterWidget.outline")]
-    pub list_filter_widget_outline: Option<String>,
-    #[serde(rename = "listFilterWidget.noMatchesOutline")]
-    pub list_filter_widget_no_matches_outline: Option<String>,
-}
-
-fn try_parse_color(color: &str) -> Result<Hsla> {
-    Ok(Rgba::try_from(color)?.into())
-}
-
-pub struct VsCodeThemeConverter {
-    theme: VsCodeTheme,
-    theme_metadata: ThemeMetadata,
-}
-
-impl VsCodeThemeConverter {
-    pub fn new(theme: VsCodeTheme, theme_metadata: ThemeMetadata) -> Self {
-        Self {
-            theme,
-            theme_metadata,
-        }
-    }
-
-    pub fn convert(self) -> Result<UserTheme> {
-        let appearance = self.theme_metadata.appearance.into();
-
-        let vscode_colors = &self.theme.colors;
-
-        let theme_colors_refinements = ThemeColorsRefinement {
-            border: vscode_colors
-                .panel_border
-                .as_ref()
-                .traverse(|color| try_parse_color(&color))?,
-            border_variant: vscode_colors
-                .panel_border
-                .as_ref()
-                .traverse(|color| try_parse_color(&color))?,
-            border_focused: vscode_colors
-                .panel_border
-                .as_ref()
-                .traverse(|color| try_parse_color(&color))?,
-            border_disabled: vscode_colors
-                .panel_border
-                .as_ref()
-                .traverse(|color| try_parse_color(&color))?,
-            border_selected: vscode_colors
-                .panel_border
-                .as_ref()
-                .traverse(|color| try_parse_color(&color))?,
-            border_transparent: vscode_colors
-                .panel_border
-                .as_ref()
-                .traverse(|color| try_parse_color(&color))?,
-            elevated_surface_background: vscode_colors
-                .panel_background
-                .as_ref()
-                .traverse(|color| try_parse_color(&color))?,
-            surface_background: vscode_colors
-                .panel_background
-                .as_ref()
-                .traverse(|color| try_parse_color(&color))?,
-            background: vscode_colors
-                .editor_background
-                .as_ref()
-                .traverse(|color| try_parse_color(&color))?,
-            element_background: vscode_colors
-                .button_background
-                .as_ref()
-                .traverse(|color| try_parse_color(&color))?,
-            text: vscode_colors
-                .foreground
-                .as_ref()
-                .traverse(|color| try_parse_color(&color))?,
-            tab_active_background: vscode_colors
-                .tab_active_background
-                .as_ref()
-                .traverse(|color| try_parse_color(&color))?,
-            tab_inactive_background: vscode_colors
-                .tab_inactive_background
-                .as_ref()
-                .traverse(|color| try_parse_color(&color))?,
-            terminal_background: vscode_colors
-                .terminal_background
-                .as_ref()
-                .traverse(|color| try_parse_color(&color))?,
-            terminal_ansi_bright_black: vscode_colors
-                .terminal_ansi_bright_black
-                .as_ref()
-                .traverse(|color| try_parse_color(&color))?,
-            terminal_ansi_bright_red: vscode_colors
-                .terminal_ansi_bright_red
-                .as_ref()
-                .traverse(|color| try_parse_color(&color))?,
-            terminal_ansi_bright_green: vscode_colors
-                .terminal_ansi_bright_green
-                .as_ref()
-                .traverse(|color| try_parse_color(&color))?,
-            terminal_ansi_bright_yellow: vscode_colors
-                .terminal_ansi_bright_yellow
-                .as_ref()
-                .traverse(|color| try_parse_color(&color))?,
-            terminal_ansi_bright_blue: vscode_colors
-                .terminal_ansi_bright_blue
-                .as_ref()
-                .traverse(|color| try_parse_color(&color))?,
-            terminal_ansi_bright_magenta: vscode_colors
-                .terminal_ansi_bright_magenta
-                .as_ref()
-                .traverse(|color| try_parse_color(&color))?,
-            terminal_ansi_bright_cyan: vscode_colors
-                .terminal_ansi_bright_cyan
-                .as_ref()
-                .traverse(|color| try_parse_color(&color))?,
-            terminal_ansi_bright_white: vscode_colors
-                .terminal_ansi_bright_white
-                .as_ref()
-                .traverse(|color| try_parse_color(&color))?,
-            terminal_ansi_black: vscode_colors
-                .terminal_ansi_black
-                .as_ref()
-                .traverse(|color| try_parse_color(&color))?,
-            terminal_ansi_red: vscode_colors
-                .terminal_ansi_red
-                .as_ref()
-                .traverse(|color| try_parse_color(&color))?,
-            terminal_ansi_green: vscode_colors
-                .terminal_ansi_green
-                .as_ref()
-                .traverse(|color| try_parse_color(&color))?,
-            terminal_ansi_yellow: vscode_colors
-                .terminal_ansi_yellow
-                .as_ref()
-                .traverse(|color| try_parse_color(&color))?,
-            terminal_ansi_blue: vscode_colors
-                .terminal_ansi_blue
-                .as_ref()
-                .traverse(|color| try_parse_color(&color))?,
-            terminal_ansi_magenta: vscode_colors
-                .terminal_ansi_magenta
-                .as_ref()
-                .traverse(|color| try_parse_color(&color))?,
-            terminal_ansi_cyan: vscode_colors
-                .terminal_ansi_cyan
-                .as_ref()
-                .traverse(|color| try_parse_color(&color))?,
-            terminal_ansi_white: vscode_colors
-                .terminal_ansi_white
-                .as_ref()
-                .traverse(|color| try_parse_color(&color))?,
-            ..Default::default()
-        };
-
-        Ok(UserTheme {
-            name: self.theme_metadata.name.into(),
-            appearance,
-            styles: UserThemeStylesRefinement {
-                colors: theme_colors_refinements,
-            },
-        })
-    }
-}
+pub use converter::*;
+pub use syntax::*;
+pub use theme::*;

crates/theme_importer/src/vscode/converter.rs πŸ”—

@@ -0,0 +1,372 @@
+use anyhow::Result;
+use gpui::{Hsla, Rgba};
+use indexmap::IndexMap;
+use strum::IntoEnumIterator;
+use theme::{
+    StatusColorsRefinement, ThemeColorsRefinement, UserFontStyle, UserFontWeight,
+    UserHighlightStyle, UserSyntaxTheme, UserTheme, UserThemeStylesRefinement,
+};
+
+use crate::util::Traverse;
+use crate::vscode::VsCodeTheme;
+use crate::ThemeMetadata;
+
+use super::ZedSyntaxToken;
+
+pub(crate) fn try_parse_color(color: &str) -> Result<Hsla> {
+    Ok(Rgba::try_from(color)?.into())
+}
+
+pub(crate) fn try_parse_font_weight(font_style: &str) -> Option<UserFontWeight> {
+    match font_style {
+        style if style.contains("bold") => Some(UserFontWeight::BOLD),
+        _ => None,
+    }
+}
+
+pub(crate) fn try_parse_font_style(font_style: &str) -> Option<UserFontStyle> {
+    match font_style {
+        style if style.contains("italic") => Some(UserFontStyle::Italic),
+        style if style.contains("oblique") => Some(UserFontStyle::Oblique),
+        _ => None,
+    }
+}
+
+pub struct VsCodeThemeConverter {
+    theme: VsCodeTheme,
+    theme_metadata: ThemeMetadata,
+}
+
+impl VsCodeThemeConverter {
+    pub fn new(theme: VsCodeTheme, theme_metadata: ThemeMetadata) -> Self {
+        Self {
+            theme,
+            theme_metadata,
+        }
+    }
+
+    pub fn convert(self) -> Result<UserTheme> {
+        let appearance = self.theme_metadata.appearance.into();
+
+        let status_color_refinements = self.convert_status_colors()?;
+        let theme_colors_refinements = self.convert_theme_colors()?;
+        let syntax_theme = self.convert_syntax_theme()?;
+
+        Ok(UserTheme {
+            name: self.theme_metadata.name.into(),
+            appearance,
+            styles: UserThemeStylesRefinement {
+                colors: theme_colors_refinements,
+                status: status_color_refinements,
+                syntax: Some(syntax_theme),
+            },
+        })
+    }
+
+    fn convert_status_colors(&self) -> Result<StatusColorsRefinement> {
+        let vscode_colors = &self.theme.colors;
+
+        Ok(StatusColorsRefinement {
+            // conflict: None,
+            // created: None,
+            deleted: vscode_colors
+                .error_foreground
+                .as_ref()
+                .traverse(|color| try_parse_color(&color))?,
+            error: vscode_colors
+                .error_foreground
+                .as_ref()
+                .traverse(|color| try_parse_color(&color))?,
+            hidden: vscode_colors
+                .tab_inactive_foreground
+                .as_ref()
+                .traverse(|color| try_parse_color(&color))?,
+            // ignored: None,
+            // info: None,
+            // modified: None,
+            // renamed: None,
+            // success: None,
+            warning: vscode_colors
+                .list_warning_foreground
+                .as_ref()
+                .traverse(|color| try_parse_color(&color))?,
+            ..Default::default()
+        })
+    }
+
+    fn convert_theme_colors(&self) -> Result<ThemeColorsRefinement> {
+        let vscode_colors = &self.theme.colors;
+
+        Ok(ThemeColorsRefinement {
+            border: vscode_colors
+                .panel_border
+                .as_ref()
+                .traverse(|color| try_parse_color(&color))?,
+            border_variant: vscode_colors
+                .panel_border
+                .as_ref()
+                .traverse(|color| try_parse_color(&color))?,
+            border_focused: vscode_colors
+                .focus_border
+                .as_ref()
+                .traverse(|color| try_parse_color(&color))?,
+            border_disabled: vscode_colors
+                .panel_border
+                .as_ref()
+                .traverse(|color| try_parse_color(&color))?,
+            border_selected: vscode_colors
+                .panel_border
+                .as_ref()
+                .traverse(|color| try_parse_color(&color))?,
+            border_transparent: vscode_colors
+                .panel_border
+                .as_ref()
+                .traverse(|color| try_parse_color(&color))?,
+            elevated_surface_background: vscode_colors
+                .panel_background
+                .as_ref()
+                .traverse(|color| try_parse_color(&color))?,
+            surface_background: vscode_colors
+                .panel_background
+                .as_ref()
+                .traverse(|color| try_parse_color(&color))?,
+            background: vscode_colors
+                .editor_background
+                .as_ref()
+                .traverse(|color| try_parse_color(&color))?,
+            element_background: vscode_colors
+                .button_background
+                .as_ref()
+                .traverse(|color| try_parse_color(&color))?,
+            element_hover: vscode_colors
+                .list_hover_background
+                .as_ref()
+                .traverse(|color| try_parse_color(&color))?,
+            element_selected: vscode_colors
+                .list_active_selection_background
+                .as_ref()
+                .traverse(|color| try_parse_color(&color))?,
+            ghost_element_hover: vscode_colors
+                .list_hover_background
+                .as_ref()
+                .traverse(|color| try_parse_color(&color))?,
+            drop_target_background: vscode_colors
+                .list_drop_background
+                .as_ref()
+                .traverse(|color| try_parse_color(&color))?,
+            text: vscode_colors
+                .foreground
+                .as_ref()
+                .traverse(|color| try_parse_color(&color))?
+                .or_else(|| {
+                    self.theme
+                        .token_colors
+                        .iter()
+                        .find(|token_color| token_color.scope.is_none())
+                        .and_then(|token_color| token_color.settings.foreground.as_ref())
+                        .traverse(|color| try_parse_color(&color))
+                        .ok()
+                        .flatten()
+                }),
+            tab_active_background: vscode_colors
+                .tab_active_background
+                .as_ref()
+                .traverse(|color| try_parse_color(&color))?,
+            tab_inactive_background: vscode_colors
+                .tab_inactive_background
+                .as_ref()
+                .traverse(|color| try_parse_color(&color))?,
+            editor_background: vscode_colors
+                .editor_background
+                .as_ref()
+                .traverse(|color| try_parse_color(&color))?,
+            editor_gutter_background: vscode_colors
+                .editor_background
+                .as_ref()
+                .traverse(|color| try_parse_color(&color))?,
+            editor_line_number: vscode_colors
+                .editor_line_number_foreground
+                .as_ref()
+                .traverse(|color| try_parse_color(&color))?,
+            editor_active_line_number: vscode_colors
+                .editor_foreground
+                .as_ref()
+                .traverse(|color| try_parse_color(&color))?,
+            terminal_background: vscode_colors
+                .terminal_background
+                .as_ref()
+                .traverse(|color| try_parse_color(&color))?,
+            terminal_ansi_bright_black: vscode_colors
+                .terminal_ansi_bright_black
+                .as_ref()
+                .traverse(|color| try_parse_color(&color))?,
+            terminal_ansi_bright_red: vscode_colors
+                .terminal_ansi_bright_red
+                .as_ref()
+                .traverse(|color| try_parse_color(&color))?,
+            terminal_ansi_bright_green: vscode_colors
+                .terminal_ansi_bright_green
+                .as_ref()
+                .traverse(|color| try_parse_color(&color))?,
+            terminal_ansi_bright_yellow: vscode_colors
+                .terminal_ansi_bright_yellow
+                .as_ref()
+                .traverse(|color| try_parse_color(&color))?,
+            terminal_ansi_bright_blue: vscode_colors
+                .terminal_ansi_bright_blue
+                .as_ref()
+                .traverse(|color| try_parse_color(&color))?,
+            terminal_ansi_bright_magenta: vscode_colors
+                .terminal_ansi_bright_magenta
+                .as_ref()
+                .traverse(|color| try_parse_color(&color))?,
+            terminal_ansi_bright_cyan: vscode_colors
+                .terminal_ansi_bright_cyan
+                .as_ref()
+                .traverse(|color| try_parse_color(&color))?,
+            terminal_ansi_bright_white: vscode_colors
+                .terminal_ansi_bright_white
+                .as_ref()
+                .traverse(|color| try_parse_color(&color))?,
+            terminal_ansi_black: vscode_colors
+                .terminal_ansi_black
+                .as_ref()
+                .traverse(|color| try_parse_color(&color))?,
+            terminal_ansi_red: vscode_colors
+                .terminal_ansi_red
+                .as_ref()
+                .traverse(|color| try_parse_color(&color))?,
+            terminal_ansi_green: vscode_colors
+                .terminal_ansi_green
+                .as_ref()
+                .traverse(|color| try_parse_color(&color))?,
+            terminal_ansi_yellow: vscode_colors
+                .terminal_ansi_yellow
+                .as_ref()
+                .traverse(|color| try_parse_color(&color))?,
+            terminal_ansi_blue: vscode_colors
+                .terminal_ansi_blue
+                .as_ref()
+                .traverse(|color| try_parse_color(&color))?,
+            terminal_ansi_magenta: vscode_colors
+                .terminal_ansi_magenta
+                .as_ref()
+                .traverse(|color| try_parse_color(&color))?,
+            terminal_ansi_cyan: vscode_colors
+                .terminal_ansi_cyan
+                .as_ref()
+                .traverse(|color| try_parse_color(&color))?,
+            terminal_ansi_white: vscode_colors
+                .terminal_ansi_white
+                .as_ref()
+                .traverse(|color| try_parse_color(&color))?,
+            ..Default::default()
+        })
+    }
+
+    fn convert_syntax_theme(&self) -> Result<UserSyntaxTheme> {
+        let mut highlight_styles = IndexMap::new();
+
+        for syntax_token in ZedSyntaxToken::iter() {
+            let multimatch_scopes = syntax_token.to_vscode();
+
+            let token_color = self.theme.token_colors.iter().find(|token_color| {
+                token_color
+                    .scope
+                    .as_ref()
+                    .map(|scope| scope.multimatch(&multimatch_scopes))
+                    .unwrap_or(false)
+            });
+
+            let Some(token_color) = token_color else {
+                continue;
+            };
+
+            let highlight_style = UserHighlightStyle {
+                color: token_color
+                    .settings
+                    .foreground
+                    .as_ref()
+                    .traverse(|color| try_parse_color(&color))?,
+                font_style: token_color
+                    .settings
+                    .font_style
+                    .as_ref()
+                    .and_then(|style| try_parse_font_style(&style)),
+                font_weight: token_color
+                    .settings
+                    .font_style
+                    .as_ref()
+                    .and_then(|style| try_parse_font_weight(&style)),
+            };
+
+            if highlight_style.is_empty() {
+                continue;
+            }
+
+            highlight_styles.insert(syntax_token.to_string(), highlight_style);
+        }
+
+        Ok(UserSyntaxTheme {
+            highlights: highlight_styles.into_iter().collect(),
+        })
+
+        // let mut highlight_styles = IndexMap::new();
+
+        // for token_color in self.theme.token_colors {
+        //     highlight_styles.extend(token_color.highlight_styles()?);
+        // }
+
+        // let syntax_theme = UserSyntaxTheme {
+        //     highlights: highlight_styles.into_iter().collect(),
+        // };
+
+        // pub fn highlight_styles(&self) -> Result<IndexMap<String, UserHighlightStyle>> {
+        // let mut highlight_styles = IndexMap::new();
+
+        // for syntax_token in ZedSyntaxToken::iter() {
+        //     let scope = syntax_token.to_scope();
+
+        //     // let token_color =
+        // }
+
+        // let scope = match self.scope {
+        //     Some(VsCodeTokenScope::One(ref scope)) => vec![scope.clone()],
+        //     Some(VsCodeTokenScope::Many(ref scopes)) => scopes.clone(),
+        //     None => return Ok(IndexMap::new()),
+        // };
+
+        // for scope in &scope {
+        //     let Some(syntax_token) = Self::to_zed_token(&scope) else {
+        //         continue;
+        //     };
+
+        //     let highlight_style = UserHighlightStyle {
+        //         color: self
+        //             .settings
+        //             .foreground
+        //             .as_ref()
+        //             .traverse(|color| try_parse_color(&color))?,
+        //         font_style: self
+        //             .settings
+        //             .font_style
+        //             .as_ref()
+        //             .and_then(|style| try_parse_font_style(&style)),
+        //         font_weight: self
+        //             .settings
+        //             .font_style
+        //             .as_ref()
+        //             .and_then(|style| try_parse_font_weight(&style)),
+        //     };
+
+        //     if highlight_style.is_empty() {
+        //         continue;
+        //     }
+
+        //     highlight_styles.insert(syntax_token, highlight_style);
+        // }
+
+        // Ok(highlight_styles)
+        // }
+    }
+}

crates/theme_importer/src/vscode/syntax.rs πŸ”—

@@ -0,0 +1,218 @@
+use serde::Deserialize;
+use strum::EnumIter;
+
+#[derive(Debug, Deserialize)]
+#[serde(untagged)]
+pub enum VsCodeTokenScope {
+    One(String),
+    Many(Vec<String>),
+}
+
+impl VsCodeTokenScope {
+    pub fn multimatch(&self, matches: &[&'static str]) -> bool {
+        match self {
+            VsCodeTokenScope::One(scope) => matches.iter().any(|&s| s == scope),
+            VsCodeTokenScope::Many(scopes) => {
+                matches.iter().any(|s| scopes.contains(&s.to_string()))
+            }
+        }
+    }
+}
+
+#[derive(Debug, Deserialize)]
+pub struct VsCodeTokenColor {
+    pub scope: Option<VsCodeTokenScope>,
+    pub settings: VsCodeTokenColorSettings,
+}
+
+#[derive(Debug, Deserialize)]
+pub struct VsCodeTokenColorSettings {
+    pub foreground: Option<String>,
+    pub background: Option<String>,
+    #[serde(rename = "fontStyle")]
+    pub font_style: Option<String>,
+}
+
+#[derive(Debug, PartialEq, Copy, Clone, EnumIter)]
+pub enum ZedSyntaxToken {
+    SyntaxAttribute,
+    SyntaxBoolean,
+    SyntaxComment,
+    SyntaxCommentDoc,
+    SyntaxConstant,
+    SyntaxConstructor,
+    SyntaxEmbedded,
+    SyntaxEmphasis,
+    SyntaxEmphasisStrong,
+    SyntaxEnum,
+    SyntaxFunction,
+    SyntaxHint,
+    SyntaxKeyword,
+    SyntaxLabel,
+    SyntaxLinkText,
+    SyntaxLinkUri,
+    SyntaxNumber,
+    SyntaxOperator,
+    SyntaxPredictive,
+    SyntaxPreproc,
+    SyntaxPrimary,
+    SyntaxProperty,
+    SyntaxPunctuation,
+    SyntaxPunctuationBracket,
+    SyntaxPunctuationDelimiter,
+    SyntaxPunctuationListMarker,
+    SyntaxPunctuationSpecial,
+    SyntaxString,
+    SyntaxStringEscape,
+    SyntaxStringRegex,
+    SyntaxStringSpecial,
+    SyntaxStringSpecialSymbol,
+    SyntaxTag,
+    SyntaxTextLiteral,
+    SyntaxTitle,
+    SyntaxType,
+    SyntaxVariable,
+    SyntaxVariableSpecial,
+    SyntaxVariant,
+}
+
+impl std::fmt::Display for ZedSyntaxToken {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        use ZedSyntaxToken::*;
+
+        write!(
+            f,
+            "{}",
+            match self {
+                SyntaxAttribute => "attribute",
+                SyntaxBoolean => "boolean",
+                SyntaxComment => "comment",
+                SyntaxCommentDoc => "comment.doc",
+                SyntaxConstant => "constant",
+                SyntaxConstructor => "constructor",
+                SyntaxEmbedded => "embedded",
+                SyntaxEmphasis => "emphasis",
+                SyntaxEmphasisStrong => "emphasis.strong",
+                SyntaxEnum => "enum",
+                SyntaxFunction => "function",
+                SyntaxHint => "hint",
+                SyntaxKeyword => "keyword",
+                SyntaxLabel => "label",
+                SyntaxLinkText => "link_text",
+                SyntaxLinkUri => "link_uri",
+                SyntaxNumber => "number",
+                SyntaxOperator => "operator",
+                SyntaxPredictive => "predictive",
+                SyntaxPreproc => "preproc",
+                SyntaxPrimary => "primary",
+                SyntaxProperty => "property",
+                SyntaxPunctuation => "punctuation",
+                SyntaxPunctuationBracket => "punctuation.bracket",
+                SyntaxPunctuationDelimiter => "punctuation.delimiter",
+                SyntaxPunctuationListMarker => "punctuation.list_marker",
+                SyntaxPunctuationSpecial => "punctuation.special",
+                SyntaxString => "string",
+                SyntaxStringEscape => "string.escape",
+                SyntaxStringRegex => "string.regex",
+                SyntaxStringSpecial => "string.special",
+                SyntaxStringSpecialSymbol => "string.special.symbol",
+                SyntaxTag => "tag",
+                SyntaxTextLiteral => "text.literal",
+                SyntaxTitle => "title",
+                SyntaxType => "type",
+                SyntaxVariable => "variable",
+                SyntaxVariableSpecial => "variable.special",
+                SyntaxVariant => "variant",
+            }
+        )
+    }
+}
+
+impl ZedSyntaxToken {
+    pub fn to_vscode(&self) -> Vec<&'static str> {
+        use ZedSyntaxToken::*;
+
+        match self {
+            SyntaxAttribute => vec!["entity.other.attribute-name"],
+            SyntaxBoolean => vec!["constant.language"],
+            SyntaxComment => vec!["comment"],
+            SyntaxCommentDoc => vec!["comment.block.documentation"],
+            SyntaxConstant => vec!["constant.character"],
+            SyntaxConstructor => vec!["entity.name.function.definition.special.constructor"],
+            SyntaxEmbedded => vec!["meta.embedded"],
+            SyntaxEmphasis => vec!["markup.italic"],
+            SyntaxEmphasisStrong => vec![
+                "markup.bold",
+                "markup.italic markup.bold",
+                "markup.bold markup.italic",
+            ],
+            SyntaxEnum => vec!["support.type.enum"],
+            SyntaxFunction => vec![
+                "entity.name.function",
+                "variable.function",
+                "support.function",
+            ],
+            SyntaxKeyword => vec!["keyword"],
+            SyntaxLabel => vec![
+                "label",
+                "entity.name",
+                "entity.name.import",
+                "entity.name.package",
+            ],
+            SyntaxLinkText => vec!["markup.underline.link", "string.other.link"],
+            SyntaxLinkUri => vec!["markup.underline.link", "string.other.link"],
+            SyntaxNumber => vec!["constant.numeric", "number"],
+            SyntaxOperator => vec!["operator", "keyword.operator"],
+            SyntaxPreproc => vec!["preproc"],
+            SyntaxProperty => vec![
+                "variable.member",
+                "support.type.property-name",
+                "variable.object.property",
+                "variable.other.field",
+            ],
+            SyntaxPunctuation => vec![
+                "punctuation",
+                "punctuation.section",
+                "punctuation.accessor",
+                "punctuation.separator",
+                "punctuation.terminator",
+                "punctuation.definition.tag",
+            ],
+            SyntaxPunctuationBracket => vec![
+                "punctuation.bracket",
+                "punctuation.definition.tag.begin",
+                "punctuation.definition.tag.end",
+            ],
+            SyntaxPunctuationDelimiter => vec![
+                "punctuation.delimiter",
+                "punctuation.separator",
+                "punctuation.terminator",
+            ],
+            SyntaxPunctuationListMarker => vec!["markup.list punctuation.definition.list.begin"],
+            SyntaxPunctuationSpecial => vec!["punctuation.special"],
+            SyntaxString => vec!["string"],
+            SyntaxStringEscape => vec!["string.escape", "constant.character", "constant.other"],
+            SyntaxStringRegex => vec!["string.regex"],
+            SyntaxStringSpecial => vec!["string.special", "constant.other.symbol"],
+            SyntaxStringSpecialSymbol => vec!["string.special.symbol", "constant.other.symbol"],
+            SyntaxTag => vec!["tag", "entity.name.tag", "meta.tag.sgml"],
+            SyntaxTextLiteral => vec!["text.literal", "string"],
+            SyntaxTitle => vec!["title", "entity.name"],
+            SyntaxType => vec!["entity.name.type", "support.type", "support.class"],
+            SyntaxVariable => vec![
+                "variable",
+                "variable.language",
+                "variable.member",
+                "variable.parameter.function-call",
+            ],
+            SyntaxVariableSpecial => vec![
+                "variable.special",
+                "variable.member",
+                "variable.annotation",
+                "variable.language",
+            ],
+            SyntaxVariant => vec!["variant"],
+            _ => vec![],
+        }
+    }
+}

crates/theme_importer/src/vscode/theme.rs πŸ”—

@@ -0,0 +1,412 @@
+use serde::Deserialize;
+
+use crate::vscode::VsCodeTokenColor;
+
+#[derive(Deserialize, Debug)]
+pub struct VsCodeTheme {
+    #[serde(rename = "$schema")]
+    pub schema: Option<String>,
+    pub name: Option<String>,
+    pub author: Option<String>,
+    pub maintainers: Option<Vec<String>>,
+    #[serde(rename = "semanticClass")]
+    pub semantic_class: Option<String>,
+    #[serde(rename = "semanticHighlighting")]
+    pub semantic_highlighting: Option<bool>,
+    pub colors: VsCodeColors,
+    #[serde(rename = "tokenColors")]
+    pub token_colors: Vec<VsCodeTokenColor>,
+}
+
+#[derive(Debug, Deserialize)]
+pub struct VsCodeColors {
+    #[serde(rename = "terminal.background")]
+    pub terminal_background: Option<String>,
+    #[serde(rename = "terminal.foreground")]
+    pub terminal_foreground: Option<String>,
+    #[serde(rename = "terminal.ansiBrightBlack")]
+    pub terminal_ansi_bright_black: Option<String>,
+    #[serde(rename = "terminal.ansiBrightRed")]
+    pub terminal_ansi_bright_red: Option<String>,
+    #[serde(rename = "terminal.ansiBrightGreen")]
+    pub terminal_ansi_bright_green: Option<String>,
+    #[serde(rename = "terminal.ansiBrightYellow")]
+    pub terminal_ansi_bright_yellow: Option<String>,
+    #[serde(rename = "terminal.ansiBrightBlue")]
+    pub terminal_ansi_bright_blue: Option<String>,
+    #[serde(rename = "terminal.ansiBrightMagenta")]
+    pub terminal_ansi_bright_magenta: Option<String>,
+    #[serde(rename = "terminal.ansiBrightCyan")]
+    pub terminal_ansi_bright_cyan: Option<String>,
+    #[serde(rename = "terminal.ansiBrightWhite")]
+    pub terminal_ansi_bright_white: Option<String>,
+    #[serde(rename = "terminal.ansiBlack")]
+    pub terminal_ansi_black: Option<String>,
+    #[serde(rename = "terminal.ansiRed")]
+    pub terminal_ansi_red: Option<String>,
+    #[serde(rename = "terminal.ansiGreen")]
+    pub terminal_ansi_green: Option<String>,
+    #[serde(rename = "terminal.ansiYellow")]
+    pub terminal_ansi_yellow: Option<String>,
+    #[serde(rename = "terminal.ansiBlue")]
+    pub terminal_ansi_blue: Option<String>,
+    #[serde(rename = "terminal.ansiMagenta")]
+    pub terminal_ansi_magenta: Option<String>,
+    #[serde(rename = "terminal.ansiCyan")]
+    pub terminal_ansi_cyan: Option<String>,
+    #[serde(rename = "terminal.ansiWhite")]
+    pub terminal_ansi_white: Option<String>,
+    #[serde(rename = "focusBorder")]
+    pub focus_border: Option<String>,
+    pub foreground: Option<String>,
+    #[serde(rename = "selection.background")]
+    pub selection_background: Option<String>,
+    #[serde(rename = "errorForeground")]
+    pub error_foreground: Option<String>,
+    #[serde(rename = "button.background")]
+    pub button_background: Option<String>,
+    #[serde(rename = "button.foreground")]
+    pub button_foreground: Option<String>,
+    #[serde(rename = "button.secondaryBackground")]
+    pub button_secondary_background: Option<String>,
+    #[serde(rename = "button.secondaryForeground")]
+    pub button_secondary_foreground: Option<String>,
+    #[serde(rename = "button.secondaryHoverBackground")]
+    pub button_secondary_hover_background: Option<String>,
+    #[serde(rename = "dropdown.background")]
+    pub dropdown_background: Option<String>,
+    #[serde(rename = "dropdown.border")]
+    pub dropdown_border: Option<String>,
+    #[serde(rename = "dropdown.foreground")]
+    pub dropdown_foreground: Option<String>,
+    #[serde(rename = "input.background")]
+    pub input_background: Option<String>,
+    #[serde(rename = "input.foreground")]
+    pub input_foreground: Option<String>,
+    #[serde(rename = "input.border")]
+    pub input_border: Option<String>,
+    #[serde(rename = "input.placeholderForeground")]
+    pub input_placeholder_foreground: Option<String>,
+    #[serde(rename = "inputOption.activeBorder")]
+    pub input_option_active_border: Option<String>,
+    #[serde(rename = "inputValidation.infoBorder")]
+    pub input_validation_info_border: Option<String>,
+    #[serde(rename = "inputValidation.warningBorder")]
+    pub input_validation_warning_border: Option<String>,
+    #[serde(rename = "inputValidation.errorBorder")]
+    pub input_validation_error_border: Option<String>,
+    #[serde(rename = "badge.foreground")]
+    pub badge_foreground: Option<String>,
+    #[serde(rename = "badge.background")]
+    pub badge_background: Option<String>,
+    #[serde(rename = "progressBar.background")]
+    pub progress_bar_background: Option<String>,
+    #[serde(rename = "list.activeSelectionBackground")]
+    pub list_active_selection_background: Option<String>,
+    #[serde(rename = "list.activeSelectionForeground")]
+    pub list_active_selection_foreground: Option<String>,
+    #[serde(rename = "list.dropBackground")]
+    pub list_drop_background: Option<String>,
+    #[serde(rename = "list.focusBackground")]
+    pub list_focus_background: Option<String>,
+    #[serde(rename = "list.highlightForeground")]
+    pub list_highlight_foreground: Option<String>,
+    #[serde(rename = "list.hoverBackground")]
+    pub list_hover_background: Option<String>,
+    #[serde(rename = "list.inactiveSelectionBackground")]
+    pub list_inactive_selection_background: Option<String>,
+    #[serde(rename = "list.warningForeground")]
+    pub list_warning_foreground: Option<String>,
+    #[serde(rename = "list.errorForeground")]
+    pub list_error_foreground: Option<String>,
+    #[serde(rename = "activityBar.background")]
+    pub activity_bar_background: Option<String>,
+    #[serde(rename = "activityBar.inactiveForeground")]
+    pub activity_bar_inactive_foreground: Option<String>,
+    #[serde(rename = "activityBar.foreground")]
+    pub activity_bar_foreground: Option<String>,
+    #[serde(rename = "activityBar.activeBorder")]
+    pub activity_bar_active_border: Option<String>,
+    #[serde(rename = "activityBar.activeBackground")]
+    pub activity_bar_active_background: Option<String>,
+    #[serde(rename = "activityBarBadge.background")]
+    pub activity_bar_badge_background: Option<String>,
+    #[serde(rename = "activityBarBadge.foreground")]
+    pub activity_bar_badge_foreground: Option<String>,
+    #[serde(rename = "sideBar.background")]
+    pub side_bar_background: Option<String>,
+    #[serde(rename = "sideBarTitle.foreground")]
+    pub side_bar_title_foreground: Option<String>,
+    #[serde(rename = "sideBarSectionHeader.background")]
+    pub side_bar_section_header_background: Option<String>,
+    #[serde(rename = "sideBarSectionHeader.border")]
+    pub side_bar_section_header_border: Option<String>,
+    #[serde(rename = "editorGroup.border")]
+    pub editor_group_border: Option<String>,
+    #[serde(rename = "editorGroup.dropBackground")]
+    pub editor_group_drop_background: Option<String>,
+    #[serde(rename = "editorGroupHeader.tabsBackground")]
+    pub editor_group_header_tabs_background: Option<String>,
+    #[serde(rename = "tab.activeBackground")]
+    pub tab_active_background: Option<String>,
+    #[serde(rename = "tab.activeForeground")]
+    pub tab_active_foreground: Option<String>,
+    #[serde(rename = "tab.border")]
+    pub tab_border: Option<String>,
+    #[serde(rename = "tab.activeBorderTop")]
+    pub tab_active_border_top: Option<String>,
+    #[serde(rename = "tab.inactiveBackground")]
+    pub tab_inactive_background: Option<String>,
+    #[serde(rename = "tab.inactiveForeground")]
+    pub tab_inactive_foreground: Option<String>,
+    #[serde(rename = "editor.foreground")]
+    pub editor_foreground: Option<String>,
+    #[serde(rename = "editor.background")]
+    pub editor_background: Option<String>,
+    #[serde(rename = "editorLineNumber.foreground")]
+    pub editor_line_number_foreground: Option<String>,
+    #[serde(rename = "editor.selectionBackground")]
+    pub editor_selection_background: Option<String>,
+    #[serde(rename = "editor.selectionHighlightBackground")]
+    pub editor_selection_highlight_background: Option<String>,
+    #[serde(rename = "editor.foldBackground")]
+    pub editor_fold_background: Option<String>,
+    #[serde(rename = "editor.wordHighlightBackground")]
+    pub editor_word_highlight_background: Option<String>,
+    #[serde(rename = "editor.wordHighlightStrongBackground")]
+    pub editor_word_highlight_strong_background: Option<String>,
+    #[serde(rename = "editor.findMatchBackground")]
+    pub editor_find_match_background: Option<String>,
+    #[serde(rename = "editor.findMatchHighlightBackground")]
+    pub editor_find_match_highlight_background: Option<String>,
+    #[serde(rename = "editor.findRangeHighlightBackground")]
+    pub editor_find_range_highlight_background: Option<String>,
+    #[serde(rename = "editor.hoverHighlightBackground")]
+    pub editor_hover_highlight_background: Option<String>,
+    #[serde(rename = "editor.lineHighlightBorder")]
+    pub editor_line_highlight_border: Option<String>,
+    #[serde(rename = "editorLink.activeForeground")]
+    pub editor_link_active_foreground: Option<String>,
+    #[serde(rename = "editor.rangeHighlightBackground")]
+    pub editor_range_highlight_background: Option<String>,
+    #[serde(rename = "editor.snippetTabstopHighlightBackground")]
+    pub editor_snippet_tabstop_highlight_background: Option<String>,
+    #[serde(rename = "editor.snippetTabstopHighlightBorder")]
+    pub editor_snippet_tabstop_highlight_border: Option<String>,
+    #[serde(rename = "editor.snippetFinalTabstopHighlightBackground")]
+    pub editor_snippet_final_tabstop_highlight_background: Option<String>,
+    #[serde(rename = "editor.snippetFinalTabstopHighlightBorder")]
+    pub editor_snippet_final_tabstop_highlight_border: Option<String>,
+    #[serde(rename = "editorWhitespace.foreground")]
+    pub editor_whitespace_foreground: Option<String>,
+    #[serde(rename = "editorIndentGuide.background")]
+    pub editor_indent_guide_background: Option<String>,
+    #[serde(rename = "editorIndentGuide.activeBackground")]
+    pub editor_indent_guide_active_background: Option<String>,
+    #[serde(rename = "editorRuler.foreground")]
+    pub editor_ruler_foreground: Option<String>,
+    #[serde(rename = "editorCodeLens.foreground")]
+    pub editor_code_lens_foreground: Option<String>,
+    #[serde(rename = "editorBracketHighlight.foreground1")]
+    pub editor_bracket_highlight_foreground1: Option<String>,
+    #[serde(rename = "editorBracketHighlight.foreground2")]
+    pub editor_bracket_highlight_foreground2: Option<String>,
+    #[serde(rename = "editorBracketHighlight.foreground3")]
+    pub editor_bracket_highlight_foreground3: Option<String>,
+    #[serde(rename = "editorBracketHighlight.foreground4")]
+    pub editor_bracket_highlight_foreground4: Option<String>,
+    #[serde(rename = "editorBracketHighlight.foreground5")]
+    pub editor_bracket_highlight_foreground5: Option<String>,
+    #[serde(rename = "editorBracketHighlight.foreground6")]
+    pub editor_bracket_highlight_foreground6: Option<String>,
+    #[serde(rename = "editorBracketHighlight.unexpectedBracket.foreground")]
+    pub editor_bracket_highlight_unexpected_bracket_foreground: Option<String>,
+    #[serde(rename = "editorOverviewRuler.border")]
+    pub editor_overview_ruler_border: Option<String>,
+    #[serde(rename = "editorOverviewRuler.selectionHighlightForeground")]
+    pub editor_overview_ruler_selection_highlight_foreground: Option<String>,
+    #[serde(rename = "editorOverviewRuler.wordHighlightForeground")]
+    pub editor_overview_ruler_word_highlight_foreground: Option<String>,
+    #[serde(rename = "editorOverviewRuler.wordHighlightStrongForeground")]
+    pub editor_overview_ruler_word_highlight_strong_foreground: Option<String>,
+    #[serde(rename = "editorOverviewRuler.modifiedForeground")]
+    pub editor_overview_ruler_modified_foreground: Option<String>,
+    #[serde(rename = "editorOverviewRuler.addedForeground")]
+    pub editor_overview_ruler_added_foreground: Option<String>,
+    #[serde(rename = "editorOverviewRuler.deletedForeground")]
+    pub editor_overview_ruler_deleted_foreground: Option<String>,
+    #[serde(rename = "editorOverviewRuler.errorForeground")]
+    pub editor_overview_ruler_error_foreground: Option<String>,
+    #[serde(rename = "editorOverviewRuler.warningForeground")]
+    pub editor_overview_ruler_warning_foreground: Option<String>,
+    #[serde(rename = "editorOverviewRuler.infoForeground")]
+    pub editor_overview_ruler_info_foreground: Option<String>,
+    #[serde(rename = "editorError.foreground")]
+    pub editor_error_foreground: Option<String>,
+    #[serde(rename = "editorWarning.foreground")]
+    pub editor_warning_foreground: Option<String>,
+    #[serde(rename = "editorGutter.modifiedBackground")]
+    pub editor_gutter_modified_background: Option<String>,
+    #[serde(rename = "editorGutter.addedBackground")]
+    pub editor_gutter_added_background: Option<String>,
+    #[serde(rename = "editorGutter.deletedBackground")]
+    pub editor_gutter_deleted_background: Option<String>,
+    #[serde(rename = "gitDecoration.modifiedResourceForeground")]
+    pub git_decoration_modified_resource_foreground: Option<String>,
+    #[serde(rename = "gitDecoration.deletedResourceForeground")]
+    pub git_decoration_deleted_resource_foreground: Option<String>,
+    #[serde(rename = "gitDecoration.untrackedResourceForeground")]
+    pub git_decoration_untracked_resource_foreground: Option<String>,
+    #[serde(rename = "gitDecoration.ignoredResourceForeground")]
+    pub git_decoration_ignored_resource_foreground: Option<String>,
+    #[serde(rename = "gitDecoration.conflictingResourceForeground")]
+    pub git_decoration_conflicting_resource_foreground: Option<String>,
+    #[serde(rename = "diffEditor.insertedTextBackground")]
+    pub diff_editor_inserted_text_background: Option<String>,
+    #[serde(rename = "diffEditor.removedTextBackground")]
+    pub diff_editor_removed_text_background: Option<String>,
+    #[serde(rename = "inlineChat.regionHighlight")]
+    pub inline_chat_region_highlight: Option<String>,
+    #[serde(rename = "editorWidget.background")]
+    pub editor_widget_background: Option<String>,
+    #[serde(rename = "editorSuggestWidget.background")]
+    pub editor_suggest_widget_background: Option<String>,
+    #[serde(rename = "editorSuggestWidget.foreground")]
+    pub editor_suggest_widget_foreground: Option<String>,
+    #[serde(rename = "editorSuggestWidget.selectedBackground")]
+    pub editor_suggest_widget_selected_background: Option<String>,
+    #[serde(rename = "editorHoverWidget.background")]
+    pub editor_hover_widget_background: Option<String>,
+    #[serde(rename = "editorHoverWidget.border")]
+    pub editor_hover_widget_border: Option<String>,
+    #[serde(rename = "editorMarkerNavigation.background")]
+    pub editor_marker_navigation_background: Option<String>,
+    #[serde(rename = "peekView.border")]
+    pub peek_view_border: Option<String>,
+    #[serde(rename = "peekViewEditor.background")]
+    pub peek_view_editor_background: Option<String>,
+    #[serde(rename = "peekViewEditor.matchHighlightBackground")]
+    pub peek_view_editor_match_highlight_background: Option<String>,
+    #[serde(rename = "peekViewResult.background")]
+    pub peek_view_result_background: Option<String>,
+    #[serde(rename = "peekViewResult.fileForeground")]
+    pub peek_view_result_file_foreground: Option<String>,
+    #[serde(rename = "peekViewResult.lineForeground")]
+    pub peek_view_result_line_foreground: Option<String>,
+    #[serde(rename = "peekViewResult.matchHighlightBackground")]
+    pub peek_view_result_match_highlight_background: Option<String>,
+    #[serde(rename = "peekViewResult.selectionBackground")]
+    pub peek_view_result_selection_background: Option<String>,
+    #[serde(rename = "peekViewResult.selectionForeground")]
+    pub peek_view_result_selection_foreground: Option<String>,
+    #[serde(rename = "peekViewTitle.background")]
+    pub peek_view_title_background: Option<String>,
+    #[serde(rename = "peekViewTitleDescription.foreground")]
+    pub peek_view_title_description_foreground: Option<String>,
+    #[serde(rename = "peekViewTitleLabel.foreground")]
+    pub peek_view_title_label_foreground: Option<String>,
+    #[serde(rename = "merge.currentHeaderBackground")]
+    pub merge_current_header_background: Option<String>,
+    #[serde(rename = "merge.incomingHeaderBackground")]
+    pub merge_incoming_header_background: Option<String>,
+    #[serde(rename = "editorOverviewRuler.currentContentForeground")]
+    pub editor_overview_ruler_current_content_foreground: Option<String>,
+    #[serde(rename = "editorOverviewRuler.incomingContentForeground")]
+    pub editor_overview_ruler_incoming_content_foreground: Option<String>,
+    #[serde(rename = "panel.background")]
+    pub panel_background: Option<String>,
+    #[serde(rename = "panel.border")]
+    pub panel_border: Option<String>,
+    #[serde(rename = "panelTitle.activeBorder")]
+    pub panel_title_active_border: Option<String>,
+    #[serde(rename = "panelTitle.activeForeground")]
+    pub panel_title_active_foreground: Option<String>,
+    #[serde(rename = "panelTitle.inactiveForeground")]
+    pub panel_title_inactive_foreground: Option<String>,
+    #[serde(rename = "statusBar.background")]
+    pub status_bar_background: Option<String>,
+    #[serde(rename = "statusBar.foreground")]
+    pub status_bar_foreground: Option<String>,
+    #[serde(rename = "statusBar.debuggingBackground")]
+    pub status_bar_debugging_background: Option<String>,
+    #[serde(rename = "statusBar.debuggingForeground")]
+    pub status_bar_debugging_foreground: Option<String>,
+    #[serde(rename = "statusBar.noFolderBackground")]
+    pub status_bar_no_folder_background: Option<String>,
+    #[serde(rename = "statusBar.noFolderForeground")]
+    pub status_bar_no_folder_foreground: Option<String>,
+    #[serde(rename = "statusBarItem.prominentBackground")]
+    pub status_bar_item_prominent_background: Option<String>,
+    #[serde(rename = "statusBarItem.prominentHoverBackground")]
+    pub status_bar_item_prominent_hover_background: Option<String>,
+    #[serde(rename = "statusBarItem.remoteForeground")]
+    pub status_bar_item_remote_foreground: Option<String>,
+    #[serde(rename = "statusBarItem.remoteBackground")]
+    pub status_bar_item_remote_background: Option<String>,
+    #[serde(rename = "titleBar.activeBackground")]
+    pub title_bar_active_background: Option<String>,
+    #[serde(rename = "titleBar.activeForeground")]
+    pub title_bar_active_foreground: Option<String>,
+    #[serde(rename = "titleBar.inactiveBackground")]
+    pub title_bar_inactive_background: Option<String>,
+    #[serde(rename = "titleBar.inactiveForeground")]
+    pub title_bar_inactive_foreground: Option<String>,
+    #[serde(rename = "extensionButton.prominentForeground")]
+    pub extension_button_prominent_foreground: Option<String>,
+    #[serde(rename = "extensionButton.prominentBackground")]
+    pub extension_button_prominent_background: Option<String>,
+    #[serde(rename = "extensionButton.prominentHoverBackground")]
+    pub extension_button_prominent_hover_background: Option<String>,
+    #[serde(rename = "pickerGroup.border")]
+    pub picker_group_border: Option<String>,
+    #[serde(rename = "pickerGroup.foreground")]
+    pub picker_group_foreground: Option<String>,
+    #[serde(rename = "debugToolBar.background")]
+    pub debug_tool_bar_background: Option<String>,
+    #[serde(rename = "walkThrough.embeddedEditorBackground")]
+    pub walk_through_embedded_editor_background: Option<String>,
+    #[serde(rename = "settings.headerForeground")]
+    pub settings_header_foreground: Option<String>,
+    #[serde(rename = "settings.modifiedItemIndicator")]
+    pub settings_modified_item_indicator: Option<String>,
+    #[serde(rename = "settings.dropdownBackground")]
+    pub settings_dropdown_background: Option<String>,
+    #[serde(rename = "settings.dropdownForeground")]
+    pub settings_dropdown_foreground: Option<String>,
+    #[serde(rename = "settings.dropdownBorder")]
+    pub settings_dropdown_border: Option<String>,
+    #[serde(rename = "settings.checkboxBackground")]
+    pub settings_checkbox_background: Option<String>,
+    #[serde(rename = "settings.checkboxForeground")]
+    pub settings_checkbox_foreground: Option<String>,
+    #[serde(rename = "settings.checkboxBorder")]
+    pub settings_checkbox_border: Option<String>,
+    #[serde(rename = "settings.textInputBackground")]
+    pub settings_text_input_background: Option<String>,
+    #[serde(rename = "settings.textInputForeground")]
+    pub settings_text_input_foreground: Option<String>,
+    #[serde(rename = "settings.textInputBorder")]
+    pub settings_text_input_border: Option<String>,
+    #[serde(rename = "settings.numberInputBackground")]
+    pub settings_number_input_background: Option<String>,
+    #[serde(rename = "settings.numberInputForeground")]
+    pub settings_number_input_foreground: Option<String>,
+    #[serde(rename = "settings.numberInputBorder")]
+    pub settings_number_input_border: Option<String>,
+    #[serde(rename = "breadcrumb.foreground")]
+    pub breadcrumb_foreground: Option<String>,
+    #[serde(rename = "breadcrumb.background")]
+    pub breadcrumb_background: Option<String>,
+    #[serde(rename = "breadcrumb.focusForeground")]
+    pub breadcrumb_focus_foreground: Option<String>,
+    #[serde(rename = "breadcrumb.activeSelectionForeground")]
+    pub breadcrumb_active_selection_foreground: Option<String>,
+    #[serde(rename = "breadcrumbPicker.background")]
+    pub breadcrumb_picker_background: Option<String>,
+    #[serde(rename = "listFilterWidget.background")]
+    pub list_filter_widget_background: Option<String>,
+    #[serde(rename = "listFilterWidget.outline")]
+    pub list_filter_widget_outline: Option<String>,
+    #[serde(rename = "listFilterWidget.noMatchesOutline")]
+    pub list_filter_widget_no_matches_outline: Option<String>,
+}

crates/ui2/src/components.rs πŸ”—

@@ -3,6 +3,7 @@ mod button;
 mod checkbox;
 mod context_menu;
 mod details;
+mod divider;
 mod elevated_surface;
 mod facepile;
 mod icon;
@@ -31,6 +32,7 @@ pub use button::*;
 pub use checkbox::*;
 pub use context_menu::*;
 pub use details::*;
+pub use divider::*;
 pub use elevated_surface::*;
 pub use facepile::*;
 pub use icon::*;

crates/ui2/src/components/divider.rs πŸ”—

@@ -0,0 +1,46 @@
+use crate::prelude::*;
+
+enum DividerDirection {
+    Horizontal,
+    Vertical,
+}
+
+#[derive(Component)]
+pub struct Divider {
+    direction: DividerDirection,
+    inset: bool,
+}
+
+impl Divider {
+    pub fn horizontal() -> Self {
+        Self {
+            direction: DividerDirection::Horizontal,
+            inset: false,
+        }
+    }
+
+    pub fn vertical() -> Self {
+        Self {
+            direction: DividerDirection::Vertical,
+            inset: false,
+        }
+    }
+
+    pub fn inset(mut self) -> Self {
+        self.inset = true;
+        self
+    }
+
+    fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
+        div()
+            .map(|this| match self.direction {
+                DividerDirection::Horizontal => {
+                    this.h_px().w_full().when(self.inset, |this| this.mx_1p5())
+                }
+                DividerDirection::Vertical => {
+                    this.w_px().h_full().when(self.inset, |this| this.my_1p5())
+                }
+            })
+            .bg(cx.theme().colors().border_variant)
+    }
+}

crates/ui2/src/components/elevated_surface.rs πŸ”—

@@ -24,5 +24,5 @@ pub fn elevated_surface<V: 'static>(level: ElevationIndex, cx: &mut ViewContext<
 }
 
 pub fn modal<V>(cx: &mut ViewContext<V>) -> Div<V> {
-    elevated_surface(ElevationIndex::ModalSurfaces, cx)
+    elevated_surface(ElevationIndex::ModalSurface, cx)
 }

crates/ui2/src/components/icon_button.rs πŸ”—

@@ -98,6 +98,7 @@ impl<V: 'static> IconButton<V> {
 
         if let Some(click_handler) = self.handlers.click.clone() {
             button = button.on_mouse_down(MouseButton::Left, move |state, event, cx| {
+                cx.stop_propagation();
                 click_handler(state, cx);
             });
         }

crates/ui2/src/components/tooltip.rs πŸ”—

@@ -1,4 +1,4 @@
-use gpui::{div, px, Div, ParentElement, Render, SharedString, Styled, ViewContext};
+use gpui::{div, Div, ParentElement, Render, SharedString, Styled, ViewContext};
 use theme2::ActiveTheme;
 
 #[derive(Clone, Debug)]
@@ -19,7 +19,7 @@ impl Render for TextTooltip {
         let theme = cx.theme();
         div()
             .bg(theme.colors().background)
-            .rounded(px(8.))
+            .rounded_lg()
             .border()
             .font("Zed Sans")
             .border_color(theme.colors().border)

crates/ui2/src/elevation.md πŸ”—

@@ -34,9 +34,9 @@ Material Design 3 has a some great visualizations of elevation that may be helpf
 
 The app background constitutes the lowest elevation layer, appearing behind all other surfaces and components. It is predominantly used for the background color of the app.
 
-### UI Surface
+### Surface
 
-The UI Surface, located above the app background, is the standard level for all elements
+The Surface elevation level, located above the app background, is the standard level for all elements
 
 Example Elements: Title Bar, Panel, Tab Bar, Editor
 

crates/ui2/src/elevation.rs πŸ”—

@@ -11,43 +11,53 @@ pub enum Elevation {
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
 pub enum ElevationIndex {
-    AppBackground,
-    UISurface,
+    Background,
+    Surface,
     ElevatedSurface,
     Wash,
-    ModalSurfaces,
+    ModalSurface,
     DraggedElement,
 }
 
 impl ElevationIndex {
     pub fn z_index(self) -> u32 {
         match self {
-            ElevationIndex::AppBackground => 0,
-            ElevationIndex::UISurface => 100,
+            ElevationIndex::Background => 0,
+            ElevationIndex::Surface => 100,
             ElevationIndex::ElevatedSurface => 200,
             ElevationIndex::Wash => 300,
-            ElevationIndex::ModalSurfaces => 400,
+            ElevationIndex::ModalSurface => 400,
             ElevationIndex::DraggedElement => 900,
         }
     }
 
     pub fn shadow(self) -> SmallVec<[BoxShadow; 2]> {
         match self {
-            ElevationIndex::AppBackground => smallvec![],
+            ElevationIndex::Surface => smallvec![],
 
-            ElevationIndex::UISurface => smallvec![BoxShadow {
+            ElevationIndex::ElevatedSurface => smallvec![BoxShadow {
                 color: hsla(0., 0., 0., 0.12),
                 offset: point(px(0.), px(1.)),
                 blur_radius: px(3.),
                 spread_radius: px(0.),
             }],
 
-            _ => smallvec![BoxShadow {
-                color: hsla(0., 0., 0., 0.32),
-                offset: point(px(1.), px(3.)),
-                blur_radius: px(12.),
-                spread_radius: px(0.),
-            }],
+            ElevationIndex::ModalSurface => smallvec![
+                BoxShadow {
+                    color: hsla(0., 0., 0., 0.12),
+                    offset: point(px(0.), px(1.)),
+                    blur_radius: px(3.),
+                    spread_radius: px(0.),
+                },
+                BoxShadow {
+                    color: hsla(0., 0., 0., 0.16),
+                    offset: point(px(3.), px(1.)),
+                    blur_radius: px(12.),
+                    spread_radius: px(0.),
+                },
+            ],
+
+            _ => smallvec![],
         }
     }
 }

crates/ui2/src/styled_ext.rs πŸ”—

@@ -1,33 +1,33 @@
-use gpui::{Div, ElementFocus, ElementInteractivity, Styled};
+use gpui::{Div, ElementFocus, ElementInteractivity, Styled, UniformList, ViewContext};
+use theme2::ActiveTheme;
 
-use crate::UITextSize;
+use crate::{ElevationIndex, UITextSize};
+
+fn elevated<E: Styled, V: 'static>(this: E, cx: &mut ViewContext<V>, index: ElevationIndex) -> E {
+    this.bg(cx.theme().colors().elevated_surface_background)
+        .rounded_lg()
+        .border()
+        .border_color(cx.theme().colors().border_variant)
+        .shadow(index.shadow())
+}
 
 /// Extends [`Styled`](gpui::Styled) with Zed specific styling methods.
-pub trait StyledExt: Styled {
+pub trait StyledExt: Styled + Sized {
     /// Horizontally stacks elements.
     ///
     /// Sets `flex()`, `flex_row()`, `items_center()`
-    fn h_flex(self) -> Self
-    where
-        Self: Sized,
-    {
+    fn h_flex(self) -> Self {
         self.flex().flex_row().items_center()
     }
 
     /// Vertically stacks elements.
     ///
     /// Sets `flex()`, `flex_col()`
-    fn v_flex(self) -> Self
-    where
-        Self: Sized,
-    {
+    fn v_flex(self) -> Self {
         self.flex().flex_col()
     }
 
-    fn text_ui_size(self, size: UITextSize) -> Self
-    where
-        Self: Sized,
-    {
+    fn text_ui_size(self, size: UITextSize) -> Self {
         let size = size.rems();
 
         self.text_size(size)
@@ -40,10 +40,7 @@ pub trait StyledExt: Styled {
     /// Note: The absolute size of this text will change based on a user's `ui_scale` setting.
     ///
     /// Use [`text_ui_sm`] for regular-sized text.
-    fn text_ui(self) -> Self
-    where
-        Self: Sized,
-    {
+    fn text_ui(self) -> Self {
         let size = UITextSize::default().rems();
 
         self.text_size(size)
@@ -56,14 +53,44 @@ pub trait StyledExt: Styled {
     /// Note: The absolute size of this text will change based on a user's `ui_scale` setting.
     ///
     /// Use [`text_ui`] for regular-sized text.
-    fn text_ui_sm(self) -> Self
-    where
-        Self: Sized,
-    {
+    fn text_ui_sm(self) -> Self {
         let size = UITextSize::Small.rems();
 
         self.text_size(size)
     }
+
+    /// The [`Surface`](ui2::ElevationIndex::Surface) elevation level, located above the app background, is the standard level for all elements
+    ///
+    /// Sets `bg()`, `rounded_lg()`, `border()`, `border_color()`, `shadow()`
+    ///
+    /// Example Elements: Title Bar, Panel, Tab Bar, Editor
+    fn elevation_1<V: 'static>(self, cx: &mut ViewContext<V>) -> Self {
+        elevated(self, cx, ElevationIndex::Surface)
+    }
+
+    /// Non-Modal Elevated Surfaces appear above the [`Surface`](ui2::ElevationIndex::Surface) layer and is used for things that should appear above most UI elements like an editor or panel, but not elements like popovers, context menus, modals, etc.
+    ///
+    /// Sets `bg()`, `rounded_lg()`, `border()`, `border_color()`, `shadow()`
+    ///
+    /// Examples: Notifications, Palettes, Detached/Floating Windows, Detached/Floating Panels
+    fn elevation_2<V: 'static>(self, cx: &mut ViewContext<V>) -> Self {
+        elevated(self, cx, ElevationIndex::ElevatedSurface)
+    }
+
+    // There is no elevation 3, as the third elevation level is reserved for wash layers. See [`Elevation`](ui2::Elevation).
+
+    /// Modal Surfaces are used for elements that should appear above all other UI elements and are located above the wash layer. This is the maximum elevation at which UI elements can be rendered in their default state.
+    ///
+    /// Elements rendered at this layer should have an enforced behavior: Any interaction outside of the modal will either dismiss the modal or prompt an action (Save your progress, etc) then dismiss the modal.
+    ///
+    /// If the element does not have this behavior, it should be rendered at the [`Elevated Surface`](ui2::ElevationIndex::ElevatedSurface) layer.
+    ///
+    /// Sets `bg()`, `rounded_lg()`, `border()`, `border_color()`, `shadow()`
+    ///
+    /// Examples: Settings Modal, Channel Management, Wizards/Setup UI, Dialogs
+    fn elevation_4<V: 'static>(self, cx: &mut ViewContext<V>) -> Self {
+        elevated(self, cx, ElevationIndex::ModalSurface)
+    }
 }
 
 impl<V, I, F> StyledExt for Div<V, I, F>
@@ -72,3 +99,5 @@ where
     F: ElementFocus<V>,
 {
 }
+
+impl<V> StyledExt for UniformList<V> {}

crates/workspace2/src/modal_layer.rs πŸ”—

@@ -1,15 +1,22 @@
-use crate::Workspace;
 use gpui::{
-    div, px, AnyView, Component, Div, EventEmitter, ParentElement, Render, StatelessInteractive,
-    Styled, Subscription, View, ViewContext,
+    div, px, AnyView, Div, EventEmitter, FocusHandle, ParentElement, Render, StatelessInteractive,
+    Styled, Subscription, View, ViewContext, VisualContext, WindowContext,
 };
-use std::{any::TypeId, sync::Arc};
 use ui::v_stack;
 
+pub struct ActiveModal {
+    modal: AnyView,
+    subscription: Subscription,
+    previous_focus_handle: Option<FocusHandle>,
+    focus_handle: FocusHandle,
+}
+
 pub struct ModalLayer {
-    open_modal: Option<AnyView>,
-    subscription: Option<Subscription>,
-    registered_modals: Vec<(TypeId, Box<dyn Fn(Div<Workspace>) -> Div<Workspace>>)>,
+    active_modal: Option<ActiveModal>,
+}
+
+pub trait Modal: Render + EventEmitter<ModalEvent> {
+    fn focus(&self, cx: &mut WindowContext);
 }
 
 pub enum ModalEvent {
@@ -18,98 +25,82 @@ pub enum ModalEvent {
 
 impl ModalLayer {
     pub fn new() -> Self {
-        Self {
-            open_modal: None,
-            subscription: None,
-            registered_modals: Vec::new(),
-        }
+        Self { active_modal: None }
     }
 
-    pub fn register_modal<A: 'static, V, B>(&mut self, action: A, build_view: B)
+    pub fn toggle_modal<V, B>(&mut self, cx: &mut ViewContext<Self>, build_view: B)
     where
-        V: EventEmitter<ModalEvent> + Render,
-        B: Fn(&mut Workspace, &mut ViewContext<Workspace>) -> Option<View<V>> + 'static,
+        V: Modal,
+        B: FnOnce(&mut ViewContext<V>) -> V,
     {
-        let build_view = Arc::new(build_view);
-
-        self.registered_modals.push((
-            TypeId::of::<A>(),
-            Box::new(move |mut div| {
-                let build_view = build_view.clone();
-
-                div.on_action(move |workspace, event: &A, cx| {
-                    let Some(new_modal) = (build_view)(workspace, cx) else {
-                        return;
-                    };
-                    workspace.modal_layer().show_modal(new_modal, cx);
-                })
-            }),
-        ));
+        let previous_focus = cx.focused();
+
+        if let Some(active_modal) = &self.active_modal {
+            let is_close = active_modal.modal.clone().downcast::<V>().is_ok();
+            self.hide_modal(cx);
+            if is_close {
+                return;
+            }
+        }
+        let new_modal = cx.build_view(build_view);
+        self.show_modal(new_modal, cx);
     }
 
-    pub fn show_modal<V>(&mut self, new_modal: View<V>, cx: &mut ViewContext<Workspace>)
+    pub fn show_modal<V>(&mut self, new_modal: View<V>, cx: &mut ViewContext<Self>)
     where
-        V: EventEmitter<ModalEvent> + Render,
+        V: Modal,
     {
-        self.subscription = Some(cx.subscribe(&new_modal, |this, modal, e, cx| match e {
-            ModalEvent::Dismissed => this.modal_layer().hide_modal(cx),
-        }));
-        self.open_modal = Some(new_modal.into());
-        cx.notify();
-    }
-
-    pub fn hide_modal(&mut self, cx: &mut ViewContext<Workspace>) {
-        self.open_modal.take();
-        self.subscription.take();
+        self.active_modal = Some(ActiveModal {
+            modal: new_modal.clone().into(),
+            subscription: cx.subscribe(&new_modal, |this, modal, e, cx| match e {
+                ModalEvent::Dismissed => this.hide_modal(cx),
+            }),
+            previous_focus_handle: cx.focused(),
+            focus_handle: cx.focus_handle(),
+        });
+        new_modal.update(cx, |modal, cx| modal.focus(cx));
         cx.notify();
     }
 
-    pub fn wrapper_element(&self, cx: &ViewContext<Workspace>) -> Div<Workspace> {
-        let mut parent = div().relative().size_full();
-
-        for (_, action) in self.registered_modals.iter() {
-            parent = (action)(parent);
+    pub fn hide_modal(&mut self, cx: &mut ViewContext<Self>) {
+        if let Some(active_modal) = self.active_modal.take() {
+            if let Some(previous_focus) = active_modal.previous_focus_handle {
+                if active_modal.focus_handle.contains_focused(cx) {
+                    previous_focus.focus(cx);
+                }
+            }
         }
 
-        parent.when_some(self.open_modal.as_ref(), |parent, open_modal| {
-            let container1 = div()
-                .absolute()
-                .flex()
-                .flex_col()
-                .items_center()
-                .size_full()
-                .top_0()
-                .left_0()
-                .z_index(400);
-
-            // transparent layer
-            let container2 = v_stack().h(px(0.0)).relative().top_20();
-
-            parent.child(container1.child(container2.child(open_modal.clone())))
-        })
+        cx.notify();
     }
 }
 
-// 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
-//     }
-// }
+impl Render for ModalLayer {
+    type Element = Div<Self>;
+
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
+        let Some(active_modal) = &self.active_modal else {
+            return div();
+        };
+
+        div()
+            .absolute()
+            .flex()
+            .flex_col()
+            .items_center()
+            .size_full()
+            .top_0()
+            .left_0()
+            .z_index(400)
+            .child(
+                v_stack()
+                    .h(px(0.0))
+                    .top_20()
+                    .track_focus(&active_modal.focus_handle)
+                    .on_mouse_down_out(|this: &mut Self, event, cx| {
+                        this.hide_modal(cx);
+                    })
+                    .child(active_modal.modal.clone()),
+            )
+    }
+}

crates/workspace2/src/workspace2.rs πŸ”—

@@ -36,11 +36,12 @@ use futures::{
     Future, FutureExt, StreamExt,
 };
 use gpui::{
-    actions, div, point, rems, size, AnyModel, AnyView, AnyWeakView, AppContext, AsyncAppContext,
-    AsyncWindowContext, Bounds, Component, Div, Entity, EntityId, EventEmitter, FocusHandle,
-    GlobalPixels, Model, ModelContext, ParentElement, Point, Render, Size, StatefulInteractive,
-    Styled, Subscription, Task, View, ViewContext, VisualContext, WeakView, WindowBounds,
-    WindowContext, WindowHandle, WindowOptions,
+    actions, div, point, rems, size, Action, AnyModel, AnyView, AnyWeakView, AppContext,
+    AsyncAppContext, AsyncWindowContext, Bounds, Component, DispatchContext, Div, Entity, EntityId,
+    EventEmitter, FocusHandle, GlobalPixels, Model, ModelContext, ParentElement, Point, Render,
+    Size, StatefulInteractive, StatefulInteractivity, StatelessInteractive, Styled, Subscription,
+    Task, View, ViewContext, VisualContext, WeakView, WindowBounds, WindowContext, WindowHandle,
+    WindowOptions,
 };
 use item::{FollowableItem, FollowableItemHandle, Item, ItemHandle, ItemSettings, ProjectItem};
 use itertools::Itertools;
@@ -530,6 +531,13 @@ pub enum Event {
 pub struct Workspace {
     weak_self: WeakView<Self>,
     focus_handle: FocusHandle,
+    workspace_actions: Vec<
+        Box<
+            dyn Fn(
+                Div<Workspace, StatefulInteractivity<Workspace>>,
+            ) -> Div<Workspace, StatefulInteractivity<Workspace>>,
+        >,
+    >,
     zoomed: Option<AnyWeakView>,
     zoomed_position: Option<DockPosition>,
     center: PaneGroup,
@@ -542,7 +550,7 @@ pub struct Workspace {
     last_active_center_pane: Option<WeakView<Pane>>,
     last_active_view_id: Option<proto::ViewId>,
     status_bar: View<StatusBar>,
-    modal_layer: ModalLayer,
+    modal_layer: View<ModalLayer>,
     //     titlebar_item: Option<AnyViewHandle>,
     notifications: Vec<(TypeId, usize, Box<dyn NotificationHandle>)>,
     project: Model<Project>,
@@ -694,7 +702,7 @@ impl Workspace {
         });
 
         let workspace_handle = cx.view().downgrade();
-        let modal_layer = ModalLayer::new();
+        let modal_layer = cx.build_view(|cx| ModalLayer::new());
 
         // todo!()
         // cx.update_default_global::<DragAndDrop<Workspace>, _, _>(|drag_and_drop, _| {
@@ -775,13 +783,10 @@ impl Workspace {
             leader_updates_tx,
             subscriptions,
             pane_history_timestamp,
+            workspace_actions: Default::default(),
         }
     }
 
-    pub fn modal_layer(&mut self) -> &mut ModalLayer {
-        &mut self.modal_layer
-    }
-
     fn new_local(
         abs_paths: Vec<PathBuf>,
         app_state: Arc<AppState>,
@@ -3495,6 +3500,35 @@ impl Workspace {
     //         )
     //     }
     // }
+    pub fn register_action<A: Action>(
+        &mut self,
+        callback: impl Fn(&mut Self, &A, &mut ViewContext<Self>) + 'static,
+    ) {
+        let callback = Arc::new(callback);
+
+        self.workspace_actions.push(Box::new(move |div| {
+            let callback = callback.clone();
+            div.on_action(move |workspace, event, cx| (callback.clone())(workspace, event, cx))
+        }));
+    }
+
+    fn add_workspace_actions_listeners(
+        &self,
+        mut div: Div<Workspace, StatefulInteractivity<Workspace>>,
+    ) -> Div<Workspace, StatefulInteractivity<Workspace>> {
+        for action in self.workspace_actions.iter() {
+            div = (action)(div)
+        }
+        div
+    }
+
+    pub fn toggle_modal<V: Modal, B>(&mut self, cx: &mut ViewContext<Self>, build: B)
+    where
+        B: FnOnce(&mut ViewContext<V>) -> V,
+    {
+        self.modal_layer
+            .update(cx, |modal_layer, cx| modal_layer.toggle_modal(cx, build))
+    }
 }
 
 fn window_bounds_env_override(cx: &AsyncAppContext) -> Option<WindowBounds> {
@@ -3709,157 +3743,160 @@ impl Render for Workspace {
     type Element = Div<Self>;
 
     fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
-        div()
-            .relative()
-            .size_full()
-            .flex()
-            .flex_col()
-            .font("Zed Sans")
-            .gap_0()
-            .justify_start()
-            .items_start()
-            .text_color(cx.theme().colors().text)
-            .bg(cx.theme().colors().background)
-            .child(self.render_titlebar(cx))
-            .child(
-                // todo! should this be a component a view?
-                self.modal_layer
-                    .wrapper_element(cx)
-                    .relative()
-                    .flex_1()
-                    .w_full()
-                    .flex()
-                    .overflow_hidden()
-                    .border_t()
-                    .border_b()
-                    .border_color(cx.theme().colors().border)
-                    // .children(
-                    //     Some(
-                    //         Panel::new("project-panel-outer", cx)
-                    //             .side(PanelSide::Left)
-                    //             .child(ProjectPanel::new("project-panel-inner")),
-                    //     )
-                    //     .filter(|_| self.is_project_panel_open()),
-                    // )
-                    // .children(
-                    //     Some(
-                    //         Panel::new("collab-panel-outer", cx)
-                    //             .child(CollabPanel::new("collab-panel-inner"))
-                    //             .side(PanelSide::Left),
-                    //     )
-                    //     .filter(|_| self.is_collab_panel_open()),
-                    // )
-                    // .child(NotificationToast::new(
-                    //     "maxbrunsfeld has requested to add you as a contact.".into(),
-                    // ))
-                    .child(
-                        div().flex().flex_col().flex_1().h_full().child(
-                            div().flex().flex_1().child(self.center.render(
-                                &self.project,
-                                &self.follower_states,
-                                self.active_call(),
-                                &self.active_pane,
-                                self.zoomed.as_ref(),
-                                &self.app_state,
-                                cx,
-                            )),
+        let mut context = DispatchContext::default();
+        context.insert("Workspace");
+        cx.with_key_dispatch_context(context, |cx| {
+            div()
+                .relative()
+                .size_full()
+                .flex()
+                .flex_col()
+                .font("Zed Sans")
+                .gap_0()
+                .justify_start()
+                .items_start()
+                .text_color(cx.theme().colors().text)
+                .bg(cx.theme().colors().background)
+                .child(self.render_titlebar(cx))
+                .child(
+                    // todo! should this be a component a view?
+                    self.add_workspace_actions_listeners(div().id("workspace"))
+                        .relative()
+                        .flex_1()
+                        .w_full()
+                        .flex()
+                        .overflow_hidden()
+                        .border_t()
+                        .border_b()
+                        .border_color(cx.theme().colors().border)
+                        .child(self.modal_layer.clone())
+                        // .children(
+                        //     Some(
+                        //         Panel::new("project-panel-outer", cx)
+                        //             .side(PanelSide::Left)
+                        //             .child(ProjectPanel::new("project-panel-inner")),
+                        //     )
+                        //     .filter(|_| self.is_project_panel_open()),
+                        // )
+                        // .children(
+                        //     Some(
+                        //         Panel::new("collab-panel-outer", cx)
+                        //             .child(CollabPanel::new("collab-panel-inner"))
+                        //             .side(PanelSide::Left),
+                        //     )
+                        //     .filter(|_| self.is_collab_panel_open()),
+                        // )
+                        // .child(NotificationToast::new(
+                        //     "maxbrunsfeld has requested to add you as a contact.".into(),
+                        // ))
+                        .child(
+                            div().flex().flex_col().flex_1().h_full().child(
+                                div().flex().flex_1().child(self.center.render(
+                                    &self.project,
+                                    &self.follower_states,
+                                    self.active_call(),
+                                    &self.active_pane,
+                                    self.zoomed.as_ref(),
+                                    &self.app_state,
+                                    cx,
+                                )),
+                            ), // .children(
+                               //     Some(
+                               //         Panel::new("terminal-panel", cx)
+                               //             .child(Terminal::new())
+                               //             .allowed_sides(PanelAllowedSides::BottomOnly)
+                               //             .side(PanelSide::Bottom),
+                               //     )
+                               //     .filter(|_| self.is_terminal_open()),
+                               // ),
                         ), // .children(
                            //     Some(
-                           //         Panel::new("terminal-panel", cx)
-                           //             .child(Terminal::new())
-                           //             .allowed_sides(PanelAllowedSides::BottomOnly)
-                           //             .side(PanelSide::Bottom),
+                           //         Panel::new("chat-panel-outer", cx)
+                           //             .side(PanelSide::Right)
+                           //             .child(ChatPanel::new("chat-panel-inner").messages(vec![
+                           //                 ChatMessage::new(
+                           //                     "osiewicz".to_string(),
+                           //                     "is this thing on?".to_string(),
+                           //                     DateTime::parse_from_rfc3339("2023-09-27T15:40:52.707Z")
+                           //                         .unwrap()
+                           //                         .naive_local(),
+                           //                 ),
+                           //                 ChatMessage::new(
+                           //                     "maxdeviant".to_string(),
+                           //                     "Reading you loud and clear!".to_string(),
+                           //                     DateTime::parse_from_rfc3339("2023-09-28T15:40:52.707Z")
+                           //                         .unwrap()
+                           //                         .naive_local(),
+                           //                 ),
+                           //             ])),
+                           //     )
+                           //     .filter(|_| self.is_chat_panel_open()),
+                           // )
+                           // .children(
+                           //     Some(
+                           //         Panel::new("notifications-panel-outer", cx)
+                           //             .side(PanelSide::Right)
+                           //             .child(NotificationsPanel::new("notifications-panel-inner")),
+                           //     )
+                           //     .filter(|_| self.is_notifications_panel_open()),
+                           // )
+                           // .children(
+                           //     Some(
+                           //         Panel::new("assistant-panel-outer", cx)
+                           //             .child(AssistantPanel::new("assistant-panel-inner")),
                            //     )
-                           //     .filter(|_| self.is_terminal_open()),
+                           //     .filter(|_| self.is_assistant_panel_open()),
                            // ),
-                    ), // .children(
-                       //     Some(
-                       //         Panel::new("chat-panel-outer", cx)
-                       //             .side(PanelSide::Right)
-                       //             .child(ChatPanel::new("chat-panel-inner").messages(vec![
-                       //                 ChatMessage::new(
-                       //                     "osiewicz".to_string(),
-                       //                     "is this thing on?".to_string(),
-                       //                     DateTime::parse_from_rfc3339("2023-09-27T15:40:52.707Z")
-                       //                         .unwrap()
-                       //                         .naive_local(),
-                       //                 ),
-                       //                 ChatMessage::new(
-                       //                     "maxdeviant".to_string(),
-                       //                     "Reading you loud and clear!".to_string(),
-                       //                     DateTime::parse_from_rfc3339("2023-09-28T15:40:52.707Z")
-                       //                         .unwrap()
-                       //                         .naive_local(),
-                       //                 ),
-                       //             ])),
-                       //     )
-                       //     .filter(|_| self.is_chat_panel_open()),
-                       // )
-                       // .children(
-                       //     Some(
-                       //         Panel::new("notifications-panel-outer", cx)
-                       //             .side(PanelSide::Right)
-                       //             .child(NotificationsPanel::new("notifications-panel-inner")),
-                       //     )
-                       //     .filter(|_| self.is_notifications_panel_open()),
-                       // )
-                       // .children(
-                       //     Some(
-                       //         Panel::new("assistant-panel-outer", cx)
-                       //             .child(AssistantPanel::new("assistant-panel-inner")),
-                       //     )
-                       //     .filter(|_| self.is_assistant_panel_open()),
-                       // ),
-            )
-            .child(self.status_bar.clone())
-            // .when(self.debug.show_toast, |this| {
-            //     this.child(Toast::new(ToastOrigin::Bottom).child(Label::new("A toast")))
-            // })
-            // .children(
-            //     Some(
-            //         div()
-            //             .absolute()
-            //             .top(px(50.))
-            //             .left(px(640.))
-            //             .z_index(8)
-            //             .child(LanguageSelector::new("language-selector")),
-            //     )
-            //     .filter(|_| self.is_language_selector_open()),
-            // )
-            .z_index(8)
-            // Debug
-            .child(
-                div()
-                    .flex()
-                    .flex_col()
-                    .z_index(9)
-                    .absolute()
-                    .top_20()
-                    .left_1_4()
-                    .w_40()
-                    .gap_2(), // .when(self.show_debug, |this| {
-                              //     this.child(Button::<Workspace>::new("Toggle User Settings").on_click(
-                              //         Arc::new(|workspace, cx| workspace.debug_toggle_user_settings(cx)),
-                              //     ))
-                              //     .child(
-                              //         Button::<Workspace>::new("Toggle Toasts").on_click(Arc::new(
-                              //             |workspace, cx| workspace.debug_toggle_toast(cx),
-                              //         )),
-                              //     )
-                              //     .child(
-                              //         Button::<Workspace>::new("Toggle Livestream").on_click(Arc::new(
-                              //             |workspace, cx| workspace.debug_toggle_livestream(cx),
-                              //         )),
-                              //     )
-                              // })
-                              // .child(
-                              //     Button::<Workspace>::new("Toggle Debug")
-                              //         .on_click(Arc::new(|workspace, cx| workspace.toggle_debug(cx))),
-                              // ),
-            )
+                )
+                .child(self.status_bar.clone())
+                // .when(self.debug.show_toast, |this| {
+                //     this.child(Toast::new(ToastOrigin::Bottom).child(Label::new("A toast")))
+                // })
+                // .children(
+                //     Some(
+                //         div()
+                //             .absolute()
+                //             .top(px(50.))
+                //             .left(px(640.))
+                //             .z_index(8)
+                //             .child(LanguageSelector::new("language-selector")),
+                //     )
+                //     .filter(|_| self.is_language_selector_open()),
+                // )
+                .z_index(8)
+                // Debug
+                .child(
+                    div()
+                        .flex()
+                        .flex_col()
+                        .z_index(9)
+                        .absolute()
+                        .top_20()
+                        .left_1_4()
+                        .w_40()
+                        .gap_2(), // .when(self.show_debug, |this| {
+                                  //     this.child(Button::<Workspace>::new("Toggle User Settings").on_click(
+                                  //         Arc::new(|workspace, cx| workspace.debug_toggle_user_settings(cx)),
+                                  //     ))
+                                  //     .child(
+                                  //         Button::<Workspace>::new("Toggle Toasts").on_click(Arc::new(
+                                  //             |workspace, cx| workspace.debug_toggle_toast(cx),
+                                  //         )),
+                                  //     )
+                                  //     .child(
+                                  //         Button::<Workspace>::new("Toggle Livestream").on_click(Arc::new(
+                                  //             |workspace, cx| workspace.debug_toggle_livestream(cx),
+                                  //         )),
+                                  //     )
+                                  // })
+                                  // .child(
+                                  //     Button::<Workspace>::new("Toggle Debug")
+                                  //         .on_click(Arc::new(|workspace, cx| workspace.toggle_debug(cx))),
+                                  // ),
+                )
+        })
     }
 }
-
 // todo!()
 // impl Entity for Workspace {
 //     type Event = Event;

crates/zed/src/languages/typescript.rs πŸ”—

@@ -2,6 +2,7 @@ use anyhow::{anyhow, Result};
 use async_compression::futures::bufread::GzipDecoder;
 use async_tar::Archive;
 use async_trait::async_trait;
+use collections::HashMap;
 use futures::{future::BoxFuture, FutureExt};
 use gpui::AppContext;
 use language::{LanguageServerName, LspAdapter, LspAdapterDelegate};
@@ -20,12 +21,7 @@ use util::{fs::remove_matching, github::latest_github_release};
 use util::{github::GitHubLspBinaryVersion, ResultExt};
 
 fn typescript_server_binary_arguments(server_path: &Path) -> Vec<OsString> {
-    vec![
-        server_path.into(),
-        "--stdio".into(),
-        "--tsserver-path".into(),
-        "node_modules/typescript/lib".into(),
-    ]
+    vec![server_path.into(), "--stdio".into()]
 }
 
 fn eslint_server_binary_arguments(server_path: &Path) -> Vec<OsString> {
@@ -158,9 +154,20 @@ impl LspAdapter for TypeScriptLspAdapter {
 
     async fn initialization_options(&self) -> Option<serde_json::Value> {
         Some(json!({
-            "provideFormatter": true
+            "provideFormatter": true,
+            "tsserver": {
+                "path": "node_modules/typescript/lib",
+            },
         }))
     }
+
+    async fn language_ids(&self) -> HashMap<String, String> {
+        HashMap::from_iter([
+            ("TypeScript".into(), "typescript".into()),
+            ("JavaScript".into(), "javascript".into()),
+            ("TSX".into(), "typescriptreact".into()),
+        ])
+    }
 }
 
 async fn get_cached_ts_server_binary(

crates/zed2/Cargo.toml πŸ”—

@@ -25,7 +25,7 @@ call = { package = "call2", path = "../call2" }
 cli = { path = "../cli" }
 # collab_ui = { path = "../collab_ui" }
 collections = { path = "../collections" }
-# command_palette = { path = "../command_palette" }
+command_palette = { package="command_palette2", path = "../command_palette2" }
 # component_test = { path = "../component_test" }
 # context_menu = { path = "../context_menu" }
 client = { package = "client2", path = "../client2" }
@@ -74,7 +74,7 @@ util = { path = "../util" }
 # vim = { path = "../vim" }
 workspace = { package = "workspace2", path = "../workspace2" }
 # welcome = { path = "../welcome" }
-# zed-actions = {path = "../zed-actions"}
+zed_actions = {package = "zed_actions2", path = "../zed_actions2"}
 anyhow.workspace = true
 async-compression = { version = "0.3", features = ["gzip", "futures-bufread"] }
 async-tar = "0.4.2"

crates/zed2/src/languages/typescript.rs πŸ”—

@@ -2,6 +2,7 @@ use anyhow::{anyhow, Result};
 use async_compression::futures::bufread::GzipDecoder;
 use async_tar::Archive;
 use async_trait::async_trait;
+use collections::HashMap;
 use futures::{future::BoxFuture, FutureExt};
 use gpui::AppContext;
 use language::{LanguageServerName, LspAdapter, LspAdapterDelegate};
@@ -20,12 +21,7 @@ use util::{fs::remove_matching, github::latest_github_release};
 use util::{github::GitHubLspBinaryVersion, ResultExt};
 
 fn typescript_server_binary_arguments(server_path: &Path) -> Vec<OsString> {
-    vec![
-        server_path.into(),
-        "--stdio".into(),
-        "--tsserver-path".into(),
-        "node_modules/typescript/lib".into(),
-    ]
+    vec![server_path.into(), "--stdio".into()]
 }
 
 fn eslint_server_binary_arguments(server_path: &Path) -> Vec<OsString> {
@@ -158,9 +154,20 @@ impl LspAdapter for TypeScriptLspAdapter {
 
     async fn initialization_options(&self) -> Option<serde_json::Value> {
         Some(json!({
-            "provideFormatter": true
+            "provideFormatter": true,
+            "tsserver": {
+                "path": "node_modules/typescript/lib",
+            },
         }))
     }
+
+    async fn language_ids(&self) -> HashMap<String, String> {
+        HashMap::from_iter([
+            ("TypeScript".into(), "typescript".into()),
+            ("JavaScript".into(), "javascript".into()),
+            ("TSX".into(), "typescriptreact".into()),
+        ])
+    }
 }
 
 async fn get_cached_ts_server_binary(

crates/zed2/src/main.rs πŸ”—

@@ -142,7 +142,7 @@ fn main() {
         // context_menu::init(cx);
         project::Project::init(&client, cx);
         client::init(&client, cx);
-        // command_palette::init(cx);
+        command_palette::init(cx);
         language::init(cx);
         editor::init(cx);
         copilot::init(
@@ -760,7 +760,7 @@ fn load_embedded_fonts(cx: &AppContext) {
 // #[cfg(not(debug_assertions))]
 // async fn watch_languages(_: Arc<dyn Fs>, _: Arc<LanguageRegistry>) -> Option<()> {
 //     None
-// }
+//
 
 // #[cfg(not(debug_assertions))]
 // fn watch_file_types(_fs: Arc<dyn Fs>, _cx: &mut AppContext) {}

crates/zed_actions2/Cargo.toml πŸ”—

@@ -0,0 +1,11 @@
+[package]
+name = "zed_actions2"
+version = "0.1.0"
+edition = "2021"
+publish = false
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+gpui = { package = "gpui2", path = "../gpui2" }
+serde.workspace = true

crates/zed_actions2/src/lib.rs πŸ”—

@@ -0,0 +1,34 @@
+use gpui::{action, actions};
+
+actions!(
+    About,
+    DebugElements,
+    DecreaseBufferFontSize,
+    Hide,
+    HideOthers,
+    IncreaseBufferFontSize,
+    Minimize,
+    OpenDefaultKeymap,
+    OpenDefaultSettings,
+    OpenKeymap,
+    OpenLicenses,
+    OpenLocalSettings,
+    OpenLog,
+    OpenSettings,
+    OpenTelemetryLog,
+    Quit,
+    ResetBufferFontSize,
+    ResetDatabase,
+    ShowAll,
+    ToggleFullScreen,
+    Zoom,
+);
+
+#[action]
+pub struct OpenBrowser {
+    pub url: String,
+}
+#[action]
+pub struct OpenZedURL {
+    pub url: String,
+}

script/eula/eula.md πŸ”—

@@ -40,7 +40,7 @@ Customer Data consisting of non-personally-identifiable information that helps Z
 
 ##### 3.3.1.2. Crash Reports
 
-Customer Data consisting of data related to the behavior of the Solution prior to a crash or failure, such as stack traces are collected and classified as " Crash Reports". Zed will use commercially reasonable efforts to exclude any personally identifiable information from Crash Reports, but due to the nature of a crash, Zed does not ensure that information such as paths will be excluded from Crash Reports. Crash Reports will be used solely for Zed's internal purposes in connection with diagnosing defects in the Solution that led to the crash. You may grant us permission to capture Crash Reports when installing or activating the Solution, and You may change Your preferences at any time in the settings feature of the Solution. Once You grant us this permission, Zed will retain the Crash Reports indefinitely.
+Customer Data consisting of data related to the behavior of the Solution prior to a crash or failure, such as stack traces are collected and classified as "Crash Reports". Zed will use commercially reasonable efforts to exclude any personally identifiable information from Crash Reports, but due to the nature of a crash, Zed does not ensure that information such as paths will be excluded from Crash Reports. Crash Reports will be used solely for Zed's internal purposes in connection with diagnosing defects in the Solution that led to the crash. You may grant us permission to capture Crash Reports when installing or activating the Solution, and You may change Your preferences at any time in the settings feature of the Solution. Once You grant us this permission, Zed will retain the Crash Reports indefinitely.
 
 ##### 3.3.1.3. User Content
 

script/eula/eula.rtf πŸ”—

@@ -69,7 +69,7 @@
 \f0\b\fs20 \cf2 3.3.1.2. Crash Reports\
 \pard\pardeftab720\sa240\partightenfactor0
 
-\f1\b0\fs24 \cf2 Customer Data consisting of data related to the behavior of the Solution prior to a crash or failure, such as stack traces are collected and classified as " Crash Reports". Zed will use commercially reasonable efforts to exclude any personally identifiable information from Crash Reports, but due to the nature of a crash, Zed does not ensure that information such as paths will be excluded from Crash Reports. Crash Reports will be used solely for Zed's internal purposes in connection with diagnosing defects in the Solution that led to the crash. You may grant us permission to capture Crash Reports when installing or activating the Solution, and You may change Your preferences at any time in the settings feature of the Solution. Once You grant us this permission, Zed will retain the Crash Reports indefinitely.\
+\f1\b0\fs24 \cf2 Customer Data consisting of data related to the behavior of the Solution prior to a crash or failure, such as stack traces are collected and classified as "Crash Reports". Zed will use commercially reasonable efforts to exclude any personally identifiable information from Crash Reports, but due to the nature of a crash, Zed does not ensure that information such as paths will be excluded from Crash Reports. Crash Reports will be used solely for Zed's internal purposes in connection with diagnosing defects in the Solution that led to the crash. You may grant us permission to capture Crash Reports when installing or activating the Solution, and You may change Your preferences at any time in the settings feature of the Solution. Once You grant us this permission, Zed will retain the Crash Reports indefinitely.\
 \pard\pardeftab720\sa332\partightenfactor0
 
 \f0\b\fs20 \cf2 3.3.1.3. User Content\