Merge branch 'main' into editor-tests

This commit is contained in:
Mikayla 2023-11-13 09:54:02 -08:00
commit 4c5d5105f3
No known key found for this signature in database
100 changed files with 13615 additions and 5795 deletions

59
Cargo.lock generated
View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,5 +1,5 @@
{ {
"name": "Notctis", "name": "Noctis",
"author": "Liviu Schera (liviuschera)", "author": "Liviu Schera (liviuschera)",
"themes": [ "themes": [
{ {

View file

@ -8,7 +8,7 @@
"appearance": "dark" "appearance": "dark"
}, },
{ {
"name": "Rose Moon", "name": "Rose Pine Moon",
"file_name": "rose-pine-moon.json", "file_name": "rose-pine-moon.json",
"appearance": "dark" "appearance": "dark"
}, },

View file

@ -158,7 +158,11 @@
}, },
{ {
"name": "String", "name": "String",
"scope": ["string.quoted", "string.template", "punctuation.definition.string"], "scope": [
"string.quoted",
"string.template",
"punctuation.definition.string"
],
"settings": { "settings": {
"foreground": "#ff8b39" "foreground": "#ff8b39"
} }
@ -398,7 +402,10 @@
}, },
{ {
"name": "CSS property", "name": "CSS property",
"scope": ["support.type.property-name.css", "support.type.property-name.json"], "scope": [
"support.type.property-name.css",
"support.type.property-name.json"
],
"settings": { "settings": {
"foreground": "#72f1b8" "foreground": "#72f1b8"
} }
@ -528,7 +535,10 @@
}, },
{ {
"name": "C# properties and fields", "name": "C# properties and fields",
"scope": ["entity.name.variable.field.cs", "entity.name.variable.property.cs"], "scope": [
"entity.name.variable.field.cs",
"entity.name.variable.property.cs"
],
"settings": { "settings": {
"foreground": "#ff7edb" "foreground": "#ff7edb"
} }
@ -543,7 +553,10 @@
}, },
{ {
"name": "C preprocessors", "name": "C preprocessors",
"scope": ["keyword.control.directive.include.c", "keyword.control.directive.define.c"], "scope": [
"keyword.control.directive.include.c",
"keyword.control.directive.define.c"
],
"settings": { "settings": {
"foreground": "#72f1b8" "foreground": "#72f1b8"
} }
@ -732,7 +745,10 @@
}, },
{ {
"name": "Markdown links and image paths", "name": "Markdown links and image paths",
"scope": ["markup.underline.link.markdown", "markup.inline.raw.string.markdown"], "scope": [
"markup.underline.link.markdown",
"markup.inline.raw.string.markdown"
],
"settings": { "settings": {
"foreground": "#72f1b8", "foreground": "#72f1b8",
"fontStyle": "italic" "fontStyle": "italic"
@ -771,7 +787,10 @@
}, },
{ {
"name": "Markdown quotes", "name": "Markdown quotes",
"scope": ["punctuation.definition.quote.begin.markdown", "markup.quote.markdown"], "scope": [
"punctuation.definition.quote.begin.markdown",
"markup.quote.markdown"
],
"settings": { "settings": {
"foreground": "#72f1b8" "foreground": "#72f1b8"
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -401,7 +401,7 @@ impl List {
v_stack() v_stack()
.w_full() .w_full()
.py_1() .py_1()
.children(self.header.map(|header| header)) .children(self.header)
.child(list_content) .child(list_content)
} }
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -36,11 +36,12 @@ use futures::{
Future, FutureExt, StreamExt, Future, FutureExt, StreamExt,
}; };
use gpui::{ use gpui::{
actions, div, point, rems, size, AnyModel, AnyView, AnyWeakView, AppContext, AsyncAppContext, actions, div, point, rems, size, Action, AnyModel, AnyView, AnyWeakView, AppContext,
AsyncWindowContext, Bounds, Component, Div, Entity, EntityId, EventEmitter, FocusHandle, AsyncAppContext, AsyncWindowContext, Bounds, Component, DispatchContext, Div, Entity, EntityId,
GlobalPixels, Model, ModelContext, ParentElement, Point, Render, Size, StatefulInteractive, EventEmitter, FocusHandle, GlobalPixels, Model, ModelContext, ParentElement, Point, Render,
Styled, Subscription, Task, View, ViewContext, VisualContext, WeakView, WindowBounds, Size, StatefulInteractive, StatefulInteractivity, StatelessInteractive, Styled, Subscription,
WindowContext, WindowHandle, WindowOptions, Task, View, ViewContext, VisualContext, WeakView, WindowBounds, WindowContext, WindowHandle,
WindowOptions,
}; };
use item::{FollowableItem, FollowableItemHandle, Item, ItemHandle, ItemSettings, ProjectItem}; use item::{FollowableItem, FollowableItemHandle, Item, ItemHandle, ItemSettings, ProjectItem};
use itertools::Itertools; use itertools::Itertools;
@ -530,6 +531,13 @@ pub enum Event {
pub struct Workspace { pub struct Workspace {
weak_self: WeakView<Self>, weak_self: WeakView<Self>,
focus_handle: FocusHandle, focus_handle: FocusHandle,
workspace_actions: Vec<
Box<
dyn Fn(
Div<Workspace, StatefulInteractivity<Workspace>>,
) -> Div<Workspace, StatefulInteractivity<Workspace>>,
>,
>,
zoomed: Option<AnyWeakView>, zoomed: Option<AnyWeakView>,
zoomed_position: Option<DockPosition>, zoomed_position: Option<DockPosition>,
center: PaneGroup, center: PaneGroup,
@ -542,7 +550,7 @@ pub struct Workspace {
last_active_center_pane: Option<WeakView<Pane>>, last_active_center_pane: Option<WeakView<Pane>>,
last_active_view_id: Option<proto::ViewId>, last_active_view_id: Option<proto::ViewId>,
status_bar: View<StatusBar>, status_bar: View<StatusBar>,
modal_layer: ModalLayer, modal_layer: View<ModalLayer>,
// titlebar_item: Option<AnyViewHandle>, // titlebar_item: Option<AnyViewHandle>,
notifications: Vec<(TypeId, usize, Box<dyn NotificationHandle>)>, notifications: Vec<(TypeId, usize, Box<dyn NotificationHandle>)>,
project: Model<Project>, project: Model<Project>,
@ -694,7 +702,7 @@ impl Workspace {
}); });
let workspace_handle = cx.view().downgrade(); let workspace_handle = cx.view().downgrade();
let modal_layer = ModalLayer::new(); let modal_layer = cx.build_view(|cx| ModalLayer::new());
// todo!() // todo!()
// cx.update_default_global::<DragAndDrop<Workspace>, _, _>(|drag_and_drop, _| { // cx.update_default_global::<DragAndDrop<Workspace>, _, _>(|drag_and_drop, _| {
@ -775,13 +783,10 @@ impl Workspace {
leader_updates_tx, leader_updates_tx,
subscriptions, subscriptions,
pane_history_timestamp, pane_history_timestamp,
workspace_actions: Default::default(),
} }
} }
pub fn modal_layer(&mut self) -> &mut ModalLayer {
&mut self.modal_layer
}
fn new_local( fn new_local(
abs_paths: Vec<PathBuf>, abs_paths: Vec<PathBuf>,
app_state: Arc<AppState>, app_state: Arc<AppState>,
@ -3495,6 +3500,35 @@ impl Workspace {
// ) // )
// } // }
// } // }
pub fn register_action<A: Action>(
&mut self,
callback: impl Fn(&mut Self, &A, &mut ViewContext<Self>) + 'static,
) {
let callback = Arc::new(callback);
self.workspace_actions.push(Box::new(move |div| {
let callback = callback.clone();
div.on_action(move |workspace, event, cx| (callback.clone())(workspace, event, cx))
}));
}
fn add_workspace_actions_listeners(
&self,
mut div: Div<Workspace, StatefulInteractivity<Workspace>>,
) -> Div<Workspace, StatefulInteractivity<Workspace>> {
for action in self.workspace_actions.iter() {
div = (action)(div)
}
div
}
pub fn toggle_modal<V: Modal, B>(&mut self, cx: &mut ViewContext<Self>, build: B)
where
B: FnOnce(&mut ViewContext<V>) -> V,
{
self.modal_layer
.update(cx, |modal_layer, cx| modal_layer.toggle_modal(cx, build))
}
} }
fn window_bounds_env_override(cx: &AsyncAppContext) -> Option<WindowBounds> { fn window_bounds_env_override(cx: &AsyncAppContext) -> Option<WindowBounds> {
@ -3709,6 +3743,9 @@ impl Render for Workspace {
type Element = Div<Self>; type Element = Div<Self>;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
let mut context = DispatchContext::default();
context.insert("Workspace");
cx.with_key_dispatch_context(context, |cx| {
div() div()
.relative() .relative()
.size_full() .size_full()
@ -3723,8 +3760,7 @@ impl Render for Workspace {
.child(self.render_titlebar(cx)) .child(self.render_titlebar(cx))
.child( .child(
// todo! should this be a component a view? // todo! should this be a component a view?
self.modal_layer self.add_workspace_actions_listeners(div().id("workspace"))
.wrapper_element(cx)
.relative() .relative()
.flex_1() .flex_1()
.w_full() .w_full()
@ -3733,6 +3769,7 @@ impl Render for Workspace {
.border_t() .border_t()
.border_b() .border_b()
.border_color(cx.theme().colors().border) .border_color(cx.theme().colors().border)
.child(self.modal_layer.clone())
// .children( // .children(
// Some( // Some(
// Panel::new("project-panel-outer", cx) // Panel::new("project-panel-outer", cx)
@ -3857,9 +3894,9 @@ impl Render for Workspace {
// .on_click(Arc::new(|workspace, cx| workspace.toggle_debug(cx))), // .on_click(Arc::new(|workspace, cx| workspace.toggle_debug(cx))),
// ), // ),
) )
})
} }
} }
// todo!() // todo!()
// impl Entity for Workspace { // impl Entity for Workspace {
// type Event = Event; // type Event = Event;

View file

@ -8,6 +8,11 @@
[ [
(jsx_element) (jsx_element)
(jsx_fragment) (jsx_fragment)
] @element
[
(jsx_opening_element)
(jsx_closing_element)
(jsx_self_closing_element) (jsx_self_closing_element)
(jsx_expression) (jsx_expression)
] @element ] @default

View file

@ -8,6 +8,11 @@
[ [
(jsx_element) (jsx_element)
(jsx_fragment) (jsx_fragment)
] @element
[
(jsx_opening_element)
(jsx_closing_element)
(jsx_self_closing_element) (jsx_self_closing_element)
(jsx_expression) (jsx_expression)
] @element ] @default

View file

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

View file

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

View file

@ -8,6 +8,11 @@
[ [
(jsx_element) (jsx_element)
(jsx_fragment) (jsx_fragment)
] @element
[
(jsx_opening_element)
(jsx_closing_element)
(jsx_self_closing_element) (jsx_self_closing_element)
(jsx_expression) (jsx_expression)
] @element ] @default

View file

@ -8,6 +8,11 @@
[ [
(jsx_element) (jsx_element)
(jsx_fragment) (jsx_fragment)
] @element
[
(jsx_opening_element)
(jsx_closing_element)
(jsx_self_closing_element) (jsx_self_closing_element)
(jsx_expression) (jsx_expression)
] @element ] @default

View file

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

View file

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

View file

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

View file

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