mirror of
https://github.com/zed-industries/zed.git
synced 2024-11-07 20:39:04 +03:00
Extract syntax highlighting properties from tree-sitter highlight queries
This commit is contained in:
parent
46dd717857
commit
85f193dd09
@ -158,7 +158,7 @@
|
||||
[
|
||||
"{"
|
||||
"}"
|
||||
] @constructor)
|
||||
] @method.constructor)
|
||||
|
||||
;; Functions
|
||||
|
||||
|
@ -47,8 +47,8 @@
|
||||
((name) @constant.builtin
|
||||
(#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"))
|
||||
|
@ -43,8 +43,8 @@
|
||||
|
||||
; Special identifiers
|
||||
|
||||
((identifier) @constructor
|
||||
(#match? @constructor "^[A-Z]"))
|
||||
((identifier) @method.constructor
|
||||
(#match? @method.constructor "^[A-Z]"))
|
||||
|
||||
((identifier) @type
|
||||
(#match? @type "^[A-Z]"))
|
||||
|
@ -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: {
|
||||
@ -314,6 +326,6 @@ export default function editor(): any {
|
||||
color: border_color(layer),
|
||||
},
|
||||
},
|
||||
syntax,
|
||||
syntax: theme.syntax,
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
import { Scale, Color } from "chroma-js"
|
||||
import { Syntax, ThemeSyntax, SyntaxHighlightStyle } from "./syntax"
|
||||
export { Syntax, ThemeSyntax, SyntaxHighlightStyle }
|
||||
import {
|
||||
ThemeConfig,
|
||||
ThemeAppearance,
|
||||
ThemeConfigInputColors,
|
||||
ThemeConfigInputColors
|
||||
} from "./theme_config"
|
||||
import { get_ramps } from "./ramps"
|
||||
import { syntaxStyle } from "./syntax"
|
||||
import { Syntax } from "../types/syntax"
|
||||
|
||||
export interface Theme {
|
||||
name: string
|
||||
@ -31,7 +31,7 @@ export interface Theme {
|
||||
modal_shadow: Shadow
|
||||
|
||||
players: Players
|
||||
syntax?: Partial<ThemeSyntax>
|
||||
syntax: Syntax
|
||||
}
|
||||
|
||||
export interface Meta {
|
||||
@ -119,7 +119,6 @@ export function create_theme(theme: ThemeConfig): Theme {
|
||||
name,
|
||||
appearance,
|
||||
input_color,
|
||||
override: { syntax },
|
||||
} = theme
|
||||
|
||||
const is_light = appearance === ThemeAppearance.Light
|
||||
@ -162,6 +161,8 @@ 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,
|
||||
|
@ -1,332 +1,80 @@
|
||||
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])
|
||||
|
||||
const completeSyntax: Syntax = {} as Syntax
|
||||
|
||||
const defaults: SyntaxHighlightStyle = {
|
||||
color: ramps.neutral(1).hex(),
|
||||
}
|
||||
|
||||
export interface Syntax {
|
||||
// == Text Styles ====== /
|
||||
comment: SyntaxHighlightStyle
|
||||
// elixir: doc comment
|
||||
"comment.doc": SyntaxHighlightStyle
|
||||
primary: SyntaxHighlightStyle
|
||||
predictive: SyntaxHighlightStyle
|
||||
hint: SyntaxHighlightStyle
|
||||
|
||||
// === 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
|
||||
|
||||
// == 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,
|
||||
}
|
||||
}
|
||||
|
||||
// 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 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
|
||||
}
|
||||
|
||||
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,
|
||||
for (const key of restKeys) {
|
||||
{
|
||||
completeSyntax[key] = {
|
||||
...defaults,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const mergedBaseSyntax = Object.assign(completeSyntax, syntax_highlights)
|
||||
|
||||
return mergedBaseSyntax
|
||||
}
|
||||
|
||||
// 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,
|
||||
...sourceArray,
|
||||
],
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
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() },
|
||||
variable: { color: ramps.neutral(1).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() },
|
||||
preproc: { color: ramps.neutral(1).hex() },
|
||||
embedded: { color: ramps.neutral(1).hex() },
|
||||
}
|
||||
|
||||
const baseSyntax = apply_defaults(ramps, syntax_highlights)
|
||||
const mergedSyntax = merge_syntax(baseSyntax, theme_syntax_overrides)
|
||||
return mergedSyntax
|
||||
}
|
||||
|
@ -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,7 @@ export type ThemeConfigInputColorsKeys = keyof ThemeConfigInputColors
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export type ThemeConfigInputSyntax = Partial<Syntax>
|
||||
export type ThemeConfigInputSyntax = Partial<Record<SyntaxProperty, Partial<SyntaxHighlightStyle>>>
|
||||
|
||||
interface ThemeConfigOverrides {
|
||||
syntax: ThemeConfigInputSyntax
|
||||
|
@ -6,15 +6,13 @@ import {
|
||||
} from "@tokens-studio/types"
|
||||
import {
|
||||
Shadow,
|
||||
SyntaxHighlightStyle,
|
||||
ThemeSyntax,
|
||||
} 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 +49,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
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { ThemeLicenseType, ThemeSyntax, ThemeFamilyMeta } from "../../common"
|
||||
import { ThemeLicenseType, ThemeFamilyMeta, ThemeConfigInputSyntax } from "../../common"
|
||||
|
||||
export interface Variant {
|
||||
colors: {
|
||||
@ -29,7 +29,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 +50,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 },
|
||||
}
|
||||
}
|
||||
|
@ -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() },
|
||||
|
@ -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 },
|
||||
|
@ -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 },
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -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 },
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -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 },
|
||||
|
102
styles/src/types/extract_syntax_types.ts
Normal file
102
styles/src/types/extract_syntax_types.ts
Normal file
@ -0,0 +1,102 @@
|
||||
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)
|
203
styles/src/types/syntax.ts
Normal file
203
styles/src/types/syntax.ts
Normal file
@ -0,0 +1,203 @@
|
||||
// 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'
|
||||
]
|
Loading…
Reference in New Issue
Block a user