Revert "Extract syntax highlighting properties from tree-sitter highlight queries (#2797)"
This reverts commit45c635872b, reversing changes made tof2b82369f2.
This commit is contained in:
+312
-75
@@ -1,45 +1,325 @@
|
||||
import deepmerge from "deepmerge"
|
||||
import { font_weights, ThemeConfigInputSyntax, RampSet } from "../common"
|
||||
import { Syntax, SyntaxHighlightStyle, allSyntaxKeys } from "../types/syntax"
|
||||
import { FontWeight, font_weights, useTheme } from "../common"
|
||||
import chroma from "chroma-js"
|
||||
|
||||
// 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 SyntaxHighlightStyle {
|
||||
color?: string
|
||||
weight?: FontWeight
|
||||
underline?: boolean
|
||||
italic?: boolean
|
||||
}
|
||||
|
||||
const completeSyntax: Syntax = {} as Syntax
|
||||
export interface Syntax {
|
||||
// == Text Styles ====== /
|
||||
comment: SyntaxHighlightStyle
|
||||
// elixir: doc comment
|
||||
"comment.doc": SyntaxHighlightStyle
|
||||
primary: SyntaxHighlightStyle
|
||||
predictive: SyntaxHighlightStyle
|
||||
hint: SyntaxHighlightStyle
|
||||
|
||||
const defaults: SyntaxHighlightStyle = {
|
||||
color: ramps.neutral(1).hex(),
|
||||
}
|
||||
// === 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
|
||||
|
||||
for (const key of restKeys) {
|
||||
{
|
||||
completeSyntax[key] = {
|
||||
...defaults,
|
||||
}
|
||||
// == 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,
|
||||
}
|
||||
}
|
||||
|
||||
const mergedBaseSyntax = Object.assign(completeSyntax, syntax_highlights)
|
||||
// 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()
|
||||
|
||||
return mergedBaseSyntax
|
||||
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
|
||||
}
|
||||
|
||||
// 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,
|
||||
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,
|
||||
{
|
||||
arrayMerge: (destinationArray, sourceArray) => [
|
||||
...destinationArray,
|
||||
@@ -47,49 +327,6 @@ const merge_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
|
||||
return syntax
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user