@motionscript/code 0.1.0-alpha.3 → 0.1.0-alpha.5
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/CHANGELOG.md +45 -0
- package/LICENSE +201 -201
- package/NOTICE +48 -0
- package/README.md +161 -108
- package/dist/browser/THIRD_PARTY_LICENSES.txt +431 -0
- package/dist/browser/index.js +7 -6
- package/dist/browser/index.js.map +3 -3
- package/dist/browser/manifest.json +84 -2
- package/dist/code-range.d.ts +6 -0
- package/dist/code-range.d.ts.map +1 -1
- package/dist/code-range.js +8 -0
- package/dist/code-range.js.map +1 -1
- package/dist/diff.d.ts +14 -0
- package/dist/diff.d.ts.map +1 -1
- package/dist/diff.js +134 -2
- package/dist/diff.js.map +1 -1
- package/dist/engine.d.ts +1 -1
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +1 -1
- package/dist/engine.js.map +1 -1
- package/dist/highlight.d.ts +10 -2
- package/dist/highlight.d.ts.map +1 -1
- package/dist/highlight.js +40 -6
- package/dist/highlight.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/layout.js.map +1 -1
- package/dist/node.d.ts +42 -7
- package/dist/node.d.ts.map +1 -1
- package/dist/node.js +174 -47
- package/dist/node.js.map +1 -1
- package/dist/nodes.js.map +1 -1
- package/dist/render.d.ts +6 -1
- package/dist/render.d.ts.map +1 -1
- package/dist/render.js +59 -0
- package/dist/render.js.map +1 -1
- package/dist/style.d.ts +3 -3
- package/dist/style.d.ts.map +1 -1
- package/dist/style.js +10 -6
- package/dist/style.js.map +1 -1
- package/dist/tokens.d.ts.map +1 -1
- package/dist/tokens.js +5 -1
- package/dist/tokens.js.map +1 -1
- package/dist/transitions.d.ts +19 -1
- package/dist/transitions.d.ts.map +1 -1
- package/dist/transitions.js.map +1 -1
- package/package.json +7 -5
- package/registry.json +6 -6
- package/src/code-range.ts +165 -156
- package/src/diff.ts +351 -216
- package/src/engine.ts +21 -21
- package/src/highlight.ts +340 -291
- package/src/index.ts +3 -3
- package/src/layout.ts +157 -157
- package/src/node.ts +1038 -904
- package/src/nodes.ts +18 -18
- package/src/render.ts +312 -247
- package/src/style.ts +255 -251
- package/src/tokens.ts +79 -75
- package/src/transitions.ts +204 -184
package/dist/highlight.js
CHANGED
|
@@ -43,6 +43,25 @@ const LANGUAGE_ALIASES = {
|
|
|
43
43
|
yml: "yaml",
|
|
44
44
|
shell: "javascript", // no shell grammar bundled; fall back rather than throw
|
|
45
45
|
};
|
|
46
|
+
/** Names that mean "no grammar, on purpose": drawn as plain text without a warning. */
|
|
47
|
+
const PLAIN_LANGUAGES = new Set(["", "text", "plaintext"]);
|
|
48
|
+
const warned = new Set();
|
|
49
|
+
/** One `console.warn` per `kind:name` for the life of the process, so a listing redrawn every frame says it once. */
|
|
50
|
+
function warnOnce(kind, name, message) {
|
|
51
|
+
const key = `${kind}:${name}`;
|
|
52
|
+
if (warned.has(key))
|
|
53
|
+
return;
|
|
54
|
+
warned.add(key);
|
|
55
|
+
console.warn(`[Code] ${message}`);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* The source as the highlighter and the commands see it: lines joined by `\n`.
|
|
59
|
+
* A `\r\n` (or a lone `\r`) from a file or a clipboard would otherwise survive
|
|
60
|
+
* as a character at the end of a line, measured and drawn as a token.
|
|
61
|
+
*/
|
|
62
|
+
export function normalizeSource(code) {
|
|
63
|
+
return code.indexOf("\r") === -1 ? code : code.replace(/\r\n?/g, "\n");
|
|
64
|
+
}
|
|
46
65
|
function resolveLanguageKey(language) {
|
|
47
66
|
const key = language.toLowerCase();
|
|
48
67
|
return LANGUAGE_ALIASES[key] ?? key;
|
|
@@ -64,12 +83,16 @@ export function registerCodeTheme(style) {
|
|
|
64
83
|
/**
|
|
65
84
|
* Resolve a theme reference (a registered name, or a CodeHighlightStyle object)
|
|
66
85
|
* to a concrete style. Unknown names fall back to the Motion Canvas default so a
|
|
67
|
-
* stray theme string never throws.
|
|
86
|
+
* stray theme string never throws, with one warning per name.
|
|
68
87
|
*/
|
|
69
88
|
export function resolveTheme(theme) {
|
|
70
89
|
if (typeof theme !== "string")
|
|
71
90
|
return theme;
|
|
72
|
-
|
|
91
|
+
const style = themesByName.get(theme);
|
|
92
|
+
if (style)
|
|
93
|
+
return style;
|
|
94
|
+
warnOnce("theme", theme, `unknown theme "${theme}"; using "${DefaultHighlightStyle.name}". Built-in themes: ${Object.keys(BUILTIN_THEMES).join(", ")}; register others with registerCodeTheme.`);
|
|
95
|
+
return DefaultHighlightStyle;
|
|
73
96
|
}
|
|
74
97
|
/** Has `language` finished loading its parser? */
|
|
75
98
|
function isLanguageLoaded(language) {
|
|
@@ -80,7 +103,9 @@ function isLanguageLoaded(language) {
|
|
|
80
103
|
* but kept in the signature for API parity with the former Shiki implementation).
|
|
81
104
|
* Resolves once every requested language's parser is available. Unknown languages
|
|
82
105
|
* resolve without loading anything — {@link canHighlight} stays false for them and
|
|
83
|
-
* the node renders them as plain text.
|
|
106
|
+
* the node renders them as plain text, with one warning per language. A grammar
|
|
107
|
+
* whose import is rejected is reported the same way and is tried again by the
|
|
108
|
+
* next call.
|
|
84
109
|
*/
|
|
85
110
|
export function ensureHighlighter(_themes = DEFAULT_THEMES, langs = DEFAULT_LANGS) {
|
|
86
111
|
const jobs = [];
|
|
@@ -89,8 +114,13 @@ export function ensureHighlighter(_themes = DEFAULT_THEMES, langs = DEFAULT_LANG
|
|
|
89
114
|
if (loadedParsers.has(key))
|
|
90
115
|
continue;
|
|
91
116
|
const loader = LANGUAGE_LOADERS[key];
|
|
92
|
-
if (!loader)
|
|
93
|
-
|
|
117
|
+
if (!loader) {
|
|
118
|
+
// Unsupported language; leave it unhighlighted, and say so.
|
|
119
|
+
if (!PLAIN_LANGUAGES.has(key)) {
|
|
120
|
+
warnOnce("language", key, `no grammar for language "${lang}"; drawing it as plain text. Supported: ${Object.keys(LANGUAGE_LOADERS).join(", ")} (aliases: ${Object.keys(LANGUAGE_ALIASES).join(", ")}).`);
|
|
121
|
+
}
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
94
124
|
let job = inFlightLangs.get(key);
|
|
95
125
|
if (!job) {
|
|
96
126
|
job = loader()
|
|
@@ -98,7 +128,10 @@ export function ensureHighlighter(_themes = DEFAULT_THEMES, langs = DEFAULT_LANG
|
|
|
98
128
|
loadedParsers.set(key, parser);
|
|
99
129
|
return parser;
|
|
100
130
|
})
|
|
101
|
-
.catch(() =>
|
|
131
|
+
.catch((error) => {
|
|
132
|
+
warnOnce("load", key, `could not load the "${lang}" grammar; drawing it as plain text: ${error instanceof Error ? error.message : String(error)}`);
|
|
133
|
+
return null;
|
|
134
|
+
})
|
|
102
135
|
.finally(() => inFlightLangs.delete(key));
|
|
103
136
|
inFlightLangs.set(key, job);
|
|
104
137
|
}
|
|
@@ -203,6 +236,7 @@ function tokenizeCode(code, language) {
|
|
|
203
236
|
* uncolored line per source line if the parser isn't loaded.
|
|
204
237
|
*/
|
|
205
238
|
export function highlightToTokens(code, language, theme = DefaultHighlightStyle) {
|
|
239
|
+
code = normalizeSource(code);
|
|
206
240
|
const style = resolveTheme(theme);
|
|
207
241
|
const cache = prepareHighlight(code, language, style);
|
|
208
242
|
const lines = [[]];
|
package/dist/highlight.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"highlight.js","sourceRoot":"","sources":["../src/highlight.ts"],"names":[],"mappings":"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","sourcesContent":["import { Parser, Tree } from \"@lezer/common\";\nimport { highlightTree } from \"@lezer/highlight\";\nimport {\n BUILTIN_THEMES,\n CodeHighlightStyle,\n CodeTheme,\n DefaultHighlightStyle,\n compileStyle,\n} from \"./style\";\n\n/**\n * Lezer-backed syntax highlighting for the Code component, replacing the former\n * Shiki wiring. This mirrors Motion Canvas's `LezerHighlighter`:\n *\n * - {@link prepareHighlight} parses code once and builds a `from:to` → color map\n * by walking {@link highlightTree}.\n * - {@link tokenizeCode} splits code at parse-tree leaf boundaries.\n * - {@link highlightAt} resolves the color (and run length) for a character index.\n *\n * Parsers load lazily and asynchronously (dynamic import) so the bundle doesn't\n * pull in every grammar. The node's asset loader awaits {@link ensureHighlighter}\n * before tokenizing; until a parser resolves, callers fall back to plain text and\n * re-tokenize once {@link canHighlight} returns true.\n */\n\n/** Dynamic-import factories for each supported language → a Lezer {@link Parser}. */\nconst LANGUAGE_LOADERS: Record<string, () => Promise<Parser>> = {\n typescript: async () => (await import(\"@lezer/javascript\")).parser.configure({ dialect: \"ts\" }),\n tsx: async () => (await import(\"@lezer/javascript\")).parser.configure({ dialect: \"ts jsx\" }),\n javascript: async () => (await import(\"@lezer/javascript\")).parser,\n jsx: async () => (await import(\"@lezer/javascript\")).parser.configure({ dialect: \"jsx\" }),\n python: async () => (await import(\"@lezer/python\")).parser,\n json: async () => (await import(\"@lezer/json\")).parser,\n html: async () => (await import(\"@lezer/html\")).parser,\n css: async () => (await import(\"@lezer/css\")).parser,\n rust: async () => (await import(\"@lezer/rust\")).parser,\n go: async () => (await import(\"@lezer/go\")).parser,\n java: async () => (await import(\"@lezer/java\")).parser,\n cpp: async () => (await import(\"@lezer/cpp\")).parser,\n php: async () => (await import(\"@lezer/php\")).parser,\n markdown: async () => (await import(\"@lezer/markdown\")).parser,\n xml: async () => (await import(\"@lezer/xml\")).parser,\n yaml: async () => (await import(\"@lezer/yaml\")).parser,\n};\n\n// Aliases so common language strings resolve to a loader above.\nconst LANGUAGE_ALIASES: Record<string, string> = {\n ts: \"typescript\",\n js: \"javascript\",\n py: \"python\",\n \"c++\": \"cpp\",\n md: \"markdown\",\n yml: \"yaml\",\n shell: \"javascript\", // no shell grammar bundled; fall back rather than throw\n};\n\nfunction resolveLanguageKey(language: string): string {\n const key = language.toLowerCase();\n return LANGUAGE_ALIASES[key] ?? key;\n}\n\n// Loaded parsers and in-flight loads, keyed by resolved language key, so\n// concurrent Code nodes asking for the same language share one dynamic import.\nconst loadedParsers = new Map<string, Parser>();\nconst inFlightLangs = new Map<string, Promise<Parser | null>>();\n\nexport const DEFAULT_THEMES = [DefaultHighlightStyle.name];\nexport const DEFAULT_LANGS = [\"typescript\", \"javascript\", \"json\", \"python\"];\n\n// Theme registry, seeded with the built-ins (Motion Canvas default + GitHub\n// dark/light). The `theme` prop is a string name or a CodeHighlightStyle object;\n// apps can register additional styles by name and reference them by that name.\nconst themesByName = new Map<string, CodeHighlightStyle>(Object.entries(BUILTIN_THEMES));\n\n/** Register a custom {@link CodeHighlightStyle} so Code nodes can reference it by name. */\nexport function registerCodeTheme(style: CodeHighlightStyle): void {\n themesByName.set(style.name, style);\n}\n\n/**\n * Resolve a theme reference (a registered name, or a CodeHighlightStyle object)\n * to a concrete style. Unknown names fall back to the Motion Canvas default so a\n * stray theme string never throws.\n */\nexport function resolveTheme(theme: CodeTheme): CodeHighlightStyle {\n if (typeof theme !== \"string\") return theme;\n return themesByName.get(theme) ?? DefaultHighlightStyle;\n}\n\n/** Has `language` finished loading its parser? */\nfunction isLanguageLoaded(language: string): boolean {\n return loadedParsers.has(resolveLanguageKey(language));\n}\n\n/**\n * Load the parsers for `langs` (themes are synchronous, so they're a no-op here\n * but kept in the signature for API parity with the former Shiki implementation).\n * Resolves once every requested language's parser is available. Unknown languages\n * resolve without loading anything — {@link canHighlight} stays false for them and\n * the node renders them as plain text.\n */\nexport function ensureHighlighter(\n _themes: string[] = DEFAULT_THEMES,\n langs: string[] = DEFAULT_LANGS,\n): Promise<void> {\n const jobs: Promise<unknown>[] = [];\n\n for (const lang of langs) {\n const key = resolveLanguageKey(lang);\n if (loadedParsers.has(key)) continue;\n\n const loader = LANGUAGE_LOADERS[key];\n if (!loader) continue; // unsupported language; leave it unhighlighted\n\n let job = inFlightLangs.get(key);\n if (!job) {\n job = loader()\n .then(parser => {\n loadedParsers.set(key, parser);\n return parser;\n })\n .catch(() => null)\n .finally(() => inFlightLangs.delete(key));\n inFlightLangs.set(key, job);\n }\n jobs.push(job);\n }\n\n return jobs.length === 0 ? Promise.resolve() : Promise.all(jobs).then(() => undefined);\n}\n\n/**\n * Load a syntax-highlight language into the shared highlighter. Exposed so a Code\n * node's asset loader can run it on the timeline, and so apps can preload\n * languages explicitly. Returns once the parser is ready (or immediately for an\n * unsupported language). The `theme` arg is accepted for backwards compatibility.\n */\nexport async function loadCodeLanguage(language: string, _theme?: string): Promise<void> {\n await ensureHighlighter(DEFAULT_THEMES, [language]);\n}\n\nexport async function initSyntaxHighlighter(\n themes: string[] = DEFAULT_THEMES,\n langs: string[] = DEFAULT_LANGS,\n): Promise<void> {\n await ensureHighlighter(themes, langs);\n}\n\n/** True once `language` can be tokenized (its parser has loaded). */\nexport function canHighlight(language: string, _theme?: CodeTheme): boolean {\n return isLanguageLoaded(language);\n}\n\n/** A parsed-and-prepared highlight cache for one snapshot of code. */\ninterface HighlightCache {\n tree: Tree;\n code: string;\n // `${from}:${to}` node id → color, exactly as Motion Canvas keys it.\n colorLookup: Map<string, string>;\n}\n\nfunction nodeId(from: number, to: number): string {\n return `${from}:${to}`;\n}\n\n/**\n * Parse `code` and build the per-node color map. Mirrors Motion Canvas's\n * `LezerHighlighter.prepare`: for each highlighted range, walk the subtree and\n * record the color against every contained node's `from:to` id, so a later\n * {@link highlightAt} lookup by `resolveInner` index finds it.\n */\nfunction prepareHighlight(code: string, language: string, style: CodeHighlightStyle): HighlightCache | null {\n const parser = loadedParsers.get(resolveLanguageKey(language));\n if (!parser) return null;\n\n const tree = parser.parse(code);\n const highlighter = compileStyle(style);\n const colorLookup = new Map<string, string>();\n\n highlightTree(tree, highlighter, (from, to, classes) => {\n // tagHighlighter emits our color string as the \"class\".\n const color = classes;\n if (!color) return;\n const cursor = tree.cursorAt(from, 1);\n do {\n colorLookup.set(nodeId(cursor.from, cursor.to), color);\n } while (cursor.next() && cursor.to <= to);\n });\n\n return { tree, code, colorLookup };\n}\n\n/**\n * Resolve the color and run length for the token starting at `index`. Mirrors\n * Motion Canvas's `LezerHighlighter.highlight`: resolve the innermost node, look\n * up its color, and report how far the run extends (`skipAhead`).\n */\nfunction highlightAt(index: number, cache: HighlightCache): { color: string | null; skipAhead: number } {\n const node = cache.tree.resolveInner(index, 1);\n const color = cache.colorLookup.get(nodeId(node.from, node.to));\n if (color) {\n return { color, skipAhead: node.to - index };\n }\n // No color: skip past a childless (leaf) node so we don't re-resolve every char.\n const skipAhead = node.firstChild ? 0 : node.to - index;\n return { color: null, skipAhead };\n}\n\n/**\n * Split `code` into structural tokens at parse-tree leaf boundaries, including the\n * gaps between leaves (whitespace/punctuation). Mirrors Motion Canvas's\n * `LezerHighlighter.tokenize`; this segmentation is what the token-level\n * append/insert/erase/replace animations diff against, so matching it keeps the\n * animation behavior identical to Motion Canvas.\n */\nfunction tokenizeCode(code: string, language: string): string[] {\n const parser = loadedParsers.get(resolveLanguageKey(language));\n if (!parser) return [code];\n\n const tree = parser.parse(code);\n const cursor = tree.cursor();\n const tokens: string[] = [];\n let current = 0;\n\n do {\n if (!cursor.node.firstChild) {\n if (cursor.from > current) tokens.push(code.slice(current, cursor.from));\n if (cursor.from < cursor.to) tokens.push(code.slice(cursor.from, cursor.to));\n current = cursor.to;\n }\n } while (cursor.next());\n\n if (current < code.length) tokens.push(code.slice(current));\n return tokens;\n}\n\n/**\n * Tokenize `code` into per-line, colored tokens — the contract the rest of the\n * Code component consumes. Combines {@link tokenizeCode} (structural split) with\n * {@link highlightAt} (per-run color), then breaks tokens at newlines so each\n * output line is a row of single-line, single-color tokens.\n *\n * Callers must have checked {@link canHighlight} first; this returns a single\n * uncolored line per source line if the parser isn't loaded.\n */\nexport function highlightToTokens(\n code: string,\n language: string,\n theme: CodeTheme = DefaultHighlightStyle,\n): { content: string; color?: string }[][] {\n const style = resolveTheme(theme);\n const cache = prepareHighlight(code, language, style);\n\n const lines: { content: string; color?: string }[][] = [[]];\n const pushLine = () => lines.push([]);\n\n if (!cache) {\n // Parser unavailable: one uncolored token per source line.\n return code.split(\"\\n\").map(line => [{ content: line, color: style.defaultColor }]);\n }\n\n // Walk the structural tokens, coloring each by its starting index and\n // splitting on newlines so no token spans rows.\n let index = 0;\n for (const token of tokenizeCode(code, language)) {\n let offset = 0;\n while (offset < token.length) {\n const { color, skipAhead } = highlightAt(index + offset, cache);\n // Extend the run as far as the highlight says, but never past this\n // structural token and never across a newline (lines are drawn rows).\n let runEnd = offset + Math.max(skipAhead, 1);\n if (runEnd > token.length) runEnd = token.length;\n const newlineRel = token.indexOf(\"\\n\", offset);\n if (newlineRel !== -1 && newlineRel < runEnd) runEnd = newlineRel;\n\n const slice = token.slice(offset, runEnd);\n if (slice.length > 0) {\n lines[lines.length - 1].push({ content: slice, color: color ?? style.defaultColor });\n }\n\n if (newlineRel === runEnd) {\n pushLine();\n runEnd += 1; // consume the newline itself\n }\n offset = runEnd;\n }\n index += token.length;\n }\n\n return lines;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"highlight.js","sourceRoot":"","sources":["../src/highlight.ts"],"names":[],"mappings":"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","sourcesContent":["import { Parser, Tree } from \"@lezer/common\";\r\nimport { highlightTree } from \"@lezer/highlight\";\r\nimport {\r\n BUILTIN_THEMES,\r\n CodeHighlightStyle,\r\n CodeTheme,\r\n DefaultHighlightStyle,\r\n compileStyle,\r\n} from \"./style\";\r\n\r\n/**\r\n * Lezer-backed syntax highlighting for the Code component, replacing the former\r\n * Shiki wiring. This mirrors Motion Canvas's `LezerHighlighter`:\r\n *\r\n * - {@link prepareHighlight} parses code once and builds a `from:to` → color map\r\n * by walking {@link highlightTree}.\r\n * - {@link tokenizeCode} splits code at parse-tree leaf boundaries.\r\n * - {@link highlightAt} resolves the color (and run length) for a character index.\r\n *\r\n * Parsers load lazily and asynchronously (dynamic import) so the bundle doesn't\r\n * pull in every grammar. The node's asset loader awaits {@link ensureHighlighter}\r\n * before tokenizing; until a parser resolves, callers fall back to plain text and\r\n * re-tokenize once {@link canHighlight} returns true.\r\n */\r\n\r\n/** Dynamic-import factories for each supported language → a Lezer {@link Parser}. */\r\nconst LANGUAGE_LOADERS: Record<string, () => Promise<Parser>> = {\r\n typescript: async () => (await import(\"@lezer/javascript\")).parser.configure({ dialect: \"ts\" }),\r\n tsx: async () => (await import(\"@lezer/javascript\")).parser.configure({ dialect: \"ts jsx\" }),\r\n javascript: async () => (await import(\"@lezer/javascript\")).parser,\r\n jsx: async () => (await import(\"@lezer/javascript\")).parser.configure({ dialect: \"jsx\" }),\r\n python: async () => (await import(\"@lezer/python\")).parser,\r\n json: async () => (await import(\"@lezer/json\")).parser,\r\n html: async () => (await import(\"@lezer/html\")).parser,\r\n css: async () => (await import(\"@lezer/css\")).parser,\r\n rust: async () => (await import(\"@lezer/rust\")).parser,\r\n go: async () => (await import(\"@lezer/go\")).parser,\r\n java: async () => (await import(\"@lezer/java\")).parser,\r\n cpp: async () => (await import(\"@lezer/cpp\")).parser,\r\n php: async () => (await import(\"@lezer/php\")).parser,\r\n markdown: async () => (await import(\"@lezer/markdown\")).parser,\r\n xml: async () => (await import(\"@lezer/xml\")).parser,\r\n yaml: async () => (await import(\"@lezer/yaml\")).parser,\r\n};\r\n\r\n// Aliases so common language strings resolve to a loader above.\r\nconst LANGUAGE_ALIASES: Record<string, string> = {\r\n ts: \"typescript\",\r\n js: \"javascript\",\r\n py: \"python\",\r\n \"c++\": \"cpp\",\r\n md: \"markdown\",\r\n yml: \"yaml\",\r\n shell: \"javascript\", // no shell grammar bundled; fall back rather than throw\r\n};\r\n\r\n/** Names that mean \"no grammar, on purpose\": drawn as plain text without a warning. */\r\nconst PLAIN_LANGUAGES = new Set([\"\", \"text\", \"plaintext\"]);\r\n\r\nconst warned = new Set<string>();\r\n\r\n/** One `console.warn` per `kind:name` for the life of the process, so a listing redrawn every frame says it once. */\r\nfunction warnOnce(kind: string, name: string, message: string): void {\r\n const key = `${kind}:${name}`;\r\n if (warned.has(key)) return;\r\n warned.add(key);\r\n console.warn(`[Code] ${message}`);\r\n}\r\n\r\n/**\r\n * The source as the highlighter and the commands see it: lines joined by `\\n`.\r\n * A `\\r\\n` (or a lone `\\r`) from a file or a clipboard would otherwise survive\r\n * as a character at the end of a line, measured and drawn as a token.\r\n */\r\nexport function normalizeSource(code: string): string {\r\n return code.indexOf(\"\\r\") === -1 ? code : code.replace(/\\r\\n?/g, \"\\n\");\r\n}\r\n\r\nfunction resolveLanguageKey(language: string): string {\r\n const key = language.toLowerCase();\r\n return LANGUAGE_ALIASES[key] ?? key;\r\n}\r\n\r\n// Loaded parsers and in-flight loads, keyed by resolved language key, so\r\n// concurrent Code nodes asking for the same language share one dynamic import.\r\nconst loadedParsers = new Map<string, Parser>();\r\nconst inFlightLangs = new Map<string, Promise<Parser | null>>();\r\n\r\nexport const DEFAULT_THEMES = [DefaultHighlightStyle.name];\r\nexport const DEFAULT_LANGS = [\"typescript\", \"javascript\", \"json\", \"python\"];\r\n\r\n// Theme registry, seeded with the built-ins (Motion Canvas default + GitHub\r\n// dark/light). The `theme` prop is a string name or a CodeHighlightStyle object;\r\n// apps can register additional styles by name and reference them by that name.\r\nconst themesByName = new Map<string, CodeHighlightStyle>(Object.entries(BUILTIN_THEMES));\r\n\r\n/** Register a custom {@link CodeHighlightStyle} so Code nodes can reference it by name. */\r\nexport function registerCodeTheme(style: CodeHighlightStyle): void {\r\n themesByName.set(style.name, style);\r\n}\r\n\r\n/**\r\n * Resolve a theme reference (a registered name, or a CodeHighlightStyle object)\r\n * to a concrete style. Unknown names fall back to the Motion Canvas default so a\r\n * stray theme string never throws, with one warning per name.\r\n */\r\nexport function resolveTheme(theme: CodeTheme): CodeHighlightStyle {\r\n if (typeof theme !== \"string\") return theme;\r\n const style = themesByName.get(theme);\r\n if (style) return style;\r\n warnOnce(\r\n \"theme\",\r\n theme,\r\n `unknown theme \"${theme}\"; using \"${DefaultHighlightStyle.name}\". Built-in themes: ${Object.keys(BUILTIN_THEMES).join(\", \")}; register others with registerCodeTheme.`,\r\n );\r\n return DefaultHighlightStyle;\r\n}\r\n\r\n/** Has `language` finished loading its parser? */\r\nfunction isLanguageLoaded(language: string): boolean {\r\n return loadedParsers.has(resolveLanguageKey(language));\r\n}\r\n\r\n/**\r\n * Load the parsers for `langs` (themes are synchronous, so they're a no-op here\r\n * but kept in the signature for API parity with the former Shiki implementation).\r\n * Resolves once every requested language's parser is available. Unknown languages\r\n * resolve without loading anything — {@link canHighlight} stays false for them and\r\n * the node renders them as plain text, with one warning per language. A grammar\r\n * whose import is rejected is reported the same way and is tried again by the\r\n * next call.\r\n */\r\nexport function ensureHighlighter(\r\n _themes: string[] = DEFAULT_THEMES,\r\n langs: string[] = DEFAULT_LANGS,\r\n): Promise<void> {\r\n const jobs: Promise<unknown>[] = [];\r\n\r\n for (const lang of langs) {\r\n const key = resolveLanguageKey(lang);\r\n if (loadedParsers.has(key)) continue;\r\n\r\n const loader = LANGUAGE_LOADERS[key];\r\n if (!loader) {\r\n // Unsupported language; leave it unhighlighted, and say so.\r\n if (!PLAIN_LANGUAGES.has(key)) {\r\n warnOnce(\r\n \"language\",\r\n key,\r\n `no grammar for language \"${lang}\"; drawing it as plain text. Supported: ${Object.keys(LANGUAGE_LOADERS).join(\", \")} (aliases: ${Object.keys(LANGUAGE_ALIASES).join(\", \")}).`,\r\n );\r\n }\r\n continue;\r\n }\r\n\r\n let job = inFlightLangs.get(key);\r\n if (!job) {\r\n job = loader()\r\n .then(parser => {\r\n loadedParsers.set(key, parser);\r\n return parser;\r\n })\r\n .catch((error: unknown) => {\r\n warnOnce(\r\n \"load\",\r\n key,\r\n `could not load the \"${lang}\" grammar; drawing it as plain text: ${error instanceof Error ? error.message : String(error)}`,\r\n );\r\n return null;\r\n })\r\n .finally(() => inFlightLangs.delete(key));\r\n inFlightLangs.set(key, job);\r\n }\r\n jobs.push(job);\r\n }\r\n\r\n return jobs.length === 0 ? Promise.resolve() : Promise.all(jobs).then(() => undefined);\r\n}\r\n\r\n/**\r\n * Load a syntax-highlight language into the shared highlighter. Exposed so a Code\r\n * node's asset loader can run it on the timeline, and so apps can preload\r\n * languages explicitly. Returns once the parser is ready (or immediately for an\r\n * unsupported language). The `theme` arg is accepted for backwards compatibility.\r\n */\r\nexport async function loadCodeLanguage(language: string, _theme?: string): Promise<void> {\r\n await ensureHighlighter(DEFAULT_THEMES, [language]);\r\n}\r\n\r\nexport async function initSyntaxHighlighter(\r\n themes: string[] = DEFAULT_THEMES,\r\n langs: string[] = DEFAULT_LANGS,\r\n): Promise<void> {\r\n await ensureHighlighter(themes, langs);\r\n}\r\n\r\n/** True once `language` can be tokenized (its parser has loaded). */\r\nexport function canHighlight(language: string, _theme?: CodeTheme): boolean {\r\n return isLanguageLoaded(language);\r\n}\r\n\r\n/** A parsed-and-prepared highlight cache for one snapshot of code. */\r\ninterface HighlightCache {\r\n tree: Tree;\r\n code: string;\r\n // `${from}:${to}` node id → color, exactly as Motion Canvas keys it.\r\n colorLookup: Map<string, string>;\r\n}\r\n\r\nfunction nodeId(from: number, to: number): string {\r\n return `${from}:${to}`;\r\n}\r\n\r\n/**\r\n * Parse `code` and build the per-node color map. Mirrors Motion Canvas's\r\n * `LezerHighlighter.prepare`: for each highlighted range, walk the subtree and\r\n * record the color against every contained node's `from:to` id, so a later\r\n * {@link highlightAt} lookup by `resolveInner` index finds it.\r\n */\r\nfunction prepareHighlight(code: string, language: string, style: CodeHighlightStyle): HighlightCache | null {\r\n const parser = loadedParsers.get(resolveLanguageKey(language));\r\n if (!parser) return null;\r\n\r\n const tree = parser.parse(code);\r\n const highlighter = compileStyle(style);\r\n const colorLookup = new Map<string, string>();\r\n\r\n highlightTree(tree, highlighter, (from, to, classes) => {\r\n // tagHighlighter emits our color string as the \"class\".\r\n const color = classes;\r\n if (!color) return;\r\n const cursor = tree.cursorAt(from, 1);\r\n do {\r\n colorLookup.set(nodeId(cursor.from, cursor.to), color);\r\n } while (cursor.next() && cursor.to <= to);\r\n });\r\n\r\n return { tree, code, colorLookup };\r\n}\r\n\r\n/**\r\n * Resolve the color and run length for the token starting at `index`. Mirrors\r\n * Motion Canvas's `LezerHighlighter.highlight`: resolve the innermost node, look\r\n * up its color, and report how far the run extends (`skipAhead`).\r\n */\r\nfunction highlightAt(index: number, cache: HighlightCache): { color: string | null; skipAhead: number } {\r\n const node = cache.tree.resolveInner(index, 1);\r\n const color = cache.colorLookup.get(nodeId(node.from, node.to));\r\n if (color) {\r\n return { color, skipAhead: node.to - index };\r\n }\r\n // No color: skip past a childless (leaf) node so we don't re-resolve every char.\r\n const skipAhead = node.firstChild ? 0 : node.to - index;\r\n return { color: null, skipAhead };\r\n}\r\n\r\n/**\r\n * Split `code` into structural tokens at parse-tree leaf boundaries, including the\r\n * gaps between leaves (whitespace/punctuation). Mirrors Motion Canvas's\r\n * `LezerHighlighter.tokenize`; this segmentation is what the token-level\r\n * append/insert/erase/replace animations diff against, so matching it keeps the\r\n * animation behavior identical to Motion Canvas.\r\n */\r\nfunction tokenizeCode(code: string, language: string): string[] {\r\n const parser = loadedParsers.get(resolveLanguageKey(language));\r\n if (!parser) return [code];\r\n\r\n const tree = parser.parse(code);\r\n const cursor = tree.cursor();\r\n const tokens: string[] = [];\r\n let current = 0;\r\n\r\n do {\r\n if (!cursor.node.firstChild) {\r\n if (cursor.from > current) tokens.push(code.slice(current, cursor.from));\r\n if (cursor.from < cursor.to) tokens.push(code.slice(cursor.from, cursor.to));\r\n current = cursor.to;\r\n }\r\n } while (cursor.next());\r\n\r\n if (current < code.length) tokens.push(code.slice(current));\r\n return tokens;\r\n}\r\n\r\n/**\r\n * Tokenize `code` into per-line, colored tokens — the contract the rest of the\r\n * Code component consumes. Combines {@link tokenizeCode} (structural split) with\r\n * {@link highlightAt} (per-run color), then breaks tokens at newlines so each\r\n * output line is a row of single-line, single-color tokens.\r\n *\r\n * Callers must have checked {@link canHighlight} first; this returns a single\r\n * uncolored line per source line if the parser isn't loaded.\r\n */\r\nexport function highlightToTokens(\r\n code: string,\r\n language: string,\r\n theme: CodeTheme = DefaultHighlightStyle,\r\n): { content: string; color?: string }[][] {\r\n code = normalizeSource(code);\r\n const style = resolveTheme(theme);\r\n const cache = prepareHighlight(code, language, style);\r\n\r\n const lines: { content: string; color?: string }[][] = [[]];\r\n const pushLine = () => lines.push([]);\r\n\r\n if (!cache) {\r\n // Parser unavailable: one uncolored token per source line.\r\n return code.split(\"\\n\").map(line => [{ content: line, color: style.defaultColor }]);\r\n }\r\n\r\n // Walk the structural tokens, coloring each by its starting index and\r\n // splitting on newlines so no token spans rows.\r\n let index = 0;\r\n for (const token of tokenizeCode(code, language)) {\r\n let offset = 0;\r\n while (offset < token.length) {\r\n const { color, skipAhead } = highlightAt(index + offset, cache);\r\n // Extend the run as far as the highlight says, but never past this\r\n // structural token and never across a newline (lines are drawn rows).\r\n let runEnd = offset + Math.max(skipAhead, 1);\r\n if (runEnd > token.length) runEnd = token.length;\r\n const newlineRel = token.indexOf(\"\\n\", offset);\r\n if (newlineRel !== -1 && newlineRel < runEnd) runEnd = newlineRel;\r\n\r\n const slice = token.slice(offset, runEnd);\r\n if (slice.length > 0) {\r\n lines[lines.length - 1].push({ content: slice, color: color ?? style.defaultColor });\r\n }\r\n\r\n if (newlineRel === runEnd) {\r\n pushLine();\r\n runEnd += 1; // consume the newline itself\r\n }\r\n offset = runEnd;\r\n }\r\n index += token.length;\r\n }\r\n\r\n return lines;\r\n}\r\n"]}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAC;AACvB,cAAc,UAAU,CAAC;AACzB,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC","sourcesContent":["export * from './node';\nexport * from './engine';\nexport { NODES } from \"./nodes\";\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAC;AACvB,cAAc,UAAU,CAAC;AACzB,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC","sourcesContent":["export * from './node';\r\nexport * from './engine';\r\nexport { NODES } from \"./nodes\";\r\n"]}
|
package/dist/layout.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"layout.js","sourceRoot":"","sources":["../src/layout.ts"],"names":[],"mappings":"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","sourcesContent":["import type { InsetsResolved, MeasureContext2D, RenderContext2D } from \"@motionscript/sdk\";\nimport type { TokenAdvanceCache } from \"./measure-cache\";\nimport type { IdLine } from \"./tokens\";\n\n/**\n * Everything about a listing's geometry that is *not* its content — the type,\n * the padding, whether there is a gutter. Split out from the node so a layout\n * can be computed for a token structure the node is no longer holding: during a\n * structural transition the frame is the interpolation of two of them, and the\n * one that is going away is not reachable through `this` any more.\n */\nexport interface CodeMetrics {\n fontSize: number;\n fontFamily: string;\n lineHeight: number;\n letterSpacing: number;\n padding: InsetsResolved;\n showLineNumbers: boolean;\n lineNumberGap: number;\n}\n\n/** Where one token sits: its LEFT edge, and the vertical CENTRE of its line's slot. */\nexport interface TokenBox {\n x: number;\n y: number;\n}\n\n/**\n * A resolved listing geometry: every token placed, in the node's own space\n * (origin at the block's centre, y-up).\n *\n * Positions are absolute rather than \"a running sum plus a width scale\", which\n * is the whole point. A token's place in the *next* structure is knowable\n * without drawing it, so a transition can move a token from where it was to\n * where it will be instead of faking the motion by collapsing the advance of\n * its neighbours — which is what made an insert look like a pile of glyphs at\n * the left margin springing apart.\n */\nexport interface CodeLayout {\n /** Token id → placement. */\n tokens: Map<number, TokenBox>;\n /** Vertical centre of each line's slot, by line index. */\n lineY: number[];\n /**\n * Width of each line's ink, by line index — the sum of its tokens' advances,\n * so a blank line is `0` and a short line is short.\n *\n * Returned rather than kept local because it is the only thing that knows a\n * listing is **ragged**: `innerW` is the longest line, and everything that\n * asks where the text actually is (hit testing, for one) would otherwise have\n * to treat the block as a rectangle the width of its longest row.\n */\n lineW: number[];\n /** Line id → its index in this structure (i.e. its line *number* minus one). */\n lineIndex: Map<number, number>;\n gutter: number;\n gutterGap: number;\n /** Content size, no padding. */\n innerW: number;\n innerH: number;\n /** Content size plus padding — what the block draws and measures as. */\n blockW: number;\n blockH: number;\n /** Left edge of the code column (after padding and gutter). */\n startX: number;\n}\n\n/**\n * Signature of everything a layout depends on other than the token structure\n * itself. A cached layout survives exactly as long as this is unchanged.\n */\nexport function metricsSignature(m: CodeMetrics): string {\n const p = m.padding;\n return [\n m.fontSize, m.fontFamily, m.lineHeight, m.letterSpacing,\n p.left, p.right, p.top, p.bottom,\n m.showLineNumbers ? 1 : 0, m.lineNumberGap,\n ].join(\"|\");\n}\n\n/**\n * Horizontal gap between the line-number column and the code text. Sized in\n * space-widths so it scales with the font, and measured with letterSpacing 0 —\n * line numbers and the gap don't carry the code's letter-spacing.\n */\nfunction gutterGapOf(scope: MeasureContext2D | RenderContext2D, m: CodeMetrics, cache: TokenAdvanceCache): number {\n return cache.advance(scope, \" \", m.fontSize, m.fontFamily, 0) * m.lineNumberGap;\n}\n\n/** Width of the line-number column for a structure of `lineCount` lines, gap included. */\nfunction gutterOf(\n scope: MeasureContext2D | RenderContext2D,\n m: CodeMetrics,\n cache: TokenAdvanceCache,\n lineCount: number,\n gap: number,\n): number {\n if (!m.showLineNumbers) return 0;\n const sample = String(Math.max(1, lineCount));\n return cache.advance(scope, sample, m.fontSize, m.fontFamily, 0) + gap;\n}\n\n/**\n * Place every token of `lines`.\n *\n * Pure in (lines, metrics, font measurements), which is what lets a caller cache\n * one per structure rather than recomputing it per frame — a transition's two\n * endpoints are both fixed for its whole duration.\n */\nexport function layoutCode(\n lines: IdLine[],\n m: CodeMetrics,\n cache: TokenAdvanceCache,\n scope: MeasureContext2D | RenderContext2D,\n): CodeLayout {\n const lineH = m.fontSize * m.lineHeight;\n const gutterGap = m.showLineNumbers ? gutterGapOf(scope, m, cache) : 0;\n const gutter = gutterOf(scope, m, cache, lines.length, gutterGap);\n\n const widths: number[] = new Array(lines.length);\n let maxLineWidth = 0;\n for (let i = 0; i < lines.length; i++) {\n let w = 0;\n for (const tok of lines[i].tokens) {\n w += cache.advance(scope, tok.content, m.fontSize, m.fontFamily, m.letterSpacing);\n }\n widths[i] = w;\n if (w > maxLineWidth) maxLineWidth = w;\n }\n\n const innerW = maxLineWidth + gutter;\n const innerH = lines.length * lineH;\n const blockW = innerW + m.padding.left + m.padding.right;\n const blockH = innerH + m.padding.top + m.padding.bottom;\n const startX = -blockW / 2 + m.padding.left + gutter;\n // y-up author space: the first line sits at the TOP of the block, so the\n // cursor starts at the top edge (+half height, minus top padding) and steps\n // DOWNWARD by subtracting a line height per row.\n const startY = blockH / 2 - m.padding.top;\n\n const tokens = new Map<number, TokenBox>();\n const lineY: number[] = new Array(lines.length);\n const lineIndex = new Map<number, number>();\n\n for (let i = 0; i < lines.length; i++) {\n const centerY = startY - i * lineH - lineH / 2;\n lineY[i] = centerY;\n lineIndex.set(lines[i].id, i);\n let x = startX;\n for (const tok of lines[i].tokens) {\n tokens.set(tok.id, { x, y: centerY });\n x += cache.advance(scope, tok.content, m.fontSize, m.fontFamily, m.letterSpacing);\n }\n }\n\n return { tokens, lineY, lineW: widths, lineIndex, gutter, gutterGap, innerW, innerH, blockW, blockH, startX };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"layout.js","sourceRoot":"","sources":["../src/layout.ts"],"names":[],"mappings":"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","sourcesContent":["import type { InsetsResolved, MeasureContext2D, RenderContext2D } from \"@motionscript/sdk\";\r\nimport type { TokenAdvanceCache } from \"./measure-cache\";\r\nimport type { IdLine } from \"./tokens\";\r\n\r\n/**\r\n * Everything about a listing's geometry that is *not* its content — the type,\r\n * the padding, whether there is a gutter. Split out from the node so a layout\r\n * can be computed for a token structure the node is no longer holding: during a\r\n * structural transition the frame is the interpolation of two of them, and the\r\n * one that is going away is not reachable through `this` any more.\r\n */\r\nexport interface CodeMetrics {\r\n fontSize: number;\r\n fontFamily: string;\r\n lineHeight: number;\r\n letterSpacing: number;\r\n padding: InsetsResolved;\r\n showLineNumbers: boolean;\r\n lineNumberGap: number;\r\n}\r\n\r\n/** Where one token sits: its LEFT edge, and the vertical CENTRE of its line's slot. */\r\nexport interface TokenBox {\r\n x: number;\r\n y: number;\r\n}\r\n\r\n/**\r\n * A resolved listing geometry: every token placed, in the node's own space\r\n * (origin at the block's centre, y-up).\r\n *\r\n * Positions are absolute rather than \"a running sum plus a width scale\", which\r\n * is the whole point. A token's place in the *next* structure is knowable\r\n * without drawing it, so a transition can move a token from where it was to\r\n * where it will be instead of faking the motion by collapsing the advance of\r\n * its neighbours — which is what made an insert look like a pile of glyphs at\r\n * the left margin springing apart.\r\n */\r\nexport interface CodeLayout {\r\n /** Token id → placement. */\r\n tokens: Map<number, TokenBox>;\r\n /** Vertical centre of each line's slot, by line index. */\r\n lineY: number[];\r\n /**\r\n * Width of each line's ink, by line index — the sum of its tokens' advances,\r\n * so a blank line is `0` and a short line is short.\r\n *\r\n * Returned rather than kept local because it is the only thing that knows a\r\n * listing is **ragged**: `innerW` is the longest line, and everything that\r\n * asks where the text actually is (hit testing, for one) would otherwise have\r\n * to treat the block as a rectangle the width of its longest row.\r\n */\r\n lineW: number[];\r\n /** Line id → its index in this structure (i.e. its line *number* minus one). */\r\n lineIndex: Map<number, number>;\r\n gutter: number;\r\n gutterGap: number;\r\n /** Content size, no padding. */\r\n innerW: number;\r\n innerH: number;\r\n /** Content size plus padding — what the block draws and measures as. */\r\n blockW: number;\r\n blockH: number;\r\n /** Left edge of the code column (after padding and gutter). */\r\n startX: number;\r\n}\r\n\r\n/**\r\n * Signature of everything a layout depends on other than the token structure\r\n * itself. A cached layout survives exactly as long as this is unchanged.\r\n */\r\nexport function metricsSignature(m: CodeMetrics): string {\r\n const p = m.padding;\r\n return [\r\n m.fontSize, m.fontFamily, m.lineHeight, m.letterSpacing,\r\n p.left, p.right, p.top, p.bottom,\r\n m.showLineNumbers ? 1 : 0, m.lineNumberGap,\r\n ].join(\"|\");\r\n}\r\n\r\n/**\r\n * Horizontal gap between the line-number column and the code text. Sized in\r\n * space-widths so it scales with the font, and measured with letterSpacing 0 —\r\n * line numbers and the gap don't carry the code's letter-spacing.\r\n */\r\nfunction gutterGapOf(scope: MeasureContext2D | RenderContext2D, m: CodeMetrics, cache: TokenAdvanceCache): number {\r\n return cache.advance(scope, \" \", m.fontSize, m.fontFamily, 0) * m.lineNumberGap;\r\n}\r\n\r\n/** Width of the line-number column for a structure of `lineCount` lines, gap included. */\r\nfunction gutterOf(\r\n scope: MeasureContext2D | RenderContext2D,\r\n m: CodeMetrics,\r\n cache: TokenAdvanceCache,\r\n lineCount: number,\r\n gap: number,\r\n): number {\r\n if (!m.showLineNumbers) return 0;\r\n const sample = String(Math.max(1, lineCount));\r\n return cache.advance(scope, sample, m.fontSize, m.fontFamily, 0) + gap;\r\n}\r\n\r\n/**\r\n * Place every token of `lines`.\r\n *\r\n * Pure in (lines, metrics, font measurements), which is what lets a caller cache\r\n * one per structure rather than recomputing it per frame — a transition's two\r\n * endpoints are both fixed for its whole duration.\r\n */\r\nexport function layoutCode(\r\n lines: IdLine[],\r\n m: CodeMetrics,\r\n cache: TokenAdvanceCache,\r\n scope: MeasureContext2D | RenderContext2D,\r\n): CodeLayout {\r\n const lineH = m.fontSize * m.lineHeight;\r\n const gutterGap = m.showLineNumbers ? gutterGapOf(scope, m, cache) : 0;\r\n const gutter = gutterOf(scope, m, cache, lines.length, gutterGap);\r\n\r\n const widths: number[] = new Array(lines.length);\r\n let maxLineWidth = 0;\r\n for (let i = 0; i < lines.length; i++) {\r\n let w = 0;\r\n for (const tok of lines[i].tokens) {\r\n w += cache.advance(scope, tok.content, m.fontSize, m.fontFamily, m.letterSpacing);\r\n }\r\n widths[i] = w;\r\n if (w > maxLineWidth) maxLineWidth = w;\r\n }\r\n\r\n const innerW = maxLineWidth + gutter;\r\n const innerH = lines.length * lineH;\r\n const blockW = innerW + m.padding.left + m.padding.right;\r\n const blockH = innerH + m.padding.top + m.padding.bottom;\r\n const startX = -blockW / 2 + m.padding.left + gutter;\r\n // y-up author space: the first line sits at the TOP of the block, so the\r\n // cursor starts at the top edge (+half height, minus top padding) and steps\r\n // DOWNWARD by subtracting a line height per row.\r\n const startY = blockH / 2 - m.padding.top;\r\n\r\n const tokens = new Map<number, TokenBox>();\r\n const lineY: number[] = new Array(lines.length);\r\n const lineIndex = new Map<number, number>();\r\n\r\n for (let i = 0; i < lines.length; i++) {\r\n const centerY = startY - i * lineH - lineH / 2;\r\n lineY[i] = centerY;\r\n lineIndex.set(lines[i].id, i);\r\n let x = startX;\r\n for (const tok of lines[i].tokens) {\r\n tokens.set(tok.id, { x, y: centerY });\r\n x += cache.advance(scope, tok.content, m.fontSize, m.fontFamily, m.letterSpacing);\r\n }\r\n }\r\n\r\n return { tokens, lineY, lineW: widths, lineIndex, gutter, gutterGap, innerW, innerH, blockW, blockH, startX };\r\n}\r\n"]}
|
package/dist/node.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { RenderContext2D, RenderPass2D, Clip, EasingFunction, NodeConfig, Size2D, SizeConstraints, Node2D, Node2DProps, MeasureContext2D, InsetsResolved, InsetsProps, type AssetScope, type Command, type CommandArgs, type Node, type TweenStepper, type Vector2 } from "@motionscript/sdk";
|
|
1
|
+
import { RenderContext2D, RenderPass2D, Clip, EasingFunction, NodeConfig, Size2D, SizeConstraints, Node2D, Node2DProps, MeasureContext2D, InsetsResolved, InsetsProps, type Color, type AssetScope, type Command, type CommandArgs, type Node, type TweenStepper, type Vector2 } from "@motionscript/sdk";
|
|
2
2
|
import { CodeRange, type CodeDiffStrategy, type CodePhaseStrategy, CodeTheme } from "./engine.js";
|
|
3
3
|
/**
|
|
4
4
|
* A listing and nothing else — no paint slots, and no box behind the tokens.
|
|
@@ -52,9 +52,13 @@ export declare class Code extends Node2D<CodeProps> {
|
|
|
52
52
|
readonly padding: InsetsResolved;
|
|
53
53
|
/** The settled structure. During an edit, the structure the edit lands on. */
|
|
54
54
|
private tokenLines;
|
|
55
|
-
private tokenized;
|
|
56
55
|
/** The source `tokenLines` spells, so a frame compares it with `code` without joining every token. */
|
|
57
56
|
private _linesSource;
|
|
57
|
+
/** What `tokenLines` were coloured and split with, so a frame notices a `language` or `theme` that has moved since. */
|
|
58
|
+
private _linesBasis;
|
|
59
|
+
/** The last `code` seen and its normalised form, so a frame that finds it unchanged does not scan it. */
|
|
60
|
+
private _rawCode;
|
|
61
|
+
private _normalCode;
|
|
58
62
|
private transitions;
|
|
59
63
|
private advanceCache;
|
|
60
64
|
private structureVersion;
|
|
@@ -62,6 +66,7 @@ export declare class Code extends Node2D<CodeProps> {
|
|
|
62
66
|
private layoutCache;
|
|
63
67
|
private highlightDimOpacity;
|
|
64
68
|
private highlightedIds;
|
|
69
|
+
private rowBands;
|
|
65
70
|
/**
|
|
66
71
|
* Which token became which across an edit, and when each part of that
|
|
67
72
|
* edit happens. Construction-time-only (see {@link CodeStrategies}) —
|
|
@@ -69,11 +74,7 @@ export declare class Code extends Node2D<CodeProps> {
|
|
|
69
74
|
*/
|
|
70
75
|
private readonly diffStrategy;
|
|
71
76
|
private readonly phaseStrategy;
|
|
72
|
-
constructor(props
|
|
73
|
-
set(props: {
|
|
74
|
-
[K in keyof CodeProps]?: CodeProps[K] | (() => CodeProps[K]);
|
|
75
|
-
}): void;
|
|
76
|
-
private tokenize;
|
|
77
|
+
constructor(props?: NodeConfig<Code, CodeProps> & CodeStrategies);
|
|
77
78
|
/**
|
|
78
79
|
* Swap in a new settled structure, invalidating the layout cache.
|
|
79
80
|
*
|
|
@@ -98,6 +99,8 @@ export declare class Code extends Node2D<CodeProps> {
|
|
|
98
99
|
private metrics;
|
|
99
100
|
/** The structural edit currently in flight, if any. */
|
|
100
101
|
private activeEdit;
|
|
102
|
+
/** The row-band change in flight, if any; the latest wins. */
|
|
103
|
+
private activeRows;
|
|
101
104
|
private settledLayout;
|
|
102
105
|
/**
|
|
103
106
|
* The one or two layouts this frame is drawn from.
|
|
@@ -230,6 +233,24 @@ export declare class Code extends Node2D<CodeProps> {
|
|
|
230
233
|
resetHighlight(args: CommandArgs<Record<string, never>> & {
|
|
231
234
|
duration: number;
|
|
232
235
|
}): Command<Record<string, never>>;
|
|
236
|
+
/**
|
|
237
|
+
* Lay a band of `color` behind whole rows: every line a range touches, across
|
|
238
|
+
* the block. Persistent, and independent of {@link highlight}'s dimming. A
|
|
239
|
+
* second call slides and resizes the bands onto their new rows, pairing them
|
|
240
|
+
* in the order given; `resetRowHighlight()` fades them out. A band keeps to
|
|
241
|
+
* its lines when an edit moves them.
|
|
242
|
+
*/
|
|
243
|
+
highlightRows(args: CommandArgs<{
|
|
244
|
+
target: CodeRange | Iterable<CodeRange>;
|
|
245
|
+
color?: Color;
|
|
246
|
+
radius?: number;
|
|
247
|
+
}> & {
|
|
248
|
+
duration: number;
|
|
249
|
+
}): Command<Record<string, never>>;
|
|
250
|
+
/** Fade every row band out and clear them. */
|
|
251
|
+
resetRowHighlight(args: CommandArgs<Record<string, never>> & {
|
|
252
|
+
duration: number;
|
|
253
|
+
}): Command<Record<string, never>>;
|
|
233
254
|
/**
|
|
234
255
|
* Animate the listing to a new source.
|
|
235
256
|
*
|
|
@@ -255,6 +276,8 @@ export declare class Code extends Node2D<CodeProps> {
|
|
|
255
276
|
* way*, and `progress` is assigned from `t` rather than accumulated.
|
|
256
277
|
*/
|
|
257
278
|
private runDim;
|
|
279
|
+
/** The same membership rule as {@link runDim}: on the stack strictly inside the run, settled at either end. */
|
|
280
|
+
private runRows;
|
|
258
281
|
/**
|
|
259
282
|
* Route a tweened `code` through the diff engine.
|
|
260
283
|
*
|
|
@@ -283,6 +306,8 @@ export declare class Code extends Node2D<CodeProps> {
|
|
|
283
306
|
* overlaps any of them. Tokens that partially overlap are included.
|
|
284
307
|
*/
|
|
285
308
|
private tokenIdsInRanges;
|
|
309
|
+
/** One band per range, over every line it touches; a range past the end of the listing gives none. */
|
|
310
|
+
private rowBandsIn;
|
|
286
311
|
/**
|
|
287
312
|
* Thin delegator: everything about *how* a frame is painted (settled or
|
|
288
313
|
* mid structural-edit, entry/exit motion, colour cross-fade) lives in
|
|
@@ -307,7 +332,17 @@ export declare class Code extends Node2D<CodeProps> {
|
|
|
307
332
|
private readonly _derived;
|
|
308
333
|
/** The first command to apply after a restore starts from the props' listing. */
|
|
309
334
|
private _drive;
|
|
335
|
+
/**
|
|
336
|
+
* Bring the settled structure up to the props it is derived from.
|
|
337
|
+
*
|
|
338
|
+
* Pulled from every reader rather than pushed from a prop write, because
|
|
339
|
+
* `code`, `language` and `theme` can each be tweened or bound, and neither
|
|
340
|
+
* has a write to hang a subscription on. Never mid-edit: re-tokenizing mints
|
|
341
|
+
* fresh ids, and an in-flight transition is keyed by the ones it captured.
|
|
342
|
+
*/
|
|
310
343
|
private _sync;
|
|
344
|
+
private _normalised;
|
|
345
|
+
private _basis;
|
|
311
346
|
private _structureFor;
|
|
312
347
|
}
|
|
313
348
|
//# sourceMappingURL=node.d.ts.map
|
package/dist/node.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"AAAA,OAAO,EAEH,eAAe,EAAE,YAAY,EAAE,IAAI,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,EAAE,eAAe,EACxF,MAAM,EAAE,WAAW,EAAE,gBAAgB,EAAE,cAAc,EAAE,WAAW,
|
|
1
|
+
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"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"}
|