@otto-code/highlight 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/colors.d.ts +4 -0
- package/dist/colors.js +53 -0
- package/dist/highlighter.d.ts +4 -0
- package/dist/highlighter.js +97 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +6 -0
- package/dist/parsers.d.ts +5 -0
- package/dist/parsers.js +85 -0
- package/dist/symbols.d.ts +15 -0
- package/dist/symbols.js +87 -0
- package/dist/themes.d.ts +12 -0
- package/dist/themes.js +257 -0
- package/dist/types.d.ts +12 -0
- package/dist/types.js +2 -0
- package/package.json +54 -0
package/dist/colors.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { DiffBackgroundColors, HighlightStyle } from "./types.js";
|
|
2
|
+
export declare const darkHighlightColors: Record<HighlightStyle, string> & DiffBackgroundColors;
|
|
3
|
+
export declare const lightHighlightColors: Record<HighlightStyle, string> & DiffBackgroundColors;
|
|
4
|
+
//# sourceMappingURL=colors.d.ts.map
|
package/dist/colors.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
export const darkHighlightColors = {
|
|
2
|
+
keyword: "#ff7b72",
|
|
3
|
+
comment: "#8b949e",
|
|
4
|
+
string: "#a5d6ff",
|
|
5
|
+
number: "#79c0ff",
|
|
6
|
+
literal: "#79c0ff",
|
|
7
|
+
function: "#d2a8ff",
|
|
8
|
+
definition: "#d2a8ff",
|
|
9
|
+
class: "#ffa657",
|
|
10
|
+
type: "#ff7b72",
|
|
11
|
+
tag: "#7ee787",
|
|
12
|
+
attribute: "#79c0ff",
|
|
13
|
+
property: "#79c0ff",
|
|
14
|
+
variable: "#c9d1d9",
|
|
15
|
+
operator: "#79c0ff",
|
|
16
|
+
punctuation: "#c9d1d9",
|
|
17
|
+
regexp: "#a5d6ff",
|
|
18
|
+
escape: "#79c0ff",
|
|
19
|
+
meta: "#8b949e",
|
|
20
|
+
heading: "#79c0ff",
|
|
21
|
+
link: "#a5d6ff",
|
|
22
|
+
diffAdded: "rgba(46, 160, 67, 0.15)",
|
|
23
|
+
diffRemoved: "rgba(248, 81, 73, 0.1)",
|
|
24
|
+
diffAddedEmphasis: "rgba(46, 160, 67, 0.4)",
|
|
25
|
+
diffRemovedEmphasis: "rgba(248, 81, 73, 0.35)",
|
|
26
|
+
};
|
|
27
|
+
export const lightHighlightColors = {
|
|
28
|
+
keyword: "#cf222e",
|
|
29
|
+
comment: "#6e7781",
|
|
30
|
+
string: "#0a3069",
|
|
31
|
+
number: "#0550ae",
|
|
32
|
+
literal: "#0550ae",
|
|
33
|
+
function: "#8250df",
|
|
34
|
+
definition: "#8250df",
|
|
35
|
+
class: "#953800",
|
|
36
|
+
type: "#cf222e",
|
|
37
|
+
tag: "#116329",
|
|
38
|
+
attribute: "#0550ae",
|
|
39
|
+
property: "#0550ae",
|
|
40
|
+
variable: "#24292f",
|
|
41
|
+
operator: "#0550ae",
|
|
42
|
+
punctuation: "#24292f",
|
|
43
|
+
regexp: "#0a3069",
|
|
44
|
+
escape: "#0550ae",
|
|
45
|
+
meta: "#6e7781",
|
|
46
|
+
heading: "#0550ae",
|
|
47
|
+
link: "#0a3069",
|
|
48
|
+
diffAdded: "rgba(46, 160, 67, 0.15)",
|
|
49
|
+
diffRemoved: "rgba(248, 81, 73, 0.1)",
|
|
50
|
+
diffAddedEmphasis: "rgba(46, 160, 67, 0.4)",
|
|
51
|
+
diffRemovedEmphasis: "rgba(248, 81, 73, 0.35)",
|
|
52
|
+
};
|
|
53
|
+
//# sourceMappingURL=colors.js.map
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { HighlightToken } from "./types.js";
|
|
2
|
+
export declare function highlightCode(code: string, filename: string): HighlightToken[][];
|
|
3
|
+
export declare function highlightLine(line: string, filename: string): HighlightToken[];
|
|
4
|
+
//# sourceMappingURL=highlighter.d.ts.map
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { highlightTree, tagHighlighter, tags } from "@lezer/highlight";
|
|
2
|
+
import { getParserForFile } from "./parsers.js";
|
|
3
|
+
const highlighter = tagHighlighter([
|
|
4
|
+
{ tag: tags.keyword, class: "keyword" },
|
|
5
|
+
{ tag: tags.controlKeyword, class: "keyword" },
|
|
6
|
+
{ tag: tags.operatorKeyword, class: "keyword" },
|
|
7
|
+
{ tag: tags.definitionKeyword, class: "keyword" },
|
|
8
|
+
{ tag: tags.moduleKeyword, class: "keyword" },
|
|
9
|
+
{ tag: tags.comment, class: "comment" },
|
|
10
|
+
{ tag: tags.lineComment, class: "comment" },
|
|
11
|
+
{ tag: tags.blockComment, class: "comment" },
|
|
12
|
+
{ tag: tags.docComment, class: "comment" },
|
|
13
|
+
{ tag: tags.string, class: "string" },
|
|
14
|
+
{ tag: tags.special(tags.string), class: "string" },
|
|
15
|
+
{ tag: tags.number, class: "number" },
|
|
16
|
+
{ tag: tags.integer, class: "number" },
|
|
17
|
+
{ tag: tags.float, class: "number" },
|
|
18
|
+
{ tag: tags.bool, class: "literal" },
|
|
19
|
+
{ tag: tags.null, class: "literal" },
|
|
20
|
+
{ tag: tags.function(tags.variableName), class: "function" },
|
|
21
|
+
{ tag: tags.function(tags.propertyName), class: "function" },
|
|
22
|
+
{ tag: tags.definition(tags.variableName), class: "definition" },
|
|
23
|
+
{ tag: tags.definition(tags.propertyName), class: "definition" },
|
|
24
|
+
{ tag: tags.definition(tags.function(tags.variableName)), class: "definition" },
|
|
25
|
+
{ tag: tags.className, class: "class" },
|
|
26
|
+
{ tag: tags.definition(tags.className), class: "class" },
|
|
27
|
+
{ tag: tags.typeName, class: "type" },
|
|
28
|
+
{ tag: tags.tagName, class: "tag" },
|
|
29
|
+
{ tag: tags.attributeName, class: "attribute" },
|
|
30
|
+
{ tag: tags.attributeValue, class: "string" },
|
|
31
|
+
{ tag: tags.propertyName, class: "property" },
|
|
32
|
+
{ tag: tags.variableName, class: "variable" },
|
|
33
|
+
{ tag: tags.local(tags.variableName), class: "variable" },
|
|
34
|
+
{ tag: tags.special(tags.variableName), class: "variable" },
|
|
35
|
+
{ tag: tags.operator, class: "operator" },
|
|
36
|
+
{ tag: tags.punctuation, class: "punctuation" },
|
|
37
|
+
{ tag: tags.bracket, class: "punctuation" },
|
|
38
|
+
{ tag: tags.separator, class: "punctuation" },
|
|
39
|
+
{ tag: tags.regexp, class: "regexp" },
|
|
40
|
+
{ tag: tags.escape, class: "escape" },
|
|
41
|
+
{ tag: tags.meta, class: "meta" },
|
|
42
|
+
{ tag: tags.heading, class: "heading" },
|
|
43
|
+
{ tag: tags.link, class: "link" },
|
|
44
|
+
{ tag: tags.url, class: "link" },
|
|
45
|
+
]);
|
|
46
|
+
export function highlightCode(code, filename) {
|
|
47
|
+
const parser = getParserForFile(filename);
|
|
48
|
+
if (!parser) {
|
|
49
|
+
return code.split("\n").map((line) => [{ text: line, style: null }]);
|
|
50
|
+
}
|
|
51
|
+
const tree = parser.parse(code);
|
|
52
|
+
const lines = code.split("\n");
|
|
53
|
+
const result = [];
|
|
54
|
+
for (let i = 0; i < lines.length; i++) {
|
|
55
|
+
result.push([]);
|
|
56
|
+
}
|
|
57
|
+
// Build a map of character positions to styles
|
|
58
|
+
const styleMap = Array.from({ length: code.length }, () => null);
|
|
59
|
+
highlightTree(tree, highlighter, (from, to, classes) => {
|
|
60
|
+
for (let i = from; i < to && i < styleMap.length; i++) {
|
|
61
|
+
styleMap[i] = classes;
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
// Convert style map to tokens per line
|
|
65
|
+
let pos = 0;
|
|
66
|
+
for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
|
|
67
|
+
const line = lines[lineIndex];
|
|
68
|
+
if (line.length === 0) {
|
|
69
|
+
result[lineIndex].push({ text: "", style: null });
|
|
70
|
+
pos++; // skip newline
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
let currentToken = { text: "", style: styleMap[pos] };
|
|
74
|
+
for (let i = 0; i < line.length; i++) {
|
|
75
|
+
const charStyle = styleMap[pos + i];
|
|
76
|
+
if (charStyle === currentToken.style) {
|
|
77
|
+
currentToken.text += line[i];
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
if (currentToken.text) {
|
|
81
|
+
result[lineIndex].push(currentToken);
|
|
82
|
+
}
|
|
83
|
+
currentToken = { text: line[i], style: charStyle };
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if (currentToken.text) {
|
|
87
|
+
result[lineIndex].push(currentToken);
|
|
88
|
+
}
|
|
89
|
+
pos += line.length + 1; // +1 for newline
|
|
90
|
+
}
|
|
91
|
+
return result;
|
|
92
|
+
}
|
|
93
|
+
export function highlightLine(line, filename) {
|
|
94
|
+
const result = highlightCode(line, filename);
|
|
95
|
+
return result[0] ?? [{ text: line, style: null }];
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=highlighter.js.map
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export type { HighlightStyle, HighlightToken } from "./types.js";
|
|
2
|
+
export { getParserForFile, isLanguageSupported, getSupportedExtensions } from "./parsers.js";
|
|
3
|
+
export { highlightCode, highlightLine } from "./highlighter.js";
|
|
4
|
+
export { extractSymbols } from "./symbols.js";
|
|
5
|
+
export type { CodeSymbol, SymbolKind } from "./symbols.js";
|
|
6
|
+
export { darkHighlightColors, lightHighlightColors } from "./colors.js";
|
|
7
|
+
export type { SyntaxThemeId, SyntaxThemeOption, SyntaxColors } from "./themes.js";
|
|
8
|
+
export { SYNTAX_THEME_IDS, SYNTAX_THEME_OPTIONS, isSyntaxThemeId, resolveSyntaxColors, } from "./themes.js";
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { getParserForFile, isLanguageSupported, getSupportedExtensions } from "./parsers.js";
|
|
2
|
+
export { highlightCode, highlightLine } from "./highlighter.js";
|
|
3
|
+
export { extractSymbols } from "./symbols.js";
|
|
4
|
+
export { darkHighlightColors, lightHighlightColors } from "./colors.js";
|
|
5
|
+
export { SYNTAX_THEME_IDS, SYNTAX_THEME_OPTIONS, isSyntaxThemeId, resolveSyntaxColors, } from "./themes.js";
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Parser } from "@lezer/common";
|
|
2
|
+
export declare function getParserForFile(filename: string): Parser | null;
|
|
3
|
+
export declare function isLanguageSupported(filename: string): boolean;
|
|
4
|
+
export declare function getSupportedExtensions(): string[];
|
|
5
|
+
//# sourceMappingURL=parsers.d.ts.map
|
package/dist/parsers.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { StreamLanguage } from "@codemirror/language";
|
|
2
|
+
import { dart } from "@codemirror/legacy-modes/mode/clike";
|
|
3
|
+
import { swift } from "@codemirror/legacy-modes/mode/swift";
|
|
4
|
+
import { parser as jsParser } from "@lezer/javascript";
|
|
5
|
+
import { parser as jsonParser } from "@lezer/json";
|
|
6
|
+
import { parser as cssParser } from "@lezer/css";
|
|
7
|
+
import { parser as cppParser } from "@lezer/cpp";
|
|
8
|
+
import { parser as goParser } from "@lezer/go";
|
|
9
|
+
import { parser as htmlParser } from "@lezer/html";
|
|
10
|
+
import { parser as javaParser } from "@lezer/java";
|
|
11
|
+
import { parser as pythonParser } from "@lezer/python";
|
|
12
|
+
import { parser as markdownParser } from "@lezer/markdown";
|
|
13
|
+
import { parser as phpParser } from "@lezer/php";
|
|
14
|
+
import { parser as rustParser } from "@lezer/rust";
|
|
15
|
+
import { parser as xmlParser } from "@lezer/xml";
|
|
16
|
+
import { parser as yamlParser } from "@lezer/yaml";
|
|
17
|
+
import { csharpLanguage } from "@replit/codemirror-lang-csharp";
|
|
18
|
+
import { parser as elixirParser } from "lezer-elixir";
|
|
19
|
+
const parsersByExtension = {
|
|
20
|
+
// JavaScript/TypeScript
|
|
21
|
+
js: jsParser,
|
|
22
|
+
jsx: jsParser.configure({ dialect: "jsx" }),
|
|
23
|
+
ts: jsParser.configure({ dialect: "ts" }),
|
|
24
|
+
tsx: jsParser.configure({ dialect: "ts jsx" }),
|
|
25
|
+
mjs: jsParser,
|
|
26
|
+
cjs: jsParser,
|
|
27
|
+
// C / C++ / Objective-C
|
|
28
|
+
c: cppParser,
|
|
29
|
+
h: cppParser,
|
|
30
|
+
cc: cppParser,
|
|
31
|
+
cpp: cppParser,
|
|
32
|
+
cxx: cppParser,
|
|
33
|
+
hpp: cppParser,
|
|
34
|
+
hxx: cppParser,
|
|
35
|
+
m: cppParser,
|
|
36
|
+
mm: cppParser,
|
|
37
|
+
// JSON
|
|
38
|
+
json: jsonParser,
|
|
39
|
+
// CSS
|
|
40
|
+
css: cssParser,
|
|
41
|
+
scss: cssParser,
|
|
42
|
+
// HTML
|
|
43
|
+
html: htmlParser,
|
|
44
|
+
htm: htmlParser,
|
|
45
|
+
// XML
|
|
46
|
+
xml: xmlParser,
|
|
47
|
+
// Java
|
|
48
|
+
java: javaParser,
|
|
49
|
+
// Python
|
|
50
|
+
py: pythonParser,
|
|
51
|
+
// Go
|
|
52
|
+
go: goParser,
|
|
53
|
+
// PHP
|
|
54
|
+
php: phpParser,
|
|
55
|
+
// YAML
|
|
56
|
+
yaml: yamlParser,
|
|
57
|
+
yml: yamlParser,
|
|
58
|
+
// Rust
|
|
59
|
+
rs: rustParser,
|
|
60
|
+
// Swift
|
|
61
|
+
swift: StreamLanguage.define(swift).parser,
|
|
62
|
+
// Dart
|
|
63
|
+
dart: StreamLanguage.define(dart).parser,
|
|
64
|
+
// C#
|
|
65
|
+
cs: csharpLanguage.parser,
|
|
66
|
+
// Elixir
|
|
67
|
+
ex: elixirParser,
|
|
68
|
+
exs: elixirParser,
|
|
69
|
+
// Markdown
|
|
70
|
+
md: markdownParser,
|
|
71
|
+
mdx: markdownParser,
|
|
72
|
+
};
|
|
73
|
+
export function getParserForFile(filename) {
|
|
74
|
+
const ext = filename.split(".").pop()?.toLowerCase();
|
|
75
|
+
if (!ext)
|
|
76
|
+
return null;
|
|
77
|
+
return parsersByExtension[ext] ?? null;
|
|
78
|
+
}
|
|
79
|
+
export function isLanguageSupported(filename) {
|
|
80
|
+
return getParserForFile(filename) !== null;
|
|
81
|
+
}
|
|
82
|
+
export function getSupportedExtensions() {
|
|
83
|
+
return Object.keys(parsersByExtension);
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=parsers.js.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type SymbolKind = "function" | "class" | "type" | "variable" | "property";
|
|
2
|
+
export interface CodeSymbol {
|
|
3
|
+
name: string;
|
|
4
|
+
kind: SymbolKind;
|
|
5
|
+
/** 1-based line of the identifier. */
|
|
6
|
+
line: number;
|
|
7
|
+
/** 1-based column of the identifier. */
|
|
8
|
+
column: number;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Extract definition symbols from source. Returns [] for unsupported
|
|
12
|
+
* languages (there is no parser) rather than throwing.
|
|
13
|
+
*/
|
|
14
|
+
export declare function extractSymbols(code: string, filename: string): CodeSymbol[];
|
|
15
|
+
//# sourceMappingURL=symbols.d.ts.map
|
package/dist/symbols.js
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { highlightTree, tagHighlighter, tags } from "@lezer/highlight";
|
|
2
|
+
import { getParserForFile } from "./parsers.js";
|
|
3
|
+
// Order matters: more specific tags are listed first so a function definition
|
|
4
|
+
// is classified as "function", not the broader "variable".
|
|
5
|
+
const definitionHighlighter = tagHighlighter([
|
|
6
|
+
{ tag: tags.definition(tags.function(tags.variableName)), class: "function" },
|
|
7
|
+
{ tag: tags.function(tags.definition(tags.variableName)), class: "function" },
|
|
8
|
+
{ tag: tags.definition(tags.className), class: "class" },
|
|
9
|
+
{ tag: tags.definition(tags.propertyName), class: "property" },
|
|
10
|
+
{ tag: tags.definition(tags.variableName), class: "variable" },
|
|
11
|
+
{ tag: tags.definition(tags.typeName), class: "type" },
|
|
12
|
+
{ tag: tags.className, class: "class" },
|
|
13
|
+
{ tag: tags.typeName, class: "type" },
|
|
14
|
+
]);
|
|
15
|
+
const CLASS_TO_KIND = {
|
|
16
|
+
function: "function",
|
|
17
|
+
class: "class",
|
|
18
|
+
type: "type",
|
|
19
|
+
variable: "variable",
|
|
20
|
+
property: "property",
|
|
21
|
+
};
|
|
22
|
+
function buildLineStarts(code) {
|
|
23
|
+
const starts = [0];
|
|
24
|
+
for (let index = 0; index < code.length; index += 1) {
|
|
25
|
+
if (code.charCodeAt(index) === 10) {
|
|
26
|
+
starts.push(index + 1);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return starts;
|
|
30
|
+
}
|
|
31
|
+
// Binary search for the 0-based line index whose start is <= offset.
|
|
32
|
+
function lineIndexForOffset(lineStarts, offset) {
|
|
33
|
+
let low = 0;
|
|
34
|
+
let high = lineStarts.length - 1;
|
|
35
|
+
while (low < high) {
|
|
36
|
+
const mid = (low + high + 1) >> 1;
|
|
37
|
+
if (lineStarts[mid] <= offset) {
|
|
38
|
+
low = mid;
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
high = mid - 1;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return low;
|
|
45
|
+
}
|
|
46
|
+
const IDENTIFIER = /^[A-Za-z_$][\w$]*$/;
|
|
47
|
+
/**
|
|
48
|
+
* Extract definition symbols from source. Returns [] for unsupported
|
|
49
|
+
* languages (there is no parser) rather than throwing.
|
|
50
|
+
*/
|
|
51
|
+
export function extractSymbols(code, filename) {
|
|
52
|
+
const parser = getParserForFile(filename);
|
|
53
|
+
if (!parser) {
|
|
54
|
+
return [];
|
|
55
|
+
}
|
|
56
|
+
const tree = parser.parse(code);
|
|
57
|
+
const lineStarts = buildLineStarts(code);
|
|
58
|
+
const symbols = [];
|
|
59
|
+
const seen = new Set();
|
|
60
|
+
highlightTree(tree, definitionHighlighter, (from, to, classes) => {
|
|
61
|
+
const kind = CLASS_TO_KIND[classes];
|
|
62
|
+
if (!kind) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const name = code.slice(from, to);
|
|
66
|
+
// Highlight ranges can cover punctuation or multi-token spans; keep only
|
|
67
|
+
// clean identifiers so the index stays name-addressable.
|
|
68
|
+
if (!IDENTIFIER.test(name)) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const lineIndex = lineIndexForOffset(lineStarts, from);
|
|
72
|
+
const dedupeKey = `${name} ${lineIndex} ${kind}`;
|
|
73
|
+
if (seen.has(dedupeKey)) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
seen.add(dedupeKey);
|
|
77
|
+
symbols.push({
|
|
78
|
+
name,
|
|
79
|
+
kind,
|
|
80
|
+
line: lineIndex + 1,
|
|
81
|
+
column: from - lineStarts[lineIndex] + 1,
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
symbols.sort((a, b) => a.line - b.line || a.column - b.column);
|
|
85
|
+
return symbols;
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=symbols.js.map
|
package/dist/themes.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { DiffBackgroundColors, HighlightStyle } from "./types.js";
|
|
2
|
+
export type SyntaxThemeId = "default" | "github" | "vscode" | "jetbrains" | "monokai" | "nightshade" | "neotokyo";
|
|
3
|
+
export declare const SYNTAX_THEME_IDS: readonly SyntaxThemeId[];
|
|
4
|
+
export interface SyntaxThemeOption {
|
|
5
|
+
id: SyntaxThemeId;
|
|
6
|
+
label: string;
|
|
7
|
+
}
|
|
8
|
+
export declare const SYNTAX_THEME_OPTIONS: readonly SyntaxThemeOption[];
|
|
9
|
+
export type SyntaxColors = Record<HighlightStyle, string> & DiffBackgroundColors;
|
|
10
|
+
export declare function isSyntaxThemeId(value: string): value is SyntaxThemeId;
|
|
11
|
+
export declare function resolveSyntaxColors(id: SyntaxThemeId, colorScheme: "light" | "dark"): SyntaxColors;
|
|
12
|
+
//# sourceMappingURL=themes.d.ts.map
|
package/dist/themes.js
ADDED
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import { darkHighlightColors, lightHighlightColors } from "./colors.js";
|
|
2
|
+
export const SYNTAX_THEME_IDS = [
|
|
3
|
+
"default",
|
|
4
|
+
"github",
|
|
5
|
+
"vscode",
|
|
6
|
+
"jetbrains",
|
|
7
|
+
"monokai",
|
|
8
|
+
"nightshade",
|
|
9
|
+
"neotokyo",
|
|
10
|
+
];
|
|
11
|
+
export const SYNTAX_THEME_OPTIONS = [
|
|
12
|
+
{ id: "default", label: "Default" },
|
|
13
|
+
{ id: "github", label: "GitHub" },
|
|
14
|
+
{ id: "vscode", label: "VS Code" },
|
|
15
|
+
{ id: "jetbrains", label: "JetBrains" },
|
|
16
|
+
{ id: "monokai", label: "Monokai" },
|
|
17
|
+
{ id: "nightshade", label: "Nightshade" },
|
|
18
|
+
{ id: "neotokyo", label: "Neotokyo" },
|
|
19
|
+
];
|
|
20
|
+
// Re-derives an rgba() string at a different alpha. Boosts each theme's diff
|
|
21
|
+
// row tints into their intraline emphasis pair without every theme authoring
|
|
22
|
+
// a second color for the same hue.
|
|
23
|
+
function withAlpha(rgbaColor, alpha) {
|
|
24
|
+
const match = rgbaColor.match(/^rgba\((\d+),\s*(\d+),\s*(\d+),/);
|
|
25
|
+
if (!match)
|
|
26
|
+
return rgbaColor;
|
|
27
|
+
const [, r, g, b] = match;
|
|
28
|
+
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
|
|
29
|
+
}
|
|
30
|
+
function expandRolePalette(r) {
|
|
31
|
+
return {
|
|
32
|
+
keyword: r.keyword,
|
|
33
|
+
comment: r.comment,
|
|
34
|
+
string: r.string,
|
|
35
|
+
number: r.number,
|
|
36
|
+
literal: r.number,
|
|
37
|
+
function: r.function,
|
|
38
|
+
definition: r.function,
|
|
39
|
+
class: r.type,
|
|
40
|
+
type: r.type,
|
|
41
|
+
tag: r.tag,
|
|
42
|
+
attribute: r.attribute,
|
|
43
|
+
property: r.attribute,
|
|
44
|
+
variable: r.base,
|
|
45
|
+
operator: r.operator,
|
|
46
|
+
punctuation: r.base,
|
|
47
|
+
regexp: r.string,
|
|
48
|
+
escape: r.number,
|
|
49
|
+
meta: r.comment,
|
|
50
|
+
heading: r.function,
|
|
51
|
+
link: r.string,
|
|
52
|
+
diffAdded: r.diffAdded,
|
|
53
|
+
diffRemoved: r.diffRemoved,
|
|
54
|
+
diffAddedEmphasis: withAlpha(r.diffAdded, 0.4),
|
|
55
|
+
diffRemovedEmphasis: withAlpha(r.diffRemoved, 0.35),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
// --- Default (high-contrast primary hues — the CGA-basic baseline) -------
|
|
59
|
+
const defaultLight = {
|
|
60
|
+
base: "#000000",
|
|
61
|
+
keyword: "#0000aa",
|
|
62
|
+
comment: "#666666",
|
|
63
|
+
string: "#aa0000",
|
|
64
|
+
number: "#aa00aa",
|
|
65
|
+
function: "#aa5500",
|
|
66
|
+
type: "#00aaaa",
|
|
67
|
+
tag: "#0000aa",
|
|
68
|
+
attribute: "#00aa00",
|
|
69
|
+
operator: "#000000",
|
|
70
|
+
diffAdded: "rgba(0, 128, 0, 0.12)",
|
|
71
|
+
diffRemoved: "rgba(170, 0, 0, 0.12)",
|
|
72
|
+
};
|
|
73
|
+
const defaultDark = {
|
|
74
|
+
base: "#ffffff",
|
|
75
|
+
keyword: "#5555ff",
|
|
76
|
+
comment: "#999999",
|
|
77
|
+
string: "#55ff55",
|
|
78
|
+
number: "#55ffff",
|
|
79
|
+
function: "#ffff55",
|
|
80
|
+
type: "#ff55ff",
|
|
81
|
+
tag: "#5555ff",
|
|
82
|
+
attribute: "#55ffff",
|
|
83
|
+
operator: "#ffffff",
|
|
84
|
+
diffAdded: "rgba(85, 255, 85, 0.18)",
|
|
85
|
+
diffRemoved: "rgba(255, 85, 85, 0.18)",
|
|
86
|
+
};
|
|
87
|
+
// --- VS Code (Light+ / Dark+) ---------------------------------------------
|
|
88
|
+
const vscodeLight = {
|
|
89
|
+
base: "#000000",
|
|
90
|
+
keyword: "#0000ff",
|
|
91
|
+
comment: "#008000",
|
|
92
|
+
string: "#a31515",
|
|
93
|
+
number: "#098658",
|
|
94
|
+
function: "#795e26",
|
|
95
|
+
type: "#267f99",
|
|
96
|
+
tag: "#800000",
|
|
97
|
+
attribute: "#e50000",
|
|
98
|
+
operator: "#000000",
|
|
99
|
+
diffAdded: "rgba(46, 125, 50, 0.14)",
|
|
100
|
+
diffRemoved: "rgba(198, 40, 40, 0.14)",
|
|
101
|
+
};
|
|
102
|
+
const vscodeDark = {
|
|
103
|
+
base: "#d4d4d4",
|
|
104
|
+
keyword: "#569cd6",
|
|
105
|
+
comment: "#6a9955",
|
|
106
|
+
string: "#ce9178",
|
|
107
|
+
number: "#b5cea8",
|
|
108
|
+
function: "#dcdcaa",
|
|
109
|
+
type: "#4ec9b0",
|
|
110
|
+
tag: "#569cd6",
|
|
111
|
+
attribute: "#9cdcfe",
|
|
112
|
+
operator: "#d4d4d4",
|
|
113
|
+
diffAdded: "rgba(75, 139, 31, 0.22)",
|
|
114
|
+
diffRemoved: "rgba(190, 17, 0, 0.22)",
|
|
115
|
+
};
|
|
116
|
+
// --- JetBrains (IntelliJ Light / Darcula) ---------------------------------
|
|
117
|
+
const jetbrainsLight = {
|
|
118
|
+
base: "#000000",
|
|
119
|
+
keyword: "#0033b3",
|
|
120
|
+
comment: "#8c8c8c",
|
|
121
|
+
string: "#067d17",
|
|
122
|
+
number: "#1750eb",
|
|
123
|
+
function: "#00627a",
|
|
124
|
+
type: "#20999d",
|
|
125
|
+
tag: "#3f7f7f",
|
|
126
|
+
attribute: "#660000",
|
|
127
|
+
operator: "#000000",
|
|
128
|
+
diffAdded: "rgba(56, 142, 60, 0.15)",
|
|
129
|
+
diffRemoved: "rgba(198, 40, 40, 0.15)",
|
|
130
|
+
};
|
|
131
|
+
const jetbrainsDark = {
|
|
132
|
+
base: "#a9b7c6",
|
|
133
|
+
keyword: "#cc7832",
|
|
134
|
+
comment: "#808080",
|
|
135
|
+
string: "#6a8759",
|
|
136
|
+
number: "#6897bb",
|
|
137
|
+
function: "#ffc66d",
|
|
138
|
+
type: "#b3ae60",
|
|
139
|
+
tag: "#e8bf6a",
|
|
140
|
+
attribute: "#a9b7c6",
|
|
141
|
+
operator: "#a9b7c6",
|
|
142
|
+
diffAdded: "rgba(46, 107, 62, 0.3)",
|
|
143
|
+
diffRemoved: "rgba(107, 46, 46, 0.3)",
|
|
144
|
+
};
|
|
145
|
+
// --- Monokai (Light / Dark) ------------------------------------------------
|
|
146
|
+
const monokaiLight = {
|
|
147
|
+
base: "#272822",
|
|
148
|
+
keyword: "#c4133b",
|
|
149
|
+
comment: "#75715e",
|
|
150
|
+
string: "#a68a0d",
|
|
151
|
+
number: "#7c3fb5",
|
|
152
|
+
function: "#4b8b1f",
|
|
153
|
+
type: "#0f83a3",
|
|
154
|
+
tag: "#c4133b",
|
|
155
|
+
attribute: "#4b8b1f",
|
|
156
|
+
operator: "#c4133b",
|
|
157
|
+
diffAdded: "rgba(75, 139, 31, 0.14)",
|
|
158
|
+
diffRemoved: "rgba(179, 37, 31, 0.14)",
|
|
159
|
+
};
|
|
160
|
+
const monokaiDark = {
|
|
161
|
+
base: "#f8f8f2",
|
|
162
|
+
keyword: "#f92672",
|
|
163
|
+
comment: "#75715e",
|
|
164
|
+
string: "#e6db74",
|
|
165
|
+
number: "#ae81ff",
|
|
166
|
+
function: "#a6e22e",
|
|
167
|
+
type: "#66d9ef",
|
|
168
|
+
tag: "#f92672",
|
|
169
|
+
attribute: "#a6e22e",
|
|
170
|
+
operator: "#f92672",
|
|
171
|
+
diffAdded: "rgba(166, 226, 46, 0.18)",
|
|
172
|
+
diffRemoved: "rgba(248, 53, 53, 0.18)",
|
|
173
|
+
};
|
|
174
|
+
// --- Nightshade (Light / Dark — gothic pink/purple/cyan, formerly "Dracula";
|
|
175
|
+
// renamed once it grew a light variant the original theme never had) --------
|
|
176
|
+
const nightshadeLight = {
|
|
177
|
+
base: "#282a36",
|
|
178
|
+
keyword: "#bd2f7a",
|
|
179
|
+
comment: "#6272a4",
|
|
180
|
+
string: "#8a7a1f",
|
|
181
|
+
number: "#7c4fd1",
|
|
182
|
+
function: "#1f9c4a",
|
|
183
|
+
type: "#0e93a8",
|
|
184
|
+
tag: "#bd2f7a",
|
|
185
|
+
attribute: "#1f9c4a",
|
|
186
|
+
operator: "#bd2f7a",
|
|
187
|
+
diffAdded: "rgba(31, 156, 74, 0.14)",
|
|
188
|
+
diffRemoved: "rgba(179, 54, 54, 0.14)",
|
|
189
|
+
};
|
|
190
|
+
const nightshadeDark = {
|
|
191
|
+
base: "#f8f8f2",
|
|
192
|
+
keyword: "#ff79c6",
|
|
193
|
+
comment: "#6272a4",
|
|
194
|
+
string: "#f1fa8c",
|
|
195
|
+
number: "#bd93f9",
|
|
196
|
+
function: "#50fa7b",
|
|
197
|
+
type: "#8be9fd",
|
|
198
|
+
tag: "#ff79c6",
|
|
199
|
+
attribute: "#50fa7b",
|
|
200
|
+
operator: "#ff79c6",
|
|
201
|
+
diffAdded: "rgba(80, 250, 123, 0.18)",
|
|
202
|
+
diffRemoved: "rgba(255, 85, 85, 0.18)",
|
|
203
|
+
};
|
|
204
|
+
// --- Neotokyo (Light / Dark — cyber yellow, hot pink, neon cyan) ----------
|
|
205
|
+
const neotokyoLight = {
|
|
206
|
+
base: "#1a1025",
|
|
207
|
+
keyword: "#c2188f",
|
|
208
|
+
comment: "#7a7a9c",
|
|
209
|
+
string: "#8a7600",
|
|
210
|
+
number: "#0089a3",
|
|
211
|
+
function: "#a3157a",
|
|
212
|
+
type: "#7b2fd4",
|
|
213
|
+
tag: "#c2188f",
|
|
214
|
+
attribute: "#0089a3",
|
|
215
|
+
operator: "#0089a3",
|
|
216
|
+
diffAdded: "rgba(31, 156, 26, 0.14)",
|
|
217
|
+
diffRemoved: "rgba(194, 31, 61, 0.14)",
|
|
218
|
+
};
|
|
219
|
+
const neotokyoDark = {
|
|
220
|
+
base: "#e4e4f4",
|
|
221
|
+
keyword: "#ff2ec4",
|
|
222
|
+
comment: "#6f6f94",
|
|
223
|
+
string: "#fcee0a",
|
|
224
|
+
number: "#0ff0fc",
|
|
225
|
+
function: "#ff6ec7",
|
|
226
|
+
type: "#b967ff",
|
|
227
|
+
tag: "#ff2ec4",
|
|
228
|
+
attribute: "#0ff0fc",
|
|
229
|
+
operator: "#0ff0fc",
|
|
230
|
+
diffAdded: "rgba(57, 255, 20, 0.18)",
|
|
231
|
+
diffRemoved: "rgba(255, 43, 78, 0.18)",
|
|
232
|
+
};
|
|
233
|
+
export function isSyntaxThemeId(value) {
|
|
234
|
+
return SYNTAX_THEME_IDS.includes(value);
|
|
235
|
+
}
|
|
236
|
+
// Resolve a theme id + the app's color scheme to a full token palette. Only the
|
|
237
|
+
// light/dark axis is coupled to the app; the theme brand is the user's choice.
|
|
238
|
+
export function resolveSyntaxColors(id, colorScheme) {
|
|
239
|
+
const dark = colorScheme === "dark";
|
|
240
|
+
switch (id) {
|
|
241
|
+
case "default":
|
|
242
|
+
return expandRolePalette(dark ? defaultDark : defaultLight);
|
|
243
|
+
case "github":
|
|
244
|
+
return dark ? darkHighlightColors : lightHighlightColors;
|
|
245
|
+
case "vscode":
|
|
246
|
+
return expandRolePalette(dark ? vscodeDark : vscodeLight);
|
|
247
|
+
case "jetbrains":
|
|
248
|
+
return expandRolePalette(dark ? jetbrainsDark : jetbrainsLight);
|
|
249
|
+
case "monokai":
|
|
250
|
+
return expandRolePalette(dark ? monokaiDark : monokaiLight);
|
|
251
|
+
case "nightshade":
|
|
252
|
+
return expandRolePalette(dark ? nightshadeDark : nightshadeLight);
|
|
253
|
+
case "neotokyo":
|
|
254
|
+
return expandRolePalette(dark ? neotokyoDark : neotokyoLight);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
//# sourceMappingURL=themes.js.map
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type HighlightStyle = "keyword" | "comment" | "string" | "number" | "literal" | "function" | "definition" | "class" | "type" | "tag" | "attribute" | "property" | "variable" | "operator" | "punctuation" | "regexp" | "escape" | "meta" | "heading" | "link";
|
|
2
|
+
export interface HighlightToken {
|
|
3
|
+
text: string;
|
|
4
|
+
style: HighlightStyle | null;
|
|
5
|
+
}
|
|
6
|
+
export interface DiffBackgroundColors {
|
|
7
|
+
diffAdded: string;
|
|
8
|
+
diffRemoved: string;
|
|
9
|
+
diffAddedEmphasis: string;
|
|
10
|
+
diffRemovedEmphasis: string;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@otto-code/highlight",
|
|
3
|
+
"version": "0.5.0",
|
|
4
|
+
"files": [
|
|
5
|
+
"dist",
|
|
6
|
+
"!dist/**/*.map"
|
|
7
|
+
],
|
|
8
|
+
"type": "module",
|
|
9
|
+
"main": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"source": "./src/index.ts",
|
|
15
|
+
"default": "./dist/index.js"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"publishConfig": {
|
|
19
|
+
"access": "public"
|
|
20
|
+
},
|
|
21
|
+
"scripts": {
|
|
22
|
+
"clean": "node ../../scripts/clean-package-dist.mjs",
|
|
23
|
+
"build": "tsc -p tsconfig.json --incremental false",
|
|
24
|
+
"build:clean": "npm run clean && npm run build",
|
|
25
|
+
"prepack": "npm run build:clean",
|
|
26
|
+
"test": "vitest run",
|
|
27
|
+
"typecheck": "tsgo --noEmit"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@codemirror/language": "^6.12.3",
|
|
31
|
+
"@codemirror/legacy-modes": "^6.5.3",
|
|
32
|
+
"@lezer/common": "^1.5.0",
|
|
33
|
+
"@lezer/cpp": "^1.1.5",
|
|
34
|
+
"@lezer/css": "^1.3.0",
|
|
35
|
+
"@lezer/go": "^1.0.1",
|
|
36
|
+
"@lezer/highlight": "^1.2.3",
|
|
37
|
+
"@lezer/html": "^1.3.13",
|
|
38
|
+
"@lezer/java": "^1.1.3",
|
|
39
|
+
"@lezer/javascript": "^1.5.4",
|
|
40
|
+
"@lezer/json": "^1.0.3",
|
|
41
|
+
"@lezer/markdown": "^1.6.2",
|
|
42
|
+
"@lezer/php": "^1.0.5",
|
|
43
|
+
"@lezer/python": "^1.1.18",
|
|
44
|
+
"@lezer/rust": "^1.0.2",
|
|
45
|
+
"@lezer/xml": "^1.0.6",
|
|
46
|
+
"@lezer/yaml": "^1.0.4",
|
|
47
|
+
"@replit/codemirror-lang-csharp": "^6.2.0",
|
|
48
|
+
"lezer-elixir": "^1.1.2"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"typescript": "^5.9.2",
|
|
52
|
+
"vitest": "^4.1.6"
|
|
53
|
+
}
|
|
54
|
+
}
|