Extract syntax highlighting properties from tree-sitter highlight queries (#2797)

This should be a purely internal change. Let me know if any visual
changes are observed from this!

### Syntax theme
- Update the theme to allow any syntax highlighting property used in any
`highlight.scm` to be styled
- Only define syntax styles that are baked into the default theme &
don't use the default text style
- Adds the `generate-syntax` command
- Removes a few unused properties that we were styling for some reason,
like `enum` and `variant`, neither of which exist in any `highlight.scm`
- Moves `@constructor` symbols to `@method.constructor` to prevent
issues with `constructor` being a reserved property in ts/js.

Syntax is now build as the theme is created rather than as part of the
styleTree. This means it no longer requires a compiled `Theme`, which
makes things a bit more straightforward if we need to access it in other
components that should be built before the styleTrees.

### Scheme

Also updates all uses of `#match` in our `highlights.scm` files, as
these break the scheme tree-sitter query. This fixes _most_ instances of
our scheme highlighting breaking.

For some reason something in here breaks the `highlights.scm` for PHP:

```scheme
((name) @constant.builtin
 (.match? @constant.builtin "^__[A-Z][A-Z\d_]+__$"))

((name) @method.constructor
(.match? @method.constructor "^[A-Z]"))

((name) @variable.builtin
 (.eq? @variable.builtin "this"))
```

Release Notes:

- No public facing changes
This commit is contained in:
Nate Butler 2023-07-27 13:14:01 -04:00 committed by GitHub
commit 45c635872b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
57 changed files with 631 additions and 554 deletions

View file

@ -54,5 +54,5 @@
(
(command (_) @constant)
(#match? @constant "^-")
(.match? @constant "^-")
)

View file

@ -86,7 +86,7 @@
(identifier) @variable
((identifier) @constant
(#match? @constant "^_*[A-Z][A-Z\\d_]*$"))
(.match? @constant "^_*[A-Z][A-Z\\d_]*$"))
(call_expression
function: (identifier) @function)
@ -106,4 +106,3 @@
(primitive_type)
(sized_type_specifier)
] @type

View file

@ -1,7 +1,7 @@
(preproc_def
value: (preproc_arg) @content
(#set! "language" "c"))
(.set! "language" "c"))
(preproc_function_def
value: (preproc_arg) @content
(#set! "language" "c"))
(.set! "language" "c"))

View file

@ -31,13 +31,13 @@
declarator: (field_identifier) @function)
((namespace_identifier) @type
(#match? @type "^[A-Z]"))
(.match? @type "^[A-Z]"))
(auto) @type
(type_identifier) @type
((identifier) @constant
(#match? @constant "^_*[A-Z][A-Z\\d_]*$"))
(.match? @constant "^_*[A-Z][A-Z\\d_]*$"))
(field_identifier) @property
(statement_identifier) @label

View file

@ -1,7 +1,7 @@
(preproc_def
value: (preproc_arg) @content
(#set! "language" "c++"))
(.set! "language" "c++"))
(preproc_function_def
value: (preproc_arg) @content
(#set! "language" "c++"))
(.set! "language" "c++"))

View file

@ -46,7 +46,7 @@
(property_name)
(plain_value)
] @variable.special
(#match? @variable.special "^--")
(.match? @variable.special "^--")
)
[

View file

@ -3,7 +3,7 @@
operator: "@"
operand: (call
target: (identifier) @unary
(#match? @unary "^(doc)$"))
(.match? @unary "^(doc)$"))
) @context
.
(call
@ -18,10 +18,10 @@
target: (identifier) @name)
operator: "when")
])
(#match? @name "^(def|defp|defdelegate|defguard|defguardp|defmacro|defmacrop|defn|defnp)$")) @item
(.match? @name "^(def|defp|defdelegate|defguard|defguardp|defmacro|defmacrop|defn|defnp)$")) @item
)
(call
target: (identifier) @name
(arguments (alias) @name)
(#match? @name "^(defmodule|defprotocol)$")) @item
(.match? @name "^(defmodule|defprotocol)$")) @item

View file

@ -54,13 +54,13 @@
(sigil_name) @__name__
quoted_start: _ @string
quoted_end: _ @string
(#match? @__name__ "^[sS]$")) @string
(.match? @__name__ "^[sS]$")) @string
(sigil
(sigil_name) @__name__
quoted_start: _ @string.regex
quoted_end: _ @string.regex
(#match? @__name__ "^[rR]$")) @string.regex
(.match? @__name__ "^[rR]$")) @string.regex
(sigil
(sigil_name) @__name__
@ -69,7 +69,7 @@
(
(identifier) @comment.unused
(#match? @comment.unused "^_")
(.match? @comment.unused "^_")
)
(call
@ -91,7 +91,7 @@
operator: "|>"
right: (identifier))
])
(#match? @keyword "^(def|defdelegate|defguard|defguardp|defmacro|defmacrop|defn|defnp|defp)$"))
(.match? @keyword "^(def|defdelegate|defguard|defguardp|defmacro|defmacrop|defn|defnp|defp)$"))
(binary_operator
operator: "|>"
@ -99,15 +99,15 @@
(call
target: (identifier) @keyword
(#match? @keyword "^(def|defdelegate|defexception|defguard|defguardp|defimpl|defmacro|defmacrop|defmodule|defn|defnp|defoverridable|defp|defprotocol|defstruct)$"))
(.match? @keyword "^(def|defdelegate|defexception|defguard|defguardp|defimpl|defmacro|defmacrop|defmodule|defn|defnp|defoverridable|defp|defprotocol|defstruct)$"))
(call
target: (identifier) @keyword
(#match? @keyword "^(alias|case|cond|else|for|if|import|quote|raise|receive|require|reraise|super|throw|try|unless|unquote|unquote_splicing|use|with)$"))
(.match? @keyword "^(alias|case|cond|else|for|if|import|quote|raise|receive|require|reraise|super|throw|try|unless|unquote|unquote_splicing|use|with)$"))
(
(identifier) @constant.builtin
(#match? @constant.builtin "^(__MODULE__|__DIR__|__ENV__|__CALLER__|__STACKTRACE__)$")
(.match? @constant.builtin "^(__MODULE__|__DIR__|__ENV__|__CALLER__|__STACKTRACE__)$")
)
(unary_operator
@ -121,7 +121,7 @@
(sigil)
(boolean)
] @comment.doc))
(#match? @__attribute__ "^(moduledoc|typedoc|doc)$"))
(.match? @__attribute__ "^(moduledoc|typedoc|doc)$"))
(comment) @comment
@ -150,4 +150,4 @@
((sigil
(sigil_name) @_sigil_name
(quoted_content) @embedded)
(#eq? @_sigil_name "H"))
(.eq? @_sigil_name "H"))

View file

@ -3,5 +3,5 @@
((sigil
(sigil_name) @_sigil_name
(quoted_content) @content)
(#eq? @_sigil_name "H")
(#set! language "heex"))
(.eq? @_sigil_name "H")
(.set! language "heex"))

View file

@ -1,7 +1,7 @@
(call
target: (identifier) @context
(arguments (alias) @name)
(#match? @context "^(defmodule|defprotocol)$")) @item
(.match? @context "^(defmodule|defprotocol)$")) @item
(call
target: (identifier) @context
@ -23,4 +23,4 @@
")" @context.extra))
operator: "when")
])
(#match? @context "^(def|defp|defdelegate|defguard|defguardp|defmacro|defmacrop|defn|defnp)$")) @item
(.match? @context "^(def|defp|defdelegate|defguard|defguardp|defmacro|defmacrop|defn|defnp)$")) @item

View file

@ -1,2 +1,2 @@
((glsl_content) @content
(#set! "language" "glsl"))
(.set! "language" "glsl"))

View file

@ -1,7 +1,7 @@
((code) @content
(#set! "language" "ruby")
(#set! "combined"))
(.set! "language" "ruby")
(.set! "combined"))
((content) @content
(#set! "language" "html")
(#set! "combined"))
(.set! "language" "html")
(.set! "combined"))

View file

@ -74,7 +74,7 @@
(sized_type_specifier) @type
((identifier) @constant
(#match? @constant "^[A-Z][A-Z\\d_]*$"))
(.match? @constant "^[A-Z][A-Z\\d_]*$"))
(identifier) @variable
@ -114,5 +114,5 @@
(
(identifier) @variable.builtin
(#match? @variable.builtin "^gl_")
(.match? @variable.builtin "^gl_")
)

View file

@ -5,9 +5,9 @@
(expression_value)
(ending_expression_value)
] @content)
(#set! language "elixir")
(#set! combined)
(.set! language "elixir")
(.set! combined)
)
((expression (expression_value) @content)
(#set! language "elixir"))
(.set! language "elixir"))

View file

@ -1,7 +1,7 @@
(script_element
(raw_text) @content
(#set! "language" "javascript"))
(.set! "language" "javascript"))
(style_element
(raw_text) @content
(#set! "language" "css"))
(.set! "language" "css"))

View file

@ -44,7 +44,7 @@
; Special identifiers
((identifier) @type
(#match? @type "^[A-Z]"))
(.match? @type "^[A-Z]"))
(type_identifier) @type
(predefined_type) @type.builtin
@ -53,7 +53,7 @@
(shorthand_property_identifier)
(shorthand_property_identifier_pattern)
] @constant
(#match? @constant "^_*[A-Z_][A-Z\\d_]*$"))
(.match? @constant "^_*[A-Z_][A-Z\\d_]*$"))
; Literals
@ -214,4 +214,4 @@
"type"
"readonly"
"override"
] @keyword
] @keyword

View file

@ -127,7 +127,7 @@
(identifier) @variable
((identifier) @variable.special
(#eq? @variable.special "self"))
(.eq? @variable.special "self"))
(variable_list
attribute: (attribute
@ -137,7 +137,7 @@
;; Constants
((identifier) @constant
(#match? @constant "^[A-Z][A-Z_0-9]*$"))
(.match? @constant "^[A-Z][A-Z_0-9]*$"))
(vararg_expression) @constant
@ -158,7 +158,7 @@
[
"{"
"}"
] @constructor)
] @method.constructor)
;; Functions
@ -180,7 +180,7 @@
(function_call
(identifier) @function.builtin
(#any-of? @function.builtin
(.any-of? @function.builtin
;; built-in functions in Lua 5.1
"assert" "collectgarbage" "dofile" "error" "getfenv" "getmetatable" "ipairs"
"load" "loadfile" "loadstring" "module" "next" "pairs" "pcall" "print"
@ -195,4 +195,4 @@
(number) @number
(string) @string
(string) @string

View file

@ -43,15 +43,15 @@
(relative_scope) @variable.builtin
((name) @constant
(#match? @constant "^_?[A-Z][A-Z\\d_]+$"))
(.match? @constant "^_?[A-Z][A-Z\\d_]+$"))
((name) @constant.builtin
(#match? @constant.builtin "^__[A-Z][A-Z\d_]+__$"))
(.match? @constant.builtin "^__[A-Z][A-Z\d_]+__$"))
((name) @constructor
(#match? @constructor "^[A-Z]"))
((name) @method.constructor
(.match? @method.constructor "^[A-Z]"))
((name) @variable.builtin
(#eq? @variable.builtin "this"))
(.eq? @variable.builtin "this"))
(variable_name) @variable

View file

@ -1,3 +1,3 @@
((text) @content
(#set! "language" "html")
(#set! "combined"))
(.set! "language" "html")
(.set! "combined"))

View file

@ -18,16 +18,16 @@
; Identifier naming conventions
((identifier) @type
(#match? @type "^[A-Z]"))
(.match? @type "^[A-Z]"))
((identifier) @constant
(#match? @constant "^_*[A-Z][A-Z\\d_]*$"))
(.match? @constant "^_*[A-Z][A-Z\\d_]*$"))
; Builtin functions
((call
function: (identifier) @function.builtin)
(#match?
(.match?
@function.builtin
"^(abs|all|any|ascii|bin|bool|breakpoint|bytearray|bytes|callable|chr|classmethod|compile|complex|delattr|dict|dir|divmod|enumerate|eval|exec|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|isinstance|issubclass|iter|len|list|locals|map|max|memoryview|min|next|object|oct|open|ord|pow|print|property|range|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|vars|zip|__import__)$"))
@ -122,4 +122,4 @@
"yield"
"match"
"case"
] @keyword
] @keyword

File diff suppressed because one or more lines are too long

View file

@ -6,5 +6,5 @@
(symbol) @name
(list . (symbol) @name)
]
(#match? @start-symbol "^define")
) @item
(.match? @start-symbol "^define")
) @item

View file

@ -11,4 +11,4 @@
(begin "begin" @open "end" @close)
(module "module" @open "end" @close)
(_ . "def" @open "end" @close)
(_ . "class" @open "end" @close)
(_ . "class" @open "end" @close)

View file

@ -33,12 +33,12 @@
(identifier) @variable
((identifier) @keyword
(#match? @keyword "^(private|protected|public)$"))
(.match? @keyword "^(private|protected|public)$"))
; Function calls
((identifier) @function.method.builtin
(#eq? @function.method.builtin "require"))
(.eq? @function.method.builtin "require"))
"defined?" @function.method.builtin
@ -60,7 +60,7 @@
] @property
((identifier) @constant.builtin
(#match? @constant.builtin "^__(FILE|LINE|ENCODING)__$"))
(.match? @constant.builtin "^__(FILE|LINE|ENCODING)__$"))
(file) @constant.builtin
(line) @constant.builtin
@ -71,7 +71,7 @@
) @constant.builtin
((constant) @constant
(#match? @constant "^[A-Z\\d_]+$"))
(.match? @constant "^[A-Z\\d_]+$"))
(constant) @type

View file

@ -38,11 +38,11 @@
; Assume uppercase names are types/enum-constructors
((identifier) @type
(#match? @type "^[A-Z]"))
(.match? @type "^[A-Z]"))
; Assume all-caps names are constants
((identifier) @constant
(#match? @constant "^_*[A-Z][A-Z\\d_]*$"))
(.match? @constant "^_*[A-Z][A-Z\\d_]*$"))
[
"("

View file

@ -1,7 +1,7 @@
(macro_invocation
(token_tree) @content
(#set! "language" "rust"))
(.set! "language" "rust"))
(macro_rule
(token_tree) @content
(#set! "language" "rust"))
(.set! "language" "rust"))

View file

@ -14,7 +14,7 @@
(directive)] @comment
((symbol) @operator
(#match? @operator "^(\\+|-|\\*|/|=|>|<|>=|<=)$"))
(.match? @operator "^(\\+|-|\\*|/|=|>|<|>=|<=)$"))
(list
.
@ -23,6 +23,6 @@
(list
.
(symbol) @keyword
(#match? @keyword
(.match? @keyword
"^(define-syntax|let\\*|lambda|λ|case|=>|quote-splicing|unquote-splicing|set!|let|letrec|letrec-syntax|let-values|let\\*-values|do|else|define|cond|syntax-rules|unquote|begin|quote|let-syntax|and|if|quasiquote|letrec|delay|or|when|unless|identifier-syntax|assert|library|export|import|rename|only|except|prefix)$"
))

View file

@ -6,5 +6,5 @@
(symbol) @name
(list . (symbol) @name)
]
(#match? @start-symbol "^define")
) @item
(.match? @start-symbol "^define")
) @item

View file

@ -2,27 +2,27 @@
; --------------
(script_element
(raw_text) @content
(#set! "language" "javascript"))
(.set! "language" "javascript"))
((script_element
(start_tag
(attribute
(quoted_attribute_value (attribute_value) @_language)))
(raw_text) @content)
(#eq? @_language "ts")
(#set! "language" "typescript"))
(.eq? @_language "ts")
(.set! "language" "typescript"))
((script_element
(start_tag
(attribute
(quoted_attribute_value (attribute_value) @_language)))
(raw_text) @content)
(#eq? @_language "typescript")
(#set! "language" "typescript"))
(.eq? @_language "typescript")
(.set! "language" "typescript"))
(style_element
(raw_text) @content
(#set! "language" "css"))
(.set! "language" "css"))
((raw_text_expr) @content
(#set! "language" "javascript"))
(.set! "language" "javascript"))

View file

@ -43,11 +43,11 @@
; Special identifiers
((identifier) @constructor
(#match? @constructor "^[A-Z]"))
((identifier) @method.constructor
(.match? @method.constructor "^[A-Z]"))
((identifier) @type
(#match? @type "^[A-Z]"))
(.match? @type "^[A-Z]"))
(type_identifier) @type
(predefined_type) @type.builtin
@ -56,7 +56,7 @@
(shorthand_property_identifier)
(shorthand_property_identifier_pattern)
] @constant
(#match? @constant "^_*[A-Z_][A-Z\\d_]*$"))
(.match? @constant "^_*[A-Z_][A-Z\\d_]*$"))
; Literals
@ -218,4 +218,4 @@
"type"
"readonly"
"override"
] @keyword
] @keyword

View file

@ -8,6 +8,7 @@
"build-licenses": "ts-node ./src/build_licenses.ts",
"build-tokens": "ts-node ./src/build_tokens.ts",
"build-types": "ts-node ./src/build_types.ts",
"generate-syntax": "ts-node ./src/types/extract_syntax_types.ts",
"test": "vitest"
},
"author": "Zed Industries (https://github.com/zed-industries/)",

View file

@ -21,9 +21,7 @@ function clear_themes(theme_directory: string) {
}
}
const all_themes: Theme[] = themes.map((theme) =>
create_theme(theme)
)
const all_themes: Theme[] = themes.map((theme) => create_theme(theme))
function write_themes(themes: Theme[], output_directory: string) {
clear_themes(output_directory)
@ -34,10 +32,7 @@ function write_themes(themes: Theme[], output_directory: string) {
const style_tree = app()
const style_tree_json = JSON.stringify(style_tree, null, 2)
const temp_path = path.join(temp_directory, `${theme.name}.json`)
const out_path = path.join(
output_directory,
`${theme.name}.json`
)
const out_path = path.join(output_directory, `${theme.name}.json`)
fs.writeFileSync(temp_path, style_tree_json)
fs.renameSync(temp_path, out_path)
console.log(`- ${out_path} created`)

View file

@ -83,8 +83,6 @@ function write_tokens(themes: Theme[], tokens_directory: string) {
console.log(`- ${METADATA_FILE} created`)
}
const all_themes: Theme[] = themes.map((theme) =>
create_theme(theme)
)
const all_themes: Theme[] = themes.map((theme) => create_theme(theme))
write_tokens(all_themes, TOKENS_DIRECTORY)

View file

@ -10,10 +10,7 @@ export type Margin = {
}
interface IconButtonOptions {
layer?:
| Theme["lowest"]
| Theme["middle"]
| Theme["highest"]
layer?: Theme["lowest"] | Theme["middle"] | Theme["highest"]
color?: keyof Theme["lowest"]
margin?: Partial<Margin>
}

View file

@ -12,44 +12,47 @@ type TabBarButtonProps = TabBarButtonOptions & {
state?: Partial<Record<InteractiveState, Partial<TabBarButtonOptions>>>
}
export function tab_bar_button(theme: Theme, { icon, color = "base" }: TabBarButtonProps) {
export function tab_bar_button(
theme: Theme,
{ icon, color = "base" }: TabBarButtonProps
) {
const button_spacing = 8
return (
interactive({
base: {
icon: {
color: foreground(theme.middle, color),
asset: icon,
dimensions: {
width: 15,
height: 15,
},
return interactive({
base: {
icon: {
color: foreground(theme.middle, color),
asset: icon,
dimensions: {
width: 15,
height: 15,
},
},
container: {
corner_radius: 4,
padding: {
top: 4,
bottom: 4,
left: 4,
right: 4,
},
margin: {
left: button_spacing / 2,
right: button_spacing / 2,
},
},
},
state: {
hovered: {
container: {
corner_radius: 4,
padding: {
top: 4, bottom: 4, left: 4, right: 4
},
margin: {
left: button_spacing / 2,
right: button_spacing / 2,
},
background: background(theme.middle, color, "hovered"),
},
},
state: {
hovered: {
container: {
background: background(theme.middle, color, "hovered"),
}
},
clicked: {
container: {
background: background(theme.middle, color, "pressed"),
}
clicked: {
container: {
background: background(theme.middle, color, "pressed"),
},
},
})
)
},
})
}

View file

@ -9,10 +9,7 @@ import { useTheme, Theme } from "../theme"
import { Margin } from "./icon_button"
interface TextButtonOptions {
layer?:
| Theme["lowest"]
| Theme["middle"]
| Theme["highest"]
layer?: Theme["lowest"] | Theme["middle"] | Theme["highest"]
color?: keyof Theme["lowest"]
margin?: Partial<Margin>
text_properties?: TextProperties

View file

@ -57,6 +57,6 @@ export default function app(): any {
tooltip: tooltip(),
terminal: terminal(),
assistant: assistant(),
feedback: feedback()
feedback: feedback(),
}
}

View file

@ -8,50 +8,48 @@ type RoleCycleButton = TextStyle & {
}
// TODO: Replace these with zed types
type RemainingTokens = TextStyle & {
background: string,
margin: { top: number, right: number },
background: string
margin: { top: number; right: number }
padding: {
right: number,
left: number,
top: number,
bottom: number,
},
corner_radius: number,
right: number
left: number
top: number
bottom: number
}
corner_radius: number
}
export default function assistant(): any {
const theme = useTheme()
const interactive_role = (color: StyleSets): Interactive<RoleCycleButton> => {
return (
interactive({
base: {
const interactive_role = (
color: StyleSets
): Interactive<RoleCycleButton> => {
return interactive({
base: {
...text(theme.highest, "sans", color, { size: "sm" }),
},
state: {
hovered: {
...text(theme.highest, "sans", color, { size: "sm" }),
background: background(theme.highest, color, "hovered"),
},
state: {
hovered: {
...text(theme.highest, "sans", color, { size: "sm" }),
background: background(theme.highest, color, "hovered"),
},
clicked: {
...text(theme.highest, "sans", color, { size: "sm" }),
background: background(theme.highest, color, "pressed"),
}
clicked: {
...text(theme.highest, "sans", color, { size: "sm" }),
background: background(theme.highest, color, "pressed"),
},
})
)
},
})
}
const tokens_remaining = (color: StyleSets): RemainingTokens => {
return (
{
...text(theme.highest, "mono", color, { size: "xs" }),
background: background(theme.highest, "on", "default"),
margin: { top: 12, right: 20 },
padding: { right: 4, left: 4, top: 1, bottom: 1 },
corner_radius: 6,
}
)
return {
...text(theme.highest, "mono", color, { size: "xs" }),
background: background(theme.highest, "on", "default"),
margin: { top: 12, right: 20 },
padding: { right: 4, left: 4, top: 1, bottom: 1 },
corner_radius: 6,
}
}
return {
@ -93,7 +91,10 @@ export default function assistant(): any {
base: {
background: background(theme.middle),
padding: { top: 4, bottom: 4 },
border: border(theme.middle, "default", { top: true, overlay: true }),
border: border(theme.middle, "default", {
top: true,
overlay: true,
}),
},
state: {
hovered: {
@ -101,7 +102,7 @@ export default function assistant(): any {
},
clicked: {
background: background(theme.middle, "pressed"),
}
},
},
}),
saved_at: {

View file

@ -9,9 +9,9 @@ import {
} from "./components"
import hover_popover from "./hover_popover"
import { build_syntax } from "../theme/syntax"
import { interactive, toggleable } from "../element"
import { useTheme } from "../theme"
import chroma from "chroma-js"
export default function editor(): any {
const theme = useTheme()
@ -48,16 +48,28 @@ export default function editor(): any {
}
}
const syntax = build_syntax()
return {
text_color: syntax.primary.color,
text_color: theme.syntax.primary.color,
background: background(layer),
active_line_background: with_opacity(background(layer, "on"), 0.75),
highlighted_line_background: background(layer, "on"),
// Inline autocomplete suggestions, Co-pilot suggestions, etc.
hint: syntax.hint,
suggestion: syntax.predictive,
hint: chroma
.mix(
theme.ramps.neutral(0.6).hex(),
theme.ramps.blue(0.4).hex(),
0.45,
"lch"
)
.hex(),
suggestion: chroma
.mix(
theme.ramps.neutral(0.4).hex(),
theme.ramps.blue(0.4).hex(),
0.45,
"lch"
)
.hex(),
code_actions: {
indicator: toggleable({
base: interactive({
@ -255,8 +267,8 @@ export default function editor(): any {
invalid_warning_diagnostic: diagnostic(theme.middle, "base"),
hover_popover: hover_popover(),
link_definition: {
color: syntax.link_uri.color,
underline: syntax.link_uri.underline,
color: theme.syntax.link_uri.color,
underline: theme.syntax.link_uri.underline,
},
jump_icon: interactive({
base: {
@ -306,7 +318,7 @@ export default function editor(): any {
? with_opacity(theme.ramps.green(0.5).hex(), 0.8)
: with_opacity(theme.ramps.green(0.4).hex(), 0.8),
},
selections: foreground(layer, "accent")
selections: foreground(layer, "accent"),
},
composition_mark: {
underline: {
@ -314,6 +326,6 @@ export default function editor(): any {
color: border_color(layer),
},
},
syntax,
syntax: theme.syntax,
}
}

View file

@ -37,7 +37,7 @@ export default function feedback(): any {
...text(theme.highest, "mono", "on", "disabled"),
background: background(theme.highest, "on", "disabled"),
border: border(theme.highest, "on", "disabled"),
}
},
},
}),
button_margin: 8,

View file

@ -152,7 +152,7 @@ export default function picker(): any {
0.5
),
},
}
},
}),
}
}

View file

@ -64,17 +64,17 @@ export default function project_panel(): any {
const unselected_default_style = merge(
base_properties,
unselected?.default ?? {},
{},
{}
)
const unselected_hovered_style = merge(
base_properties,
{ background: background(theme.middle, "hovered") },
unselected?.hovered ?? {},
unselected?.hovered ?? {}
)
const unselected_clicked_style = merge(
base_properties,
{ background: background(theme.middle, "pressed") },
unselected?.clicked ?? {},
unselected?.clicked ?? {}
)
const selected_default_style = merge(
base_properties,
@ -82,7 +82,7 @@ export default function project_panel(): any {
background: background(theme.lowest),
text: text(theme.lowest, "sans", { size: "sm" }),
},
selected_style?.default ?? {},
selected_style?.default ?? {}
)
const selected_hovered_style = merge(
base_properties,
@ -90,7 +90,7 @@ export default function project_panel(): any {
background: background(theme.lowest, "hovered"),
text: text(theme.lowest, "sans", { size: "sm" }),
},
selected_style?.hovered ?? {},
selected_style?.hovered ?? {}
)
const selected_clicked_style = merge(
base_properties,
@ -98,7 +98,7 @@ export default function project_panel(): any {
background: background(theme.lowest, "pressed"),
text: text(theme.lowest, "sans", { size: "sm" }),
},
selected_style?.clicked ?? {},
selected_style?.clicked ?? {}
)
return toggleable({
@ -175,7 +175,7 @@ export default function project_panel(): any {
default: {
icon_color: foreground(theme.middle, "variant"),
},
},
}
),
cut_entry: entry(
{
@ -190,7 +190,7 @@ export default function project_panel(): any {
size: "sm",
}),
},
},
}
),
filename_editor: {
background: background(theme.middle, "on"),

View file

@ -34,10 +34,14 @@ export default function status_bar(): any {
...text(layer, "mono", "variant", { size: "xs" }),
},
active_language: text_button({
color: "variant"
color: "variant",
}),
auto_update_progress_message: text(layer, "sans", "variant", {
size: "xs",
}),
auto_update_done_message: text(layer, "sans", "variant", {
size: "xs",
}),
auto_update_progress_message: text(layer, "sans", "variant", { size: "xs" }),
auto_update_done_message: text(layer, "sans", "variant", { size: "xs" }),
lsp_status: interactive({
base: {
...diagnostic_status_container,

View file

@ -183,10 +183,10 @@ export function titlebar(): any {
project_name_divider: text(theme.lowest, "sans", "variant"),
project_menu_button: toggleable_text_button(theme, {
color: 'base',
color: "base",
}),
git_menu_button: toggleable_text_button(theme, {
color: 'variant',
color: "variant",
}),
// Collaborators

View file

@ -1,28 +1,28 @@
import { Scale, Color } from "chroma-js"
import { Syntax, ThemeSyntax, SyntaxHighlightStyle } from "./syntax"
export { Syntax, ThemeSyntax, SyntaxHighlightStyle }
import {
ThemeConfig,
ThemeAppearance,
ThemeConfigInputColors,
} from "./theme_config"
import { get_ramps } from "./ramps"
import { syntaxStyle } from "./syntax"
import { Syntax } from "../types/syntax"
export interface Theme {
name: string
is_light: boolean
/**
* App background, other elements that should sit directly on top of the background.
*/
* App background, other elements that should sit directly on top of the background.
*/
lowest: Layer
/**
* Panels, tabs, other UI surfaces that sit on top of the background.
*/
* Panels, tabs, other UI surfaces that sit on top of the background.
*/
middle: Layer
/**
* Editors like code buffers, conversation editors, etc.
*/
* Editors like code buffers, conversation editors, etc.
*/
highest: Layer
ramps: RampSet
@ -31,7 +31,7 @@ export interface Theme {
modal_shadow: Shadow
players: Players
syntax?: Partial<ThemeSyntax>
syntax: Syntax
}
export interface Meta {
@ -115,12 +115,7 @@ export interface Style {
}
export function create_theme(theme: ThemeConfig): Theme {
const {
name,
appearance,
input_color,
override: { syntax },
} = theme
const { name, appearance, input_color } = theme
const is_light = appearance === ThemeAppearance.Light
const color_ramps: ThemeConfigInputColors = input_color
@ -162,6 +157,11 @@ export function create_theme(theme: ThemeConfig): Theme {
"7": player(ramps.yellow),
}
const syntax = syntaxStyle(
ramps,
theme.override.syntax ? theme.override.syntax : {}
)
return {
name,
is_light,

View file

@ -1,325 +1,45 @@
import deepmerge from "deepmerge"
import { FontWeight, font_weights, useTheme } from "../common"
import chroma from "chroma-js"
import { font_weights, ThemeConfigInputSyntax, RampSet } from "../common"
import { Syntax, SyntaxHighlightStyle, allSyntaxKeys } from "../types/syntax"
export interface SyntaxHighlightStyle {
color?: string
weight?: FontWeight
underline?: boolean
italic?: boolean
}
// Apply defaults to any missing syntax properties that are not defined manually
function apply_defaults(
ramps: RampSet,
syntax_highlights: Partial<Syntax>
): Syntax {
const restKeys: (keyof Syntax)[] = allSyntaxKeys.filter(
(key) => !syntax_highlights[key]
)
export interface Syntax {
// == Text Styles ====== /
comment: SyntaxHighlightStyle
// elixir: doc comment
"comment.doc": SyntaxHighlightStyle
primary: SyntaxHighlightStyle
predictive: SyntaxHighlightStyle
hint: SyntaxHighlightStyle
const completeSyntax: Syntax = {} as Syntax
// === Formatted Text ====== /
emphasis: SyntaxHighlightStyle
"emphasis.strong": SyntaxHighlightStyle
title: SyntaxHighlightStyle
link_uri: SyntaxHighlightStyle
link_text: SyntaxHighlightStyle
/** md: indented_code_block, fenced_code_block, code_span */
"text.literal": SyntaxHighlightStyle
const defaults: SyntaxHighlightStyle = {
color: ramps.neutral(1).hex(),
}
// == Punctuation ====== /
punctuation: SyntaxHighlightStyle
/** Example: `(`, `[`, `{`...*/
"punctuation.bracket": SyntaxHighlightStyle
/**., ;*/
"punctuation.delimiter": SyntaxHighlightStyle
// js, ts: ${, } in a template literal
// yaml: *, &, ---, ...
"punctuation.special": SyntaxHighlightStyle
// md: list_marker_plus, list_marker_dot, etc
"punctuation.list_marker": SyntaxHighlightStyle
// == Strings ====== /
string: SyntaxHighlightStyle
// css: color_value
// js: this, super
// toml: offset_date_time, local_date_time...
"string.special": SyntaxHighlightStyle
// elixir: atom, quoted_atom, keyword, quoted_keyword
// ruby: simple_symbol, delimited_symbol...
"string.special.symbol"?: SyntaxHighlightStyle
// elixir, python, yaml...: escape_sequence
"string.escape"?: SyntaxHighlightStyle
// Regular expressions
"string.regex"?: SyntaxHighlightStyle
// == Types ====== /
// We allow Function here because all JS objects literals have this property
constructor: SyntaxHighlightStyle | Function // eslint-disable-line @typescript-eslint/ban-types
variant: SyntaxHighlightStyle
type: SyntaxHighlightStyle
// js: predefined_type
"type.builtin"?: SyntaxHighlightStyle
// == Values
variable: SyntaxHighlightStyle
// this, ...
// css: -- (var(--foo))
// lua: self
"variable.special"?: SyntaxHighlightStyle
// c: statement_identifier,
label: SyntaxHighlightStyle
// css: tag_name, nesting_selector, universal_selector...
tag: SyntaxHighlightStyle
// css: attribute, pseudo_element_selector (tag_name),
attribute: SyntaxHighlightStyle
// css: class_name, property_name, namespace_name...
property: SyntaxHighlightStyle
// true, false, null, nullptr
constant: SyntaxHighlightStyle
// css: @media, @import, @supports...
// js: declare, implements, interface, keyof, public...
keyword: SyntaxHighlightStyle
// note: js enum is currently defined as a keyword
enum: SyntaxHighlightStyle
// -, --, ->, !=, &&, ||, <=...
operator: SyntaxHighlightStyle
number: SyntaxHighlightStyle
boolean: SyntaxHighlightStyle
// elixir: __MODULE__, __DIR__, __ENV__, etc
// go: nil, iota
"constant.builtin"?: SyntaxHighlightStyle
// == Functions ====== /
function: SyntaxHighlightStyle
// lua: assert, error, loadfile, tostring, unpack...
"function.builtin"?: SyntaxHighlightStyle
// go: call_expression, method_declaration
// js: call_expression, method_definition, pair (key, arrow function)
// rust: function_item name: (identifier)
"function.definition"?: SyntaxHighlightStyle
// rust: macro_definition name: (identifier)
"function.special.definition"?: SyntaxHighlightStyle
"function.method"?: SyntaxHighlightStyle
// ruby: identifier/"defined?" // Nate note: I don't fully understand this one.
"function.method.builtin"?: SyntaxHighlightStyle
// == Unsorted ====== /
// lua: hash_bang_line
preproc: SyntaxHighlightStyle
// elixir, python: interpolation (ex: foo in ${foo})
// js: template_substitution
embedded: SyntaxHighlightStyle
}
export type ThemeSyntax = Partial<Syntax>
const default_syntax_highlight_style: Omit<SyntaxHighlightStyle, "color"> = {
weight: "normal",
underline: false,
italic: false,
}
function build_default_syntax(): Syntax {
const theme = useTheme()
// Make a temporary object that is allowed to be missing
// the "color" property for each style
const syntax: {
[key: string]: Omit<SyntaxHighlightStyle, "color">
} = {}
// then spread the default to each style
for (const key of Object.keys({} as Syntax)) {
syntax[key as keyof Syntax] = {
...default_syntax_highlight_style,
for (const key of restKeys) {
{
completeSyntax[key] = {
...defaults,
}
}
}
// Mix the neutral and blue colors to get a
// predictive color distinct from any other color in the theme
const predictive = chroma
.mix(
theme.ramps.neutral(0.4).hex(),
theme.ramps.blue(0.4).hex(),
0.45,
"lch"
)
.hex()
// Mix the neutral and green colors to get a
// hint color distinct from any other color in the theme
const hint = chroma
.mix(
theme.ramps.neutral(0.6).hex(),
theme.ramps.blue(0.4).hex(),
0.45,
"lch"
)
.hex()
const mergedBaseSyntax = Object.assign(completeSyntax, syntax_highlights)
const color = {
primary: theme.ramps.neutral(1).hex(),
comment: theme.ramps.neutral(0.71).hex(),
punctuation: theme.ramps.neutral(0.86).hex(),
predictive: predictive,
hint: hint,
emphasis: theme.ramps.blue(0.5).hex(),
string: theme.ramps.orange(0.5).hex(),
function: theme.ramps.yellow(0.5).hex(),
type: theme.ramps.cyan(0.5).hex(),
constructor: theme.ramps.blue(0.5).hex(),
variant: theme.ramps.blue(0.5).hex(),
property: theme.ramps.blue(0.5).hex(),
enum: theme.ramps.orange(0.5).hex(),
operator: theme.ramps.orange(0.5).hex(),
number: theme.ramps.green(0.5).hex(),
boolean: theme.ramps.green(0.5).hex(),
constant: theme.ramps.green(0.5).hex(),
keyword: theme.ramps.blue(0.5).hex(),
}
// Then assign colors and use Syntax to enforce each style getting it's own color
const default_syntax: Syntax = {
...syntax,
comment: {
color: color.comment,
},
"comment.doc": {
color: color.comment,
},
primary: {
color: color.primary,
},
predictive: {
color: color.predictive,
italic: true,
},
hint: {
color: color.hint,
weight: font_weights.bold,
},
emphasis: {
color: color.emphasis,
},
"emphasis.strong": {
color: color.emphasis,
weight: font_weights.bold,
},
title: {
color: color.primary,
weight: font_weights.bold,
},
link_uri: {
color: theme.ramps.green(0.5).hex(),
underline: true,
},
link_text: {
color: theme.ramps.orange(0.5).hex(),
italic: true,
},
"text.literal": {
color: color.string,
},
punctuation: {
color: color.punctuation,
},
"punctuation.bracket": {
color: color.punctuation,
},
"punctuation.delimiter": {
color: color.punctuation,
},
"punctuation.special": {
color: theme.ramps.neutral(0.86).hex(),
},
"punctuation.list_marker": {
color: color.punctuation,
},
string: {
color: color.string,
},
"string.special": {
color: color.string,
},
"string.special.symbol": {
color: color.string,
},
"string.escape": {
color: color.comment,
},
"string.regex": {
color: color.string,
},
constructor: {
color: theme.ramps.blue(0.5).hex(),
},
variant: {
color: theme.ramps.blue(0.5).hex(),
},
type: {
color: color.type,
},
variable: {
color: color.primary,
},
label: {
color: theme.ramps.blue(0.5).hex(),
},
tag: {
color: theme.ramps.blue(0.5).hex(),
},
attribute: {
color: theme.ramps.blue(0.5).hex(),
},
property: {
color: theme.ramps.blue(0.5).hex(),
},
constant: {
color: color.constant,
},
keyword: {
color: color.keyword,
},
enum: {
color: color.enum,
},
operator: {
color: color.operator,
},
number: {
color: color.number,
},
boolean: {
color: color.boolean,
},
function: {
color: color.function,
},
preproc: {
color: color.primary,
},
embedded: {
color: color.primary,
},
}
return default_syntax
return mergedBaseSyntax
}
export function build_syntax(): Syntax {
const theme = useTheme()
const default_syntax: Syntax = build_default_syntax()
if (!theme.syntax) {
return default_syntax
}
const syntax = deepmerge<Syntax, Partial<ThemeSyntax>>(
default_syntax,
theme.syntax,
// Merge the base syntax with the theme syntax overrides
// This is a deep merge, so any nested properties will be merged as well
// This allows for a theme to only override a single property of a syntax highlight style
const merge_syntax = (
baseSyntax: Syntax,
theme_syntax_overrides: ThemeConfigInputSyntax
): Syntax => {
return deepmerge<Syntax, ThemeConfigInputSyntax>(
baseSyntax,
theme_syntax_overrides,
{
arrayMerge: (destinationArray, sourceArray) => [
...destinationArray,
@ -327,6 +47,49 @@ export function build_syntax(): Syntax {
],
}
)
return syntax
}
/** Returns a complete Syntax object of the combined styles of a theme's syntax overrides and the default syntax styles */
export const syntaxStyle = (
ramps: RampSet,
theme_syntax_overrides: ThemeConfigInputSyntax
): Syntax => {
const syntax_highlights: Partial<Syntax> = {
comment: { color: ramps.neutral(0.71).hex() },
"comment.doc": { color: ramps.neutral(0.71).hex() },
primary: { color: ramps.neutral(1).hex() },
emphasis: { color: ramps.blue(0.5).hex() },
"emphasis.strong": {
color: ramps.blue(0.5).hex(),
weight: font_weights.bold,
},
link_uri: { color: ramps.green(0.5).hex(), underline: true },
link_text: { color: ramps.orange(0.5).hex(), italic: true },
"text.literal": { color: ramps.orange(0.5).hex() },
punctuation: { color: ramps.neutral(0.86).hex() },
"punctuation.bracket": { color: ramps.neutral(0.86).hex() },
"punctuation.special": { color: ramps.neutral(0.86).hex() },
"punctuation.delimiter": { color: ramps.neutral(0.86).hex() },
"punctuation.list_marker": { color: ramps.neutral(0.86).hex() },
string: { color: ramps.orange(0.5).hex() },
"string.special": { color: ramps.orange(0.5).hex() },
"string.special.symbol": { color: ramps.orange(0.5).hex() },
"string.escape": { color: ramps.neutral(0.71).hex() },
"string.regex": { color: ramps.orange(0.5).hex() },
"method.constructor": { color: ramps.blue(0.5).hex() },
type: { color: ramps.cyan(0.5).hex() },
label: { color: ramps.blue(0.5).hex() },
attribute: { color: ramps.blue(0.5).hex() },
property: { color: ramps.blue(0.5).hex() },
constant: { color: ramps.green(0.5).hex() },
keyword: { color: ramps.blue(0.5).hex() },
operator: { color: ramps.orange(0.5).hex() },
number: { color: ramps.green(0.5).hex() },
boolean: { color: ramps.green(0.5).hex() },
function: { color: ramps.yellow(0.5).hex() },
}
const baseSyntax = apply_defaults(ramps, syntax_highlights)
const mergedSyntax = merge_syntax(baseSyntax, theme_syntax_overrides)
return mergedSyntax
}

View file

@ -1,5 +1,5 @@
import { Scale, Color } from "chroma-js"
import { Syntax } from "./syntax"
import { SyntaxHighlightStyle, SyntaxProperty } from "../types/syntax"
interface ThemeMeta {
/** The name of the theme */
@ -55,7 +55,9 @@ export type ThemeConfigInputColorsKeys = keyof ThemeConfigInputColors
* }
* ```
*/
export type ThemeConfigInputSyntax = Partial<Syntax>
export type ThemeConfigInputSyntax = Partial<
Record<SyntaxProperty, Partial<SyntaxHighlightStyle>>
>
interface ThemeConfigOverrides {
syntax: ThemeConfigInputSyntax

View file

@ -4,17 +4,13 @@ import {
SingleOtherToken,
TokenTypes,
} from "@tokens-studio/types"
import {
Shadow,
SyntaxHighlightStyle,
ThemeSyntax,
} from "../create_theme"
import { Shadow } from "../create_theme"
import { LayerToken, layer_token } from "./layer"
import { PlayersToken, players_token } from "./players"
import { color_token } from "./token"
import { Syntax } from "../syntax"
import editor from "../../style_tree/editor"
import { useTheme } from "../../../src/common"
import { Syntax, SyntaxHighlightStyle } from "../../types/syntax"
interface ThemeTokens {
name: SingleOtherToken
@ -51,7 +47,7 @@ const modal_shadow_token = (): SingleBoxShadowToken => {
return create_shadow_token(shadow, "modal_shadow")
}
type ThemeSyntaxColorTokens = Record<keyof ThemeSyntax, SingleColorToken>
type ThemeSyntaxColorTokens = Record<keyof Syntax, SingleColorToken>
function syntax_highlight_style_color_tokens(
syntax: Syntax

View file

@ -1,4 +1,8 @@
import { ThemeLicenseType, ThemeSyntax, ThemeFamilyMeta } from "../../common"
import {
ThemeLicenseType,
ThemeFamilyMeta,
ThemeConfigInputSyntax,
} from "../../common"
export interface Variant {
colors: {
@ -29,7 +33,7 @@ export const meta: ThemeFamilyMeta = {
"https://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave/",
}
export const build_syntax = (variant: Variant): ThemeSyntax => {
export const build_syntax = (variant: Variant): ThemeConfigInputSyntax => {
const { colors } = variant
return {
primary: { color: colors.base06 },
@ -50,7 +54,6 @@ export const build_syntax = (variant: Variant): ThemeSyntax => {
property: { color: colors.base08 },
variable: { color: colors.base06 },
"variable.special": { color: colors.base0E },
variant: { color: colors.base0A },
keyword: { color: colors.base0E },
}
}

View file

@ -3,8 +3,8 @@ import {
chroma,
color_ramp,
ThemeLicenseType,
ThemeSyntax,
ThemeFamilyMeta,
ThemeConfigInputSyntax,
} from "../../common"
export const ayu = {
@ -27,7 +27,7 @@ export const build_theme = (t: typeof dark, light: boolean) => {
purple: t.syntax.constant.hex(),
}
const syntax: ThemeSyntax = {
const syntax: ThemeConfigInputSyntax = {
constant: { color: t.syntax.constant.hex() },
"string.regex": { color: t.syntax.regexp.hex() },
string: { color: t.syntax.string.hex() },
@ -61,7 +61,7 @@ export const build_theme = (t: typeof dark, light: boolean) => {
}
}
export const build_syntax = (t: typeof dark): ThemeSyntax => {
export const build_syntax = (t: typeof dark): ThemeConfigInputSyntax => {
return {
constant: { color: t.syntax.constant.hex() },
"string.regex": { color: t.syntax.regexp.hex() },

View file

@ -4,8 +4,8 @@ import {
ThemeAppearance,
ThemeLicenseType,
ThemeConfig,
ThemeSyntax,
ThemeFamilyMeta,
ThemeConfigInputSyntax,
} from "../../common"
const meta: ThemeFamilyMeta = {
@ -214,7 +214,7 @@ const build_variant = (variant: Variant): ThemeConfig => {
magenta: color_ramp(chroma(variant.colors.gray)),
}
const syntax: ThemeSyntax = {
const syntax: ThemeConfigInputSyntax = {
primary: { color: neutral[is_light ? 0 : 8] },
"text.literal": { color: colors.blue },
comment: { color: colors.gray },
@ -229,7 +229,7 @@ const build_variant = (variant: Variant): ThemeConfig => {
"string.special.symbol": { color: colors.aqua },
"string.regex": { color: colors.orange },
type: { color: colors.yellow },
enum: { color: colors.orange },
// enum: { color: colors.orange },
tag: { color: colors.aqua },
constant: { color: colors.yellow },
keyword: { color: colors.red },

View file

@ -54,7 +54,6 @@ export const theme: ThemeConfig = {
syntax: {
boolean: { color: color.orange },
comment: { color: color.grey },
enum: { color: color.red },
"emphasis.strong": { color: color.orange },
function: { color: color.blue },
keyword: { color: color.purple },
@ -73,8 +72,7 @@ export const theme: ThemeConfig = {
"text.literal": { color: color.green },
type: { color: color.teal },
"variable.special": { color: color.orange },
variant: { color: color.blue },
constructor: { color: color.blue },
"method.constructor": { color: color.blue },
},
},
}

View file

@ -55,7 +55,6 @@ export const theme: ThemeConfig = {
syntax: {
boolean: { color: color.orange },
comment: { color: color.grey },
enum: { color: color.red },
"emphasis.strong": { color: color.orange },
function: { color: color.blue },
keyword: { color: color.purple },
@ -73,7 +72,6 @@ export const theme: ThemeConfig = {
"text.literal": { color: color.green },
type: { color: color.teal },
"variable.special": { color: color.orange },
variant: { color: color.blue },
},
},
}

View file

@ -1,4 +1,4 @@
import { ThemeSyntax } from "../../common"
import { ThemeConfigInputSyntax } from "../../common"
export const color = {
default: {
@ -54,7 +54,7 @@ export const color = {
},
}
export const syntax = (c: typeof color.default): Partial<ThemeSyntax> => {
export const syntax = (c: typeof color.default): ThemeConfigInputSyntax => {
return {
comment: { color: c.muted },
operator: { color: c.pine },

View file

@ -0,0 +1,111 @@
import fs from "fs"
import path from "path"
import readline from "readline"
function escapeTypeName(name: string): string {
return `'${name.replace("@", "").toLowerCase()}'`
}
const generatedNote = `// This file is generated by extract_syntax_types.ts
// Do not edit this file directly
// It is generated from the highlight.scm files in the zed crate
// To regenerate this file manually:
// 'npm run extract-syntax-types' from ./styles`
const defaultTextProperty = ` /** Default text color */
| 'primary'`
const main = async () => {
const pathFromRoot = "crates/zed/src/languages"
const directoryPath = path.join(__dirname, "../../../", pathFromRoot)
const stylesMap: Record<string, Set<string>> = {}
const propertyLanguageMap: Record<string, Set<string>> = {}
const processFile = async (filePath: string, language: string) => {
const fileStream = fs.createReadStream(filePath)
const rl = readline.createInterface({
input: fileStream,
crlfDelay: Infinity,
})
for await (const line of rl) {
const cleanedLine = line.replace(/"@[a-zA-Z0-9_.]*"/g, "")
const match = cleanedLine.match(/@(\w+\.*)*/g)
if (match) {
match.forEach((property) => {
const formattedProperty = escapeTypeName(property)
// Only add non-empty properties
if (formattedProperty !== "''") {
if (!propertyLanguageMap[formattedProperty]) {
propertyLanguageMap[formattedProperty] = new Set()
}
propertyLanguageMap[formattedProperty].add(language)
}
})
}
}
}
const directories = fs
.readdirSync(directoryPath, { withFileTypes: true })
.filter((dirent) => dirent.isDirectory())
.map((dirent) => dirent.name)
for (const dir of directories) {
const highlightsFilePath = path.join(
directoryPath,
dir,
"highlights.scm"
)
if (fs.existsSync(highlightsFilePath)) {
await processFile(highlightsFilePath, dir)
}
}
for (const [language, properties] of Object.entries(stylesMap)) {
console.log(`${language}: ${Array.from(properties).join(", ")}`)
}
const sortedProperties = Object.entries(propertyLanguageMap).sort(
([propA], [propB]) => propA.localeCompare(propB)
)
const outStream = fs.createWriteStream(path.join(__dirname, "syntax.ts"))
let allProperties = ""
const syntaxKeys = []
for (const [property, languages] of sortedProperties) {
let languagesArray = Array.from(languages)
const moreThanSeven = languagesArray.length > 7
// Limit to the first 7 languages, append "..." if more than 7
languagesArray = languagesArray.slice(0, 7)
if (moreThanSeven) {
languagesArray.push("...")
}
const languagesString = languagesArray.join(", ")
const comment = `/** ${languagesString} */`
allProperties += ` ${comment}\n | ${property} \n`
syntaxKeys.push(property)
}
outStream.write(`${generatedNote}
export type SyntaxHighlightStyle = {
color: string,
fade_out?: number,
italic?: boolean,
underline?: boolean,
weight?: string,
}
export type Syntax = Record<SyntaxProperty, SyntaxHighlightStyle>
export type SyntaxOverride = Partial<Syntax>
export type SyntaxProperty = \n${defaultTextProperty}\n\n${allProperties}
export const allSyntaxKeys: SyntaxProperty[] = [\n ${syntaxKeys.join(
",\n "
)}\n]`)
outStream.end()
}
main().catch(console.error)

202
styles/src/types/syntax.ts Normal file
View file

@ -0,0 +1,202 @@
// This file is generated by extract_syntax_types.ts
// Do not edit this file directly
// It is generated from the highlight.scm files in the zed crate
// To regenerate this file manually:
// 'npm run extract-syntax-types' from ./styles
export type SyntaxHighlightStyle = {
color: string
fade_out?: number
italic?: boolean
underline?: boolean
weight?: string
}
export type Syntax = Record<SyntaxProperty, SyntaxHighlightStyle>
export type SyntaxOverride = Partial<Syntax>
export type SyntaxProperty =
/** Default text color */
| "primary"
/** elixir */
| "__attribute__"
/** elixir */
| "__name__"
/** elixir */
| "_sigil_name"
/** css, heex, lua */
| "attribute"
/** javascript, lua, tsx, typescript, yaml */
| "boolean"
/** elixir */
| "comment.doc"
/** elixir */
| "comment.unused"
/** bash, c, cpp, css, elixir, elm, erb, ... */
| "comment"
/** elixir, go, javascript, lua, php, python, racket, ... */
| "constant.builtin"
/** bash, c, cpp, elixir, elm, glsl, heex, ... */
| "constant"
/** glsl */
| "delimiter"
/** bash, elixir, javascript, python, ruby, tsx, typescript */
| "embedded"
/** markdown */
| "emphasis.strong"
/** markdown */
| "emphasis"
/** go, python, racket, ruby, scheme */
| "escape"
/** lua */
| "field"
/** lua, php, python */
| "function.builtin"
/** elm, lua, rust */
| "function.definition"
/** ruby */
| "function.method.builtin"
/** go, javascript, php, python, ruby, rust, tsx, ... */
| "function.method"
/** rust */
| "function.special.definition"
/** c, cpp, glsl, rust */
| "function.special"
/** bash, c, cpp, css, elixir, elm, glsl, ... */
| "function"
/** elm */
| "identifier"
/** glsl */
| "keyword.function"
/** bash, c, cpp, css, elixir, elm, erb, ... */
| "keyword"
/** c, cpp, glsl */
| "label"
/** markdown */
| "link_text"
/** markdown */
| "link_uri"
/** lua, php, tsx, typescript */
| "method.constructor"
/** lua */
| "method"
/** heex */
| "module"
/** svelte */
| "none"
/** bash, c, cpp, css, elixir, glsl, go, ... */
| "number"
/** bash, c, cpp, css, elixir, elm, glsl, ... */
| "operator"
/** lua */
| "parameter"
/** lua */
| "preproc"
/** bash, c, cpp, css, glsl, go, html, ... */
| "property"
/** c, cpp, elixir, elm, heex, html, javascript, ... */
| "punctuation.bracket"
/** c, cpp, css, elixir, elm, heex, javascript, ... */
| "punctuation.delimiter"
/** markdown */
| "punctuation.list_marker"
/** elixir, javascript, python, ruby, tsx, typescript, yaml */
| "punctuation.special"
/** elixir */
| "punctuation"
/** glsl */
| "storageclass"
/** elixir, elm, yaml */
| "string.escape"
/** elixir, javascript, racket, ruby, tsx, typescript */
| "string.regex"
/** elixir, ruby */
| "string.special.symbol"
/** css, elixir, toml */
| "string.special"
/** bash, c, cpp, css, elixir, elm, glsl, ... */
| "string"
/** svelte */
| "tag.delimiter"
/** css, heex, php, svelte */
| "tag"
/** markdown */
| "text.literal"
/** markdown */
| "title"
/** javascript, php, rust, tsx, typescript */
| "type.builtin"
/** glsl */
| "type.qualifier"
/** c, cpp, css, elixir, elm, glsl, go, ... */
| "type"
/** glsl, php */
| "variable.builtin"
/** cpp, css, javascript, lua, racket, ruby, rust, ... */
| "variable.special"
/** c, cpp, elm, glsl, go, javascript, lua, ... */
| "variable"
export const allSyntaxKeys: SyntaxProperty[] = [
"__attribute__",
"__name__",
"_sigil_name",
"attribute",
"boolean",
"comment.doc",
"comment.unused",
"comment",
"constant.builtin",
"constant",
"delimiter",
"embedded",
"emphasis.strong",
"emphasis",
"escape",
"field",
"function.builtin",
"function.definition",
"function.method.builtin",
"function.method",
"function.special.definition",
"function.special",
"function",
"identifier",
"keyword.function",
"keyword",
"label",
"link_text",
"link_uri",
"method.constructor",
"method",
"module",
"none",
"number",
"operator",
"parameter",
"preproc",
"property",
"punctuation.bracket",
"punctuation.delimiter",
"punctuation.list_marker",
"punctuation.special",
"punctuation",
"storageclass",
"string.escape",
"string.regex",
"string.special.symbol",
"string.special",
"string",
"tag.delimiter",
"tag",
"text.literal",
"title",
"type.builtin",
"type.qualifier",
"type",
"variable.builtin",
"variable.special",
"variable",
]

View file

@ -24,7 +24,5 @@
"useUnknownInCatchVariables": false,
"baseUrl": "."
},
"exclude": [
"node_modules"
]
"exclude": ["node_modules"]
}