@motionscript/code 0.1.0-alpha.0 → 0.1.0-alpha.3
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 +21 -0
- package/README.md +81 -50
- package/dist/browser/index.js +6 -7
- package/dist/browser/index.js.map +3 -3
- package/dist/browser/manifest.json +2 -2
- package/dist/code-range.d.ts +1 -1
- package/dist/code-range.js +1 -1
- package/dist/code-range.js.map +1 -1
- package/dist/layout.d.ts +1 -1
- package/dist/layout.d.ts.map +1 -1
- package/dist/layout.js.map +1 -1
- package/dist/measure-cache.d.ts +1 -1
- package/dist/measure-cache.d.ts.map +1 -1
- package/dist/measure-cache.js.map +1 -1
- package/dist/node.d.ts +21 -1
- package/dist/node.d.ts.map +1 -1
- package/dist/node.js +64 -9
- package/dist/node.js.map +1 -1
- package/dist/render.d.ts +1 -1
- package/dist/render.d.ts.map +1 -1
- package/dist/render.js +1 -1
- package/dist/render.js.map +1 -1
- package/package.json +4 -3
- package/src/code-range.ts +1 -1
- package/src/layout.ts +1 -1
- package/src/measure-cache.ts +0 -0
- package/src/node.ts +80 -10
- package/src/render.ts +1 -1
package/dist/code-range.d.ts
CHANGED
|
@@ -30,7 +30,7 @@ export declare function word(line: number, col: number, length?: number): CodeRa
|
|
|
30
30
|
export declare function lines(from: number, to?: number): CodeRange;
|
|
31
31
|
/**
|
|
32
32
|
* Immutable, chainable, iterable builder over multiple ranges — mirrors
|
|
33
|
-
* {@link FillChain}/`Fills` in `@motionscript/
|
|
33
|
+
* {@link FillChain}/`Fills` in `@motionscript/sdk`. Every method returns a
|
|
34
34
|
* *new* chain with one more range appended, so the next range-kind method is
|
|
35
35
|
* called directly rather than through a separate combinator:
|
|
36
36
|
*
|
package/dist/code-range.js
CHANGED
|
@@ -32,7 +32,7 @@ export function lines(from, to) {
|
|
|
32
32
|
}
|
|
33
33
|
/**
|
|
34
34
|
* Immutable, chainable, iterable builder over multiple ranges — mirrors
|
|
35
|
-
* {@link FillChain}/`Fills` in `@motionscript/
|
|
35
|
+
* {@link FillChain}/`Fills` in `@motionscript/sdk`. Every method returns a
|
|
36
36
|
* *new* chain with one more range appended, so the next range-kind method is
|
|
37
37
|
* called directly rather than through a separate combinator:
|
|
38
38
|
*
|
package/dist/code-range.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"code-range.js","sourceRoot":"","sources":["../src/code-range.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * A range over a code document. Lines and columns are 1-indexed.\n *\n * `endLine`/`endCol` may be `Infinity` to mean \"to the end of the line\" or\n * \"to the end of the document\".\n */\nexport interface CodeRange {\n startLine: number;\n startCol: number;\n endLine: number;\n endCol: number;\n}\n\n/**\n * Create a range that spans `length` characters starting at (line, col).\n * If `length` is omitted, the range extends to the end of the line.\n *\n * Example:\n * word(1, 3, 3) // line 1, column 3, spans 3 characters\n * word(1, 3) // line 1, column 3, to end of line\n */\nexport function word(line: number, col: number, length?: number): CodeRange {\n return {\n startLine: line,\n startCol: col,\n endLine: line,\n endCol: length === undefined ? Infinity : col + length,\n };\n}\n\n/**\n * Create a range that covers entire lines from `from` to `to` (inclusive).\n * If `to` is omitted, only line `from` is covered.\n *\n * Example:\n * lines(1, 3) // lines 1 through 3\n * lines(2) // line 2 only\n */\nexport function lines(from: number, to?: number): CodeRange {\n return {\n startLine: from,\n startCol: 1,\n endLine: to ?? from,\n endCol: Infinity,\n };\n}\n\n\n\n/**\n * Immutable, chainable, iterable builder over multiple ranges — mirrors\n * {@link FillChain}/`Fills` in `@motionscript/
|
|
1
|
+
{"version":3,"file":"code-range.js","sourceRoot":"","sources":["../src/code-range.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * A range over a code document. Lines and columns are 1-indexed.\n *\n * `endLine`/`endCol` may be `Infinity` to mean \"to the end of the line\" or\n * \"to the end of the document\".\n */\nexport interface CodeRange {\n startLine: number;\n startCol: number;\n endLine: number;\n endCol: number;\n}\n\n/**\n * Create a range that spans `length` characters starting at (line, col).\n * If `length` is omitted, the range extends to the end of the line.\n *\n * Example:\n * word(1, 3, 3) // line 1, column 3, spans 3 characters\n * word(1, 3) // line 1, column 3, to end of line\n */\nexport function word(line: number, col: number, length?: number): CodeRange {\n return {\n startLine: line,\n startCol: col,\n endLine: line,\n endCol: length === undefined ? Infinity : col + length,\n };\n}\n\n/**\n * Create a range that covers entire lines from `from` to `to` (inclusive).\n * If `to` is omitted, only line `from` is covered.\n *\n * Example:\n * lines(1, 3) // lines 1 through 3\n * lines(2) // line 2 only\n */\nexport function lines(from: number, to?: number): CodeRange {\n return {\n startLine: from,\n startCol: 1,\n endLine: to ?? from,\n endCol: Infinity,\n };\n}\n\n\n\n/**\n * Immutable, chainable, iterable builder over multiple ranges — mirrors\n * {@link FillChain}/`Fills` in `@motionscript/sdk`. Every method returns a\n * *new* chain with one more range appended, so the next range-kind method is\n * called directly rather than through a separate combinator:\n *\n * @example\n * CodeRanges.lines(2).word(5, 1, 3) // a 2-range selection, one expression\n */\nexport class CodeRangeChain {\n constructor(public readonly list: CodeRange[] = []) { }\n\n lines(from: number, to?: number): CodeRangeChain {\n return new CodeRangeChain([...this.list, lines(from, to)]);\n }\n\n word(line: number, col: number, length?: number): CodeRangeChain {\n return new CodeRangeChain([...this.list, word(line, col, length)]);\n }\n\n *[Symbol.iterator](): Iterator<CodeRange> {\n yield* this.list;\n }\n}\n\n/**\n * Entry point for building multi-range selections fluently — an empty\n * {@link CodeRangeChain}, so `CodeRanges.lines(2)` *is* `new\n * CodeRangeChain().lines(2)`. `word`/`lines` stay directly importable and\n * usable standalone for a single range; reach for `CodeRanges` when a call\n * needs more than one.\n */\nexport const CodeRanges = new CodeRangeChain();\n\n/**\n * Convert a CodeRange to absolute character offsets [start, end) in the joined\n * source text, given the per-line lengths of that source. Lines/columns are\n * clamped into the document so out-of-bounds inputs produce a valid range.\n */\nexport function rangeToCharOffsets(\n r: CodeRange,\n lineLengths: number[],\n): { start: number; end: number } {\n if (lineLengths.length === 0) return { start: 0, end: 0 };\n\n // Cumulative line starts in the joined string (lines joined with '\\n').\n const lineStart: number[] = new Array(lineLengths.length);\n let acc = 0;\n for (let i = 0; i < lineLengths.length; i++) {\n lineStart[i] = acc;\n acc += lineLengths[i] + 1; // +1 for the joining newline\n }\n const docEnd = acc > 0 ? acc - 1 : 0; // strip trailing newline\n\n const clampLine = (n: number) =>\n Math.max(0, Math.min(lineLengths.length - 1, n - 1)); // to 0-indexed\n\n // A range read back from JSON holds `Infinity` as `null`; both mean \"to the end\".\n const endLine = r.endLine ?? Infinity;\n const endCol = r.endCol ?? Infinity;\n\n const sLine = clampLine(r.startLine);\n const eLine = clampLine(endLine);\n const sColMax = lineLengths[sLine];\n const eColMax = lineLengths[eLine];\n\n // Columns are 1-indexed; clamp to [1, lineLength+1] so endCol can sit past\n // the last char (one-past-end).\n const sCol = Math.max(0, Math.min(sColMax, r.startCol - 1));\n const eCol = endCol === Infinity\n ? eColMax\n : Math.max(0, Math.min(eColMax, endCol - 1));\n\n const start = Math.min(docEnd, lineStart[sLine] + sCol);\n const end = Math.min(docEnd, lineStart[eLine] + eCol);\n return { start: Math.min(start, end), end: Math.max(start, end) };\n}\n\n/**\n * Convert [start, end) character offsets in joined source to a CodeRange.\n * Lines/cols in the returned range are 1-indexed.\n */\nexport function charOffsetsToRange(\n start: number,\n end: number,\n lineLengths: number[],\n): CodeRange {\n let off = 0;\n let startLine = 1, startCol = 1, endLine = 1, endCol = 1;\n let foundStart = false;\n for (let li = 0; li < lineLengths.length; li++) {\n const lineStart = off;\n const lineEnd = off + lineLengths[li];\n if (!foundStart && start >= lineStart && start <= lineEnd) {\n startLine = li + 1;\n startCol = (start - lineStart) + 1;\n foundStart = true;\n }\n if (end >= lineStart && end <= lineEnd) {\n endLine = li + 1;\n endCol = (end - lineStart) + 1;\n break;\n }\n off = lineEnd + 1;\n }\n return { startLine, startCol, endLine, endCol };\n}\n"]}
|
package/dist/layout.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { InsetsResolved, MeasureContext2D, RenderContext2D } from "@motionscript/
|
|
1
|
+
import type { InsetsResolved, MeasureContext2D, RenderContext2D } from "@motionscript/sdk";
|
|
2
2
|
import type { TokenAdvanceCache } from "./measure-cache.js";
|
|
3
3
|
import type { IdLine } from "./tokens.js";
|
|
4
4
|
/**
|
package/dist/layout.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../src/layout.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../src/layout.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAC3F,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAEvC;;;;;;GAMG;AACH,MAAM,WAAW,WAAW;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,cAAc,CAAC;IACxB,eAAe,EAAE,OAAO,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;CACzB;AAED,uFAAuF;AACvF,MAAM,WAAW,QAAQ;IACrB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACb;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,UAAU;IACvB,4BAA4B;IAC5B,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC9B,0DAA0D;IAC1D,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB;;;;;;;;OAQG;IACH,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,gFAAgF;IAChF,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,gCAAgC;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,wEAAwE;IACxE,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,+DAA+D;IAC/D,MAAM,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,WAAW,GAAG,MAAM,CAOvD;AAwBD;;;;;;GAMG;AACH,wBAAgB,UAAU,CACtB,KAAK,EAAE,MAAM,EAAE,EACf,CAAC,EAAE,WAAW,EACd,KAAK,EAAE,iBAAiB,EACxB,KAAK,EAAE,gBAAgB,GAAG,eAAe,GAC1C,UAAU,CA0CZ"}
|
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/
|
|
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"]}
|
package/dist/measure-cache.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"measure-cache.d.ts","sourceRoot":"","sources":["../src/measure-cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"measure-cache.d.ts","sourceRoot":"","sources":["../src/measure-cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEtE;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBAAa,iBAAiB;IAC1B,OAAO,CAAC,KAAK,CAA6B;IAC1C,OAAO,CAAC,GAAG,CAAM;IAEjB,+EAA+E;IAC/E,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM;IAIvD,0EAA0E;IAC1E,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAOvB;;;;OAIG;IACH,OAAO,CACH,KAAK,EAAE,gBAAgB,GAAG,eAAe,EACzC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,aAAa,EAAE,MAAM,GACtB,MAAM;CAYZ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"measure-cache.js","sourceRoot":"","sources":["../src/measure-cache.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,OAAO,iBAAiB;IAClB,KAAK,GAAG,IAAI,GAAG,EAAkB,CAAC;IAClC,GAAG,GAAG,EAAE,CAAC;IAEjB,+EAA+E;IAC/E,SAAS,CAAC,QAAgB,EAAE,UAAkB;QAC1C,OAAO,GAAG,QAAQ,IAAI,UAAU,EAAE,CAAC;IACvC,CAAC;IAED,0EAA0E;IAC1E,IAAI,CAAC,GAAW;QACZ,IAAI,GAAG,KAAK,IAAI,CAAC,GAAG,EAAE,CAAC;YACnB,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;YACnB,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACnB,CAAC;IACL,CAAC;IAED;;;;OAIG;IACH,OAAO,CACH,KAAyC,EACzC,OAAe,EACf,QAAgB,EAChB,UAAkB,EAClB,aAAqB;QAErB,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,CAAC,CAAC;QACnC,MAAM,GAAG,GAAG,GAAG,OAAO,IAAI,aAAa,EAAE,CAAC;QAC1C,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAChC,IAAI,GAAG,KAAK,SAAS;YAAE,OAAO,GAAG,CAAC;QAClC,wEAAwE;QACxE,8DAA8D;QAC9D,iDAAiD;QACjD,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC,WAAW,CAAC,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,CAAC,CAAC;QAC7F,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC3B,OAAO,KAAK,CAAC;IACjB,CAAC;CACJ","sourcesContent":["import { MeasureContext2D, RenderContext2D } from \"@motionscript/
|
|
1
|
+
{"version":3,"file":"measure-cache.js","sourceRoot":"","sources":["../src/measure-cache.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,OAAO,iBAAiB;IAClB,KAAK,GAAG,IAAI,GAAG,EAAkB,CAAC;IAClC,GAAG,GAAG,EAAE,CAAC;IAEjB,+EAA+E;IAC/E,SAAS,CAAC,QAAgB,EAAE,UAAkB;QAC1C,OAAO,GAAG,QAAQ,IAAI,UAAU,EAAE,CAAC;IACvC,CAAC;IAED,0EAA0E;IAC1E,IAAI,CAAC,GAAW;QACZ,IAAI,GAAG,KAAK,IAAI,CAAC,GAAG,EAAE,CAAC;YACnB,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;YACnB,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACnB,CAAC;IACL,CAAC;IAED;;;;OAIG;IACH,OAAO,CACH,KAAyC,EACzC,OAAe,EACf,QAAgB,EAChB,UAAkB,EAClB,aAAqB;QAErB,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,CAAC,CAAC;QACnC,MAAM,GAAG,GAAG,GAAG,OAAO,IAAI,aAAa,EAAE,CAAC;QAC1C,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAChC,IAAI,GAAG,KAAK,SAAS;YAAE,OAAO,GAAG,CAAC;QAClC,wEAAwE;QACxE,8DAA8D;QAC9D,iDAAiD;QACjD,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC,WAAW,CAAC,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,CAAC,CAAC;QAC7F,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC3B,OAAO,KAAK,CAAC;IACjB,CAAC;CACJ","sourcesContent":["import { MeasureContext2D, RenderContext2D } from \"@motionscript/sdk\";\r\n\r\n/**\r\n * Memoizes text-advance measurements for the Code node.\r\n *\r\n * `scope.measureText` runs a full CanvasKit/Skia paragraph layout (shaping plus\r\n * font object alloc/free) on every call — far too expensive to repeat for every\r\n * token on every frame. A token's advance only depends on (content, fontSize,\r\n * fontFamily, letterSpacing); content changes only at edit time and the font\r\n * inputs only change via props, so the same string measures to the same width\r\n * across the many static frames the player renders.\r\n *\r\n * fontSize + fontFamily fold into a `signature` checked once per frame: when it\r\n * changes the cache clears. letterSpacing folds into the per-entry key so the\r\n * letter-spaced token advances and the unspaced gutter advances coexist in one\r\n * map. The signature check (not the node's `set()`) is the invalidation point on\r\n * purpose — animated/bound font props (`to({ fontSize })`, `fontSize={() => …}`)\r\n * bypass `set()` but still flow through the per-frame signature comparison.\r\n *\r\n * NOTE: the two `measureText` implementations in packages/browser/src\r\n * (measure-scope.ts and render-context.ts) are uncached and shape+free fonts on\r\n * every call. A shared cache there would speed up all text nodes, but it touches\r\n * shared infra and cross-font correctness, so it's intentionally left out here.\r\n */\r\nexport class TokenAdvanceCache {\r\n private cache = new Map<string, number>();\r\n private sig = \"\";\r\n\r\n /** Signature of the font inputs that, when changed, invalidate every entry. */\r\n signature(fontSize: number, fontFamily: string): string {\r\n return `${fontSize}|${fontFamily}`;\r\n }\r\n\r\n /** Clear the cache if the font signature changed since the last frame. */\r\n sync(sig: string): void {\r\n if (sig !== this.sig) {\r\n this.cache.clear();\r\n this.sig = sig;\r\n }\r\n }\r\n\r\n /**\r\n * Advance width of `content`, measured once per unique (content,\r\n * letterSpacing) pair under the current font signature. Call `sync()` first\r\n * each frame so a font change is reflected.\r\n */\r\n advance(\r\n scope: MeasureContext2D | RenderContext2D,\r\n content: string,\r\n fontSize: number,\r\n fontFamily: string,\r\n letterSpacing: number,\r\n ): number {\r\n if (content.length === 0) return 0;\r\n const key = `${content}\u0000${letterSpacing}`;\r\n const hit = this.cache.get(key);\r\n if (hit !== undefined) return hit;\r\n // Only the advance width is cached: a code block's geometry is a column\r\n // of x offsets, and its line height comes from the node's own\r\n // `lineHeight` prop rather than from the shaper.\r\n const { width } = scope.measureText(content, fontSize, fontFamily, undefined, letterSpacing);\r\n this.cache.set(key, width);\r\n return width;\r\n }\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/
|
|
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";
|
|
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.
|
|
@@ -53,6 +53,8 @@ export declare class Code extends Node2D<CodeProps> {
|
|
|
53
53
|
/** The settled structure. During an edit, the structure the edit lands on. */
|
|
54
54
|
private tokenLines;
|
|
55
55
|
private tokenized;
|
|
56
|
+
/** The source `tokenLines` spells, so a frame compares it with `code` without joining every token. */
|
|
57
|
+
private _linesSource;
|
|
56
58
|
private transitions;
|
|
57
59
|
private advanceCache;
|
|
58
60
|
private structureVersion;
|
|
@@ -289,5 +291,23 @@ export declare class Code extends Node2D<CodeProps> {
|
|
|
289
291
|
* fields and caches.
|
|
290
292
|
*/
|
|
291
293
|
protected drawSelf(draw: RenderContext2D): void;
|
|
294
|
+
/**
|
|
295
|
+
* Whether a listing command has applied since the timeline last restored the
|
|
296
|
+
* props.
|
|
297
|
+
*
|
|
298
|
+
* A slot rather than a field because slots are all a restore puts back. The
|
|
299
|
+
* structure, highlight and transitions live outside the props, and only a
|
|
300
|
+
* command that has started writes them, so before the first one starts (or
|
|
301
|
+
* after a seek back past it) they still hold whatever the last evaluation
|
|
302
|
+
* left — the end of every command, after compile. This reads false again
|
|
303
|
+
* there, and `_sync` derives them from the props instead.
|
|
304
|
+
*/
|
|
305
|
+
private readonly _driven;
|
|
306
|
+
/** Each source the props have named, tokenized once, so a listing derived again keeps the ids a highlight selected. */
|
|
307
|
+
private readonly _derived;
|
|
308
|
+
/** The first command to apply after a restore starts from the props' listing. */
|
|
309
|
+
private _drive;
|
|
310
|
+
private _sync;
|
|
311
|
+
private _structureFor;
|
|
292
312
|
}
|
|
293
313
|
//# 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,EAE3C,KAAK,UAAU,EAAE,KAAK,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,IAAI,EAAE,KAAK,YAAY,EAAE,KAAK,OAAO,EACrH,MAAM,
|
|
1
|
+
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"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"}
|
package/dist/node.js
CHANGED
|
@@ -4,12 +4,14 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
4
4
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
|
-
import { node, Clip, Node2D, property,
|
|
7
|
+
import { node, Clip, Node2D, property, insetsProperty, lerpNumber, command, driveCommand, } from "@motionscript/sdk";
|
|
8
8
|
import { rangeToCharOffsets, charOffsetsToRange, TokenAdvanceCache, tokenizeCodeToIdLines, defaultCodeDiff, layoutCode, metricsSignature, makeAnim, defaultCodePhases, resolveTokenStates, moveProgress, canHighlight, ensureHighlighter, DefaultHighlightStyle, drawCode, } from "./engine.js";
|
|
9
9
|
let Code = class Code extends Node2D {
|
|
10
10
|
/** The settled structure. During an edit, the structure the edit lands on. */
|
|
11
11
|
tokenLines = [];
|
|
12
12
|
tokenized = false;
|
|
13
|
+
/** The source `tokenLines` spells, so a frame compares it with `code` without joining every token. */
|
|
14
|
+
_linesSource = "";
|
|
13
15
|
transitions = [];
|
|
14
16
|
// Caches expensive scope.measureText() calls; cleared when the font
|
|
15
17
|
// signature (fontSize|fontFamily) changes. See TokenAdvanceCache.
|
|
@@ -38,6 +40,7 @@ let Code = class Code extends Node2D {
|
|
|
38
40
|
this.phaseStrategy = props.phaseStrategy ?? defaultCodePhases;
|
|
39
41
|
this.applyProp("width", props.width ?? "hug");
|
|
40
42
|
this.applyProp("height", props.height ?? "hug");
|
|
43
|
+
this.applyProp("_driven", false);
|
|
41
44
|
// Best-effort, for a highlighter constructed outside the asset pipeline
|
|
42
45
|
// entirely (a bare `new Code(...)` in a test or a headless measure). On
|
|
43
46
|
// the timeline the authoritative load is the one `declareAssets` declares,
|
|
@@ -54,7 +57,7 @@ let Code = class Code extends Node2D {
|
|
|
54
57
|
}
|
|
55
58
|
}
|
|
56
59
|
tokenize() {
|
|
57
|
-
this.setLines(
|
|
60
|
+
this.setLines(this._structureFor(this.code), this.code);
|
|
58
61
|
// Only consider ourselves tokenized once we actually highlighted; while
|
|
59
62
|
// the language is still loading we keep retrying on each render.
|
|
60
63
|
this.tokenized = canHighlight(this.language, this.theme);
|
|
@@ -66,10 +69,11 @@ let Code = class Code extends Node2D {
|
|
|
66
69
|
* counter rather than a hash of the content — a write that skipped the bump
|
|
67
70
|
* would keep serving the previous frame's geometry for the new listing.
|
|
68
71
|
*/
|
|
69
|
-
setLines(lines) {
|
|
72
|
+
setLines(lines, source) {
|
|
70
73
|
if (this.tokenLines === lines)
|
|
71
74
|
return;
|
|
72
75
|
this.tokenLines = lines;
|
|
76
|
+
this._linesSource = source;
|
|
73
77
|
this.structureVersion++;
|
|
74
78
|
this.layoutCache = null;
|
|
75
79
|
this.layoutCacheKey = null;
|
|
@@ -149,6 +153,7 @@ let Code = class Code extends Node2D {
|
|
|
149
153
|
return { from: edit.fromLayout, to: edit.toLayout, edit };
|
|
150
154
|
}
|
|
151
155
|
measure(constraints, scope) {
|
|
156
|
+
this._sync();
|
|
152
157
|
this.advanceCache.sync(this.advanceCache.signature(this.fontSize, this.fontFamily));
|
|
153
158
|
const wm = this.width;
|
|
154
159
|
const hm = this.height;
|
|
@@ -183,6 +188,7 @@ let Code = class Code extends Node2D {
|
|
|
183
188
|
// column-by-column rather than merely look different.
|
|
184
189
|
ctx.pushTextStyle(null);
|
|
185
190
|
try {
|
|
191
|
+
this._sync();
|
|
186
192
|
// Keep retrying until the language+theme have actually loaded, so a frame
|
|
187
193
|
// that rendered as plain text upgrades to full highlighting the moment the
|
|
188
194
|
// asset loader resolves. Never mid-edit: re-tokenizing mints fresh ids,
|
|
@@ -237,6 +243,7 @@ let Code = class Code extends Node2D {
|
|
|
237
243
|
* silhouette measured against stale metrics.
|
|
238
244
|
*/
|
|
239
245
|
hitTestSelf(local, tolerance) {
|
|
246
|
+
this._sync();
|
|
240
247
|
const layout = this.hitLayout();
|
|
241
248
|
if (!layout)
|
|
242
249
|
return super.hitTestSelf(local, tolerance);
|
|
@@ -286,11 +293,13 @@ let Code = class Code extends Node2D {
|
|
|
286
293
|
* above it, instead of colouring the new text as its own program.
|
|
287
294
|
*/
|
|
288
295
|
append(args) {
|
|
296
|
+
this._sync();
|
|
289
297
|
const { code } = args.data;
|
|
290
298
|
return this.editTo(this.joinedSource() + code, args.duration, args.easing);
|
|
291
299
|
}
|
|
292
300
|
/** Insert `code` above the listing. */
|
|
293
301
|
prepend(args) {
|
|
302
|
+
this._sync();
|
|
294
303
|
const { code } = args.data;
|
|
295
304
|
return this.editTo(code + this.joinedSource(), args.duration, args.easing);
|
|
296
305
|
}
|
|
@@ -301,6 +310,7 @@ let Code = class Code extends Node2D {
|
|
|
301
310
|
* of the existing line.
|
|
302
311
|
*/
|
|
303
312
|
insert(args) {
|
|
313
|
+
this._sync();
|
|
304
314
|
const { position, code } = args.data;
|
|
305
315
|
const source = this.joinedSource();
|
|
306
316
|
const offset = this.offsetAt(position);
|
|
@@ -319,6 +329,7 @@ let Code = class Code extends Node2D {
|
|
|
319
329
|
* the rest of the line reflows around the hole.
|
|
320
330
|
*/
|
|
321
331
|
erase(args) {
|
|
332
|
+
this._sync();
|
|
322
333
|
const { target: codeRange } = args.data;
|
|
323
334
|
const { duration, easing } = args;
|
|
324
335
|
const source = this.joinedSource();
|
|
@@ -345,6 +356,7 @@ let Code = class Code extends Node2D {
|
|
|
345
356
|
}
|
|
346
357
|
/** Replace the code in `codeRange` with `replacement`. */
|
|
347
358
|
replace(args) {
|
|
359
|
+
this._sync();
|
|
348
360
|
const { target: codeRange, replacement } = args.data;
|
|
349
361
|
const source = this.joinedSource();
|
|
350
362
|
const { start, end } = rangeToCharOffsets(codeRange, this.lineLengths());
|
|
@@ -358,6 +370,7 @@ let Code = class Code extends Node2D {
|
|
|
358
370
|
* again with a different range to cross-fade.
|
|
359
371
|
*/
|
|
360
372
|
highlight(args) {
|
|
373
|
+
this._sync();
|
|
361
374
|
const { target: codeRange, dim } = args.data;
|
|
362
375
|
const { duration, easing } = args;
|
|
363
376
|
const toDim = dim ?? 0.4;
|
|
@@ -392,6 +405,7 @@ let Code = class Code extends Node2D {
|
|
|
392
405
|
* highlight state.
|
|
393
406
|
*/
|
|
394
407
|
resetHighlight(args) {
|
|
408
|
+
this._sync();
|
|
395
409
|
const { duration, easing } = args;
|
|
396
410
|
if (this.highlightDimOpacity === null)
|
|
397
411
|
return driveCommand(duration, () => { });
|
|
@@ -452,6 +466,7 @@ let Code = class Code extends Node2D {
|
|
|
452
466
|
// the edit settles.
|
|
453
467
|
this.tokenized = canHighlight(this.language, this.theme);
|
|
454
468
|
return driveCommand(duration, (t) => {
|
|
469
|
+
this._drive();
|
|
455
470
|
const running = t > 0 && t < 1;
|
|
456
471
|
const index = this.transitions.indexOf(transition);
|
|
457
472
|
if (running && index < 0)
|
|
@@ -463,11 +478,11 @@ let Code = class Code extends Node2D {
|
|
|
463
478
|
// starts, the listing is what preceded it; at or past the end, the
|
|
464
479
|
// result. A `finally` could only ever have run forwards.
|
|
465
480
|
if (t <= 0) {
|
|
466
|
-
this.setLines(from);
|
|
481
|
+
this.setLines(from, fromCode);
|
|
467
482
|
this._writeProp("code", fromCode);
|
|
468
483
|
}
|
|
469
484
|
else {
|
|
470
|
-
this.setLines(edit.lines);
|
|
485
|
+
this.setLines(edit.lines, next);
|
|
471
486
|
this._writeProp("code", next);
|
|
472
487
|
}
|
|
473
488
|
});
|
|
@@ -484,6 +499,7 @@ let Code = class Code extends Node2D {
|
|
|
484
499
|
runDim(tokens, duration, easing, settle) {
|
|
485
500
|
const transition = { kind: "dim", tokens, progress: 0 };
|
|
486
501
|
return driveCommand(duration, (t) => {
|
|
502
|
+
this._drive();
|
|
487
503
|
const running = t > 0 && t < 1;
|
|
488
504
|
const index = this.transitions.indexOf(transition);
|
|
489
505
|
if (running && index < 0)
|
|
@@ -504,6 +520,7 @@ let Code = class Code extends Node2D {
|
|
|
504
520
|
* the rest of the step's props tween alongside it untouched.
|
|
505
521
|
*/
|
|
506
522
|
_prepareStep(to, duration, easing) {
|
|
523
|
+
this._sync();
|
|
507
524
|
const next = to.code;
|
|
508
525
|
if (typeof next !== "string" || next === this.joinedSource()) {
|
|
509
526
|
return super._prepareStep(to, duration, easing);
|
|
@@ -536,6 +553,7 @@ let Code = class Code extends Node2D {
|
|
|
536
553
|
const ranges = [];
|
|
537
554
|
if (!text)
|
|
538
555
|
return ranges;
|
|
556
|
+
this._sync();
|
|
539
557
|
const source = this.joinedSource();
|
|
540
558
|
const lineLens = this.lineLengths();
|
|
541
559
|
let from = 0;
|
|
@@ -558,9 +576,7 @@ let Code = class Code extends Node2D {
|
|
|
558
576
|
return this.findRangeAt(text, 0);
|
|
559
577
|
}
|
|
560
578
|
joinedSource() {
|
|
561
|
-
return this.
|
|
562
|
-
.map(line => line.tokens.map(t => t.content).join(''))
|
|
563
|
-
.join('\n');
|
|
579
|
+
return this._linesSource;
|
|
564
580
|
}
|
|
565
581
|
lineLengths() {
|
|
566
582
|
return this.tokenLines.map(line => line.tokens.reduce((acc, t) => acc + t.content.length, 0));
|
|
@@ -627,6 +643,43 @@ let Code = class Code extends Node2D {
|
|
|
627
643
|
highlightActive: this.highlightDimOpacity !== null || this.transitions.some(tr => tr.kind === "dim"),
|
|
628
644
|
});
|
|
629
645
|
}
|
|
646
|
+
/** Each source the props have named, tokenized once, so a listing derived again keeps the ids a highlight selected. */
|
|
647
|
+
_derived = new Map();
|
|
648
|
+
/** The first command to apply after a restore starts from the props' listing. */
|
|
649
|
+
_drive() {
|
|
650
|
+
this._sync();
|
|
651
|
+
this._writeProp("_driven", true);
|
|
652
|
+
}
|
|
653
|
+
_sync() {
|
|
654
|
+
if (!this._driven) {
|
|
655
|
+
this.transitions.length = 0;
|
|
656
|
+
this.highlightDimOpacity = null;
|
|
657
|
+
if (this.highlightedIds.size > 0)
|
|
658
|
+
this.highlightedIds = new Set();
|
|
659
|
+
this.setLines(this._structureFor(this.code), this.code);
|
|
660
|
+
}
|
|
661
|
+
else if (this._linesSource !== this.code && !this.activeEdit()) {
|
|
662
|
+
// A `set` or a binding moved `code` outside a listing command.
|
|
663
|
+
this.setLines(this._structureFor(this.code), this.code);
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
_structureFor(code) {
|
|
667
|
+
const highlighted = canHighlight(this.language, this.theme);
|
|
668
|
+
let entry = this._derived.get(code);
|
|
669
|
+
if (!entry || entry.language !== this.language || entry.theme !== this.theme || entry.highlighted !== highlighted) {
|
|
670
|
+
entry = {
|
|
671
|
+
language: this.language,
|
|
672
|
+
theme: this.theme,
|
|
673
|
+
highlighted,
|
|
674
|
+
lines: tokenizeCodeToIdLines(code, this.language, this.theme),
|
|
675
|
+
};
|
|
676
|
+
this._derived.delete(code);
|
|
677
|
+
this._derived.set(code, entry);
|
|
678
|
+
if (this._derived.size > DERIVED_LISTINGS)
|
|
679
|
+
this._derived.delete(this._derived.keys().next().value);
|
|
680
|
+
}
|
|
681
|
+
return entry.lines;
|
|
682
|
+
}
|
|
630
683
|
};
|
|
631
684
|
__decorate([
|
|
632
685
|
property({ default: "" })
|
|
@@ -656,7 +709,7 @@ __decorate([
|
|
|
656
709
|
property({ default: 2 })
|
|
657
710
|
], Code.prototype, "lineNumberGap", void 0);
|
|
658
711
|
__decorate([
|
|
659
|
-
|
|
712
|
+
insetsProperty()
|
|
660
713
|
], Code.prototype, "padding", void 0);
|
|
661
714
|
__decorate([
|
|
662
715
|
command({ args: [{ key: "code", kind: "text", multiline: true }] })
|
|
@@ -705,6 +758,8 @@ Code = __decorate([
|
|
|
705
758
|
})
|
|
706
759
|
], Code);
|
|
707
760
|
export { Code };
|
|
761
|
+
/** Sources a node keeps tokenized, oldest dropped first; a bound `code` can name any number of them. */
|
|
762
|
+
const DERIVED_LISTINGS = 16;
|
|
708
763
|
/**
|
|
709
764
|
* Normalize `highlight()`'s `codeRange` argument to a plain array: a single
|
|
710
765
|
* `CodeRange` (a plain object, not iterable) becomes a one-element array; a
|