Merge remote-tracking branch 'origin/main' into tokio

Nathan Sobo created

Change summary

Cargo.lock                                         |    3 
assets/icons/broadcast-24.svg                      |    6 
assets/icons/share.svg                             |    1 
assets/keymaps/default.json                        |   16 
assets/keymaps/vim.json                            |   28 
assets/themes/cave-dark.json                       | 1435 ++++++++++++++++
assets/themes/cave-light.json                      | 1435 ++++++++++++++++
assets/themes/dark.json                            |  137 +
assets/themes/light.json                           |  137 +
assets/themes/solarized-dark.json                  | 1435 ++++++++++++++++
assets/themes/solarized-light.json                 | 1435 ++++++++++++++++
assets/themes/sulphurpool-dark.json                | 1435 ++++++++++++++++
assets/themes/sulphurpool-light.json               | 1435 ++++++++++++++++
crates/editor/src/display_map.rs                   |   13 
crates/editor/src/editor.rs                        |   14 
crates/editor/src/element.rs                       |    2 
crates/editor/src/movement.rs                      |   62 
crates/go_to_line/src/go_to_line.rs                |   36 
crates/gpui/src/app.rs                             |   97 
crates/gpui/src/elements/container.rs              |   19 
crates/gpui/src/elements/mouse_event_handler.rs    |   38 
crates/gpui/src/platform.rs                        |    5 
crates/gpui/src/platform/mac/platform.rs           |    1 
crates/gpui/src/platform/mac/window.rs             |   37 
crates/gpui/src/platform/test.rs                   |    2 
crates/gpui/src/presenter.rs                       |   21 
crates/gpui/src/scene.rs                           |   22 
crates/language/Cargo.toml                         |    8 
crates/language/src/buffer.rs                      |   43 
crates/language/src/highlight_map.rs               |    4 
crates/language/src/language.rs                    |    4 
crates/picker/src/picker.rs                        |    2 
crates/project/src/project.rs                      |  154 +
crates/theme/src/theme.rs                          |   14 
crates/theme_selector/src/theme_selector.rs        |    7 
crates/vim/src/insert.rs                           |    2 
crates/vim/src/motion.rs                           |  144 +
crates/vim/src/normal.rs                           |  926 +++-------
crates/vim/src/normal/change.rs                    |  436 ++++
crates/vim/src/normal/delete.rs                    |  386 ++++
crates/vim/src/vim.rs                              |   10 
crates/vim/src/vim_test_context.rs                 |   77 
crates/workspace/src/workspace.rs                  |  123 
crates/zed/Cargo.toml                              |    2 
crates/zed/src/languages.rs                        |    2 
crates/zed/src/languages/c/highlights.scm          |   11 
crates/zed/src/languages/javascript/highlights.scm |    1 
crates/zed/src/languages/json/highlights.scm       |    9 
crates/zed/src/languages/markdown/highlights.scm   |    2 
crates/zed/src/languages/rust/highlights.scm       |   14 
crates/zed/src/languages/toml/highlights.scm       |   20 
crates/zed/src/languages/typescript.rs             |   51 
crates/zed/src/languages/typescript/highlights.scm |    1 
crates/zed/src/languages/typescript/outline.scm    |   10 
crates/zed/src/main.rs                             |   12 
styles/dist/solarized-dark.json                    |  567 ++++++
styles/dist/solarized-light.json                   |  567 ++++++
styles/src/buildThemes.ts                          |   11 
styles/src/styleTree/editor.ts                     |   30 
styles/src/styleTree/selectorModal.ts              |    4 
styles/src/styleTree/workspace.ts                  |   36 
styles/src/themes/base16.ts                        |  242 ++
styles/src/themes/cave.ts                          |   29 
styles/src/themes/dark.ts                          |   14 
styles/src/themes/light.ts                         |   12 
styles/src/themes/solarized.ts                     |   29 
styles/src/themes/sulphurpool.ts                   |   29 
styles/src/themes/theme.ts                         |   19 
styles/src/tokens.ts                               |    6 
styles/src/utils/snakeCase.ts                      |    2 
70 files changed, 12,344 insertions(+), 1,035 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -2588,6 +2588,7 @@ dependencies = [
  "tree-sitter",
  "tree-sitter-json 0.19.0",
  "tree-sitter-rust",
+ "tree-sitter-typescript",
  "unindent",
  "util",
 ]
@@ -5857,7 +5858,7 @@ checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9"
 
 [[package]]
 name = "zed"
-version = "0.29.0"
+version = "0.30.0"
 dependencies = [
  "anyhow",
  "assets",

assets/icons/broadcast-24.svg 🔗

@@ -1,6 +0,0 @@
-<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
-<path d="M6.87348 15.1266C4.04217 12.2953 4.04217 7.70484 6.87348 4.87354M17.1265 4.87354C19.9578 7.70484 19.9578 12.2953 17.1265 15.1266" stroke="#636B78" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
-<path d="M8.9948 13.0052C7.33507 11.3454 7.33507 8.65448 8.9948 6.99475M15.0052 6.99475C16.6649 8.65448 16.6649 11.3454 15.0052 13.0052" stroke="#636B78" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
-<path d="M12.5 10C12.5 10.2761 12.2761 10.5 12 10.5C11.7239 10.5 11.5 10.2761 11.5 10C11.5 9.72386 11.7239 9.5 12 9.5C12.2761 9.5 12.5 9.72386 12.5 10Z" stroke="#636B78" stroke-linecap="round" stroke-linejoin="round"/>
-<path d="M12 13.75V19.25" stroke="#636B78" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
-</svg>

assets/icons/share.svg 🔗

@@ -0,0 +1,3 @@
+<svg width="12" height="14" viewBox="0 0 12 14" fill="none" xmlns="http://www.w3.org/2000/svg">

assets/keymaps/default.json 🔗

@@ -210,9 +210,11 @@
             "cmd-shift-F": "project_search::Deploy",
             "cmd-k cmd-t": "theme_selector::Toggle",
             "cmd-k t": "theme_selector::Reload",
+            "cmd-k cmd-s": "zed::OpenKeymap",
             "cmd-t": "project_symbols::Toggle",
             "cmd-p": "file_finder::Toggle",
-            "cmd-shift-P": "command_palette::Toggle"
+            "cmd-shift-P": "command_palette::Toggle",
+            "cmd-shift-M": "diagnostics::Deploy"
         }
     },
     // Bindings from Sublime Text
@@ -244,6 +246,7 @@
             "cmd-k cmd-right": "workspace::ActivateNextPane"
         }
     },
+    // Bindings from Atom
     {
         "context": "Pane",
         "bindings": {
@@ -289,18 +292,13 @@
     {
         "bindings": {
             "ctrl-alt-cmd-f": "workspace::FollowNextCollaborator",
-            "cmd-alt-i": "zed::DebugElements",
-            "alt-cmd-,": "zed::OpenKeymap"
+            "cmd-alt-i": "zed::DebugElements"
         }
     },
     {
         "context": "Editor",
         "bindings": {
-            "ctrl-w": "editor::SelectLargerSyntaxNode",
-            "ctrl-shift-W": "editor::SelectSmallerSyntaxNode",
-            "alt-cmd-f": "editor::FoldSelectedRanges",
-            "alt-enter": "editor::OpenExcerpts",
-            "cmd-f10": "editor::RestartLanguageServer"
+            "alt-enter": "editor::OpenExcerpts"
         }
     },
     {
@@ -312,8 +310,6 @@
     {
         "context": "Workspace",
         "bindings": {
-            "alt-shift-D": "diagnostics::Deploy",
-            "ctrl-alt-cmd-j": "journal::NewJournalEntry",
             "cmd-1": [
                 "workspace::ToggleSidebarItemFocus",
                 {

assets/keymaps/vim.json 🔗

@@ -75,37 +75,13 @@
     {
         "context": "Editor && vim_operator == c",
         "bindings": {
-            "w": [
-                "vim::NextWordEnd",
-                {
-                    "ignorePunctuation": false
-                }
-            ],
+            "w": "vim::ChangeWord",
             "shift-W": [
-                "vim::NextWordEnd",
+                "vim::ChangeWord",
                 {
                     "ignorePunctuation": true
                 }
             ]
         }
-    },
-    {
-        "context": "Editor && vim_operator == d",
-        "bindings": {
-            "w": [
-                "vim::NextWordStart",
-                {
-                    "ignorePunctuation": false,
-                    "stopAtNewline": true
-                }
-            ],
-            "shift-W": [
-                "vim::NextWordStart",
-                {
-                    "ignorePunctuation": true,
-                    "stopAtNewline": true
-                }
-            ]
-        }
     }
 ]

assets/themes/cave-dark.json 🔗

@@ -0,0 +1,1435 @@
+{
+  "selector": {
+    "background": "#26232a",
+    "corner_radius": 8,
+    "padding": 8,
+    "item": {
+      "padding": {
+        "bottom": 4,
+        "left": 12,
+        "right": 12,
+        "top": 4
+      },
+      "corner_radius": 8,
+      "text": {
+        "family": "Zed Sans",
+        "color": "#8b8792",
+        "size": 14
+      },
+      "highlight_text": {
+        "family": "Zed Sans",
+        "color": "#576ddb",
+        "weight": "bold",
+        "size": 14
+      }
+    },
+    "active_item": {
+      "padding": {
+        "bottom": 4,
+        "left": 12,
+        "right": 12,
+        "top": 4
+      },
+      "corner_radius": 8,
+      "text": {
+        "family": "Zed Sans",
+        "color": "#e2dfe7",
+        "size": 14
+      },
+      "highlight_text": {
+        "family": "Zed Sans",
+        "color": "#576ddb",
+        "weight": "bold",
+        "size": 14
+      },
+      "background": "#5852607a"
+    },
+    "border": {
+      "color": "#19171c",
+      "width": 1
+    },
+    "empty": {
+      "text": {
+        "family": "Zed Sans",
+        "color": "#7e7887",
+        "size": 14
+      },
+      "padding": {
+        "bottom": 4,
+        "left": 12,
+        "right": 12,
+        "top": 8
+      }
+    },
+    "input_editor": {
+      "background": "#19171c",
+      "corner_radius": 8,
+      "placeholder_text": {
+        "family": "Zed Sans",
+        "color": "#7e7887",
+        "size": 14
+      },
+      "selection": {
+        "cursor": "#576ddb",
+        "selection": "#576ddb3d"
+      },
+      "text": {
+        "family": "Zed Mono",
+        "color": "#e2dfe7",
+        "size": 14
+      },
+      "border": {
+        "color": "#26232a",
+        "width": 1
+      },
+      "padding": {
+        "bottom": 7,
+        "left": 16,
+        "right": 16,
+        "top": 7
+      }
+    },
+    "shadow": {
+      "blur": 16,
+      "color": "#00000052",
+      "offset": [
+        0,
+        2
+      ]
+    }
+  },
+  "workspace": {
+    "background": "#26232a",
+    "leader_border_opacity": 0.7,
+    "leader_border_width": 2,
+    "tab": {
+      "height": 32,
+      "background": "#26232a",
+      "icon_close": "#8b8792",
+      "icon_close_active": "#efecf4",
+      "icon_conflict": "#a06e3b",
+      "icon_dirty": "#576ddb",
+      "icon_width": 8,
+      "spacing": 8,
+      "text": {
+        "family": "Zed Sans",
+        "color": "#8b8792",
+        "size": 14
+      },
+      "border": {
+        "color": "#19171c",
+        "width": 1,
+        "left": true,
+        "bottom": true,
+        "overlay": true
+      },
+      "padding": {
+        "left": 8,
+        "right": 8
+      }
+    },
+    "active_tab": {
+      "height": 32,
+      "background": "#19171c",
+      "icon_close": "#8b8792",
+      "icon_close_active": "#efecf4",
+      "icon_conflict": "#a06e3b",
+      "icon_dirty": "#576ddb",
+      "icon_width": 8,
+      "spacing": 8,
+      "text": {
+        "family": "Zed Sans",
+        "color": "#efecf4",
+        "size": 14
+      },
+      "border": {
+        "color": "#19171c",
+        "width": 1,
+        "left": true,
+        "bottom": false,
+        "overlay": true
+      },
+      "padding": {
+        "left": 8,
+        "right": 8
+      }
+    },
+    "modal": {
+      "margin": {
+        "bottom": 52,
+        "top": 52
+      },
+      "cursor": "Arrow"
+    },
+    "left_sidebar": {
+      "width": 30,
+      "background": "#26232a",
+      "border": {
+        "color": "#19171c",
+        "width": 1,
+        "right": true
+      },
+      "item": {
+        "height": 32,
+        "icon_color": "#8b8792",
+        "icon_size": 18
+      },
+      "active_item": {
+        "height": 32,
+        "icon_color": "#efecf4",
+        "icon_size": 18
+      },
+      "resize_handle": {
+        "background": "#19171c",
+        "padding": {
+          "left": 1
+        }
+      }
+    },
+    "right_sidebar": {
+      "width": 30,
+      "background": "#26232a",
+      "border": {
+        "color": "#19171c",
+        "width": 1,
+        "left": true
+      },
+      "item": {
+        "height": 32,
+        "icon_color": "#8b8792",
+        "icon_size": 18
+      },
+      "active_item": {
+        "height": 32,
+        "icon_color": "#efecf4",
+        "icon_size": 18
+      },
+      "resize_handle": {
+        "background": "#19171c",
+        "padding": {
+          "left": 1
+        }
+      }
+    },
+    "pane_divider": {
+      "color": "#26232a",
+      "width": 1
+    },
+    "status_bar": {
+      "height": 24,
+      "item_spacing": 8,
+      "padding": {
+        "left": 6,
+        "right": 6
+      },
+      "border": {
+        "color": "#19171c",
+        "width": 1,
+        "top": true,
+        "overlay": true
+      },
+      "cursor_position": {
+        "family": "Zed Sans",
+        "color": "#8b8792",
+        "size": 14
+      },
+      "diagnostic_message": {
+        "family": "Zed Sans",
+        "color": "#8b8792",
+        "size": 14
+      },
+      "lsp_message": {
+        "family": "Zed Sans",
+        "color": "#8b8792",
+        "size": 14
+      },
+      "auto_update_progress_message": {
+        "family": "Zed Sans",
+        "color": "#8b8792",
+        "size": 14
+      },
+      "auto_update_done_message": {
+        "family": "Zed Sans",
+        "color": "#8b8792",
+        "size": 14
+      }
+    },
+    "titlebar": {
+      "avatar_width": 18,
+      "height": 32,
+      "background": "#26232a",
+      "padding": {
+        "left": 80
+      },
+      "title": {
+        "family": "Zed Sans",
+        "color": "#e2dfe7",
+        "size": 14
+      },
+      "avatar": {
+        "corner_radius": 10,
+        "border": {
+          "color": "#00000088",
+          "width": 1
+        }
+      },
+      "avatar_ribbon": {
+        "height": 3,
+        "width": 12
+      },
+      "border": {
+        "color": "#19171c",
+        "width": 1,
+        "bottom": true
+      },
+      "sign_in_prompt": {
+        "family": "Zed Sans",
+        "color": "#8b8792",
+        "size": 12,
+        "border": {
+          "color": "#19171c",
+          "width": 1
+        },
+        "corner_radius": 6,
+        "margin": {
+          "top": 1,
+          "right": 6
+        },
+        "padding": {
+          "left": 6,
+          "right": 6
+        }
+      },
+      "hovered_sign_in_prompt": {
+        "family": "Zed Sans",
+        "color": "#efecf4",
+        "size": 12,
+        "border": {
+          "color": "#19171c",
+          "width": 1
+        },
+        "corner_radius": 6,
+        "margin": {
+          "top": 1,
+          "right": 6
+        },
+        "padding": {
+          "left": 6,
+          "right": 6
+        }
+      },
+      "offline_icon": {
+        "color": "#8b8792",
+        "width": 16,
+        "padding": {
+          "right": 4
+        }
+      },
+      "share_icon": {
+        "margin": {
+          "top": 3,
+          "bottom": 2
+        },
+        "corner_radius": 6,
+        "color": "#8b8792"
+      },
+      "hovered_share_icon": {
+        "margin": {
+          "top": 3,
+          "bottom": 2
+        },
+        "corner_radius": 6,
+        "background": "#58526052",
+        "color": "#8b8792"
+      },
+      "hovered_active_share_icon": {
+        "margin": {
+          "top": 3,
+          "bottom": 2
+        },
+        "corner_radius": 6,
+        "background": "#58526052",
+        "color": "#efecf4"
+      },
+      "active_share_icon": {
+        "margin": {
+          "top": 3,
+          "bottom": 2
+        },
+        "corner_radius": 6,
+        "background": "#5852607a",
+        "color": "#efecf4"
+      },
+      "outdated_warning": {
+        "family": "Zed Sans",
+        "color": "#a06e3b",
+        "size": 13,
+        "margin": {
+          "right": 6
+        }
+      }
+    },
+    "toolbar": {
+      "height": 34,
+      "background": "#19171c",
+      "border": {
+        "color": "#26232a",
+        "width": 1,
+        "bottom": true
+      },
+      "item_spacing": 8,
+      "padding": {
+        "left": 16,
+        "right": 8,
+        "top": 4,
+        "bottom": 4
+      }
+    },
+    "breadcrumbs": {
+      "family": "Zed Mono",
+      "color": "#8b8792",
+      "size": 14,
+      "padding": {
+        "left": 6
+      }
+    },
+    "disconnected_overlay": {
+      "family": "Zed Sans",
+      "color": "#efecf4",
+      "size": 14,
+      "background": "#000000aa"
+    }
+  },
+  "editor": {
+    "text_color": "#efecf4",
+    "background": "#19171c",
+    "active_line_background": "#efecf412",
+    "code_actions_indicator": "#8b8792",
+    "diff_background_deleted": "#be4678",
+    "diff_background_inserted": "#2a9292",
+    "document_highlight_read_background": "#19171c1f",
+    "document_highlight_write_background": "#19171c29",
+    "error_color": "#be4678",
+    "gutter_background": "#19171c",
+    "gutter_padding_factor": 3.5,
+    "highlighted_line_background": "#efecf41f",
+    "line_number": "#7e7887",
+    "line_number_active": "#efecf4",
+    "rename_fade": 0.6,
+    "unnecessary_code_fade": 0.5,
+    "selection": {
+      "cursor": "#576ddb",
+      "selection": "#576ddb3d"
+    },
+    "guest_selections": [
+      {
+        "cursor": "#2a9292",
+        "selection": "#2a92923d"
+      },
+      {
+        "cursor": "#bf40bf",
+        "selection": "#bf40bf3d"
+      },
+      {
+        "cursor": "#aa573c",
+        "selection": "#aa573c3d"
+      },
+      {
+        "cursor": "#955ae7",
+        "selection": "#955ae73d"
+      },
+      {
+        "cursor": "#398bc6",
+        "selection": "#398bc63d"
+      },
+      {
+        "cursor": "#be4678",
+        "selection": "#be46783d"
+      },
+      {
+        "cursor": "#a06e3b",
+        "selection": "#a06e3b3d"
+      }
+    ],
+    "autocomplete": {
+      "background": "#19171c",
+      "corner_radius": 8,
+      "padding": 4,
+      "border": {
+        "color": "#26232a",
+        "width": 1
+      },
+      "item": {
+        "corner_radius": 6,
+        "padding": {
+          "bottom": 2,
+          "left": 6,
+          "right": 6,
+          "top": 2
+        }
+      },
+      "hovered_item": {
+        "corner_radius": 6,
+        "padding": {
+          "bottom": 2,
+          "left": 6,
+          "right": 6,
+          "top": 2
+        },
+        "background": "#26232a"
+      },
+      "margin": {
+        "left": -14
+      },
+      "match_highlight": {
+        "family": "Zed Mono",
+        "color": "#576ddb",
+        "size": 14
+      },
+      "selected_item": {
+        "corner_radius": 6,
+        "padding": {
+          "bottom": 2,
+          "left": 6,
+          "right": 6,
+          "top": 2
+        },
+        "background": "#26232a"
+      }
+    },
+    "diagnostic_header": {
+      "background": "#26232a",
+      "icon_width_factor": 1.5,
+      "text_scale_factor": 0.857,
+      "border": {
+        "color": "#26232a",
+        "width": 1,
+        "bottom": true,
+        "top": true
+      },
+      "code": {
+        "family": "Zed Mono",
+        "color": "#8b8792",
+        "size": 14,
+        "margin": {
+          "left": 10
+        }
+      },
+      "message": {
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#e2dfe7",
+          "size": 14,
+          "weight": "bold"
+        },
+        "text": {
+          "family": "Zed Sans",
+          "color": "#8b8792",
+          "size": 14
+        }
+      }
+    },
+    "diagnostic_path_header": {
+      "background": "#efecf412",
+      "text_scale_factor": 0.857,
+      "filename": {
+        "family": "Zed Mono",
+        "color": "#e2dfe7",
+        "size": 14
+      },
+      "path": {
+        "family": "Zed Mono",
+        "color": "#8b8792",
+        "size": 14,
+        "margin": {
+          "left": 12
+        }
+      }
+    },
+    "error_diagnostic": {
+      "text_scale_factor": 0.857,
+      "header": {
+        "border": {
+          "color": "#19171c",
+          "width": 1,
+          "top": true
+        }
+      },
+      "message": {
+        "text": {
+          "family": "Zed Sans",
+          "color": "#be4678",
+          "size": 14
+        },
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#be4678",
+          "size": 14,
+          "weight": "bold"
+        }
+      }
+    },
+    "warning_diagnostic": {
+      "text_scale_factor": 0.857,
+      "header": {
+        "border": {
+          "color": "#19171c",
+          "width": 1,
+          "top": true
+        }
+      },
+      "message": {
+        "text": {
+          "family": "Zed Sans",
+          "color": "#a06e3b",
+          "size": 14
+        },
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#a06e3b",
+          "size": 14,
+          "weight": "bold"
+        }
+      }
+    },
+    "information_diagnostic": {
+      "text_scale_factor": 0.857,
+      "header": {
+        "border": {
+          "color": "#19171c",
+          "width": 1,
+          "top": true
+        }
+      },
+      "message": {
+        "text": {
+          "family": "Zed Sans",
+          "color": "#576ddb",
+          "size": 14
+        },
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#576ddb",
+          "size": 14,
+          "weight": "bold"
+        }
+      }
+    },
+    "hint_diagnostic": {
+      "text_scale_factor": 0.857,
+      "header": {
+        "border": {
+          "color": "#19171c",
+          "width": 1,
+          "top": true
+        }
+      },
+      "message": {
+        "text": {
+          "family": "Zed Sans",
+          "color": "#576ddb",
+          "size": 14
+        },
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#576ddb",
+          "size": 14,
+          "weight": "bold"
+        }
+      }
+    },
+    "invalid_error_diagnostic": {
+      "text_scale_factor": 0.857,
+      "header": {
+        "border": {
+          "color": "#19171c",
+          "width": 1,
+          "top": true
+        }
+      },
+      "message": {
+        "text": {
+          "family": "Zed Sans",
+          "color": "#8b8792",
+          "size": 14
+        },
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#8b8792",
+          "size": 14,
+          "weight": "bold"
+        }
+      }
+    },
+    "invalid_hint_diagnostic": {
+      "text_scale_factor": 0.857,
+      "header": {
+        "border": {
+          "color": "#19171c",
+          "width": 1,
+          "top": true
+        }
+      },
+      "message": {
+        "text": {
+          "family": "Zed Sans",
+          "color": "#8b8792",
+          "size": 14
+        },
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#8b8792",
+          "size": 14,
+          "weight": "bold"
+        }
+      }
+    },
+    "invalid_information_diagnostic": {
+      "text_scale_factor": 0.857,
+      "header": {
+        "border": {
+          "color": "#19171c",
+          "width": 1,
+          "top": true
+        }
+      },
+      "message": {
+        "text": {
+          "family": "Zed Sans",
+          "color": "#8b8792",
+          "size": 14
+        },
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#8b8792",
+          "size": 14,
+          "weight": "bold"
+        }
+      }
+    },
+    "invalid_warning_diagnostic": {
+      "text_scale_factor": 0.857,
+      "header": {
+        "border": {
+          "color": "#19171c",
+          "width": 1,
+          "top": true
+        }
+      },
+      "message": {
+        "text": {
+          "family": "Zed Sans",
+          "color": "#8b8792",
+          "size": 14
+        },
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#8b8792",
+          "size": 14,
+          "weight": "bold"
+        }
+      }
+    },
+    "syntax": {
+      "primary": {
+        "color": "#efecf4",
+        "weight": "normal"
+      },
+      "comment": {
+        "color": "#8b8792",
+        "weight": "normal"
+      },
+      "punctuation": {
+        "color": "#8b8792",
+        "weight": "normal"
+      },
+      "constant": {
+        "color": "#7e7887",
+        "weight": "normal"
+      },
+      "keyword": {
+        "color": "#576ddb",
+        "weight": "normal"
+      },
+      "function": {
+        "color": "#a06e3b",
+        "weight": "normal"
+      },
+      "type": {
+        "color": "#398bc6",
+        "weight": "normal"
+      },
+      "variant": {
+        "color": "#576ddb",
+        "weight": "normal"
+      },
+      "property": {
+        "color": "#576ddb",
+        "weight": "normal"
+      },
+      "enum": {
+        "color": "#aa573c",
+        "weight": "normal"
+      },
+      "operator": {
+        "color": "#aa573c",
+        "weight": "normal"
+      },
+      "string": {
+        "color": "#aa573c",
+        "weight": "normal"
+      },
+      "number": {
+        "color": "#2a9292",
+        "weight": "normal"
+      },
+      "boolean": {
+        "color": "#2a9292",
+        "weight": "normal"
+      },
+      "predictive": {
+        "color": "#8b8792",
+        "weight": "normal"
+      },
+      "title": {
+        "color": "#a06e3b",
+        "weight": "bold"
+      },
+      "emphasis": {
+        "color": "#576ddb",
+        "weight": "normal"
+      },
+      "emphasis.strong": {
+        "color": "#576ddb",
+        "weight": "bold"
+      },
+      "link_uri": {
+        "color": "#2a9292",
+        "weight": "normal",
+        "underline": true
+      },
+      "link_text": {
+        "color": "#aa573c",
+        "weight": "normal",
+        "italic": true
+      }
+    }
+  },
+  "project_diagnostics": {
+    "tab_icon_spacing": 4,
+    "tab_icon_width": 13,
+    "tab_summary_spacing": 10,
+    "empty_message": {
+      "family": "Zed Sans",
+      "color": "#e2dfe7",
+      "size": 18
+    },
+    "status_bar_item": {
+      "family": "Zed Sans",
+      "color": "#8b8792",
+      "size": 14,
+      "margin": {
+        "right": 10
+      }
+    }
+  },
+  "command_palette": {
+    "keystroke_spacing": 8,
+    "key": {
+      "text": {
+        "family": "Zed Mono",
+        "color": "#8b8792",
+        "size": 12
+      },
+      "corner_radius": 4,
+      "background": "#19171c",
+      "border": {
+        "color": "#26232a",
+        "width": 1
+      },
+      "padding": {
+        "top": 2,
+        "bottom": 2,
+        "left": 8,
+        "right": 8
+      },
+      "margin": {
+        "left": 2
+      }
+    }
+  },
+  "project_panel": {
+    "padding": {
+      "top": 6,
+      "left": 12
+    },
+    "entry": {
+      "height": 22,
+      "icon_color": "#8b8792",
+      "icon_size": 8,
+      "icon_spacing": 8,
+      "text": {
+        "family": "Zed Mono",
+        "color": "#8b8792",
+        "size": 14
+      }
+    },
+    "hovered_entry": {
+      "height": 22,
+      "background": "#58526052",
+      "icon_color": "#8b8792",
+      "icon_size": 8,
+      "icon_spacing": 8,
+      "text": {
+        "family": "Zed Mono",
+        "color": "#8b8792",
+        "size": 14
+      }
+    },
+    "selected_entry": {
+      "height": 22,
+      "icon_color": "#8b8792",
+      "icon_size": 8,
+      "icon_spacing": 8,
+      "text": {
+        "family": "Zed Mono",
+        "color": "#e2dfe7",
+        "size": 14
+      }
+    },
+    "hovered_selected_entry": {
+      "height": 22,
+      "background": "#58526052",
+      "icon_color": "#8b8792",
+      "icon_size": 8,
+      "icon_spacing": 8,
+      "text": {
+        "family": "Zed Mono",
+        "color": "#e2dfe7",
+        "size": 14
+      }
+    }
+  },
+  "chat_panel": {
+    "padding": {
+      "top": 12,
+      "left": 12,
+      "bottom": 12,
+      "right": 12
+    },
+    "channel_name": {
+      "family": "Zed Sans",
+      "color": "#e2dfe7",
+      "weight": "bold",
+      "size": 14
+    },
+    "channel_name_hash": {
+      "family": "Zed Sans",
+      "color": "#8b8792",
+      "size": 14,
+      "padding": {
+        "right": 8
+      }
+    },
+    "channel_select": {
+      "header": {
+        "name": {
+          "family": "Zed Sans",
+          "color": "#e2dfe7",
+          "size": 14
+        },
+        "padding": {
+          "bottom": 4,
+          "left": 0
+        },
+        "hash": {
+          "family": "Zed Sans",
+          "color": "#8b8792",
+          "size": 14,
+          "margin": {
+            "right": 8
+          }
+        },
+        "corner_radius": 0
+      },
+      "item": {
+        "name": {
+          "family": "Zed Sans",
+          "color": "#8b8792",
+          "size": 14
+        },
+        "padding": 4,
+        "hash": {
+          "family": "Zed Sans",
+          "color": "#8b8792",
+          "size": 14,
+          "margin": {
+            "right": 8
+          }
+        },
+        "corner_radius": 0
+      },
+      "hovered_item": {
+        "name": {
+          "family": "Zed Sans",
+          "color": "#8b8792",
+          "size": 14
+        },
+        "padding": 4,
+        "hash": {
+          "family": "Zed Sans",
+          "color": "#8b8792",
+          "size": 14,
+          "margin": {
+            "right": 8
+          }
+        },
+        "background": "#58526052",
+        "corner_radius": 6
+      },
+      "active_item": {
+        "name": {
+          "family": "Zed Sans",
+          "color": "#e2dfe7",
+          "size": 14
+        },
+        "padding": 4,
+        "hash": {
+          "family": "Zed Sans",
+          "color": "#8b8792",
+          "size": 14,
+          "margin": {
+            "right": 8
+          }
+        },
+        "corner_radius": 0
+      },
+      "hovered_active_item": {
+        "name": {
+          "family": "Zed Sans",
+          "color": "#e2dfe7",
+          "size": 14
+        },
+        "padding": 4,
+        "hash": {
+          "family": "Zed Sans",
+          "color": "#8b8792",
+          "size": 14,
+          "margin": {
+            "right": 8
+          }
+        },
+        "background": "#58526052",
+        "corner_radius": 6
+      },
+      "menu": {
+        "background": "#19171c",
+        "corner_radius": 6,
+        "padding": 4,
+        "border": {
+          "color": "#19171c",
+          "width": 1
+        },
+        "shadow": {
+          "blur": 16,
+          "color": "#00000052",
+          "offset": [
+            0,
+            2
+          ]
+        }
+      }
+    },
+    "sign_in_prompt": {
+      "family": "Zed Sans",
+      "color": "#8b8792",
+      "underline": true,
+      "size": 14
+    },
+    "hovered_sign_in_prompt": {
+      "family": "Zed Sans",
+      "color": "#e2dfe7",
+      "underline": true,
+      "size": 14
+    },
+    "message": {
+      "body": {
+        "family": "Zed Sans",
+        "color": "#8b8792",
+        "size": 14
+      },
+      "timestamp": {
+        "family": "Zed Sans",
+        "color": "#8b8792",
+        "size": 14
+      },
+      "padding": {
+        "bottom": 6
+      },
+      "sender": {
+        "family": "Zed Sans",
+        "color": "#e2dfe7",
+        "weight": "bold",
+        "size": 14,
+        "margin": {
+          "right": 8
+        }
+      }
+    },
+    "pending_message": {
+      "body": {
+        "family": "Zed Sans",
+        "color": "#8b8792",
+        "size": 14
+      },
+      "timestamp": {
+        "family": "Zed Sans",
+        "color": "#8b8792",
+        "size": 14
+      },
+      "padding": {
+        "bottom": 6
+      },
+      "sender": {
+        "family": "Zed Sans",
+        "color": "#8b8792",
+        "weight": "bold",
+        "size": 14,
+        "margin": {
+          "right": 8
+        }
+      }
+    },
+    "input_editor": {
+      "background": "#19171c",
+      "corner_radius": 6,
+      "text": {
+        "family": "Zed Mono",
+        "color": "#e2dfe7",
+        "size": 14
+      },
+      "placeholder_text": {
+        "family": "Zed Mono",
+        "color": "#7e7887",
+        "size": 14
+      },
+      "selection": {
+        "cursor": "#576ddb",
+        "selection": "#576ddb3d"
+      },
+      "border": {
+        "color": "#26232a",
+        "width": 1
+      },
+      "padding": {
+        "bottom": 7,
+        "left": 8,
+        "right": 8,
+        "top": 7
+      }
+    }
+  },
+  "contacts_panel": {
+    "padding": {
+      "top": 12,
+      "left": 12,
+      "bottom": 12,
+      "right": 12
+    },
+    "host_row_height": 28,
+    "tree_branch_color": "#655f6d",
+    "tree_branch_width": 1,
+    "host_avatar": {
+      "corner_radius": 10,
+      "width": 18
+    },
+    "host_username": {
+      "family": "Zed Mono",
+      "color": "#e2dfe7",
+      "size": 14,
+      "padding": {
+        "left": 8
+      }
+    },
+    "project": {
+      "guest_avatar_spacing": 4,
+      "height": 24,
+      "guest_avatar": {
+        "corner_radius": 8,
+        "width": 14
+      },
+      "name": {
+        "family": "Zed Mono",
+        "color": "#7e7887",
+        "size": 14,
+        "margin": {
+          "right": 6
+        }
+      },
+      "padding": {
+        "left": 8
+      }
+    },
+    "shared_project": {
+      "guest_avatar_spacing": 4,
+      "height": 24,
+      "guest_avatar": {
+        "corner_radius": 8,
+        "width": 14
+      },
+      "name": {
+        "family": "Zed Mono",
+        "color": "#8b8792",
+        "size": 14,
+        "margin": {
+          "right": 6
+        }
+      },
+      "padding": {
+        "left": 8
+      },
+      "background": "#26232a",
+      "corner_radius": 6
+    },
+    "hovered_shared_project": {
+      "guest_avatar_spacing": 4,
+      "height": 24,
+      "guest_avatar": {
+        "corner_radius": 8,
+        "width": 14
+      },
+      "name": {
+        "family": "Zed Mono",
+        "color": "#8b8792",
+        "size": 14,
+        "margin": {
+          "right": 6
+        }
+      },
+      "padding": {
+        "left": 8
+      },
+      "background": "#58526052",
+      "corner_radius": 6
+    },
+    "unshared_project": {
+      "guest_avatar_spacing": 4,
+      "height": 24,
+      "guest_avatar": {
+        "corner_radius": 8,
+        "width": 14
+      },
+      "name": {
+        "family": "Zed Mono",
+        "color": "#7e7887",
+        "size": 14,
+        "margin": {
+          "right": 6
+        }
+      },
+      "padding": {
+        "left": 8
+      }
+    },
+    "hovered_unshared_project": {
+      "guest_avatar_spacing": 4,
+      "height": 24,
+      "guest_avatar": {
+        "corner_radius": 8,
+        "width": 14
+      },
+      "name": {
+        "family": "Zed Mono",
+        "color": "#7e7887",
+        "size": 14,
+        "margin": {
+          "right": 6
+        }
+      },
+      "padding": {
+        "left": 8
+      },
+      "corner_radius": 6
+    }
+  },
+  "search": {
+    "match_background": "#955ae780",
+    "tab_icon_spacing": 8,
+    "tab_icon_width": 14,
+    "active_hovered_option_button": {
+      "family": "Zed Mono",
+      "color": "#efecf4",
+      "size": 14,
+      "background": "#655f6d",
+      "corner_radius": 4,
+      "border": {
+        "color": "#655f6d",
+        "width": 1
+      },
+      "margin": {
+        "left": 2,
+        "right": 2
+      },
+      "padding": {
+        "bottom": 3,
+        "left": 8,
+        "right": 8,
+        "top": 3
+      }
+    },
+    "active_option_button": {
+      "family": "Zed Mono",
+      "color": "#efecf4",
+      "size": 14,
+      "background": "#655f6d",
+      "corner_radius": 4,
+      "border": {
+        "color": "#655f6d",
+        "width": 1
+      },
+      "margin": {
+        "left": 2,
+        "right": 2
+      },
+      "padding": {
+        "bottom": 3,
+        "left": 8,
+        "right": 8,
+        "top": 3
+      }
+    },
+    "editor": {
+      "background": "#19171c",
+      "corner_radius": 8,
+      "min_width": 200,
+      "max_width": 500,
+      "placeholder_text": {
+        "family": "Zed Mono",
+        "color": "#7e7887",
+        "size": 14
+      },
+      "selection": {
+        "cursor": "#576ddb",
+        "selection": "#576ddb3d"
+      },
+      "text": {
+        "family": "Zed Mono",
+        "color": "#efecf4",
+        "size": 14
+      },
+      "border": {
+        "color": "#26232a",
+        "width": 1
+      },
+      "margin": {
+        "right": 6
+      },
+      "padding": {
+        "top": 3,
+        "bottom": 3,
+        "left": 12,
+        "right": 8
+      }
+    },
+    "hovered_option_button": {
+      "family": "Zed Mono",
+      "color": "#efecf4",
+      "size": 14,
+      "background": "#26232a",
+      "corner_radius": 4,
+      "border": {
+        "color": "#655f6d",
+        "width": 1
+      },
+      "margin": {
+        "left": 2,
+        "right": 2
+      },
+      "padding": {
+        "bottom": 3,
+        "left": 8,
+        "right": 8,
+        "top": 3
+      }
+    },
+    "invalid_editor": {
+      "background": "#19171c",
+      "corner_radius": 8,
+      "min_width": 200,
+      "max_width": 500,
+      "placeholder_text": {
+        "family": "Zed Mono",
+        "color": "#7e7887",
+        "size": 14
+      },
+      "selection": {
+        "cursor": "#576ddb",
+        "selection": "#576ddb3d"
+      },
+      "text": {
+        "family": "Zed Mono",
+        "color": "#efecf4",
+        "size": 14
+      },
+      "border": {
+        "color": "#be4678",
+        "width": 1
+      },
+      "margin": {
+        "right": 6
+      },
+      "padding": {
+        "top": 3,
+        "bottom": 3,
+        "left": 12,
+        "right": 8
+      }
+    },
+    "match_index": {
+      "family": "Zed Mono",
+      "color": "#8b8792",
+      "size": 14,
+      "padding": 6
+    },
+    "option_button": {
+      "family": "Zed Mono",
+      "color": "#8b8792",
+      "size": 14,
+      "background": "#26232a",
+      "corner_radius": 4,
+      "border": {
+        "color": "#26232a",
+        "width": 1
+      },
+      "margin": {
+        "left": 2,
+        "right": 2
+      },
+      "padding": {
+        "bottom": 3,
+        "left": 8,
+        "right": 8,
+        "top": 3
+      }
+    },
+    "option_button_group": {
+      "padding": {
+        "left": 4,
+        "right": 4
+      }
+    },
+    "results_status": {
+      "family": "Zed Mono",
+      "color": "#e2dfe7",
+      "size": 18
+    }
+  },
+  "breadcrumbs": {
+    "family": "Zed Sans",
+    "color": "#8b8792",
+    "size": 14,
+    "padding": {
+      "left": 6
+    }
+  }
+}

assets/themes/cave-light.json 🔗

@@ -0,0 +1,1435 @@
+{
+  "selector": {
+    "background": "#e2dfe7",
+    "corner_radius": 8,
+    "padding": 8,
+    "item": {
+      "padding": {
+        "bottom": 4,
+        "left": 12,
+        "right": 12,
+        "top": 4
+      },
+      "corner_radius": 8,
+      "text": {
+        "family": "Zed Sans",
+        "color": "#585260",
+        "size": 14
+      },
+      "highlight_text": {
+        "family": "Zed Sans",
+        "color": "#576ddb",
+        "weight": "bold",
+        "size": 14
+      }
+    },
+    "active_item": {
+      "padding": {
+        "bottom": 4,
+        "left": 12,
+        "right": 12,
+        "top": 4
+      },
+      "corner_radius": 8,
+      "text": {
+        "family": "Zed Sans",
+        "color": "#26232a",
+        "size": 14
+      },
+      "highlight_text": {
+        "family": "Zed Sans",
+        "color": "#576ddb",
+        "weight": "bold",
+        "size": 14
+      },
+      "background": "#8b87922e"
+    },
+    "border": {
+      "color": "#efecf4",
+      "width": 1
+    },
+    "empty": {
+      "text": {
+        "family": "Zed Sans",
+        "color": "#655f6d",
+        "size": 14
+      },
+      "padding": {
+        "bottom": 4,
+        "left": 12,
+        "right": 12,
+        "top": 8
+      }
+    },
+    "input_editor": {
+      "background": "#efecf4",
+      "corner_radius": 8,
+      "placeholder_text": {
+        "family": "Zed Sans",
+        "color": "#655f6d",
+        "size": 14
+      },
+      "selection": {
+        "cursor": "#576ddb",
+        "selection": "#576ddb3d"
+      },
+      "text": {
+        "family": "Zed Mono",
+        "color": "#26232a",
+        "size": 14
+      },
+      "border": {
+        "color": "#e2dfe7",
+        "width": 1
+      },
+      "padding": {
+        "bottom": 7,
+        "left": 16,
+        "right": 16,
+        "top": 7
+      }
+    },
+    "shadow": {
+      "blur": 16,
+      "color": "#0000001f",
+      "offset": [
+        0,
+        2
+      ]
+    }
+  },
+  "workspace": {
+    "background": "#e2dfe7",
+    "leader_border_opacity": 0.7,
+    "leader_border_width": 2,
+    "tab": {
+      "height": 32,
+      "background": "#e2dfe7",
+      "icon_close": "#585260",
+      "icon_close_active": "#19171c",
+      "icon_conflict": "#a06e3b",
+      "icon_dirty": "#576ddb",
+      "icon_width": 8,
+      "spacing": 8,
+      "text": {
+        "family": "Zed Sans",
+        "color": "#585260",
+        "size": 14
+      },
+      "border": {
+        "color": "#efecf4",
+        "width": 1,
+        "left": true,
+        "bottom": true,
+        "overlay": true
+      },
+      "padding": {
+        "left": 8,
+        "right": 8
+      }
+    },
+    "active_tab": {
+      "height": 32,
+      "background": "#efecf4",
+      "icon_close": "#585260",
+      "icon_close_active": "#19171c",
+      "icon_conflict": "#a06e3b",
+      "icon_dirty": "#576ddb",
+      "icon_width": 8,
+      "spacing": 8,
+      "text": {
+        "family": "Zed Sans",
+        "color": "#19171c",
+        "size": 14
+      },
+      "border": {
+        "color": "#efecf4",
+        "width": 1,
+        "left": true,
+        "bottom": false,
+        "overlay": true
+      },
+      "padding": {
+        "left": 8,
+        "right": 8
+      }
+    },
+    "modal": {
+      "margin": {
+        "bottom": 52,
+        "top": 52
+      },
+      "cursor": "Arrow"
+    },
+    "left_sidebar": {
+      "width": 30,
+      "background": "#e2dfe7",
+      "border": {
+        "color": "#efecf4",
+        "width": 1,
+        "right": true
+      },
+      "item": {
+        "height": 32,
+        "icon_color": "#585260",
+        "icon_size": 18
+      },
+      "active_item": {
+        "height": 32,
+        "icon_color": "#19171c",
+        "icon_size": 18
+      },
+      "resize_handle": {
+        "background": "#efecf4",
+        "padding": {
+          "left": 1
+        }
+      }
+    },
+    "right_sidebar": {
+      "width": 30,
+      "background": "#e2dfe7",
+      "border": {
+        "color": "#efecf4",
+        "width": 1,
+        "left": true
+      },
+      "item": {
+        "height": 32,
+        "icon_color": "#585260",
+        "icon_size": 18
+      },
+      "active_item": {
+        "height": 32,
+        "icon_color": "#19171c",
+        "icon_size": 18
+      },
+      "resize_handle": {
+        "background": "#efecf4",
+        "padding": {
+          "left": 1
+        }
+      }
+    },
+    "pane_divider": {
+      "color": "#e2dfe7",
+      "width": 1
+    },
+    "status_bar": {
+      "height": 24,
+      "item_spacing": 8,
+      "padding": {
+        "left": 6,
+        "right": 6
+      },
+      "border": {
+        "color": "#efecf4",
+        "width": 1,
+        "top": true,
+        "overlay": true
+      },
+      "cursor_position": {
+        "family": "Zed Sans",
+        "color": "#585260",
+        "size": 14
+      },
+      "diagnostic_message": {
+        "family": "Zed Sans",
+        "color": "#585260",
+        "size": 14
+      },
+      "lsp_message": {
+        "family": "Zed Sans",
+        "color": "#585260",
+        "size": 14
+      },
+      "auto_update_progress_message": {
+        "family": "Zed Sans",
+        "color": "#585260",
+        "size": 14
+      },
+      "auto_update_done_message": {
+        "family": "Zed Sans",
+        "color": "#585260",
+        "size": 14
+      }
+    },
+    "titlebar": {
+      "avatar_width": 18,
+      "height": 32,
+      "background": "#e2dfe7",
+      "padding": {
+        "left": 80
+      },
+      "title": {
+        "family": "Zed Sans",
+        "color": "#26232a",
+        "size": 14
+      },
+      "avatar": {
+        "corner_radius": 10,
+        "border": {
+          "color": "#00000088",
+          "width": 1
+        }
+      },
+      "avatar_ribbon": {
+        "height": 3,
+        "width": 12
+      },
+      "border": {
+        "color": "#efecf4",
+        "width": 1,
+        "bottom": true
+      },
+      "sign_in_prompt": {
+        "family": "Zed Sans",
+        "color": "#585260",
+        "size": 12,
+        "border": {
+          "color": "#efecf4",
+          "width": 1
+        },
+        "corner_radius": 6,
+        "margin": {
+          "top": 1,
+          "right": 6
+        },
+        "padding": {
+          "left": 6,
+          "right": 6
+        }
+      },
+      "hovered_sign_in_prompt": {
+        "family": "Zed Sans",
+        "color": "#19171c",
+        "size": 12,
+        "border": {
+          "color": "#efecf4",
+          "width": 1
+        },
+        "corner_radius": 6,
+        "margin": {
+          "top": 1,
+          "right": 6
+        },
+        "padding": {
+          "left": 6,
+          "right": 6
+        }
+      },
+      "offline_icon": {
+        "color": "#585260",
+        "width": 16,
+        "padding": {
+          "right": 4
+        }
+      },
+      "share_icon": {
+        "margin": {
+          "top": 3,
+          "bottom": 2
+        },
+        "corner_radius": 6,
+        "color": "#585260"
+      },
+      "hovered_share_icon": {
+        "margin": {
+          "top": 3,
+          "bottom": 2
+        },
+        "corner_radius": 6,
+        "background": "#8b87921f",
+        "color": "#585260"
+      },
+      "hovered_active_share_icon": {
+        "margin": {
+          "top": 3,
+          "bottom": 2
+        },
+        "corner_radius": 6,
+        "background": "#8b87921f",
+        "color": "#19171c"
+      },
+      "active_share_icon": {
+        "margin": {
+          "top": 3,
+          "bottom": 2
+        },
+        "corner_radius": 6,
+        "background": "#8b87922e",
+        "color": "#19171c"
+      },
+      "outdated_warning": {
+        "family": "Zed Sans",
+        "color": "#a06e3b",
+        "size": 13,
+        "margin": {
+          "right": 6
+        }
+      }
+    },
+    "toolbar": {
+      "height": 34,
+      "background": "#efecf4",
+      "border": {
+        "color": "#e2dfe7",
+        "width": 1,
+        "bottom": true
+      },
+      "item_spacing": 8,
+      "padding": {
+        "left": 16,
+        "right": 8,
+        "top": 4,
+        "bottom": 4
+      }
+    },
+    "breadcrumbs": {
+      "family": "Zed Mono",
+      "color": "#585260",
+      "size": 14,
+      "padding": {
+        "left": 6
+      }
+    },
+    "disconnected_overlay": {
+      "family": "Zed Sans",
+      "color": "#19171c",
+      "size": 14,
+      "background": "#000000aa"
+    }
+  },
+  "editor": {
+    "text_color": "#19171c",
+    "background": "#efecf4",
+    "active_line_background": "#19171c12",
+    "code_actions_indicator": "#585260",
+    "diff_background_deleted": "#be4678",
+    "diff_background_inserted": "#2a9292",
+    "document_highlight_read_background": "#efecf41f",
+    "document_highlight_write_background": "#efecf429",
+    "error_color": "#be4678",
+    "gutter_background": "#efecf4",
+    "gutter_padding_factor": 3.5,
+    "highlighted_line_background": "#19171c1f",
+    "line_number": "#655f6d",
+    "line_number_active": "#19171c",
+    "rename_fade": 0.6,
+    "unnecessary_code_fade": 0.5,
+    "selection": {
+      "cursor": "#576ddb",
+      "selection": "#576ddb3d"
+    },
+    "guest_selections": [
+      {
+        "cursor": "#2a9292",
+        "selection": "#2a92923d"
+      },
+      {
+        "cursor": "#bf40bf",
+        "selection": "#bf40bf3d"
+      },
+      {
+        "cursor": "#aa573c",
+        "selection": "#aa573c3d"
+      },
+      {
+        "cursor": "#955ae7",
+        "selection": "#955ae73d"
+      },
+      {
+        "cursor": "#398bc6",
+        "selection": "#398bc63d"
+      },
+      {
+        "cursor": "#be4678",
+        "selection": "#be46783d"
+      },
+      {
+        "cursor": "#a06e3b",
+        "selection": "#a06e3b3d"
+      }
+    ],
+    "autocomplete": {
+      "background": "#efecf4",
+      "corner_radius": 8,
+      "padding": 4,
+      "border": {
+        "color": "#e2dfe7",
+        "width": 1
+      },
+      "item": {
+        "corner_radius": 6,
+        "padding": {
+          "bottom": 2,
+          "left": 6,
+          "right": 6,
+          "top": 2
+        }
+      },
+      "hovered_item": {
+        "corner_radius": 6,
+        "padding": {
+          "bottom": 2,
+          "left": 6,
+          "right": 6,
+          "top": 2
+        },
+        "background": "#e2dfe7"
+      },
+      "margin": {
+        "left": -14
+      },
+      "match_highlight": {
+        "family": "Zed Mono",
+        "color": "#576ddb",
+        "size": 14
+      },
+      "selected_item": {
+        "corner_radius": 6,
+        "padding": {
+          "bottom": 2,
+          "left": 6,
+          "right": 6,
+          "top": 2
+        },
+        "background": "#e2dfe7"
+      }
+    },
+    "diagnostic_header": {
+      "background": "#e2dfe7",
+      "icon_width_factor": 1.5,
+      "text_scale_factor": 0.857,
+      "border": {
+        "color": "#e2dfe7",
+        "width": 1,
+        "bottom": true,
+        "top": true
+      },
+      "code": {
+        "family": "Zed Mono",
+        "color": "#585260",
+        "size": 14,
+        "margin": {
+          "left": 10
+        }
+      },
+      "message": {
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#26232a",
+          "size": 14,
+          "weight": "bold"
+        },
+        "text": {
+          "family": "Zed Sans",
+          "color": "#585260",
+          "size": 14
+        }
+      }
+    },
+    "diagnostic_path_header": {
+      "background": "#19171c12",
+      "text_scale_factor": 0.857,
+      "filename": {
+        "family": "Zed Mono",
+        "color": "#26232a",
+        "size": 14
+      },
+      "path": {
+        "family": "Zed Mono",
+        "color": "#585260",
+        "size": 14,
+        "margin": {
+          "left": 12
+        }
+      }
+    },
+    "error_diagnostic": {
+      "text_scale_factor": 0.857,
+      "header": {
+        "border": {
+          "color": "#efecf4",
+          "width": 1,
+          "top": true
+        }
+      },
+      "message": {
+        "text": {
+          "family": "Zed Sans",
+          "color": "#be4678",
+          "size": 14
+        },
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#be4678",
+          "size": 14,
+          "weight": "bold"
+        }
+      }
+    },
+    "warning_diagnostic": {
+      "text_scale_factor": 0.857,
+      "header": {
+        "border": {
+          "color": "#efecf4",
+          "width": 1,
+          "top": true
+        }
+      },
+      "message": {
+        "text": {
+          "family": "Zed Sans",
+          "color": "#a06e3b",
+          "size": 14
+        },
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#a06e3b",
+          "size": 14,
+          "weight": "bold"
+        }
+      }
+    },
+    "information_diagnostic": {
+      "text_scale_factor": 0.857,
+      "header": {
+        "border": {
+          "color": "#efecf4",
+          "width": 1,
+          "top": true
+        }
+      },
+      "message": {
+        "text": {
+          "family": "Zed Sans",
+          "color": "#576ddb",
+          "size": 14
+        },
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#576ddb",
+          "size": 14,
+          "weight": "bold"
+        }
+      }
+    },
+    "hint_diagnostic": {
+      "text_scale_factor": 0.857,
+      "header": {
+        "border": {
+          "color": "#efecf4",
+          "width": 1,
+          "top": true
+        }
+      },
+      "message": {
+        "text": {
+          "family": "Zed Sans",
+          "color": "#576ddb",
+          "size": 14
+        },
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#576ddb",
+          "size": 14,
+          "weight": "bold"
+        }
+      }
+    },
+    "invalid_error_diagnostic": {
+      "text_scale_factor": 0.857,
+      "header": {
+        "border": {
+          "color": "#efecf4",
+          "width": 1,
+          "top": true
+        }
+      },
+      "message": {
+        "text": {
+          "family": "Zed Sans",
+          "color": "#585260",
+          "size": 14
+        },
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#585260",
+          "size": 14,
+          "weight": "bold"
+        }
+      }
+    },
+    "invalid_hint_diagnostic": {
+      "text_scale_factor": 0.857,
+      "header": {
+        "border": {
+          "color": "#efecf4",
+          "width": 1,
+          "top": true
+        }
+      },
+      "message": {
+        "text": {
+          "family": "Zed Sans",
+          "color": "#585260",
+          "size": 14
+        },
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#585260",
+          "size": 14,
+          "weight": "bold"
+        }
+      }
+    },
+    "invalid_information_diagnostic": {
+      "text_scale_factor": 0.857,
+      "header": {
+        "border": {
+          "color": "#efecf4",
+          "width": 1,
+          "top": true
+        }
+      },
+      "message": {
+        "text": {
+          "family": "Zed Sans",
+          "color": "#585260",
+          "size": 14
+        },
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#585260",
+          "size": 14,
+          "weight": "bold"
+        }
+      }
+    },
+    "invalid_warning_diagnostic": {
+      "text_scale_factor": 0.857,
+      "header": {
+        "border": {
+          "color": "#efecf4",
+          "width": 1,
+          "top": true
+        }
+      },
+      "message": {
+        "text": {
+          "family": "Zed Sans",
+          "color": "#585260",
+          "size": 14
+        },
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#585260",
+          "size": 14,
+          "weight": "bold"
+        }
+      }
+    },
+    "syntax": {
+      "primary": {
+        "color": "#19171c",
+        "weight": "normal"
+      },
+      "comment": {
+        "color": "#585260",
+        "weight": "normal"
+      },
+      "punctuation": {
+        "color": "#585260",
+        "weight": "normal"
+      },
+      "constant": {
+        "color": "#655f6d",
+        "weight": "normal"
+      },
+      "keyword": {
+        "color": "#576ddb",
+        "weight": "normal"
+      },
+      "function": {
+        "color": "#a06e3b",
+        "weight": "normal"
+      },
+      "type": {
+        "color": "#398bc6",
+        "weight": "normal"
+      },
+      "variant": {
+        "color": "#576ddb",
+        "weight": "normal"
+      },
+      "property": {
+        "color": "#576ddb",
+        "weight": "normal"
+      },
+      "enum": {
+        "color": "#aa573c",
+        "weight": "normal"
+      },
+      "operator": {
+        "color": "#aa573c",
+        "weight": "normal"
+      },
+      "string": {
+        "color": "#aa573c",
+        "weight": "normal"
+      },
+      "number": {
+        "color": "#2a9292",
+        "weight": "normal"
+      },
+      "boolean": {
+        "color": "#2a9292",
+        "weight": "normal"
+      },
+      "predictive": {
+        "color": "#585260",
+        "weight": "normal"
+      },
+      "title": {
+        "color": "#a06e3b",
+        "weight": "bold"
+      },
+      "emphasis": {
+        "color": "#576ddb",
+        "weight": "normal"
+      },
+      "emphasis.strong": {
+        "color": "#576ddb",
+        "weight": "bold"
+      },
+      "link_uri": {
+        "color": "#2a9292",
+        "weight": "normal",
+        "underline": true
+      },
+      "link_text": {
+        "color": "#aa573c",
+        "weight": "normal",
+        "italic": true
+      }
+    }
+  },
+  "project_diagnostics": {
+    "tab_icon_spacing": 4,
+    "tab_icon_width": 13,
+    "tab_summary_spacing": 10,
+    "empty_message": {
+      "family": "Zed Sans",
+      "color": "#26232a",
+      "size": 18
+    },
+    "status_bar_item": {
+      "family": "Zed Sans",
+      "color": "#585260",
+      "size": 14,
+      "margin": {
+        "right": 10
+      }
+    }
+  },
+  "command_palette": {
+    "keystroke_spacing": 8,
+    "key": {
+      "text": {
+        "family": "Zed Mono",
+        "color": "#585260",
+        "size": 12
+      },
+      "corner_radius": 4,
+      "background": "#efecf4",
+      "border": {
+        "color": "#e2dfe7",
+        "width": 1
+      },
+      "padding": {
+        "top": 2,
+        "bottom": 2,
+        "left": 8,
+        "right": 8
+      },
+      "margin": {
+        "left": 2
+      }
+    }
+  },
+  "project_panel": {
+    "padding": {
+      "top": 6,
+      "left": 12
+    },
+    "entry": {
+      "height": 22,
+      "icon_color": "#585260",
+      "icon_size": 8,
+      "icon_spacing": 8,
+      "text": {
+        "family": "Zed Mono",
+        "color": "#585260",
+        "size": 14
+      }
+    },
+    "hovered_entry": {
+      "height": 22,
+      "background": "#8b87921f",
+      "icon_color": "#585260",
+      "icon_size": 8,
+      "icon_spacing": 8,
+      "text": {
+        "family": "Zed Mono",
+        "color": "#585260",
+        "size": 14
+      }
+    },
+    "selected_entry": {
+      "height": 22,
+      "icon_color": "#585260",
+      "icon_size": 8,
+      "icon_spacing": 8,
+      "text": {
+        "family": "Zed Mono",
+        "color": "#26232a",
+        "size": 14
+      }
+    },
+    "hovered_selected_entry": {
+      "height": 22,
+      "background": "#8b87921f",
+      "icon_color": "#585260",
+      "icon_size": 8,
+      "icon_spacing": 8,
+      "text": {
+        "family": "Zed Mono",
+        "color": "#26232a",
+        "size": 14
+      }
+    }
+  },
+  "chat_panel": {
+    "padding": {
+      "top": 12,
+      "left": 12,
+      "bottom": 12,
+      "right": 12
+    },
+    "channel_name": {
+      "family": "Zed Sans",
+      "color": "#26232a",
+      "weight": "bold",
+      "size": 14
+    },
+    "channel_name_hash": {
+      "family": "Zed Sans",
+      "color": "#585260",
+      "size": 14,
+      "padding": {
+        "right": 8
+      }
+    },
+    "channel_select": {
+      "header": {
+        "name": {
+          "family": "Zed Sans",
+          "color": "#26232a",
+          "size": 14
+        },
+        "padding": {
+          "bottom": 4,
+          "left": 0
+        },
+        "hash": {
+          "family": "Zed Sans",
+          "color": "#585260",
+          "size": 14,
+          "margin": {
+            "right": 8
+          }
+        },
+        "corner_radius": 0
+      },
+      "item": {
+        "name": {
+          "family": "Zed Sans",
+          "color": "#585260",
+          "size": 14
+        },
+        "padding": 4,
+        "hash": {
+          "family": "Zed Sans",
+          "color": "#585260",
+          "size": 14,
+          "margin": {
+            "right": 8
+          }
+        },
+        "corner_radius": 0
+      },
+      "hovered_item": {
+        "name": {
+          "family": "Zed Sans",
+          "color": "#585260",
+          "size": 14
+        },
+        "padding": 4,
+        "hash": {
+          "family": "Zed Sans",
+          "color": "#585260",
+          "size": 14,
+          "margin": {
+            "right": 8
+          }
+        },
+        "background": "#8b87921f",
+        "corner_radius": 6
+      },
+      "active_item": {
+        "name": {
+          "family": "Zed Sans",
+          "color": "#26232a",
+          "size": 14
+        },
+        "padding": 4,
+        "hash": {
+          "family": "Zed Sans",
+          "color": "#585260",
+          "size": 14,
+          "margin": {
+            "right": 8
+          }
+        },
+        "corner_radius": 0
+      },
+      "hovered_active_item": {
+        "name": {
+          "family": "Zed Sans",
+          "color": "#26232a",
+          "size": 14
+        },
+        "padding": 4,
+        "hash": {
+          "family": "Zed Sans",
+          "color": "#585260",
+          "size": 14,
+          "margin": {
+            "right": 8
+          }
+        },
+        "background": "#8b87921f",
+        "corner_radius": 6
+      },
+      "menu": {
+        "background": "#efecf4",
+        "corner_radius": 6,
+        "padding": 4,
+        "border": {
+          "color": "#efecf4",
+          "width": 1
+        },
+        "shadow": {
+          "blur": 16,
+          "color": "#0000001f",
+          "offset": [
+            0,
+            2
+          ]
+        }
+      }
+    },
+    "sign_in_prompt": {
+      "family": "Zed Sans",
+      "color": "#585260",
+      "underline": true,
+      "size": 14
+    },
+    "hovered_sign_in_prompt": {
+      "family": "Zed Sans",
+      "color": "#26232a",
+      "underline": true,
+      "size": 14
+    },
+    "message": {
+      "body": {
+        "family": "Zed Sans",
+        "color": "#585260",
+        "size": 14
+      },
+      "timestamp": {
+        "family": "Zed Sans",
+        "color": "#585260",
+        "size": 14
+      },
+      "padding": {
+        "bottom": 6
+      },
+      "sender": {
+        "family": "Zed Sans",
+        "color": "#26232a",
+        "weight": "bold",
+        "size": 14,
+        "margin": {
+          "right": 8
+        }
+      }
+    },
+    "pending_message": {
+      "body": {
+        "family": "Zed Sans",
+        "color": "#585260",
+        "size": 14
+      },
+      "timestamp": {
+        "family": "Zed Sans",
+        "color": "#585260",
+        "size": 14
+      },
+      "padding": {
+        "bottom": 6
+      },
+      "sender": {
+        "family": "Zed Sans",
+        "color": "#585260",
+        "weight": "bold",
+        "size": 14,
+        "margin": {
+          "right": 8
+        }
+      }
+    },
+    "input_editor": {
+      "background": "#efecf4",
+      "corner_radius": 6,
+      "text": {
+        "family": "Zed Mono",
+        "color": "#26232a",
+        "size": 14
+      },
+      "placeholder_text": {
+        "family": "Zed Mono",
+        "color": "#655f6d",
+        "size": 14
+      },
+      "selection": {
+        "cursor": "#576ddb",
+        "selection": "#576ddb3d"
+      },
+      "border": {
+        "color": "#e2dfe7",
+        "width": 1
+      },
+      "padding": {
+        "bottom": 7,
+        "left": 8,
+        "right": 8,
+        "top": 7
+      }
+    }
+  },
+  "contacts_panel": {
+    "padding": {
+      "top": 12,
+      "left": 12,
+      "bottom": 12,
+      "right": 12
+    },
+    "host_row_height": 28,
+    "tree_branch_color": "#7e7887",
+    "tree_branch_width": 1,
+    "host_avatar": {
+      "corner_radius": 10,
+      "width": 18
+    },
+    "host_username": {
+      "family": "Zed Mono",
+      "color": "#26232a",
+      "size": 14,
+      "padding": {
+        "left": 8
+      }
+    },
+    "project": {
+      "guest_avatar_spacing": 4,
+      "height": 24,
+      "guest_avatar": {
+        "corner_radius": 8,
+        "width": 14
+      },
+      "name": {
+        "family": "Zed Mono",
+        "color": "#655f6d",
+        "size": 14,
+        "margin": {
+          "right": 6
+        }
+      },
+      "padding": {
+        "left": 8
+      }
+    },
+    "shared_project": {
+      "guest_avatar_spacing": 4,
+      "height": 24,
+      "guest_avatar": {
+        "corner_radius": 8,
+        "width": 14
+      },
+      "name": {
+        "family": "Zed Mono",
+        "color": "#585260",
+        "size": 14,
+        "margin": {
+          "right": 6
+        }
+      },
+      "padding": {
+        "left": 8
+      },
+      "background": "#e2dfe7",
+      "corner_radius": 6
+    },
+    "hovered_shared_project": {
+      "guest_avatar_spacing": 4,
+      "height": 24,
+      "guest_avatar": {
+        "corner_radius": 8,
+        "width": 14
+      },
+      "name": {
+        "family": "Zed Mono",
+        "color": "#585260",
+        "size": 14,
+        "margin": {
+          "right": 6
+        }
+      },
+      "padding": {
+        "left": 8
+      },
+      "background": "#8b87921f",
+      "corner_radius": 6
+    },
+    "unshared_project": {
+      "guest_avatar_spacing": 4,
+      "height": 24,
+      "guest_avatar": {
+        "corner_radius": 8,
+        "width": 14
+      },
+      "name": {
+        "family": "Zed Mono",
+        "color": "#655f6d",
+        "size": 14,
+        "margin": {
+          "right": 6
+        }
+      },
+      "padding": {
+        "left": 8
+      }
+    },
+    "hovered_unshared_project": {
+      "guest_avatar_spacing": 4,
+      "height": 24,
+      "guest_avatar": {
+        "corner_radius": 8,
+        "width": 14
+      },
+      "name": {
+        "family": "Zed Mono",
+        "color": "#655f6d",
+        "size": 14,
+        "margin": {
+          "right": 6
+        }
+      },
+      "padding": {
+        "left": 8
+      },
+      "corner_radius": 6
+    }
+  },
+  "search": {
+    "match_background": "#955ae780",
+    "tab_icon_spacing": 8,
+    "tab_icon_width": 14,
+    "active_hovered_option_button": {
+      "family": "Zed Mono",
+      "color": "#19171c",
+      "size": 14,
+      "background": "#7e7887",
+      "corner_radius": 4,
+      "border": {
+        "color": "#7e7887",
+        "width": 1
+      },
+      "margin": {
+        "left": 2,
+        "right": 2
+      },
+      "padding": {
+        "bottom": 3,
+        "left": 8,
+        "right": 8,
+        "top": 3
+      }
+    },
+    "active_option_button": {
+      "family": "Zed Mono",
+      "color": "#19171c",
+      "size": 14,
+      "background": "#7e7887",
+      "corner_radius": 4,
+      "border": {
+        "color": "#7e7887",
+        "width": 1
+      },
+      "margin": {
+        "left": 2,
+        "right": 2
+      },
+      "padding": {
+        "bottom": 3,
+        "left": 8,
+        "right": 8,
+        "top": 3
+      }
+    },
+    "editor": {
+      "background": "#efecf4",
+      "corner_radius": 8,
+      "min_width": 200,
+      "max_width": 500,
+      "placeholder_text": {
+        "family": "Zed Mono",
+        "color": "#655f6d",
+        "size": 14
+      },
+      "selection": {
+        "cursor": "#576ddb",
+        "selection": "#576ddb3d"
+      },
+      "text": {
+        "family": "Zed Mono",
+        "color": "#19171c",
+        "size": 14
+      },
+      "border": {
+        "color": "#e2dfe7",
+        "width": 1
+      },
+      "margin": {
+        "right": 6
+      },
+      "padding": {
+        "top": 3,
+        "bottom": 3,
+        "left": 12,
+        "right": 8
+      }
+    },
+    "hovered_option_button": {
+      "family": "Zed Mono",
+      "color": "#19171c",
+      "size": 14,
+      "background": "#e2dfe7",
+      "corner_radius": 4,
+      "border": {
+        "color": "#7e7887",
+        "width": 1
+      },
+      "margin": {
+        "left": 2,
+        "right": 2
+      },
+      "padding": {
+        "bottom": 3,
+        "left": 8,
+        "right": 8,
+        "top": 3
+      }
+    },
+    "invalid_editor": {
+      "background": "#efecf4",
+      "corner_radius": 8,
+      "min_width": 200,
+      "max_width": 500,
+      "placeholder_text": {
+        "family": "Zed Mono",
+        "color": "#655f6d",
+        "size": 14
+      },
+      "selection": {
+        "cursor": "#576ddb",
+        "selection": "#576ddb3d"
+      },
+      "text": {
+        "family": "Zed Mono",
+        "color": "#19171c",
+        "size": 14
+      },
+      "border": {
+        "color": "#be4678",
+        "width": 1
+      },
+      "margin": {
+        "right": 6
+      },
+      "padding": {
+        "top": 3,
+        "bottom": 3,
+        "left": 12,
+        "right": 8
+      }
+    },
+    "match_index": {
+      "family": "Zed Mono",
+      "color": "#585260",
+      "size": 14,
+      "padding": 6
+    },
+    "option_button": {
+      "family": "Zed Mono",
+      "color": "#585260",
+      "size": 14,
+      "background": "#e2dfe7",
+      "corner_radius": 4,
+      "border": {
+        "color": "#e2dfe7",
+        "width": 1
+      },
+      "margin": {
+        "left": 2,
+        "right": 2
+      },
+      "padding": {
+        "bottom": 3,
+        "left": 8,
+        "right": 8,
+        "top": 3
+      }
+    },
+    "option_button_group": {
+      "padding": {
+        "left": 4,
+        "right": 4
+      }
+    },
+    "results_status": {
+      "family": "Zed Mono",
+      "color": "#26232a",
+      "size": 18
+    }
+  },
+  "breadcrumbs": {
+    "family": "Zed Sans",
+    "color": "#585260",
+    "size": 14,
+    "padding": {
+      "left": 6
+    }
+  }
+}

assets/themes/dark.json 🔗

@@ -89,10 +89,6 @@
         "top": 7
       }
     },
-    "margin": {
-      "bottom": 52,
-      "top": 52
-    },
     "shadow": {
       "blur": 16,
       "color": "#00000052",
@@ -158,6 +154,13 @@
         "right": 8
       }
     },
+    "modal": {
+      "margin": {
+        "bottom": 52,
+        "top": 52
+      },
+      "cursor": "Arrow"
+    },
     "left_sidebar": {
       "width": 30,
       "background": "#1c1c1c",
@@ -255,8 +258,9 @@
       "avatar_width": 18,
       "height": 32,
       "background": "#2b2b2b",
-      "share_icon_color": "#9c9c9c",
-      "share_icon_active_color": "#2472f2",
+      "padding": {
+        "left": 80
+      },
       "title": {
         "family": "Zed Sans",
         "color": "#f1f1f1",
@@ -321,10 +325,48 @@
           "right": 4
         }
       },
+      "share_icon": {
+        "margin": {
+          "top": 3,
+          "bottom": 2
+        },
+        "corner_radius": 6,
+        "color": "#9c9c9c"
+      },
+      "hovered_share_icon": {
+        "margin": {
+          "top": 3,
+          "bottom": 2
+        },
+        "corner_radius": 6,
+        "background": "#323232",
+        "color": "#9c9c9c"
+      },
+      "hovered_active_share_icon": {
+        "margin": {
+          "top": 3,
+          "bottom": 2
+        },
+        "corner_radius": 6,
+        "background": "#323232",
+        "color": "#ffffff"
+      },
+      "active_share_icon": {
+        "margin": {
+          "top": 3,
+          "bottom": 2
+        },
+        "corner_radius": 6,
+        "background": "#1c1c1c",
+        "color": "#ffffff"
+      },
       "outdated_warning": {
         "family": "Zed Sans",
         "color": "#f7bb57",
-        "size": 13
+        "size": 13,
+        "margin": {
+          "right": 6
+        }
       }
     },
     "toolbar": {
@@ -689,33 +731,88 @@
       }
     },
     "syntax": {
-      "keyword": "#4f8ff7",
-      "function": "#f9da82",
-      "string": "#f99d5f",
-      "type": "#3eeeda",
-      "number": "#aeef4b",
-      "comment": "#aaaaaa",
-      "property": "#4f8ff7",
-      "variant": "#53c1f5",
-      "constant": "#d5d5d5",
+      "primary": {
+        "color": "#d5d5d5",
+        "weight": "normal"
+      },
+      "comment": {
+        "color": "#aaaaaa",
+        "weight": "normal"
+      },
+      "punctuation": {
+        "color": "#c6c6c6",
+        "weight": "normal"
+      },
+      "constant": {
+        "color": "#d5d5d5",
+        "weight": "normal"
+      },
+      "keyword": {
+        "color": "#4f8ff7",
+        "weight": "normal"
+      },
+      "function": {
+        "color": "#f9da82",
+        "weight": "normal"
+      },
+      "type": {
+        "color": "#3eeeda",
+        "weight": "normal"
+      },
+      "variant": {
+        "color": "#53c1f5",
+        "weight": "normal"
+      },
+      "property": {
+        "color": "#4f8ff7",
+        "weight": "normal"
+      },
+      "enum": {
+        "color": "#ee670a",
+        "weight": "normal"
+      },
+      "operator": {
+        "color": "#ee670a",
+        "weight": "normal"
+      },
+      "string": {
+        "color": "#f99d5f",
+        "weight": "normal"
+      },
+      "number": {
+        "color": "#aeef4b",
+        "weight": "normal"
+      },
+      "boolean": {
+        "color": "#aeef4b",
+        "weight": "normal"
+      },
+      "predictive": {
+        "color": "#808080",
+        "weight": "normal"
+      },
       "title": {
         "color": "#de900c",
         "weight": "bold"
       },
-      "emphasis": "#4f8ff7",
-      "emphasis_strong": {
+      "emphasis": {
+        "color": "#4f8ff7",
+        "weight": "normal"
+      },
+      "emphasis.strong": {
         "color": "#4f8ff7",
         "weight": "bold"
       },
       "link_uri": {
         "color": "#79ba16",
+        "weight": "normal",
         "underline": true
       },
       "link_text": {
         "color": "#ee670a",
+        "weight": "normal",
         "italic": true
-      },
-      "list_marker": "#c6c6c6"
+      }
     }
   },
   "project_diagnostics": {

assets/themes/light.json 🔗

@@ -89,10 +89,6 @@
         "top": 7
       }
     },
-    "margin": {
-      "bottom": 52,
-      "top": 52
-    },
     "shadow": {
       "blur": 16,
       "color": "#0000001f",
@@ -158,6 +154,13 @@
         "right": 8
       }
     },
+    "modal": {
+      "margin": {
+        "bottom": 52,
+        "top": 52
+      },
+      "cursor": "Arrow"
+    },
     "left_sidebar": {
       "width": 30,
       "background": "#f8f8f8",
@@ -255,8 +258,9 @@
       "avatar_width": 18,
       "height": 32,
       "background": "#eaeaea",
-      "share_icon_color": "#717171",
-      "share_icon_active_color": "#484bed",
+      "padding": {
+        "left": 80
+      },
       "title": {
         "family": "Zed Sans",
         "color": "#2b2b2b",
@@ -321,10 +325,48 @@
           "right": 4
         }
       },
+      "share_icon": {
+        "margin": {
+          "top": 3,
+          "bottom": 2
+        },
+        "corner_radius": 6,
+        "color": "#717171"
+      },
+      "hovered_share_icon": {
+        "margin": {
+          "top": 3,
+          "bottom": 2
+        },
+        "corner_radius": 6,
+        "background": "#e3e3e3",
+        "color": "#717171"
+      },
+      "hovered_active_share_icon": {
+        "margin": {
+          "top": 3,
+          "bottom": 2
+        },
+        "corner_radius": 6,
+        "background": "#e3e3e3",
+        "color": "#000000"
+      },
+      "active_share_icon": {
+        "margin": {
+          "top": 3,
+          "bottom": 2
+        },
+        "corner_radius": 6,
+        "background": "#d5d5d5",
+        "color": "#000000"
+      },
       "outdated_warning": {
         "family": "Zed Sans",
         "color": "#d3a20b",
-        "size": 13
+        "size": 13,
+        "margin": {
+          "right": 6
+        }
       }
     },
     "toolbar": {
@@ -689,33 +731,88 @@
       }
     },
     "syntax": {
-      "keyword": "#1819a1",
-      "function": "#bb550e",
-      "string": "#eb2d2d",
-      "type": "#a8820e",
-      "number": "#484bed",
-      "comment": "#717171",
-      "property": "#106c4e",
-      "variant": "#97142a",
-      "constant": "#1c1c1c",
+      "primary": {
+        "color": "#1c1c1c",
+        "weight": "normal"
+      },
+      "comment": {
+        "color": "#717171",
+        "weight": "normal"
+      },
+      "punctuation": {
+        "color": "#555555",
+        "weight": "normal"
+      },
+      "constant": {
+        "color": "#1c1c1c",
+        "weight": "normal"
+      },
+      "keyword": {
+        "color": "#1819a1",
+        "weight": "normal"
+      },
+      "function": {
+        "color": "#bb550e",
+        "weight": "normal"
+      },
+      "type": {
+        "color": "#a8820e",
+        "weight": "normal"
+      },
+      "variant": {
+        "color": "#97142a",
+        "weight": "normal"
+      },
+      "property": {
+        "color": "#106c4e",
+        "weight": "normal"
+      },
+      "enum": {
+        "color": "#eb2d2d",
+        "weight": "normal"
+      },
+      "operator": {
+        "color": "#eb2d2d",
+        "weight": "normal"
+      },
+      "string": {
+        "color": "#eb2d2d",
+        "weight": "normal"
+      },
+      "number": {
+        "color": "#484bed",
+        "weight": "normal"
+      },
+      "boolean": {
+        "color": "#eb2d2d",
+        "weight": "normal"
+      },
+      "predictive": {
+        "color": "#808080",
+        "weight": "normal"
+      },
       "title": {
         "color": "#1096d3",
         "weight": "bold"
       },
-      "emphasis": "#484bed",
-      "emphasis_strong": {
+      "emphasis": {
+        "color": "#484bed",
+        "weight": "normal"
+      },
+      "emphasis.strong": {
         "color": "#484bed",
         "weight": "bold"
       },
       "link_uri": {
         "color": "#79ba16",
+        "weight": "normal",
         "underline": true
       },
       "link_text": {
         "color": "#eb2d2d",
+        "weight": "normal",
         "italic": true
-      },
-      "list_marker": "#555555"
+      }
     }
   },
   "project_diagnostics": {

assets/themes/solarized-dark.json 🔗

@@ -0,0 +1,1435 @@
+{
+  "selector": {
+    "background": "#073642",
+    "corner_radius": 8,
+    "padding": 8,
+    "item": {
+      "padding": {
+        "bottom": 4,
+        "left": 12,
+        "right": 12,
+        "top": 4
+      },
+      "corner_radius": 8,
+      "text": {
+        "family": "Zed Sans",
+        "color": "#93a1a1",
+        "size": 14
+      },
+      "highlight_text": {
+        "family": "Zed Sans",
+        "color": "#268bd2",
+        "weight": "bold",
+        "size": 14
+      }
+    },
+    "active_item": {
+      "padding": {
+        "bottom": 4,
+        "left": 12,
+        "right": 12,
+        "top": 4
+      },
+      "corner_radius": 8,
+      "text": {
+        "family": "Zed Sans",
+        "color": "#eee8d5",
+        "size": 14
+      },
+      "highlight_text": {
+        "family": "Zed Sans",
+        "color": "#268bd2",
+        "weight": "bold",
+        "size": 14
+      },
+      "background": "#586e757a"
+    },
+    "border": {
+      "color": "#002b36",
+      "width": 1
+    },
+    "empty": {
+      "text": {
+        "family": "Zed Sans",
+        "color": "#839496",
+        "size": 14
+      },
+      "padding": {
+        "bottom": 4,
+        "left": 12,
+        "right": 12,
+        "top": 8
+      }
+    },
+    "input_editor": {
+      "background": "#002b36",
+      "corner_radius": 8,
+      "placeholder_text": {
+        "family": "Zed Sans",
+        "color": "#839496",
+        "size": 14
+      },
+      "selection": {
+        "cursor": "#268bd2",
+        "selection": "#268bd23d"
+      },
+      "text": {
+        "family": "Zed Mono",
+        "color": "#eee8d5",
+        "size": 14
+      },
+      "border": {
+        "color": "#073642",
+        "width": 1
+      },
+      "padding": {
+        "bottom": 7,
+        "left": 16,
+        "right": 16,
+        "top": 7
+      }
+    },
+    "shadow": {
+      "blur": 16,
+      "color": "#00000052",
+      "offset": [
+        0,
+        2
+      ]
+    }
+  },
+  "workspace": {
+    "background": "#073642",
+    "leader_border_opacity": 0.7,
+    "leader_border_width": 2,
+    "tab": {
+      "height": 32,
+      "background": "#073642",
+      "icon_close": "#93a1a1",
+      "icon_close_active": "#fdf6e3",
+      "icon_conflict": "#b58900",
+      "icon_dirty": "#268bd2",
+      "icon_width": 8,
+      "spacing": 8,
+      "text": {
+        "family": "Zed Sans",
+        "color": "#93a1a1",
+        "size": 14
+      },
+      "border": {
+        "color": "#002b36",
+        "width": 1,
+        "left": true,
+        "bottom": true,
+        "overlay": true
+      },
+      "padding": {
+        "left": 8,
+        "right": 8
+      }
+    },
+    "active_tab": {
+      "height": 32,
+      "background": "#002b36",
+      "icon_close": "#93a1a1",
+      "icon_close_active": "#fdf6e3",
+      "icon_conflict": "#b58900",
+      "icon_dirty": "#268bd2",
+      "icon_width": 8,
+      "spacing": 8,
+      "text": {
+        "family": "Zed Sans",
+        "color": "#fdf6e3",
+        "size": 14
+      },
+      "border": {
+        "color": "#002b36",
+        "width": 1,
+        "left": true,
+        "bottom": false,
+        "overlay": true
+      },
+      "padding": {
+        "left": 8,
+        "right": 8
+      }
+    },
+    "modal": {
+      "margin": {
+        "bottom": 52,
+        "top": 52
+      },
+      "cursor": "Arrow"
+    },
+    "left_sidebar": {
+      "width": 30,
+      "background": "#073642",
+      "border": {
+        "color": "#002b36",
+        "width": 1,
+        "right": true
+      },
+      "item": {
+        "height": 32,
+        "icon_color": "#93a1a1",
+        "icon_size": 18
+      },
+      "active_item": {
+        "height": 32,
+        "icon_color": "#fdf6e3",
+        "icon_size": 18
+      },
+      "resize_handle": {
+        "background": "#002b36",
+        "padding": {
+          "left": 1
+        }
+      }
+    },
+    "right_sidebar": {
+      "width": 30,
+      "background": "#073642",
+      "border": {
+        "color": "#002b36",
+        "width": 1,
+        "left": true
+      },
+      "item": {
+        "height": 32,
+        "icon_color": "#93a1a1",
+        "icon_size": 18
+      },
+      "active_item": {
+        "height": 32,
+        "icon_color": "#fdf6e3",
+        "icon_size": 18
+      },
+      "resize_handle": {
+        "background": "#002b36",
+        "padding": {
+          "left": 1
+        }
+      }
+    },
+    "pane_divider": {
+      "color": "#073642",
+      "width": 1
+    },
+    "status_bar": {
+      "height": 24,
+      "item_spacing": 8,
+      "padding": {
+        "left": 6,
+        "right": 6
+      },
+      "border": {
+        "color": "#002b36",
+        "width": 1,
+        "top": true,
+        "overlay": true
+      },
+      "cursor_position": {
+        "family": "Zed Sans",
+        "color": "#93a1a1",
+        "size": 14
+      },
+      "diagnostic_message": {
+        "family": "Zed Sans",
+        "color": "#93a1a1",
+        "size": 14
+      },
+      "lsp_message": {
+        "family": "Zed Sans",
+        "color": "#93a1a1",
+        "size": 14
+      },
+      "auto_update_progress_message": {
+        "family": "Zed Sans",
+        "color": "#93a1a1",
+        "size": 14
+      },
+      "auto_update_done_message": {
+        "family": "Zed Sans",
+        "color": "#93a1a1",
+        "size": 14
+      }
+    },
+    "titlebar": {
+      "avatar_width": 18,
+      "height": 32,
+      "background": "#073642",
+      "padding": {
+        "left": 80
+      },
+      "title": {
+        "family": "Zed Sans",
+        "color": "#eee8d5",
+        "size": 14
+      },
+      "avatar": {
+        "corner_radius": 10,
+        "border": {
+          "color": "#00000088",
+          "width": 1
+        }
+      },
+      "avatar_ribbon": {
+        "height": 3,
+        "width": 12
+      },
+      "border": {
+        "color": "#002b36",
+        "width": 1,
+        "bottom": true
+      },
+      "sign_in_prompt": {
+        "family": "Zed Sans",
+        "color": "#93a1a1",
+        "size": 12,
+        "border": {
+          "color": "#002b36",
+          "width": 1
+        },
+        "corner_radius": 6,
+        "margin": {
+          "top": 1,
+          "right": 6
+        },
+        "padding": {
+          "left": 6,
+          "right": 6
+        }
+      },
+      "hovered_sign_in_prompt": {
+        "family": "Zed Sans",
+        "color": "#fdf6e3",
+        "size": 12,
+        "border": {
+          "color": "#002b36",
+          "width": 1
+        },
+        "corner_radius": 6,
+        "margin": {
+          "top": 1,
+          "right": 6
+        },
+        "padding": {
+          "left": 6,
+          "right": 6
+        }
+      },
+      "offline_icon": {
+        "color": "#93a1a1",
+        "width": 16,
+        "padding": {
+          "right": 4
+        }
+      },
+      "share_icon": {
+        "margin": {
+          "top": 3,
+          "bottom": 2
+        },
+        "corner_radius": 6,
+        "color": "#93a1a1"
+      },
+      "hovered_share_icon": {
+        "margin": {
+          "top": 3,
+          "bottom": 2
+        },
+        "corner_radius": 6,
+        "background": "#586e7552",
+        "color": "#93a1a1"
+      },
+      "hovered_active_share_icon": {
+        "margin": {
+          "top": 3,
+          "bottom": 2
+        },
+        "corner_radius": 6,
+        "background": "#586e7552",
+        "color": "#fdf6e3"
+      },
+      "active_share_icon": {
+        "margin": {
+          "top": 3,
+          "bottom": 2
+        },
+        "corner_radius": 6,
+        "background": "#586e757a",
+        "color": "#fdf6e3"
+      },
+      "outdated_warning": {
+        "family": "Zed Sans",
+        "color": "#b58900",
+        "size": 13,
+        "margin": {
+          "right": 6
+        }
+      }
+    },
+    "toolbar": {
+      "height": 34,
+      "background": "#002b36",
+      "border": {
+        "color": "#073642",
+        "width": 1,
+        "bottom": true
+      },
+      "item_spacing": 8,
+      "padding": {
+        "left": 16,
+        "right": 8,
+        "top": 4,
+        "bottom": 4
+      }
+    },
+    "breadcrumbs": {
+      "family": "Zed Mono",
+      "color": "#93a1a1",
+      "size": 14,
+      "padding": {
+        "left": 6
+      }
+    },
+    "disconnected_overlay": {
+      "family": "Zed Sans",
+      "color": "#fdf6e3",
+      "size": 14,
+      "background": "#000000aa"
+    }
+  },
+  "editor": {
+    "text_color": "#fdf6e3",
+    "background": "#002b36",
+    "active_line_background": "#fdf6e312",
+    "code_actions_indicator": "#93a1a1",
+    "diff_background_deleted": "#dc322f",
+    "diff_background_inserted": "#859900",
+    "document_highlight_read_background": "#002b361f",
+    "document_highlight_write_background": "#002b3629",
+    "error_color": "#dc322f",
+    "gutter_background": "#002b36",
+    "gutter_padding_factor": 3.5,
+    "highlighted_line_background": "#fdf6e31f",
+    "line_number": "#839496",
+    "line_number_active": "#fdf6e3",
+    "rename_fade": 0.6,
+    "unnecessary_code_fade": 0.5,
+    "selection": {
+      "cursor": "#268bd2",
+      "selection": "#268bd23d"
+    },
+    "guest_selections": [
+      {
+        "cursor": "#859900",
+        "selection": "#8599003d"
+      },
+      {
+        "cursor": "#d33682",
+        "selection": "#d336823d"
+      },
+      {
+        "cursor": "#cb4b16",
+        "selection": "#cb4b163d"
+      },
+      {
+        "cursor": "#6c71c4",
+        "selection": "#6c71c43d"
+      },
+      {
+        "cursor": "#2aa198",
+        "selection": "#2aa1983d"
+      },
+      {
+        "cursor": "#dc322f",
+        "selection": "#dc322f3d"
+      },
+      {
+        "cursor": "#b58900",
+        "selection": "#b589003d"
+      }
+    ],
+    "autocomplete": {
+      "background": "#002b36",
+      "corner_radius": 8,
+      "padding": 4,
+      "border": {
+        "color": "#073642",
+        "width": 1
+      },
+      "item": {
+        "corner_radius": 6,
+        "padding": {
+          "bottom": 2,
+          "left": 6,
+          "right": 6,
+          "top": 2
+        }
+      },
+      "hovered_item": {
+        "corner_radius": 6,
+        "padding": {
+          "bottom": 2,
+          "left": 6,
+          "right": 6,
+          "top": 2
+        },
+        "background": "#073642"
+      },
+      "margin": {
+        "left": -14
+      },
+      "match_highlight": {
+        "family": "Zed Mono",
+        "color": "#268bd2",
+        "size": 14
+      },
+      "selected_item": {
+        "corner_radius": 6,
+        "padding": {
+          "bottom": 2,
+          "left": 6,
+          "right": 6,
+          "top": 2
+        },
+        "background": "#073642"
+      }
+    },
+    "diagnostic_header": {
+      "background": "#073642",
+      "icon_width_factor": 1.5,
+      "text_scale_factor": 0.857,
+      "border": {
+        "color": "#073642",
+        "width": 1,
+        "bottom": true,
+        "top": true
+      },
+      "code": {
+        "family": "Zed Mono",
+        "color": "#93a1a1",
+        "size": 14,
+        "margin": {
+          "left": 10
+        }
+      },
+      "message": {
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#eee8d5",
+          "size": 14,
+          "weight": "bold"
+        },
+        "text": {
+          "family": "Zed Sans",
+          "color": "#93a1a1",
+          "size": 14
+        }
+      }
+    },
+    "diagnostic_path_header": {
+      "background": "#fdf6e312",
+      "text_scale_factor": 0.857,
+      "filename": {
+        "family": "Zed Mono",
+        "color": "#eee8d5",
+        "size": 14
+      },
+      "path": {
+        "family": "Zed Mono",
+        "color": "#93a1a1",
+        "size": 14,
+        "margin": {
+          "left": 12
+        }
+      }
+    },
+    "error_diagnostic": {
+      "text_scale_factor": 0.857,
+      "header": {
+        "border": {
+          "color": "#002b36",
+          "width": 1,
+          "top": true
+        }
+      },
+      "message": {
+        "text": {
+          "family": "Zed Sans",
+          "color": "#dc322f",
+          "size": 14
+        },
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#dc322f",
+          "size": 14,
+          "weight": "bold"
+        }
+      }
+    },
+    "warning_diagnostic": {
+      "text_scale_factor": 0.857,
+      "header": {
+        "border": {
+          "color": "#002b36",
+          "width": 1,
+          "top": true
+        }
+      },
+      "message": {
+        "text": {
+          "family": "Zed Sans",
+          "color": "#b58900",
+          "size": 14
+        },
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#b58900",
+          "size": 14,
+          "weight": "bold"
+        }
+      }
+    },
+    "information_diagnostic": {
+      "text_scale_factor": 0.857,
+      "header": {
+        "border": {
+          "color": "#002b36",
+          "width": 1,
+          "top": true
+        }
+      },
+      "message": {
+        "text": {
+          "family": "Zed Sans",
+          "color": "#268bd2",
+          "size": 14
+        },
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#268bd2",
+          "size": 14,
+          "weight": "bold"
+        }
+      }
+    },
+    "hint_diagnostic": {
+      "text_scale_factor": 0.857,
+      "header": {
+        "border": {
+          "color": "#002b36",
+          "width": 1,
+          "top": true
+        }
+      },
+      "message": {
+        "text": {
+          "family": "Zed Sans",
+          "color": "#268bd2",
+          "size": 14
+        },
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#268bd2",
+          "size": 14,
+          "weight": "bold"
+        }
+      }
+    },
+    "invalid_error_diagnostic": {
+      "text_scale_factor": 0.857,
+      "header": {
+        "border": {
+          "color": "#002b36",
+          "width": 1,
+          "top": true
+        }
+      },
+      "message": {
+        "text": {
+          "family": "Zed Sans",
+          "color": "#93a1a1",
+          "size": 14
+        },
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#93a1a1",
+          "size": 14,
+          "weight": "bold"
+        }
+      }
+    },
+    "invalid_hint_diagnostic": {
+      "text_scale_factor": 0.857,
+      "header": {
+        "border": {
+          "color": "#002b36",
+          "width": 1,
+          "top": true
+        }
+      },
+      "message": {
+        "text": {
+          "family": "Zed Sans",
+          "color": "#93a1a1",
+          "size": 14
+        },
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#93a1a1",
+          "size": 14,
+          "weight": "bold"
+        }
+      }
+    },
+    "invalid_information_diagnostic": {
+      "text_scale_factor": 0.857,
+      "header": {
+        "border": {
+          "color": "#002b36",
+          "width": 1,
+          "top": true
+        }
+      },
+      "message": {
+        "text": {
+          "family": "Zed Sans",
+          "color": "#93a1a1",
+          "size": 14
+        },
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#93a1a1",
+          "size": 14,
+          "weight": "bold"
+        }
+      }
+    },
+    "invalid_warning_diagnostic": {
+      "text_scale_factor": 0.857,
+      "header": {
+        "border": {
+          "color": "#002b36",
+          "width": 1,
+          "top": true
+        }
+      },
+      "message": {
+        "text": {
+          "family": "Zed Sans",
+          "color": "#93a1a1",
+          "size": 14
+        },
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#93a1a1",
+          "size": 14,
+          "weight": "bold"
+        }
+      }
+    },
+    "syntax": {
+      "primary": {
+        "color": "#fdf6e3",
+        "weight": "normal"
+      },
+      "comment": {
+        "color": "#93a1a1",
+        "weight": "normal"
+      },
+      "punctuation": {
+        "color": "#93a1a1",
+        "weight": "normal"
+      },
+      "constant": {
+        "color": "#839496",
+        "weight": "normal"
+      },
+      "keyword": {
+        "color": "#268bd2",
+        "weight": "normal"
+      },
+      "function": {
+        "color": "#b58900",
+        "weight": "normal"
+      },
+      "type": {
+        "color": "#2aa198",
+        "weight": "normal"
+      },
+      "variant": {
+        "color": "#268bd2",
+        "weight": "normal"
+      },
+      "property": {
+        "color": "#268bd2",
+        "weight": "normal"
+      },
+      "enum": {
+        "color": "#cb4b16",
+        "weight": "normal"
+      },
+      "operator": {
+        "color": "#cb4b16",
+        "weight": "normal"
+      },
+      "string": {
+        "color": "#cb4b16",
+        "weight": "normal"
+      },
+      "number": {
+        "color": "#859900",
+        "weight": "normal"
+      },
+      "boolean": {
+        "color": "#859900",
+        "weight": "normal"
+      },
+      "predictive": {
+        "color": "#93a1a1",
+        "weight": "normal"
+      },
+      "title": {
+        "color": "#b58900",
+        "weight": "bold"
+      },
+      "emphasis": {
+        "color": "#268bd2",
+        "weight": "normal"
+      },
+      "emphasis.strong": {
+        "color": "#268bd2",
+        "weight": "bold"
+      },
+      "link_uri": {
+        "color": "#859900",
+        "weight": "normal",
+        "underline": true
+      },
+      "link_text": {
+        "color": "#cb4b16",
+        "weight": "normal",
+        "italic": true
+      }
+    }
+  },
+  "project_diagnostics": {
+    "tab_icon_spacing": 4,
+    "tab_icon_width": 13,
+    "tab_summary_spacing": 10,
+    "empty_message": {
+      "family": "Zed Sans",
+      "color": "#eee8d5",
+      "size": 18
+    },
+    "status_bar_item": {
+      "family": "Zed Sans",
+      "color": "#93a1a1",
+      "size": 14,
+      "margin": {
+        "right": 10
+      }
+    }
+  },
+  "command_palette": {
+    "keystroke_spacing": 8,
+    "key": {
+      "text": {
+        "family": "Zed Mono",
+        "color": "#93a1a1",
+        "size": 12
+      },
+      "corner_radius": 4,
+      "background": "#002b36",
+      "border": {
+        "color": "#073642",
+        "width": 1
+      },
+      "padding": {
+        "top": 2,
+        "bottom": 2,
+        "left": 8,
+        "right": 8
+      },
+      "margin": {
+        "left": 2
+      }
+    }
+  },
+  "project_panel": {
+    "padding": {
+      "top": 6,
+      "left": 12
+    },
+    "entry": {
+      "height": 22,
+      "icon_color": "#93a1a1",
+      "icon_size": 8,
+      "icon_spacing": 8,
+      "text": {
+        "family": "Zed Mono",
+        "color": "#93a1a1",
+        "size": 14
+      }
+    },
+    "hovered_entry": {
+      "height": 22,
+      "background": "#586e7552",
+      "icon_color": "#93a1a1",
+      "icon_size": 8,
+      "icon_spacing": 8,
+      "text": {
+        "family": "Zed Mono",
+        "color": "#93a1a1",
+        "size": 14
+      }
+    },
+    "selected_entry": {
+      "height": 22,
+      "icon_color": "#93a1a1",
+      "icon_size": 8,
+      "icon_spacing": 8,
+      "text": {
+        "family": "Zed Mono",
+        "color": "#eee8d5",
+        "size": 14
+      }
+    },
+    "hovered_selected_entry": {
+      "height": 22,
+      "background": "#586e7552",
+      "icon_color": "#93a1a1",
+      "icon_size": 8,
+      "icon_spacing": 8,
+      "text": {
+        "family": "Zed Mono",
+        "color": "#eee8d5",
+        "size": 14
+      }
+    }
+  },
+  "chat_panel": {
+    "padding": {
+      "top": 12,
+      "left": 12,
+      "bottom": 12,
+      "right": 12
+    },
+    "channel_name": {
+      "family": "Zed Sans",
+      "color": "#eee8d5",
+      "weight": "bold",
+      "size": 14
+    },
+    "channel_name_hash": {
+      "family": "Zed Sans",
+      "color": "#93a1a1",
+      "size": 14,
+      "padding": {
+        "right": 8
+      }
+    },
+    "channel_select": {
+      "header": {
+        "name": {
+          "family": "Zed Sans",
+          "color": "#eee8d5",
+          "size": 14
+        },
+        "padding": {
+          "bottom": 4,
+          "left": 0
+        },
+        "hash": {
+          "family": "Zed Sans",
+          "color": "#93a1a1",
+          "size": 14,
+          "margin": {
+            "right": 8
+          }
+        },
+        "corner_radius": 0
+      },
+      "item": {
+        "name": {
+          "family": "Zed Sans",
+          "color": "#93a1a1",
+          "size": 14
+        },
+        "padding": 4,
+        "hash": {
+          "family": "Zed Sans",
+          "color": "#93a1a1",
+          "size": 14,
+          "margin": {
+            "right": 8
+          }
+        },
+        "corner_radius": 0
+      },
+      "hovered_item": {
+        "name": {
+          "family": "Zed Sans",
+          "color": "#93a1a1",
+          "size": 14
+        },
+        "padding": 4,
+        "hash": {
+          "family": "Zed Sans",
+          "color": "#93a1a1",
+          "size": 14,
+          "margin": {
+            "right": 8
+          }
+        },
+        "background": "#586e7552",
+        "corner_radius": 6
+      },
+      "active_item": {
+        "name": {
+          "family": "Zed Sans",
+          "color": "#eee8d5",
+          "size": 14
+        },
+        "padding": 4,
+        "hash": {
+          "family": "Zed Sans",
+          "color": "#93a1a1",
+          "size": 14,
+          "margin": {
+            "right": 8
+          }
+        },
+        "corner_radius": 0
+      },
+      "hovered_active_item": {
+        "name": {
+          "family": "Zed Sans",
+          "color": "#eee8d5",
+          "size": 14
+        },
+        "padding": 4,
+        "hash": {
+          "family": "Zed Sans",
+          "color": "#93a1a1",
+          "size": 14,
+          "margin": {
+            "right": 8
+          }
+        },
+        "background": "#586e7552",
+        "corner_radius": 6
+      },
+      "menu": {
+        "background": "#002b36",
+        "corner_radius": 6,
+        "padding": 4,
+        "border": {
+          "color": "#002b36",
+          "width": 1
+        },
+        "shadow": {
+          "blur": 16,
+          "color": "#00000052",
+          "offset": [
+            0,
+            2
+          ]
+        }
+      }
+    },
+    "sign_in_prompt": {
+      "family": "Zed Sans",
+      "color": "#93a1a1",
+      "underline": true,
+      "size": 14
+    },
+    "hovered_sign_in_prompt": {
+      "family": "Zed Sans",
+      "color": "#eee8d5",
+      "underline": true,
+      "size": 14
+    },
+    "message": {
+      "body": {
+        "family": "Zed Sans",
+        "color": "#93a1a1",
+        "size": 14
+      },
+      "timestamp": {
+        "family": "Zed Sans",
+        "color": "#93a1a1",
+        "size": 14
+      },
+      "padding": {
+        "bottom": 6
+      },
+      "sender": {
+        "family": "Zed Sans",
+        "color": "#eee8d5",
+        "weight": "bold",
+        "size": 14,
+        "margin": {
+          "right": 8
+        }
+      }
+    },
+    "pending_message": {
+      "body": {
+        "family": "Zed Sans",
+        "color": "#93a1a1",
+        "size": 14
+      },
+      "timestamp": {
+        "family": "Zed Sans",
+        "color": "#93a1a1",
+        "size": 14
+      },
+      "padding": {
+        "bottom": 6
+      },
+      "sender": {
+        "family": "Zed Sans",
+        "color": "#93a1a1",
+        "weight": "bold",
+        "size": 14,
+        "margin": {
+          "right": 8
+        }
+      }
+    },
+    "input_editor": {
+      "background": "#002b36",
+      "corner_radius": 6,
+      "text": {
+        "family": "Zed Mono",
+        "color": "#eee8d5",
+        "size": 14
+      },
+      "placeholder_text": {
+        "family": "Zed Mono",
+        "color": "#839496",
+        "size": 14
+      },
+      "selection": {
+        "cursor": "#268bd2",
+        "selection": "#268bd23d"
+      },
+      "border": {
+        "color": "#073642",
+        "width": 1
+      },
+      "padding": {
+        "bottom": 7,
+        "left": 8,
+        "right": 8,
+        "top": 7
+      }
+    }
+  },
+  "contacts_panel": {
+    "padding": {
+      "top": 12,
+      "left": 12,
+      "bottom": 12,
+      "right": 12
+    },
+    "host_row_height": 28,
+    "tree_branch_color": "#657b83",
+    "tree_branch_width": 1,
+    "host_avatar": {
+      "corner_radius": 10,
+      "width": 18
+    },
+    "host_username": {
+      "family": "Zed Mono",
+      "color": "#eee8d5",
+      "size": 14,
+      "padding": {
+        "left": 8
+      }
+    },
+    "project": {
+      "guest_avatar_spacing": 4,
+      "height": 24,
+      "guest_avatar": {
+        "corner_radius": 8,
+        "width": 14
+      },
+      "name": {
+        "family": "Zed Mono",
+        "color": "#839496",
+        "size": 14,
+        "margin": {
+          "right": 6
+        }
+      },
+      "padding": {
+        "left": 8
+      }
+    },
+    "shared_project": {
+      "guest_avatar_spacing": 4,
+      "height": 24,
+      "guest_avatar": {
+        "corner_radius": 8,
+        "width": 14
+      },
+      "name": {
+        "family": "Zed Mono",
+        "color": "#93a1a1",
+        "size": 14,
+        "margin": {
+          "right": 6
+        }
+      },
+      "padding": {
+        "left": 8
+      },
+      "background": "#073642",
+      "corner_radius": 6
+    },
+    "hovered_shared_project": {
+      "guest_avatar_spacing": 4,
+      "height": 24,
+      "guest_avatar": {
+        "corner_radius": 8,
+        "width": 14
+      },
+      "name": {
+        "family": "Zed Mono",
+        "color": "#93a1a1",
+        "size": 14,
+        "margin": {
+          "right": 6
+        }
+      },
+      "padding": {
+        "left": 8
+      },
+      "background": "#586e7552",
+      "corner_radius": 6
+    },
+    "unshared_project": {
+      "guest_avatar_spacing": 4,
+      "height": 24,
+      "guest_avatar": {
+        "corner_radius": 8,
+        "width": 14
+      },
+      "name": {
+        "family": "Zed Mono",
+        "color": "#839496",
+        "size": 14,
+        "margin": {
+          "right": 6
+        }
+      },
+      "padding": {
+        "left": 8
+      }
+    },
+    "hovered_unshared_project": {
+      "guest_avatar_spacing": 4,
+      "height": 24,
+      "guest_avatar": {
+        "corner_radius": 8,
+        "width": 14
+      },
+      "name": {
+        "family": "Zed Mono",
+        "color": "#839496",
+        "size": 14,
+        "margin": {
+          "right": 6
+        }
+      },
+      "padding": {
+        "left": 8
+      },
+      "corner_radius": 6
+    }
+  },
+  "search": {
+    "match_background": "#6c71c480",
+    "tab_icon_spacing": 8,
+    "tab_icon_width": 14,
+    "active_hovered_option_button": {
+      "family": "Zed Mono",
+      "color": "#fdf6e3",
+      "size": 14,
+      "background": "#657b83",
+      "corner_radius": 4,
+      "border": {
+        "color": "#657b83",
+        "width": 1
+      },
+      "margin": {
+        "left": 2,
+        "right": 2
+      },
+      "padding": {
+        "bottom": 3,
+        "left": 8,
+        "right": 8,
+        "top": 3
+      }
+    },
+    "active_option_button": {
+      "family": "Zed Mono",
+      "color": "#fdf6e3",
+      "size": 14,
+      "background": "#657b83",
+      "corner_radius": 4,
+      "border": {
+        "color": "#657b83",
+        "width": 1
+      },
+      "margin": {
+        "left": 2,
+        "right": 2
+      },
+      "padding": {
+        "bottom": 3,
+        "left": 8,
+        "right": 8,
+        "top": 3
+      }
+    },
+    "editor": {
+      "background": "#002b36",
+      "corner_radius": 8,
+      "min_width": 200,
+      "max_width": 500,
+      "placeholder_text": {
+        "family": "Zed Mono",
+        "color": "#839496",
+        "size": 14
+      },
+      "selection": {
+        "cursor": "#268bd2",
+        "selection": "#268bd23d"
+      },
+      "text": {
+        "family": "Zed Mono",
+        "color": "#fdf6e3",
+        "size": 14
+      },
+      "border": {
+        "color": "#073642",
+        "width": 1
+      },
+      "margin": {
+        "right": 6
+      },
+      "padding": {
+        "top": 3,
+        "bottom": 3,
+        "left": 12,
+        "right": 8
+      }
+    },
+    "hovered_option_button": {
+      "family": "Zed Mono",
+      "color": "#fdf6e3",
+      "size": 14,
+      "background": "#073642",
+      "corner_radius": 4,
+      "border": {
+        "color": "#657b83",
+        "width": 1
+      },
+      "margin": {
+        "left": 2,
+        "right": 2
+      },
+      "padding": {
+        "bottom": 3,
+        "left": 8,
+        "right": 8,
+        "top": 3
+      }
+    },
+    "invalid_editor": {
+      "background": "#002b36",
+      "corner_radius": 8,
+      "min_width": 200,
+      "max_width": 500,
+      "placeholder_text": {
+        "family": "Zed Mono",
+        "color": "#839496",
+        "size": 14
+      },
+      "selection": {
+        "cursor": "#268bd2",
+        "selection": "#268bd23d"
+      },
+      "text": {
+        "family": "Zed Mono",
+        "color": "#fdf6e3",
+        "size": 14
+      },
+      "border": {
+        "color": "#dc322f",
+        "width": 1
+      },
+      "margin": {
+        "right": 6
+      },
+      "padding": {
+        "top": 3,
+        "bottom": 3,
+        "left": 12,
+        "right": 8
+      }
+    },
+    "match_index": {
+      "family": "Zed Mono",
+      "color": "#93a1a1",
+      "size": 14,
+      "padding": 6
+    },
+    "option_button": {
+      "family": "Zed Mono",
+      "color": "#93a1a1",
+      "size": 14,
+      "background": "#073642",
+      "corner_radius": 4,
+      "border": {
+        "color": "#073642",
+        "width": 1
+      },
+      "margin": {
+        "left": 2,
+        "right": 2
+      },
+      "padding": {
+        "bottom": 3,
+        "left": 8,
+        "right": 8,
+        "top": 3
+      }
+    },
+    "option_button_group": {
+      "padding": {
+        "left": 4,
+        "right": 4
+      }
+    },
+    "results_status": {
+      "family": "Zed Mono",
+      "color": "#eee8d5",
+      "size": 18
+    }
+  },
+  "breadcrumbs": {
+    "family": "Zed Sans",
+    "color": "#93a1a1",
+    "size": 14,
+    "padding": {
+      "left": 6
+    }
+  }
+}

assets/themes/solarized-light.json 🔗

@@ -0,0 +1,1435 @@
+{
+  "selector": {
+    "background": "#eee8d5",
+    "corner_radius": 8,
+    "padding": 8,
+    "item": {
+      "padding": {
+        "bottom": 4,
+        "left": 12,
+        "right": 12,
+        "top": 4
+      },
+      "corner_radius": 8,
+      "text": {
+        "family": "Zed Sans",
+        "color": "#586e75",
+        "size": 14
+      },
+      "highlight_text": {
+        "family": "Zed Sans",
+        "color": "#268bd2",
+        "weight": "bold",
+        "size": 14
+      }
+    },
+    "active_item": {
+      "padding": {
+        "bottom": 4,
+        "left": 12,
+        "right": 12,
+        "top": 4
+      },
+      "corner_radius": 8,
+      "text": {
+        "family": "Zed Sans",
+        "color": "#073642",
+        "size": 14
+      },
+      "highlight_text": {
+        "family": "Zed Sans",
+        "color": "#268bd2",
+        "weight": "bold",
+        "size": 14
+      },
+      "background": "#93a1a12e"
+    },
+    "border": {
+      "color": "#fdf6e3",
+      "width": 1
+    },
+    "empty": {
+      "text": {
+        "family": "Zed Sans",
+        "color": "#657b83",
+        "size": 14
+      },
+      "padding": {
+        "bottom": 4,
+        "left": 12,
+        "right": 12,
+        "top": 8
+      }
+    },
+    "input_editor": {
+      "background": "#fdf6e3",
+      "corner_radius": 8,
+      "placeholder_text": {
+        "family": "Zed Sans",
+        "color": "#657b83",
+        "size": 14
+      },
+      "selection": {
+        "cursor": "#268bd2",
+        "selection": "#268bd23d"
+      },
+      "text": {
+        "family": "Zed Mono",
+        "color": "#073642",
+        "size": 14
+      },
+      "border": {
+        "color": "#eee8d5",
+        "width": 1
+      },
+      "padding": {
+        "bottom": 7,
+        "left": 16,
+        "right": 16,
+        "top": 7
+      }
+    },
+    "shadow": {
+      "blur": 16,
+      "color": "#0000001f",
+      "offset": [
+        0,
+        2
+      ]
+    }
+  },
+  "workspace": {
+    "background": "#eee8d5",
+    "leader_border_opacity": 0.7,
+    "leader_border_width": 2,
+    "tab": {
+      "height": 32,
+      "background": "#eee8d5",
+      "icon_close": "#586e75",
+      "icon_close_active": "#002b36",
+      "icon_conflict": "#b58900",
+      "icon_dirty": "#268bd2",
+      "icon_width": 8,
+      "spacing": 8,
+      "text": {
+        "family": "Zed Sans",
+        "color": "#586e75",
+        "size": 14
+      },
+      "border": {
+        "color": "#fdf6e3",
+        "width": 1,
+        "left": true,
+        "bottom": true,
+        "overlay": true
+      },
+      "padding": {
+        "left": 8,
+        "right": 8
+      }
+    },
+    "active_tab": {
+      "height": 32,
+      "background": "#fdf6e3",
+      "icon_close": "#586e75",
+      "icon_close_active": "#002b36",
+      "icon_conflict": "#b58900",
+      "icon_dirty": "#268bd2",
+      "icon_width": 8,
+      "spacing": 8,
+      "text": {
+        "family": "Zed Sans",
+        "color": "#002b36",
+        "size": 14
+      },
+      "border": {
+        "color": "#fdf6e3",
+        "width": 1,
+        "left": true,
+        "bottom": false,
+        "overlay": true
+      },
+      "padding": {
+        "left": 8,
+        "right": 8
+      }
+    },
+    "modal": {
+      "margin": {
+        "bottom": 52,
+        "top": 52
+      },
+      "cursor": "Arrow"
+    },
+    "left_sidebar": {
+      "width": 30,
+      "background": "#eee8d5",
+      "border": {
+        "color": "#fdf6e3",
+        "width": 1,
+        "right": true
+      },
+      "item": {
+        "height": 32,
+        "icon_color": "#586e75",
+        "icon_size": 18
+      },
+      "active_item": {
+        "height": 32,
+        "icon_color": "#002b36",
+        "icon_size": 18
+      },
+      "resize_handle": {
+        "background": "#fdf6e3",
+        "padding": {
+          "left": 1
+        }
+      }
+    },
+    "right_sidebar": {
+      "width": 30,
+      "background": "#eee8d5",
+      "border": {
+        "color": "#fdf6e3",
+        "width": 1,
+        "left": true
+      },
+      "item": {
+        "height": 32,
+        "icon_color": "#586e75",
+        "icon_size": 18
+      },
+      "active_item": {
+        "height": 32,
+        "icon_color": "#002b36",
+        "icon_size": 18
+      },
+      "resize_handle": {
+        "background": "#fdf6e3",
+        "padding": {
+          "left": 1
+        }
+      }
+    },
+    "pane_divider": {
+      "color": "#eee8d5",
+      "width": 1
+    },
+    "status_bar": {
+      "height": 24,
+      "item_spacing": 8,
+      "padding": {
+        "left": 6,
+        "right": 6
+      },
+      "border": {
+        "color": "#fdf6e3",
+        "width": 1,
+        "top": true,
+        "overlay": true
+      },
+      "cursor_position": {
+        "family": "Zed Sans",
+        "color": "#586e75",
+        "size": 14
+      },
+      "diagnostic_message": {
+        "family": "Zed Sans",
+        "color": "#586e75",
+        "size": 14
+      },
+      "lsp_message": {
+        "family": "Zed Sans",
+        "color": "#586e75",
+        "size": 14
+      },
+      "auto_update_progress_message": {
+        "family": "Zed Sans",
+        "color": "#586e75",
+        "size": 14
+      },
+      "auto_update_done_message": {
+        "family": "Zed Sans",
+        "color": "#586e75",
+        "size": 14
+      }
+    },
+    "titlebar": {
+      "avatar_width": 18,
+      "height": 32,
+      "background": "#eee8d5",
+      "padding": {
+        "left": 80
+      },
+      "title": {
+        "family": "Zed Sans",
+        "color": "#073642",
+        "size": 14
+      },
+      "avatar": {
+        "corner_radius": 10,
+        "border": {
+          "color": "#00000088",
+          "width": 1
+        }
+      },
+      "avatar_ribbon": {
+        "height": 3,
+        "width": 12
+      },
+      "border": {
+        "color": "#fdf6e3",
+        "width": 1,
+        "bottom": true
+      },
+      "sign_in_prompt": {
+        "family": "Zed Sans",
+        "color": "#586e75",
+        "size": 12,
+        "border": {
+          "color": "#fdf6e3",
+          "width": 1
+        },
+        "corner_radius": 6,
+        "margin": {
+          "top": 1,
+          "right": 6
+        },
+        "padding": {
+          "left": 6,
+          "right": 6
+        }
+      },
+      "hovered_sign_in_prompt": {
+        "family": "Zed Sans",
+        "color": "#002b36",
+        "size": 12,
+        "border": {
+          "color": "#fdf6e3",
+          "width": 1
+        },
+        "corner_radius": 6,
+        "margin": {
+          "top": 1,
+          "right": 6
+        },
+        "padding": {
+          "left": 6,
+          "right": 6
+        }
+      },
+      "offline_icon": {
+        "color": "#586e75",
+        "width": 16,
+        "padding": {
+          "right": 4
+        }
+      },
+      "share_icon": {
+        "margin": {
+          "top": 3,
+          "bottom": 2
+        },
+        "corner_radius": 6,
+        "color": "#586e75"
+      },
+      "hovered_share_icon": {
+        "margin": {
+          "top": 3,
+          "bottom": 2
+        },
+        "corner_radius": 6,
+        "background": "#93a1a11f",
+        "color": "#586e75"
+      },
+      "hovered_active_share_icon": {
+        "margin": {
+          "top": 3,
+          "bottom": 2
+        },
+        "corner_radius": 6,
+        "background": "#93a1a11f",
+        "color": "#002b36"
+      },
+      "active_share_icon": {
+        "margin": {
+          "top": 3,
+          "bottom": 2
+        },
+        "corner_radius": 6,
+        "background": "#93a1a12e",
+        "color": "#002b36"
+      },
+      "outdated_warning": {
+        "family": "Zed Sans",
+        "color": "#b58900",
+        "size": 13,
+        "margin": {
+          "right": 6
+        }
+      }
+    },
+    "toolbar": {
+      "height": 34,
+      "background": "#fdf6e3",
+      "border": {
+        "color": "#eee8d5",
+        "width": 1,
+        "bottom": true
+      },
+      "item_spacing": 8,
+      "padding": {
+        "left": 16,
+        "right": 8,
+        "top": 4,
+        "bottom": 4
+      }
+    },
+    "breadcrumbs": {
+      "family": "Zed Mono",
+      "color": "#586e75",
+      "size": 14,
+      "padding": {
+        "left": 6
+      }
+    },
+    "disconnected_overlay": {
+      "family": "Zed Sans",
+      "color": "#002b36",
+      "size": 14,
+      "background": "#000000aa"
+    }
+  },
+  "editor": {
+    "text_color": "#002b36",
+    "background": "#fdf6e3",
+    "active_line_background": "#002b3612",
+    "code_actions_indicator": "#586e75",
+    "diff_background_deleted": "#dc322f",
+    "diff_background_inserted": "#859900",
+    "document_highlight_read_background": "#fdf6e31f",
+    "document_highlight_write_background": "#fdf6e329",
+    "error_color": "#dc322f",
+    "gutter_background": "#fdf6e3",
+    "gutter_padding_factor": 3.5,
+    "highlighted_line_background": "#002b361f",
+    "line_number": "#657b83",
+    "line_number_active": "#002b36",
+    "rename_fade": 0.6,
+    "unnecessary_code_fade": 0.5,
+    "selection": {
+      "cursor": "#268bd2",
+      "selection": "#268bd23d"
+    },
+    "guest_selections": [
+      {
+        "cursor": "#859900",
+        "selection": "#8599003d"
+      },
+      {
+        "cursor": "#d33682",
+        "selection": "#d336823d"
+      },
+      {
+        "cursor": "#cb4b16",
+        "selection": "#cb4b163d"
+      },
+      {
+        "cursor": "#6c71c4",
+        "selection": "#6c71c43d"
+      },
+      {
+        "cursor": "#2aa198",
+        "selection": "#2aa1983d"
+      },
+      {
+        "cursor": "#dc322f",
+        "selection": "#dc322f3d"
+      },
+      {
+        "cursor": "#b58900",
+        "selection": "#b589003d"
+      }
+    ],
+    "autocomplete": {
+      "background": "#fdf6e3",
+      "corner_radius": 8,
+      "padding": 4,
+      "border": {
+        "color": "#eee8d5",
+        "width": 1
+      },
+      "item": {
+        "corner_radius": 6,
+        "padding": {
+          "bottom": 2,
+          "left": 6,
+          "right": 6,
+          "top": 2
+        }
+      },
+      "hovered_item": {
+        "corner_radius": 6,
+        "padding": {
+          "bottom": 2,
+          "left": 6,
+          "right": 6,
+          "top": 2
+        },
+        "background": "#eee8d5"
+      },
+      "margin": {
+        "left": -14
+      },
+      "match_highlight": {
+        "family": "Zed Mono",
+        "color": "#268bd2",
+        "size": 14
+      },
+      "selected_item": {
+        "corner_radius": 6,
+        "padding": {
+          "bottom": 2,
+          "left": 6,
+          "right": 6,
+          "top": 2
+        },
+        "background": "#eee8d5"
+      }
+    },
+    "diagnostic_header": {
+      "background": "#eee8d5",
+      "icon_width_factor": 1.5,
+      "text_scale_factor": 0.857,
+      "border": {
+        "color": "#eee8d5",
+        "width": 1,
+        "bottom": true,
+        "top": true
+      },
+      "code": {
+        "family": "Zed Mono",
+        "color": "#586e75",
+        "size": 14,
+        "margin": {
+          "left": 10
+        }
+      },
+      "message": {
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#073642",
+          "size": 14,
+          "weight": "bold"
+        },
+        "text": {
+          "family": "Zed Sans",
+          "color": "#586e75",
+          "size": 14
+        }
+      }
+    },
+    "diagnostic_path_header": {
+      "background": "#002b3612",
+      "text_scale_factor": 0.857,
+      "filename": {
+        "family": "Zed Mono",
+        "color": "#073642",
+        "size": 14
+      },
+      "path": {
+        "family": "Zed Mono",
+        "color": "#586e75",
+        "size": 14,
+        "margin": {
+          "left": 12
+        }
+      }
+    },
+    "error_diagnostic": {
+      "text_scale_factor": 0.857,
+      "header": {
+        "border": {
+          "color": "#fdf6e3",
+          "width": 1,
+          "top": true
+        }
+      },
+      "message": {
+        "text": {
+          "family": "Zed Sans",
+          "color": "#dc322f",
+          "size": 14
+        },
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#dc322f",
+          "size": 14,
+          "weight": "bold"
+        }
+      }
+    },
+    "warning_diagnostic": {
+      "text_scale_factor": 0.857,
+      "header": {
+        "border": {
+          "color": "#fdf6e3",
+          "width": 1,
+          "top": true
+        }
+      },
+      "message": {
+        "text": {
+          "family": "Zed Sans",
+          "color": "#b58900",
+          "size": 14
+        },
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#b58900",
+          "size": 14,
+          "weight": "bold"
+        }
+      }
+    },
+    "information_diagnostic": {
+      "text_scale_factor": 0.857,
+      "header": {
+        "border": {
+          "color": "#fdf6e3",
+          "width": 1,
+          "top": true
+        }
+      },
+      "message": {
+        "text": {
+          "family": "Zed Sans",
+          "color": "#268bd2",
+          "size": 14
+        },
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#268bd2",
+          "size": 14,
+          "weight": "bold"
+        }
+      }
+    },
+    "hint_diagnostic": {
+      "text_scale_factor": 0.857,
+      "header": {
+        "border": {
+          "color": "#fdf6e3",
+          "width": 1,
+          "top": true
+        }
+      },
+      "message": {
+        "text": {
+          "family": "Zed Sans",
+          "color": "#268bd2",
+          "size": 14
+        },
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#268bd2",
+          "size": 14,
+          "weight": "bold"
+        }
+      }
+    },
+    "invalid_error_diagnostic": {
+      "text_scale_factor": 0.857,
+      "header": {
+        "border": {
+          "color": "#fdf6e3",
+          "width": 1,
+          "top": true
+        }
+      },
+      "message": {
+        "text": {
+          "family": "Zed Sans",
+          "color": "#586e75",
+          "size": 14
+        },
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#586e75",
+          "size": 14,
+          "weight": "bold"
+        }
+      }
+    },
+    "invalid_hint_diagnostic": {
+      "text_scale_factor": 0.857,
+      "header": {
+        "border": {
+          "color": "#fdf6e3",
+          "width": 1,
+          "top": true
+        }
+      },
+      "message": {
+        "text": {
+          "family": "Zed Sans",
+          "color": "#586e75",
+          "size": 14
+        },
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#586e75",
+          "size": 14,
+          "weight": "bold"
+        }
+      }
+    },
+    "invalid_information_diagnostic": {
+      "text_scale_factor": 0.857,
+      "header": {
+        "border": {
+          "color": "#fdf6e3",
+          "width": 1,
+          "top": true
+        }
+      },
+      "message": {
+        "text": {
+          "family": "Zed Sans",
+          "color": "#586e75",
+          "size": 14
+        },
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#586e75",
+          "size": 14,
+          "weight": "bold"
+        }
+      }
+    },
+    "invalid_warning_diagnostic": {
+      "text_scale_factor": 0.857,
+      "header": {
+        "border": {
+          "color": "#fdf6e3",
+          "width": 1,
+          "top": true
+        }
+      },
+      "message": {
+        "text": {
+          "family": "Zed Sans",
+          "color": "#586e75",
+          "size": 14
+        },
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#586e75",
+          "size": 14,
+          "weight": "bold"
+        }
+      }
+    },
+    "syntax": {
+      "primary": {
+        "color": "#002b36",
+        "weight": "normal"
+      },
+      "comment": {
+        "color": "#586e75",
+        "weight": "normal"
+      },
+      "punctuation": {
+        "color": "#586e75",
+        "weight": "normal"
+      },
+      "constant": {
+        "color": "#657b83",
+        "weight": "normal"
+      },
+      "keyword": {
+        "color": "#268bd2",
+        "weight": "normal"
+      },
+      "function": {
+        "color": "#b58900",
+        "weight": "normal"
+      },
+      "type": {
+        "color": "#2aa198",
+        "weight": "normal"
+      },
+      "variant": {
+        "color": "#268bd2",
+        "weight": "normal"
+      },
+      "property": {
+        "color": "#268bd2",
+        "weight": "normal"
+      },
+      "enum": {
+        "color": "#cb4b16",
+        "weight": "normal"
+      },
+      "operator": {
+        "color": "#cb4b16",
+        "weight": "normal"
+      },
+      "string": {
+        "color": "#cb4b16",
+        "weight": "normal"
+      },
+      "number": {
+        "color": "#859900",
+        "weight": "normal"
+      },
+      "boolean": {
+        "color": "#859900",
+        "weight": "normal"
+      },
+      "predictive": {
+        "color": "#586e75",
+        "weight": "normal"
+      },
+      "title": {
+        "color": "#b58900",
+        "weight": "bold"
+      },
+      "emphasis": {
+        "color": "#268bd2",
+        "weight": "normal"
+      },
+      "emphasis.strong": {
+        "color": "#268bd2",
+        "weight": "bold"
+      },
+      "link_uri": {
+        "color": "#859900",
+        "weight": "normal",
+        "underline": true
+      },
+      "link_text": {
+        "color": "#cb4b16",
+        "weight": "normal",
+        "italic": true
+      }
+    }
+  },
+  "project_diagnostics": {
+    "tab_icon_spacing": 4,
+    "tab_icon_width": 13,
+    "tab_summary_spacing": 10,
+    "empty_message": {
+      "family": "Zed Sans",
+      "color": "#073642",
+      "size": 18
+    },
+    "status_bar_item": {
+      "family": "Zed Sans",
+      "color": "#586e75",
+      "size": 14,
+      "margin": {
+        "right": 10
+      }
+    }
+  },
+  "command_palette": {
+    "keystroke_spacing": 8,
+    "key": {
+      "text": {
+        "family": "Zed Mono",
+        "color": "#586e75",
+        "size": 12
+      },
+      "corner_radius": 4,
+      "background": "#fdf6e3",
+      "border": {
+        "color": "#eee8d5",
+        "width": 1
+      },
+      "padding": {
+        "top": 2,
+        "bottom": 2,
+        "left": 8,
+        "right": 8
+      },
+      "margin": {
+        "left": 2
+      }
+    }
+  },
+  "project_panel": {
+    "padding": {
+      "top": 6,
+      "left": 12
+    },
+    "entry": {
+      "height": 22,
+      "icon_color": "#586e75",
+      "icon_size": 8,
+      "icon_spacing": 8,
+      "text": {
+        "family": "Zed Mono",
+        "color": "#586e75",
+        "size": 14
+      }
+    },
+    "hovered_entry": {
+      "height": 22,
+      "background": "#93a1a11f",
+      "icon_color": "#586e75",
+      "icon_size": 8,
+      "icon_spacing": 8,
+      "text": {
+        "family": "Zed Mono",
+        "color": "#586e75",
+        "size": 14
+      }
+    },
+    "selected_entry": {
+      "height": 22,
+      "icon_color": "#586e75",
+      "icon_size": 8,
+      "icon_spacing": 8,
+      "text": {
+        "family": "Zed Mono",
+        "color": "#073642",
+        "size": 14
+      }
+    },
+    "hovered_selected_entry": {
+      "height": 22,
+      "background": "#93a1a11f",
+      "icon_color": "#586e75",
+      "icon_size": 8,
+      "icon_spacing": 8,
+      "text": {
+        "family": "Zed Mono",
+        "color": "#073642",
+        "size": 14
+      }
+    }
+  },
+  "chat_panel": {
+    "padding": {
+      "top": 12,
+      "left": 12,
+      "bottom": 12,
+      "right": 12
+    },
+    "channel_name": {
+      "family": "Zed Sans",
+      "color": "#073642",
+      "weight": "bold",
+      "size": 14
+    },
+    "channel_name_hash": {
+      "family": "Zed Sans",
+      "color": "#586e75",
+      "size": 14,
+      "padding": {
+        "right": 8
+      }
+    },
+    "channel_select": {
+      "header": {
+        "name": {
+          "family": "Zed Sans",
+          "color": "#073642",
+          "size": 14
+        },
+        "padding": {
+          "bottom": 4,
+          "left": 0
+        },
+        "hash": {
+          "family": "Zed Sans",
+          "color": "#586e75",
+          "size": 14,
+          "margin": {
+            "right": 8
+          }
+        },
+        "corner_radius": 0
+      },
+      "item": {
+        "name": {
+          "family": "Zed Sans",
+          "color": "#586e75",
+          "size": 14
+        },
+        "padding": 4,
+        "hash": {
+          "family": "Zed Sans",
+          "color": "#586e75",
+          "size": 14,
+          "margin": {
+            "right": 8
+          }
+        },
+        "corner_radius": 0
+      },
+      "hovered_item": {
+        "name": {
+          "family": "Zed Sans",
+          "color": "#586e75",
+          "size": 14
+        },
+        "padding": 4,
+        "hash": {
+          "family": "Zed Sans",
+          "color": "#586e75",
+          "size": 14,
+          "margin": {
+            "right": 8
+          }
+        },
+        "background": "#93a1a11f",
+        "corner_radius": 6
+      },
+      "active_item": {
+        "name": {
+          "family": "Zed Sans",
+          "color": "#073642",
+          "size": 14
+        },
+        "padding": 4,
+        "hash": {
+          "family": "Zed Sans",
+          "color": "#586e75",
+          "size": 14,
+          "margin": {
+            "right": 8
+          }
+        },
+        "corner_radius": 0
+      },
+      "hovered_active_item": {
+        "name": {
+          "family": "Zed Sans",
+          "color": "#073642",
+          "size": 14
+        },
+        "padding": 4,
+        "hash": {
+          "family": "Zed Sans",
+          "color": "#586e75",
+          "size": 14,
+          "margin": {
+            "right": 8
+          }
+        },
+        "background": "#93a1a11f",
+        "corner_radius": 6
+      },
+      "menu": {
+        "background": "#fdf6e3",
+        "corner_radius": 6,
+        "padding": 4,
+        "border": {
+          "color": "#fdf6e3",
+          "width": 1
+        },
+        "shadow": {
+          "blur": 16,
+          "color": "#0000001f",
+          "offset": [
+            0,
+            2
+          ]
+        }
+      }
+    },
+    "sign_in_prompt": {
+      "family": "Zed Sans",
+      "color": "#586e75",
+      "underline": true,
+      "size": 14
+    },
+    "hovered_sign_in_prompt": {
+      "family": "Zed Sans",
+      "color": "#073642",
+      "underline": true,
+      "size": 14
+    },
+    "message": {
+      "body": {
+        "family": "Zed Sans",
+        "color": "#586e75",
+        "size": 14
+      },
+      "timestamp": {
+        "family": "Zed Sans",
+        "color": "#586e75",
+        "size": 14
+      },
+      "padding": {
+        "bottom": 6
+      },
+      "sender": {
+        "family": "Zed Sans",
+        "color": "#073642",
+        "weight": "bold",
+        "size": 14,
+        "margin": {
+          "right": 8
+        }
+      }
+    },
+    "pending_message": {
+      "body": {
+        "family": "Zed Sans",
+        "color": "#586e75",
+        "size": 14
+      },
+      "timestamp": {
+        "family": "Zed Sans",
+        "color": "#586e75",
+        "size": 14
+      },
+      "padding": {
+        "bottom": 6
+      },
+      "sender": {
+        "family": "Zed Sans",
+        "color": "#586e75",
+        "weight": "bold",
+        "size": 14,
+        "margin": {
+          "right": 8
+        }
+      }
+    },
+    "input_editor": {
+      "background": "#fdf6e3",
+      "corner_radius": 6,
+      "text": {
+        "family": "Zed Mono",
+        "color": "#073642",
+        "size": 14
+      },
+      "placeholder_text": {
+        "family": "Zed Mono",
+        "color": "#657b83",
+        "size": 14
+      },
+      "selection": {
+        "cursor": "#268bd2",
+        "selection": "#268bd23d"
+      },
+      "border": {
+        "color": "#eee8d5",
+        "width": 1
+      },
+      "padding": {
+        "bottom": 7,
+        "left": 8,
+        "right": 8,
+        "top": 7
+      }
+    }
+  },
+  "contacts_panel": {
+    "padding": {
+      "top": 12,
+      "left": 12,
+      "bottom": 12,
+      "right": 12
+    },
+    "host_row_height": 28,
+    "tree_branch_color": "#839496",
+    "tree_branch_width": 1,
+    "host_avatar": {
+      "corner_radius": 10,
+      "width": 18
+    },
+    "host_username": {
+      "family": "Zed Mono",
+      "color": "#073642",
+      "size": 14,
+      "padding": {
+        "left": 8
+      }
+    },
+    "project": {
+      "guest_avatar_spacing": 4,
+      "height": 24,
+      "guest_avatar": {
+        "corner_radius": 8,
+        "width": 14
+      },
+      "name": {
+        "family": "Zed Mono",
+        "color": "#657b83",
+        "size": 14,
+        "margin": {
+          "right": 6
+        }
+      },
+      "padding": {
+        "left": 8
+      }
+    },
+    "shared_project": {
+      "guest_avatar_spacing": 4,
+      "height": 24,
+      "guest_avatar": {
+        "corner_radius": 8,
+        "width": 14
+      },
+      "name": {
+        "family": "Zed Mono",
+        "color": "#586e75",
+        "size": 14,
+        "margin": {
+          "right": 6
+        }
+      },
+      "padding": {
+        "left": 8
+      },
+      "background": "#eee8d5",
+      "corner_radius": 6
+    },
+    "hovered_shared_project": {
+      "guest_avatar_spacing": 4,
+      "height": 24,
+      "guest_avatar": {
+        "corner_radius": 8,
+        "width": 14
+      },
+      "name": {
+        "family": "Zed Mono",
+        "color": "#586e75",
+        "size": 14,
+        "margin": {
+          "right": 6
+        }
+      },
+      "padding": {
+        "left": 8
+      },
+      "background": "#93a1a11f",
+      "corner_radius": 6
+    },
+    "unshared_project": {
+      "guest_avatar_spacing": 4,
+      "height": 24,
+      "guest_avatar": {
+        "corner_radius": 8,
+        "width": 14
+      },
+      "name": {
+        "family": "Zed Mono",
+        "color": "#657b83",
+        "size": 14,
+        "margin": {
+          "right": 6
+        }
+      },
+      "padding": {
+        "left": 8
+      }
+    },
+    "hovered_unshared_project": {
+      "guest_avatar_spacing": 4,
+      "height": 24,
+      "guest_avatar": {
+        "corner_radius": 8,
+        "width": 14
+      },
+      "name": {
+        "family": "Zed Mono",
+        "color": "#657b83",
+        "size": 14,
+        "margin": {
+          "right": 6
+        }
+      },
+      "padding": {
+        "left": 8
+      },
+      "corner_radius": 6
+    }
+  },
+  "search": {
+    "match_background": "#6c71c480",
+    "tab_icon_spacing": 8,
+    "tab_icon_width": 14,
+    "active_hovered_option_button": {
+      "family": "Zed Mono",
+      "color": "#002b36",
+      "size": 14,
+      "background": "#839496",
+      "corner_radius": 4,
+      "border": {
+        "color": "#839496",
+        "width": 1
+      },
+      "margin": {
+        "left": 2,
+        "right": 2
+      },
+      "padding": {
+        "bottom": 3,
+        "left": 8,
+        "right": 8,
+        "top": 3
+      }
+    },
+    "active_option_button": {
+      "family": "Zed Mono",
+      "color": "#002b36",
+      "size": 14,
+      "background": "#839496",
+      "corner_radius": 4,
+      "border": {
+        "color": "#839496",
+        "width": 1
+      },
+      "margin": {
+        "left": 2,
+        "right": 2
+      },
+      "padding": {
+        "bottom": 3,
+        "left": 8,
+        "right": 8,
+        "top": 3
+      }
+    },
+    "editor": {
+      "background": "#fdf6e3",
+      "corner_radius": 8,
+      "min_width": 200,
+      "max_width": 500,
+      "placeholder_text": {
+        "family": "Zed Mono",
+        "color": "#657b83",
+        "size": 14
+      },
+      "selection": {
+        "cursor": "#268bd2",
+        "selection": "#268bd23d"
+      },
+      "text": {
+        "family": "Zed Mono",
+        "color": "#002b36",
+        "size": 14
+      },
+      "border": {
+        "color": "#eee8d5",
+        "width": 1
+      },
+      "margin": {
+        "right": 6
+      },
+      "padding": {
+        "top": 3,
+        "bottom": 3,
+        "left": 12,
+        "right": 8
+      }
+    },
+    "hovered_option_button": {
+      "family": "Zed Mono",
+      "color": "#002b36",
+      "size": 14,
+      "background": "#eee8d5",
+      "corner_radius": 4,
+      "border": {
+        "color": "#839496",
+        "width": 1
+      },
+      "margin": {
+        "left": 2,
+        "right": 2
+      },
+      "padding": {
+        "bottom": 3,
+        "left": 8,
+        "right": 8,
+        "top": 3
+      }
+    },
+    "invalid_editor": {
+      "background": "#fdf6e3",
+      "corner_radius": 8,
+      "min_width": 200,
+      "max_width": 500,
+      "placeholder_text": {
+        "family": "Zed Mono",
+        "color": "#657b83",
+        "size": 14
+      },
+      "selection": {
+        "cursor": "#268bd2",
+        "selection": "#268bd23d"
+      },
+      "text": {
+        "family": "Zed Mono",
+        "color": "#002b36",
+        "size": 14
+      },
+      "border": {
+        "color": "#dc322f",
+        "width": 1
+      },
+      "margin": {
+        "right": 6
+      },
+      "padding": {
+        "top": 3,
+        "bottom": 3,
+        "left": 12,
+        "right": 8
+      }
+    },
+    "match_index": {
+      "family": "Zed Mono",
+      "color": "#586e75",
+      "size": 14,
+      "padding": 6
+    },
+    "option_button": {
+      "family": "Zed Mono",
+      "color": "#586e75",
+      "size": 14,
+      "background": "#eee8d5",
+      "corner_radius": 4,
+      "border": {
+        "color": "#eee8d5",
+        "width": 1
+      },
+      "margin": {
+        "left": 2,
+        "right": 2
+      },
+      "padding": {
+        "bottom": 3,
+        "left": 8,
+        "right": 8,
+        "top": 3
+      }
+    },
+    "option_button_group": {
+      "padding": {
+        "left": 4,
+        "right": 4
+      }
+    },
+    "results_status": {
+      "family": "Zed Mono",
+      "color": "#073642",
+      "size": 18
+    }
+  },
+  "breadcrumbs": {
+    "family": "Zed Sans",
+    "color": "#586e75",
+    "size": 14,
+    "padding": {
+      "left": 6
+    }
+  }
+}

assets/themes/sulphurpool-dark.json 🔗

@@ -0,0 +1,1435 @@
+{
+  "selector": {
+    "background": "#293256",
+    "corner_radius": 8,
+    "padding": 8,
+    "item": {
+      "padding": {
+        "bottom": 4,
+        "left": 12,
+        "right": 12,
+        "top": 4
+      },
+      "corner_radius": 8,
+      "text": {
+        "family": "Zed Sans",
+        "color": "#979db4",
+        "size": 14
+      },
+      "highlight_text": {
+        "family": "Zed Sans",
+        "color": "#3d8fd1",
+        "weight": "bold",
+        "size": 14
+      }
+    },
+    "active_item": {
+      "padding": {
+        "bottom": 4,
+        "left": 12,
+        "right": 12,
+        "top": 4
+      },
+      "corner_radius": 8,
+      "text": {
+        "family": "Zed Sans",
+        "color": "#dfe2f1",
+        "size": 14
+      },
+      "highlight_text": {
+        "family": "Zed Sans",
+        "color": "#3d8fd1",
+        "weight": "bold",
+        "size": 14
+      },
+      "background": "#5e66877a"
+    },
+    "border": {
+      "color": "#202746",
+      "width": 1
+    },
+    "empty": {
+      "text": {
+        "family": "Zed Sans",
+        "color": "#898ea4",
+        "size": 14
+      },
+      "padding": {
+        "bottom": 4,
+        "left": 12,
+        "right": 12,
+        "top": 8
+      }
+    },
+    "input_editor": {
+      "background": "#202746",
+      "corner_radius": 8,
+      "placeholder_text": {
+        "family": "Zed Sans",
+        "color": "#898ea4",
+        "size": 14
+      },
+      "selection": {
+        "cursor": "#3d8fd1",
+        "selection": "#3d8fd13d"
+      },
+      "text": {
+        "family": "Zed Mono",
+        "color": "#dfe2f1",
+        "size": 14
+      },
+      "border": {
+        "color": "#293256",
+        "width": 1
+      },
+      "padding": {
+        "bottom": 7,
+        "left": 16,
+        "right": 16,
+        "top": 7
+      }
+    },
+    "shadow": {
+      "blur": 16,
+      "color": "#00000052",
+      "offset": [
+        0,
+        2
+      ]
+    }
+  },
+  "workspace": {
+    "background": "#293256",
+    "leader_border_opacity": 0.7,
+    "leader_border_width": 2,
+    "tab": {
+      "height": 32,
+      "background": "#293256",
+      "icon_close": "#979db4",
+      "icon_close_active": "#f5f7ff",
+      "icon_conflict": "#c08b30",
+      "icon_dirty": "#3d8fd1",
+      "icon_width": 8,
+      "spacing": 8,
+      "text": {
+        "family": "Zed Sans",
+        "color": "#979db4",
+        "size": 14
+      },
+      "border": {
+        "color": "#202746",
+        "width": 1,
+        "left": true,
+        "bottom": true,
+        "overlay": true
+      },
+      "padding": {
+        "left": 8,
+        "right": 8
+      }
+    },
+    "active_tab": {
+      "height": 32,
+      "background": "#202746",
+      "icon_close": "#979db4",
+      "icon_close_active": "#f5f7ff",
+      "icon_conflict": "#c08b30",
+      "icon_dirty": "#3d8fd1",
+      "icon_width": 8,
+      "spacing": 8,
+      "text": {
+        "family": "Zed Sans",
+        "color": "#f5f7ff",
+        "size": 14
+      },
+      "border": {
+        "color": "#202746",
+        "width": 1,
+        "left": true,
+        "bottom": false,
+        "overlay": true
+      },
+      "padding": {
+        "left": 8,
+        "right": 8
+      }
+    },
+    "modal": {
+      "margin": {
+        "bottom": 52,
+        "top": 52
+      },
+      "cursor": "Arrow"
+    },
+    "left_sidebar": {
+      "width": 30,
+      "background": "#293256",
+      "border": {
+        "color": "#202746",
+        "width": 1,
+        "right": true
+      },
+      "item": {
+        "height": 32,
+        "icon_color": "#979db4",
+        "icon_size": 18
+      },
+      "active_item": {
+        "height": 32,
+        "icon_color": "#f5f7ff",
+        "icon_size": 18
+      },
+      "resize_handle": {
+        "background": "#202746",
+        "padding": {
+          "left": 1
+        }
+      }
+    },
+    "right_sidebar": {
+      "width": 30,
+      "background": "#293256",
+      "border": {
+        "color": "#202746",
+        "width": 1,
+        "left": true
+      },
+      "item": {
+        "height": 32,
+        "icon_color": "#979db4",
+        "icon_size": 18
+      },
+      "active_item": {
+        "height": 32,
+        "icon_color": "#f5f7ff",
+        "icon_size": 18
+      },
+      "resize_handle": {
+        "background": "#202746",
+        "padding": {
+          "left": 1
+        }
+      }
+    },
+    "pane_divider": {
+      "color": "#293256",
+      "width": 1
+    },
+    "status_bar": {
+      "height": 24,
+      "item_spacing": 8,
+      "padding": {
+        "left": 6,
+        "right": 6
+      },
+      "border": {
+        "color": "#202746",
+        "width": 1,
+        "top": true,
+        "overlay": true
+      },
+      "cursor_position": {
+        "family": "Zed Sans",
+        "color": "#979db4",
+        "size": 14
+      },
+      "diagnostic_message": {
+        "family": "Zed Sans",
+        "color": "#979db4",
+        "size": 14
+      },
+      "lsp_message": {
+        "family": "Zed Sans",
+        "color": "#979db4",
+        "size": 14
+      },
+      "auto_update_progress_message": {
+        "family": "Zed Sans",
+        "color": "#979db4",
+        "size": 14
+      },
+      "auto_update_done_message": {
+        "family": "Zed Sans",
+        "color": "#979db4",
+        "size": 14
+      }
+    },
+    "titlebar": {
+      "avatar_width": 18,
+      "height": 32,
+      "background": "#293256",
+      "padding": {
+        "left": 80
+      },
+      "title": {
+        "family": "Zed Sans",
+        "color": "#dfe2f1",
+        "size": 14
+      },
+      "avatar": {
+        "corner_radius": 10,
+        "border": {
+          "color": "#00000088",
+          "width": 1
+        }
+      },
+      "avatar_ribbon": {
+        "height": 3,
+        "width": 12
+      },
+      "border": {
+        "color": "#202746",
+        "width": 1,
+        "bottom": true
+      },
+      "sign_in_prompt": {
+        "family": "Zed Sans",
+        "color": "#979db4",
+        "size": 12,
+        "border": {
+          "color": "#202746",
+          "width": 1
+        },
+        "corner_radius": 6,
+        "margin": {
+          "top": 1,
+          "right": 6
+        },
+        "padding": {
+          "left": 6,
+          "right": 6
+        }
+      },
+      "hovered_sign_in_prompt": {
+        "family": "Zed Sans",
+        "color": "#f5f7ff",
+        "size": 12,
+        "border": {
+          "color": "#202746",
+          "width": 1
+        },
+        "corner_radius": 6,
+        "margin": {
+          "top": 1,
+          "right": 6
+        },
+        "padding": {
+          "left": 6,
+          "right": 6
+        }
+      },
+      "offline_icon": {
+        "color": "#979db4",
+        "width": 16,
+        "padding": {
+          "right": 4
+        }
+      },
+      "share_icon": {
+        "margin": {
+          "top": 3,
+          "bottom": 2
+        },
+        "corner_radius": 6,
+        "color": "#979db4"
+      },
+      "hovered_share_icon": {
+        "margin": {
+          "top": 3,
+          "bottom": 2
+        },
+        "corner_radius": 6,
+        "background": "#5e668752",
+        "color": "#979db4"
+      },
+      "hovered_active_share_icon": {
+        "margin": {
+          "top": 3,
+          "bottom": 2
+        },
+        "corner_radius": 6,
+        "background": "#5e668752",
+        "color": "#f5f7ff"
+      },
+      "active_share_icon": {
+        "margin": {
+          "top": 3,
+          "bottom": 2
+        },
+        "corner_radius": 6,
+        "background": "#5e66877a",
+        "color": "#f5f7ff"
+      },
+      "outdated_warning": {
+        "family": "Zed Sans",
+        "color": "#c08b30",
+        "size": 13,
+        "margin": {
+          "right": 6
+        }
+      }
+    },
+    "toolbar": {
+      "height": 34,
+      "background": "#202746",
+      "border": {
+        "color": "#293256",
+        "width": 1,
+        "bottom": true
+      },
+      "item_spacing": 8,
+      "padding": {
+        "left": 16,
+        "right": 8,
+        "top": 4,
+        "bottom": 4
+      }
+    },
+    "breadcrumbs": {
+      "family": "Zed Mono",
+      "color": "#979db4",
+      "size": 14,
+      "padding": {
+        "left": 6
+      }
+    },
+    "disconnected_overlay": {
+      "family": "Zed Sans",
+      "color": "#f5f7ff",
+      "size": 14,
+      "background": "#000000aa"
+    }
+  },
+  "editor": {
+    "text_color": "#f5f7ff",
+    "background": "#202746",
+    "active_line_background": "#f5f7ff12",
+    "code_actions_indicator": "#979db4",
+    "diff_background_deleted": "#c94922",
+    "diff_background_inserted": "#ac9739",
+    "document_highlight_read_background": "#2027461f",
+    "document_highlight_write_background": "#20274629",
+    "error_color": "#c94922",
+    "gutter_background": "#202746",
+    "gutter_padding_factor": 3.5,
+    "highlighted_line_background": "#f5f7ff1f",
+    "line_number": "#898ea4",
+    "line_number_active": "#f5f7ff",
+    "rename_fade": 0.6,
+    "unnecessary_code_fade": 0.5,
+    "selection": {
+      "cursor": "#3d8fd1",
+      "selection": "#3d8fd13d"
+    },
+    "guest_selections": [
+      {
+        "cursor": "#ac9739",
+        "selection": "#ac97393d"
+      },
+      {
+        "cursor": "#9c637a",
+        "selection": "#9c637a3d"
+      },
+      {
+        "cursor": "#c76b29",
+        "selection": "#c76b293d"
+      },
+      {
+        "cursor": "#6679cc",
+        "selection": "#6679cc3d"
+      },
+      {
+        "cursor": "#22a2c9",
+        "selection": "#22a2c93d"
+      },
+      {
+        "cursor": "#c94922",
+        "selection": "#c949223d"
+      },
+      {
+        "cursor": "#c08b30",
+        "selection": "#c08b303d"
+      }
+    ],
+    "autocomplete": {
+      "background": "#202746",
+      "corner_radius": 8,
+      "padding": 4,
+      "border": {
+        "color": "#293256",
+        "width": 1
+      },
+      "item": {
+        "corner_radius": 6,
+        "padding": {
+          "bottom": 2,
+          "left": 6,
+          "right": 6,
+          "top": 2
+        }
+      },
+      "hovered_item": {
+        "corner_radius": 6,
+        "padding": {
+          "bottom": 2,
+          "left": 6,
+          "right": 6,
+          "top": 2
+        },
+        "background": "#293256"
+      },
+      "margin": {
+        "left": -14
+      },
+      "match_highlight": {
+        "family": "Zed Mono",
+        "color": "#3d8fd1",
+        "size": 14
+      },
+      "selected_item": {
+        "corner_radius": 6,
+        "padding": {
+          "bottom": 2,
+          "left": 6,
+          "right": 6,
+          "top": 2
+        },
+        "background": "#293256"
+      }
+    },
+    "diagnostic_header": {
+      "background": "#293256",
+      "icon_width_factor": 1.5,
+      "text_scale_factor": 0.857,
+      "border": {
+        "color": "#293256",
+        "width": 1,
+        "bottom": true,
+        "top": true
+      },
+      "code": {
+        "family": "Zed Mono",
+        "color": "#979db4",
+        "size": 14,
+        "margin": {
+          "left": 10
+        }
+      },
+      "message": {
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#dfe2f1",
+          "size": 14,
+          "weight": "bold"
+        },
+        "text": {
+          "family": "Zed Sans",
+          "color": "#979db4",
+          "size": 14
+        }
+      }
+    },
+    "diagnostic_path_header": {
+      "background": "#f5f7ff12",
+      "text_scale_factor": 0.857,
+      "filename": {
+        "family": "Zed Mono",
+        "color": "#dfe2f1",
+        "size": 14
+      },
+      "path": {
+        "family": "Zed Mono",
+        "color": "#979db4",
+        "size": 14,
+        "margin": {
+          "left": 12
+        }
+      }
+    },
+    "error_diagnostic": {
+      "text_scale_factor": 0.857,
+      "header": {
+        "border": {
+          "color": "#202746",
+          "width": 1,
+          "top": true
+        }
+      },
+      "message": {
+        "text": {
+          "family": "Zed Sans",
+          "color": "#c94922",
+          "size": 14
+        },
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#c94922",
+          "size": 14,
+          "weight": "bold"
+        }
+      }
+    },
+    "warning_diagnostic": {
+      "text_scale_factor": 0.857,
+      "header": {
+        "border": {
+          "color": "#202746",
+          "width": 1,
+          "top": true
+        }
+      },
+      "message": {
+        "text": {
+          "family": "Zed Sans",
+          "color": "#c08b30",
+          "size": 14
+        },
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#c08b30",
+          "size": 14,
+          "weight": "bold"
+        }
+      }
+    },
+    "information_diagnostic": {
+      "text_scale_factor": 0.857,
+      "header": {
+        "border": {
+          "color": "#202746",
+          "width": 1,
+          "top": true
+        }
+      },
+      "message": {
+        "text": {
+          "family": "Zed Sans",
+          "color": "#3d8fd1",
+          "size": 14
+        },
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#3d8fd1",
+          "size": 14,
+          "weight": "bold"
+        }
+      }
+    },
+    "hint_diagnostic": {
+      "text_scale_factor": 0.857,
+      "header": {
+        "border": {
+          "color": "#202746",
+          "width": 1,
+          "top": true
+        }
+      },
+      "message": {
+        "text": {
+          "family": "Zed Sans",
+          "color": "#3d8fd1",
+          "size": 14
+        },
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#3d8fd1",
+          "size": 14,
+          "weight": "bold"
+        }
+      }
+    },
+    "invalid_error_diagnostic": {
+      "text_scale_factor": 0.857,
+      "header": {
+        "border": {
+          "color": "#202746",
+          "width": 1,
+          "top": true
+        }
+      },
+      "message": {
+        "text": {
+          "family": "Zed Sans",
+          "color": "#979db4",
+          "size": 14
+        },
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#979db4",
+          "size": 14,
+          "weight": "bold"
+        }
+      }
+    },
+    "invalid_hint_diagnostic": {
+      "text_scale_factor": 0.857,
+      "header": {
+        "border": {
+          "color": "#202746",
+          "width": 1,
+          "top": true
+        }
+      },
+      "message": {
+        "text": {
+          "family": "Zed Sans",
+          "color": "#979db4",
+          "size": 14
+        },
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#979db4",
+          "size": 14,
+          "weight": "bold"
+        }
+      }
+    },
+    "invalid_information_diagnostic": {
+      "text_scale_factor": 0.857,
+      "header": {
+        "border": {
+          "color": "#202746",
+          "width": 1,
+          "top": true
+        }
+      },
+      "message": {
+        "text": {
+          "family": "Zed Sans",
+          "color": "#979db4",
+          "size": 14
+        },
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#979db4",
+          "size": 14,
+          "weight": "bold"
+        }
+      }
+    },
+    "invalid_warning_diagnostic": {
+      "text_scale_factor": 0.857,
+      "header": {
+        "border": {
+          "color": "#202746",
+          "width": 1,
+          "top": true
+        }
+      },
+      "message": {
+        "text": {
+          "family": "Zed Sans",
+          "color": "#979db4",
+          "size": 14
+        },
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#979db4",
+          "size": 14,
+          "weight": "bold"
+        }
+      }
+    },
+    "syntax": {
+      "primary": {
+        "color": "#f5f7ff",
+        "weight": "normal"
+      },
+      "comment": {
+        "color": "#979db4",
+        "weight": "normal"
+      },
+      "punctuation": {
+        "color": "#979db4",
+        "weight": "normal"
+      },
+      "constant": {
+        "color": "#898ea4",
+        "weight": "normal"
+      },
+      "keyword": {
+        "color": "#3d8fd1",
+        "weight": "normal"
+      },
+      "function": {
+        "color": "#c08b30",
+        "weight": "normal"
+      },
+      "type": {
+        "color": "#22a2c9",
+        "weight": "normal"
+      },
+      "variant": {
+        "color": "#3d8fd1",
+        "weight": "normal"
+      },
+      "property": {
+        "color": "#3d8fd1",
+        "weight": "normal"
+      },
+      "enum": {
+        "color": "#c76b29",
+        "weight": "normal"
+      },
+      "operator": {
+        "color": "#c76b29",
+        "weight": "normal"
+      },
+      "string": {
+        "color": "#c76b29",
+        "weight": "normal"
+      },
+      "number": {
+        "color": "#ac9739",
+        "weight": "normal"
+      },
+      "boolean": {
+        "color": "#ac9739",
+        "weight": "normal"
+      },
+      "predictive": {
+        "color": "#979db4",
+        "weight": "normal"
+      },
+      "title": {
+        "color": "#c08b30",
+        "weight": "bold"
+      },
+      "emphasis": {
+        "color": "#3d8fd1",
+        "weight": "normal"
+      },
+      "emphasis.strong": {
+        "color": "#3d8fd1",
+        "weight": "bold"
+      },
+      "link_uri": {
+        "color": "#ac9739",
+        "weight": "normal",
+        "underline": true
+      },
+      "link_text": {
+        "color": "#c76b29",
+        "weight": "normal",
+        "italic": true
+      }
+    }
+  },
+  "project_diagnostics": {
+    "tab_icon_spacing": 4,
+    "tab_icon_width": 13,
+    "tab_summary_spacing": 10,
+    "empty_message": {
+      "family": "Zed Sans",
+      "color": "#dfe2f1",
+      "size": 18
+    },
+    "status_bar_item": {
+      "family": "Zed Sans",
+      "color": "#979db4",
+      "size": 14,
+      "margin": {
+        "right": 10
+      }
+    }
+  },
+  "command_palette": {
+    "keystroke_spacing": 8,
+    "key": {
+      "text": {
+        "family": "Zed Mono",
+        "color": "#979db4",
+        "size": 12
+      },
+      "corner_radius": 4,
+      "background": "#202746",
+      "border": {
+        "color": "#293256",
+        "width": 1
+      },
+      "padding": {
+        "top": 2,
+        "bottom": 2,
+        "left": 8,
+        "right": 8
+      },
+      "margin": {
+        "left": 2
+      }
+    }
+  },
+  "project_panel": {
+    "padding": {
+      "top": 6,
+      "left": 12
+    },
+    "entry": {
+      "height": 22,
+      "icon_color": "#979db4",
+      "icon_size": 8,
+      "icon_spacing": 8,
+      "text": {
+        "family": "Zed Mono",
+        "color": "#979db4",
+        "size": 14
+      }
+    },
+    "hovered_entry": {
+      "height": 22,
+      "background": "#5e668752",
+      "icon_color": "#979db4",
+      "icon_size": 8,
+      "icon_spacing": 8,
+      "text": {
+        "family": "Zed Mono",
+        "color": "#979db4",
+        "size": 14
+      }
+    },
+    "selected_entry": {
+      "height": 22,
+      "icon_color": "#979db4",
+      "icon_size": 8,
+      "icon_spacing": 8,
+      "text": {
+        "family": "Zed Mono",
+        "color": "#dfe2f1",
+        "size": 14
+      }
+    },
+    "hovered_selected_entry": {
+      "height": 22,
+      "background": "#5e668752",
+      "icon_color": "#979db4",
+      "icon_size": 8,
+      "icon_spacing": 8,
+      "text": {
+        "family": "Zed Mono",
+        "color": "#dfe2f1",
+        "size": 14
+      }
+    }
+  },
+  "chat_panel": {
+    "padding": {
+      "top": 12,
+      "left": 12,
+      "bottom": 12,
+      "right": 12
+    },
+    "channel_name": {
+      "family": "Zed Sans",
+      "color": "#dfe2f1",
+      "weight": "bold",
+      "size": 14
+    },
+    "channel_name_hash": {
+      "family": "Zed Sans",
+      "color": "#979db4",
+      "size": 14,
+      "padding": {
+        "right": 8
+      }
+    },
+    "channel_select": {
+      "header": {
+        "name": {
+          "family": "Zed Sans",
+          "color": "#dfe2f1",
+          "size": 14
+        },
+        "padding": {
+          "bottom": 4,
+          "left": 0
+        },
+        "hash": {
+          "family": "Zed Sans",
+          "color": "#979db4",
+          "size": 14,
+          "margin": {
+            "right": 8
+          }
+        },
+        "corner_radius": 0
+      },
+      "item": {
+        "name": {
+          "family": "Zed Sans",
+          "color": "#979db4",
+          "size": 14
+        },
+        "padding": 4,
+        "hash": {
+          "family": "Zed Sans",
+          "color": "#979db4",
+          "size": 14,
+          "margin": {
+            "right": 8
+          }
+        },
+        "corner_radius": 0
+      },
+      "hovered_item": {
+        "name": {
+          "family": "Zed Sans",
+          "color": "#979db4",
+          "size": 14
+        },
+        "padding": 4,
+        "hash": {
+          "family": "Zed Sans",
+          "color": "#979db4",
+          "size": 14,
+          "margin": {
+            "right": 8
+          }
+        },
+        "background": "#5e668752",
+        "corner_radius": 6
+      },
+      "active_item": {
+        "name": {
+          "family": "Zed Sans",
+          "color": "#dfe2f1",
+          "size": 14
+        },
+        "padding": 4,
+        "hash": {
+          "family": "Zed Sans",
+          "color": "#979db4",
+          "size": 14,
+          "margin": {
+            "right": 8
+          }
+        },
+        "corner_radius": 0
+      },
+      "hovered_active_item": {
+        "name": {
+          "family": "Zed Sans",
+          "color": "#dfe2f1",
+          "size": 14
+        },
+        "padding": 4,
+        "hash": {
+          "family": "Zed Sans",
+          "color": "#979db4",
+          "size": 14,
+          "margin": {
+            "right": 8
+          }
+        },
+        "background": "#5e668752",
+        "corner_radius": 6
+      },
+      "menu": {
+        "background": "#202746",
+        "corner_radius": 6,
+        "padding": 4,
+        "border": {
+          "color": "#202746",
+          "width": 1
+        },
+        "shadow": {
+          "blur": 16,
+          "color": "#00000052",
+          "offset": [
+            0,
+            2
+          ]
+        }
+      }
+    },
+    "sign_in_prompt": {
+      "family": "Zed Sans",
+      "color": "#979db4",
+      "underline": true,
+      "size": 14
+    },
+    "hovered_sign_in_prompt": {
+      "family": "Zed Sans",
+      "color": "#dfe2f1",
+      "underline": true,
+      "size": 14
+    },
+    "message": {
+      "body": {
+        "family": "Zed Sans",
+        "color": "#979db4",
+        "size": 14
+      },
+      "timestamp": {
+        "family": "Zed Sans",
+        "color": "#979db4",
+        "size": 14
+      },
+      "padding": {
+        "bottom": 6
+      },
+      "sender": {
+        "family": "Zed Sans",
+        "color": "#dfe2f1",
+        "weight": "bold",
+        "size": 14,
+        "margin": {
+          "right": 8
+        }
+      }
+    },
+    "pending_message": {
+      "body": {
+        "family": "Zed Sans",
+        "color": "#979db4",
+        "size": 14
+      },
+      "timestamp": {
+        "family": "Zed Sans",
+        "color": "#979db4",
+        "size": 14
+      },
+      "padding": {
+        "bottom": 6
+      },
+      "sender": {
+        "family": "Zed Sans",
+        "color": "#979db4",
+        "weight": "bold",
+        "size": 14,
+        "margin": {
+          "right": 8
+        }
+      }
+    },
+    "input_editor": {
+      "background": "#202746",
+      "corner_radius": 6,
+      "text": {
+        "family": "Zed Mono",
+        "color": "#dfe2f1",
+        "size": 14
+      },
+      "placeholder_text": {
+        "family": "Zed Mono",
+        "color": "#898ea4",
+        "size": 14
+      },
+      "selection": {
+        "cursor": "#3d8fd1",
+        "selection": "#3d8fd13d"
+      },
+      "border": {
+        "color": "#293256",
+        "width": 1
+      },
+      "padding": {
+        "bottom": 7,
+        "left": 8,
+        "right": 8,
+        "top": 7
+      }
+    }
+  },
+  "contacts_panel": {
+    "padding": {
+      "top": 12,
+      "left": 12,
+      "bottom": 12,
+      "right": 12
+    },
+    "host_row_height": 28,
+    "tree_branch_color": "#6b7394",
+    "tree_branch_width": 1,
+    "host_avatar": {
+      "corner_radius": 10,
+      "width": 18
+    },
+    "host_username": {
+      "family": "Zed Mono",
+      "color": "#dfe2f1",
+      "size": 14,
+      "padding": {
+        "left": 8
+      }
+    },
+    "project": {
+      "guest_avatar_spacing": 4,
+      "height": 24,
+      "guest_avatar": {
+        "corner_radius": 8,
+        "width": 14
+      },
+      "name": {
+        "family": "Zed Mono",
+        "color": "#898ea4",
+        "size": 14,
+        "margin": {
+          "right": 6
+        }
+      },
+      "padding": {
+        "left": 8
+      }
+    },
+    "shared_project": {
+      "guest_avatar_spacing": 4,
+      "height": 24,
+      "guest_avatar": {
+        "corner_radius": 8,
+        "width": 14
+      },
+      "name": {
+        "family": "Zed Mono",
+        "color": "#979db4",
+        "size": 14,
+        "margin": {
+          "right": 6
+        }
+      },
+      "padding": {
+        "left": 8
+      },
+      "background": "#293256",
+      "corner_radius": 6
+    },
+    "hovered_shared_project": {
+      "guest_avatar_spacing": 4,
+      "height": 24,
+      "guest_avatar": {
+        "corner_radius": 8,
+        "width": 14
+      },
+      "name": {
+        "family": "Zed Mono",
+        "color": "#979db4",
+        "size": 14,
+        "margin": {
+          "right": 6
+        }
+      },
+      "padding": {
+        "left": 8
+      },
+      "background": "#5e668752",
+      "corner_radius": 6
+    },
+    "unshared_project": {
+      "guest_avatar_spacing": 4,
+      "height": 24,
+      "guest_avatar": {
+        "corner_radius": 8,
+        "width": 14
+      },
+      "name": {
+        "family": "Zed Mono",
+        "color": "#898ea4",
+        "size": 14,
+        "margin": {
+          "right": 6
+        }
+      },
+      "padding": {
+        "left": 8
+      }
+    },
+    "hovered_unshared_project": {
+      "guest_avatar_spacing": 4,
+      "height": 24,
+      "guest_avatar": {
+        "corner_radius": 8,
+        "width": 14
+      },
+      "name": {
+        "family": "Zed Mono",
+        "color": "#898ea4",
+        "size": 14,
+        "margin": {
+          "right": 6
+        }
+      },
+      "padding": {
+        "left": 8
+      },
+      "corner_radius": 6
+    }
+  },
+  "search": {
+    "match_background": "#6679cc80",
+    "tab_icon_spacing": 8,
+    "tab_icon_width": 14,
+    "active_hovered_option_button": {
+      "family": "Zed Mono",
+      "color": "#f5f7ff",
+      "size": 14,
+      "background": "#6b7394",
+      "corner_radius": 4,
+      "border": {
+        "color": "#6b7394",
+        "width": 1
+      },
+      "margin": {
+        "left": 2,
+        "right": 2
+      },
+      "padding": {
+        "bottom": 3,
+        "left": 8,
+        "right": 8,
+        "top": 3
+      }
+    },
+    "active_option_button": {
+      "family": "Zed Mono",
+      "color": "#f5f7ff",
+      "size": 14,
+      "background": "#6b7394",
+      "corner_radius": 4,
+      "border": {
+        "color": "#6b7394",
+        "width": 1
+      },
+      "margin": {
+        "left": 2,
+        "right": 2
+      },
+      "padding": {
+        "bottom": 3,
+        "left": 8,
+        "right": 8,
+        "top": 3
+      }
+    },
+    "editor": {
+      "background": "#202746",
+      "corner_radius": 8,
+      "min_width": 200,
+      "max_width": 500,
+      "placeholder_text": {
+        "family": "Zed Mono",
+        "color": "#898ea4",
+        "size": 14
+      },
+      "selection": {
+        "cursor": "#3d8fd1",
+        "selection": "#3d8fd13d"
+      },
+      "text": {
+        "family": "Zed Mono",
+        "color": "#f5f7ff",
+        "size": 14
+      },
+      "border": {
+        "color": "#293256",
+        "width": 1
+      },
+      "margin": {
+        "right": 6
+      },
+      "padding": {
+        "top": 3,
+        "bottom": 3,
+        "left": 12,
+        "right": 8
+      }
+    },
+    "hovered_option_button": {
+      "family": "Zed Mono",
+      "color": "#f5f7ff",
+      "size": 14,
+      "background": "#293256",
+      "corner_radius": 4,
+      "border": {
+        "color": "#6b7394",
+        "width": 1
+      },
+      "margin": {
+        "left": 2,
+        "right": 2
+      },
+      "padding": {
+        "bottom": 3,
+        "left": 8,
+        "right": 8,
+        "top": 3
+      }
+    },
+    "invalid_editor": {
+      "background": "#202746",
+      "corner_radius": 8,
+      "min_width": 200,
+      "max_width": 500,
+      "placeholder_text": {
+        "family": "Zed Mono",
+        "color": "#898ea4",
+        "size": 14
+      },
+      "selection": {
+        "cursor": "#3d8fd1",
+        "selection": "#3d8fd13d"
+      },
+      "text": {
+        "family": "Zed Mono",
+        "color": "#f5f7ff",
+        "size": 14
+      },
+      "border": {
+        "color": "#c94922",
+        "width": 1
+      },
+      "margin": {
+        "right": 6
+      },
+      "padding": {
+        "top": 3,
+        "bottom": 3,
+        "left": 12,
+        "right": 8
+      }
+    },
+    "match_index": {
+      "family": "Zed Mono",
+      "color": "#979db4",
+      "size": 14,
+      "padding": 6
+    },
+    "option_button": {
+      "family": "Zed Mono",
+      "color": "#979db4",
+      "size": 14,
+      "background": "#293256",
+      "corner_radius": 4,
+      "border": {
+        "color": "#293256",
+        "width": 1
+      },
+      "margin": {
+        "left": 2,
+        "right": 2
+      },
+      "padding": {
+        "bottom": 3,
+        "left": 8,
+        "right": 8,
+        "top": 3
+      }
+    },
+    "option_button_group": {
+      "padding": {
+        "left": 4,
+        "right": 4
+      }
+    },
+    "results_status": {
+      "family": "Zed Mono",
+      "color": "#dfe2f1",
+      "size": 18
+    }
+  },
+  "breadcrumbs": {
+    "family": "Zed Sans",
+    "color": "#979db4",
+    "size": 14,
+    "padding": {
+      "left": 6
+    }
+  }
+}

assets/themes/sulphurpool-light.json 🔗

@@ -0,0 +1,1435 @@
+{
+  "selector": {
+    "background": "#dfe2f1",
+    "corner_radius": 8,
+    "padding": 8,
+    "item": {
+      "padding": {
+        "bottom": 4,
+        "left": 12,
+        "right": 12,
+        "top": 4
+      },
+      "corner_radius": 8,
+      "text": {
+        "family": "Zed Sans",
+        "color": "#5e6687",
+        "size": 14
+      },
+      "highlight_text": {
+        "family": "Zed Sans",
+        "color": "#3d8fd1",
+        "weight": "bold",
+        "size": 14
+      }
+    },
+    "active_item": {
+      "padding": {
+        "bottom": 4,
+        "left": 12,
+        "right": 12,
+        "top": 4
+      },
+      "corner_radius": 8,
+      "text": {
+        "family": "Zed Sans",
+        "color": "#293256",
+        "size": 14
+      },
+      "highlight_text": {
+        "family": "Zed Sans",
+        "color": "#3d8fd1",
+        "weight": "bold",
+        "size": 14
+      },
+      "background": "#979db42e"
+    },
+    "border": {
+      "color": "#f5f7ff",
+      "width": 1
+    },
+    "empty": {
+      "text": {
+        "family": "Zed Sans",
+        "color": "#6b7394",
+        "size": 14
+      },
+      "padding": {
+        "bottom": 4,
+        "left": 12,
+        "right": 12,
+        "top": 8
+      }
+    },
+    "input_editor": {
+      "background": "#f5f7ff",
+      "corner_radius": 8,
+      "placeholder_text": {
+        "family": "Zed Sans",
+        "color": "#6b7394",
+        "size": 14
+      },
+      "selection": {
+        "cursor": "#3d8fd1",
+        "selection": "#3d8fd13d"
+      },
+      "text": {
+        "family": "Zed Mono",
+        "color": "#293256",
+        "size": 14
+      },
+      "border": {
+        "color": "#dfe2f1",
+        "width": 1
+      },
+      "padding": {
+        "bottom": 7,
+        "left": 16,
+        "right": 16,
+        "top": 7
+      }
+    },
+    "shadow": {
+      "blur": 16,
+      "color": "#0000001f",
+      "offset": [
+        0,
+        2
+      ]
+    }
+  },
+  "workspace": {
+    "background": "#dfe2f1",
+    "leader_border_opacity": 0.7,
+    "leader_border_width": 2,
+    "tab": {
+      "height": 32,
+      "background": "#dfe2f1",
+      "icon_close": "#5e6687",
+      "icon_close_active": "#202746",
+      "icon_conflict": "#c08b30",
+      "icon_dirty": "#3d8fd1",
+      "icon_width": 8,
+      "spacing": 8,
+      "text": {
+        "family": "Zed Sans",
+        "color": "#5e6687",
+        "size": 14
+      },
+      "border": {
+        "color": "#f5f7ff",
+        "width": 1,
+        "left": true,
+        "bottom": true,
+        "overlay": true
+      },
+      "padding": {
+        "left": 8,
+        "right": 8
+      }
+    },
+    "active_tab": {
+      "height": 32,
+      "background": "#f5f7ff",
+      "icon_close": "#5e6687",
+      "icon_close_active": "#202746",
+      "icon_conflict": "#c08b30",
+      "icon_dirty": "#3d8fd1",
+      "icon_width": 8,
+      "spacing": 8,
+      "text": {
+        "family": "Zed Sans",
+        "color": "#202746",
+        "size": 14
+      },
+      "border": {
+        "color": "#f5f7ff",
+        "width": 1,
+        "left": true,
+        "bottom": false,
+        "overlay": true
+      },
+      "padding": {
+        "left": 8,
+        "right": 8
+      }
+    },
+    "modal": {
+      "margin": {
+        "bottom": 52,
+        "top": 52
+      },
+      "cursor": "Arrow"
+    },
+    "left_sidebar": {
+      "width": 30,
+      "background": "#dfe2f1",
+      "border": {
+        "color": "#f5f7ff",
+        "width": 1,
+        "right": true
+      },
+      "item": {
+        "height": 32,
+        "icon_color": "#5e6687",
+        "icon_size": 18
+      },
+      "active_item": {
+        "height": 32,
+        "icon_color": "#202746",
+        "icon_size": 18
+      },
+      "resize_handle": {
+        "background": "#f5f7ff",
+        "padding": {
+          "left": 1
+        }
+      }
+    },
+    "right_sidebar": {
+      "width": 30,
+      "background": "#dfe2f1",
+      "border": {
+        "color": "#f5f7ff",
+        "width": 1,
+        "left": true
+      },
+      "item": {
+        "height": 32,
+        "icon_color": "#5e6687",
+        "icon_size": 18
+      },
+      "active_item": {
+        "height": 32,
+        "icon_color": "#202746",
+        "icon_size": 18
+      },
+      "resize_handle": {
+        "background": "#f5f7ff",
+        "padding": {
+          "left": 1
+        }
+      }
+    },
+    "pane_divider": {
+      "color": "#dfe2f1",
+      "width": 1
+    },
+    "status_bar": {
+      "height": 24,
+      "item_spacing": 8,
+      "padding": {
+        "left": 6,
+        "right": 6
+      },
+      "border": {
+        "color": "#f5f7ff",
+        "width": 1,
+        "top": true,
+        "overlay": true
+      },
+      "cursor_position": {
+        "family": "Zed Sans",
+        "color": "#5e6687",
+        "size": 14
+      },
+      "diagnostic_message": {
+        "family": "Zed Sans",
+        "color": "#5e6687",
+        "size": 14
+      },
+      "lsp_message": {
+        "family": "Zed Sans",
+        "color": "#5e6687",
+        "size": 14
+      },
+      "auto_update_progress_message": {
+        "family": "Zed Sans",
+        "color": "#5e6687",
+        "size": 14
+      },
+      "auto_update_done_message": {
+        "family": "Zed Sans",
+        "color": "#5e6687",
+        "size": 14
+      }
+    },
+    "titlebar": {
+      "avatar_width": 18,
+      "height": 32,
+      "background": "#dfe2f1",
+      "padding": {
+        "left": 80
+      },
+      "title": {
+        "family": "Zed Sans",
+        "color": "#293256",
+        "size": 14
+      },
+      "avatar": {
+        "corner_radius": 10,
+        "border": {
+          "color": "#00000088",
+          "width": 1
+        }
+      },
+      "avatar_ribbon": {
+        "height": 3,
+        "width": 12
+      },
+      "border": {
+        "color": "#f5f7ff",
+        "width": 1,
+        "bottom": true
+      },
+      "sign_in_prompt": {
+        "family": "Zed Sans",
+        "color": "#5e6687",
+        "size": 12,
+        "border": {
+          "color": "#f5f7ff",
+          "width": 1
+        },
+        "corner_radius": 6,
+        "margin": {
+          "top": 1,
+          "right": 6
+        },
+        "padding": {
+          "left": 6,
+          "right": 6
+        }
+      },
+      "hovered_sign_in_prompt": {
+        "family": "Zed Sans",
+        "color": "#202746",
+        "size": 12,
+        "border": {
+          "color": "#f5f7ff",
+          "width": 1
+        },
+        "corner_radius": 6,
+        "margin": {
+          "top": 1,
+          "right": 6
+        },
+        "padding": {
+          "left": 6,
+          "right": 6
+        }
+      },
+      "offline_icon": {
+        "color": "#5e6687",
+        "width": 16,
+        "padding": {
+          "right": 4
+        }
+      },
+      "share_icon": {
+        "margin": {
+          "top": 3,
+          "bottom": 2
+        },
+        "corner_radius": 6,
+        "color": "#5e6687"
+      },
+      "hovered_share_icon": {
+        "margin": {
+          "top": 3,
+          "bottom": 2
+        },
+        "corner_radius": 6,
+        "background": "#979db41f",
+        "color": "#5e6687"
+      },
+      "hovered_active_share_icon": {
+        "margin": {
+          "top": 3,
+          "bottom": 2
+        },
+        "corner_radius": 6,
+        "background": "#979db41f",
+        "color": "#202746"
+      },
+      "active_share_icon": {
+        "margin": {
+          "top": 3,
+          "bottom": 2
+        },
+        "corner_radius": 6,
+        "background": "#979db42e",
+        "color": "#202746"
+      },
+      "outdated_warning": {
+        "family": "Zed Sans",
+        "color": "#c08b30",
+        "size": 13,
+        "margin": {
+          "right": 6
+        }
+      }
+    },
+    "toolbar": {
+      "height": 34,
+      "background": "#f5f7ff",
+      "border": {
+        "color": "#dfe2f1",
+        "width": 1,
+        "bottom": true
+      },
+      "item_spacing": 8,
+      "padding": {
+        "left": 16,
+        "right": 8,
+        "top": 4,
+        "bottom": 4
+      }
+    },
+    "breadcrumbs": {
+      "family": "Zed Mono",
+      "color": "#5e6687",
+      "size": 14,
+      "padding": {
+        "left": 6
+      }
+    },
+    "disconnected_overlay": {
+      "family": "Zed Sans",
+      "color": "#202746",
+      "size": 14,
+      "background": "#000000aa"
+    }
+  },
+  "editor": {
+    "text_color": "#202746",
+    "background": "#f5f7ff",
+    "active_line_background": "#20274612",
+    "code_actions_indicator": "#5e6687",
+    "diff_background_deleted": "#c94922",
+    "diff_background_inserted": "#ac9739",
+    "document_highlight_read_background": "#f5f7ff1f",
+    "document_highlight_write_background": "#f5f7ff29",
+    "error_color": "#c94922",
+    "gutter_background": "#f5f7ff",
+    "gutter_padding_factor": 3.5,
+    "highlighted_line_background": "#2027461f",
+    "line_number": "#6b7394",
+    "line_number_active": "#202746",
+    "rename_fade": 0.6,
+    "unnecessary_code_fade": 0.5,
+    "selection": {
+      "cursor": "#3d8fd1",
+      "selection": "#3d8fd13d"
+    },
+    "guest_selections": [
+      {
+        "cursor": "#ac9739",
+        "selection": "#ac97393d"
+      },
+      {
+        "cursor": "#9c637a",
+        "selection": "#9c637a3d"
+      },
+      {
+        "cursor": "#c76b29",
+        "selection": "#c76b293d"
+      },
+      {
+        "cursor": "#6679cc",
+        "selection": "#6679cc3d"
+      },
+      {
+        "cursor": "#22a2c9",
+        "selection": "#22a2c93d"
+      },
+      {
+        "cursor": "#c94922",
+        "selection": "#c949223d"
+      },
+      {
+        "cursor": "#c08b30",
+        "selection": "#c08b303d"
+      }
+    ],
+    "autocomplete": {
+      "background": "#f5f7ff",
+      "corner_radius": 8,
+      "padding": 4,
+      "border": {
+        "color": "#dfe2f1",
+        "width": 1
+      },
+      "item": {
+        "corner_radius": 6,
+        "padding": {
+          "bottom": 2,
+          "left": 6,
+          "right": 6,
+          "top": 2
+        }
+      },
+      "hovered_item": {
+        "corner_radius": 6,
+        "padding": {
+          "bottom": 2,
+          "left": 6,
+          "right": 6,
+          "top": 2
+        },
+        "background": "#dfe2f1"
+      },
+      "margin": {
+        "left": -14
+      },
+      "match_highlight": {
+        "family": "Zed Mono",
+        "color": "#3d8fd1",
+        "size": 14
+      },
+      "selected_item": {
+        "corner_radius": 6,
+        "padding": {
+          "bottom": 2,
+          "left": 6,
+          "right": 6,
+          "top": 2
+        },
+        "background": "#dfe2f1"
+      }
+    },
+    "diagnostic_header": {
+      "background": "#dfe2f1",
+      "icon_width_factor": 1.5,
+      "text_scale_factor": 0.857,
+      "border": {
+        "color": "#dfe2f1",
+        "width": 1,
+        "bottom": true,
+        "top": true
+      },
+      "code": {
+        "family": "Zed Mono",
+        "color": "#5e6687",
+        "size": 14,
+        "margin": {
+          "left": 10
+        }
+      },
+      "message": {
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#293256",
+          "size": 14,
+          "weight": "bold"
+        },
+        "text": {
+          "family": "Zed Sans",
+          "color": "#5e6687",
+          "size": 14
+        }
+      }
+    },
+    "diagnostic_path_header": {
+      "background": "#20274612",
+      "text_scale_factor": 0.857,
+      "filename": {
+        "family": "Zed Mono",
+        "color": "#293256",
+        "size": 14
+      },
+      "path": {
+        "family": "Zed Mono",
+        "color": "#5e6687",
+        "size": 14,
+        "margin": {
+          "left": 12
+        }
+      }
+    },
+    "error_diagnostic": {
+      "text_scale_factor": 0.857,
+      "header": {
+        "border": {
+          "color": "#f5f7ff",
+          "width": 1,
+          "top": true
+        }
+      },
+      "message": {
+        "text": {
+          "family": "Zed Sans",
+          "color": "#c94922",
+          "size": 14
+        },
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#c94922",
+          "size": 14,
+          "weight": "bold"
+        }
+      }
+    },
+    "warning_diagnostic": {
+      "text_scale_factor": 0.857,
+      "header": {
+        "border": {
+          "color": "#f5f7ff",
+          "width": 1,
+          "top": true
+        }
+      },
+      "message": {
+        "text": {
+          "family": "Zed Sans",
+          "color": "#c08b30",
+          "size": 14
+        },
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#c08b30",
+          "size": 14,
+          "weight": "bold"
+        }
+      }
+    },
+    "information_diagnostic": {
+      "text_scale_factor": 0.857,
+      "header": {
+        "border": {
+          "color": "#f5f7ff",
+          "width": 1,
+          "top": true
+        }
+      },
+      "message": {
+        "text": {
+          "family": "Zed Sans",
+          "color": "#3d8fd1",
+          "size": 14
+        },
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#3d8fd1",
+          "size": 14,
+          "weight": "bold"
+        }
+      }
+    },
+    "hint_diagnostic": {
+      "text_scale_factor": 0.857,
+      "header": {
+        "border": {
+          "color": "#f5f7ff",
+          "width": 1,
+          "top": true
+        }
+      },
+      "message": {
+        "text": {
+          "family": "Zed Sans",
+          "color": "#3d8fd1",
+          "size": 14
+        },
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#3d8fd1",
+          "size": 14,
+          "weight": "bold"
+        }
+      }
+    },
+    "invalid_error_diagnostic": {
+      "text_scale_factor": 0.857,
+      "header": {
+        "border": {
+          "color": "#f5f7ff",
+          "width": 1,
+          "top": true
+        }
+      },
+      "message": {
+        "text": {
+          "family": "Zed Sans",
+          "color": "#5e6687",
+          "size": 14
+        },
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#5e6687",
+          "size": 14,
+          "weight": "bold"
+        }
+      }
+    },
+    "invalid_hint_diagnostic": {
+      "text_scale_factor": 0.857,
+      "header": {
+        "border": {
+          "color": "#f5f7ff",
+          "width": 1,
+          "top": true
+        }
+      },
+      "message": {
+        "text": {
+          "family": "Zed Sans",
+          "color": "#5e6687",
+          "size": 14
+        },
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#5e6687",
+          "size": 14,
+          "weight": "bold"
+        }
+      }
+    },
+    "invalid_information_diagnostic": {
+      "text_scale_factor": 0.857,
+      "header": {
+        "border": {
+          "color": "#f5f7ff",
+          "width": 1,
+          "top": true
+        }
+      },
+      "message": {
+        "text": {
+          "family": "Zed Sans",
+          "color": "#5e6687",
+          "size": 14
+        },
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#5e6687",
+          "size": 14,
+          "weight": "bold"
+        }
+      }
+    },
+    "invalid_warning_diagnostic": {
+      "text_scale_factor": 0.857,
+      "header": {
+        "border": {
+          "color": "#f5f7ff",
+          "width": 1,
+          "top": true
+        }
+      },
+      "message": {
+        "text": {
+          "family": "Zed Sans",
+          "color": "#5e6687",
+          "size": 14
+        },
+        "highlight_text": {
+          "family": "Zed Sans",
+          "color": "#5e6687",
+          "size": 14,
+          "weight": "bold"
+        }
+      }
+    },
+    "syntax": {
+      "primary": {
+        "color": "#202746",
+        "weight": "normal"
+      },
+      "comment": {
+        "color": "#5e6687",
+        "weight": "normal"
+      },
+      "punctuation": {
+        "color": "#5e6687",
+        "weight": "normal"
+      },
+      "constant": {
+        "color": "#6b7394",
+        "weight": "normal"
+      },
+      "keyword": {
+        "color": "#3d8fd1",
+        "weight": "normal"
+      },
+      "function": {
+        "color": "#c08b30",
+        "weight": "normal"
+      },
+      "type": {
+        "color": "#22a2c9",
+        "weight": "normal"
+      },
+      "variant": {
+        "color": "#3d8fd1",
+        "weight": "normal"
+      },
+      "property": {
+        "color": "#3d8fd1",
+        "weight": "normal"
+      },
+      "enum": {
+        "color": "#c76b29",
+        "weight": "normal"
+      },
+      "operator": {
+        "color": "#c76b29",
+        "weight": "normal"
+      },
+      "string": {
+        "color": "#c76b29",
+        "weight": "normal"
+      },
+      "number": {
+        "color": "#ac9739",
+        "weight": "normal"
+      },
+      "boolean": {
+        "color": "#ac9739",
+        "weight": "normal"
+      },
+      "predictive": {
+        "color": "#5e6687",
+        "weight": "normal"
+      },
+      "title": {
+        "color": "#c08b30",
+        "weight": "bold"
+      },
+      "emphasis": {
+        "color": "#3d8fd1",
+        "weight": "normal"
+      },
+      "emphasis.strong": {
+        "color": "#3d8fd1",
+        "weight": "bold"
+      },
+      "link_uri": {
+        "color": "#ac9739",
+        "weight": "normal",
+        "underline": true
+      },
+      "link_text": {
+        "color": "#c76b29",
+        "weight": "normal",
+        "italic": true
+      }
+    }
+  },
+  "project_diagnostics": {
+    "tab_icon_spacing": 4,
+    "tab_icon_width": 13,
+    "tab_summary_spacing": 10,
+    "empty_message": {
+      "family": "Zed Sans",
+      "color": "#293256",
+      "size": 18
+    },
+    "status_bar_item": {
+      "family": "Zed Sans",
+      "color": "#5e6687",
+      "size": 14,
+      "margin": {
+        "right": 10
+      }
+    }
+  },
+  "command_palette": {
+    "keystroke_spacing": 8,
+    "key": {
+      "text": {
+        "family": "Zed Mono",
+        "color": "#5e6687",
+        "size": 12
+      },
+      "corner_radius": 4,
+      "background": "#f5f7ff",
+      "border": {
+        "color": "#dfe2f1",
+        "width": 1
+      },
+      "padding": {
+        "top": 2,
+        "bottom": 2,
+        "left": 8,
+        "right": 8
+      },
+      "margin": {
+        "left": 2
+      }
+    }
+  },
+  "project_panel": {
+    "padding": {
+      "top": 6,
+      "left": 12
+    },
+    "entry": {
+      "height": 22,
+      "icon_color": "#5e6687",
+      "icon_size": 8,
+      "icon_spacing": 8,
+      "text": {
+        "family": "Zed Mono",
+        "color": "#5e6687",
+        "size": 14
+      }
+    },
+    "hovered_entry": {
+      "height": 22,
+      "background": "#979db41f",
+      "icon_color": "#5e6687",
+      "icon_size": 8,
+      "icon_spacing": 8,
+      "text": {
+        "family": "Zed Mono",
+        "color": "#5e6687",
+        "size": 14
+      }
+    },
+    "selected_entry": {
+      "height": 22,
+      "icon_color": "#5e6687",
+      "icon_size": 8,
+      "icon_spacing": 8,
+      "text": {
+        "family": "Zed Mono",
+        "color": "#293256",
+        "size": 14
+      }
+    },
+    "hovered_selected_entry": {
+      "height": 22,
+      "background": "#979db41f",
+      "icon_color": "#5e6687",
+      "icon_size": 8,
+      "icon_spacing": 8,
+      "text": {
+        "family": "Zed Mono",
+        "color": "#293256",
+        "size": 14
+      }
+    }
+  },
+  "chat_panel": {
+    "padding": {
+      "top": 12,
+      "left": 12,
+      "bottom": 12,
+      "right": 12
+    },
+    "channel_name": {
+      "family": "Zed Sans",
+      "color": "#293256",
+      "weight": "bold",
+      "size": 14
+    },
+    "channel_name_hash": {
+      "family": "Zed Sans",
+      "color": "#5e6687",
+      "size": 14,
+      "padding": {
+        "right": 8
+      }
+    },
+    "channel_select": {
+      "header": {
+        "name": {
+          "family": "Zed Sans",
+          "color": "#293256",
+          "size": 14
+        },
+        "padding": {
+          "bottom": 4,
+          "left": 0
+        },
+        "hash": {
+          "family": "Zed Sans",
+          "color": "#5e6687",
+          "size": 14,
+          "margin": {
+            "right": 8
+          }
+        },
+        "corner_radius": 0
+      },
+      "item": {
+        "name": {
+          "family": "Zed Sans",
+          "color": "#5e6687",
+          "size": 14
+        },
+        "padding": 4,
+        "hash": {
+          "family": "Zed Sans",
+          "color": "#5e6687",
+          "size": 14,
+          "margin": {
+            "right": 8
+          }
+        },
+        "corner_radius": 0
+      },
+      "hovered_item": {
+        "name": {
+          "family": "Zed Sans",
+          "color": "#5e6687",
+          "size": 14
+        },
+        "padding": 4,
+        "hash": {
+          "family": "Zed Sans",
+          "color": "#5e6687",
+          "size": 14,
+          "margin": {
+            "right": 8
+          }
+        },
+        "background": "#979db41f",
+        "corner_radius": 6
+      },
+      "active_item": {
+        "name": {
+          "family": "Zed Sans",
+          "color": "#293256",
+          "size": 14
+        },
+        "padding": 4,
+        "hash": {
+          "family": "Zed Sans",
+          "color": "#5e6687",
+          "size": 14,
+          "margin": {
+            "right": 8
+          }
+        },
+        "corner_radius": 0
+      },
+      "hovered_active_item": {
+        "name": {
+          "family": "Zed Sans",
+          "color": "#293256",
+          "size": 14
+        },
+        "padding": 4,
+        "hash": {
+          "family": "Zed Sans",
+          "color": "#5e6687",
+          "size": 14,
+          "margin": {
+            "right": 8
+          }
+        },
+        "background": "#979db41f",
+        "corner_radius": 6
+      },
+      "menu": {
+        "background": "#f5f7ff",
+        "corner_radius": 6,
+        "padding": 4,
+        "border": {
+          "color": "#f5f7ff",
+          "width": 1
+        },
+        "shadow": {
+          "blur": 16,
+          "color": "#0000001f",
+          "offset": [
+            0,
+            2
+          ]
+        }
+      }
+    },
+    "sign_in_prompt": {
+      "family": "Zed Sans",
+      "color": "#5e6687",
+      "underline": true,
+      "size": 14
+    },
+    "hovered_sign_in_prompt": {
+      "family": "Zed Sans",
+      "color": "#293256",
+      "underline": true,
+      "size": 14
+    },
+    "message": {
+      "body": {
+        "family": "Zed Sans",
+        "color": "#5e6687",
+        "size": 14
+      },
+      "timestamp": {
+        "family": "Zed Sans",
+        "color": "#5e6687",
+        "size": 14
+      },
+      "padding": {
+        "bottom": 6
+      },
+      "sender": {
+        "family": "Zed Sans",
+        "color": "#293256",
+        "weight": "bold",
+        "size": 14,
+        "margin": {
+          "right": 8
+        }
+      }
+    },
+    "pending_message": {
+      "body": {
+        "family": "Zed Sans",
+        "color": "#5e6687",
+        "size": 14
+      },
+      "timestamp": {
+        "family": "Zed Sans",
+        "color": "#5e6687",
+        "size": 14
+      },
+      "padding": {
+        "bottom": 6
+      },
+      "sender": {
+        "family": "Zed Sans",
+        "color": "#5e6687",
+        "weight": "bold",
+        "size": 14,
+        "margin": {
+          "right": 8
+        }
+      }
+    },
+    "input_editor": {
+      "background": "#f5f7ff",
+      "corner_radius": 6,
+      "text": {
+        "family": "Zed Mono",
+        "color": "#293256",
+        "size": 14
+      },
+      "placeholder_text": {
+        "family": "Zed Mono",
+        "color": "#6b7394",
+        "size": 14
+      },
+      "selection": {
+        "cursor": "#3d8fd1",
+        "selection": "#3d8fd13d"
+      },
+      "border": {
+        "color": "#dfe2f1",
+        "width": 1
+      },
+      "padding": {
+        "bottom": 7,
+        "left": 8,
+        "right": 8,
+        "top": 7
+      }
+    }
+  },
+  "contacts_panel": {
+    "padding": {
+      "top": 12,
+      "left": 12,
+      "bottom": 12,
+      "right": 12
+    },
+    "host_row_height": 28,
+    "tree_branch_color": "#898ea4",
+    "tree_branch_width": 1,
+    "host_avatar": {
+      "corner_radius": 10,
+      "width": 18
+    },
+    "host_username": {
+      "family": "Zed Mono",
+      "color": "#293256",
+      "size": 14,
+      "padding": {
+        "left": 8
+      }
+    },
+    "project": {
+      "guest_avatar_spacing": 4,
+      "height": 24,
+      "guest_avatar": {
+        "corner_radius": 8,
+        "width": 14
+      },
+      "name": {
+        "family": "Zed Mono",
+        "color": "#6b7394",
+        "size": 14,
+        "margin": {
+          "right": 6
+        }
+      },
+      "padding": {
+        "left": 8
+      }
+    },
+    "shared_project": {
+      "guest_avatar_spacing": 4,
+      "height": 24,
+      "guest_avatar": {
+        "corner_radius": 8,
+        "width": 14
+      },
+      "name": {
+        "family": "Zed Mono",
+        "color": "#5e6687",
+        "size": 14,
+        "margin": {
+          "right": 6
+        }
+      },
+      "padding": {
+        "left": 8
+      },
+      "background": "#dfe2f1",
+      "corner_radius": 6
+    },
+    "hovered_shared_project": {
+      "guest_avatar_spacing": 4,
+      "height": 24,
+      "guest_avatar": {
+        "corner_radius": 8,
+        "width": 14
+      },
+      "name": {
+        "family": "Zed Mono",
+        "color": "#5e6687",
+        "size": 14,
+        "margin": {
+          "right": 6
+        }
+      },
+      "padding": {
+        "left": 8
+      },
+      "background": "#979db41f",
+      "corner_radius": 6
+    },
+    "unshared_project": {
+      "guest_avatar_spacing": 4,
+      "height": 24,
+      "guest_avatar": {
+        "corner_radius": 8,
+        "width": 14
+      },
+      "name": {
+        "family": "Zed Mono",
+        "color": "#6b7394",
+        "size": 14,
+        "margin": {
+          "right": 6
+        }
+      },
+      "padding": {
+        "left": 8
+      }
+    },
+    "hovered_unshared_project": {
+      "guest_avatar_spacing": 4,
+      "height": 24,
+      "guest_avatar": {
+        "corner_radius": 8,
+        "width": 14
+      },
+      "name": {
+        "family": "Zed Mono",
+        "color": "#6b7394",
+        "size": 14,
+        "margin": {
+          "right": 6
+        }
+      },
+      "padding": {
+        "left": 8
+      },
+      "corner_radius": 6
+    }
+  },
+  "search": {
+    "match_background": "#6679cc80",
+    "tab_icon_spacing": 8,
+    "tab_icon_width": 14,
+    "active_hovered_option_button": {
+      "family": "Zed Mono",
+      "color": "#202746",
+      "size": 14,
+      "background": "#898ea4",
+      "corner_radius": 4,
+      "border": {
+        "color": "#898ea4",
+        "width": 1
+      },
+      "margin": {
+        "left": 2,
+        "right": 2
+      },
+      "padding": {
+        "bottom": 3,
+        "left": 8,
+        "right": 8,
+        "top": 3
+      }
+    },
+    "active_option_button": {
+      "family": "Zed Mono",
+      "color": "#202746",
+      "size": 14,
+      "background": "#898ea4",
+      "corner_radius": 4,
+      "border": {
+        "color": "#898ea4",
+        "width": 1
+      },
+      "margin": {
+        "left": 2,
+        "right": 2
+      },
+      "padding": {
+        "bottom": 3,
+        "left": 8,
+        "right": 8,
+        "top": 3
+      }
+    },
+    "editor": {
+      "background": "#f5f7ff",
+      "corner_radius": 8,
+      "min_width": 200,
+      "max_width": 500,
+      "placeholder_text": {
+        "family": "Zed Mono",
+        "color": "#6b7394",
+        "size": 14
+      },
+      "selection": {
+        "cursor": "#3d8fd1",
+        "selection": "#3d8fd13d"
+      },
+      "text": {
+        "family": "Zed Mono",
+        "color": "#202746",
+        "size": 14
+      },
+      "border": {
+        "color": "#dfe2f1",
+        "width": 1
+      },
+      "margin": {
+        "right": 6
+      },
+      "padding": {
+        "top": 3,
+        "bottom": 3,
+        "left": 12,
+        "right": 8
+      }
+    },
+    "hovered_option_button": {
+      "family": "Zed Mono",
+      "color": "#202746",
+      "size": 14,
+      "background": "#dfe2f1",
+      "corner_radius": 4,
+      "border": {
+        "color": "#898ea4",
+        "width": 1
+      },
+      "margin": {
+        "left": 2,
+        "right": 2
+      },
+      "padding": {
+        "bottom": 3,
+        "left": 8,
+        "right": 8,
+        "top": 3
+      }
+    },
+    "invalid_editor": {
+      "background": "#f5f7ff",
+      "corner_radius": 8,
+      "min_width": 200,
+      "max_width": 500,
+      "placeholder_text": {
+        "family": "Zed Mono",
+        "color": "#6b7394",
+        "size": 14
+      },
+      "selection": {
+        "cursor": "#3d8fd1",
+        "selection": "#3d8fd13d"
+      },
+      "text": {
+        "family": "Zed Mono",
+        "color": "#202746",
+        "size": 14
+      },
+      "border": {
+        "color": "#c94922",
+        "width": 1
+      },
+      "margin": {
+        "right": 6
+      },
+      "padding": {
+        "top": 3,
+        "bottom": 3,
+        "left": 12,
+        "right": 8
+      }
+    },
+    "match_index": {
+      "family": "Zed Mono",
+      "color": "#5e6687",
+      "size": 14,
+      "padding": 6
+    },
+    "option_button": {
+      "family": "Zed Mono",
+      "color": "#5e6687",
+      "size": 14,
+      "background": "#dfe2f1",
+      "corner_radius": 4,
+      "border": {
+        "color": "#dfe2f1",
+        "width": 1
+      },
+      "margin": {
+        "left": 2,
+        "right": 2
+      },
+      "padding": {
+        "bottom": 3,
+        "left": 8,
+        "right": 8,
+        "top": 3
+      }
+    },
+    "option_button_group": {
+      "padding": {
+        "left": 4,
+        "right": 4
+      }
+    },
+    "results_status": {
+      "family": "Zed Mono",
+      "color": "#293256",
+      "size": 18
+    }
+  },
+  "breadcrumbs": {
+    "family": "Zed Sans",
+    "color": "#5e6687",
+    "size": 14,
+    "padding": {
+      "left": 6
+    }
+  }
+}

crates/editor/src/display_map.rs 🔗

@@ -814,14 +814,20 @@ pub mod tests {
             DisplayPoint::new(0, 7)
         );
         assert_eq!(
-            movement::up(&snapshot, DisplayPoint::new(1, 10), SelectionGoal::None),
+            movement::up(
+                &snapshot,
+                DisplayPoint::new(1, 10),
+                SelectionGoal::None,
+                false
+            ),
             (DisplayPoint::new(0, 7), SelectionGoal::Column(10))
         );
         assert_eq!(
             movement::down(
                 &snapshot,
                 DisplayPoint::new(0, 7),
-                SelectionGoal::Column(10)
+                SelectionGoal::Column(10),
+                false
             ),
             (DisplayPoint::new(1, 10), SelectionGoal::Column(10))
         );
@@ -829,7 +835,8 @@ pub mod tests {
             movement::down(
                 &snapshot,
                 DisplayPoint::new(1, 10),
-                SelectionGoal::Column(10)
+                SelectionGoal::Column(10),
+                false
             ),
             (DisplayPoint::new(2, 4), SelectionGoal::Column(10))
         );

crates/editor/src/editor.rs 🔗

@@ -1134,8 +1134,10 @@ impl Editor {
     }
 
     pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut ViewContext<Self>) {
-        self.display_map
-            .update(cx, |map, _| map.clip_at_line_ends = clip);
+        if self.display_map.read(cx).clip_at_line_ends != clip {
+            self.display_map
+                .update(cx, |map, _| map.clip_at_line_ends = clip);
+        }
     }
 
     pub fn set_keymap_context_layer<Tag: 'static>(&mut self, context: gpui::keymap::Context) {
@@ -3579,13 +3581,13 @@ impl Editor {
             if !selection.is_empty() {
                 selection.goal = SelectionGoal::None;
             }
-            let (cursor, goal) = movement::up(&map, selection.start, selection.goal);
+            let (cursor, goal) = movement::up(&map, selection.start, selection.goal, false);
             selection.collapse_to(cursor, goal);
         });
     }
 
     pub fn select_up(&mut self, _: &SelectUp, cx: &mut ViewContext<Self>) {
-        self.move_selection_heads(cx, movement::up)
+        self.move_selection_heads(cx, |map, head, goal| movement::up(map, head, goal, false))
     }
 
     pub fn move_down(&mut self, _: &MoveDown, cx: &mut ViewContext<Self>) {
@@ -3606,13 +3608,13 @@ impl Editor {
             if !selection.is_empty() {
                 selection.goal = SelectionGoal::None;
             }
-            let (cursor, goal) = movement::down(&map, selection.end, selection.goal);
+            let (cursor, goal) = movement::down(&map, selection.end, selection.goal, false);
             selection.collapse_to(cursor, goal);
         });
     }
 
     pub fn select_down(&mut self, _: &SelectDown, cx: &mut ViewContext<Self>) {
-        self.move_selection_heads(cx, movement::down)
+        self.move_selection_heads(cx, |map, head, goal| movement::down(map, head, goal, false))
     }
 
     pub fn move_to_previous_word_start(

crates/editor/src/element.rs 🔗

@@ -16,6 +16,7 @@ use gpui::{
         PathBuilder,
     },
     json::{self, ToJson},
+    platform::CursorStyle,
     text_layout::{self, Line, RunStyle, TextLayoutCache},
     AppContext, Axis, Border, Element, ElementBox, Event, EventContext, LayoutContext,
     MutableAppContext, PaintContext, Quad, Scene, SizeConstraint, ViewContext, WeakViewHandle,
@@ -329,6 +330,7 @@ impl EditorElement {
         let content_origin = bounds.origin() + vec2f(layout.gutter_margin, 0.);
 
         cx.scene.push_layer(Some(bounds));
+        cx.scene.push_cursor_style(bounds, CursorStyle::IBeam);
 
         for (range, color) in &layout.highlighted_ranges {
             self.paint_highlighted_range(

crates/editor/src/movement.rs 🔗

@@ -28,6 +28,7 @@ pub fn up(
     map: &DisplaySnapshot,
     start: DisplayPoint,
     goal: SelectionGoal,
+    preserve_column_at_start: bool,
 ) -> (DisplayPoint, SelectionGoal) {
     let mut goal_column = if let SelectionGoal::Column(column) = goal {
         column
@@ -42,6 +43,8 @@ pub fn up(
     );
     if point.row() < start.row() {
         *point.column_mut() = map.column_from_chars(point.row(), goal_column);
+    } else if preserve_column_at_start {
+        return (start, goal);
     } else {
         point = DisplayPoint::new(0, 0);
         goal_column = 0;
@@ -63,6 +66,7 @@ pub fn down(
     map: &DisplaySnapshot,
     start: DisplayPoint,
     goal: SelectionGoal,
+    preserve_column_at_end: bool,
 ) -> (DisplayPoint, SelectionGoal) {
     let mut goal_column = if let SelectionGoal::Column(column) = goal {
         column
@@ -74,6 +78,8 @@ pub fn down(
     let mut point = map.clip_point(DisplayPoint::new(next_row, 0), Bias::Right);
     if point.row() > start.row() {
         *point.column_mut() = map.column_from_chars(point.row(), goal_column);
+    } else if preserve_column_at_end {
+        return (start, goal);
     } else {
         point = map.max_point();
         goal_column = map.column_to_chars(point.row(), point.column())
@@ -503,41 +509,81 @@ mod tests {
 
         // Can't move up into the first excerpt's header
         assert_eq!(
-            up(&snapshot, DisplayPoint::new(2, 2), SelectionGoal::Column(2)),
+            up(
+                &snapshot,
+                DisplayPoint::new(2, 2),
+                SelectionGoal::Column(2),
+                false
+            ),
             (DisplayPoint::new(2, 0), SelectionGoal::Column(0)),
         );
         assert_eq!(
-            up(&snapshot, DisplayPoint::new(2, 0), SelectionGoal::None),
+            up(
+                &snapshot,
+                DisplayPoint::new(2, 0),
+                SelectionGoal::None,
+                false
+            ),
             (DisplayPoint::new(2, 0), SelectionGoal::Column(0)),
         );
 
         // Move up and down within first excerpt
         assert_eq!(
-            up(&snapshot, DisplayPoint::new(3, 4), SelectionGoal::Column(4)),
+            up(
+                &snapshot,
+                DisplayPoint::new(3, 4),
+                SelectionGoal::Column(4),
+                false
+            ),
             (DisplayPoint::new(2, 3), SelectionGoal::Column(4)),
         );
         assert_eq!(
-            down(&snapshot, DisplayPoint::new(2, 3), SelectionGoal::Column(4)),
+            down(
+                &snapshot,
+                DisplayPoint::new(2, 3),
+                SelectionGoal::Column(4),
+                false
+            ),
             (DisplayPoint::new(3, 4), SelectionGoal::Column(4)),
         );
 
         // Move up and down across second excerpt's header
         assert_eq!(
-            up(&snapshot, DisplayPoint::new(6, 5), SelectionGoal::Column(5)),
+            up(
+                &snapshot,
+                DisplayPoint::new(6, 5),
+                SelectionGoal::Column(5),
+                false
+            ),
             (DisplayPoint::new(3, 4), SelectionGoal::Column(5)),
         );
         assert_eq!(
-            down(&snapshot, DisplayPoint::new(3, 4), SelectionGoal::Column(5)),
+            down(
+                &snapshot,
+                DisplayPoint::new(3, 4),
+                SelectionGoal::Column(5),
+                false
+            ),
             (DisplayPoint::new(6, 5), SelectionGoal::Column(5)),
         );
 
         // Can't move down off the end
         assert_eq!(
-            down(&snapshot, DisplayPoint::new(7, 0), SelectionGoal::Column(0)),
+            down(
+                &snapshot,
+                DisplayPoint::new(7, 0),
+                SelectionGoal::Column(0),
+                false
+            ),
             (DisplayPoint::new(7, 2), SelectionGoal::Column(2)),
         );
         assert_eq!(
-            down(&snapshot, DisplayPoint::new(7, 2), SelectionGoal::Column(2)),
+            down(
+                &snapshot,
+                DisplayPoint::new(7, 2),
+                SelectionGoal::Column(2),
+                false
+            ),
             (DisplayPoint::new(7, 2), SelectionGoal::Column(2)),
         );
     }

crates/go_to_line/src/go_to_line.rs 🔗

@@ -161,29 +161,25 @@ impl View for GoToLine {
             self.max_point.row + 1
         );
 
-        Align::new(
-            ConstrainedBox::new(
-                Container::new(
-                    Flex::new(Axis::Vertical)
-                        .with_child(
-                            Container::new(ChildView::new(&self.line_editor).boxed())
-                                .with_style(theme.input_editor.container)
-                                .boxed(),
-                        )
-                        .with_child(
-                            Container::new(Label::new(label, theme.empty.label.clone()).boxed())
-                                .with_style(theme.empty.container)
-                                .boxed(),
-                        )
-                        .boxed(),
-                )
-                .with_style(theme.container)
-                .boxed(),
+        ConstrainedBox::new(
+            Container::new(
+                Flex::new(Axis::Vertical)
+                    .with_child(
+                        Container::new(ChildView::new(&self.line_editor).boxed())
+                            .with_style(theme.input_editor.container)
+                            .boxed(),
+                    )
+                    .with_child(
+                        Container::new(Label::new(label, theme.empty.label.clone()).boxed())
+                            .with_style(theme.empty.container)
+                            .boxed(),
+                    )
+                    .boxed(),
             )
-            .with_max_width(500.0)
+            .with_style(theme.container)
             .boxed(),
         )
-        .top()
+        .with_max_width(500.0)
         .named("go to line")
     }
 

crates/gpui/src/app.rs 🔗

@@ -4,7 +4,7 @@ use crate::{
     elements::ElementBox,
     executor::{self, Task},
     keymap::{self, Binding, Keystroke},
-    platform::{self, CursorStyle, Platform, PromptLevel, WindowOptions},
+    platform::{self, Platform, PromptLevel, WindowOptions},
     presenter::Presenter,
     util::post_inc,
     AssetCache, AssetSource, ClipboardItem, FontCache, PathPromptOptions, TextLayoutCache,
@@ -31,10 +31,7 @@ use std::{
     path::{Path, PathBuf},
     pin::Pin,
     rc::{self, Rc},
-    sync::{
-        atomic::{AtomicUsize, Ordering::SeqCst},
-        Arc, Weak,
-    },
+    sync::{Arc, Weak},
     time::Duration,
 };
 
@@ -766,7 +763,6 @@ pub struct MutableAppContext {
     pending_global_notifications: HashSet<TypeId>,
     pending_flushes: usize,
     flushing_effects: bool,
-    next_cursor_style_handle_id: Arc<AtomicUsize>,
     halt_action_dispatch: bool,
 }
 
@@ -818,7 +814,6 @@ impl MutableAppContext {
             pending_global_notifications: HashSet::new(),
             pending_flushes: 0,
             flushing_effects: false,
-            next_cursor_style_handle_id: Default::default(),
             halt_action_dispatch: false,
         }
     }
@@ -1596,6 +1591,7 @@ impl MutableAppContext {
                 Window {
                     root_view: root_view.clone().into(),
                     focused_view_id: Some(root_view.id()),
+                    is_active: true,
                     invalidation: None,
                 },
             );
@@ -1643,10 +1639,17 @@ impl MutableAppContext {
             }));
         }
 
+        {
+            let mut app = self.upgrade();
+            window.on_active_status_change(Box::new(move |is_active| {
+                app.update(|cx| cx.window_changed_active_status(window_id, is_active))
+            }));
+        }
+
         {
             let mut app = self.upgrade();
             window.on_resize(Box::new(move || {
-                app.update(|cx| cx.resize_window(window_id))
+                app.update(|cx| cx.window_was_resized(window_id))
             }));
         }
 
@@ -1861,6 +1864,10 @@ impl MutableAppContext {
                                     .get_or_insert(WindowInvalidation::default());
                             }
                         }
+                        Effect::ActivateWindow {
+                            window_id,
+                            is_active,
+                        } => self.handle_activation_effect(window_id, is_active),
                         Effect::RefreshWindows => {
                             refreshing = true;
                         }
@@ -1919,11 +1926,18 @@ impl MutableAppContext {
         }
     }
 
-    fn resize_window(&mut self, window_id: usize) {
+    fn window_was_resized(&mut self, window_id: usize) {
         self.pending_effects
             .push_back(Effect::ResizeWindow { window_id });
     }
 
+    fn window_changed_active_status(&mut self, window_id: usize, is_active: bool) {
+        self.pending_effects.push_back(Effect::ActivateWindow {
+            window_id,
+            is_active,
+        });
+    }
+
     pub fn refresh_windows(&mut self) {
         self.pending_effects.push_back(Effect::RefreshWindows);
     }
@@ -1949,16 +1963,6 @@ impl MutableAppContext {
         self.presenters_and_platform_windows = presenters;
     }
 
-    pub fn set_cursor_style(&mut self, style: CursorStyle) -> CursorStyleHandle {
-        self.platform.set_cursor_style(style);
-        let id = self.next_cursor_style_handle_id.fetch_add(1, SeqCst);
-        CursorStyleHandle {
-            id,
-            next_cursor_style_handle_id: self.next_cursor_style_handle_id.clone(),
-            platform: self.platform(),
-        }
-    }
-
     fn handle_subscription_effect(
         &mut self,
         entity_id: usize,
@@ -2219,6 +2223,34 @@ impl MutableAppContext {
         }
     }
 
+    fn handle_activation_effect(&mut self, window_id: usize, active: bool) {
+        if self
+            .cx
+            .windows
+            .get(&window_id)
+            .map(|w| w.is_active)
+            .map_or(false, |cur_active| cur_active == active)
+        {
+            return;
+        }
+
+        self.update(|this| {
+            let window = this.cx.windows.get_mut(&window_id)?;
+            window.is_active = active;
+            let view_id = window.focused_view_id?;
+            if let Some(mut view) = this.cx.views.remove(&(window_id, view_id)) {
+                if active {
+                    view.on_focus(this, window_id, view_id);
+                } else {
+                    view.on_blur(this, window_id, view_id);
+                }
+                this.cx.views.insert((window_id, view_id), view);
+            }
+
+            Some(())
+        });
+    }
+
     fn handle_focus_effect(&mut self, window_id: usize, focused_id: Option<usize>) {
         self.pending_focus_index.take();
 
@@ -2582,6 +2614,7 @@ impl ReadView for AppContext {
 struct Window {
     root_view: AnyViewHandle,
     focused_view_id: Option<usize>,
+    is_active: bool,
     invalidation: Option<WindowInvalidation>,
 }
 
@@ -2648,6 +2681,10 @@ pub enum Effect {
     ResizeWindow {
         window_id: usize,
     },
+    ActivateWindow {
+        window_id: usize,
+        is_active: bool,
+    },
     RefreshWindows,
 }
 
@@ -2729,6 +2766,14 @@ impl Debug for Effect {
                 .debug_struct("Effect::RefreshWindow")
                 .field("window_id", window_id)
                 .finish(),
+            Effect::ActivateWindow {
+                window_id,
+                is_active,
+            } => f
+                .debug_struct("Effect::ActivateWindow")
+                .field("window_id", window_id)
+                .field("is_active", is_active)
+                .finish(),
             Effect::RefreshWindows => f.debug_struct("Effect::FullViewRefresh").finish(),
         }
     }
@@ -4452,20 +4497,6 @@ impl<T> Drop for ElementStateHandle<T> {
     }
 }
 
-pub struct CursorStyleHandle {
-    id: usize,
-    next_cursor_style_handle_id: Arc<AtomicUsize>,
-    platform: Arc<dyn Platform>,
-}
-
-impl Drop for CursorStyleHandle {
-    fn drop(&mut self) {
-        if self.id + 1 == self.next_cursor_style_handle_id.load(SeqCst) {
-            self.platform.set_cursor_style(CursorStyle::Arrow);
-        }
-    }
-}
-
 #[must_use]
 pub enum Subscription {
     Subscription {

crates/gpui/src/elements/container.rs 🔗

@@ -1,17 +1,17 @@
-use pathfinder_geometry::rect::RectF;
-use serde::Deserialize;
-use serde_json::json;
-
 use crate::{
     color::Color,
     geometry::{
         deserialize_vec2f,
+        rect::RectF,
         vector::{vec2f, Vector2F},
     },
     json::ToJson,
+    platform::CursorStyle,
     scene::{self, Border, Quad},
     Element, ElementBox, Event, EventContext, LayoutContext, PaintContext, SizeConstraint,
 };
+use serde::Deserialize;
+use serde_json::json;
 
 #[derive(Clone, Copy, Debug, Default, Deserialize)]
 pub struct ContainerStyle {
@@ -27,6 +27,8 @@ pub struct ContainerStyle {
     pub corner_radius: f32,
     #[serde(default)]
     pub shadow: Option<Shadow>,
+    #[serde(default)]
+    pub cursor: Option<CursorStyle>,
 }
 
 pub struct Container {
@@ -128,6 +130,11 @@ impl Container {
         self
     }
 
+    pub fn with_cursor(mut self, style: CursorStyle) -> Self {
+        self.style.cursor = Some(style);
+        self
+    }
+
     fn margin_size(&self) -> Vector2F {
         vec2f(
             self.style.margin.left + self.style.margin.right,
@@ -205,6 +212,10 @@ impl Element for Container {
             });
         }
 
+        if let Some(style) = self.style.cursor {
+            cx.scene.push_cursor_style(quad_bounds, style);
+        }
+
         let child_origin =
             quad_bounds.origin() + vec2f(self.style.padding.left, self.style.padding.top);
 

crates/gpui/src/elements/mouse_event_handler.rs 🔗

@@ -5,8 +5,8 @@ use crate::{
         vector::{vec2f, Vector2F},
     },
     platform::CursorStyle,
-    CursorStyleHandle, DebugContext, Element, ElementBox, ElementStateContext, ElementStateHandle,
-    Event, EventContext, LayoutContext, PaintContext, SizeConstraint,
+    DebugContext, Element, ElementBox, ElementStateContext, ElementStateHandle, Event,
+    EventContext, LayoutContext, PaintContext, SizeConstraint,
 };
 use serde_json::json;
 
@@ -25,7 +25,6 @@ pub struct MouseState {
     pub hovered: bool,
     pub clicked: bool,
     prev_drag_position: Option<Vector2F>,
-    cursor_style_handle: Option<CursorStyleHandle>,
 }
 
 impl MouseEventHandler {
@@ -72,6 +71,14 @@ impl MouseEventHandler {
         self.padding = padding;
         self
     }
+
+    fn hit_bounds(&self, bounds: RectF) -> RectF {
+        RectF::from_points(
+            bounds.origin() - vec2f(self.padding.left, self.padding.top),
+            bounds.lower_right() + vec2f(self.padding.right, self.padding.bottom),
+        )
+        .round_out()
+    }
 }
 
 impl Element for MouseEventHandler {
@@ -93,6 +100,10 @@ impl Element for MouseEventHandler {
         _: &mut Self::LayoutState,
         cx: &mut PaintContext,
     ) -> Self::PaintState {
+        if let Some(cursor_style) = self.cursor_style {
+            cx.scene
+                .push_cursor_style(self.hit_bounds(bounds), cursor_style);
+        }
         self.child.paint(bounds.origin(), visible_bounds, cx);
     }
 
@@ -105,19 +116,13 @@ impl Element for MouseEventHandler {
         _: &mut Self::PaintState,
         cx: &mut EventContext,
     ) -> bool {
-        let cursor_style = self.cursor_style;
+        let hit_bounds = self.hit_bounds(visible_bounds);
         let mouse_down_handler = self.mouse_down_handler.as_mut();
         let click_handler = self.click_handler.as_mut();
         let drag_handler = self.drag_handler.as_mut();
 
         let handled_in_child = self.child.dispatch_event(event, cx);
 
-        let hit_bounds = RectF::from_points(
-            visible_bounds.origin() - vec2f(self.padding.left, self.padding.top),
-            visible_bounds.lower_right() + vec2f(self.padding.right, self.padding.bottom),
-        )
-        .round_out();
-
         self.state.update(cx, |state, cx| match event {
             Event::MouseMoved {
                 position,
@@ -127,16 +132,6 @@ impl Element for MouseEventHandler {
                     let mouse_in = hit_bounds.contains_point(*position);
                     if state.hovered != mouse_in {
                         state.hovered = mouse_in;
-                        if let Some(cursor_style) = cursor_style {
-                            if !state.clicked {
-                                if state.hovered {
-                                    state.cursor_style_handle =
-                                        Some(cx.set_cursor_style(cursor_style));
-                                } else {
-                                    state.cursor_style_handle = None;
-                                }
-                            }
-                        }
                         cx.notify();
                         return true;
                     }
@@ -160,9 +155,6 @@ impl Element for MouseEventHandler {
                 state.prev_drag_position = None;
                 if !handled_in_child && state.clicked {
                     state.clicked = false;
-                    if !state.hovered {
-                        state.cursor_style_handle = None;
-                    }
                     cx.notify();
                     if let Some(handler) = click_handler {
                         if hit_bounds.contains_point(*position) {

crates/gpui/src/platform.rs 🔗

@@ -21,6 +21,7 @@ use anyhow::{anyhow, Result};
 use async_task::Runnable;
 pub use event::{Event, NavigationDirection};
 use postage::oneshot;
+use serde::Deserialize;
 use std::{
     any::Any,
     path::{Path, PathBuf},
@@ -86,6 +87,7 @@ pub trait Dispatcher: Send + Sync {
 pub trait Window: WindowContext {
     fn as_any_mut(&mut self) -> &mut dyn Any;
     fn on_event(&mut self, callback: Box<dyn FnMut(Event)>);
+    fn on_active_status_change(&mut self, callback: Box<dyn FnMut(bool)>);
     fn on_resize(&mut self, callback: Box<dyn FnMut()>);
     fn on_close(&mut self, callback: Box<dyn FnOnce()>);
     fn prompt(&self, level: PromptLevel, msg: &str, answers: &[&str]) -> oneshot::Receiver<usize>;
@@ -125,11 +127,12 @@ pub enum PromptLevel {
     Critical,
 }
 
-#[derive(Copy, Clone, Debug)]
+#[derive(Copy, Clone, Debug, Deserialize)]
 pub enum CursorStyle {
     Arrow,
     ResizeLeftRight,
     PointingHand,
+    IBeam,
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]

crates/gpui/src/platform/mac/platform.rs 🔗

@@ -583,6 +583,7 @@ impl platform::Platform for MacPlatform {
                 CursorStyle::Arrow => msg_send![class!(NSCursor), arrowCursor],
                 CursorStyle::ResizeLeftRight => msg_send![class!(NSCursor), resizeLeftRightCursor],
                 CursorStyle::PointingHand => msg_send![class!(NSCursor), pointingHandCursor],
+                CursorStyle::IBeam => msg_send![class!(NSCursor), IBeamCursor],
             };
             let _: () = msg_send![cursor, set];
         }

crates/gpui/src/platform/mac/window.rs 🔗

@@ -73,6 +73,14 @@ unsafe fn build_classes() {
             sel!(windowDidResize:),
             window_did_resize as extern "C" fn(&Object, Sel, id),
         );
+        decl.add_method(
+            sel!(windowDidBecomeKey:),
+            window_did_change_key_status as extern "C" fn(&Object, Sel, id),
+        );
+        decl.add_method(
+            sel!(windowDidResignKey:),
+            window_did_change_key_status as extern "C" fn(&Object, Sel, id),
+        );
         decl.add_method(sel!(close), close_window as extern "C" fn(&Object, Sel));
         decl.register()
     };
@@ -157,6 +165,7 @@ struct WindowState {
     id: usize,
     native_window: id,
     event_callback: Option<Box<dyn FnMut(Event)>>,
+    activate_callback: Option<Box<dyn FnMut(bool)>>,
     resize_callback: Option<Box<dyn FnMut()>>,
     close_callback: Option<Box<dyn FnOnce()>>,
     synthetic_drag_counter: usize,
@@ -234,6 +243,7 @@ impl Window {
                 event_callback: None,
                 resize_callback: None,
                 close_callback: None,
+                activate_callback: None,
                 synthetic_drag_counter: 0,
                 executor,
                 scene_to_render: Default::default(),
@@ -333,6 +343,10 @@ impl platform::Window for Window {
         self.0.as_ref().borrow_mut().close_callback = Some(callback);
     }
 
+    fn on_active_status_change(&mut self, callback: Box<dyn FnMut(bool)>) {
+        self.0.as_ref().borrow_mut().activate_callback = Some(callback);
+    }
+
     fn prompt(
         &self,
         level: platform::PromptLevel,
@@ -598,6 +612,29 @@ extern "C" fn window_did_resize(this: &Object, _: Sel, _: id) {
     window_state.as_ref().borrow().move_traffic_light();
 }
 
+extern "C" fn window_did_change_key_status(this: &Object, selector: Sel, _: id) {
+    let is_active = if selector == sel!(windowDidBecomeKey:) {
+        true
+    } else if selector == sel!(windowDidResignKey:) {
+        false
+    } else {
+        unreachable!();
+    };
+
+    let window_state = unsafe { get_window_state(this) };
+    let executor = window_state.as_ref().borrow().executor.clone();
+    executor
+        .spawn(async move {
+            let mut window_state_borrow = window_state.as_ref().borrow_mut();
+            if let Some(mut callback) = window_state_borrow.activate_callback.take() {
+                drop(window_state_borrow);
+                callback(is_active);
+                window_state.borrow_mut().activate_callback = Some(callback);
+            };
+        })
+        .detach();
+}
+
 extern "C" fn close_window(this: &Object, _: Sel) {
     unsafe {
         let close_callback = {

crates/gpui/src/platform/test.rs 🔗

@@ -229,6 +229,8 @@ impl super::Window for Window {
         self.event_handlers.push(callback);
     }
 
+    fn on_active_status_change(&mut self, _: Box<dyn FnMut(bool)>) {}
+
     fn on_resize(&mut self, callback: Box<dyn FnMut()>) {
         self.resize_handlers.push(callback);
     }

crates/gpui/src/presenter.rs 🔗

@@ -4,7 +4,7 @@ use crate::{
     font_cache::FontCache,
     geometry::rect::RectF,
     json::{self, ToJson},
-    platform::Event,
+    platform::{CursorStyle, Event},
     text_layout::TextLayoutCache,
     Action, AnyModelHandle, AnyViewHandle, AnyWeakModelHandle, AssetCache, ElementBox,
     ElementStateContext, Entity, FontSystem, ModelHandle, ReadModel, ReadView, Scene,
@@ -22,6 +22,7 @@ pub struct Presenter {
     window_id: usize,
     pub(crate) rendered_views: HashMap<usize, ElementBox>,
     parents: HashMap<usize, usize>,
+    cursor_styles: Vec<(RectF, CursorStyle)>,
     font_cache: Arc<FontCache>,
     text_layout_cache: TextLayoutCache,
     asset_cache: Arc<AssetCache>,
@@ -42,6 +43,7 @@ impl Presenter {
             window_id,
             rendered_views: cx.render_views(window_id, titlebar_height),
             parents: HashMap::new(),
+            cursor_styles: Default::default(),
             font_cache,
             text_layout_cache,
             asset_cache,
@@ -118,6 +120,7 @@ impl Presenter {
                 RectF::new(Vector2F::zero(), window_size),
             );
             self.text_layout_cache.finish_frame();
+            self.cursor_styles = scene.cursor_styles();
 
             if let Some(event) = self.last_mouse_moved_event.clone() {
                 self.dispatch_event(event, cx)
@@ -171,8 +174,22 @@ impl Presenter {
     pub fn dispatch_event(&mut self, event: Event, cx: &mut MutableAppContext) {
         if let Some(root_view_id) = cx.root_view_id(self.window_id) {
             match event {
-                Event::MouseMoved { .. } => {
+                Event::MouseMoved {
+                    position,
+                    left_mouse_down,
+                } => {
                     self.last_mouse_moved_event = Some(event.clone());
+
+                    if !left_mouse_down {
+                        let mut style_to_assign = CursorStyle::Arrow;
+                        for (bounds, style) in self.cursor_styles.iter().rev() {
+                            if bounds.contains_point(position) {
+                                style_to_assign = *style;
+                                break;
+                            }
+                        }
+                        cx.platform().set_cursor_style(style_to_assign);
+                    }
                 }
                 Event::LeftMouseDragged { position } => {
                     self.last_mouse_moved_event = Some(Event::MouseMoved {

crates/gpui/src/scene.rs 🔗

@@ -7,6 +7,7 @@ use crate::{
     fonts::{FontId, GlyphId},
     geometry::{rect::RectF, vector::Vector2F},
     json::ToJson,
+    platform::CursorStyle,
     ImageData,
 };
 
@@ -32,6 +33,7 @@ pub struct Layer {
     image_glyphs: Vec<ImageGlyph>,
     icons: Vec<Icon>,
     paths: Vec<Path>,
+    cursor_styles: Vec<(RectF, CursorStyle)>,
 }
 
 #[derive(Default, Debug)]
@@ -173,6 +175,13 @@ impl Scene {
         self.stacking_contexts.iter().flat_map(|s| &s.layers)
     }
 
+    pub fn cursor_styles(&self) -> Vec<(RectF, CursorStyle)> {
+        self.layers()
+            .flat_map(|layer| &layer.cursor_styles)
+            .copied()
+            .collect()
+    }
+
     pub fn push_stacking_context(&mut self, clip_bounds: Option<RectF>) {
         self.active_stacking_context_stack
             .push(self.stacking_contexts.len());
@@ -197,6 +206,10 @@ impl Scene {
         self.active_layer().push_quad(quad)
     }
 
+    pub fn push_cursor_style(&mut self, bounds: RectF, style: CursorStyle) {
+        self.active_layer().push_cursor_style(bounds, style);
+    }
+
     pub fn push_image(&mut self, image: Image) {
         self.active_layer().push_image(image)
     }
@@ -285,6 +298,7 @@ impl Layer {
             glyphs: Default::default(),
             icons: Default::default(),
             paths: Default::default(),
+            cursor_styles: Default::default(),
         }
     }
 
@@ -302,6 +316,14 @@ impl Layer {
         self.quads.as_slice()
     }
 
+    fn push_cursor_style(&mut self, bounds: RectF, style: CursorStyle) {
+        if let Some(bounds) = bounds.intersection(self.clip_bounds.unwrap_or(bounds)) {
+            if can_draw(bounds) {
+                self.cursor_styles.push((bounds, style));
+            }
+        }
+    }
+
     fn push_underline(&mut self, underline: Underline) {
         if underline.width > 0. {
             self.underlines.push(underline);

crates/language/Cargo.toml 🔗

@@ -15,6 +15,7 @@ test-support = [
     "lsp/test-support",
     "text/test-support",
     "tree-sitter-rust",
+    "tree-sitter-typescript",
     "util/test-support",
 ]
 
@@ -45,7 +46,8 @@ similar = "1.3"
 smallvec = { version = "1.6", features = ["union"] }
 smol = "1.2"
 tree-sitter = "0.20"
-tree-sitter-rust = { version = "0.20.0", optional = true }
+tree-sitter-rust = { version = "*", optional = true }
+tree-sitter-typescript = { version = "*", optional = true }
 
 [dev-dependencies]
 client = { path = "../client", features = ["test-support"] }
@@ -57,6 +59,6 @@ util = { path = "../util", features = ["test-support"] }
 ctor = "0.1"
 env_logger = "0.8"
 rand = "0.8.3"
-tree-sitter-json = "0.19.0"
-tree-sitter-rust = "0.20.0"
+tree-sitter-json = "*"
+tree-sitter-rust = "*"
 unindent = "0.1.7"

crates/language/src/buffer.rs 🔗

@@ -38,7 +38,7 @@ use tree_sitter::{InputEdit, QueryCursor, Tree};
 use util::TryFutureExt as _;
 
 #[cfg(any(test, feature = "test-support"))]
-pub use tree_sitter_rust;
+pub use {tree_sitter_rust, tree_sitter_typescript};
 
 pub use lsp::DiagnosticSeverity;
 
@@ -1638,6 +1638,34 @@ impl BufferSnapshot {
             .and_then(|language| language.grammar.as_ref())
     }
 
+    pub fn range_for_word_token_at<T: ToOffset + ToPoint>(
+        &self,
+        position: T,
+    ) -> Option<Range<usize>> {
+        let offset = position.to_offset(self);
+
+        // Find the first leaf node that touches the position.
+        let tree = self.tree.as_ref()?;
+        let mut cursor = tree.root_node().walk();
+        while cursor.goto_first_child_for_byte(offset).is_some() {}
+        let node = cursor.node();
+        if node.child_count() > 0 {
+            return None;
+        }
+
+        // Check that the leaf node contains word characters.
+        let range = node.byte_range();
+        if self
+            .text_for_range(range.clone())
+            .flat_map(str::chars)
+            .any(|c| c.is_alphanumeric())
+        {
+            return Some(range);
+        } else {
+            None
+        }
+    }
+
     pub fn range_for_syntax_ancestor<T: ToOffset>(&self, range: Range<T>) -> Option<Range<usize>> {
         let tree = self.tree.as_ref()?;
         let range = range.start.to_offset(self)..range.end.to_offset(self);
@@ -1730,7 +1758,7 @@ impl BufferSnapshot {
             .and_then(|language| language.grammar.as_ref())?;
 
         let mut cursor = QueryCursorHandle::new();
-        cursor.set_byte_range(range);
+        cursor.set_byte_range(range.clone());
         let matches = cursor.matches(
             &grammar.outline_query,
             tree.root_node(),
@@ -1750,7 +1778,10 @@ impl BufferSnapshot {
         let items = matches
             .filter_map(|mat| {
                 let item_node = mat.nodes_for_capture_index(item_capture_ix).next()?;
-                let range = item_node.start_byte()..item_node.end_byte();
+                let item_range = item_node.start_byte()..item_node.end_byte();
+                if item_range.end < range.start || item_range.start > range.end {
+                    return None;
+                }
                 let mut text = String::new();
                 let mut name_ranges = Vec::new();
                 let mut highlight_ranges = Vec::new();
@@ -1808,15 +1839,15 @@ impl BufferSnapshot {
                 }
 
                 while stack.last().map_or(false, |prev_range| {
-                    !prev_range.contains(&range.start) || !prev_range.contains(&range.end)
+                    !prev_range.contains(&item_range.start) || !prev_range.contains(&item_range.end)
                 }) {
                     stack.pop();
                 }
-                stack.push(range.clone());
+                stack.push(item_range.clone());
 
                 Some(OutlineItem {
                     depth: stack.len() - 1,
-                    range: self.anchor_after(range.start)..self.anchor_before(range.end),
+                    range: self.anchor_after(item_range.start)..self.anchor_before(item_range.end),
                     text,
                     highlight_ranges,
                     name_ranges,

crates/language/src/highlight_map.rs 🔗

@@ -51,6 +51,10 @@ impl HighlightMap {
 }
 
 impl HighlightId {
+    pub fn is_default(&self) -> bool {
+        *self == DEFAULT_SYNTAX_HIGHLIGHT_ID
+    }
+
     pub fn style(&self, theme: &SyntaxTheme) -> Option<HighlightStyle> {
         theme
             .highlights

crates/language/src/language.rs 🔗

@@ -546,7 +546,9 @@ impl Language {
             {
                 let end_offset = offset + chunk.text.len();
                 if let Some(highlight_id) = chunk.syntax_highlight_id {
-                    result.push((offset..end_offset, highlight_id));
+                    if !highlight_id.is_default() {
+                        result.push((offset..end_offset, highlight_id));
+                    }
                 }
                 offset = end_offset;
             }

crates/picker/src/picker.rs 🔗

@@ -99,8 +99,6 @@ impl<D: PickerDelegate> View for Picker<D> {
             .constrained()
             .with_max_width(self.max_size.x())
             .with_max_height(self.max_size.y())
-            .aligned()
-            .top()
             .named("picker")
     }
 

crates/project/src/project.rs 🔗

@@ -669,6 +669,10 @@ impl Project {
             .map(|worktree| worktree.read(cx).id())
     }
 
+    pub fn can_share(&self, cx: &AppContext) -> bool {
+        self.is_local() && self.visible_worktrees(cx).next().is_some()
+    }
+
     pub fn share(&self, cx: &mut ModelContext<Self>) -> Task<Result<()>> {
         let rpc = self.client.clone();
         cx.spawn(|this, mut cx| async move {
@@ -2488,26 +2492,51 @@ impl Project {
                 };
 
                 source_buffer_handle.read_with(&cx, |this, _| {
+                    let snapshot = this.snapshot();
+                    let clipped_position = this.clip_point_utf16(position, Bias::Left);
+                    let mut range_for_token = None;
                     Ok(completions
                         .into_iter()
                         .filter_map(|lsp_completion| {
                             let (old_range, new_text) = match lsp_completion.text_edit.as_ref() {
+                                // If the language server provides a range to overwrite, then
+                                // check that the range is valid.
                                 Some(lsp::CompletionTextEdit::Edit(edit)) => {
-                                    (range_from_lsp(edit.range), edit.new_text.clone())
+                                    let range = range_from_lsp(edit.range);
+                                    let start = snapshot.clip_point_utf16(range.start, Bias::Left);
+                                    let end = snapshot.clip_point_utf16(range.end, Bias::Left);
+                                    if start != range.start || end != range.end {
+                                        log::info!("completion out of expected range");
+                                        return None;
+                                    }
+                                    (
+                                        snapshot.anchor_before(start)..snapshot.anchor_after(end),
+                                        edit.new_text.clone(),
+                                    )
                                 }
+                                // If the language server does not provide a range, then infer
+                                // the range based on the syntax tree.
                                 None => {
-                                    let clipped_position =
-                                        this.clip_point_utf16(position, Bias::Left);
                                     if position != clipped_position {
                                         log::info!("completion out of expected range");
                                         return None;
                                     }
+                                    let Range { start, end } = range_for_token
+                                        .get_or_insert_with(|| {
+                                            let offset = position.to_offset(&snapshot);
+                                            snapshot
+                                                .range_for_word_token_at(offset)
+                                                .unwrap_or_else(|| offset..offset)
+                                        })
+                                        .clone();
+                                    let text = lsp_completion
+                                        .insert_text
+                                        .as_ref()
+                                        .unwrap_or(&lsp_completion.label)
+                                        .clone();
                                     (
-                                        this.common_prefix_at(
-                                            clipped_position,
-                                            &lsp_completion.label,
-                                        ),
-                                        lsp_completion.label.clone(),
+                                        snapshot.anchor_before(start)..snapshot.anchor_after(end),
+                                        text.clone(),
                                     )
                                 }
                                 Some(lsp::CompletionTextEdit::InsertAndReplace(_)) => {
@@ -2516,28 +2545,20 @@ impl Project {
                                 }
                             };
 
-                            let clipped_start = this.clip_point_utf16(old_range.start, Bias::Left);
-                            let clipped_end = this.clip_point_utf16(old_range.end, Bias::Left);
-                            if clipped_start == old_range.start && clipped_end == old_range.end {
-                                Some(Completion {
-                                    old_range: this.anchor_before(old_range.start)
-                                        ..this.anchor_after(old_range.end),
-                                    new_text,
-                                    label: language
-                                        .as_ref()
-                                        .and_then(|l| l.label_for_completion(&lsp_completion))
-                                        .unwrap_or_else(|| {
-                                            CodeLabel::plain(
-                                                lsp_completion.label.clone(),
-                                                lsp_completion.filter_text.as_deref(),
-                                            )
-                                        }),
-                                    lsp_completion,
-                                })
-                            } else {
-                                log::info!("completion out of expected range");
-                                None
-                            }
+                            Some(Completion {
+                                old_range,
+                                new_text,
+                                label: language
+                                    .as_ref()
+                                    .and_then(|l| l.label_for_completion(&lsp_completion))
+                                    .unwrap_or_else(|| {
+                                        CodeLabel::plain(
+                                            lsp_completion.label.clone(),
+                                            lsp_completion.filter_text.as_deref(),
+                                        )
+                                    }),
+                                lsp_completion,
+                            })
                         })
                         .collect())
                 })
@@ -4889,8 +4910,8 @@ mod tests {
     use futures::{future, StreamExt};
     use gpui::test::subscribe;
     use language::{
-        tree_sitter_rust, Diagnostic, FakeLspAdapter, LanguageConfig, OffsetRangeExt, Point,
-        ToPoint,
+        tree_sitter_rust, tree_sitter_typescript, Diagnostic, FakeLspAdapter, LanguageConfig,
+        OffsetRangeExt, Point, ToPoint,
     };
     use lsp::Url;
     use serde_json::json;
@@ -6507,6 +6528,75 @@ mod tests {
         }
     }
 
+    #[gpui::test]
+    async fn test_completions_without_edit_ranges(cx: &mut gpui::TestAppContext) {
+        let mut language = Language::new(
+            LanguageConfig {
+                name: "TypeScript".into(),
+                path_suffixes: vec!["ts".to_string()],
+                ..Default::default()
+            },
+            Some(tree_sitter_typescript::language_typescript()),
+        );
+        let mut fake_language_servers = language.set_fake_lsp_adapter(Default::default());
+
+        let fs = FakeFs::new(cx.background());
+        fs.insert_tree(
+            "/dir",
+            json!({
+                "a.ts": "",
+            }),
+        )
+        .await;
+
+        let project = Project::test(fs, cx);
+        project.update(cx, |project, _| project.languages.add(Arc::new(language)));
+
+        let (tree, _) = project
+            .update(cx, |project, cx| {
+                project.find_or_create_local_worktree("/dir", true, cx)
+            })
+            .await
+            .unwrap();
+        let worktree_id = tree.read_with(cx, |tree, _| tree.id());
+        cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete())
+            .await;
+
+        let buffer = project
+            .update(cx, |p, cx| p.open_buffer((worktree_id, "a.ts"), cx))
+            .await
+            .unwrap();
+
+        let fake_server = fake_language_servers.next().await.unwrap();
+
+        let text = "let a = b.fqn";
+        buffer.update(cx, |buffer, cx| buffer.set_text(text, cx));
+        let completions = project.update(cx, |project, cx| {
+            project.completions(&buffer, text.len(), cx)
+        });
+
+        fake_server
+            .handle_request::<lsp::request::Completion, _, _>(|_, _| async move {
+                Ok(Some(lsp::CompletionResponse::Array(vec![
+                    lsp::CompletionItem {
+                        label: "fullyQualifiedName?".into(),
+                        insert_text: Some("fullyQualifiedName".into()),
+                        ..Default::default()
+                    },
+                ])))
+            })
+            .next()
+            .await;
+        let completions = completions.await.unwrap();
+        let snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
+        assert_eq!(completions.len(), 1);
+        assert_eq!(completions[0].new_text, "fullyQualifiedName");
+        assert_eq!(
+            completions[0].old_range.to_offset(&snapshot),
+            text.len() - 3..text.len()
+        );
+    }
+
     #[gpui::test(iterations = 10)]
     async fn test_apply_code_actions_with_commands(cx: &mut gpui::TestAppContext) {
         let mut language = Language::new(

crates/theme/src/theme.rs 🔗

@@ -43,6 +43,7 @@ pub struct Workspace {
     pub status_bar: StatusBar,
     pub toolbar: Toolbar,
     pub disconnected_overlay: ContainedText,
+    pub modal: ContainerStyle,
 }
 
 #[derive(Clone, Deserialize, Default)]
@@ -54,8 +55,10 @@ pub struct Titlebar {
     pub avatar_width: f32,
     pub avatar_ribbon: AvatarRibbon,
     pub offline_icon: OfflineIcon,
-    pub share_icon_color: Color,
-    pub share_icon_active_color: Color,
+    pub share_icon: ShareIcon,
+    pub hovered_share_icon: ShareIcon,
+    pub active_share_icon: ShareIcon,
+    pub hovered_active_share_icon: ShareIcon,
     pub avatar: ImageStyle,
     pub sign_in_prompt: ContainedText,
     pub hovered_sign_in_prompt: ContainedText,
@@ -78,6 +81,13 @@ pub struct OfflineIcon {
     pub color: Color,
 }
 
+#[derive(Clone, Deserialize, Default)]
+pub struct ShareIcon {
+    #[serde(flatten)]
+    pub container: ContainerStyle,
+    pub color: Color,
+}
+
 #[derive(Clone, Deserialize, Default)]
 pub struct Tab {
     pub height: f32,

crates/theme_selector/src/theme_selector.rs 🔗

@@ -36,7 +36,12 @@ impl ThemeSelector {
         let handle = cx.weak_handle();
         let picker = cx.add_view(|cx| Picker::new(handle, cx));
         let original_theme = cx.global::<Settings>().theme.clone();
-        let theme_names = registry.list().collect::<Vec<_>>();
+        let mut theme_names = registry.list().collect::<Vec<_>>();
+        theme_names.sort_unstable_by(|a, b| {
+            a.ends_with("dark")
+                .cmp(&b.ends_with("dark"))
+                .then_with(|| a.cmp(&b))
+        });
         let matches = theme_names
             .iter()
             .map(|name| StringMatch {

crates/vim/src/insert.rs 🔗

@@ -28,7 +28,7 @@ mod test {
 
     #[gpui::test]
     async fn test_enter_and_exit_insert_mode(cx: &mut gpui::TestAppContext) {
-        let mut cx = VimTestContext::new(cx, true, "").await;
+        let mut cx = VimTestContext::new(cx, true).await;
         cx.simulate_keystroke("i");
         assert_eq!(cx.mode(), Mode::Insert);
         cx.simulate_keystrokes(["T", "e", "s", "t"]);

crates/vim/src/motion.rs 🔗

@@ -4,7 +4,7 @@ use editor::{
     movement, Bias, DisplayPoint,
 };
 use gpui::{actions, impl_actions, MutableAppContext};
-use language::SelectionGoal;
+use language::{Selection, SelectionGoal};
 use serde::Deserialize;
 use workspace::Workspace;
 
@@ -14,22 +14,15 @@ use crate::{
     Vim,
 };
 
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Debug)]
 pub enum Motion {
     Left,
     Down,
     Up,
     Right,
-    NextWordStart {
-        ignore_punctuation: bool,
-        stop_at_newline: bool,
-    },
-    NextWordEnd {
-        ignore_punctuation: bool,
-    },
-    PreviousWordStart {
-        ignore_punctuation: bool,
-    },
+    NextWordStart { ignore_punctuation: bool },
+    NextWordEnd { ignore_punctuation: bool },
+    PreviousWordStart { ignore_punctuation: bool },
     StartOfLine,
     EndOfLine,
     StartOfDocument,
@@ -41,8 +34,6 @@ pub enum Motion {
 struct NextWordStart {
     #[serde(default)]
     ignore_punctuation: bool,
-    #[serde(default)]
-    stop_at_newline: bool,
 }
 
 #[derive(Clone, Deserialize)]
@@ -87,19 +78,8 @@ pub fn init(cx: &mut MutableAppContext) {
     cx.add_action(|_: &mut Workspace, _: &EndOfDocument, cx: _| motion(Motion::EndOfDocument, cx));
 
     cx.add_action(
-        |_: &mut Workspace,
-         &NextWordStart {
-             ignore_punctuation,
-             stop_at_newline,
-         }: &NextWordStart,
-         cx: _| {
-            motion(
-                Motion::NextWordStart {
-                    ignore_punctuation,
-                    stop_at_newline,
-                },
-                cx,
-            )
+        |_: &mut Workspace, &NextWordStart { ignore_punctuation }: &NextWordStart, cx: _| {
+            motion(Motion::NextWordStart { ignore_punctuation }, cx)
         },
     );
     cx.add_action(
@@ -128,29 +108,48 @@ fn motion(motion: Motion, cx: &mut MutableAppContext) {
     }
 }
 
+// Motion handling is specified here:
+// https://github.com/vim/vim/blob/master/runtime/doc/motion.txt
 impl Motion {
+    pub fn linewise(self) -> bool {
+        use Motion::*;
+        match self {
+            Down | Up | StartOfDocument | EndOfDocument => true,
+            _ => false,
+        }
+    }
+
+    pub fn inclusive(self) -> bool {
+        use Motion::*;
+        if self.linewise() {
+            return true;
+        }
+
+        match self {
+            EndOfLine | NextWordEnd { .. } => true,
+            Left | Right | StartOfLine | NextWordStart { .. } | PreviousWordStart { .. } => false,
+            _ => panic!("Exclusivity not defined for {self:?}"),
+        }
+    }
+
     pub fn move_point(
         self,
         map: &DisplaySnapshot,
         point: DisplayPoint,
         goal: SelectionGoal,
-        block_cursor_positioning: bool,
     ) -> (DisplayPoint, SelectionGoal) {
         use Motion::*;
         match self {
             Left => (left(map, point), SelectionGoal::None),
-            Down => movement::down(map, point, goal),
-            Up => movement::up(map, point, goal),
+            Down => movement::down(map, point, goal, true),
+            Up => movement::up(map, point, goal, true),
             Right => (right(map, point), SelectionGoal::None),
-            NextWordStart {
-                ignore_punctuation,
-                stop_at_newline,
-            } => (
-                next_word_start(map, point, ignore_punctuation, stop_at_newline),
+            NextWordStart { ignore_punctuation } => (
+                next_word_start(map, point, ignore_punctuation),
                 SelectionGoal::None,
             ),
             NextWordEnd { ignore_punctuation } => (
-                next_word_end(map, point, ignore_punctuation, block_cursor_positioning),
+                next_word_end(map, point, ignore_punctuation),
                 SelectionGoal::None,
             ),
             PreviousWordStart { ignore_punctuation } => (
@@ -164,11 +163,55 @@ impl Motion {
         }
     }
 
-    pub fn line_wise(self) -> bool {
-        use Motion::*;
-        match self {
-            Down | Up | StartOfDocument | EndOfDocument => true,
-            _ => false,
+    // Expands a selection using self motion for an operator
+    pub fn expand_selection(
+        self,
+        map: &DisplaySnapshot,
+        selection: &mut Selection<DisplayPoint>,
+        expand_to_surrounding_newline: bool,
+    ) {
+        let (head, goal) = self.move_point(map, selection.head(), selection.goal);
+        selection.set_head(head, goal);
+
+        if self.linewise() {
+            selection.start = map.prev_line_boundary(selection.start.to_point(map)).1;
+
+            if expand_to_surrounding_newline {
+                if selection.end.row() < map.max_point().row() {
+                    *selection.end.row_mut() += 1;
+                    *selection.end.column_mut() = 0;
+                    // Don't reset the end here
+                    return;
+                } else if selection.start.row() > 0 {
+                    *selection.start.row_mut() -= 1;
+                    *selection.start.column_mut() = map.line_len(selection.start.row());
+                }
+            }
+
+            selection.end = map.next_line_boundary(selection.end.to_point(map)).1;
+        } else {
+            // If the motion is exclusive and the end of the motion is in column 1, the
+            // end of the motion is moved to the end of the previous line and the motion
+            // becomes inclusive. Example: "}" moves to the first line after a paragraph,
+            // but "d}" will not include that line.
+            let mut inclusive = self.inclusive();
+            if !inclusive
+                && selection.end.row() > selection.start.row()
+                && selection.end.column() == 0
+                && selection.end.row() > 0
+            {
+                inclusive = true;
+                *selection.end.row_mut() -= 1;
+                *selection.end.column_mut() = 0;
+                selection.end = map.clip_point(
+                    map.next_line_boundary(selection.end.to_point(map)).1,
+                    Bias::Left,
+                );
+            }
+
+            if inclusive && selection.end.column() < map.line_len(selection.end.row()) {
+                *selection.end.column_mut() += 1;
+            }
         }
     }
 }
@@ -187,7 +230,6 @@ fn next_word_start(
     map: &DisplaySnapshot,
     point: DisplayPoint,
     ignore_punctuation: bool,
-    stop_at_newline: bool,
 ) -> DisplayPoint {
     let mut crossed_newline = false;
     movement::find_boundary(map, point, |left, right| {
@@ -196,8 +238,8 @@ fn next_word_start(
         let at_newline = right == '\n';
 
         let found = (left_kind != right_kind && !right.is_whitespace())
-            || (at_newline && (crossed_newline || stop_at_newline))
-            || (at_newline && left == '\n'); // Prevents skipping repeated empty lines
+            || at_newline && crossed_newline
+            || at_newline && left == '\n'; // Prevents skipping repeated empty lines
 
         if at_newline {
             crossed_newline = true;
@@ -210,7 +252,6 @@ fn next_word_end(
     map: &DisplaySnapshot,
     mut point: DisplayPoint,
     ignore_punctuation: bool,
-    before_end_character: bool,
 ) -> DisplayPoint {
     *point.column_mut() += 1;
     point = movement::find_boundary(map, point, |left, right| {
@@ -221,13 +262,12 @@ fn next_word_end(
     });
     // find_boundary clips, so if the character after the next character is a newline or at the end of the document, we know
     // we have backtraced already
-    if before_end_character
-        && !map
-            .chars_at(point)
-            .skip(1)
-            .next()
-            .map(|c| c == '\n')
-            .unwrap_or(true)
+    if !map
+        .chars_at(point)
+        .skip(1)
+        .next()
+        .map(|c| c == '\n')
+        .unwrap_or(true)
     {
         *point.column_mut() = point.column().saturating_sub(1);
     }

crates/vim/src/normal.rs 🔗

@@ -1,11 +1,17 @@
-use crate::{
-    motion::Motion,
-    state::{Mode, Operator},
-    Vim,
-};
-use editor::Bias;
-use gpui::MutableAppContext;
-use language::SelectionGoal;
+mod change;
+mod delete;
+
+use crate::{motion::Motion, state::Operator, Vim};
+use change::init as change_init;
+use gpui::{actions, MutableAppContext};
+
+use self::{change::change_over, delete::delete_over};
+
+actions!(vim, [InsertLineAbove, InsertLineBelow, InsertAfter]);
+
+pub fn init(cx: &mut MutableAppContext) {
+    change_init(cx);
+}
 
 pub fn normal_motion(motion: Motion, cx: &mut MutableAppContext) {
     Vim::update(cx, |vim, cx| {
@@ -23,82 +29,7 @@ pub fn normal_motion(motion: Motion, cx: &mut MutableAppContext) {
 
 fn move_cursor(vim: &mut Vim, motion: Motion, cx: &mut MutableAppContext) {
     vim.update_active_editor(cx, |editor, cx| {
-        editor.move_cursors(cx, |map, cursor, goal| {
-            motion.move_point(map, cursor, goal, true)
-        })
-    });
-}
-
-fn change_over(vim: &mut Vim, motion: Motion, cx: &mut MutableAppContext) {
-    vim.update_active_editor(cx, |editor, cx| {
-        editor.transact(cx, |editor, cx| {
-            // Don't clip at line ends during change operation
-            editor.set_clip_at_line_ends(false, cx);
-            editor.move_selections(cx, |map, selection| {
-                let (head, goal) = motion.move_point(map, selection.head(), selection.goal, false);
-                selection.set_head(head, goal);
-
-                if motion.line_wise() {
-                    selection.start = map.prev_line_boundary(selection.start.to_point(map)).1;
-                    selection.end = map.next_line_boundary(selection.end.to_point(map)).1;
-                }
-            });
-            editor.set_clip_at_line_ends(true, cx);
-            editor.insert(&"", cx);
-        });
-    });
-    vim.switch_mode(Mode::Insert, cx)
-}
-
-fn delete_over(vim: &mut Vim, motion: Motion, cx: &mut MutableAppContext) {
-    vim.update_active_editor(cx, |editor, cx| {
-        editor.transact(cx, |editor, cx| {
-            // Use goal column to preserve previous position
-            editor.set_clip_at_line_ends(false, cx);
-            editor.move_selections(cx, |map, selection| {
-                let original_head = selection.head();
-                let (head, _) = motion.move_point(map, selection.head(), selection.goal, false);
-                // Set the goal column to the original position in order to fix it up
-                // after the deletion
-                selection.set_head(head, SelectionGoal::Column(original_head.column()));
-
-                if motion.line_wise() {
-                    if selection.end.row() == map.max_point().row() {
-                        // Delete previous line break since we are at the end of the document
-                        if selection.start.row() > 0 {
-                            *selection.start.row_mut() = selection.start.row().saturating_sub(1);
-                            selection.start = map.clip_point(selection.start, Bias::Left);
-                            selection.start =
-                                map.next_line_boundary(selection.start.to_point(map)).1;
-                        } else {
-                            // Selection covers the whole document. Just delete to the start of the
-                            // line.
-                            selection.start =
-                                map.prev_line_boundary(selection.start.to_point(map)).1;
-                        }
-                        selection.end = map.next_line_boundary(selection.end.to_point(map)).1;
-                    } else {
-                        // Delete next line break so that we leave the previous line alone
-                        selection.start = map.prev_line_boundary(selection.start.to_point(map)).1;
-                        *selection.end.column_mut() = 0;
-                        *selection.end.row_mut() += 1;
-                        selection.end = map.clip_point(selection.end, Bias::Left);
-                    }
-                }
-            });
-            editor.insert(&"", cx);
-
-            // Fixup cursor position after the deletion
-            editor.set_clip_at_line_ends(true, cx);
-            editor.move_cursors(cx, |map, mut cursor, goal| {
-                if motion.line_wise() {
-                    if let SelectionGoal::Column(column) = goal {
-                        *cursor.column_mut() = column
-                    }
-                }
-                (map.clip_point(cursor, Bias::Left), SelectionGoal::None)
-            });
-        });
+        editor.move_cursors(cx, |map, cursor, goal| motion.move_point(map, cursor, goal))
     });
 }
 
@@ -116,144 +47,218 @@ mod test {
     };
 
     #[gpui::test]
-    async fn test_hjkl(cx: &mut gpui::TestAppContext) {
-        let mut cx = VimTestContext::new(cx, true, "Test\nTestTest\nTest").await;
-        cx.simulate_keystroke("l");
-        cx.assert_editor_state(indoc! {"
-            T|est
-            TestTest
-            Test"});
-        cx.simulate_keystroke("h");
-        cx.assert_editor_state(indoc! {"
-            |Test
-            TestTest
-            Test"});
-        cx.simulate_keystroke("j");
-        cx.assert_editor_state(indoc! {"
-            Test
-            |TestTest
-            Test"});
-        cx.simulate_keystroke("k");
-        cx.assert_editor_state(indoc! {"
-            |Test
-            TestTest
-            Test"});
-        cx.simulate_keystroke("j");
-        cx.assert_editor_state(indoc! {"
-            Test
-            |TestTest
-            Test"});
+    async fn test_h(cx: &mut gpui::TestAppContext) {
+        let cx = VimTestContext::new(cx, true).await;
+        let mut cx = cx.binding(["h"]);
+        cx.assert("The q|uick", "The |quick");
+        cx.assert("|The quick", "|The quick");
+        cx.assert(
+            indoc! {"
+                The quick
+                |brown"},
+            indoc! {"
+                The quick
+                |brown"},
+        );
+    }
 
-        // When moving left, cursor does not wrap to the previous line
-        cx.simulate_keystroke("h");
-        cx.assert_editor_state(indoc! {"
-            Test
-            |TestTest
-            Test"});
+    #[gpui::test]
+    async fn test_l(cx: &mut gpui::TestAppContext) {
+        let cx = VimTestContext::new(cx, true).await;
+        let mut cx = cx.binding(["l"]);
+        cx.assert("The q|uick", "The qu|ick");
+        cx.assert("The quic|k", "The quic|k");
+        cx.assert(
+            indoc! {"
+                The quic|k
+                brown"},
+            indoc! {"
+                The quic|k
+                brown"},
+        );
+    }
 
-        // When moving right, cursor does not reach the line end or wrap to the next line
-        for _ in 0..9 {
-            cx.simulate_keystroke("l");
-        }
-        cx.assert_editor_state(indoc! {"
-            Test
-            TestTes|t
-            Test"});
+    #[gpui::test]
+    async fn test_j(cx: &mut gpui::TestAppContext) {
+        let cx = VimTestContext::new(cx, true).await;
+        let mut cx = cx.binding(["j"]);
+        cx.assert(
+            indoc! {"
+                The |quick
+                brown fox"},
+            indoc! {"
+                The quick
+                brow|n fox"},
+        );
+        cx.assert(
+            indoc! {"
+                The quick
+                brow|n fox"},
+            indoc! {"
+                The quick
+                brow|n fox"},
+        );
+        cx.assert(
+            indoc! {"
+                The quic|k
+                brown"},
+            indoc! {"
+                The quick
+                brow|n"},
+        );
+        cx.assert(
+            indoc! {"
+                The quick
+                |brown"},
+            indoc! {"
+                The quick
+                |brown"},
+        );
+    }
 
-        // Goal column respects the inability to reach the end of the line
-        cx.simulate_keystroke("k");
-        cx.assert_editor_state(indoc! {"
-            Tes|t
-            TestTest
-            Test"});
-        cx.simulate_keystroke("j");
-        cx.assert_editor_state(indoc! {"
-            Test
-            TestTes|t
-            Test"});
+    #[gpui::test]
+    async fn test_k(cx: &mut gpui::TestAppContext) {
+        let cx = VimTestContext::new(cx, true).await;
+        let mut cx = cx.binding(["k"]);
+        cx.assert(
+            indoc! {"
+                The |quick
+                brown fox"},
+            indoc! {"
+                The |quick
+                brown fox"},
+        );
+        cx.assert(
+            indoc! {"
+                The quick
+                brow|n fox"},
+            indoc! {"
+                The |quick
+                brown fox"},
+        );
+        cx.assert(
+            indoc! {"
+                The
+                quic|k"},
+            indoc! {"
+                Th|e
+                quick"},
+        );
     }
 
     #[gpui::test]
     async fn test_jump_to_line_boundaries(cx: &mut gpui::TestAppContext) {
-        let initial_content = indoc! {"
-            Test Test
-            
-            T"};
-        let mut cx = VimTestContext::new(cx, true, initial_content).await;
-
-        cx.simulate_keystroke("shift-$");
-        cx.assert_editor_state(indoc! {"
-            Test Tes|t
-            
-            T"});
-        cx.simulate_keystroke("0");
-        cx.assert_editor_state(indoc! {"
-            |Test Test
-            
-            T"});
-
-        cx.simulate_keystroke("j");
-        cx.simulate_keystroke("shift-$");
-        cx.assert_editor_state(indoc! {"
-            Test Test
-            |
-            T"});
-        cx.simulate_keystroke("0");
-        cx.assert_editor_state(indoc! {"
-            Test Test
-            |
-            T"});
+        let cx = VimTestContext::new(cx, true).await;
+        let mut cx = cx.binding(["shift-$"]);
+        cx.assert("T|est test", "Test tes|t");
+        cx.assert("Test tes|t", "Test tes|t");
+        cx.assert(
+            indoc! {"
+                The |quick
+                brown"},
+            indoc! {"
+                The quic|k
+                brown"},
+        );
+        cx.assert(
+            indoc! {"
+                The quic|k
+                brown"},
+            indoc! {"
+                The quic|k
+                brown"},
+        );
 
-        cx.simulate_keystroke("j");
-        cx.simulate_keystroke("shift-$");
-        cx.assert_editor_state(indoc! {"
-            Test Test
-            
-            |T"});
-        cx.simulate_keystroke("0");
-        cx.assert_editor_state(indoc! {"
-            Test Test
-            
-            |T"});
+        let mut cx = cx.binding(["0"]);
+        cx.assert("Test |test", "|Test test");
+        cx.assert("|Test test", "|Test test");
+        cx.assert(
+            indoc! {"
+                The |quick
+                brown"},
+            indoc! {"
+                |The quick
+                brown"},
+        );
+        cx.assert(
+            indoc! {"
+                |The quick
+                brown"},
+            indoc! {"
+                |The quick
+                brown"},
+        );
     }
 
     #[gpui::test]
     async fn test_jump_to_end(cx: &mut gpui::TestAppContext) {
-        let mut cx = VimTestContext::new(cx, true, "").await;
+        let cx = VimTestContext::new(cx, true).await;
+        let mut cx = cx.binding(["shift-G"]);
 
-        cx.set_state(
+        cx.assert(
             indoc! {"
-            The |quick
-            
-            brown fox jumps
-            over the lazy dog"},
-            Mode::Normal,
+                The |quick
+                
+                brown fox jumps
+                over the lazy dog"},
+            indoc! {"
+                The quick
+                
+                brown fox jumps
+                over| the lazy dog"},
         );
-        cx.simulate_keystroke("shift-G");
-        cx.assert_editor_state(indoc! {"
+        cx.assert(
+            indoc! {"
+                The quick
+                
+                brown fox jumps
+                over| the lazy dog"},
+            indoc! {"
+                The quick
+                
+                brown fox jumps
+                over| the lazy dog"},
+        );
+        cx.assert(
+            indoc! {"
+            The qui|ck
+            
+            brown"},
+            indoc! {"
             The quick
             
-            brown fox jumps
-            over| the lazy dog"});
-
-        // Repeat the action doesn't move
-        cx.simulate_keystroke("shift-G");
-        cx.assert_editor_state(indoc! {"
+            brow|n"},
+        );
+        cx.assert(
+            indoc! {"
+            The qui|ck
+            
+            "},
+            indoc! {"
             The quick
             
-            brown fox jumps
-            over| the lazy dog"});
+            |"},
+        );
     }
 
     #[gpui::test]
     async fn test_next_word_start(cx: &mut gpui::TestAppContext) {
-        let (initial_content, cursor_offsets) = marked_text(indoc! {"
+        let mut cx = VimTestContext::new(cx, true).await;
+        let (_, cursor_offsets) = marked_text(indoc! {"
             The |quick|-|brown
             |
             |
             |fox_jumps |over
             |th||e"});
-        let mut cx = VimTestContext::new(cx, true, &initial_content).await;
+        cx.set_state(
+            indoc! {"
+            |The quick-brown
+            
+            
+            fox_jumps over
+            the"},
+            Mode::Normal,
+        );
 
         for cursor_offset in cursor_offsets {
             cx.simulate_keystroke("w");
@@ -261,13 +266,21 @@ mod test {
         }
 
         // Reset and test ignoring punctuation
-        cx.simulate_keystrokes(["g", "g", "0"]);
         let (_, cursor_offsets) = marked_text(indoc! {"
             The |quick-brown
             |
             |
             |fox_jumps |over
             |th||e"});
+        cx.set_state(
+            indoc! {"
+            |The quick-brown
+            
+            
+            fox_jumps over
+            the"},
+            Mode::Normal,
+        );
 
         for cursor_offset in cursor_offsets {
             cx.simulate_keystroke("shift-W");
@@ -277,13 +290,22 @@ mod test {
 
     #[gpui::test]
     async fn test_next_word_end(cx: &mut gpui::TestAppContext) {
-        let (initial_content, cursor_offsets) = marked_text(indoc! {"
+        let mut cx = VimTestContext::new(cx, true).await;
+        let (_, cursor_offsets) = marked_text(indoc! {"
             Th|e quic|k|-brow|n
             
             
             fox_jump|s ove|r
             th|e"});
-        let mut cx = VimTestContext::new(cx, true, &initial_content).await;
+        cx.set_state(
+            indoc! {"
+            |The quick-brown
+            
+            
+            fox_jumps over
+            the"},
+            Mode::Normal,
+        );
 
         for cursor_offset in cursor_offsets {
             cx.simulate_keystroke("e");
@@ -291,13 +313,21 @@ mod test {
         }
 
         // Reset and test ignoring punctuation
-        cx.simulate_keystrokes(["g", "g", "0"]);
         let (_, cursor_offsets) = marked_text(indoc! {"
             Th|e quick-brow|n
             
             
             fox_jump|s ove|r
             th||e"});
+        cx.set_state(
+            indoc! {"
+            |The quick-brown
+            
+            
+            fox_jumps over
+            the"},
+            Mode::Normal,
+        );
         for cursor_offset in cursor_offsets {
             cx.simulate_keystroke("shift-E");
             cx.assert_newest_selection_head_offset(cursor_offset);
@@ -306,14 +336,22 @@ mod test {
 
     #[gpui::test]
     async fn test_previous_word_start(cx: &mut gpui::TestAppContext) {
-        let (initial_content, cursor_offsets) = marked_text(indoc! {"
+        let mut cx = VimTestContext::new(cx, true).await;
+        let (_, cursor_offsets) = marked_text(indoc! {"
             ||The |quick|-|brown
             |
             |
             |fox_jumps |over
             |the"});
-        let mut cx = VimTestContext::new(cx, true, &initial_content).await;
-        cx.simulate_keystrokes(["shift-G", "shift-$"]);
+        cx.set_state(
+            indoc! {"
+            The quick-brown
+            
+            
+            fox_jumps over
+            th|e"},
+            Mode::Normal,
+        );
 
         for cursor_offset in cursor_offsets.into_iter().rev() {
             cx.simulate_keystroke("b");
@@ -321,13 +359,21 @@ mod test {
         }
 
         // Reset and test ignoring punctuation
-        cx.simulate_keystrokes(["shift-G", "shift-$"]);
         let (_, cursor_offsets) = marked_text(indoc! {"
             ||The |quick-brown
             |
             |
             |fox_jumps |over
             |the"});
+        cx.set_state(
+            indoc! {"
+            The quick-brown
+            
+            
+            fox_jumps over
+            th|e"},
+            Mode::Normal,
+        );
         for cursor_offset in cursor_offsets.into_iter().rev() {
             cx.simulate_keystroke("shift-B");
             cx.assert_newest_selection_head_offset(cursor_offset);
@@ -336,7 +382,7 @@ mod test {
 
     #[gpui::test]
     async fn test_g_prefix_and_abort(cx: &mut gpui::TestAppContext) {
-        let mut cx = VimTestContext::new(cx, true, "").await;
+        let mut cx = VimTestContext::new(cx, true).await;
 
         // Can abort with escape to get back to normal mode
         cx.simulate_keystroke("g");
@@ -352,455 +398,55 @@ mod test {
 
     #[gpui::test]
     async fn test_move_to_start(cx: &mut gpui::TestAppContext) {
-        let mut cx = VimTestContext::new(cx, true, "").await;
-
-        cx.set_state(
+        let cx = VimTestContext::new(cx, true).await;
+        let mut cx = cx.binding(["g", "g"]);
+        cx.assert(
             indoc! {"
-            The q|uick
+                The quick
             
-            brown fox jumps
-            over the lazy dog"},
-            Mode::Normal,
-        );
-
-        // Jump to the end to
-        cx.simulate_keystroke("shift-G");
-        cx.assert_editor_state(indoc! {"
-            The quick
-            
-            brown fox jumps
-            over |the lazy dog"});
-
-        // Jump to the start
-        cx.simulate_keystrokes(["g", "g"]);
-        cx.assert_editor_state(indoc! {"
-            The q|uick
-            
-            brown fox jumps
-            over the lazy dog"});
-        assert_eq!(cx.mode(), Normal);
-        assert_eq!(cx.active_operator(), None);
-
-        // Repeat action doesn't change
-        cx.simulate_keystrokes(["g", "g"]);
-        cx.assert_editor_state(indoc! {"
-            The q|uick
-            
-            brown fox jumps
-            over the lazy dog"});
-        assert_eq!(cx.mode(), Normal);
-        assert_eq!(cx.active_operator(), None);
-    }
-
-    #[gpui::test]
-    async fn test_change(cx: &mut gpui::TestAppContext) {
-        fn assert(motion: &str, initial_state: &str, state_after: &str, cx: &mut VimTestContext) {
-            cx.assert_binding(
-                ["c", motion],
-                initial_state,
-                Mode::Normal,
-                state_after,
-                Mode::Insert,
-            );
-        }
-        let cx = &mut VimTestContext::new(cx, true, "").await;
-        assert("h", "Te|st", "T|st", cx);
-        assert("l", "Te|st", "Te|t", cx);
-        assert("w", "|Test", "|", cx);
-        assert("w", "Te|st", "Te|", cx);
-        assert("w", "Te|st Test", "Te| Test", cx);
-        assert("e", "Te|st Test", "Te| Test", cx);
-        assert("b", "Te|st", "|st", cx);
-        assert("b", "Test Te|st", "Test |st", cx);
-        assert(
-            "w",
-            indoc! {"
-            The quick
-            brown |fox
-            jumps over"},
-            indoc! {"
-            The quick
-            brown |
-            jumps over"},
-            cx,
-        );
-        assert(
-            "shift-W",
-            indoc! {"
-            The quick
-            brown |fox-fox
-            jumps over"},
-            indoc! {"
-            The quick
-            brown |
-            jumps over"},
-            cx,
-        );
-        assert(
-            "k",
-            indoc! {"
-            The quick
-            brown |fox"},
-            indoc! {"
-            |"},
-            cx,
-        );
-        assert(
-            "j",
-            indoc! {"
-            The q|uick
-            brown fox"},
-            indoc! {"
-            |"},
-            cx,
-        );
-        assert(
-            "shift-$",
-            indoc! {"
-            The q|uick
-            brown fox"},
-            indoc! {"
-            The q|
-            brown fox"},
-            cx,
-        );
-        assert(
-            "0",
-            indoc! {"
-            The q|uick
-            brown fox"},
-            indoc! {"
-            |uick
-            brown fox"},
-            cx,
-        );
-    }
-
-    #[gpui::test]
-    async fn test_delete(cx: &mut gpui::TestAppContext) {
-        fn assert(motion: &str, initial_state: &str, state_after: &str, cx: &mut VimTestContext) {
-            cx.assert_binding(
-                ["d", motion],
-                initial_state,
-                Mode::Normal,
-                state_after,
-                Mode::Normal,
-            );
-        }
-        let cx = &mut VimTestContext::new(cx, true, "").await;
-        assert("h", "Te|st", "T|st", cx);
-        assert("l", "Te|st", "Te|t", cx);
-        assert("w", "|Test", "|", cx);
-        assert("w", "Te|st", "T|e", cx);
-        assert("w", "Te|st Test", "Te|Test", cx);
-        assert("e", "Te|st Test", "Te| Test", cx);
-        assert("b", "Te|st", "|st", cx);
-        assert("b", "Test Te|st", "Test |st", cx);
-        assert(
-            "w",
-            indoc! {"
-            The quick
-            brown |fox
-            jumps over"},
-            // Trailing space after cursor
-            indoc! {"
-            The quick
-            brown| 
-            jumps over"},
-            cx,
-        );
-        assert(
-            "shift-W",
-            indoc! {"
-            The quick
-            brown |fox-fox
-            jumps over"},
-            // Trailing space after cursor
-            indoc! {"
-            The quick
-            brown| 
-            jumps over"},
-            cx,
-        );
-        assert(
-            "shift-$",
-            indoc! {"
-            The q|uick
-            brown fox"},
-            indoc! {"
-            The |q
-            brown fox"},
-            cx,
-        );
-        assert(
-            "0",
-            indoc! {"
-            The q|uick
-            brown fox"},
-            indoc! {"
-            |uick
-            brown fox"},
-            cx,
-        );
-    }
-
-    #[gpui::test]
-    async fn test_linewise_delete(cx: &mut gpui::TestAppContext) {
-        fn assert(motion: &str, initial_state: &str, state_after: &str, cx: &mut VimTestContext) {
-            cx.assert_binding(
-                ["d", motion],
-                initial_state,
-                Mode::Normal,
-                state_after,
-                Mode::Normal,
-            );
-        }
-        let cx = &mut VimTestContext::new(cx, true, "").await;
-        assert(
-            "k",
-            indoc! {"
-            The quick
-            brown |fox
-            jumps over"},
-            indoc! {"
-            jumps |over"},
-            cx,
-        );
-        assert(
-            "k",
-            indoc! {"
-            The quick
-            brown fox
-            jumps |over"},
-            indoc! {"
-            The qu|ick"},
-            cx,
-        );
-        assert(
-            "j",
+                brown fox jumps
+                over |the lazy dog"},
             indoc! {"
-            The q|uick
-            brown fox
-            jumps over"},
-            indoc! {"
-            jumps| over"},
-            cx,
-        );
-        assert(
-            "j",
-            indoc! {"
-            The quick
-            brown| fox
-            jumps over"},
-            indoc! {"
-            The q|uick"},
-            cx,
-        );
-        assert(
-            "j",
-            indoc! {"
-            The quick
-            brown| fox
-            jumps over"},
-            indoc! {"
-            The q|uick"},
-            cx,
-        );
-        cx.assert_binding(
-            ["d", "g", "g"],
-            indoc! {"
-            The quick
-            brown| fox
-            jumps over
-            the lazy"},
-            Mode::Normal,
-            indoc! {"
-            jumps| over
-            the lazy"},
-            Mode::Normal,
-        );
-        cx.assert_binding(
-            ["d", "g", "g"],
-            indoc! {"
-            The quick
-            brown fox
-            jumps over
-            the l|azy"},
-            Mode::Normal,
-            "|",
-            Mode::Normal,
-        );
-        assert(
-            "shift-G",
-            indoc! {"
-            The quick
-            brown| fox
-            jumps over
-            the lazy"},
-            indoc! {"
-            The q|uick"},
-            cx,
-        );
-        cx.assert_binding(
-            ["d", "g", "g"],
-            indoc! {"
-            The q|uick
-            brown fox
-            jumps over
-            the lazy"},
-            Mode::Normal,
-            indoc! {"
-            brown| fox
-            jumps over
-            the lazy"},
-            Mode::Normal,
-        );
-    }
-
-    #[gpui::test]
-    async fn test_linewise_change(cx: &mut gpui::TestAppContext) {
-        fn assert(motion: &str, initial_state: &str, state_after: &str, cx: &mut VimTestContext) {
-            cx.assert_binding(
-                ["c", motion],
-                initial_state,
-                Mode::Normal,
-                state_after,
-                Mode::Insert,
-            );
-        }
-        let cx = &mut VimTestContext::new(cx, true, "").await;
-        assert(
-            "k",
-            indoc! {"
-            The quick
-            brown |fox
-            jumps over"},
-            indoc! {"
-            |
-            jumps over"},
-            cx,
-        );
-        assert(
-            "k",
-            indoc! {"
-            The quick
-            brown fox
-            jumps |over"},
-            indoc! {"
-            The quick
-            |"},
-            cx,
-        );
-        assert(
-            "j",
-            indoc! {"
-            The q|uick
-            brown fox
-            jumps over"},
-            indoc! {"
-            |
-            jumps over"},
-            cx,
-        );
-        assert(
-            "j",
-            indoc! {"
-            The quick
-            brown| fox
-            jumps over"},
-            indoc! {"
-            The quick
-            |"},
-            cx,
-        );
-        assert(
-            "j",
-            indoc! {"
-            The quick
-            brown| fox
-            jumps over"},
-            indoc! {"
-            The quick
-            |"},
-            cx,
-        );
-        assert(
-            "shift-G",
-            indoc! {"
-            The quick
-            brown| fox
-            jumps over
-            the lazy"},
-            indoc! {"
-            The quick
-            |"},
-            cx,
-        );
-        assert(
-            "shift-G",
-            indoc! {"
-            The quick
-            brown| fox
-            jumps over
-            the lazy"},
-            indoc! {"
-            The quick
-            |"},
-            cx,
+                The q|uick
+            
+                brown fox jumps
+                over the lazy dog"},
         );
-        assert(
-            "shift-G",
+        cx.assert(
             indoc! {"
-            The quick
-            brown fox
-            jumps over
-            the l|azy"},
+                The q|uick
+            
+                brown fox jumps
+                over the lazy dog"},
             indoc! {"
-            The quick
-            brown fox
-            jumps over
-            |"},
-            cx,
+                The q|uick
+            
+                brown fox jumps
+                over the lazy dog"},
         );
-        cx.assert_binding(
-            ["c", "g", "g"],
+        cx.assert(
             indoc! {"
-            The quick
-            brown| fox
-            jumps over
-            the lazy"},
-            Mode::Normal,
-            indoc! {"
-            |
-            jumps over
-            the lazy"},
-            Mode::Insert,
-        );
-        cx.assert_binding(
-            ["c", "g", "g"],
+                The quick
+            
+                brown fox jumps
+                over the la|zy dog"},
             indoc! {"
-            The quick
-            brown fox
-            jumps over
-            the l|azy"},
-            Mode::Normal,
-            "|",
-            Mode::Insert,
+                The quic|k
+            
+                brown fox jumps
+                over the lazy dog"},
         );
-        cx.assert_binding(
-            ["c", "g", "g"],
+        cx.assert(
             indoc! {"
-            The q|uick
-            brown fox
-            jumps over
-            the lazy"},
-            Mode::Normal,
+                
+            
+                brown fox jumps
+                over the la|zy dog"},
             indoc! {"
-            |
-            brown fox
-            jumps over
-            the lazy"},
-            Mode::Insert,
+                |
+            
+                brown fox jumps
+                over the lazy dog"},
         );
     }
 }

crates/vim/src/normal/change.rs 🔗

@@ -0,0 +1,436 @@
+use crate::{motion::Motion, state::Mode, Vim};
+use editor::{char_kind, movement};
+use gpui::{impl_actions, MutableAppContext, ViewContext};
+use serde::Deserialize;
+use workspace::Workspace;
+
+#[derive(Clone, Deserialize)]
+#[serde(rename_all = "camelCase")]
+struct ChangeWord {
+    #[serde(default)]
+    ignore_punctuation: bool,
+}
+
+impl_actions!(vim, [ChangeWord]);
+
+pub fn init(cx: &mut MutableAppContext) {
+    cx.add_action(change_word);
+}
+
+pub fn change_over(vim: &mut Vim, motion: Motion, cx: &mut MutableAppContext) {
+    vim.update_active_editor(cx, |editor, cx| {
+        editor.transact(cx, |editor, cx| {
+            // We are swapping to insert mode anyway. Just set the line end clipping behavior now
+            editor.set_clip_at_line_ends(false, cx);
+            editor.move_selections(cx, |map, selection| {
+                motion.expand_selection(map, selection, false);
+            });
+            editor.insert(&"", cx);
+        });
+    });
+    vim.switch_mode(Mode::Insert, cx)
+}
+
+// From the docs https://vimhelp.org/change.txt.html#cw
+// Special case: When the cursor is in a word, "cw" and "cW" do not include the
+// white space after a word, they only change up to the end of the word. This is
+// because Vim interprets "cw" as change-word, and a word does not include the
+// following white space.
+fn change_word(
+    _: &mut Workspace,
+    &ChangeWord { ignore_punctuation }: &ChangeWord,
+    cx: &mut ViewContext<Workspace>,
+) {
+    Vim::update(cx, |vim, cx| {
+        vim.update_active_editor(cx, |editor, cx| {
+            editor.transact(cx, |editor, cx| {
+                // We are swapping to insert mode anyway. Just set the line end clipping behavior now
+                editor.set_clip_at_line_ends(false, cx);
+                editor.move_selections(cx, |map, selection| {
+                    if selection.end.column() == map.line_len(selection.end.row()) {
+                        return;
+                    }
+
+                    selection.end = movement::find_boundary(map, selection.end, |left, right| {
+                        let left_kind = char_kind(left).coerce_punctuation(ignore_punctuation);
+                        let right_kind = char_kind(right).coerce_punctuation(ignore_punctuation);
+
+                        left_kind != right_kind || left == '\n' || right == '\n'
+                    });
+                });
+                editor.insert(&"", cx);
+            });
+        });
+        vim.switch_mode(Mode::Insert, cx);
+    });
+}
+
+#[cfg(test)]
+mod test {
+    use indoc::indoc;
+
+    use crate::{state::Mode, vim_test_context::VimTestContext};
+
+    #[gpui::test]
+    async fn test_change_h(cx: &mut gpui::TestAppContext) {
+        let cx = VimTestContext::new(cx, true).await;
+        let mut cx = cx.binding(["c", "h"]).mode_after(Mode::Insert);
+        cx.assert("Te|st", "T|st");
+        cx.assert("T|est", "|est");
+        cx.assert("|Test", "|Test");
+        cx.assert(
+            indoc! {"
+                Test
+                |test"},
+            indoc! {"
+                Test
+                |test"},
+        );
+    }
+
+    #[gpui::test]
+    async fn test_change_l(cx: &mut gpui::TestAppContext) {
+        let cx = VimTestContext::new(cx, true).await;
+        let mut cx = cx.binding(["c", "l"]).mode_after(Mode::Insert);
+        cx.assert("Te|st", "Te|t");
+        cx.assert("Tes|t", "Tes|");
+    }
+
+    #[gpui::test]
+    async fn test_change_w(cx: &mut gpui::TestAppContext) {
+        let cx = VimTestContext::new(cx, true).await;
+        let mut cx = cx.binding(["c", "w"]).mode_after(Mode::Insert);
+        cx.assert("Te|st", "Te|");
+        cx.assert("T|est test", "T| test");
+        cx.assert("Test|  test", "Test|test");
+        cx.assert(
+            indoc! {"
+                Test te|st
+                test"},
+            indoc! {"
+                Test te|
+                test"},
+        );
+        cx.assert(
+            indoc! {"
+                Test tes|t
+                test"},
+            indoc! {"
+                Test tes|
+                test"},
+        );
+        cx.assert(
+            indoc! {"
+                Test test
+                |
+                test"},
+            indoc! {"
+                Test test
+                |
+                test"},
+        );
+
+        let mut cx = cx.binding(["c", "shift-W"]);
+        cx.assert("Test te|st-test test", "Test te| test");
+    }
+
+    #[gpui::test]
+    async fn test_change_e(cx: &mut gpui::TestAppContext) {
+        let cx = VimTestContext::new(cx, true).await;
+        let mut cx = cx.binding(["c", "e"]).mode_after(Mode::Insert);
+        cx.assert("Te|st Test", "Te| Test");
+        cx.assert("T|est test", "T| test");
+        cx.assert(
+            indoc! {"
+                Test te|st
+                test"},
+            indoc! {"
+                Test te|
+                test"},
+        );
+        cx.assert(
+            indoc! {"
+                Test tes|t
+                test"},
+            "Test tes|",
+        );
+        cx.assert(
+            indoc! {"
+                Test test
+                |
+                test"},
+            indoc! {"
+                Test test
+                |
+                test"},
+        );
+
+        let mut cx = cx.binding(["c", "shift-E"]);
+        cx.assert("Test te|st-test test", "Test te| test");
+    }
+
+    #[gpui::test]
+    async fn test_change_b(cx: &mut gpui::TestAppContext) {
+        let cx = VimTestContext::new(cx, true).await;
+        let mut cx = cx.binding(["c", "b"]).mode_after(Mode::Insert);
+        cx.assert("Te|st Test", "|st Test");
+        cx.assert("Test |test", "|test");
+        cx.assert("Test1 test2 |test3", "Test1 |test3");
+        cx.assert(
+            indoc! {"
+                Test test
+                |test"},
+            indoc! {"
+                Test |
+                test"},
+        );
+        cx.assert(
+            indoc! {"
+                Test test
+                |
+                test"},
+            indoc! {"
+                Test |
+                
+                test"},
+        );
+
+        let mut cx = cx.binding(["c", "shift-B"]);
+        cx.assert("Test test-test |test", "Test |test");
+    }
+
+    #[gpui::test]
+    async fn test_change_end_of_line(cx: &mut gpui::TestAppContext) {
+        let cx = VimTestContext::new(cx, true).await;
+        let mut cx = cx.binding(["c", "shift-$"]).mode_after(Mode::Insert);
+        cx.assert(
+            indoc! {"
+                The q|uick
+                brown fox"},
+            indoc! {"
+                The q|
+                brown fox"},
+        );
+        cx.assert(
+            indoc! {"
+                The quick
+                |
+                brown fox"},
+            indoc! {"
+                The quick
+                |
+                brown fox"},
+        );
+    }
+
+    #[gpui::test]
+    async fn test_change_0(cx: &mut gpui::TestAppContext) {
+        let cx = VimTestContext::new(cx, true).await;
+        let mut cx = cx.binding(["c", "0"]).mode_after(Mode::Insert);
+        cx.assert(
+            indoc! {"
+                The q|uick
+                brown fox"},
+            indoc! {"
+                |uick
+                brown fox"},
+        );
+        cx.assert(
+            indoc! {"
+                The quick
+                |
+                brown fox"},
+            indoc! {"
+                The quick
+                |
+                brown fox"},
+        );
+    }
+
+    #[gpui::test]
+    async fn test_change_k(cx: &mut gpui::TestAppContext) {
+        let cx = VimTestContext::new(cx, true).await;
+        let mut cx = cx.binding(["c", "k"]).mode_after(Mode::Insert);
+        cx.assert(
+            indoc! {"
+                The quick
+                brown |fox
+                jumps over"},
+            indoc! {"
+                |
+                jumps over"},
+        );
+        cx.assert(
+            indoc! {"
+                The quick
+                brown fox
+                jumps |over"},
+            indoc! {"
+                The quick
+                |"},
+        );
+        cx.assert(
+            indoc! {"
+                The q|uick
+                brown fox
+                jumps over"},
+            indoc! {"
+                |
+                brown fox
+                jumps over"},
+        );
+        cx.assert(
+            indoc! {"
+                |
+                brown fox
+                jumps over"},
+            indoc! {"
+                |
+                brown fox
+                jumps over"},
+        );
+    }
+
+    #[gpui::test]
+    async fn test_change_j(cx: &mut gpui::TestAppContext) {
+        let cx = VimTestContext::new(cx, true).await;
+        let mut cx = cx.binding(["c", "j"]).mode_after(Mode::Insert);
+        cx.assert(
+            indoc! {"
+                The quick
+                brown |fox
+                jumps over"},
+            indoc! {"
+                The quick
+                |"},
+        );
+        cx.assert(
+            indoc! {"
+                The quick
+                brown fox
+                jumps |over"},
+            indoc! {"
+                The quick
+                brown fox
+                |"},
+        );
+        cx.assert(
+            indoc! {"
+                The q|uick
+                brown fox
+                jumps over"},
+            indoc! {"
+                |
+                jumps over"},
+        );
+        cx.assert(
+            indoc! {"
+                The quick
+                brown fox
+                |"},
+            indoc! {"
+                The quick
+                brown fox
+                |"},
+        );
+    }
+
+    #[gpui::test]
+    async fn test_change_end_of_document(cx: &mut gpui::TestAppContext) {
+        let cx = VimTestContext::new(cx, true).await;
+        let mut cx = cx.binding(["c", "shift-G"]).mode_after(Mode::Insert);
+        cx.assert(
+            indoc! {"
+                The quick
+                brown| fox
+                jumps over
+                the lazy"},
+            indoc! {"
+                The quick
+                |"},
+        );
+        cx.assert(
+            indoc! {"
+                The quick
+                brown| fox
+                jumps over
+                the lazy"},
+            indoc! {"
+                The quick
+                |"},
+        );
+        cx.assert(
+            indoc! {"
+                The quick
+                brown fox
+                jumps over
+                the l|azy"},
+            indoc! {"
+                The quick
+                brown fox
+                jumps over
+                |"},
+        );
+        cx.assert(
+            indoc! {"
+                The quick
+                brown fox
+                jumps over
+                |"},
+            indoc! {"
+                The quick
+                brown fox
+                jumps over
+                |"},
+        );
+    }
+
+    #[gpui::test]
+    async fn test_change_gg(cx: &mut gpui::TestAppContext) {
+        let cx = VimTestContext::new(cx, true).await;
+        let mut cx = cx.binding(["c", "g", "g"]).mode_after(Mode::Insert);
+        cx.assert(
+            indoc! {"
+                The quick
+                brown| fox
+                jumps over
+                the lazy"},
+            indoc! {"
+                |
+                jumps over
+                the lazy"},
+        );
+        cx.assert(
+            indoc! {"
+                The quick
+                brown fox
+                jumps over
+                the l|azy"},
+            "|",
+        );
+        cx.assert(
+            indoc! {"
+                The q|uick
+                brown fox
+                jumps over
+                the lazy"},
+            indoc! {"
+                |
+                brown fox
+                jumps over
+                the lazy"},
+        );
+        cx.assert(
+            indoc! {"
+                |
+                brown fox
+                jumps over
+                the lazy"},
+            indoc! {"
+                |
+                brown fox
+                jumps over
+                the lazy"},
+        );
+    }
+}

crates/vim/src/normal/delete.rs 🔗

@@ -0,0 +1,386 @@
+use crate::{motion::Motion, Vim};
+use editor::Bias;
+use gpui::MutableAppContext;
+use language::SelectionGoal;
+
+pub fn delete_over(vim: &mut Vim, motion: Motion, cx: &mut MutableAppContext) {
+    vim.update_active_editor(cx, |editor, cx| {
+        editor.transact(cx, |editor, cx| {
+            editor.set_clip_at_line_ends(false, cx);
+            editor.move_selections(cx, |map, selection| {
+                let original_head = selection.head();
+                motion.expand_selection(map, selection, true);
+                selection.goal = SelectionGoal::Column(original_head.column());
+            });
+            editor.insert(&"", cx);
+
+            // Fixup cursor position after the deletion
+            editor.set_clip_at_line_ends(true, cx);
+            editor.move_cursors(cx, |map, mut cursor, goal| {
+                if motion.linewise() {
+                    if let SelectionGoal::Column(column) = goal {
+                        *cursor.column_mut() = column
+                    }
+                }
+
+                (map.clip_point(cursor, Bias::Left), SelectionGoal::None)
+            });
+        });
+    });
+}
+
+#[cfg(test)]
+mod test {
+    use indoc::indoc;
+
+    use crate::vim_test_context::VimTestContext;
+
+    #[gpui::test]
+    async fn test_delete_h(cx: &mut gpui::TestAppContext) {
+        let cx = VimTestContext::new(cx, true).await;
+        let mut cx = cx.binding(["d", "h"]);
+        cx.assert("Te|st", "T|st");
+        cx.assert("T|est", "|est");
+        cx.assert("|Test", "|Test");
+        cx.assert(
+            indoc! {"
+                Test
+                |test"},
+            indoc! {"
+                Test
+                |test"},
+        );
+    }
+
+    #[gpui::test]
+    async fn test_delete_l(cx: &mut gpui::TestAppContext) {
+        let cx = VimTestContext::new(cx, true).await;
+        let mut cx = cx.binding(["d", "l"]);
+        cx.assert("|Test", "|est");
+        cx.assert("Te|st", "Te|t");
+        cx.assert("Tes|t", "Te|s");
+        cx.assert(
+            indoc! {"
+                Tes|t
+                test"},
+            indoc! {"
+                Te|s
+                test"},
+        );
+    }
+
+    #[gpui::test]
+    async fn test_delete_w(cx: &mut gpui::TestAppContext) {
+        let cx = VimTestContext::new(cx, true).await;
+        let mut cx = cx.binding(["d", "w"]);
+        cx.assert("Te|st", "T|e");
+        cx.assert("T|est test", "T|test");
+        cx.assert(
+            indoc! {"
+                Test te|st
+                test"},
+            indoc! {"
+                Test t|e
+                test"},
+        );
+        cx.assert(
+            indoc! {"
+                Test tes|t
+                test"},
+            indoc! {"
+                Test te|s
+                test"},
+        );
+        cx.assert(
+            indoc! {"
+                Test test
+                |
+                test"},
+            indoc! {"
+                Test test
+                |
+                test"},
+        );
+
+        let mut cx = cx.binding(["d", "shift-W"]);
+        cx.assert("Test te|st-test test", "Test te|test");
+    }
+
+    #[gpui::test]
+    async fn test_delete_e(cx: &mut gpui::TestAppContext) {
+        let cx = VimTestContext::new(cx, true).await;
+        let mut cx = cx.binding(["d", "e"]);
+        cx.assert("Te|st Test", "Te| Test");
+        cx.assert("T|est test", "T| test");
+        cx.assert(
+            indoc! {"
+                Test te|st
+                test"},
+            indoc! {"
+                Test t|e
+                test"},
+        );
+        cx.assert(
+            indoc! {"
+                Test tes|t
+                test"},
+            "Test te|s",
+        );
+        cx.assert(
+            indoc! {"
+                Test test
+                |
+                test"},
+            indoc! {"
+                Test test
+                |
+                test"},
+        );
+
+        let mut cx = cx.binding(["d", "shift-E"]);
+        cx.assert("Test te|st-test test", "Test te| test");
+    }
+
+    #[gpui::test]
+    async fn test_delete_b(cx: &mut gpui::TestAppContext) {
+        let cx = VimTestContext::new(cx, true).await;
+        let mut cx = cx.binding(["d", "b"]);
+        cx.assert("Te|st Test", "|st Test");
+        cx.assert("Test |test", "|test");
+        cx.assert("Test1 test2 |test3", "Test1 |test3");
+        cx.assert(
+            indoc! {"
+                Test test
+                |test"},
+            // Trailing whitespace after cursor
+            indoc! {"
+                Test| 
+                test"},
+        );
+        cx.assert(
+            indoc! {"
+                Test test
+                |
+                test"},
+            // Trailing whitespace after cursor
+            indoc! {"
+                Test| 
+                
+                test"},
+        );
+
+        let mut cx = cx.binding(["d", "shift-B"]);
+        cx.assert("Test test-test |test", "Test |test");
+    }
+
+    #[gpui::test]
+    async fn test_delete_end_of_line(cx: &mut gpui::TestAppContext) {
+        let cx = VimTestContext::new(cx, true).await;
+        let mut cx = cx.binding(["d", "shift-$"]);
+        cx.assert(
+            indoc! {"
+                The q|uick
+                brown fox"},
+            indoc! {"
+                The |q
+                brown fox"},
+        );
+        cx.assert(
+            indoc! {"
+                The quick
+                |
+                brown fox"},
+            indoc! {"
+                The quick
+                |
+                brown fox"},
+        );
+    }
+
+    #[gpui::test]
+    async fn test_delete_0(cx: &mut gpui::TestAppContext) {
+        let cx = VimTestContext::new(cx, true).await;
+        let mut cx = cx.binding(["d", "0"]);
+        cx.assert(
+            indoc! {"
+                The q|uick
+                brown fox"},
+            indoc! {"
+                |uick
+                brown fox"},
+        );
+        cx.assert(
+            indoc! {"
+                The quick
+                |
+                brown fox"},
+            indoc! {"
+                The quick
+                |
+                brown fox"},
+        );
+    }
+
+    #[gpui::test]
+    async fn test_delete_k(cx: &mut gpui::TestAppContext) {
+        let cx = VimTestContext::new(cx, true).await;
+        let mut cx = cx.binding(["d", "k"]);
+        cx.assert(
+            indoc! {"
+                The quick
+                brown |fox
+                jumps over"},
+            "jumps |over",
+        );
+        cx.assert(
+            indoc! {"
+                The quick
+                brown fox
+                jumps |over"},
+            "The qu|ick",
+        );
+        cx.assert(
+            indoc! {"
+                The q|uick
+                brown fox
+                jumps over"},
+            indoc! {"
+                brown| fox
+                jumps over"},
+        );
+        cx.assert(
+            indoc! {"
+                |brown fox
+                jumps over"},
+            "|jumps over",
+        );
+    }
+
+    #[gpui::test]
+    async fn test_delete_j(cx: &mut gpui::TestAppContext) {
+        let cx = VimTestContext::new(cx, true).await;
+        let mut cx = cx.binding(["d", "j"]);
+        cx.assert(
+            indoc! {"
+                The quick
+                brown |fox
+                jumps over"},
+            "The qu|ick",
+        );
+        cx.assert(
+            indoc! {"
+                The quick
+                brown fox
+                jumps |over"},
+            indoc! {"
+                The quick
+                brown |fox"},
+        );
+        cx.assert(
+            indoc! {"
+                The q|uick
+                brown fox
+                jumps over"},
+            "jumps| over",
+        );
+        cx.assert(
+            indoc! {"
+                The quick
+                brown fox
+                |"},
+            indoc! {"
+                The quick
+                |brown fox"},
+        );
+    }
+
+    #[gpui::test]
+    async fn test_delete_end_of_document(cx: &mut gpui::TestAppContext) {
+        let cx = VimTestContext::new(cx, true).await;
+        let mut cx = cx.binding(["d", "shift-G"]);
+        cx.assert(
+            indoc! {"
+                The quick
+                brown| fox
+                jumps over
+                the lazy"},
+            "The q|uick",
+        );
+        cx.assert(
+            indoc! {"
+                The quick
+                brown| fox
+                jumps over
+                the lazy"},
+            "The q|uick",
+        );
+        cx.assert(
+            indoc! {"
+                The quick
+                brown fox
+                jumps over
+                the l|azy"},
+            indoc! {"
+                The quick
+                brown fox
+                jumps| over"},
+        );
+        cx.assert(
+            indoc! {"
+                The quick
+                brown fox
+                jumps over
+                |"},
+            indoc! {"
+                The quick
+                brown fox
+                |jumps over"},
+        );
+    }
+
+    #[gpui::test]
+    async fn test_delete_gg(cx: &mut gpui::TestAppContext) {
+        let cx = VimTestContext::new(cx, true).await;
+        let mut cx = cx.binding(["d", "g", "g"]);
+        cx.assert(
+            indoc! {"
+                The quick
+                brown| fox
+                jumps over
+                the lazy"},
+            indoc! {"
+                jumps| over
+                the lazy"},
+        );
+        cx.assert(
+            indoc! {"
+                The quick
+                brown fox
+                jumps over
+                the l|azy"},
+            "|",
+        );
+        cx.assert(
+            indoc! {"
+                The q|uick
+                brown fox
+                jumps over
+                the lazy"},
+            indoc! {"
+                brown| fox
+                jumps over
+                the lazy"},
+        );
+        cx.assert(
+            indoc! {"
+                |
+                brown fox
+                jumps over
+                the lazy"},
+            indoc! {"
+                |brown fox
+                jumps over
+                the lazy"},
+        );
+    }
+}

crates/vim/src/vim.rs 🔗

@@ -1,10 +1,11 @@
+#[cfg(test)]
+mod vim_test_context;
+
 mod editor_events;
 mod insert;
 mod motion;
 mod normal;
 mod state;
-#[cfg(test)]
-mod vim_test_context;
 
 use collections::HashMap;
 use editor::{CursorShape, Editor};
@@ -25,6 +26,7 @@ impl_actions!(vim, [SwitchMode, PushOperator]);
 
 pub fn init(cx: &mut MutableAppContext) {
     editor_events::init(cx);
+    normal::init(cx);
     insert::init(cx);
     motion::init(cx);
 
@@ -142,14 +144,14 @@ mod test {
 
     #[gpui::test]
     async fn test_initially_disabled(cx: &mut gpui::TestAppContext) {
-        let mut cx = VimTestContext::new(cx, false, "").await;
+        let mut cx = VimTestContext::new(cx, false).await;
         cx.simulate_keystrokes(["h", "j", "k", "l"]);
         cx.assert_editor_state("hjkl|");
     }
 
     #[gpui::test]
     async fn test_toggle_through_settings(cx: &mut gpui::TestAppContext) {
-        let mut cx = VimTestContext::new(cx, true, "").await;
+        let mut cx = VimTestContext::new(cx, true).await;
 
         cx.simulate_keystroke("i");
         assert_eq!(cx.mode(), Mode::Insert);

crates/vim/src/vim_test_context.rs 🔗

@@ -15,11 +15,7 @@ pub struct VimTestContext<'a> {
 }
 
 impl<'a> VimTestContext<'a> {
-    pub async fn new(
-        cx: &'a mut gpui::TestAppContext,
-        enabled: bool,
-        initial_editor_text: &str,
-    ) -> VimTestContext<'a> {
+    pub async fn new(cx: &'a mut gpui::TestAppContext, enabled: bool) -> VimTestContext<'a> {
         cx.update(|cx| {
             editor::init(cx);
             crate::init(cx);
@@ -38,10 +34,7 @@ impl<'a> VimTestContext<'a> {
         params
             .fs
             .as_fake()
-            .insert_tree(
-                "/root",
-                json!({ "dir": { "test.txt": initial_editor_text } }),
-            )
+            .insert_tree("/root", json!({ "dir": { "test.txt": "" } }))
             .await;
 
         let (window_id, workspace) = cx.add_window(|cx| Workspace::new(&params, cx));
@@ -202,6 +195,14 @@ impl<'a> VimTestContext<'a> {
         assert_eq!(self.mode(), mode_after);
         assert_eq!(self.active_operator(), None);
     }
+
+    pub fn binding<const COUNT: usize>(
+        mut self,
+        keystrokes: [&'static str; COUNT],
+    ) -> VimBindingTestContext<'a, COUNT> {
+        let mode = self.mode();
+        VimBindingTestContext::new(keystrokes, mode, mode, self)
+    }
 }
 
 impl<'a> Deref for VimTestContext<'a> {
@@ -211,3 +212,61 @@ impl<'a> Deref for VimTestContext<'a> {
         self.cx
     }
 }
+
+pub struct VimBindingTestContext<'a, const COUNT: usize> {
+    cx: VimTestContext<'a>,
+    keystrokes_under_test: [&'static str; COUNT],
+    initial_mode: Mode,
+    mode_after: Mode,
+}
+
+impl<'a, const COUNT: usize> VimBindingTestContext<'a, COUNT> {
+    pub fn new(
+        keystrokes_under_test: [&'static str; COUNT],
+        initial_mode: Mode,
+        mode_after: Mode,
+        cx: VimTestContext<'a>,
+    ) -> Self {
+        Self {
+            cx,
+            keystrokes_under_test,
+            initial_mode,
+            mode_after,
+        }
+    }
+
+    pub fn binding<const NEW_COUNT: usize>(
+        self,
+        keystrokes_under_test: [&'static str; NEW_COUNT],
+    ) -> VimBindingTestContext<'a, NEW_COUNT> {
+        VimBindingTestContext {
+            keystrokes_under_test,
+            cx: self.cx,
+            initial_mode: self.initial_mode,
+            mode_after: self.mode_after,
+        }
+    }
+
+    pub fn mode_after(mut self, mode_after: Mode) -> Self {
+        self.mode_after = mode_after;
+        self
+    }
+
+    pub fn assert(&mut self, initial_state: &str, state_after: &str) {
+        self.cx.assert_binding(
+            self.keystrokes_under_test,
+            initial_state,
+            self.initial_mode,
+            state_after,
+            self.mode_after,
+        )
+    }
+}
+
+impl<'a, const COUNT: usize> Deref for VimBindingTestContext<'a, COUNT> {
+    type Target = VimTestContext<'a>;
+
+    fn deref(&self) -> &Self::Target {
+        &self.cx
+    }
+}

crates/workspace/src/workspace.rs 🔗

@@ -1297,7 +1297,7 @@ impl Workspace {
             if project.is_local() {
                 if project.is_shared() {
                     project.unshare(cx);
-                } else {
+                } else if project.can_share(cx) {
                     project.share(cx).detach();
                 }
             }
@@ -1475,28 +1475,38 @@ impl Workspace {
     }
 
     fn render_titlebar(&self, theme: &Theme, cx: &mut RenderContext<Self>) -> ElementBox {
+        let mut worktree_root_names = String::new();
+        {
+            let mut worktrees = self.project.read(cx).visible_worktrees(cx).peekable();
+            while let Some(worktree) = worktrees.next() {
+                worktree_root_names.push_str(worktree.read(cx).root_name());
+                if worktrees.peek().is_some() {
+                    worktree_root_names.push_str(", ");
+                }
+            }
+        }
+
         ConstrainedBox::new(
             Container::new(
                 Stack::new()
                     .with_child(
-                        Align::new(
-                            Label::new("zed".into(), theme.workspace.titlebar.title.clone())
-                                .boxed(),
-                        )
-                        .boxed(),
+                        Label::new(worktree_root_names, theme.workspace.titlebar.title.clone())
+                            .aligned()
+                            .left()
+                            .boxed(),
                     )
                     .with_child(
                         Align::new(
                             Flex::row()
-                                .with_children(self.render_share_icon(theme, cx))
                                 .with_children(self.render_collaborators(theme, cx))
-                                .with_child(self.render_current_user(
+                                .with_children(self.render_current_user(
                                     self.user_store.read(cx).current_user().as_ref(),
                                     self.project.read(cx).replica_id(),
                                     theme,
                                     cx,
                                 ))
                                 .with_children(self.render_connection_status(cx))
+                                .with_children(self.render_share_icon(theme, cx))
                                 .boxed(),
                         )
                         .right()
@@ -1540,25 +1550,30 @@ impl Workspace {
         replica_id: ReplicaId,
         theme: &Theme,
         cx: &mut RenderContext<Self>,
-    ) -> ElementBox {
+    ) -> Option<ElementBox> {
+        let status = *self.client.status().borrow();
         if let Some(avatar) = user.and_then(|user| user.avatar.clone()) {
-            self.render_avatar(avatar, replica_id, None, theme, cx)
+            Some(self.render_avatar(avatar, replica_id, None, theme, cx))
+        } else if matches!(status, client::Status::UpgradeRequired) {
+            None
         } else {
-            MouseEventHandler::new::<Authenticate, _, _>(0, cx, |state, _| {
-                let style = if state.hovered {
-                    &theme.workspace.titlebar.hovered_sign_in_prompt
-                } else {
-                    &theme.workspace.titlebar.sign_in_prompt
-                };
-                Label::new("Sign in".to_string(), style.text.clone())
-                    .contained()
-                    .with_style(style.container)
-                    .boxed()
-            })
-            .on_click(|cx| cx.dispatch_action(Authenticate))
-            .with_cursor_style(CursorStyle::PointingHand)
-            .aligned()
-            .boxed()
+            Some(
+                MouseEventHandler::new::<Authenticate, _, _>(0, cx, |state, _| {
+                    let style = if state.hovered {
+                        &theme.workspace.titlebar.hovered_sign_in_prompt
+                    } else {
+                        &theme.workspace.titlebar.sign_in_prompt
+                    };
+                    Label::new("Sign in".to_string(), style.text.clone())
+                        .contained()
+                        .with_style(style.container)
+                        .boxed()
+                })
+                .on_click(|cx| cx.dispatch_action(Authenticate))
+                .with_cursor_style(CursorStyle::PointingHand)
+                .aligned()
+                .boxed(),
+            )
         }
     }
 
@@ -1598,6 +1613,8 @@ impl Workspace {
             )
             .constrained()
             .with_width(theme.workspace.right_sidebar.width)
+            .contained()
+            .with_margin_left(2.)
             .boxed();
 
         if let Some(peer_id) = peer_id {
@@ -1611,22 +1628,39 @@ impl Workspace {
     }
 
     fn render_share_icon(&self, theme: &Theme, cx: &mut RenderContext<Self>) -> Option<ElementBox> {
-        if self.project().read(cx).is_local() && self.client.user_id().is_some() {
-            let color = if self.project().read(cx).is_shared() {
-                theme.workspace.titlebar.share_icon_active_color
-            } else {
-                theme.workspace.titlebar.share_icon_color
-            };
+        if self.project().read(cx).is_local()
+            && self.client.user_id().is_some()
+            && self.project().read(cx).can_share(cx)
+        {
             Some(
-                MouseEventHandler::new::<ToggleShare, _, _>(0, cx, |_, _| {
-                    Align::new(
-                        Svg::new("icons/broadcast-24.svg")
-                            .with_color(color)
-                            .constrained()
-                            .with_width(24.)
-                            .boxed(),
-                    )
-                    .boxed()
+                MouseEventHandler::new::<ToggleShare, _, _>(0, cx, |state, cx| {
+                    let style = if self.project().read(cx).is_shared() {
+                        if state.hovered {
+                            &theme.workspace.titlebar.hovered_active_share_icon
+                        } else {
+                            &theme.workspace.titlebar.active_share_icon
+                        }
+                    } else {
+                        if state.hovered {
+                            &theme.workspace.titlebar.hovered_share_icon
+                        } else {
+                            &theme.workspace.titlebar.share_icon
+                        }
+                    };
+                    Svg::new("icons/share.svg")
+                        .with_color(style.color)
+                        .constrained()
+                        .with_height(14.)
+                        .aligned()
+                        .contained()
+                        .with_style(style.container)
+                        .constrained()
+                        .with_width(24.)
+                        .aligned()
+                        .constrained()
+                        .with_width(theme.workspace.right_sidebar.width)
+                        .aligned()
+                        .boxed()
                 })
                 .with_cursor_style(CursorStyle::PointingHand)
                 .on_click(|cx| cx.dispatch_action(ToggleShare))
@@ -1983,7 +2017,14 @@ impl View for Workspace {
                                 content.add_child(self.right_sidebar.render(&theme, cx));
                                 content.boxed()
                             })
-                            .with_children(self.modal.as_ref().map(|m| ChildView::new(m).boxed()))
+                            .with_children(self.modal.as_ref().map(|m| {
+                                ChildView::new(m)
+                                    .contained()
+                                    .with_style(theme.workspace.modal)
+                                    .aligned()
+                                    .top()
+                                    .boxed()
+                            }))
                             .flex(1.0, true)
                             .boxed(),
                     )

crates/zed/Cargo.toml 🔗

@@ -3,7 +3,7 @@ authors = ["Nathan Sobo <nathansobo@gmail.com>"]
 description = "The fast, collaborative code editor."
 edition = "2021"
 name = "zed"
-version = "0.29.0"
+version = "0.30.0"
 
 [lib]
 name = "zed"

crates/zed/src/languages.rs 🔗

@@ -63,7 +63,7 @@ pub fn build_language_registry(login_shell_env_loaded: Task<()>) -> LanguageRegi
     languages
 }
 
-fn language(
+pub(crate) fn language(
     name: &str,
     grammar: tree_sitter::Language,
     lsp_adapter: Option<Arc<dyn LspAdapter>>,

crates/zed/src/languages/rust/highlights.scm 🔗

@@ -34,6 +34,20 @@
 ((identifier) @constant
  (#match? @constant "^[A-Z][A-Z\\d_]+$"))
 
+[
+  "("
+  ")"
+  "{"
+  "}"
+  "["
+  "]"
+] @punctuation.bracket
+
+(_
+  .
+  "<" @punctuation.bracket
+  ">" @punctuation.bracket)
+
 [
   "as"
   "async"

crates/zed/src/languages/toml/highlights.scm 🔗

@@ -20,14 +20,18 @@
 ; Punctuation
 ;------------
 
-"." @punctuation.delimiter
-"," @punctuation.delimiter
+[
+  "."
+  ","
+] @punctuation.delimiter
 
 "=" @operator
 
-"[" @punctuation.bracket
-"]" @punctuation.bracket
-"[[" @punctuation.bracket
-"]]" @punctuation.bracket
-"{" @punctuation.bracket
-"}" @punctuation.bracket
+[
+  "["
+  "]"
+  "[["
+  "]]"
+  "{"
+  "}"
+]  @punctuation.bracket

crates/zed/src/languages/typescript.rs 🔗

@@ -144,3 +144,54 @@ impl LspAdapter for TypeScriptLspAdapter {
         }))
     }
 }
+
+#[cfg(test)]
+mod tests {
+    use std::sync::Arc;
+
+    use gpui::MutableAppContext;
+    use unindent::Unindent;
+
+    #[gpui::test]
+    fn test_outline(cx: &mut MutableAppContext) {
+        let language = crate::languages::language(
+            "typescript",
+            tree_sitter_typescript::language_typescript(),
+            None,
+        );
+
+        let text = r#"
+            function a() {
+              // local variables are omitted
+              let a1 = 1;
+              // all functions are included
+              async function a2() {}
+            }
+            // top-level variables are included
+            let b: C
+            function getB() {}
+            // exported variables are included
+            export const d = e;
+        "#
+        .unindent();
+
+        let buffer = cx.add_model(|cx| {
+            language::Buffer::new(0, text, cx).with_language(Arc::new(language), cx)
+        });
+        let outline = buffer.read(cx).snapshot().outline(None).unwrap();
+        assert_eq!(
+            outline
+                .items
+                .iter()
+                .map(|item| (item.text.as_str(), item.depth))
+                .collect::<Vec<_>>(),
+            &[
+                ("function a ( )", 0),
+                ("async function a2 ( )", 1),
+                ("let b", 0),
+                ("function getB ( )", 0),
+                ("const d", 0),
+            ]
+        );
+    }
+}

crates/zed/src/languages/typescript/outline.scm 🔗

@@ -6,6 +6,10 @@
     "enum" @context
     name: (_) @name) @item
 
+(type_alias_declaration
+    "type" @context
+    name: (_) @name) @item
+
 (function_declaration
     "async"? @context
     "function" @context
@@ -18,6 +22,12 @@
     "interface" @context
     name: (_) @name) @item
 
+(export_statement
+    (lexical_declaration
+        ["let" "const"] @context
+        (variable_declarator
+            name: (_) @name) @item))
+
 (program
     (lexical_declaration
         ["let" "const"] @context

crates/zed/src/main.rs 🔗

@@ -169,11 +169,19 @@ fn main() {
         .detach();
 
         languages.set_language_server_download_dir(zed::ROOT_PATH.clone());
-        languages.set_theme(&settings.theme.editor.syntax);
+        let languages = Arc::new(languages);
+
+        cx.observe_global::<Settings, _>({
+            let languages = languages.clone();
+            move |settings, _| {
+                languages.set_theme(&settings.theme.editor.syntax);
+            }
+        })
+        .detach();
         cx.set_global(settings);
 
         let app_state = Arc::new(AppState {
-            languages: Arc::new(languages),
+            languages,
             themes,
             channel_list,
             client,

styles/dist/solarized-dark.json 🔗

@@ -0,0 +1,567 @@
+{
+  "meta": {
+    "themeName": "solarized-dark"
+  },
+  "text": {
+    "primary": {
+      "value": "#eee8d5",
+      "type": "color"
+    },
+    "secondary": {
+      "value": "#93a1a1",
+      "type": "color"
+    },
+    "muted": {
+      "value": "#93a1a1",
+      "type": "color"
+    },
+    "placeholder": {
+      "value": "#839496",
+      "type": "color"
+    },
+    "active": {
+      "value": "#fdf6e3",
+      "type": "color"
+    },
+    "feature": {
+      "value": "#268bd2",
+      "type": "color"
+    },
+    "ok": {
+      "value": "#859900",
+      "type": "color"
+    },
+    "error": {
+      "value": "#dc322f",
+      "type": "color"
+    },
+    "warning": {
+      "value": "#b58900",
+      "type": "color"
+    },
+    "info": {
+      "value": "#268bd2",
+      "type": "color"
+    }
+  },
+  "icon": {
+    "primary": {
+      "value": "#eee8d5",
+      "type": "color"
+    },
+    "secondary": {
+      "value": "#93a1a1",
+      "type": "color"
+    },
+    "muted": {
+      "value": "#93a1a1",
+      "type": "color"
+    },
+    "placeholder": {
+      "value": "#839496",
+      "type": "color"
+    },
+    "active": {
+      "value": "#fdf6e3",
+      "type": "color"
+    },
+    "feature": {
+      "value": "#268bd2",
+      "type": "color"
+    },
+    "ok": {
+      "value": "#859900",
+      "type": "color"
+    },
+    "error": {
+      "value": "#dc322f",
+      "type": "color"
+    },
+    "warning": {
+      "value": "#b58900",
+      "type": "color"
+    },
+    "info": {
+      "value": "#268bd2",
+      "type": "color"
+    }
+  },
+  "background": {
+    "100": {
+      "base": {
+        "value": "#073642",
+        "type": "color"
+      },
+      "hovered": {
+        "value": "#586e75",
+        "type": "color"
+      },
+      "active": {
+        "value": "#586e75",
+        "type": "color"
+      },
+      "focused": {
+        "value": "#586e75",
+        "type": "color"
+      }
+    },
+    "300": {
+      "base": {
+        "value": "#073642",
+        "type": "color"
+      },
+      "hovered": {
+        "value": "#586e75",
+        "type": "color"
+      },
+      "active": {
+        "value": "#586e75",
+        "type": "color"
+      },
+      "focused": {
+        "value": "#586e75",
+        "type": "color"
+      }
+    },
+    "500": {
+      "base": {
+        "value": "#002b36",
+        "type": "color"
+      },
+      "hovered": {
+        "value": "#073642",
+        "type": "color"
+      },
+      "active": {
+        "value": "#073642",
+        "type": "color"
+      },
+      "focused": {
+        "value": "#073642",
+        "type": "color"
+      }
+    },
+    "on300": {
+      "base": {
+        "value": "#002b36",
+        "type": "color"
+      },
+      "hovered": {
+        "value": "#073642",
+        "type": "color"
+      },
+      "active": {
+        "value": "#073642",
+        "type": "color"
+      },
+      "focused": {
+        "value": "#073642",
+        "type": "color"
+      }
+    },
+    "on500": {
+      "base": {
+        "value": "#073642",
+        "type": "color"
+      },
+      "hovered": {
+        "value": "#586e75",
+        "type": "color"
+      },
+      "active": {
+        "value": "#586e75",
+        "type": "color"
+      },
+      "focused": {
+        "value": "#586e75",
+        "type": "color"
+      }
+    },
+    "ok": {
+      "base": {
+        "value": "#859900",
+        "type": "color"
+      },
+      "hovered": {
+        "value": "#859900",
+        "type": "color"
+      },
+      "active": {
+        "value": "#859900",
+        "type": "color"
+      },
+      "focused": {
+        "value": "#859900",
+        "type": "color"
+      }
+    },
+    "error": {
+      "base": {
+        "value": "#dc322f",
+        "type": "color"
+      },
+      "hovered": {
+        "value": "#dc322f",
+        "type": "color"
+      },
+      "active": {
+        "value": "#dc322f",
+        "type": "color"
+      },
+      "focused": {
+        "value": "#dc322f",
+        "type": "color"
+      }
+    },
+    "warning": {
+      "base": {
+        "value": "#b58900",
+        "type": "color"
+      },
+      "hovered": {
+        "value": "#b58900",
+        "type": "color"
+      },
+      "active": {
+        "value": "#b58900",
+        "type": "color"
+      },
+      "focused": {
+        "value": "#b58900",
+        "type": "color"
+      }
+    },
+    "info": {
+      "base": {
+        "value": "#268bd2",
+        "type": "color"
+      },
+      "hovered": {
+        "value": "#268bd2",
+        "type": "color"
+      },
+      "active": {
+        "value": "#268bd2",
+        "type": "color"
+      },
+      "focused": {
+        "value": "#268bd2",
+        "type": "color"
+      }
+    }
+  },
+  "border": {
+    "primary": {
+      "value": "#002b36",
+      "type": "color"
+    },
+    "secondary": {
+      "value": "#073642",
+      "type": "color"
+    },
+    "muted": {
+      "value": "#586e75",
+      "type": "color"
+    },
+    "focused": {
+      "value": "#586e75",
+      "type": "color"
+    },
+    "active": {
+      "value": "#586e75",
+      "type": "color"
+    },
+    "ok": {
+      "value": "#859900",
+      "type": "color"
+    },
+    "error": {
+      "value": "#dc322f",
+      "type": "color"
+    },
+    "warning": {
+      "value": "#b58900",
+      "type": "color"
+    },
+    "info": {
+      "value": "#268bd2",
+      "type": "color"
+    }
+  },
+  "editor": {
+    "background": {
+      "value": "#002b36",
+      "type": "color"
+    },
+    "indent_guide": {
+      "value": "#586e75",
+      "type": "color"
+    },
+    "indent_guide_active": {
+      "value": "#073642",
+      "type": "color"
+    },
+    "line": {
+      "active": {
+        "value": "#fdf6e312",
+        "type": "color"
+      },
+      "highlighted": {
+        "value": "#fdf6e31f",
+        "type": "color"
+      },
+      "inserted": {
+        "value": "#859900",
+        "type": "color"
+      },
+      "deleted": {
+        "value": "#dc322f",
+        "type": "color"
+      },
+      "modified": {
+        "value": "#268bd2",
+        "type": "color"
+      }
+    },
+    "highlight": {
+      "selection": {
+        "value": "#268bd23d",
+        "type": "color"
+      },
+      "occurrence": {
+        "value": "#657b831f",
+        "type": "color"
+      },
+      "activeOccurrence": {
+        "value": "#657b8329",
+        "type": "color"
+      },
+      "matchingBracket": {
+        "value": "#073642",
+        "type": "color"
+      },
+      "match": {
+        "value": "#6c71c480",
+        "type": "color"
+      },
+      "activeMatch": {
+        "value": "#6c71c4b3",
+        "type": "color"
+      },
+      "related": {
+        "value": "#073642",
+        "type": "color"
+      }
+    },
+    "gutter": {
+      "primary": {
+        "value": "#839496",
+        "type": "color"
+      },
+      "active": {
+        "value": "#fdf6e3",
+        "type": "color"
+      }
+    }
+  },
+  "syntax": {
+    "primary": {
+      "value": "#fdf6e3",
+      "type": "color"
+    },
+    "comment": {
+      "value": "#eee8d5",
+      "type": "color"
+    },
+    "keyword": {
+      "value": "#268bd2",
+      "type": "color"
+    },
+    "function": {
+      "value": "#b58900",
+      "type": "color"
+    },
+    "type": {
+      "value": "#2aa198",
+      "type": "color"
+    },
+    "variant": {
+      "value": "#268bd2",
+      "type": "color"
+    },
+    "property": {
+      "value": "#268bd2",
+      "type": "color"
+    },
+    "enum": {
+      "value": "#cb4b16",
+      "type": "color"
+    },
+    "operator": {
+      "value": "#cb4b16",
+      "type": "color"
+    },
+    "string": {
+      "value": "#cb4b16",
+      "type": "color"
+    },
+    "number": {
+      "value": "#859900",
+      "type": "color"
+    },
+    "boolean": {
+      "value": "#859900",
+      "type": "color"
+    }
+  },
+  "player": {
+    "1": {
+      "baseColor": {
+        "value": "#268bd2",
+        "type": "color"
+      },
+      "cursorColor": {
+        "value": "#268bd2",
+        "type": "color"
+      },
+      "selectionColor": {
+        "value": "#268bd23d",
+        "type": "color"
+      },
+      "borderColor": {
+        "value": "#268bd2cc",
+        "type": "color"
+      }
+    },
+    "2": {
+      "baseColor": {
+        "value": "#859900",
+        "type": "color"
+      },
+      "cursorColor": {
+        "value": "#859900",
+        "type": "color"
+      },
+      "selectionColor": {
+        "value": "#8599003d",
+        "type": "color"
+      },
+      "borderColor": {
+        "value": "#859900cc",
+        "type": "color"
+      }
+    },
+    "3": {
+      "baseColor": {
+        "value": "#d33682",
+        "type": "color"
+      },
+      "cursorColor": {
+        "value": "#d33682",
+        "type": "color"
+      },
+      "selectionColor": {
+        "value": "#d336823d",
+        "type": "color"
+      },
+      "borderColor": {
+        "value": "#d33682cc",
+        "type": "color"
+      }
+    },
+    "4": {
+      "baseColor": {
+        "value": "#cb4b16",
+        "type": "color"
+      },
+      "cursorColor": {
+        "value": "#cb4b16",
+        "type": "color"
+      },
+      "selectionColor": {
+        "value": "#cb4b163d",
+        "type": "color"
+      },
+      "borderColor": {
+        "value": "#cb4b16cc",
+        "type": "color"
+      }
+    },
+    "5": {
+      "baseColor": {
+        "value": "#6c71c4",
+        "type": "color"
+      },
+      "cursorColor": {
+        "value": "#6c71c4",
+        "type": "color"
+      },
+      "selectionColor": {
+        "value": "#6c71c43d",
+        "type": "color"
+      },
+      "borderColor": {
+        "value": "#6c71c4cc",
+        "type": "color"
+      }
+    },
+    "6": {
+      "baseColor": {
+        "value": "#2aa198",
+        "type": "color"
+      },
+      "cursorColor": {
+        "value": "#2aa198",
+        "type": "color"
+      },
+      "selectionColor": {
+        "value": "#2aa1983d",
+        "type": "color"
+      },
+      "borderColor": {
+        "value": "#2aa198cc",
+        "type": "color"
+      }
+    },
+    "7": {
+      "baseColor": {
+        "value": "#dc322f",
+        "type": "color"
+      },
+      "cursorColor": {
+        "value": "#dc322f",
+        "type": "color"
+      },
+      "selectionColor": {
+        "value": "#dc322f3d",
+        "type": "color"
+      },
+      "borderColor": {
+        "value": "#dc322fcc",
+        "type": "color"
+      }
+    },
+    "8": {
+      "baseColor": {
+        "value": "#b58900",
+        "type": "color"
+      },
+      "cursorColor": {
+        "value": "#b58900",
+        "type": "color"
+      },
+      "selectionColor": {
+        "value": "#b589003d",
+        "type": "color"
+      },
+      "borderColor": {
+        "value": "#b58900cc",
+        "type": "color"
+      }
+    }
+  },
+  "shadowAlpha": {
+    "value": 0.32,
+    "type": "number"
+  }
+}

styles/dist/solarized-light.json 🔗

@@ -0,0 +1,567 @@
+{
+  "meta": {
+    "themeName": "solarized-light"
+  },
+  "text": {
+    "primary": {
+      "value": "#073642",
+      "type": "color"
+    },
+    "secondary": {
+      "value": "#586e75",
+      "type": "color"
+    },
+    "muted": {
+      "value": "#586e75",
+      "type": "color"
+    },
+    "placeholder": {
+      "value": "#657b83",
+      "type": "color"
+    },
+    "active": {
+      "value": "#002b36",
+      "type": "color"
+    },
+    "feature": {
+      "value": "#268bd2",
+      "type": "color"
+    },
+    "ok": {
+      "value": "#859900",
+      "type": "color"
+    },
+    "error": {
+      "value": "#dc322f",
+      "type": "color"
+    },
+    "warning": {
+      "value": "#b58900",
+      "type": "color"
+    },
+    "info": {
+      "value": "#268bd2",
+      "type": "color"
+    }
+  },
+  "icon": {
+    "primary": {
+      "value": "#073642",
+      "type": "color"
+    },
+    "secondary": {
+      "value": "#586e75",
+      "type": "color"
+    },
+    "muted": {
+      "value": "#586e75",
+      "type": "color"
+    },
+    "placeholder": {
+      "value": "#657b83",
+      "type": "color"
+    },
+    "active": {
+      "value": "#002b36",
+      "type": "color"
+    },
+    "feature": {
+      "value": "#268bd2",
+      "type": "color"
+    },
+    "ok": {
+      "value": "#859900",
+      "type": "color"
+    },
+    "error": {
+      "value": "#dc322f",
+      "type": "color"
+    },
+    "warning": {
+      "value": "#b58900",
+      "type": "color"
+    },
+    "info": {
+      "value": "#268bd2",
+      "type": "color"
+    }
+  },
+  "background": {
+    "100": {
+      "base": {
+        "value": "#eee8d5",
+        "type": "color"
+      },
+      "hovered": {
+        "value": "#93a1a1",
+        "type": "color"
+      },
+      "active": {
+        "value": "#93a1a1",
+        "type": "color"
+      },
+      "focused": {
+        "value": "#93a1a1",
+        "type": "color"
+      }
+    },
+    "300": {
+      "base": {
+        "value": "#eee8d5",
+        "type": "color"
+      },
+      "hovered": {
+        "value": "#93a1a1",
+        "type": "color"
+      },
+      "active": {
+        "value": "#93a1a1",
+        "type": "color"
+      },
+      "focused": {
+        "value": "#93a1a1",
+        "type": "color"
+      }
+    },
+    "500": {
+      "base": {
+        "value": "#fdf6e3",
+        "type": "color"
+      },
+      "hovered": {
+        "value": "#eee8d5",
+        "type": "color"
+      },
+      "active": {
+        "value": "#eee8d5",
+        "type": "color"
+      },
+      "focused": {
+        "value": "#eee8d5",
+        "type": "color"
+      }
+    },
+    "on300": {
+      "base": {
+        "value": "#fdf6e3",
+        "type": "color"
+      },
+      "hovered": {
+        "value": "#eee8d5",
+        "type": "color"
+      },
+      "active": {
+        "value": "#eee8d5",
+        "type": "color"
+      },
+      "focused": {
+        "value": "#eee8d5",
+        "type": "color"
+      }
+    },
+    "on500": {
+      "base": {
+        "value": "#eee8d5",
+        "type": "color"
+      },
+      "hovered": {
+        "value": "#93a1a1",
+        "type": "color"
+      },
+      "active": {
+        "value": "#93a1a1",
+        "type": "color"
+      },
+      "focused": {
+        "value": "#93a1a1",
+        "type": "color"
+      }
+    },
+    "ok": {
+      "base": {
+        "value": "#859900",
+        "type": "color"
+      },
+      "hovered": {
+        "value": "#859900",
+        "type": "color"
+      },
+      "active": {
+        "value": "#859900",
+        "type": "color"
+      },
+      "focused": {
+        "value": "#859900",
+        "type": "color"
+      }
+    },
+    "error": {
+      "base": {
+        "value": "#dc322f",
+        "type": "color"
+      },
+      "hovered": {
+        "value": "#dc322f",
+        "type": "color"
+      },
+      "active": {
+        "value": "#dc322f",
+        "type": "color"
+      },
+      "focused": {
+        "value": "#dc322f",
+        "type": "color"
+      }
+    },
+    "warning": {
+      "base": {
+        "value": "#b58900",
+        "type": "color"
+      },
+      "hovered": {
+        "value": "#b58900",
+        "type": "color"
+      },
+      "active": {
+        "value": "#b58900",
+        "type": "color"
+      },
+      "focused": {
+        "value": "#b58900",
+        "type": "color"
+      }
+    },
+    "info": {
+      "base": {
+        "value": "#268bd2",
+        "type": "color"
+      },
+      "hovered": {
+        "value": "#268bd2",
+        "type": "color"
+      },
+      "active": {
+        "value": "#268bd2",
+        "type": "color"
+      },
+      "focused": {
+        "value": "#268bd2",
+        "type": "color"
+      }
+    }
+  },
+  "border": {
+    "primary": {
+      "value": "#fdf6e3",
+      "type": "color"
+    },
+    "secondary": {
+      "value": "#eee8d5",
+      "type": "color"
+    },
+    "muted": {
+      "value": "#93a1a1",
+      "type": "color"
+    },
+    "focused": {
+      "value": "#93a1a1",
+      "type": "color"
+    },
+    "active": {
+      "value": "#93a1a1",
+      "type": "color"
+    },
+    "ok": {
+      "value": "#859900",
+      "type": "color"
+    },
+    "error": {
+      "value": "#dc322f",
+      "type": "color"
+    },
+    "warning": {
+      "value": "#b58900",
+      "type": "color"
+    },
+    "info": {
+      "value": "#268bd2",
+      "type": "color"
+    }
+  },
+  "editor": {
+    "background": {
+      "value": "#fdf6e3",
+      "type": "color"
+    },
+    "indent_guide": {
+      "value": "#93a1a1",
+      "type": "color"
+    },
+    "indent_guide_active": {
+      "value": "#eee8d5",
+      "type": "color"
+    },
+    "line": {
+      "active": {
+        "value": "#002b3612",
+        "type": "color"
+      },
+      "highlighted": {
+        "value": "#002b361f",
+        "type": "color"
+      },
+      "inserted": {
+        "value": "#859900",
+        "type": "color"
+      },
+      "deleted": {
+        "value": "#dc322f",
+        "type": "color"
+      },
+      "modified": {
+        "value": "#268bd2",
+        "type": "color"
+      }
+    },
+    "highlight": {
+      "selection": {
+        "value": "#268bd23d",
+        "type": "color"
+      },
+      "occurrence": {
+        "value": "#8394961f",
+        "type": "color"
+      },
+      "activeOccurrence": {
+        "value": "#83949629",
+        "type": "color"
+      },
+      "matchingBracket": {
+        "value": "#eee8d5",
+        "type": "color"
+      },
+      "match": {
+        "value": "#6c71c480",
+        "type": "color"
+      },
+      "activeMatch": {
+        "value": "#6c71c4b3",
+        "type": "color"
+      },
+      "related": {
+        "value": "#eee8d5",
+        "type": "color"
+      }
+    },
+    "gutter": {
+      "primary": {
+        "value": "#657b83",
+        "type": "color"
+      },
+      "active": {
+        "value": "#002b36",
+        "type": "color"
+      }
+    }
+  },
+  "syntax": {
+    "primary": {
+      "value": "#002b36",
+      "type": "color"
+    },
+    "comment": {
+      "value": "#073642",
+      "type": "color"
+    },
+    "keyword": {
+      "value": "#268bd2",
+      "type": "color"
+    },
+    "function": {
+      "value": "#b58900",
+      "type": "color"
+    },
+    "type": {
+      "value": "#2aa198",
+      "type": "color"
+    },
+    "variant": {
+      "value": "#268bd2",
+      "type": "color"
+    },
+    "property": {
+      "value": "#268bd2",
+      "type": "color"
+    },
+    "enum": {
+      "value": "#cb4b16",
+      "type": "color"
+    },
+    "operator": {
+      "value": "#cb4b16",
+      "type": "color"
+    },
+    "string": {
+      "value": "#cb4b16",
+      "type": "color"
+    },
+    "number": {
+      "value": "#859900",
+      "type": "color"
+    },
+    "boolean": {
+      "value": "#859900",
+      "type": "color"
+    }
+  },
+  "player": {
+    "1": {
+      "baseColor": {
+        "value": "#268bd2",
+        "type": "color"
+      },
+      "cursorColor": {
+        "value": "#268bd2",
+        "type": "color"
+      },
+      "selectionColor": {
+        "value": "#268bd23d",
+        "type": "color"
+      },
+      "borderColor": {
+        "value": "#268bd2cc",
+        "type": "color"
+      }
+    },
+    "2": {
+      "baseColor": {
+        "value": "#859900",
+        "type": "color"
+      },
+      "cursorColor": {
+        "value": "#859900",
+        "type": "color"
+      },
+      "selectionColor": {
+        "value": "#8599003d",
+        "type": "color"
+      },
+      "borderColor": {
+        "value": "#859900cc",
+        "type": "color"
+      }
+    },
+    "3": {
+      "baseColor": {
+        "value": "#d33682",
+        "type": "color"
+      },
+      "cursorColor": {
+        "value": "#d33682",
+        "type": "color"
+      },
+      "selectionColor": {
+        "value": "#d336823d",
+        "type": "color"
+      },
+      "borderColor": {
+        "value": "#d33682cc",
+        "type": "color"
+      }
+    },
+    "4": {
+      "baseColor": {
+        "value": "#cb4b16",
+        "type": "color"
+      },
+      "cursorColor": {
+        "value": "#cb4b16",
+        "type": "color"
+      },
+      "selectionColor": {
+        "value": "#cb4b163d",
+        "type": "color"
+      },
+      "borderColor": {
+        "value": "#cb4b16cc",
+        "type": "color"
+      }
+    },
+    "5": {
+      "baseColor": {
+        "value": "#6c71c4",
+        "type": "color"
+      },
+      "cursorColor": {
+        "value": "#6c71c4",
+        "type": "color"
+      },
+      "selectionColor": {
+        "value": "#6c71c43d",
+        "type": "color"
+      },
+      "borderColor": {
+        "value": "#6c71c4cc",
+        "type": "color"
+      }
+    },
+    "6": {
+      "baseColor": {
+        "value": "#2aa198",
+        "type": "color"
+      },
+      "cursorColor": {
+        "value": "#2aa198",
+        "type": "color"
+      },
+      "selectionColor": {
+        "value": "#2aa1983d",
+        "type": "color"
+      },
+      "borderColor": {
+        "value": "#2aa198cc",
+        "type": "color"
+      }
+    },
+    "7": {
+      "baseColor": {
+        "value": "#dc322f",
+        "type": "color"
+      },
+      "cursorColor": {
+        "value": "#dc322f",
+        "type": "color"
+      },
+      "selectionColor": {
+        "value": "#dc322f3d",
+        "type": "color"
+      },
+      "borderColor": {
+        "value": "#dc322fcc",
+        "type": "color"
+      }
+    },
+    "8": {
+      "baseColor": {
+        "value": "#b58900",
+        "type": "color"
+      },
+      "cursorColor": {
+        "value": "#b58900",
+        "type": "color"
+      },
+      "selectionColor": {
+        "value": "#b589003d",
+        "type": "color"
+      },
+      "borderColor": {
+        "value": "#b58900cc",
+        "type": "color"
+      }
+    }
+  },
+  "shadowAlpha": {
+    "value": 0.32,
+    "type": "number"
+  }
+}

styles/src/buildThemes.ts 🔗

@@ -1,11 +1,20 @@
 import * as fs from "fs";
 import * as path from "path";
 import app from "./styleTree/app";
+import { dark as caveDark, light as caveLight } from "./themes/cave";
 import dark from "./themes/dark";
 import light from "./themes/light";
+import { dark as solarizedDark, light as solarizedLight } from "./themes/solarized";
+import { dark as sulphurpoolDark, light as sulphurpoolLight } from "./themes/sulphurpool";
 import snakeCase from "./utils/snakeCase";
 
-const themes = [dark, light];
+const themes = [
+  dark, light,
+  caveDark, caveLight,
+  solarizedDark, solarizedLight,
+  sulphurpoolDark, sulphurpoolLight
+];
+
 for (let theme of themes) {
   let styleTree = snakeCase(app(theme));
   let styleTreeJSON = JSON.stringify(styleTree, null, 2);

styles/src/styleTree/editor.ts 🔗

@@ -37,8 +37,18 @@ export default function editor(theme: Theme) {
     };
   }
 
+  const syntax: any = {};
+  for (const syntaxKey in theme.syntax) {
+    const style = theme.syntax[syntaxKey];
+    syntax[syntaxKey] = {
+      color: style.color.value,
+      weight: style.weight.value,
+      underline: style.underline,
+      italic: style.italic,
+    };
+  }
+
   return {
-    // textColor: theme.syntax.primary.color,
     textColor: theme.syntax.primary.color.value,
     background: backgroundColor(theme, 500),
     activeLineBackground: theme.editor.line.active.value,
@@ -125,22 +135,6 @@ export default function editor(theme: Theme) {
     invalidHintDiagnostic: diagnostic(theme, "muted"),
     invalidInformationDiagnostic: diagnostic(theme, "muted"),
     invalidWarningDiagnostic: diagnostic(theme, "muted"),
-    syntax: {
-      keyword: theme.syntax.keyword.color.value,
-      function: theme.syntax.function.color.value,
-      string: theme.syntax.string.color.value,
-      type: theme.syntax.type.color.value,
-      number: theme.syntax.number.color.value,
-      comment: theme.syntax.comment.color.value,
-      property: theme.syntax.property.color.value,
-      variant: theme.syntax.variant.color.value,
-      constant: theme.syntax.constant.color.value,
-      title: { color: theme.syntax.title.color.value, weight: "bold" },
-      emphasis: theme.textColor.feature.value,
-      "emphasis.strong": { color: theme.textColor.feature.value, weight: "bold" },
-      link_uri: { color: theme.syntax.linkUrl.color.value, underline: true },
-      link_text: { color: theme.syntax.linkText.color.value, italic: true },
-      list_marker: theme.syntax.punctuation.color.value,
-    },
+    syntax,
   };
 }

styles/src/styleTree/selectorModal.ts 🔗

@@ -50,10 +50,6 @@ export default function selectorModal(theme: Theme): Object {
         top: 7,
       },
     },
-    margin: {
-      bottom: 52,
-      top: 52,
-    },
     shadow: shadow(theme),
   };
 }

styles/src/styleTree/workspace.ts 🔗

@@ -68,6 +68,10 @@ export default function workspace(theme: Theme) {
       },
     },
   };
+  const shareIcon = {
+    margin: { top: 3, bottom: 2 },
+    cornerRadius: 6,
+  };
 
   return {
     background: backgroundColor(theme, 300),
@@ -75,6 +79,13 @@ export default function workspace(theme: Theme) {
     leaderBorderWidth: 2.0,
     tab,
     activeTab,
+    modal: {
+      margin: {
+        bottom: 52,
+        top: 52,
+      },
+      cursor: "Arrow"
+    },
     leftSidebar: {
       ...sidebar,
       border: border(theme, "primary", { right: true }),
@@ -105,8 +116,9 @@ export default function workspace(theme: Theme) {
       avatarWidth: 18,
       height: 32,
       background: backgroundColor(theme, 100),
-      shareIconColor: iconColor(theme, "secondary"),
-      shareIconActiveColor: iconColor(theme, "feature"),
+      padding: {
+        left: 80,
+      },
       title: text(theme, "sans", "primary"),
       avatar: {
         cornerRadius: 10,
@@ -134,9 +146,29 @@ export default function workspace(theme: Theme) {
           right: 4,
         },
       },
+      shareIcon: {
+        ...shareIcon,
+        color: iconColor(theme, "secondary")
+      },
+      hoveredShareIcon: {
+        ...shareIcon,
+        background: backgroundColor(theme, 100, "hovered"),
+        color: iconColor(theme, "secondary"),
+      },
+      hoveredActiveShareIcon: {
+        ...shareIcon,
+        background: backgroundColor(theme, 100, "hovered"),
+        color: iconColor(theme, "active"),
+      },
+      activeShareIcon: {
+        ...shareIcon,
+        background: backgroundColor(theme, 100, "active"),
+        color: iconColor(theme, "active"),
+      },
       outdatedWarning: {
         ...text(theme, "sans", "warning"),
         size: 13,
+        margin: { right: 6 }
       },
     },
     toolbar: {

styles/src/themes/base16.ts 🔗

@@ -0,0 +1,242 @@
+import { ColorToken, fontWeights, NumberToken } from "../tokens";
+import { withOpacity } from "../utils/color";
+import Theme, { buildPlayer, Syntax } from "./theme";
+
+export interface Accents {
+  "red": ColorToken,
+  "orange": ColorToken,
+  "yellow": ColorToken,
+  "green": ColorToken,
+  "cyan": ColorToken,
+  "blue": ColorToken,
+  "violet": ColorToken,
+  "magenta": ColorToken,
+}
+
+export function createTheme(name: string, isLight: boolean, neutral: ColorToken[], accent: Accents): Theme {
+  if (isLight) {
+    neutral = [...neutral].reverse();
+  }
+  let blend = isLight ? 0.12 : 0.32;
+
+  const backgroundColor = {
+    100: {
+      base: neutral[1],
+      hovered: withOpacity(neutral[2], blend),
+      active: withOpacity(neutral[2], blend * 1.5),
+      focused: neutral[2],
+    },
+    300: {
+      base: neutral[1],
+      hovered: withOpacity(neutral[2], blend),
+      active: withOpacity(neutral[2], blend * 1.5),
+      focused: neutral[2],
+    },
+    500: {
+      base: neutral[0],
+      hovered: neutral[1],
+      active: neutral[1],
+      focused: neutral[1],
+    },
+    on300: {
+      base: neutral[0],
+      hovered: neutral[1],
+      active: neutral[1],
+      focused: neutral[1],
+    },
+    on500: {
+      base: neutral[1],
+      hovered: neutral[3],
+      active: neutral[3],
+      focused: neutral[3],
+    },
+    ok: {
+      base: accent.green,
+      hovered: accent.green,
+      active: accent.green,
+      focused: accent.green,
+    },
+    error: {
+      base: accent.red,
+      hovered: accent.red,
+      active: accent.red,
+      focused: accent.red,
+    },
+    warning: {
+      base: accent.yellow,
+      hovered: accent.yellow,
+      active: accent.yellow,
+      focused: accent.yellow,
+    },
+    info: {
+      base: accent.blue,
+      hovered: accent.blue,
+      active: accent.blue,
+      focused: accent.blue,
+    },
+  };
+
+  const borderColor = {
+    primary: neutral[0],
+    secondary: neutral[1],
+    muted: neutral[3],
+    focused: neutral[3],
+    active: neutral[3],
+    ok: accent.green,
+    error: accent.red,
+    warning: accent.yellow,
+    info: accent.blue,
+  };
+
+  const textColor = {
+    primary: neutral[6],
+    secondary: neutral[5],
+    muted: neutral[5],
+    placeholder: neutral[4],
+    active: neutral[7],
+    feature: accent.blue,
+    ok: accent.green,
+    error: accent.red,
+    warning: accent.yellow,
+    info: accent.blue,
+  };
+
+  const player = {
+    1: buildPlayer(accent.blue),
+    2: buildPlayer(accent.green),
+    3: buildPlayer(accent.magenta),
+    4: buildPlayer(accent.orange),
+    5: buildPlayer(accent.violet),
+    6: buildPlayer(accent.cyan),
+    7: buildPlayer(accent.red),
+    8: buildPlayer(accent.yellow),
+  };
+
+  const editor = {
+    background: backgroundColor[500].base,
+    indent_guide: borderColor.muted,
+    indent_guide_active: borderColor.secondary,
+    line: {
+      active: withOpacity(neutral[7], 0.07),
+      highlighted: withOpacity(neutral[7], 0.12),
+      inserted: backgroundColor.ok.active,
+      deleted: backgroundColor.error.active,
+      modified: backgroundColor.info.active,
+    },
+    highlight: {
+      selection: player[1].selectionColor,
+      occurrence: withOpacity(neutral[0], 0.12),
+      activeOccurrence: withOpacity(neutral[0], 0.16),
+      matchingBracket: backgroundColor[500].active,
+      match: withOpacity(accent.violet, 0.5),
+      activeMatch: withOpacity(accent.violet, 0.7),
+      related: backgroundColor[500].focused,
+    },
+    gutter: {
+      primary: textColor.placeholder,
+      active: textColor.active,
+    },
+  };
+
+  const syntax: Syntax = {
+    primary: {
+      color: neutral[7],
+      weight: fontWeights.normal,
+    },
+    comment: {
+      color: neutral[5],
+      weight: fontWeights.normal,
+    },
+    punctuation: {
+      color: neutral[5],
+      weight: fontWeights.normal,
+    },
+    constant: {
+      color: neutral[4],
+      weight: fontWeights.normal,
+    },
+    keyword: {
+      color: accent.blue,
+      weight: fontWeights.normal,
+    },
+    function: {
+      color: accent.yellow,
+      weight: fontWeights.normal,
+    },
+    type: {
+      color: accent.cyan,
+      weight: fontWeights.normal,
+    },
+    variant: {
+      color: accent.blue,
+      weight: fontWeights.normal,
+    },
+    property: {
+      color: accent.blue,
+      weight: fontWeights.normal,
+    },
+    enum: {
+      color: accent.orange,
+      weight: fontWeights.normal,
+    },
+    operator: {
+      color: accent.orange,
+      weight: fontWeights.normal,
+    },
+    string: {
+      color: accent.orange,
+      weight: fontWeights.normal,
+    },
+    number: {
+      color: accent.green,
+      weight: fontWeights.normal,
+    },
+    boolean: {
+      color: accent.green,
+      weight: fontWeights.normal,
+    },
+    predictive: {
+      color: textColor.muted,
+      weight: fontWeights.normal,
+    },
+    title: {
+      color: accent.yellow,
+      weight: fontWeights.bold,
+    },
+    emphasis: {
+      color: textColor.feature,
+      weight: fontWeights.normal,
+    },
+    "emphasis.strong": {
+      color: textColor.feature,
+      weight: fontWeights.bold,
+    },
+    linkUri: {
+      color: accent.green,
+      weight: fontWeights.normal,
+      underline: true,
+    },
+    linkText: {
+      color: accent.orange,
+      weight: fontWeights.normal,
+      italic: true,
+    },
+  };
+
+  const shadowAlpha: NumberToken = {
+    value: blend,
+    type: "number",
+  };
+
+  return {
+    name,
+    backgroundColor,
+    borderColor,
+    textColor,
+    iconColor: textColor,
+    editor,
+    syntax,
+    player,
+    shadowAlpha,
+  };
+}

styles/src/themes/cave.ts 🔗

@@ -0,0 +1,29 @@
+import { createTheme } from "./base16";
+import { color } from "../tokens";
+
+const name = "cave";
+
+const neutrals = [
+  color("#19171c"),
+  color("#26232a"),
+  color("#585260"),
+  color("#655f6d"),
+  color("#7e7887"),
+  color("#8b8792"),
+  color("#e2dfe7"),
+  color("#efecf4"),
+];
+
+const colors = {
+  "red": color("#be4678"),
+  "orange": color("#aa573c"),
+  "yellow": color("#a06e3b"),
+  "green": color("#2a9292"),
+  "cyan": color("#398bc6"),
+  "blue": color("#576ddb"),
+  "violet": color("#955ae7"),
+  "magenta": color("#bf40bf"),
+};
+
+export const dark = createTheme(`${name}-dark`, false, neutrals, colors);
+export const light = createTheme(`${name}-light`, true, neutrals, colors);

styles/src/themes/dark.ts 🔗

@@ -1,4 +1,4 @@
-import { colors, fontWeights, NumberToken } from "../tokens";
+import { color, colors, fontWeights, NumberToken } from "../tokens";
 import { withOpacity } from "../utils/color";
 import Theme, { buildPlayer, Syntax } from "./theme";
 
@@ -202,22 +202,22 @@ const syntax: Syntax = {
     weight: fontWeights.bold,
   },
   emphasis: {
-    color: textColor.active,
+    color: textColor.feature,
     weight: fontWeights.normal,
   },
-  emphasisStrong: {
-    color: textColor.active,
+  "emphasis.strong": {
+    color: textColor.feature,
     weight: fontWeights.bold,
   },
-  linkUrl: {
+  linkUri: {
     color: colors.lime[500],
     weight: fontWeights.normal,
-    // TODO: add underline
+    underline: true,
   },
   linkText: {
     color: colors.orange[500],
     weight: fontWeights.normal,
-    // TODO: add italic
+    italic: true,
   },
 };
 

styles/src/themes/light.ts 🔗

@@ -200,22 +200,22 @@ const syntax: Syntax = {
     weight: fontWeights.bold,
   },
   emphasis: {
-    color: textColor.active,
+    color: textColor.feature,
     weight: fontWeights.normal,
   },
-  emphasisStrong: {
-    color: textColor.active,
+  "emphasis.strong": {
+    color: textColor.feature,
     weight: fontWeights.bold,
   },
-  linkUrl: {
+  linkUri: {
     color: colors.lime[500],
     weight: fontWeights.normal,
-    // TODO: add underline
+    underline: true
   },
   linkText: {
     color: colors.red[500],
     weight: fontWeights.normal,
-    // TODO: add italic
+    italic: true
   },
 };
 

styles/src/themes/solarized.ts 🔗

@@ -0,0 +1,29 @@
+import { createTheme } from "./base16";
+import { color } from "../tokens";
+
+const name = "solarized";
+
+const neutrals = [
+  color("#002b36"),
+  color("#073642"),
+  color("#586e75"),
+  color("#657b83"),
+  color("#839496"),
+  color("#93a1a1"),
+  color("#eee8d5"),
+  color("#fdf6e3"),
+];
+
+const colors = {
+  "red": color("#dc322f"),
+  "orange": color("#cb4b16"),
+  "yellow": color("#b58900"),
+  "green": color("#859900"),
+  "cyan": color("#2aa198"),
+  "blue": color("#268bd2"),
+  "violet": color("#6c71c4"),
+  "magenta": color("#d33682"),
+};
+
+export const dark = createTheme(`${name}-dark`, false, neutrals, colors);
+export const light = createTheme(`${name}-light`, true, neutrals, colors);

styles/src/themes/sulphurpool.ts 🔗

@@ -0,0 +1,29 @@
+import { createTheme } from "./base16";
+import { color } from "../tokens";
+
+const name = "sulphurpool";
+
+const neutrals = [
+  color("#202746"),
+  color("#293256"),
+  color("#5e6687"),
+  color("#6b7394"),
+  color("#898ea4"),
+  color("#979db4"),
+  color("#dfe2f1"),
+  color("#f5f7ff"),
+]
+
+const colors = {
+  "red": color("#c94922"),
+  "orange": color("#c76b29"),
+  "yellow": color("#c08b30"),
+  "green": color("#ac9739"),
+  "cyan": color("#22a2c9"),
+  "blue": color("#3d8fd1"),
+  "violet": color("#6679cc"),
+  "magenta": color("#9c637a"),
+};
+
+export const dark = createTheme(`${name}-dark`, false, neutrals, colors);
+export const light = createTheme(`${name}-light`, true, neutrals, colors);

styles/src/themes/theme.ts 🔗

@@ -3,7 +3,9 @@ import { withOpacity } from "../utils/color";
 
 export interface SyntaxHighlightStyle {
   color: ColorToken;
-  weight: FontWeightToken;
+  weight?: FontWeightToken;
+  underline?: boolean,
+  italic?: boolean,
 }
 
 export interface Player {
@@ -49,21 +51,30 @@ export interface Syntax {
   number: SyntaxHighlightStyle;
   boolean: SyntaxHighlightStyle;
   predictive: SyntaxHighlightStyle;
-  // TODO: Either move the following or rename
   title: SyntaxHighlightStyle;
   emphasis: SyntaxHighlightStyle;
-  emphasisStrong: SyntaxHighlightStyle;
-  linkUrl: SyntaxHighlightStyle;
+  linkUri: SyntaxHighlightStyle;
   linkText: SyntaxHighlightStyle;
+
+  [key: string]: SyntaxHighlightStyle;
 };
 
 export default interface Theme {
   name: string;
   backgroundColor: {
+    // Basically just Title Bar
+    // Lowest background level
     100: BackgroundColorSet;
+    // Tab bars, panels, popovers
+    // Mid-ground
     300: BackgroundColorSet;
+    // The editor
+    // Foreground
     500: BackgroundColorSet;
+    // Hacks for elements on top of the midground
+    // Buttons in a panel, tab bar, or panel
     on300: BackgroundColorSet;
+    // Hacks for elements on top of the editor
     on500: BackgroundColorSet;
     ok: BackgroundColorSet;
     error: BackgroundColorSet;

styles/src/tokens.ts 🔗

@@ -71,6 +71,12 @@ export interface ColorToken {
   type: "color",
   step?: number,
 }
+export function color(value: string): ColorToken {
+  return {
+    value,
+    type: "color",
+  };
+}
 export const colors = {
   neutral: colorRamp(["white", "black"], { steps: 37, increment: 25 }), // (900/25) + 1
   rose: colorRamp("#F43F5EFF"),

styles/src/utils/snakeCase.ts 🔗

@@ -17,7 +17,7 @@ type SnakeCased<Type> = {
 export default function snakeCaseTree<T>(object: T): SnakeCased<T> {
   const snakeObject: any = {};
   for (const key in object) {
-    snakeObject[snakeCase(key)] = snakeCaseValue(object[key]);
+    snakeObject[snakeCase(key, { keepSpecialCharacters: true })] = snakeCaseValue(object[key]);
   }
   return snakeObject;
 }