@singapore-editor/tree-sitter 0.1.1
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/README.md +32 -0
- package/dist/assets/__vite-browser-external-CMrW8369.js +9 -0
- package/dist/assets/__vite-browser-external-CMrW8369.js.map +1 -0
- package/dist/assets/treeSitter.worker-D1ozCaGZ.js +5698 -0
- package/dist/assets/treeSitter.worker-D1ozCaGZ.js.map +1 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +143 -0
- package/dist/index.js.map +1 -0
- package/dist/session.d.ts +89 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +437 -0
- package/dist/session.js.map +1 -0
- package/dist/structuralSelection.d.ts +37 -0
- package/dist/structuralSelection.d.ts.map +1 -0
- package/dist/structuralSelection.js +139 -0
- package/dist/structuralSelection.js.map +1 -0
- package/dist/treeSitter/markdown.d.ts +12 -0
- package/dist/treeSitter/markdown.d.ts.map +1 -0
- package/dist/treeSitter/registry.d.ts +56 -0
- package/dist/treeSitter/registry.d.ts.map +1 -0
- package/dist/treeSitter/registry.js +144 -0
- package/dist/treeSitter/registry.js.map +1 -0
- package/dist/treeSitter/source.d.ts +42 -0
- package/dist/treeSitter/source.d.ts.map +1 -0
- package/dist/treeSitter/source.js +175 -0
- package/dist/treeSitter/source.js.map +1 -0
- package/dist/treeSitter/sourceChunkRetention.d.ts +30 -0
- package/dist/treeSitter/sourceChunkRetention.d.ts.map +1 -0
- package/dist/treeSitter/sourceChunkRetention.js +76 -0
- package/dist/treeSitter/sourceChunkRetention.js.map +1 -0
- package/dist/treeSitter/treeSitter.worker.d.ts +64 -0
- package/dist/treeSitter/treeSitter.worker.d.ts.map +1 -0
- package/dist/treeSitter/types.d.ts +198 -0
- package/dist/treeSitter/types.d.ts.map +1 -0
- package/dist/treeSitter/workerClient.d.ts +133 -0
- package/dist/treeSitter/workerClient.d.ts.map +1 -0
- package/dist/treeSitter/workerClient.js +420 -0
- package/dist/treeSitter/workerClient.js.map +1 -0
- package/package.json +50 -0
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { createAnchorSelection, normalizeSelectionSet, resolveSelection } from "@singapore-editor/core/document";
|
|
2
|
+
//#region src/structuralSelection.ts
|
|
3
|
+
/**
|
|
4
|
+
* The nesting the grammar found, as one unordered bucket for the editor's selection ladder to rank.
|
|
5
|
+
*
|
|
6
|
+
* Fold ranges are node ranges the parse has already published, so expand climbs exactly the nesting
|
|
7
|
+
* the gutter offers to collapse rather than a second, differently shaped idea of what encloses what.
|
|
8
|
+
* The fold query only reports nodes that span lines, so a construct written on one line is left to
|
|
9
|
+
* the word and line rungs.
|
|
10
|
+
*/
|
|
11
|
+
var treeSitterSelectionRanges = (folds) => folds.map((fold) => ({
|
|
12
|
+
start: fold.startIndex,
|
|
13
|
+
end: fold.endIndex
|
|
14
|
+
}));
|
|
15
|
+
var selectTreeSitterToken = async (options) => {
|
|
16
|
+
const input = normalizedSelectionInput(options);
|
|
17
|
+
return selectionCommandResult(options, input, await requestSelectionRanges(options, input.ranges, "selectToken"), (range) => [range]);
|
|
18
|
+
};
|
|
19
|
+
var expandTreeSitterSelection = async (options) => {
|
|
20
|
+
const input = normalizedSelectionInput(options);
|
|
21
|
+
return selectionCommandResult(options, input, await requestSelectionRanges(options, input.ranges, "expand"), (range, index) => {
|
|
22
|
+
const stack = stackForSelection(options, index, input.ranges[index]);
|
|
23
|
+
const previous = stack.at(-1);
|
|
24
|
+
if (previous && rangesEqual(previous, range)) return stack;
|
|
25
|
+
return [...stack, range];
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
var shrinkTreeSitterSelection = (options) => {
|
|
29
|
+
const input = normalizedSelectionInput(options);
|
|
30
|
+
const ranges = rangesFromShrinkState(options, input.ranges);
|
|
31
|
+
if (!ranges) return noOpSelectionCommandResult(options, input, "stale");
|
|
32
|
+
const stacks = options.state.stacks.map((stack) => stack.slice(0, -1));
|
|
33
|
+
const settled = settleSelectionRanges(options.snapshot, input, ranges, stacks);
|
|
34
|
+
return {
|
|
35
|
+
selections: settled.selections,
|
|
36
|
+
state: {
|
|
37
|
+
snapshotVersion: options.snapshotVersion,
|
|
38
|
+
stacks: settled.stacks
|
|
39
|
+
},
|
|
40
|
+
status: "ok"
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
var requestSelectionRanges = (options, ranges, action) => options.backend.select({
|
|
44
|
+
documentId: options.documentId,
|
|
45
|
+
runtimeSessionId: options.runtimeSessionId,
|
|
46
|
+
languageId: options.languageId,
|
|
47
|
+
snapshotVersion: options.snapshotVersion,
|
|
48
|
+
action,
|
|
49
|
+
ranges
|
|
50
|
+
});
|
|
51
|
+
var selectionCommandResult = (options, input, result, nextStack) => {
|
|
52
|
+
if (!result || result.status === "stale") return noOpSelectionCommandResult(options, input, "stale");
|
|
53
|
+
if (result.ranges.length !== input.sources.length) return noOpSelectionCommandResult(options, input, "stale");
|
|
54
|
+
const stacks = result.ranges.map(nextStack);
|
|
55
|
+
const settled = settleSelectionRanges(options.snapshot, input, result.ranges, stacks);
|
|
56
|
+
return {
|
|
57
|
+
selections: settled.selections,
|
|
58
|
+
state: {
|
|
59
|
+
snapshotVersion: options.snapshotVersion,
|
|
60
|
+
stacks: settled.stacks
|
|
61
|
+
},
|
|
62
|
+
status: "ok"
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
var noOpSelectionCommandResult = (options, input, status) => ({
|
|
66
|
+
selections: options.selections,
|
|
67
|
+
state: options.state ?? {
|
|
68
|
+
snapshotVersion: options.snapshotVersion,
|
|
69
|
+
stacks: input.ranges.map((range) => [range])
|
|
70
|
+
},
|
|
71
|
+
status
|
|
72
|
+
});
|
|
73
|
+
var normalizedSelectionInput = (options) => {
|
|
74
|
+
const selections = normalizeSelectionSet(options.snapshot, options.selections);
|
|
75
|
+
const sources = selections.selections.map((selection) => resolveSelection(options.snapshot, selection));
|
|
76
|
+
return {
|
|
77
|
+
selections,
|
|
78
|
+
sources,
|
|
79
|
+
ranges: sources.map(selectionRange)
|
|
80
|
+
};
|
|
81
|
+
};
|
|
82
|
+
var settleSelectionRanges = (snapshot, input, ranges, stacks) => {
|
|
83
|
+
const selections = ranges.map((range, index) => {
|
|
84
|
+
const source = input.sources[index];
|
|
85
|
+
return createAnchorSelection(snapshot, range.startIndex, range.endIndex, {
|
|
86
|
+
affinity: source?.affinity,
|
|
87
|
+
id: source?.id,
|
|
88
|
+
reversed: source?.reversed ?? false
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
const normalized = normalizeSelectionSet(snapshot, {
|
|
92
|
+
selections,
|
|
93
|
+
lastAddedIndex: input.selections.lastAddedIndex,
|
|
94
|
+
normalized: false
|
|
95
|
+
});
|
|
96
|
+
const stackById = new Map(input.sources.map((source, index) => [source.id, stacks[index] ?? []]));
|
|
97
|
+
return {
|
|
98
|
+
selections: normalized,
|
|
99
|
+
stacks: normalized.selections.map((selection) => {
|
|
100
|
+
const resolved = resolveSelection(snapshot, selection);
|
|
101
|
+
return stackWithTop(stackById.get(resolved.id) ?? [], selectionRange(resolved));
|
|
102
|
+
})
|
|
103
|
+
};
|
|
104
|
+
};
|
|
105
|
+
var rangesFromShrinkState = (options, selected) => {
|
|
106
|
+
if (!options.state) return null;
|
|
107
|
+
if (options.state.snapshotVersion !== options.snapshotVersion) return null;
|
|
108
|
+
if (options.state.stacks.length !== selected.length) return null;
|
|
109
|
+
const ranges = options.state.stacks.map((stack, index) => {
|
|
110
|
+
const top = stack.at(-1);
|
|
111
|
+
const current = selected[index];
|
|
112
|
+
if (!top || !current || !rangesEqual(top, current)) return void 0;
|
|
113
|
+
return stack.at(-2) ?? top;
|
|
114
|
+
});
|
|
115
|
+
if (ranges.some((range) => !range)) return null;
|
|
116
|
+
return ranges;
|
|
117
|
+
};
|
|
118
|
+
var selectionRange = (selection) => ({
|
|
119
|
+
startIndex: selection.startOffset,
|
|
120
|
+
endIndex: selection.endOffset
|
|
121
|
+
});
|
|
122
|
+
var stackWithTop = (stack, range) => {
|
|
123
|
+
const top = stack.at(-1);
|
|
124
|
+
if (top && rangesEqual(top, range)) return stack;
|
|
125
|
+
if (stack.length === 0) return [range];
|
|
126
|
+
return [...stack.slice(0, -1), range];
|
|
127
|
+
};
|
|
128
|
+
var stackForSelection = (options, index, selected) => {
|
|
129
|
+
if (!selected) return [];
|
|
130
|
+
if (options.state?.snapshotVersion !== options.snapshotVersion) return [selected];
|
|
131
|
+
const stack = options.state.stacks[index];
|
|
132
|
+
const top = stack?.at(-1);
|
|
133
|
+
return stack && top && rangesEqual(top, selected) ? stack : [selected];
|
|
134
|
+
};
|
|
135
|
+
var rangesEqual = (left, right) => left.startIndex === right.startIndex && left.endIndex === right.endIndex;
|
|
136
|
+
//#endregion
|
|
137
|
+
export { expandTreeSitterSelection, selectTreeSitterToken, shrinkTreeSitterSelection, treeSitterSelectionRanges };
|
|
138
|
+
|
|
139
|
+
//# sourceMappingURL=structuralSelection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"structuralSelection.js","names":[],"sources":["../src/structuralSelection.ts"],"sourcesContent":["import type { PieceTableSnapshot, TextOffsetRange } from '@singapore-editor/core/document'\nimport type { FoldRange } from '@singapore-editor/core/syntax'\nimport {\n createAnchorSelection,\n normalizeSelectionSet,\n type PieceTableAnchor,\n resolveSelection,\n type SelectionSet,\n} from '@singapore-editor/core/document'\nimport type { TreeSitterBackend } from './treeSitter/workerClient'\nimport type {\n TreeSitterLanguageId,\n TreeSitterSelectionRange,\n TreeSitterSelectionResult,\n} from './treeSitter/types'\n\nexport type TreeSitterSelectionExpansionState = {\n readonly snapshotVersion: number\n readonly stacks: readonly (readonly TreeSitterSelectionRange[])[]\n}\n\nexport type TreeSitterSelectionCommandOptions = {\n readonly documentId: string\n readonly runtimeSessionId: string\n readonly languageId: TreeSitterLanguageId\n readonly snapshotVersion: number\n readonly snapshot: PieceTableSnapshot\n readonly selections: SelectionSet<PieceTableAnchor>\n readonly backend: Pick<TreeSitterBackend, 'select'>\n readonly state?: TreeSitterSelectionExpansionState\n}\n\nexport type TreeSitterSelectionCommandResult = {\n readonly selections: SelectionSet<PieceTableAnchor>\n readonly state: TreeSitterSelectionExpansionState\n readonly status: 'ok' | 'stale'\n}\n\ntype NormalizedSelectionInput = {\n readonly selections: SelectionSet<PieceTableAnchor>\n readonly sources: readonly ResolvedSelection[]\n readonly ranges: readonly TreeSitterSelectionRange[]\n}\n\ntype ResolvedSelection = ReturnType<typeof resolveSelection>\n\ntype SettledSelectionResult = {\n readonly selections: SelectionSet<PieceTableAnchor>\n readonly stacks: readonly (readonly TreeSitterSelectionRange[])[]\n}\n\n/**\n * The nesting the grammar found, as one unordered bucket for the editor's selection ladder to rank.\n *\n * Fold ranges are node ranges the parse has already published, so expand climbs exactly the nesting\n * the gutter offers to collapse rather than a second, differently shaped idea of what encloses what.\n * The fold query only reports nodes that span lines, so a construct written on one line is left to\n * the word and line rungs.\n */\nexport const treeSitterSelectionRanges = (\n folds: readonly FoldRange[],\n): readonly TextOffsetRange[] =>\n folds.map((fold) => ({ start: fold.startIndex, end: fold.endIndex }))\n\nexport const selectTreeSitterToken = async (\n options: TreeSitterSelectionCommandOptions,\n): Promise<TreeSitterSelectionCommandResult> => {\n const input = normalizedSelectionInput(options)\n const result = await requestSelectionRanges(options, input.ranges, 'selectToken')\n return selectionCommandResult(options, input, result, (range) => [range])\n}\n\nexport const expandTreeSitterSelection = async (\n options: TreeSitterSelectionCommandOptions,\n): Promise<TreeSitterSelectionCommandResult> => {\n const input = normalizedSelectionInput(options)\n const result = await requestSelectionRanges(options, input.ranges, 'expand')\n return selectionCommandResult(options, input, result, (range, index) => {\n const stack = stackForSelection(options, index, input.ranges[index])\n const previous = stack.at(-1)\n if (previous && rangesEqual(previous, range)) return stack\n return [...stack, range]\n })\n}\n\nexport const shrinkTreeSitterSelection = (\n options: TreeSitterSelectionCommandOptions,\n): TreeSitterSelectionCommandResult => {\n const input = normalizedSelectionInput(options)\n const ranges = rangesFromShrinkState(options, input.ranges)\n if (!ranges) return noOpSelectionCommandResult(options, input, 'stale')\n\n const stacks = options.state!.stacks.map((stack) => stack.slice(0, -1))\n const settled = settleSelectionRanges(options.snapshot, input, ranges, stacks)\n\n return {\n selections: settled.selections,\n state: {\n snapshotVersion: options.snapshotVersion,\n stacks: settled.stacks,\n },\n status: 'ok',\n }\n}\n\nconst requestSelectionRanges = (\n options: TreeSitterSelectionCommandOptions,\n ranges: readonly TreeSitterSelectionRange[],\n action: 'selectToken' | 'expand',\n): Promise<TreeSitterSelectionResult | undefined> =>\n options.backend.select({\n documentId: options.documentId,\n runtimeSessionId: options.runtimeSessionId,\n languageId: options.languageId,\n snapshotVersion: options.snapshotVersion,\n action,\n ranges,\n })\n\nconst selectionCommandResult = (\n options: TreeSitterSelectionCommandOptions,\n input: NormalizedSelectionInput,\n result: TreeSitterSelectionResult | undefined,\n nextStack: (\n range: TreeSitterSelectionRange,\n index: number,\n ) => readonly TreeSitterSelectionRange[],\n): TreeSitterSelectionCommandResult => {\n if (!result || result.status === 'stale') {\n return noOpSelectionCommandResult(options, input, 'stale')\n }\n if (result.ranges.length !== input.sources.length) {\n return noOpSelectionCommandResult(options, input, 'stale')\n }\n\n const stacks = result.ranges.map(nextStack)\n const settled = settleSelectionRanges(options.snapshot, input, result.ranges, stacks)\n\n return {\n selections: settled.selections,\n state: {\n snapshotVersion: options.snapshotVersion,\n stacks: settled.stacks,\n },\n status: 'ok',\n }\n}\n\nconst noOpSelectionCommandResult = (\n options: TreeSitterSelectionCommandOptions,\n input: NormalizedSelectionInput,\n status: 'ok' | 'stale',\n): TreeSitterSelectionCommandResult => ({\n selections: options.selections,\n state: options.state ?? {\n snapshotVersion: options.snapshotVersion,\n stacks: input.ranges.map((range) => [range]),\n },\n status,\n})\n\nconst normalizedSelectionInput = (\n options: TreeSitterSelectionCommandOptions,\n): NormalizedSelectionInput => {\n const selections = normalizeSelectionSet(options.snapshot, options.selections)\n const sources = selections.selections.map((selection) =>\n resolveSelection(options.snapshot, selection),\n )\n return {\n selections,\n sources,\n ranges: sources.map(selectionRange),\n }\n}\n\nconst settleSelectionRanges = (\n snapshot: PieceTableSnapshot,\n input: NormalizedSelectionInput,\n ranges: readonly TreeSitterSelectionRange[],\n stacks: readonly (readonly TreeSitterSelectionRange[])[],\n): SettledSelectionResult => {\n const selections = ranges.map((range, index) => {\n const source = input.sources[index]\n return createAnchorSelection(snapshot, range.startIndex, range.endIndex, {\n affinity: source?.affinity,\n id: source?.id,\n // Which end leads is the user's, not the tree's: a selection dragged right to left keeps\n // growing away from its anchor.\n reversed: source?.reversed ?? false,\n })\n })\n\n const normalized = normalizeSelectionSet(snapshot, {\n selections,\n lastAddedIndex: input.selections.lastAddedIndex,\n normalized: false,\n })\n const stackById = new Map(\n input.sources.map((source, index) => [source.id, stacks[index] ?? []] as const),\n )\n const settledStacks = normalized.selections.map((selection) => {\n const resolved = resolveSelection(snapshot, selection)\n return stackWithTop(stackById.get(resolved.id) ?? [], selectionRange(resolved))\n })\n\n return { selections: normalized, stacks: settledStacks }\n}\n\nconst rangesFromShrinkState = (\n options: TreeSitterSelectionCommandOptions,\n selected: readonly TreeSitterSelectionRange[],\n): readonly TreeSitterSelectionRange[] | null => {\n if (!options.state) return null\n if (options.state.snapshotVersion !== options.snapshotVersion) return null\n\n if (options.state.stacks.length !== selected.length) return null\n\n const ranges = options.state.stacks.map((stack, index) => {\n const top = stack.at(-1)\n const current = selected[index]\n if (!top || !current || !rangesEqual(top, current)) return undefined\n return stack.at(-2) ?? top\n })\n if (ranges.some((range) => !range)) return null\n return ranges as readonly TreeSitterSelectionRange[]\n}\n\nconst selectionRange = (selection: ResolvedSelection): TreeSitterSelectionRange => ({\n startIndex: selection.startOffset,\n endIndex: selection.endOffset,\n})\n\nconst stackWithTop = (\n stack: readonly TreeSitterSelectionRange[],\n range: TreeSitterSelectionRange,\n): readonly TreeSitterSelectionRange[] => {\n const top = stack.at(-1)\n if (top && rangesEqual(top, range)) return stack\n if (stack.length === 0) return [range]\n return [...stack.slice(0, -1), range]\n}\n\nconst stackForSelection = (\n options: TreeSitterSelectionCommandOptions,\n index: number,\n selected: TreeSitterSelectionRange | undefined,\n): readonly TreeSitterSelectionRange[] => {\n if (!selected) return []\n if (options.state?.snapshotVersion !== options.snapshotVersion) return [selected]\n\n const stack = options.state.stacks[index]\n const top = stack?.at(-1)\n return stack && top && rangesEqual(top, selected) ? stack : [selected]\n}\n\nconst rangesEqual = (left: TreeSitterSelectionRange, right: TreeSitterSelectionRange): boolean =>\n left.startIndex === right.startIndex && left.endIndex === right.endIndex\n"],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { MarkdownDocument } from 'tree-sitter-md';
|
|
2
|
+
import { type Node, type Range } from 'web-tree-sitter';
|
|
3
|
+
import type { TextEdit } from '@singapore-editor/core/document';
|
|
4
|
+
import type { FoldRange, TreeSitterCapture, TreeSitterSyntaxRange } from './types';
|
|
5
|
+
export declare const initializeMarkdown: () => Promise<void>;
|
|
6
|
+
export declare function editMarkdown(document: MarkdownDocument, edits: readonly TextEdit[]): void;
|
|
7
|
+
export declare function markdownCaptures(document: MarkdownDocument, range: TreeSitterSyntaxRange): TreeSitterCapture[];
|
|
8
|
+
export declare function markdownFolds(document: MarkdownDocument, range: TreeSitterSyntaxRange): FoldRange[];
|
|
9
|
+
export declare function markdownRange(document: MarkdownDocument, startIndex: number, endIndex: number): Range;
|
|
10
|
+
export declare function markdownMdxSource(text: string, root: Node, offset?: number): string;
|
|
11
|
+
export declare function markdownRecords(document: MarkdownDocument, range: TreeSitterSyntaxRange): Uint32Array;
|
|
12
|
+
//# sourceMappingURL=markdown.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/treeSitter/markdown.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAGvE,OAAO,EAAY,KAAK,IAAI,EAAE,KAAK,KAAK,EAAE,MAAM,iBAAiB,CAAA;AACjE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAA;AAC/D,OAAO,KAAK,EAAE,SAAS,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAA;AAGlF,eAAO,MAAM,kBAAkB,QAAO,OAAO,CAAC,IAAI,CAQjD,CAAA;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,gBAAgB,EAAE,KAAK,EAAE,SAAS,QAAQ,EAAE,GAAG,IAAI,CAIzF;AAED,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,gBAAgB,EAC1B,KAAK,EAAE,qBAAqB,GAC3B,iBAAiB,EAAE,CAuBrB;AAED,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,gBAAgB,EAC1B,KAAK,EAAE,qBAAqB,GAC3B,SAAS,EAAE,CAmBb;AAED,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,gBAAgB,EAC1B,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,GACf,KAAK,CAOP;AAcD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,SAAI,GAAG,MAAM,CAe9E;AAED,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,gBAAgB,EAC1B,KAAK,EAAE,qBAAqB,GAC3B,WAAW,CAqBb"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
export type TreeSitterLanguageId = string;
|
|
2
|
+
export type TreeSitterLanguageAssets = {
|
|
3
|
+
readonly wasmUrl: string;
|
|
4
|
+
readonly highlightQuerySource?: string;
|
|
5
|
+
readonly foldQuerySource?: string;
|
|
6
|
+
readonly injectionQuerySource?: string;
|
|
7
|
+
};
|
|
8
|
+
type TreeSitterLanguageContributionMetadata = {
|
|
9
|
+
readonly id: TreeSitterLanguageId;
|
|
10
|
+
readonly extensions?: readonly string[];
|
|
11
|
+
readonly aliases?: readonly string[];
|
|
12
|
+
readonly filenames?: readonly string[];
|
|
13
|
+
readonly injectionDependencies?: readonly string[];
|
|
14
|
+
};
|
|
15
|
+
type TreeSitterInlineLanguageContribution = TreeSitterLanguageContributionMetadata & TreeSitterLanguageAssets & {
|
|
16
|
+
readonly load?: never;
|
|
17
|
+
};
|
|
18
|
+
type TreeSitterLazyLanguageContribution = TreeSitterLanguageContributionMetadata & {
|
|
19
|
+
readonly load: () => Promise<TreeSitterLanguageAssets>;
|
|
20
|
+
};
|
|
21
|
+
export type TreeSitterLanguageContribution = TreeSitterInlineLanguageContribution | TreeSitterLazyLanguageContribution;
|
|
22
|
+
export type TreeSitterLanguageDescriptor = TreeSitterLanguageContributionMetadata & TreeSitterLanguageAssets & {
|
|
23
|
+
readonly extensions: readonly string[];
|
|
24
|
+
readonly aliases: readonly string[];
|
|
25
|
+
};
|
|
26
|
+
export type TreeSitterLanguageRegistrationOptions = {
|
|
27
|
+
readonly replace?: boolean;
|
|
28
|
+
};
|
|
29
|
+
export type TreeSitterLanguageDisposable = {
|
|
30
|
+
dispose(): void;
|
|
31
|
+
};
|
|
32
|
+
export type TreeSitterLanguageResolver = {
|
|
33
|
+
resolveTreeSitterLanguage(languageId: TreeSitterLanguageId): Promise<TreeSitterLanguageDescriptor | null>;
|
|
34
|
+
};
|
|
35
|
+
export declare class TreeSitterLanguageRegistry implements TreeSitterLanguageResolver {
|
|
36
|
+
private readonly registrations;
|
|
37
|
+
registerLanguage(contribution: TreeSitterLanguageContribution, options?: TreeSitterLanguageRegistrationOptions): TreeSitterLanguageDisposable;
|
|
38
|
+
hasLanguage(languageId: string | null | undefined): boolean;
|
|
39
|
+
resolveLanguageAlias(alias: string | null | undefined): TreeSitterLanguageId | null;
|
|
40
|
+
resolveTreeSitterLanguage(languageId: TreeSitterLanguageId): Promise<TreeSitterLanguageDescriptor | null>;
|
|
41
|
+
clear(): void;
|
|
42
|
+
private assertCanRegister;
|
|
43
|
+
private unregisterLanguage;
|
|
44
|
+
private findActiveRegistration;
|
|
45
|
+
private activeRegistrationForId;
|
|
46
|
+
private isActiveRegistration;
|
|
47
|
+
}
|
|
48
|
+
export declare const createTreeSitterLanguageRegistry: () => TreeSitterLanguageRegistry;
|
|
49
|
+
export declare const resolveTreeSitterLanguageContribution: (contribution: TreeSitterLanguageContribution) => Promise<TreeSitterLanguageDescriptor>;
|
|
50
|
+
/** A language's descriptor followed by every language its injection queries name, transitively. */
|
|
51
|
+
export declare const resolveTreeSitterLanguageClosure: (resolver: TreeSitterLanguageResolver, languageId: TreeSitterLanguageId, isCancelled?: () => boolean) => Promise<readonly TreeSitterLanguageDescriptor[]>;
|
|
52
|
+
export declare const withInjectedLanguages: (resolver: TreeSitterLanguageResolver | undefined, descriptor: TreeSitterLanguageDescriptor, isCancelled: () => boolean) => Promise<readonly TreeSitterLanguageDescriptor[]>;
|
|
53
|
+
export declare const resolveTreeSitterLanguageAlias: (alias: string | null | undefined, registry?: TreeSitterLanguageRegistry) => TreeSitterLanguageId | null;
|
|
54
|
+
export declare const isTreeSitterLanguageId: (languageId: string | null | undefined) => languageId is TreeSitterLanguageId;
|
|
55
|
+
export {};
|
|
56
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/treeSitter/registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
//#region src/treeSitter/registry.ts
|
|
2
|
+
var TreeSitterLanguageRegistry = class {
|
|
3
|
+
registrations = [];
|
|
4
|
+
registerLanguage(contribution, options = {}) {
|
|
5
|
+
const registration = createRegistration(contribution);
|
|
6
|
+
this.assertCanRegister(registration.id, options);
|
|
7
|
+
this.registrations.push(registration);
|
|
8
|
+
return { dispose: () => this.unregisterLanguage(registration) };
|
|
9
|
+
}
|
|
10
|
+
hasLanguage(languageId) {
|
|
11
|
+
const id = normalizeOptionalLanguageId(languageId);
|
|
12
|
+
if (!id) return false;
|
|
13
|
+
return this.activeRegistrationForId(id) !== null;
|
|
14
|
+
}
|
|
15
|
+
resolveLanguageAlias(alias) {
|
|
16
|
+
const normalized = normalizeOptionalAlias(alias);
|
|
17
|
+
if (!normalized) return null;
|
|
18
|
+
return this.findActiveRegistration((candidate) => {
|
|
19
|
+
if (candidate.id.toLowerCase() === normalized) return true;
|
|
20
|
+
return candidate.aliases.includes(normalized);
|
|
21
|
+
})?.id ?? null;
|
|
22
|
+
}
|
|
23
|
+
async resolveTreeSitterLanguage(languageId) {
|
|
24
|
+
const id = this.resolveLanguageAlias(languageId) ?? normalizeLanguageId(languageId);
|
|
25
|
+
const registration = this.activeRegistrationForId(id);
|
|
26
|
+
if (!registration) return null;
|
|
27
|
+
if (!registration.descriptorPromise) registration.descriptorPromise = resolveTreeSitterLanguageContribution(registration.contribution);
|
|
28
|
+
return registration.descriptorPromise;
|
|
29
|
+
}
|
|
30
|
+
clear() {
|
|
31
|
+
this.registrations.length = 0;
|
|
32
|
+
}
|
|
33
|
+
assertCanRegister(languageId, options) {
|
|
34
|
+
if (options.replace) return;
|
|
35
|
+
if (!this.hasLanguage(languageId)) return;
|
|
36
|
+
throw new Error(`Tree-sitter language "${languageId}" is already registered`);
|
|
37
|
+
}
|
|
38
|
+
unregisterLanguage(registration) {
|
|
39
|
+
const index = this.registrations.indexOf(registration);
|
|
40
|
+
if (index === -1) return;
|
|
41
|
+
this.registrations.splice(index, 1);
|
|
42
|
+
}
|
|
43
|
+
findActiveRegistration(predicate) {
|
|
44
|
+
for (let index = this.registrations.length - 1; index >= 0; index -= 1) {
|
|
45
|
+
const registration = this.registrations[index];
|
|
46
|
+
if (!this.isActiveRegistration(registration)) continue;
|
|
47
|
+
if (predicate(registration)) return registration;
|
|
48
|
+
}
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
activeRegistrationForId(languageId) {
|
|
52
|
+
for (let index = this.registrations.length - 1; index >= 0; index -= 1) {
|
|
53
|
+
const registration = this.registrations[index];
|
|
54
|
+
if (registration.id === languageId) return registration;
|
|
55
|
+
}
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
isActiveRegistration(registration) {
|
|
59
|
+
return this.activeRegistrationForId(registration.id) === registration;
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
var createTreeSitterLanguageRegistry = () => new TreeSitterLanguageRegistry();
|
|
63
|
+
var resolveTreeSitterLanguageContribution = async (contribution) => {
|
|
64
|
+
return createTreeSitterLanguageDescriptor(contribution, await loadTreeSitterLanguageAssets(contribution));
|
|
65
|
+
};
|
|
66
|
+
/** A language's descriptor followed by every language its injection queries name, transitively. */
|
|
67
|
+
var resolveTreeSitterLanguageClosure = async (resolver, languageId, isCancelled = () => false) => {
|
|
68
|
+
const descriptor = await resolver.resolveTreeSitterLanguage(languageId);
|
|
69
|
+
if (!descriptor || isCancelled()) return [];
|
|
70
|
+
return withInjectedLanguages(resolver, descriptor, isCancelled);
|
|
71
|
+
};
|
|
72
|
+
var withInjectedLanguages = async (resolver, descriptor, isCancelled) => {
|
|
73
|
+
const descriptors = [descriptor];
|
|
74
|
+
const seen = /* @__PURE__ */ new Set([descriptor.id]);
|
|
75
|
+
for (let index = 0; index < descriptors.length; index += 1) {
|
|
76
|
+
const dependencies = descriptors[index]?.injectionDependencies ?? [];
|
|
77
|
+
for (const id of dependencies) {
|
|
78
|
+
if (seen.has(id) || isCancelled()) continue;
|
|
79
|
+
seen.add(id);
|
|
80
|
+
const injected = await resolver?.resolveTreeSitterLanguage(id);
|
|
81
|
+
if (injected) descriptors.push(injected);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return descriptors;
|
|
85
|
+
};
|
|
86
|
+
var resolveTreeSitterLanguageAlias = (alias, registry) => registry?.resolveLanguageAlias(alias) ?? null;
|
|
87
|
+
var isTreeSitterLanguageId = (languageId) => normalizeOptionalLanguageId(languageId) !== null;
|
|
88
|
+
var createRegistration = (contribution) => ({
|
|
89
|
+
contribution,
|
|
90
|
+
id: normalizeLanguageId(contribution.id),
|
|
91
|
+
aliases: uniqueItems((contribution.aliases ?? []).map(normalizeAlias)),
|
|
92
|
+
descriptorPromise: null
|
|
93
|
+
});
|
|
94
|
+
var createTreeSitterLanguageDescriptor = (contribution, assets) => ({
|
|
95
|
+
id: normalizeLanguageId(contribution.id),
|
|
96
|
+
extensions: uniqueItems((contribution.extensions ?? []).map(normalizeExtension)),
|
|
97
|
+
aliases: uniqueItems((contribution.aliases ?? []).map(normalizeAlias)),
|
|
98
|
+
filenames: contribution.filenames ?? [],
|
|
99
|
+
injectionDependencies: contribution.injectionDependencies ?? [],
|
|
100
|
+
wasmUrl: normalizeWasmUrl(assets.wasmUrl, contribution.id),
|
|
101
|
+
highlightQuerySource: assets.highlightQuerySource,
|
|
102
|
+
foldQuerySource: assets.foldQuerySource,
|
|
103
|
+
injectionQuerySource: assets.injectionQuerySource
|
|
104
|
+
});
|
|
105
|
+
var loadTreeSitterLanguageAssets = async (contribution) => {
|
|
106
|
+
if ("load" in contribution && contribution.load) return contribution.load();
|
|
107
|
+
return contribution;
|
|
108
|
+
};
|
|
109
|
+
var normalizeOptionalLanguageId = (languageId) => {
|
|
110
|
+
if (!languageId) return null;
|
|
111
|
+
const id = languageId.trim();
|
|
112
|
+
return id.length > 0 ? id : null;
|
|
113
|
+
};
|
|
114
|
+
var normalizeLanguageId = (languageId) => {
|
|
115
|
+
const id = normalizeOptionalLanguageId(languageId);
|
|
116
|
+
if (id) return id;
|
|
117
|
+
throw new Error("Tree-sitter language id cannot be empty");
|
|
118
|
+
};
|
|
119
|
+
var normalizeOptionalAlias = (alias) => {
|
|
120
|
+
if (!alias) return null;
|
|
121
|
+
const normalized = alias.trim().toLowerCase();
|
|
122
|
+
return normalized.length > 0 ? normalized : null;
|
|
123
|
+
};
|
|
124
|
+
var normalizeAlias = (alias) => {
|
|
125
|
+
const normalized = normalizeOptionalAlias(alias);
|
|
126
|
+
if (normalized) return normalized;
|
|
127
|
+
throw new Error("Tree-sitter language alias cannot be empty");
|
|
128
|
+
};
|
|
129
|
+
var normalizeExtension = (extension) => {
|
|
130
|
+
const normalized = extension.trim().toLowerCase();
|
|
131
|
+
if (!normalized) throw new Error("Tree-sitter language extension cannot be empty");
|
|
132
|
+
if (normalized.startsWith(".")) return normalized;
|
|
133
|
+
return `.${normalized}`;
|
|
134
|
+
};
|
|
135
|
+
var normalizeWasmUrl = (wasmUrl, languageId) => {
|
|
136
|
+
const normalized = wasmUrl.trim();
|
|
137
|
+
if (normalized) return normalized;
|
|
138
|
+
throw new Error(`Tree-sitter language "${languageId}" is missing a wasmUrl`);
|
|
139
|
+
};
|
|
140
|
+
var uniqueItems = (items) => Array.from(new Set(items));
|
|
141
|
+
//#endregion
|
|
142
|
+
export { TreeSitterLanguageRegistry, createTreeSitterLanguageRegistry, isTreeSitterLanguageId, resolveTreeSitterLanguageAlias, resolveTreeSitterLanguageClosure, resolveTreeSitterLanguageContribution, withInjectedLanguages };
|
|
143
|
+
|
|
144
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","names":[],"sources":["../../src/treeSitter/registry.ts"],"sourcesContent":["export type TreeSitterLanguageId = string\n\nexport type TreeSitterLanguageAssets = {\n readonly wasmUrl: string\n readonly highlightQuerySource?: string\n readonly foldQuerySource?: string\n readonly injectionQuerySource?: string\n}\n\ntype TreeSitterLanguageContributionMetadata = {\n readonly id: TreeSitterLanguageId\n readonly extensions?: readonly string[]\n readonly aliases?: readonly string[]\n readonly filenames?: readonly string[]\n readonly injectionDependencies?: readonly string[]\n}\n\ntype TreeSitterInlineLanguageContribution = TreeSitterLanguageContributionMetadata &\n TreeSitterLanguageAssets & {\n readonly load?: never\n }\n\ntype TreeSitterLazyLanguageContribution = TreeSitterLanguageContributionMetadata & {\n readonly load: () => Promise<TreeSitterLanguageAssets>\n}\n\nexport type TreeSitterLanguageContribution =\n | TreeSitterInlineLanguageContribution\n | TreeSitterLazyLanguageContribution\n\nexport type TreeSitterLanguageDescriptor = TreeSitterLanguageContributionMetadata &\n TreeSitterLanguageAssets & {\n readonly extensions: readonly string[]\n readonly aliases: readonly string[]\n }\n\nexport type TreeSitterLanguageRegistrationOptions = {\n readonly replace?: boolean\n}\n\nexport type TreeSitterLanguageDisposable = {\n dispose(): void\n}\n\nexport type TreeSitterLanguageResolver = {\n resolveTreeSitterLanguage(\n languageId: TreeSitterLanguageId,\n ): Promise<TreeSitterLanguageDescriptor | null>\n}\n\ntype TreeSitterLanguageRegistration = {\n readonly contribution: TreeSitterLanguageContribution\n readonly id: TreeSitterLanguageId\n readonly aliases: readonly string[]\n descriptorPromise: Promise<TreeSitterLanguageDescriptor> | null\n}\n\nexport class TreeSitterLanguageRegistry implements TreeSitterLanguageResolver {\n private readonly registrations: TreeSitterLanguageRegistration[] = []\n\n public registerLanguage(\n contribution: TreeSitterLanguageContribution,\n options: TreeSitterLanguageRegistrationOptions = {},\n ): TreeSitterLanguageDisposable {\n const registration = createRegistration(contribution)\n this.assertCanRegister(registration.id, options)\n this.registrations.push(registration)\n\n return {\n dispose: () => this.unregisterLanguage(registration),\n }\n }\n\n public hasLanguage(languageId: string | null | undefined): boolean {\n const id = normalizeOptionalLanguageId(languageId)\n if (!id) return false\n return this.activeRegistrationForId(id) !== null\n }\n\n public resolveLanguageAlias(alias: string | null | undefined): TreeSitterLanguageId | null {\n const normalized = normalizeOptionalAlias(alias)\n if (!normalized) return null\n\n const registration = this.findActiveRegistration((candidate) => {\n if (candidate.id.toLowerCase() === normalized) return true\n return candidate.aliases.includes(normalized)\n })\n return registration?.id ?? null\n }\n\n public async resolveTreeSitterLanguage(\n languageId: TreeSitterLanguageId,\n ): Promise<TreeSitterLanguageDescriptor | null> {\n const id = this.resolveLanguageAlias(languageId) ?? normalizeLanguageId(languageId)\n const registration = this.activeRegistrationForId(id)\n if (!registration) return null\n\n if (!registration.descriptorPromise) {\n registration.descriptorPromise = resolveTreeSitterLanguageContribution(\n registration.contribution,\n )\n }\n\n return registration.descriptorPromise\n }\n\n public clear(): void {\n this.registrations.length = 0\n }\n\n private assertCanRegister(\n languageId: TreeSitterLanguageId,\n options: TreeSitterLanguageRegistrationOptions,\n ): void {\n if (options.replace) return\n if (!this.hasLanguage(languageId)) return\n\n throw new Error(`Tree-sitter language \"${languageId}\" is already registered`)\n }\n\n private unregisterLanguage(registration: TreeSitterLanguageRegistration): void {\n const index = this.registrations.indexOf(registration)\n if (index === -1) return\n\n this.registrations.splice(index, 1)\n }\n\n private findActiveRegistration(\n predicate: (registration: TreeSitterLanguageRegistration) => boolean,\n ): TreeSitterLanguageRegistration | null {\n for (let index = this.registrations.length - 1; index >= 0; index -= 1) {\n const registration = this.registrations[index]!\n if (!this.isActiveRegistration(registration)) continue\n if (predicate(registration)) return registration\n }\n\n return null\n }\n\n private activeRegistrationForId(\n languageId: TreeSitterLanguageId,\n ): TreeSitterLanguageRegistration | null {\n for (let index = this.registrations.length - 1; index >= 0; index -= 1) {\n const registration = this.registrations[index]!\n if (registration.id === languageId) return registration\n }\n\n return null\n }\n\n private isActiveRegistration(registration: TreeSitterLanguageRegistration): boolean {\n return this.activeRegistrationForId(registration.id) === registration\n }\n}\n\nexport const createTreeSitterLanguageRegistry = (): TreeSitterLanguageRegistry =>\n new TreeSitterLanguageRegistry()\n\nexport const resolveTreeSitterLanguageContribution = async (\n contribution: TreeSitterLanguageContribution,\n): Promise<TreeSitterLanguageDescriptor> => {\n const assets = await loadTreeSitterLanguageAssets(contribution)\n return createTreeSitterLanguageDescriptor(contribution, assets)\n}\n\n/** A language's descriptor followed by every language its injection queries name, transitively. */\nexport const resolveTreeSitterLanguageClosure = async (\n resolver: TreeSitterLanguageResolver,\n languageId: TreeSitterLanguageId,\n isCancelled: () => boolean = () => false,\n): Promise<readonly TreeSitterLanguageDescriptor[]> => {\n const descriptor = await resolver.resolveTreeSitterLanguage(languageId)\n if (!descriptor || isCancelled()) return []\n return withInjectedLanguages(resolver, descriptor, isCancelled)\n}\n\nexport const withInjectedLanguages = async (\n resolver: TreeSitterLanguageResolver | undefined,\n descriptor: TreeSitterLanguageDescriptor,\n isCancelled: () => boolean,\n): Promise<readonly TreeSitterLanguageDescriptor[]> => {\n const descriptors = [descriptor]\n const seen = new Set([descriptor.id])\n for (let index = 0; index < descriptors.length; index += 1) {\n const dependencies = descriptors[index]?.injectionDependencies ?? []\n for (const id of dependencies) {\n if (seen.has(id) || isCancelled()) continue\n seen.add(id)\n const injected = await resolver?.resolveTreeSitterLanguage(id)\n if (injected) descriptors.push(injected)\n }\n }\n return descriptors\n}\n\nexport const resolveTreeSitterLanguageAlias = (\n alias: string | null | undefined,\n registry?: TreeSitterLanguageRegistry,\n): TreeSitterLanguageId | null => registry?.resolveLanguageAlias(alias) ?? null\n\nexport const isTreeSitterLanguageId = (\n languageId: string | null | undefined,\n): languageId is TreeSitterLanguageId => normalizeOptionalLanguageId(languageId) !== null\n\nconst createRegistration = (\n contribution: TreeSitterLanguageContribution,\n): TreeSitterLanguageRegistration => ({\n contribution,\n id: normalizeLanguageId(contribution.id),\n aliases: uniqueItems((contribution.aliases ?? []).map(normalizeAlias)),\n descriptorPromise: null,\n})\n\nconst createTreeSitterLanguageDescriptor = (\n contribution: TreeSitterLanguageContribution,\n assets: TreeSitterLanguageAssets,\n): TreeSitterLanguageDescriptor => ({\n id: normalizeLanguageId(contribution.id),\n extensions: uniqueItems((contribution.extensions ?? []).map(normalizeExtension)),\n aliases: uniqueItems((contribution.aliases ?? []).map(normalizeAlias)),\n filenames: contribution.filenames ?? [],\n injectionDependencies: contribution.injectionDependencies ?? [],\n wasmUrl: normalizeWasmUrl(assets.wasmUrl, contribution.id),\n highlightQuerySource: assets.highlightQuerySource,\n foldQuerySource: assets.foldQuerySource,\n injectionQuerySource: assets.injectionQuerySource,\n})\n\nconst loadTreeSitterLanguageAssets = async (\n contribution: TreeSitterLanguageContribution,\n): Promise<TreeSitterLanguageAssets> => {\n if ('load' in contribution && contribution.load) return contribution.load()\n return contribution\n}\n\nconst normalizeOptionalLanguageId = (\n languageId: string | null | undefined,\n): TreeSitterLanguageId | null => {\n if (!languageId) return null\n\n const id = languageId.trim()\n return id.length > 0 ? id : null\n}\n\nconst normalizeLanguageId = (languageId: string): TreeSitterLanguageId => {\n const id = normalizeOptionalLanguageId(languageId)\n if (id) return id\n\n throw new Error('Tree-sitter language id cannot be empty')\n}\n\nconst normalizeOptionalAlias = (alias: string | null | undefined): string | null => {\n if (!alias) return null\n\n const normalized = alias.trim().toLowerCase()\n return normalized.length > 0 ? normalized : null\n}\n\nconst normalizeAlias = (alias: string): string => {\n const normalized = normalizeOptionalAlias(alias)\n if (normalized) return normalized\n\n throw new Error('Tree-sitter language alias cannot be empty')\n}\n\nconst normalizeExtension = (extension: string): string => {\n const normalized = extension.trim().toLowerCase()\n if (!normalized) throw new Error('Tree-sitter language extension cannot be empty')\n if (normalized.startsWith('.')) return normalized\n return `.${normalized}`\n}\n\nconst normalizeWasmUrl = (wasmUrl: string, languageId: string): string => {\n const normalized = wasmUrl.trim()\n if (normalized) return normalized\n\n throw new Error(`Tree-sitter language \"${languageId}\" is missing a wasmUrl`)\n}\n\nconst uniqueItems = <T>(items: readonly T[]): readonly T[] => Array.from(new Set(items))\n"],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { PieceTableSnapshot } from '@singapore-editor/core/document';
|
|
2
|
+
type TreeSitterSourcePieceSpan = {
|
|
3
|
+
readonly chunkId: string;
|
|
4
|
+
readonly start: number;
|
|
5
|
+
readonly length: number;
|
|
6
|
+
};
|
|
7
|
+
type TreeSitterSourceChunkPayload = {
|
|
8
|
+
readonly chunkId: string;
|
|
9
|
+
readonly text: string;
|
|
10
|
+
};
|
|
11
|
+
export type TreeSitterSourceDescriptor = {
|
|
12
|
+
readonly length: number;
|
|
13
|
+
readonly pieces: readonly TreeSitterSourcePieceSpan[];
|
|
14
|
+
readonly chunks: readonly TreeSitterSourceChunkPayload[];
|
|
15
|
+
};
|
|
16
|
+
export type TreeSitterSourceDescriptorOptions = {
|
|
17
|
+
readonly sentChunkLengths?: ReadonlyMap<string, number>;
|
|
18
|
+
};
|
|
19
|
+
type ResolvedTreeSitterSourceChunk = {
|
|
20
|
+
readonly text: string;
|
|
21
|
+
readonly length: number;
|
|
22
|
+
};
|
|
23
|
+
export type TreeSitterSourceCache = Map<string, Map<string, ResolvedTreeSitterSourceChunk>>;
|
|
24
|
+
type TreeSitterInputChunk = {
|
|
25
|
+
readonly start: number;
|
|
26
|
+
readonly end: number;
|
|
27
|
+
readonly chunkStart: number;
|
|
28
|
+
readonly source: ResolvedTreeSitterSourceChunk;
|
|
29
|
+
};
|
|
30
|
+
export type TreeSitterPieceTableInput = {
|
|
31
|
+
readonly length: number;
|
|
32
|
+
readonly chunks: readonly TreeSitterInputChunk[];
|
|
33
|
+
lastChunkIndex?: number;
|
|
34
|
+
};
|
|
35
|
+
export declare const createTreeSitterSourceDescriptor: (snapshot: PieceTableSnapshot, options?: TreeSitterSourceDescriptorOptions) => TreeSitterSourceDescriptor;
|
|
36
|
+
export declare const resolveTreeSitterSourceDescriptor: (cache: TreeSitterSourceCache, documentId: string, descriptor: TreeSitterSourceDescriptor) => TreeSitterPieceTableInput;
|
|
37
|
+
export declare const disposeTreeSitterSourceDocument: (cache: TreeSitterSourceCache, documentId: string) => void;
|
|
38
|
+
export declare const clearTreeSitterSourceCache: (cache: TreeSitterSourceCache) => void;
|
|
39
|
+
export declare const readTreeSitterPieceTableInput: (input: TreeSitterPieceTableInput, index: number) => string | undefined;
|
|
40
|
+
export declare const readTreeSitterInputRange: (input: TreeSitterPieceTableInput, startIndex: number, endIndex: number) => string;
|
|
41
|
+
export {};
|
|
42
|
+
//# sourceMappingURL=source.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"source.d.ts","sourceRoot":"","sources":["../../src/treeSitter/source.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAA;AAIzE,KAAK,yBAAyB,GAAG;IAC/B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CACxB,CAAA;AAED,KAAK,4BAA4B,GAAG;IAClC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CACtB,CAAA;AAED,MAAM,MAAM,0BAA0B,GAAG;IACvC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,MAAM,EAAE,SAAS,yBAAyB,EAAE,CAAA;IACrD,QAAQ,CAAC,MAAM,EAAE,SAAS,4BAA4B,EAAE,CAAA;CACzD,CAAA;AAED,MAAM,MAAM,iCAAiC,GAAG;IAC9C,QAAQ,CAAC,gBAAgB,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACxD,CAAA;AAED,KAAK,6BAA6B,GAAG;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CACxB,CAAA;AAED,MAAM,MAAM,qBAAqB,GAAG,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,6BAA6B,CAAC,CAAC,CAAA;AAE3F,KAAK,oBAAoB,GAAG;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,MAAM,EAAE,6BAA6B,CAAA;CAC/C,CAAA;AAED,MAAM,MAAM,yBAAyB,GAAG;IACtC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,MAAM,EAAE,SAAS,oBAAoB,EAAE,CAAA;IAChD,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB,CAAA;AAQD,eAAO,MAAM,gCAAgC,GAC3C,UAAU,kBAAkB,EAC5B,UAAS,iCAAsC,KAC9C,0BAoBF,CAAA;AAED,eAAO,MAAM,iCAAiC,GAC5C,OAAO,qBAAqB,EAC5B,YAAY,MAAM,EAClB,YAAY,0BAA0B,KACrC,yBASF,CAAA;AAED,eAAO,MAAM,+BAA+B,GAC1C,OAAO,qBAAqB,EAC5B,YAAY,MAAM,KACjB,IAEF,CAAA;AAED,eAAO,MAAM,0BAA0B,GAAI,OAAO,qBAAqB,KAAG,IAEzE,CAAA;AAED,eAAO,MAAM,6BAA6B,GACxC,OAAO,yBAAyB,EAChC,OAAO,MAAM,KACZ,MAAM,GAAG,SAeX,CAAA;AAED,eAAO,MAAM,wBAAwB,GACnC,OAAO,yBAAyB,EAChC,YAAY,MAAM,EAClB,UAAU,MAAM,KACf,MAgBF,CAAA"}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { debugPieceTable, forEachBufferSpan } from "@singapore-editor/core/debug";
|
|
2
|
+
//#region src/treeSitter/source.ts
|
|
3
|
+
var SOURCE_CHUNK_SIZE = 16384;
|
|
4
|
+
var PARSER_READ_BATCH_CODE_UNITS = 4096;
|
|
5
|
+
var sourceOwners = /* @__PURE__ */ new WeakMap();
|
|
6
|
+
var nextSourceOwner = 1;
|
|
7
|
+
var createTreeSitterSourceDescriptor = (snapshot, options = {}) => {
|
|
8
|
+
const pieces = [];
|
|
9
|
+
const chunks = [];
|
|
10
|
+
const emittedChunkIds = /* @__PURE__ */ new Set();
|
|
11
|
+
for (const piece of debugPieceTable(snapshot)) {
|
|
12
|
+
if (!piece.visible) continue;
|
|
13
|
+
appendPieceSpans(snapshot, piece.buffer, piece.start, piece.length, {
|
|
14
|
+
pieces,
|
|
15
|
+
chunks,
|
|
16
|
+
emittedChunkIds,
|
|
17
|
+
sentChunkLengths: options.sentChunkLengths
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
length: snapshot.length,
|
|
22
|
+
pieces,
|
|
23
|
+
chunks
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
var resolveTreeSitterSourceDescriptor = (cache, documentId, descriptor) => {
|
|
27
|
+
const documentCache = ensureDocumentSourceCache(cache, documentId);
|
|
28
|
+
const chunks = resolveDescriptorChunks(documentCache, descriptor);
|
|
29
|
+
keepReferencedChunks(documentCache, descriptor);
|
|
30
|
+
return {
|
|
31
|
+
length: descriptor.length,
|
|
32
|
+
chunks
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
var readTreeSitterPieceTableInput = (input, index) => {
|
|
36
|
+
if (index < 0 || index >= input.length) return void 0;
|
|
37
|
+
const chunk = findChunkContainingWithCursor(input, index);
|
|
38
|
+
if (!chunk) return void 0;
|
|
39
|
+
const sourceStart = chunk.chunkStart + index - chunk.start;
|
|
40
|
+
const sourceEnd = chunk.chunkStart + chunk.end - chunk.start;
|
|
41
|
+
const readEnd = safeParserReadEnd(chunk.source, sourceStart, Math.min(sourceEnd, sourceStart + PARSER_READ_BATCH_CODE_UNITS), sourceEnd);
|
|
42
|
+
return readResolvedChunkText(chunk.source, sourceStart, readEnd);
|
|
43
|
+
};
|
|
44
|
+
var readTreeSitterInputRange = (input, startIndex, endIndex) => {
|
|
45
|
+
if (endIndex <= startIndex) return "";
|
|
46
|
+
const chunks = [];
|
|
47
|
+
for (const chunk of input.chunks) {
|
|
48
|
+
if (chunk.end <= startIndex) continue;
|
|
49
|
+
if (chunk.start >= endIndex) break;
|
|
50
|
+
const start = Math.max(startIndex, chunk.start) - chunk.start;
|
|
51
|
+
const end = Math.min(endIndex, chunk.end) - chunk.start;
|
|
52
|
+
chunks.push(readResolvedChunkText(chunk.source, chunk.chunkStart + start, chunk.chunkStart + end));
|
|
53
|
+
}
|
|
54
|
+
return chunks.join("");
|
|
55
|
+
};
|
|
56
|
+
var appendPieceSpans = (snapshot, bufferId, start, length, builder) => {
|
|
57
|
+
forEachBufferSpan(snapshot.buffers, bufferId, start, start + length, (text, from, to, owner) => {
|
|
58
|
+
appendSourceSpans(text, owner, from, to, builder);
|
|
59
|
+
});
|
|
60
|
+
};
|
|
61
|
+
var appendSourceSpans = (text, owner, start, end, builder) => {
|
|
62
|
+
let offset = start;
|
|
63
|
+
while (offset < end) {
|
|
64
|
+
const chunkStart = Math.floor(offset / SOURCE_CHUNK_SIZE) * SOURCE_CHUNK_SIZE;
|
|
65
|
+
const chunkLength = Math.min(text.length - chunkStart, SOURCE_CHUNK_SIZE);
|
|
66
|
+
const spanStart = offset - chunkStart;
|
|
67
|
+
const spanLength = Math.min(end - offset, chunkLength - spanStart);
|
|
68
|
+
const chunkId = sourceChunkId(owner, chunkStart);
|
|
69
|
+
builder.pieces.push({
|
|
70
|
+
chunkId,
|
|
71
|
+
start: spanStart,
|
|
72
|
+
length: spanLength
|
|
73
|
+
});
|
|
74
|
+
appendChunkPayload(text, chunkId, chunkStart, chunkLength, builder);
|
|
75
|
+
offset += spanLength;
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
var appendChunkPayload = (text, chunkId, chunkStart, chunkLength, builder) => {
|
|
79
|
+
if (builder.sentChunkLengths?.get(chunkId) === chunkLength) return;
|
|
80
|
+
if (builder.emittedChunkIds.has(chunkId)) return;
|
|
81
|
+
builder.emittedChunkIds.add(chunkId);
|
|
82
|
+
builder.chunks.push({
|
|
83
|
+
chunkId,
|
|
84
|
+
text: text.slice(chunkStart, chunkStart + chunkLength)
|
|
85
|
+
});
|
|
86
|
+
};
|
|
87
|
+
var sourceChunkId = (owner, chunkStart) => {
|
|
88
|
+
let id = sourceOwners.get(owner);
|
|
89
|
+
if (id === void 0) {
|
|
90
|
+
id = nextSourceOwner++;
|
|
91
|
+
sourceOwners.set(owner, id);
|
|
92
|
+
}
|
|
93
|
+
return `${id}:${chunkStart}`;
|
|
94
|
+
};
|
|
95
|
+
var ensureDocumentSourceCache = (cache, documentId) => {
|
|
96
|
+
const existing = cache.get(documentId);
|
|
97
|
+
if (existing) return existing;
|
|
98
|
+
const documentCache = /* @__PURE__ */ new Map();
|
|
99
|
+
cache.set(documentId, documentCache);
|
|
100
|
+
return documentCache;
|
|
101
|
+
};
|
|
102
|
+
var resolveDescriptorChunks = (cache, descriptor) => {
|
|
103
|
+
cacheChunkPayloads(cache, descriptor.chunks);
|
|
104
|
+
const chunks = [];
|
|
105
|
+
let documentOffset = 0;
|
|
106
|
+
for (const piece of descriptor.pieces) {
|
|
107
|
+
const source = cache.get(piece.chunkId);
|
|
108
|
+
if (!source) throw new Error(`Tree-sitter source chunk "${piece.chunkId}" is missing`);
|
|
109
|
+
chunks.push({
|
|
110
|
+
start: documentOffset,
|
|
111
|
+
end: documentOffset + piece.length,
|
|
112
|
+
chunkStart: piece.start,
|
|
113
|
+
source
|
|
114
|
+
});
|
|
115
|
+
documentOffset += piece.length;
|
|
116
|
+
}
|
|
117
|
+
if (documentOffset !== descriptor.length) throw new Error("Tree-sitter source length mismatch");
|
|
118
|
+
return chunks;
|
|
119
|
+
};
|
|
120
|
+
var keepReferencedChunks = (cache, descriptor) => {
|
|
121
|
+
const referenced = new Set(descriptor.pieces.map((piece) => piece.chunkId));
|
|
122
|
+
for (const chunkId of cache.keys()) if (!referenced.has(chunkId)) cache.delete(chunkId);
|
|
123
|
+
};
|
|
124
|
+
var cacheChunkPayloads = (cache, chunks) => {
|
|
125
|
+
for (const chunk of chunks) cache.set(chunk.chunkId, {
|
|
126
|
+
text: chunk.text,
|
|
127
|
+
length: chunk.text.length
|
|
128
|
+
});
|
|
129
|
+
};
|
|
130
|
+
var readResolvedChunkText = (chunk, start, end) => chunk.text.slice(start, end);
|
|
131
|
+
var safeParserReadEnd = (chunk, start, end, maxEnd) => {
|
|
132
|
+
if (end >= maxEnd || end <= start) return end;
|
|
133
|
+
if (!isHighSurrogate(readResolvedChunkCodeUnit(chunk, end - 1))) return end;
|
|
134
|
+
return Math.max(start + 1, end - 1);
|
|
135
|
+
};
|
|
136
|
+
var readResolvedChunkCodeUnit = (chunk, index) => chunk.text.charCodeAt(index);
|
|
137
|
+
var isHighSurrogate = (codeUnit) => codeUnit >= 55296 && codeUnit <= 56319;
|
|
138
|
+
var findChunkContaining = (chunks, index) => {
|
|
139
|
+
let low = 0;
|
|
140
|
+
let high = chunks.length - 1;
|
|
141
|
+
while (low <= high) {
|
|
142
|
+
const middle = Math.floor((low + high) / 2);
|
|
143
|
+
const chunk = chunks[middle];
|
|
144
|
+
if (!chunk) return null;
|
|
145
|
+
if (index < chunk.start) {
|
|
146
|
+
high = middle - 1;
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
if (index >= chunk.end) {
|
|
150
|
+
low = middle + 1;
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
return chunk;
|
|
154
|
+
}
|
|
155
|
+
return null;
|
|
156
|
+
};
|
|
157
|
+
var findChunkContainingWithCursor = (input, index) => {
|
|
158
|
+
const cachedIndex = input.lastChunkIndex;
|
|
159
|
+
const cached = cachedIndex === void 0 ? null : input.chunks[cachedIndex];
|
|
160
|
+
if (cached && index >= cached.start && index < cached.end) return cached;
|
|
161
|
+
if (cachedIndex !== void 0) {
|
|
162
|
+
const next = input.chunks[cachedIndex + 1];
|
|
163
|
+
if (next && index >= next.start && index < next.end) {
|
|
164
|
+
input.lastChunkIndex = cachedIndex + 1;
|
|
165
|
+
return next;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
const chunk = findChunkContaining(input.chunks, index);
|
|
169
|
+
if (chunk) input.lastChunkIndex = input.chunks.indexOf(chunk);
|
|
170
|
+
return chunk;
|
|
171
|
+
};
|
|
172
|
+
//#endregion
|
|
173
|
+
export { createTreeSitterSourceDescriptor, readTreeSitterInputRange, readTreeSitterPieceTableInput, resolveTreeSitterSourceDescriptor };
|
|
174
|
+
|
|
175
|
+
//# sourceMappingURL=source.js.map
|