@pierre/diffs 1.0.0-beta.1 → 1.0.0-beta.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/README.md +2 -1
- package/dist/managers/LineSelectionManager.d.ts +1 -0
- package/dist/managers/LineSelectionManager.d.ts.map +1 -1
- package/dist/managers/LineSelectionManager.js +21 -15
- package/dist/managers/LineSelectionManager.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/parseLineType.d.ts.map +1 -1
- package/dist/utils/processLine.js +1 -1
- package/dist/utils/processLine.js.map +1 -1
- package/dist/utils/renderDiffWithHighlighter.js +34 -18
- package/dist/utils/renderDiffWithHighlighter.js.map +1 -1
- package/dist/worker/worker-portable.js +35 -20
- package/dist/worker/worker-portable.js.map +1 -1
- package/dist/worker/worker.js +35 -19
- package/dist/worker/worker.js.map +1 -1
- package/package.json +19 -19
package/README.md
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LineSelectionManager.d.ts","names":["options: LineSelectionOptions"],"sources":["../../src/managers/LineSelectionManager.ts"],"sourcesContent":[],"mappings":";;;KAGY,aAAA,GAAgB;UAEX,iBAAA;EAFjB,KAAY,EAAA,MAAA;EAEZ,IAAiB,CAAA,EAER,aAFQ;EAOjB,GAAiB,EAAA,MAAA;EAEU,OAAA,CAAA,EALf,aAKe;;AAEI,UAJd,oBAAA,CAIc;EAAA,mBAAA,CAAA,EAAA,OAAA;EAgB/B,cAAa,CAAA,EAAA,CAAA,KAAA,EAlBc,iBAkBd,GAAA,IAAA,EAAA,GAAA,IAAA;EAOkB,oBAAA,CAAA,EAAA,CAAA,KAAA,EAxBE,iBAwBF,GAAA,IAAA,EAAA,GAAA,IAAA;EAET,kBAAA,CAAA,EAAA,CAAA,KAAA,EAzBS,iBAyBT,GAAA,IAAA,EAAA,GAAA,IAAA;;;;;
|
|
1
|
+
{"version":3,"file":"LineSelectionManager.d.ts","names":["options: LineSelectionOptions"],"sources":["../../src/managers/LineSelectionManager.ts"],"sourcesContent":[],"mappings":";;;KAGY,aAAA,GAAgB;UAEX,iBAAA;EAFjB,KAAY,EAAA,MAAA;EAEZ,IAAiB,CAAA,EAER,aAFQ;EAOjB,GAAiB,EAAA,MAAA;EAEU,OAAA,CAAA,EALf,aAKe;;AAEI,UAJd,oBAAA,CAIc;EAAA,mBAAA,CAAA,EAAA,OAAA;EAgB/B,cAAa,CAAA,EAAA,CAAA,KAAA,EAlBc,iBAkBd,GAAA,IAAA,EAAA,GAAA,IAAA;EAOkB,oBAAA,CAAA,EAAA,CAAA,KAAA,EAxBE,iBAwBF,GAAA,IAAA,EAAA,GAAA,IAAA;EAET,kBAAA,CAAA,EAAA,CAAA,KAAA,EAzBS,iBAyBT,GAAA,IAAA,EAAA,GAAA,IAAA;;;;;AAsbtB;;;;AAIE,cAncW,oBAAA,CAmcX;EACC,QAAA,OAAA;EAAuB,QAAA,GAAA;EAAA,QAAA,aAAA;;;;wBA7bK;sBAET;;aAoBT;;;sBA2BS;kBAaJ;;;;;;;;;;;;;;;;;;;iBA0XF,yBAAA;;;;;GAKb,uBAAuB"}
|
|
@@ -81,7 +81,7 @@ var LineSelectionManager = class {
|
|
|
81
81
|
event.preventDefault();
|
|
82
82
|
const { lineNumber, eventSide, lineIndex } = mouseEventData;
|
|
83
83
|
if (event.shiftKey && this.selectedRange != null) {
|
|
84
|
-
const range = this.deriveRowRangeFromDOM(this.selectedRange);
|
|
84
|
+
const range = this.deriveRowRangeFromDOM(this.selectedRange, this.pre?.dataset.type === "split");
|
|
85
85
|
if (range == null) return;
|
|
86
86
|
const useStart = range.start <= range.end ? lineIndex >= range.start : lineIndex <= range.end;
|
|
87
87
|
this.anchor = {
|
|
@@ -150,7 +150,8 @@ var LineSelectionManager = class {
|
|
|
150
150
|
console.error(codeElements);
|
|
151
151
|
throw new Error("LineSelectionManager.applySelectionToDOM: Somehow there are more than 2 code elements...");
|
|
152
152
|
}
|
|
153
|
-
const
|
|
153
|
+
const split = this.pre.dataset.type === "split";
|
|
154
|
+
const rowRange = this.deriveRowRangeFromDOM(this.selectedRange, split);
|
|
154
155
|
if (rowRange == null) {
|
|
155
156
|
console.error({
|
|
156
157
|
rowRange,
|
|
@@ -163,7 +164,7 @@ var LineSelectionManager = class {
|
|
|
163
164
|
const last = Math.max(rowRange.start, rowRange.end);
|
|
164
165
|
for (const code of codeElements) for (const element of code.children) {
|
|
165
166
|
if (!(element instanceof HTMLElement)) continue;
|
|
166
|
-
const lineIndex = this.getLineIndex(element);
|
|
167
|
+
const lineIndex = this.getLineIndex(element, split);
|
|
167
168
|
if ((lineIndex ?? 0) > last) break;
|
|
168
169
|
if (lineIndex == null || lineIndex < first) continue;
|
|
169
170
|
let attributeValue = isSingle ? "single" : lineIndex === first ? "first" : lineIndex === last ? "last" : "";
|
|
@@ -178,24 +179,24 @@ var LineSelectionManager = class {
|
|
|
178
179
|
}
|
|
179
180
|
}
|
|
180
181
|
};
|
|
181
|
-
deriveRowRangeFromDOM(range) {
|
|
182
|
+
deriveRowRangeFromDOM(range, split) {
|
|
182
183
|
if (range == null) return void 0;
|
|
183
|
-
const start = this.findRowIndexForLineNumber(range.start, range.side);
|
|
184
|
-
const end = range.end === range.start && (range.endSide == null || range.endSide === range.side) ? start : this.findRowIndexForLineNumber(range.end, range.endSide ?? range.side);
|
|
184
|
+
const start = this.findRowIndexForLineNumber(range.start, range.side, split);
|
|
185
|
+
const end = range.end === range.start && (range.endSide == null || range.endSide === range.side) ? start : this.findRowIndexForLineNumber(range.end, range.endSide ?? range.side, split);
|
|
185
186
|
return start != null && end != null ? {
|
|
186
187
|
start,
|
|
187
188
|
end
|
|
188
189
|
} : void 0;
|
|
189
190
|
}
|
|
190
|
-
findRowIndexForLineNumber(lineNumber, targetSide = "additions") {
|
|
191
|
+
findRowIndexForLineNumber(lineNumber, targetSide = "additions", split) {
|
|
191
192
|
if (this.pre == null) return void 0;
|
|
192
193
|
const elements = Array.from(this.pre.querySelectorAll(`[data-line="${lineNumber}"]`));
|
|
193
194
|
elements.push(...Array.from(this.pre.querySelectorAll(`[data-alt-line="${lineNumber}"]`)));
|
|
194
195
|
if (elements.length === 0) return void 0;
|
|
195
196
|
for (const element of elements) {
|
|
196
197
|
if (!(element instanceof HTMLElement)) continue;
|
|
197
|
-
if (this.getLineSideFromElement(element) === targetSide) return this.getLineIndex(element);
|
|
198
|
-
else if (parseInt(element.dataset.altLine ?? "") === lineNumber) return this.getLineIndex(element);
|
|
198
|
+
if (this.getLineSideFromElement(element) === targetSide) return this.getLineIndex(element, split);
|
|
199
|
+
else if (parseInt(element.dataset.altLine ?? "") === lineNumber) return this.getLineIndex(element, split);
|
|
199
200
|
}
|
|
200
201
|
console.error("LineSelectionManager.findRowIndexForLineNumber: Invalid selection", lineNumber, targetSide);
|
|
201
202
|
}
|
|
@@ -226,11 +227,11 @@ var LineSelectionManager = class {
|
|
|
226
227
|
continue;
|
|
227
228
|
}
|
|
228
229
|
if (element.hasAttribute("data-line")) {
|
|
229
|
-
lineNumber =
|
|
230
|
-
lineIndex =
|
|
230
|
+
lineNumber = this.getLineNumber(element);
|
|
231
|
+
lineIndex = this.getLineIndex(element, this.pre?.dataset.type === "split");
|
|
231
232
|
if (element.dataset.lineType === "change-deletion") eventSide = "deletions";
|
|
232
233
|
else if (element.dataset.lineType === "change-additions") eventSide = "additions";
|
|
233
|
-
if (
|
|
234
|
+
if (lineIndex == null || lineNumber == null) {
|
|
234
235
|
lineIndex = void 0;
|
|
235
236
|
lineNumber = void 0;
|
|
236
237
|
break;
|
|
@@ -250,9 +251,14 @@ var LineSelectionManager = class {
|
|
|
250
251
|
eventSide: eventSide ?? "additions"
|
|
251
252
|
};
|
|
252
253
|
}
|
|
253
|
-
|
|
254
|
-
const
|
|
255
|
-
return !Number.isNaN(
|
|
254
|
+
getLineNumber(element) {
|
|
255
|
+
const lineNumber = parseInt(element.dataset.line ?? "", 10);
|
|
256
|
+
return !Number.isNaN(lineNumber) ? lineNumber : void 0;
|
|
257
|
+
}
|
|
258
|
+
getLineIndex(element, split) {
|
|
259
|
+
const lineIndexes = (element.dataset.lineIndex ?? "").split(",").map((value) => parseInt(value)).filter((value) => !Number.isNaN(value));
|
|
260
|
+
if (split && lineIndexes.length === 2) return lineIndexes[1];
|
|
261
|
+
else if (!split) return lineIndexes[0];
|
|
256
262
|
}
|
|
257
263
|
getLineSideFromElement(element) {
|
|
258
264
|
if (element.dataset.lineType === "change-deletion") return "deletions";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LineSelectionManager.js","names":["options: LineSelectionOptions","lineNumber: number | undefined","lineIndex: number | undefined","eventSide: AnnotationSide | undefined"],"sources":["../../src/managers/LineSelectionManager.ts"],"sourcesContent":["import type { AnnotationSide } from '../types';\nimport { areSelectionsEqual } from '../utils/areSelectionsEqual';\n\nexport type SelectionSide = AnnotationSide;\n\nexport interface SelectedLineRange {\n start: number;\n side?: SelectionSide;\n end: number;\n endSide?: SelectionSide;\n}\n\nexport interface LineSelectionOptions {\n enableLineSelection?: boolean;\n onLineSelected?: (range: SelectedLineRange | null) => void;\n onLineSelectionStart?: (range: SelectedLineRange | null) => void;\n onLineSelectionEnd?: (range: SelectedLineRange | null) => void;\n}\n\ninterface MouseInfo {\n lineNumber: number;\n eventSide: AnnotationSide;\n lineIndex: number;\n}\n\n/**\n * Manages line selection state and interactions for code/diff viewers.\n * Handles:\n * - Click and drag selection\n * - Shift-click to extend selection\n * - DOM attribute updates (data-selected-line)\n */\nexport class LineSelectionManager {\n private pre: HTMLPreElement | undefined;\n private selectedRange: SelectedLineRange | null = null;\n private renderedSelectionRange: SelectedLineRange | null | undefined;\n private anchor: { line: number; side: SelectionSide } | undefined;\n private _queuedRender: number | undefined;\n\n constructor(private options: LineSelectionOptions = {}) {}\n\n setOptions(options: LineSelectionOptions): void {\n this.options = { ...this.options, ...options };\n this.removeEventListeners();\n if (this.options.enableLineSelection === true) {\n this.attachEventListeners();\n }\n }\n\n cleanUp(): void {\n this.removeEventListeners();\n if (this._queuedRender != null) {\n cancelAnimationFrame(this._queuedRender);\n this._queuedRender = undefined;\n }\n if (this.pre != null) {\n delete this.pre.dataset.interactiveLineNumbers;\n }\n this.pre = undefined;\n }\n\n setup(pre: HTMLPreElement): void {\n // Assume we are always dirty after a setup...\n this.setDirty();\n if (this.pre !== pre) {\n this.cleanUp();\n }\n this.pre = pre;\n const { enableLineSelection = false } = this.options;\n if (enableLineSelection) {\n this.pre.dataset.interactiveLineNumbers = '';\n this.attachEventListeners();\n } else {\n this.removeEventListeners();\n delete this.pre.dataset.interactiveLineNumbers;\n }\n\n this.setSelection(this.selectedRange);\n }\n\n setDirty(): void {\n this.renderedSelectionRange = undefined;\n }\n\n isDirty(): boolean {\n return this.renderedSelectionRange === undefined;\n }\n\n setSelection(range: SelectedLineRange | null): void {\n const isRangeChange = !(\n range === this.selectedRange ||\n areSelectionsEqual(range ?? undefined, this.selectedRange ?? undefined)\n );\n if (!this.isDirty() && !isRangeChange) return;\n this.selectedRange = range;\n this.renderSelection();\n if (isRangeChange) {\n this.notifySelectionChange();\n }\n }\n\n getSelection(): SelectedLineRange | null {\n return this.selectedRange;\n }\n\n private attachEventListeners(): void {\n if (this.pre == null) return;\n // Lets run a cleanup, just in case\n this.removeEventListeners();\n this.pre.addEventListener('mousedown', this.handleMouseDown);\n }\n\n private removeEventListeners(): void {\n if (this.pre == null) return;\n this.pre.removeEventListener('mousedown', this.handleMouseDown);\n document.removeEventListener('mousemove', this.handleMouseMove);\n document.removeEventListener('mouseup', this.handleMouseUp);\n }\n\n private handleMouseDown = (event: MouseEvent): void => {\n // Only handle left mouse button\n const mouseEventData =\n event.button === 0\n ? this.getMouseEventDataForPath(event.composedPath(), 'click')\n : undefined;\n if (mouseEventData == null) {\n return;\n }\n event.preventDefault();\n const { lineNumber, eventSide, lineIndex } = mouseEventData;\n if (event.shiftKey && this.selectedRange != null) {\n const range = this.deriveRowRangeFromDOM(this.selectedRange);\n if (range == null) return;\n const useStart =\n range.start <= range.end\n ? lineIndex >= range.start\n : lineIndex <= range.end;\n this.anchor = {\n line: useStart ? this.selectedRange.start : this.selectedRange.end,\n side:\n (useStart\n ? this.selectedRange.side\n : (this.selectedRange.endSide ?? this.selectedRange.side)) ??\n 'additions',\n };\n this.updateSelection(lineNumber, eventSide);\n this.notifySelectionStart(this.selectedRange);\n } else {\n // Check if clicking on already selected single line to unselect\n if (\n this.selectedRange?.start === lineNumber &&\n this.selectedRange?.end === lineNumber\n ) {\n this.updateSelection(null);\n this.notifySelectionEnd(null);\n this.notifySelectionChange();\n return;\n }\n this.selectedRange = null;\n this.anchor = { line: lineNumber, side: eventSide };\n this.updateSelection(lineNumber, eventSide);\n this.notifySelectionStart(this.selectedRange);\n }\n\n document.addEventListener('mousemove', this.handleMouseMove);\n document.addEventListener('mouseup', this.handleMouseUp);\n };\n\n private handleMouseMove = (event: MouseEvent): void => {\n const mouseEventData = this.getMouseEventDataForPath(\n event.composedPath(),\n 'move'\n );\n if (mouseEventData == null || this.anchor == null) return;\n const { lineNumber, eventSide } = mouseEventData;\n this.updateSelection(lineNumber, eventSide);\n };\n\n private handleMouseUp = (): void => {\n this.anchor = undefined;\n document.removeEventListener('mousemove', this.handleMouseMove);\n document.removeEventListener('mouseup', this.handleMouseUp);\n this.notifySelectionEnd(this.selectedRange);\n this.notifySelectionChange();\n };\n\n private updateSelection(currentLine: null): void;\n private updateSelection(currentLine: number, side: AnnotationSide): void;\n private updateSelection(\n currentLine: number | null,\n side?: AnnotationSide\n ): void {\n if (currentLine == null) {\n this.selectedRange = null;\n } else {\n const anchorSide = this.anchor?.side ?? side;\n const anchorLine = this.anchor?.line ?? currentLine;\n this.selectedRange = {\n start: anchorLine,\n end: currentLine,\n side: anchorSide,\n endSide: anchorSide !== side ? side : undefined,\n };\n }\n this._queuedRender ??= requestAnimationFrame(this.renderSelection);\n }\n\n private renderSelection = (): void => {\n if (this._queuedRender != null) {\n cancelAnimationFrame(this._queuedRender);\n this._queuedRender = undefined;\n }\n if (\n this.pre == null ||\n this.renderedSelectionRange === this.selectedRange\n ) {\n return;\n }\n\n // First clear existing selections, maybe we\n // can cache this to better avoid this query?\n const allSelected = this.pre.querySelectorAll('[data-selected-line]');\n for (const element of allSelected) {\n element.removeAttribute('data-selected-line');\n }\n\n this.renderedSelectionRange = this.selectedRange;\n if (this.selectedRange == null) {\n return;\n }\n\n const codeElements = this.pre.querySelectorAll('[data-code]');\n if (codeElements.length === 0) return;\n if (codeElements.length > 2) {\n console.error(codeElements);\n throw new Error(\n 'LineSelectionManager.applySelectionToDOM: Somehow there are more than 2 code elements...'\n );\n }\n const rowRange = this.deriveRowRangeFromDOM(this.selectedRange);\n if (rowRange == null) {\n console.error({ rowRange, selectedRange: this.selectedRange });\n throw new Error(\n 'LineSelectionManager.renderSelection: No valid rowRange'\n );\n }\n const isSingle = rowRange.start === rowRange.end;\n const first = Math.min(rowRange.start, rowRange.end);\n const last = Math.max(rowRange.start, rowRange.end);\n for (const code of codeElements) {\n for (const element of code.children) {\n if (!(element instanceof HTMLElement)) continue;\n const lineIndex = this.getLineIndex(element);\n if ((lineIndex ?? 0) > last) break;\n if (lineIndex == null || lineIndex < first) continue;\n let attributeValue = isSingle\n ? 'single'\n : lineIndex === first\n ? 'first'\n : lineIndex === last\n ? 'last'\n : '';\n element.setAttribute('data-selected-line', attributeValue);\n // If we have a line annotation following our selected line, we should\n // mark it as selected as well\n if (\n element.nextSibling instanceof HTMLElement &&\n element.nextSibling.hasAttribute('data-line-annotation')\n ) {\n // Depending on the line's attribute value, lets go ahead and correct\n // it when adding in the annotation row\n if (isSingle) {\n // Single technically becomes 2 selected lines\n attributeValue = 'last';\n element.setAttribute('data-selected-line', 'first');\n } else if (lineIndex === first) {\n // We don't want apply 'first' to the line annotation\n attributeValue = '';\n } else if (lineIndex === last) {\n // the annotation will become the last selected line and therefore\n // our existing line should no longer be last\n element.setAttribute('data-selected-line', '');\n }\n element.nextSibling.setAttribute(\n 'data-selected-line',\n attributeValue\n );\n }\n }\n }\n };\n\n private deriveRowRangeFromDOM(\n range: SelectedLineRange\n ): { start: number; end: number } | undefined {\n if (range == null) return undefined;\n const start = this.findRowIndexForLineNumber(range.start, range.side);\n const end =\n range.end === range.start &&\n (range.endSide == null || range.endSide === range.side)\n ? start\n : this.findRowIndexForLineNumber(\n range.end,\n range.endSide ?? range.side\n );\n return start != null && end != null ? { start, end } : undefined;\n }\n\n private findRowIndexForLineNumber(\n lineNumber: number,\n targetSide: SelectionSide = 'additions'\n ): number | undefined {\n if (this.pre == null) return undefined;\n const elements = Array.from(\n this.pre.querySelectorAll(`[data-line=\"${lineNumber}\"]`)\n );\n // Given how unified diffs can order things, we need to always process\n // `[data-line]` elements before `[data-alt-line]`\n elements.push(\n ...Array.from(\n this.pre.querySelectorAll(`[data-alt-line=\"${lineNumber}\"]`)\n )\n );\n if (elements.length === 0) return undefined;\n\n for (const element of elements) {\n if (!(element instanceof HTMLElement)) {\n continue;\n }\n const side = this.getLineSideFromElement(element);\n if (side === targetSide) {\n return this.getLineIndex(element);\n } else if (parseInt(element.dataset.altLine ?? '') === lineNumber) {\n return this.getLineIndex(element);\n }\n }\n console.error(\n 'LineSelectionManager.findRowIndexForLineNumber: Invalid selection',\n lineNumber,\n targetSide\n );\n return undefined;\n }\n\n private notifySelectionChange(): void {\n const { onLineSelected } = this.options;\n if (onLineSelected == null) return;\n\n onLineSelected(this.selectedRange ?? null);\n }\n\n private notifySelectionStart(range: SelectedLineRange | null): void {\n const { onLineSelectionStart } = this.options;\n if (onLineSelectionStart == null) return;\n onLineSelectionStart(range);\n }\n\n private notifySelectionEnd(range: SelectedLineRange | null): void {\n const { onLineSelectionEnd } = this.options;\n if (onLineSelectionEnd == null) return;\n onLineSelectionEnd(range);\n }\n\n private getMouseEventDataForPath(\n path: (EventTarget | undefined)[],\n eventType: 'click' | 'move'\n ): MouseInfo | undefined {\n let lineNumber: number | undefined;\n let lineIndex: number | undefined;\n let isNumberColumn = false;\n let eventSide: AnnotationSide | undefined;\n for (const element of path) {\n if (!(element instanceof HTMLElement)) {\n continue;\n }\n if (element.hasAttribute('data-column-number')) {\n isNumberColumn = true;\n continue;\n }\n if (element.hasAttribute('data-line')) {\n lineNumber = parseInt(element.dataset.line ?? '', 10);\n lineIndex = parseInt(element.dataset.lineIndex ?? '', 10);\n if (element.dataset.lineType === 'change-deletion') {\n eventSide = 'deletions';\n } else if (element.dataset.lineType === 'change-additions') {\n eventSide = 'additions';\n }\n // if we can't pull out an index or line number, we can't do anything.\n if (Number.isNaN(lineIndex) || Number.isNaN(lineNumber)) {\n lineIndex = undefined;\n lineNumber = undefined;\n break;\n }\n // If we already have an eventSide, we done computin\n if (eventSide != null) {\n break;\n } else {\n // context type lines will need to be discovered higher up\n // at the data-code level\n }\n continue;\n }\n if (element.hasAttribute('data-code')) {\n eventSide ??= element.hasAttribute('data-deletions')\n ? 'deletions'\n : // context in unified style are assumed to be additions based on\n // their line numbers\n 'additions';\n // If we got to the code element, we def done, son\n break;\n }\n }\n if (\n (eventType === 'click' && !isNumberColumn) ||\n lineIndex == null ||\n lineNumber == null\n ) {\n return undefined;\n }\n return {\n lineIndex,\n lineNumber,\n // Normally this shouldn't hit unless we broke early for whatever reason,\n // but for types lets ensure it's additions if undefined\n eventSide: eventSide ?? 'additions',\n };\n }\n\n private getLineIndex(element: HTMLElement): number | undefined {\n const lineIndex = parseInt(element.dataset.lineIndex ?? '', 10);\n return !Number.isNaN(lineIndex) ? lineIndex : undefined;\n }\n\n private getLineSideFromElement(element: HTMLElement): SelectionSide {\n if (element.dataset.lineType === 'change-deletion') {\n return 'deletions';\n }\n if (element.dataset.lineType === 'change-addition') {\n return 'additions';\n }\n const parent = element.closest('[data-code]');\n if (!(parent instanceof HTMLElement)) {\n return 'additions';\n }\n return parent.hasAttribute('data-deletions') ? 'deletions' : 'additions';\n }\n}\n\nexport function pluckLineSelectionOptions({\n enableLineSelection,\n onLineSelected,\n onLineSelectionStart,\n onLineSelectionEnd,\n}: LineSelectionOptions): LineSelectionOptions {\n return {\n enableLineSelection,\n onLineSelected,\n onLineSelectionStart,\n onLineSelectionEnd,\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"LineSelectionManager.js","names":["options: LineSelectionOptions","lineNumber: number | undefined","lineIndex: number | undefined","eventSide: AnnotationSide | undefined"],"sources":["../../src/managers/LineSelectionManager.ts"],"sourcesContent":["import type { AnnotationSide } from '../types';\nimport { areSelectionsEqual } from '../utils/areSelectionsEqual';\n\nexport type SelectionSide = AnnotationSide;\n\nexport interface SelectedLineRange {\n start: number;\n side?: SelectionSide;\n end: number;\n endSide?: SelectionSide;\n}\n\nexport interface LineSelectionOptions {\n enableLineSelection?: boolean;\n onLineSelected?: (range: SelectedLineRange | null) => void;\n onLineSelectionStart?: (range: SelectedLineRange | null) => void;\n onLineSelectionEnd?: (range: SelectedLineRange | null) => void;\n}\n\ninterface MouseInfo {\n lineNumber: number;\n eventSide: AnnotationSide;\n lineIndex: number;\n}\n\n/**\n * Manages line selection state and interactions for code/diff viewers.\n * Handles:\n * - Click and drag selection\n * - Shift-click to extend selection\n * - DOM attribute updates (data-selected-line)\n */\nexport class LineSelectionManager {\n private pre: HTMLPreElement | undefined;\n private selectedRange: SelectedLineRange | null = null;\n private renderedSelectionRange: SelectedLineRange | null | undefined;\n private anchor: { line: number; side: SelectionSide } | undefined;\n private _queuedRender: number | undefined;\n\n constructor(private options: LineSelectionOptions = {}) {}\n\n setOptions(options: LineSelectionOptions): void {\n this.options = { ...this.options, ...options };\n this.removeEventListeners();\n if (this.options.enableLineSelection === true) {\n this.attachEventListeners();\n }\n }\n\n cleanUp(): void {\n this.removeEventListeners();\n if (this._queuedRender != null) {\n cancelAnimationFrame(this._queuedRender);\n this._queuedRender = undefined;\n }\n if (this.pre != null) {\n delete this.pre.dataset.interactiveLineNumbers;\n }\n this.pre = undefined;\n }\n\n setup(pre: HTMLPreElement): void {\n // Assume we are always dirty after a setup...\n this.setDirty();\n if (this.pre !== pre) {\n this.cleanUp();\n }\n this.pre = pre;\n const { enableLineSelection = false } = this.options;\n if (enableLineSelection) {\n this.pre.dataset.interactiveLineNumbers = '';\n this.attachEventListeners();\n } else {\n this.removeEventListeners();\n delete this.pre.dataset.interactiveLineNumbers;\n }\n\n this.setSelection(this.selectedRange);\n }\n\n setDirty(): void {\n this.renderedSelectionRange = undefined;\n }\n\n isDirty(): boolean {\n return this.renderedSelectionRange === undefined;\n }\n\n setSelection(range: SelectedLineRange | null): void {\n const isRangeChange = !(\n range === this.selectedRange ||\n areSelectionsEqual(range ?? undefined, this.selectedRange ?? undefined)\n );\n if (!this.isDirty() && !isRangeChange) return;\n this.selectedRange = range;\n this.renderSelection();\n if (isRangeChange) {\n this.notifySelectionChange();\n }\n }\n\n getSelection(): SelectedLineRange | null {\n return this.selectedRange;\n }\n\n private attachEventListeners(): void {\n if (this.pre == null) return;\n // Lets run a cleanup, just in case\n this.removeEventListeners();\n this.pre.addEventListener('mousedown', this.handleMouseDown);\n }\n\n private removeEventListeners(): void {\n if (this.pre == null) return;\n this.pre.removeEventListener('mousedown', this.handleMouseDown);\n document.removeEventListener('mousemove', this.handleMouseMove);\n document.removeEventListener('mouseup', this.handleMouseUp);\n }\n\n private handleMouseDown = (event: MouseEvent): void => {\n // Only handle left mouse button\n const mouseEventData =\n event.button === 0\n ? this.getMouseEventDataForPath(event.composedPath(), 'click')\n : undefined;\n if (mouseEventData == null) {\n return;\n }\n event.preventDefault();\n const { lineNumber, eventSide, lineIndex } = mouseEventData;\n if (event.shiftKey && this.selectedRange != null) {\n const range = this.deriveRowRangeFromDOM(\n this.selectedRange,\n this.pre?.dataset.type === 'split'\n );\n if (range == null) return;\n const useStart =\n range.start <= range.end\n ? lineIndex >= range.start\n : lineIndex <= range.end;\n this.anchor = {\n line: useStart ? this.selectedRange.start : this.selectedRange.end,\n side:\n (useStart\n ? this.selectedRange.side\n : (this.selectedRange.endSide ?? this.selectedRange.side)) ??\n 'additions',\n };\n this.updateSelection(lineNumber, eventSide);\n this.notifySelectionStart(this.selectedRange);\n } else {\n // Check if clicking on already selected single line to unselect\n if (\n this.selectedRange?.start === lineNumber &&\n this.selectedRange?.end === lineNumber\n ) {\n this.updateSelection(null);\n this.notifySelectionEnd(null);\n this.notifySelectionChange();\n return;\n }\n this.selectedRange = null;\n this.anchor = { line: lineNumber, side: eventSide };\n this.updateSelection(lineNumber, eventSide);\n this.notifySelectionStart(this.selectedRange);\n }\n\n document.addEventListener('mousemove', this.handleMouseMove);\n document.addEventListener('mouseup', this.handleMouseUp);\n };\n\n private handleMouseMove = (event: MouseEvent): void => {\n const mouseEventData = this.getMouseEventDataForPath(\n event.composedPath(),\n 'move'\n );\n if (mouseEventData == null || this.anchor == null) return;\n const { lineNumber, eventSide } = mouseEventData;\n this.updateSelection(lineNumber, eventSide);\n };\n\n private handleMouseUp = (): void => {\n this.anchor = undefined;\n document.removeEventListener('mousemove', this.handleMouseMove);\n document.removeEventListener('mouseup', this.handleMouseUp);\n this.notifySelectionEnd(this.selectedRange);\n this.notifySelectionChange();\n };\n\n private updateSelection(currentLine: null): void;\n private updateSelection(currentLine: number, side: AnnotationSide): void;\n private updateSelection(\n currentLine: number | null,\n side?: AnnotationSide\n ): void {\n if (currentLine == null) {\n this.selectedRange = null;\n } else {\n const anchorSide = this.anchor?.side ?? side;\n const anchorLine = this.anchor?.line ?? currentLine;\n this.selectedRange = {\n start: anchorLine,\n end: currentLine,\n side: anchorSide,\n endSide: anchorSide !== side ? side : undefined,\n };\n }\n this._queuedRender ??= requestAnimationFrame(this.renderSelection);\n }\n\n private renderSelection = (): void => {\n if (this._queuedRender != null) {\n cancelAnimationFrame(this._queuedRender);\n this._queuedRender = undefined;\n }\n if (\n this.pre == null ||\n this.renderedSelectionRange === this.selectedRange\n ) {\n return;\n }\n\n // First clear existing selections, maybe we\n // can cache this to better avoid this query?\n const allSelected = this.pre.querySelectorAll('[data-selected-line]');\n for (const element of allSelected) {\n element.removeAttribute('data-selected-line');\n }\n\n this.renderedSelectionRange = this.selectedRange;\n if (this.selectedRange == null) {\n return;\n }\n\n const codeElements = this.pre.querySelectorAll('[data-code]');\n if (codeElements.length === 0) return;\n if (codeElements.length > 2) {\n console.error(codeElements);\n throw new Error(\n 'LineSelectionManager.applySelectionToDOM: Somehow there are more than 2 code elements...'\n );\n }\n const split = this.pre.dataset.type === 'split';\n const rowRange = this.deriveRowRangeFromDOM(this.selectedRange, split);\n if (rowRange == null) {\n console.error({ rowRange, selectedRange: this.selectedRange });\n throw new Error(\n 'LineSelectionManager.renderSelection: No valid rowRange'\n );\n }\n const isSingle = rowRange.start === rowRange.end;\n const first = Math.min(rowRange.start, rowRange.end);\n const last = Math.max(rowRange.start, rowRange.end);\n for (const code of codeElements) {\n for (const element of code.children) {\n if (!(element instanceof HTMLElement)) continue;\n const lineIndex = this.getLineIndex(element, split);\n if ((lineIndex ?? 0) > last) break;\n if (lineIndex == null || lineIndex < first) continue;\n let attributeValue = isSingle\n ? 'single'\n : lineIndex === first\n ? 'first'\n : lineIndex === last\n ? 'last'\n : '';\n element.setAttribute('data-selected-line', attributeValue);\n // If we have a line annotation following our selected line, we should\n // mark it as selected as well\n if (\n element.nextSibling instanceof HTMLElement &&\n element.nextSibling.hasAttribute('data-line-annotation')\n ) {\n // Depending on the line's attribute value, lets go ahead and correct\n // it when adding in the annotation row\n if (isSingle) {\n // Single technically becomes 2 selected lines\n attributeValue = 'last';\n element.setAttribute('data-selected-line', 'first');\n } else if (lineIndex === first) {\n // We don't want apply 'first' to the line annotation\n attributeValue = '';\n } else if (lineIndex === last) {\n // the annotation will become the last selected line and therefore\n // our existing line should no longer be last\n element.setAttribute('data-selected-line', '');\n }\n element.nextSibling.setAttribute(\n 'data-selected-line',\n attributeValue\n );\n }\n }\n }\n };\n\n private deriveRowRangeFromDOM(\n range: SelectedLineRange,\n split: boolean\n ): { start: number; end: number } | undefined {\n if (range == null) return undefined;\n const start = this.findRowIndexForLineNumber(\n range.start,\n range.side,\n split\n );\n const end =\n range.end === range.start &&\n (range.endSide == null || range.endSide === range.side)\n ? start\n : this.findRowIndexForLineNumber(\n range.end,\n range.endSide ?? range.side,\n split\n );\n return start != null && end != null ? { start, end } : undefined;\n }\n\n private findRowIndexForLineNumber(\n lineNumber: number,\n targetSide: SelectionSide = 'additions',\n split: boolean\n ): number | undefined {\n if (this.pre == null) return undefined;\n const elements = Array.from(\n this.pre.querySelectorAll(`[data-line=\"${lineNumber}\"]`)\n );\n // Given how unified diffs can order things, we need to always process\n // `[data-line]` elements before `[data-alt-line]`\n elements.push(\n ...Array.from(\n this.pre.querySelectorAll(`[data-alt-line=\"${lineNumber}\"]`)\n )\n );\n if (elements.length === 0) return undefined;\n\n for (const element of elements) {\n if (!(element instanceof HTMLElement)) {\n continue;\n }\n const side = this.getLineSideFromElement(element);\n if (side === targetSide) {\n return this.getLineIndex(element, split);\n } else if (parseInt(element.dataset.altLine ?? '') === lineNumber) {\n return this.getLineIndex(element, split);\n }\n }\n console.error(\n 'LineSelectionManager.findRowIndexForLineNumber: Invalid selection',\n lineNumber,\n targetSide\n );\n return undefined;\n }\n\n private notifySelectionChange(): void {\n const { onLineSelected } = this.options;\n if (onLineSelected == null) return;\n\n onLineSelected(this.selectedRange ?? null);\n }\n\n private notifySelectionStart(range: SelectedLineRange | null): void {\n const { onLineSelectionStart } = this.options;\n if (onLineSelectionStart == null) return;\n onLineSelectionStart(range);\n }\n\n private notifySelectionEnd(range: SelectedLineRange | null): void {\n const { onLineSelectionEnd } = this.options;\n if (onLineSelectionEnd == null) return;\n onLineSelectionEnd(range);\n }\n\n private getMouseEventDataForPath(\n path: (EventTarget | undefined)[],\n eventType: 'click' | 'move'\n ): MouseInfo | undefined {\n let lineNumber: number | undefined;\n let lineIndex: number | undefined;\n let isNumberColumn = false;\n let eventSide: AnnotationSide | undefined;\n for (const element of path) {\n if (!(element instanceof HTMLElement)) {\n continue;\n }\n if (element.hasAttribute('data-column-number')) {\n isNumberColumn = true;\n continue;\n }\n if (element.hasAttribute('data-line')) {\n lineNumber = this.getLineNumber(element);\n lineIndex = this.getLineIndex(\n element,\n this.pre?.dataset.type === 'split'\n );\n if (element.dataset.lineType === 'change-deletion') {\n eventSide = 'deletions';\n } else if (element.dataset.lineType === 'change-additions') {\n eventSide = 'additions';\n }\n // if we can't pull out an index or line number, we can't do anything.\n if (lineIndex == null || lineNumber == null) {\n lineIndex = undefined;\n lineNumber = undefined;\n break;\n }\n // If we already have an eventSide, we done computin\n if (eventSide != null) {\n break;\n } else {\n // context type lines will need to be discovered higher up\n // at the data-code level\n }\n continue;\n }\n if (element.hasAttribute('data-code')) {\n eventSide ??= element.hasAttribute('data-deletions')\n ? 'deletions'\n : // context in unified style are assumed to be additions based on\n // their line numbers\n 'additions';\n // If we got to the code element, we def done, son\n break;\n }\n }\n if (\n (eventType === 'click' && !isNumberColumn) ||\n lineIndex == null ||\n lineNumber == null\n ) {\n return undefined;\n }\n return {\n lineIndex,\n lineNumber,\n // Normally this shouldn't hit unless we broke early for whatever reason,\n // but for types lets ensure it's additions if undefined\n eventSide: eventSide ?? 'additions',\n };\n }\n\n private getLineNumber(element: HTMLElement): number | undefined {\n const lineNumber = parseInt(element.dataset.line ?? '', 10);\n return !Number.isNaN(lineNumber) ? lineNumber : undefined;\n }\n\n private getLineIndex(\n element: HTMLElement,\n split: boolean\n ): number | undefined {\n const lineIndexes = (element.dataset.lineIndex ?? '')\n .split(',')\n .map((value) => parseInt(value))\n .filter((value) => !Number.isNaN(value));\n\n if (split && lineIndexes.length === 2) {\n return lineIndexes[1];\n } else if (!split) {\n return lineIndexes[0];\n }\n return undefined;\n }\n\n private getLineSideFromElement(element: HTMLElement): SelectionSide {\n if (element.dataset.lineType === 'change-deletion') {\n return 'deletions';\n }\n if (element.dataset.lineType === 'change-addition') {\n return 'additions';\n }\n const parent = element.closest('[data-code]');\n if (!(parent instanceof HTMLElement)) {\n return 'additions';\n }\n return parent.hasAttribute('data-deletions') ? 'deletions' : 'additions';\n }\n}\n\nexport function pluckLineSelectionOptions({\n enableLineSelection,\n onLineSelected,\n onLineSelectionStart,\n onLineSelectionEnd,\n}: LineSelectionOptions): LineSelectionOptions {\n return {\n enableLineSelection,\n onLineSelected,\n onLineSelectionStart,\n onLineSelectionEnd,\n };\n}\n"],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -120,7 +120,7 @@ interface LineInfo {
|
|
|
120
120
|
type: LineTypes;
|
|
121
121
|
lineNumber: number;
|
|
122
122
|
altLineNumber?: number;
|
|
123
|
-
lineIndex: number
|
|
123
|
+
lineIndex: number | `${number},${number}`;
|
|
124
124
|
}
|
|
125
125
|
interface SharedRenderState {
|
|
126
126
|
lineInfo: Record<number, LineInfo | undefined> | ((shikiLineNumber: number) => LineInfo);
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","names":[],"sources":["../src/types.ts"],"sourcesContent":[],"mappings":";;;;UAaiB,YAAA;;EAAjB,IAAiB,EAAA,MAAA;EAoBjB,QAAY,EAAA,MAAA;EAMZ,IAAY,CAAA,EAtBH,kBAsBG;EAEZ,MAAY,CAAA,EAAA,MAAA;;AAAmB,KARnB,eAAA,GACR,YAO2B,GAAA,aAAA,GAAA,cAAA,GAAA,CAAA,MAAA,GAAA,CAAA,CAAA,CAAA;AAAA,KAFnB,UAAA,GAAa,MAEM,CAAA,MAAA,GAAA,OAAA,EAFmB,eAEnB,CAAA;AAKnB,KALA,gBAAA,GAAmB,kBAKnB,CAJV,kBAIU,EAHV,eAGU,CAAA;AAOK,KAPL,WAAA,GAOK,QAER,GAAA,aAAA,GAAA,gBAAA,GAAA,KAAA,GAAA,SAAA;AAGQ,UALA,WAAA,CAKA;EAMjB,aAAiB,CAAA,EAAA,MAAA;EAQjB,KAAiB,EAjBR,gBA6BO,EAAA;AAKhB;AAGS,UAlCQ,cAAA,CAkCR;EACD,IAAA,EAAA,SAAA;EACC,KAAA,EAAA,MAAA,EAAA;EAAA,OAAA,EAAA,OAAA;AAUT;AAGY,UA3CK,aAAA,CA2CL;EAOZ,IAAY,EAAA,QAAA;EAEZ,SAAY,EAAA,MAAA,EAAA;EAEZ,SAAY,EAAA,MAAA,EAAA;EAEZ,gBAAiB,EAAA,OAAA;EACP,gBAAA,EAAA,OAAA;;AAGI,UApDG,IAAA,CAoDH;EAAA,eAAA,EAAA,MAAA;EAWd,cAAiB,EAAA,MAAA;EAIE,cAAA,EAAA,MAAA;EAIF,gBAAA,EAAA,MAAA;EARwB,gBAAA,EAAA,MAAA;EAAA,aAAA,EAAA,MAAA;EAkBzC,aAAiB,EAAA,MAAA;EAGX,aAAA,EAAA,MAAA;EADF,aAAA,EAAA,MAAA;EADM,aAAA,EAAA,MAAA;EAAA,aAAA,EAAA,MAAA;EAeV,WAAiB,EAAA,CArFD,cAqFC,GArFgB,aAqFhB,CAAA,EAAA;EACL,WAAA,EAAA,MAAA,GAAA,SAAA;EACA,SAAA,EAAA,MAAA,GAAA,SAAA;;AACC,UAnFI,gBAAA,CAmFJ;EAGb,IAAY,EAAA,MAAA;EAIZ,QAAY,EAAA,MAAA,GAAA,SAAA;EAIZ,IAAY,CAAA,EA3FH,kBA2FG;EAEZ,IAAY,EA5FJ,WA4FI;EAA+B,KAEtC,EA7FI,IA6FJ,EAAA;EAIL,cAAY,EAAA,MAAA;EAIZ,gBAAY,EAAA,MAAA;EACJ,OAAA,CAAA,EAAA,MAAA;EAEa,IAAA,CAAA,EAAA,MAAA;EAAjB,QAAA,CAAA,EAAA,MAAA,EAAA;EAAA,QAAA,CAAA,EAAA,MAAA,EAAA;EAEJ,QAAiB,CAAA,EAAA,MAAA;AAKjB;AAKY,KA1GA,kBAAA,GAAqB,eA0GrB,GAAA,MAAA;AAMK,KA7GL,YAAA,
|
|
1
|
+
{"version":3,"file":"types.d.ts","names":[],"sources":["../src/types.ts"],"sourcesContent":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parseLineType.d.ts","names":[],"sources":["../../src/utils/parseLineType.ts"],"sourcesContent":[],"mappings":";;;UAEiB,UAAA;;EAAjB,IAAiB,EAET,OAFS,CAED,YAFC,
|
|
1
|
+
{"version":3,"file":"parseLineType.d.ts","names":[],"sources":["../../src/utils/parseLineType.ts"],"sourcesContent":[],"mappings":";;;UAEiB,UAAA;;EAAjB,IAAiB,EAET,OAFS,CAED,YAFC,EAED,UAAA,CAAA;AAGhB;iBAAgB,aAAA,gBAA6B"}
|
|
@@ -32,7 +32,7 @@ function processLine(node, line, state) {
|
|
|
32
32
|
"data-line": lineInfo.lineNumber,
|
|
33
33
|
"data-alt-line": lineInfo.altLineNumber,
|
|
34
34
|
"data-line-type": lineInfo.type,
|
|
35
|
-
"data-line-index": lineInfo.lineIndex
|
|
35
|
+
"data-line-index": lineInfo.lineIndex
|
|
36
36
|
}
|
|
37
37
|
});
|
|
38
38
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"processLine.js","names":[],"sources":["../../src/utils/processLine.ts"],"sourcesContent":["import type { ElementContent, Element as HASTElement } from 'hast';\n\nimport type { SharedRenderState } from '../types';\nimport { createHastElement, createTextNodeElement } from './hast_utils';\n\nexport function processLine(\n node: HASTElement,\n line: number,\n state: SharedRenderState\n): ElementContent {\n const lineInfo =\n typeof state.lineInfo === 'function'\n ? state.lineInfo(line)\n : state.lineInfo[line];\n if (lineInfo == null) {\n console.error({ node, line, state });\n throw new Error(`processLine: line ${line}, contains no state.lineInfo`);\n }\n // We need to convert the current line to a div but keep all the decorations\n // that may be applied\n node.tagName = 'span';\n node.properties['data-column-content'] = '';\n\n // NOTE(amadeus): We need to push newline characters into empty rows or else\n // copy/pasta will have issues\n if (node.children.length === 0) {\n node.children.push(createTextNodeElement('\\n'));\n }\n const children = [\n createHastElement({\n tagName: 'span',\n children: [\n createHastElement({\n tagName: 'span',\n children: [{ type: 'text', value: `${lineInfo.lineNumber}` }],\n properties: { 'data-line-number-content': '' },\n }),\n ],\n properties: { 'data-column-number': '' },\n }),\n node,\n ];\n return createHastElement({\n tagName: 'div',\n children,\n properties: {\n 'data-line': lineInfo.lineNumber,\n 'data-alt-line': lineInfo.altLineNumber,\n 'data-line-type': lineInfo.type,\n 'data-line-index'
|
|
1
|
+
{"version":3,"file":"processLine.js","names":[],"sources":["../../src/utils/processLine.ts"],"sourcesContent":["import type { ElementContent, Element as HASTElement } from 'hast';\n\nimport type { SharedRenderState } from '../types';\nimport { createHastElement, createTextNodeElement } from './hast_utils';\n\nexport function processLine(\n node: HASTElement,\n line: number,\n state: SharedRenderState\n): ElementContent {\n const lineInfo =\n typeof state.lineInfo === 'function'\n ? state.lineInfo(line)\n : state.lineInfo[line];\n if (lineInfo == null) {\n console.error({ node, line, state });\n throw new Error(`processLine: line ${line}, contains no state.lineInfo`);\n }\n // We need to convert the current line to a div but keep all the decorations\n // that may be applied\n node.tagName = 'span';\n node.properties['data-column-content'] = '';\n\n // NOTE(amadeus): We need to push newline characters into empty rows or else\n // copy/pasta will have issues\n if (node.children.length === 0) {\n node.children.push(createTextNodeElement('\\n'));\n }\n const children = [\n createHastElement({\n tagName: 'span',\n children: [\n createHastElement({\n tagName: 'span',\n children: [{ type: 'text', value: `${lineInfo.lineNumber}` }],\n properties: { 'data-line-number-content': '' },\n }),\n ],\n properties: { 'data-column-number': '' },\n }),\n node,\n ];\n return createHastElement({\n tagName: 'div',\n children,\n properties: {\n 'data-line': lineInfo.lineNumber,\n 'data-alt-line': lineInfo.altLineNumber,\n 'data-line-type': lineInfo.type,\n 'data-line-index': lineInfo.lineIndex,\n },\n });\n}\n"],"mappings":";;;AAKA,SAAgB,YACd,MACA,MACA,OACgB;CAChB,MAAM,WACJ,OAAO,MAAM,aAAa,aACtB,MAAM,SAAS,KAAK,GACpB,MAAM,SAAS;AACrB,KAAI,YAAY,MAAM;AACpB,UAAQ,MAAM;GAAE;GAAM;GAAM;GAAO,CAAC;AACpC,QAAM,IAAI,MAAM,qBAAqB,KAAK,8BAA8B;;AAI1E,MAAK,UAAU;AACf,MAAK,WAAW,yBAAyB;AAIzC,KAAI,KAAK,SAAS,WAAW,EAC3B,MAAK,SAAS,KAAK,sBAAsB,KAAK,CAAC;AAgBjD,QAAO,kBAAkB;EACvB,SAAS;EACT,UAhBe,CACf,kBAAkB;GAChB,SAAS;GACT,UAAU,CACR,kBAAkB;IAChB,SAAS;IACT,UAAU,CAAC;KAAE,MAAM;KAAQ,OAAO,GAAG,SAAS;KAAc,CAAC;IAC7D,YAAY,EAAE,4BAA4B,IAAI;IAC/C,CAAC,CACH;GACD,YAAY,EAAE,sBAAsB,IAAI;GACzC,CAAC,EACF,KACD;EAIC,YAAY;GACV,aAAa,SAAS;GACtB,iBAAiB,SAAS;GAC1B,kBAAkB,SAAS;GAC3B,mBAAmB,SAAS;GAC7B;EACF,CAAC"}
|
|
@@ -48,11 +48,13 @@ function renderDiffWithHighlighter(diff, highlighter, options, forcePlainText =
|
|
|
48
48
|
};
|
|
49
49
|
}
|
|
50
50
|
const hunks = [];
|
|
51
|
-
let
|
|
51
|
+
let splitLineIndex = 0;
|
|
52
|
+
let unifiedLineIndex = 0;
|
|
52
53
|
for (const hunk of diff.hunks) {
|
|
53
|
-
const { oldContent, newContent, oldInfo, newInfo, oldDecorations, newDecorations,
|
|
54
|
+
const { oldContent, newContent, oldInfo, newInfo, oldDecorations, newDecorations, splitLineIndex: newSplitLineIndex, unifiedLineIndex: newUnifiedLineIndex } = processLines({
|
|
54
55
|
hunks: [hunk],
|
|
55
|
-
|
|
56
|
+
splitLineIndex,
|
|
57
|
+
unifiedLineIndex,
|
|
56
58
|
lineDiffType: options.lineDiffType
|
|
57
59
|
});
|
|
58
60
|
const oldFile = {
|
|
@@ -74,7 +76,8 @@ function renderDiffWithHighlighter(diff, highlighter, options, forcePlainText =
|
|
|
74
76
|
options,
|
|
75
77
|
languageOverride: forcePlainText ? "text" : diff.lang
|
|
76
78
|
}));
|
|
77
|
-
|
|
79
|
+
splitLineIndex = newSplitLineIndex;
|
|
80
|
+
unifiedLineIndex = newUnifiedLineIndex;
|
|
78
81
|
}
|
|
79
82
|
return {
|
|
80
83
|
code: (() => {
|
|
@@ -148,7 +151,7 @@ function computeLineDiffDecorations({ oldLine, newLine, oldLineIndex, newLineInd
|
|
|
148
151
|
spanIndex += span[1].length;
|
|
149
152
|
}
|
|
150
153
|
}
|
|
151
|
-
function processLines({ hunks, oldLines, newLines,
|
|
154
|
+
function processLines({ hunks, oldLines, newLines, splitLineIndex = 0, unifiedLineIndex = 0, lineDiffType }) {
|
|
152
155
|
const oldInfo = {};
|
|
153
156
|
const newInfo = {};
|
|
154
157
|
const oldDecorations = [];
|
|
@@ -164,12 +167,14 @@ function processLines({ hunks, oldLines, newLines, lineIndex = 0, lineDiffType }
|
|
|
164
167
|
oldInfo[oldLineIndex] = {
|
|
165
168
|
type: "context-expanded",
|
|
166
169
|
lineNumber: oldLineNumber,
|
|
167
|
-
|
|
170
|
+
altLineNumber: newLineNumber,
|
|
171
|
+
lineIndex: `${unifiedLineIndex},${splitLineIndex}`
|
|
168
172
|
};
|
|
169
173
|
newInfo[newLineIndex] = {
|
|
170
174
|
type: "context-expanded",
|
|
171
175
|
lineNumber: newLineNumber,
|
|
172
|
-
|
|
176
|
+
altLineNumber: oldLineNumber,
|
|
177
|
+
lineIndex: `${unifiedLineIndex},${splitLineIndex}`
|
|
173
178
|
};
|
|
174
179
|
oldContent += oldLines[oldLineIndex - 1];
|
|
175
180
|
newContent += newLines[newLineIndex - 1];
|
|
@@ -177,7 +182,8 @@ function processLines({ hunks, oldLines, newLines, lineIndex = 0, lineDiffType }
|
|
|
177
182
|
newLineIndex++;
|
|
178
183
|
oldLineNumber++;
|
|
179
184
|
newLineNumber++;
|
|
180
|
-
|
|
185
|
+
splitLineIndex++;
|
|
186
|
+
unifiedLineIndex++;
|
|
181
187
|
}
|
|
182
188
|
oldLineNumber = hunk.deletionStart;
|
|
183
189
|
newLineNumber = hunk.additionStart;
|
|
@@ -185,12 +191,14 @@ function processLines({ hunks, oldLines, newLines, lineIndex = 0, lineDiffType }
|
|
|
185
191
|
oldInfo[oldLineIndex] = {
|
|
186
192
|
type: "context",
|
|
187
193
|
lineNumber: oldLineNumber,
|
|
188
|
-
|
|
194
|
+
altLineNumber: newLineNumber,
|
|
195
|
+
lineIndex: `${unifiedLineIndex},${splitLineIndex}`
|
|
189
196
|
};
|
|
190
197
|
newInfo[newLineIndex] = {
|
|
191
198
|
type: "context",
|
|
192
199
|
lineNumber: newLineNumber,
|
|
193
|
-
|
|
200
|
+
altLineNumber: oldLineNumber,
|
|
201
|
+
lineIndex: `${unifiedLineIndex},${splitLineIndex}`
|
|
194
202
|
};
|
|
195
203
|
oldContent += line;
|
|
196
204
|
newContent += line;
|
|
@@ -198,11 +206,13 @@ function processLines({ hunks, oldLines, newLines, lineIndex = 0, lineDiffType }
|
|
|
198
206
|
newLineIndex++;
|
|
199
207
|
newLineNumber++;
|
|
200
208
|
oldLineNumber++;
|
|
201
|
-
|
|
209
|
+
splitLineIndex++;
|
|
210
|
+
unifiedLineIndex++;
|
|
202
211
|
}
|
|
203
212
|
else {
|
|
204
213
|
const len = Math.max(hunkContent.additions.length, hunkContent.deletions.length);
|
|
205
214
|
let i = 0;
|
|
215
|
+
let _unifiedLineIndex = unifiedLineIndex;
|
|
206
216
|
while (i < len) {
|
|
207
217
|
const oldLine = hunkContent.deletions[i];
|
|
208
218
|
const newLine = hunkContent.additions[i];
|
|
@@ -219,7 +229,7 @@ function processLines({ hunks, oldLines, newLines, lineIndex = 0, lineDiffType }
|
|
|
219
229
|
oldInfo[oldLineIndex] = {
|
|
220
230
|
type: "change-deletion",
|
|
221
231
|
lineNumber: oldLineNumber,
|
|
222
|
-
lineIndex
|
|
232
|
+
lineIndex: `${_unifiedLineIndex},${splitLineIndex}`
|
|
223
233
|
};
|
|
224
234
|
oldContent += oldLine;
|
|
225
235
|
oldLineIndex++;
|
|
@@ -229,15 +239,17 @@ function processLines({ hunks, oldLines, newLines, lineIndex = 0, lineDiffType }
|
|
|
229
239
|
newInfo[newLineIndex] = {
|
|
230
240
|
type: "change-addition",
|
|
231
241
|
lineNumber: newLineNumber,
|
|
232
|
-
lineIndex
|
|
242
|
+
lineIndex: `${_unifiedLineIndex + hunkContent.deletions.length},${splitLineIndex}`
|
|
233
243
|
};
|
|
234
244
|
newContent += newLine;
|
|
235
245
|
newLineIndex++;
|
|
236
246
|
newLineNumber++;
|
|
237
247
|
}
|
|
238
|
-
|
|
248
|
+
splitLineIndex++;
|
|
249
|
+
_unifiedLineIndex++;
|
|
239
250
|
i++;
|
|
240
251
|
}
|
|
252
|
+
unifiedLineIndex += hunkContent.additions.length + hunkContent.deletions.length;
|
|
241
253
|
}
|
|
242
254
|
if (oldLines == null || newLines == null || hunk !== hunks[hunks.length - 1]) continue;
|
|
243
255
|
while (oldLineIndex <= oldLines.length || newLineIndex <= oldLines.length) {
|
|
@@ -248,7 +260,8 @@ function processLines({ hunks, oldLines, newLines, lineIndex = 0, lineDiffType }
|
|
|
248
260
|
oldInfo[oldLineIndex] = {
|
|
249
261
|
type: "context-expanded",
|
|
250
262
|
lineNumber: oldLineNumber,
|
|
251
|
-
|
|
263
|
+
altLineNumber: newLineNumber,
|
|
264
|
+
lineIndex: `${unifiedLineIndex},${splitLineIndex}`
|
|
252
265
|
};
|
|
253
266
|
oldContent += oldLine;
|
|
254
267
|
oldLineIndex++;
|
|
@@ -258,13 +271,15 @@ function processLines({ hunks, oldLines, newLines, lineIndex = 0, lineDiffType }
|
|
|
258
271
|
newInfo[newLineIndex] = {
|
|
259
272
|
type: "context-expanded",
|
|
260
273
|
lineNumber: newLineNumber,
|
|
261
|
-
|
|
274
|
+
altLineNumber: oldLineNumber,
|
|
275
|
+
lineIndex: `${unifiedLineIndex},${splitLineIndex}`
|
|
262
276
|
};
|
|
263
277
|
newContent += newLine;
|
|
264
278
|
newLineIndex++;
|
|
265
279
|
newLineNumber++;
|
|
266
280
|
}
|
|
267
|
-
|
|
281
|
+
splitLineIndex++;
|
|
282
|
+
unifiedLineIndex++;
|
|
268
283
|
}
|
|
269
284
|
}
|
|
270
285
|
return {
|
|
@@ -274,7 +289,8 @@ function processLines({ hunks, oldLines, newLines, lineIndex = 0, lineDiffType }
|
|
|
274
289
|
newInfo,
|
|
275
290
|
oldDecorations,
|
|
276
291
|
newDecorations,
|
|
277
|
-
|
|
292
|
+
splitLineIndex,
|
|
293
|
+
unifiedLineIndex
|
|
278
294
|
};
|
|
279
295
|
}
|
|
280
296
|
function renderTwoFiles({ oldFile, newFile, oldInfo, newInfo, highlighter, oldDecorations, newDecorations, languageOverride, options: { theme: themeOrThemes = DEFAULT_THEMES,...options } }) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"renderDiffWithHighlighter.js","names":["hunks: RenderDiffFilesResult[]","deletionSpans: [0 | 1, string][]","additionSpans: [0 | 1, string][]","oldInfo: Record<number, LineInfo | undefined>","newInfo: Record<number, LineInfo | undefined>","oldDecorations: DecorationItem[]","newDecorations: DecorationItem[]","hastConfig: CodeToHastOptions<DiffsThemeNames>"],"sources":["../../src/utils/renderDiffWithHighlighter.ts"],"sourcesContent":["import { diffChars, diffWordsWithSpace } from 'diff';\n\nimport { DEFAULT_THEMES } from '../constants';\nimport type {\n CodeToHastOptions,\n DecorationItem,\n DiffsHighlighter,\n DiffsThemeNames,\n FileContents,\n FileDiffMetadata,\n Hunk,\n LineDiffTypes,\n LineInfo,\n RenderDiffFilesResult,\n RenderDiffOptions,\n SupportedLanguages,\n ThemedDiffResult,\n} from '../types';\nimport { cleanLastNewline } from './cleanLastNewline';\nimport { createTransformerWithState } from './createTransformerWithState';\nimport { formatCSSVariablePrefix } from './formatCSSVariablePrefix';\nimport { getFiletypeFromFileName } from './getFiletypeFromFileName';\nimport { getHighlighterThemeStyles } from './getHighlighterThemeStyles';\nimport { getLineNodes } from './getLineNodes';\nimport {\n createDiffSpanDecoration,\n pushOrJoinSpan,\n} from './parseDiffDecorations';\n\nexport function renderDiffWithHighlighter(\n diff: FileDiffMetadata,\n highlighter: DiffsHighlighter,\n options: RenderDiffOptions,\n forcePlainText = false\n): ThemedDiffResult {\n const baseThemeType = (() => {\n const theme = options.theme ?? DEFAULT_THEMES;\n if (typeof theme === 'string') {\n return highlighter.getTheme(theme).type;\n }\n return undefined;\n })();\n const themeStyles = getHighlighterThemeStyles({\n theme: options.theme,\n highlighter,\n });\n // If we've received a diff with both files\n if (diff.newLines != null && diff.oldLines != null) {\n const {\n oldContent,\n newContent,\n oldInfo,\n newInfo,\n oldDecorations,\n newDecorations,\n } = processLines({\n hunks: diff.hunks,\n oldLines: diff.oldLines,\n newLines: diff.newLines,\n lineDiffType: options.lineDiffType,\n });\n const oldFile = {\n name: diff.prevName ?? diff.name,\n contents: oldContent,\n };\n const newFile = {\n name: diff.name,\n contents: newContent,\n };\n const code = renderTwoFiles({\n oldFile,\n oldInfo,\n oldDecorations,\n\n newFile,\n newInfo,\n newDecorations,\n\n highlighter,\n options,\n languageOverride: forcePlainText ? 'text' : diff.lang,\n });\n return { code, themeStyles, baseThemeType };\n }\n const hunks: RenderDiffFilesResult[] = [];\n let lineIndex = 0;\n for (const hunk of diff.hunks) {\n const result = processLines({\n hunks: [hunk],\n lineIndex,\n lineDiffType: options.lineDiffType,\n });\n const {\n oldContent,\n newContent,\n oldInfo,\n newInfo,\n oldDecorations,\n newDecorations,\n lineIndex: newLineIndex,\n } = result;\n const oldFile = {\n name: diff.prevName ?? diff.name,\n contents: oldContent,\n };\n const newFile = {\n name: diff.name,\n contents: newContent,\n };\n hunks.push(\n renderTwoFiles({\n oldFile,\n oldInfo,\n oldDecorations,\n\n newFile,\n newInfo,\n newDecorations,\n\n highlighter,\n options,\n languageOverride: forcePlainText ? 'text' : diff.lang,\n })\n );\n lineIndex = newLineIndex;\n }\n\n const code = (() => {\n if (hunks.length <= 1) {\n const hunk = hunks[0] ?? { oldLines: [], newLines: [] };\n if (hunk.newLines.length === 0 || hunk.oldLines.length === 0) {\n return hunk;\n }\n }\n return { hunks };\n })();\n\n return { code, themeStyles, baseThemeType };\n}\n\ninterface ProcessLineDiffProps {\n oldLine: string | undefined;\n newLine: string | undefined;\n oldLineIndex: number;\n newLineIndex: number;\n oldDecorations: DecorationItem[];\n newDecorations: DecorationItem[];\n lineDiffType: LineDiffTypes;\n}\n\nfunction computeLineDiffDecorations({\n oldLine,\n newLine,\n oldLineIndex,\n newLineIndex,\n oldDecorations,\n newDecorations,\n lineDiffType,\n}: ProcessLineDiffProps) {\n if (oldLine == null || newLine == null || lineDiffType === 'none') {\n return;\n }\n oldLine = cleanLastNewline(oldLine);\n newLine = cleanLastNewline(newLine);\n // NOTE(amadeus): Because we visually trim trailing newlines when rendering,\n // we also gotta make sure the diff parsing doesn't include the newline\n // character that could be there...\n const lineDiff =\n lineDiffType === 'char'\n ? diffChars(oldLine, newLine)\n : diffWordsWithSpace(oldLine, newLine);\n const deletionSpans: [0 | 1, string][] = [];\n const additionSpans: [0 | 1, string][] = [];\n const enableJoin = lineDiffType === 'word-alt';\n for (const item of lineDiff) {\n const isLastItem = item === lineDiff[lineDiff.length - 1];\n if (!item.added && !item.removed) {\n pushOrJoinSpan({\n item,\n arr: deletionSpans,\n enableJoin,\n isNeutral: true,\n isLastItem,\n });\n pushOrJoinSpan({\n item,\n arr: additionSpans,\n enableJoin,\n isNeutral: true,\n isLastItem,\n });\n } else if (item.removed) {\n pushOrJoinSpan({ item, arr: deletionSpans, enableJoin, isLastItem });\n } else {\n pushOrJoinSpan({ item, arr: additionSpans, enableJoin, isLastItem });\n }\n }\n let spanIndex = 0;\n for (const span of deletionSpans) {\n if (span[0] === 1) {\n oldDecorations.push(\n createDiffSpanDecoration({\n // Decoration indexes start at 0\n line: oldLineIndex - 1,\n spanStart: spanIndex,\n spanLength: span[1].length,\n })\n );\n }\n spanIndex += span[1].length;\n }\n spanIndex = 0;\n for (const span of additionSpans) {\n if (span[0] === 1) {\n newDecorations.push(\n createDiffSpanDecoration({\n // Decoration indexes start at 0\n line: newLineIndex - 1,\n spanStart: spanIndex,\n spanLength: span[1].length,\n })\n );\n }\n spanIndex += span[1].length;\n }\n}\n\ninterface ProcessLinesProps {\n hunks: Hunk[];\n oldLines?: string[];\n newLines?: string[];\n lineIndex?: number;\n newLineIndex?: number;\n oldLineIndex?: number;\n lineDiffType: LineDiffTypes;\n}\n\nfunction processLines({\n hunks,\n oldLines,\n newLines,\n lineIndex = 0,\n lineDiffType,\n}: ProcessLinesProps) {\n const oldInfo: Record<number, LineInfo | undefined> = {};\n const newInfo: Record<number, LineInfo | undefined> = {};\n const oldDecorations: DecorationItem[] = [];\n const newDecorations: DecorationItem[] = [];\n let newLineIndex = 1;\n let oldLineIndex = 1;\n let newLineNumber = 1;\n let oldLineNumber = 1;\n let oldContent = '';\n let newContent = '';\n for (const hunk of hunks) {\n // If there's content prior to the hunk, lets fill it up\n while (\n oldLines != null &&\n newLines != null &&\n newLineIndex < hunk.additionStart &&\n oldLineIndex < hunk.deletionStart\n ) {\n oldInfo[oldLineIndex] = {\n type: 'context-expanded',\n lineNumber: oldLineNumber,\n lineIndex,\n };\n newInfo[newLineIndex] = {\n type: 'context-expanded',\n lineNumber: newLineNumber,\n lineIndex,\n };\n oldContent += oldLines[oldLineIndex - 1];\n newContent += newLines[newLineIndex - 1];\n oldLineIndex++;\n newLineIndex++;\n oldLineNumber++;\n newLineNumber++;\n lineIndex++;\n }\n oldLineNumber = hunk.deletionStart;\n newLineNumber = hunk.additionStart;\n\n // Lets process the actual hunk content\n for (const hunkContent of hunk.hunkContent) {\n if (hunkContent.type === 'context') {\n for (const line of hunkContent.lines) {\n oldInfo[oldLineIndex] = {\n type: 'context',\n lineNumber: oldLineNumber,\n lineIndex,\n };\n newInfo[newLineIndex] = {\n type: 'context',\n lineNumber: newLineNumber,\n lineIndex,\n };\n oldContent += line;\n newContent += line;\n oldLineIndex++;\n newLineIndex++;\n newLineNumber++;\n oldLineNumber++;\n lineIndex++;\n }\n } else {\n const len = Math.max(\n hunkContent.additions.length,\n hunkContent.deletions.length\n );\n let i = 0;\n while (i < len) {\n const oldLine = hunkContent.deletions[i];\n const newLine = hunkContent.additions[i];\n computeLineDiffDecorations({\n newLine,\n oldLine,\n oldLineIndex,\n newLineIndex,\n oldDecorations,\n newDecorations,\n lineDiffType,\n });\n if (oldLine != null) {\n oldInfo[oldLineIndex] = {\n type: 'change-deletion',\n lineNumber: oldLineNumber,\n lineIndex,\n };\n oldContent += oldLine;\n oldLineIndex++;\n oldLineNumber++;\n }\n if (newLine != null) {\n newInfo[newLineIndex] = {\n type: 'change-addition',\n lineNumber: newLineNumber,\n lineIndex,\n };\n newContent += newLine;\n newLineIndex++;\n newLineNumber++;\n }\n lineIndex++;\n i++;\n }\n }\n }\n\n if (\n oldLines == null ||\n newLines == null ||\n hunk !== hunks[hunks.length - 1]\n )\n continue;\n // If we are on the last hunk, we should fully iterate through the rest\n // of the lines\n while (oldLineIndex <= oldLines.length || newLineIndex <= oldLines.length) {\n const oldLine = oldLines[oldLineIndex - 1];\n const newLine = newLines[newLineIndex - 1];\n if (oldLine == null && newLine == null) {\n break;\n }\n if (oldLine != null) {\n oldInfo[oldLineIndex] = {\n type: 'context-expanded',\n lineNumber: oldLineNumber,\n lineIndex,\n };\n oldContent += oldLine;\n oldLineIndex++;\n oldLineNumber++;\n }\n if (newLine != null) {\n newInfo[newLineIndex] = {\n type: 'context-expanded',\n lineNumber: newLineNumber,\n lineIndex,\n };\n newContent += newLine;\n newLineIndex++;\n newLineNumber++;\n }\n lineIndex++;\n }\n }\n return {\n oldContent: cleanLastNewline(oldContent),\n newContent: cleanLastNewline(newContent),\n oldInfo,\n newInfo,\n oldDecorations,\n newDecorations,\n lineIndex,\n };\n}\n\ninterface RenderTwoFilesProps {\n oldFile: FileContents;\n newFile: FileContents;\n oldInfo: Record<number, LineInfo | undefined>;\n newInfo: Record<number, LineInfo | undefined>;\n oldDecorations: DecorationItem[];\n newDecorations: DecorationItem[];\n options: RenderDiffOptions;\n highlighter: DiffsHighlighter;\n languageOverride: SupportedLanguages | undefined;\n}\n\nfunction renderTwoFiles({\n oldFile,\n newFile,\n oldInfo,\n newInfo,\n highlighter,\n oldDecorations,\n newDecorations,\n languageOverride,\n options: { theme: themeOrThemes = DEFAULT_THEMES, ...options },\n}: RenderTwoFilesProps) {\n const oldLang = languageOverride ?? getFiletypeFromFileName(oldFile.name);\n const newLang = languageOverride ?? getFiletypeFromFileName(newFile.name);\n const { state, transformers } = createTransformerWithState();\n const hastConfig: CodeToHastOptions<DiffsThemeNames> = (() => {\n return typeof themeOrThemes === 'string'\n ? {\n ...options,\n // language will be overwritten for each highlight\n lang: 'text',\n theme: themeOrThemes,\n transformers,\n decorations: undefined,\n defaultColor: false,\n cssVariablePrefix: formatCSSVariablePrefix(),\n }\n : {\n ...options,\n // language will be overwritten for each highlight\n lang: 'text',\n themes: themeOrThemes,\n transformers,\n decorations: undefined,\n defaultColor: false,\n cssVariablePrefix: formatCSSVariablePrefix(),\n };\n })();\n\n const oldLines = (() => {\n if (oldFile.contents === '') {\n return [];\n }\n hastConfig.lang = oldLang;\n state.lineInfo = oldInfo;\n hastConfig.decorations = oldDecorations;\n return getLineNodes(highlighter.codeToHast(oldFile.contents, hastConfig));\n })();\n const newLines = (() => {\n if (newFile.contents === '') {\n return [];\n }\n hastConfig.lang = newLang;\n hastConfig.decorations = newDecorations;\n state.lineInfo = newInfo;\n return getLineNodes(highlighter.codeToHast(newFile.contents, hastConfig));\n })();\n\n return { oldLines, newLines };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"renderDiffWithHighlighter.js","names":["hunks: RenderDiffFilesResult[]","deletionSpans: [0 | 1, string][]","additionSpans: [0 | 1, string][]","oldInfo: Record<number, LineInfo | undefined>","newInfo: Record<number, LineInfo | undefined>","oldDecorations: DecorationItem[]","newDecorations: DecorationItem[]","hastConfig: CodeToHastOptions<DiffsThemeNames>"],"sources":["../../src/utils/renderDiffWithHighlighter.ts"],"sourcesContent":["import { diffChars, diffWordsWithSpace } from 'diff';\n\nimport { DEFAULT_THEMES } from '../constants';\nimport type {\n CodeToHastOptions,\n DecorationItem,\n DiffsHighlighter,\n DiffsThemeNames,\n FileContents,\n FileDiffMetadata,\n Hunk,\n LineDiffTypes,\n LineInfo,\n RenderDiffFilesResult,\n RenderDiffOptions,\n SupportedLanguages,\n ThemedDiffResult,\n} from '../types';\nimport { cleanLastNewline } from './cleanLastNewline';\nimport { createTransformerWithState } from './createTransformerWithState';\nimport { formatCSSVariablePrefix } from './formatCSSVariablePrefix';\nimport { getFiletypeFromFileName } from './getFiletypeFromFileName';\nimport { getHighlighterThemeStyles } from './getHighlighterThemeStyles';\nimport { getLineNodes } from './getLineNodes';\nimport {\n createDiffSpanDecoration,\n pushOrJoinSpan,\n} from './parseDiffDecorations';\n\nexport function renderDiffWithHighlighter(\n diff: FileDiffMetadata,\n highlighter: DiffsHighlighter,\n options: RenderDiffOptions,\n forcePlainText = false\n): ThemedDiffResult {\n const baseThemeType = (() => {\n const theme = options.theme ?? DEFAULT_THEMES;\n if (typeof theme === 'string') {\n return highlighter.getTheme(theme).type;\n }\n return undefined;\n })();\n const themeStyles = getHighlighterThemeStyles({\n theme: options.theme,\n highlighter,\n });\n // If we've received a diff with both files\n if (diff.newLines != null && diff.oldLines != null) {\n const {\n oldContent,\n newContent,\n oldInfo,\n newInfo,\n oldDecorations,\n newDecorations,\n } = processLines({\n hunks: diff.hunks,\n oldLines: diff.oldLines,\n newLines: diff.newLines,\n lineDiffType: options.lineDiffType,\n });\n const oldFile = {\n name: diff.prevName ?? diff.name,\n contents: oldContent,\n };\n const newFile = {\n name: diff.name,\n contents: newContent,\n };\n const code = renderTwoFiles({\n oldFile,\n oldInfo,\n oldDecorations,\n\n newFile,\n newInfo,\n newDecorations,\n\n highlighter,\n options,\n languageOverride: forcePlainText ? 'text' : diff.lang,\n });\n return { code, themeStyles, baseThemeType };\n }\n const hunks: RenderDiffFilesResult[] = [];\n let splitLineIndex = 0;\n let unifiedLineIndex = 0;\n for (const hunk of diff.hunks) {\n const {\n oldContent,\n newContent,\n oldInfo,\n newInfo,\n oldDecorations,\n newDecorations,\n splitLineIndex: newSplitLineIndex,\n unifiedLineIndex: newUnifiedLineIndex,\n } = processLines({\n hunks: [hunk],\n splitLineIndex,\n unifiedLineIndex,\n lineDiffType: options.lineDiffType,\n });\n const oldFile = {\n name: diff.prevName ?? diff.name,\n contents: oldContent,\n };\n const newFile = {\n name: diff.name,\n contents: newContent,\n };\n hunks.push(\n renderTwoFiles({\n oldFile,\n oldInfo,\n oldDecorations,\n\n newFile,\n newInfo,\n newDecorations,\n\n highlighter,\n options,\n languageOverride: forcePlainText ? 'text' : diff.lang,\n })\n );\n splitLineIndex = newSplitLineIndex;\n unifiedLineIndex = newUnifiedLineIndex;\n }\n\n const code = (() => {\n if (hunks.length <= 1) {\n const hunk = hunks[0] ?? { oldLines: [], newLines: [] };\n if (hunk.newLines.length === 0 || hunk.oldLines.length === 0) {\n return hunk;\n }\n }\n return { hunks };\n })();\n\n return { code, themeStyles, baseThemeType };\n}\n\ninterface ProcessLineDiffProps {\n oldLine: string | undefined;\n newLine: string | undefined;\n oldLineIndex: number;\n newLineIndex: number;\n oldDecorations: DecorationItem[];\n newDecorations: DecorationItem[];\n lineDiffType: LineDiffTypes;\n}\n\nfunction computeLineDiffDecorations({\n oldLine,\n newLine,\n oldLineIndex,\n newLineIndex,\n oldDecorations,\n newDecorations,\n lineDiffType,\n}: ProcessLineDiffProps) {\n if (oldLine == null || newLine == null || lineDiffType === 'none') {\n return;\n }\n oldLine = cleanLastNewline(oldLine);\n newLine = cleanLastNewline(newLine);\n // NOTE(amadeus): Because we visually trim trailing newlines when rendering,\n // we also gotta make sure the diff parsing doesn't include the newline\n // character that could be there...\n const lineDiff =\n lineDiffType === 'char'\n ? diffChars(oldLine, newLine)\n : diffWordsWithSpace(oldLine, newLine);\n const deletionSpans: [0 | 1, string][] = [];\n const additionSpans: [0 | 1, string][] = [];\n const enableJoin = lineDiffType === 'word-alt';\n for (const item of lineDiff) {\n const isLastItem = item === lineDiff[lineDiff.length - 1];\n if (!item.added && !item.removed) {\n pushOrJoinSpan({\n item,\n arr: deletionSpans,\n enableJoin,\n isNeutral: true,\n isLastItem,\n });\n pushOrJoinSpan({\n item,\n arr: additionSpans,\n enableJoin,\n isNeutral: true,\n isLastItem,\n });\n } else if (item.removed) {\n pushOrJoinSpan({ item, arr: deletionSpans, enableJoin, isLastItem });\n } else {\n pushOrJoinSpan({ item, arr: additionSpans, enableJoin, isLastItem });\n }\n }\n let spanIndex = 0;\n for (const span of deletionSpans) {\n if (span[0] === 1) {\n oldDecorations.push(\n createDiffSpanDecoration({\n // Decoration indexes start at 0\n line: oldLineIndex - 1,\n spanStart: spanIndex,\n spanLength: span[1].length,\n })\n );\n }\n spanIndex += span[1].length;\n }\n spanIndex = 0;\n for (const span of additionSpans) {\n if (span[0] === 1) {\n newDecorations.push(\n createDiffSpanDecoration({\n // Decoration indexes start at 0\n line: newLineIndex - 1,\n spanStart: spanIndex,\n spanLength: span[1].length,\n })\n );\n }\n spanIndex += span[1].length;\n }\n}\n\ninterface ProcessLinesProps {\n hunks: Hunk[];\n oldLines?: string[];\n newLines?: string[];\n splitLineIndex?: number;\n unifiedLineIndex?: number;\n newLineIndex?: number;\n oldLineIndex?: number;\n lineDiffType: LineDiffTypes;\n}\n\nfunction processLines({\n hunks,\n oldLines,\n newLines,\n splitLineIndex = 0,\n unifiedLineIndex = 0,\n lineDiffType,\n}: ProcessLinesProps) {\n const oldInfo: Record<number, LineInfo | undefined> = {};\n const newInfo: Record<number, LineInfo | undefined> = {};\n const oldDecorations: DecorationItem[] = [];\n const newDecorations: DecorationItem[] = [];\n let newLineIndex = 1;\n let oldLineIndex = 1;\n let newLineNumber = 1;\n let oldLineNumber = 1;\n let oldContent = '';\n let newContent = '';\n for (const hunk of hunks) {\n // If there's content prior to the hunk, lets fill it up\n while (\n oldLines != null &&\n newLines != null &&\n newLineIndex < hunk.additionStart &&\n oldLineIndex < hunk.deletionStart\n ) {\n oldInfo[oldLineIndex] = {\n type: 'context-expanded',\n lineNumber: oldLineNumber,\n altLineNumber: newLineNumber,\n lineIndex: `${unifiedLineIndex},${splitLineIndex}`,\n };\n newInfo[newLineIndex] = {\n type: 'context-expanded',\n lineNumber: newLineNumber,\n altLineNumber: oldLineNumber,\n lineIndex: `${unifiedLineIndex},${splitLineIndex}`,\n };\n oldContent += oldLines[oldLineIndex - 1];\n newContent += newLines[newLineIndex - 1];\n oldLineIndex++;\n newLineIndex++;\n oldLineNumber++;\n newLineNumber++;\n splitLineIndex++;\n unifiedLineIndex++;\n }\n oldLineNumber = hunk.deletionStart;\n newLineNumber = hunk.additionStart;\n\n // Lets process the actual hunk content\n for (const hunkContent of hunk.hunkContent) {\n if (hunkContent.type === 'context') {\n for (const line of hunkContent.lines) {\n oldInfo[oldLineIndex] = {\n type: 'context',\n lineNumber: oldLineNumber,\n altLineNumber: newLineNumber,\n lineIndex: `${unifiedLineIndex},${splitLineIndex}`,\n };\n newInfo[newLineIndex] = {\n type: 'context',\n lineNumber: newLineNumber,\n altLineNumber: oldLineNumber,\n lineIndex: `${unifiedLineIndex},${splitLineIndex}`,\n };\n oldContent += line;\n newContent += line;\n oldLineIndex++;\n newLineIndex++;\n newLineNumber++;\n oldLineNumber++;\n splitLineIndex++;\n unifiedLineIndex++;\n }\n } else {\n const len = Math.max(\n hunkContent.additions.length,\n hunkContent.deletions.length\n );\n let i = 0;\n // NOTE(amadeus): Since we iterate through deletions and additions\n // simultaneously, we have to create a secondary iterator for\n // unifiedLineIndex, and then when we're done, add the combined lengths\n // of additions/deletions to the main variable\n let _unifiedLineIndex = unifiedLineIndex;\n while (i < len) {\n const oldLine = hunkContent.deletions[i];\n const newLine = hunkContent.additions[i];\n computeLineDiffDecorations({\n newLine,\n oldLine,\n oldLineIndex,\n newLineIndex,\n oldDecorations,\n newDecorations,\n lineDiffType,\n });\n if (oldLine != null) {\n oldInfo[oldLineIndex] = {\n type: 'change-deletion',\n lineNumber: oldLineNumber,\n lineIndex: `${_unifiedLineIndex},${splitLineIndex}`,\n };\n oldContent += oldLine;\n oldLineIndex++;\n oldLineNumber++;\n }\n if (newLine != null) {\n newInfo[newLineIndex] = {\n type: 'change-addition',\n lineNumber: newLineNumber,\n lineIndex: `${_unifiedLineIndex + hunkContent.deletions.length},${splitLineIndex}`,\n };\n newContent += newLine;\n newLineIndex++;\n newLineNumber++;\n }\n splitLineIndex++;\n _unifiedLineIndex++;\n i++;\n }\n unifiedLineIndex +=\n hunkContent.additions.length + hunkContent.deletions.length;\n }\n }\n\n if (\n oldLines == null ||\n newLines == null ||\n hunk !== hunks[hunks.length - 1]\n )\n continue;\n // If we are on the last hunk, we should fully iterate through the rest\n // of the lines\n while (oldLineIndex <= oldLines.length || newLineIndex <= oldLines.length) {\n const oldLine = oldLines[oldLineIndex - 1];\n const newLine = newLines[newLineIndex - 1];\n if (oldLine == null && newLine == null) {\n break;\n }\n if (oldLine != null) {\n oldInfo[oldLineIndex] = {\n type: 'context-expanded',\n lineNumber: oldLineNumber,\n altLineNumber: newLineNumber,\n lineIndex: `${unifiedLineIndex},${splitLineIndex}`,\n };\n oldContent += oldLine;\n oldLineIndex++;\n oldLineNumber++;\n }\n if (newLine != null) {\n newInfo[newLineIndex] = {\n type: 'context-expanded',\n lineNumber: newLineNumber,\n altLineNumber: oldLineNumber,\n lineIndex: `${unifiedLineIndex},${splitLineIndex}`,\n };\n newContent += newLine;\n newLineIndex++;\n newLineNumber++;\n }\n splitLineIndex++;\n unifiedLineIndex++;\n }\n }\n return {\n oldContent: cleanLastNewline(oldContent),\n newContent: cleanLastNewline(newContent),\n oldInfo,\n newInfo,\n oldDecorations,\n newDecorations,\n splitLineIndex,\n unifiedLineIndex,\n };\n}\n\ninterface RenderTwoFilesProps {\n oldFile: FileContents;\n newFile: FileContents;\n oldInfo: Record<number, LineInfo | undefined>;\n newInfo: Record<number, LineInfo | undefined>;\n oldDecorations: DecorationItem[];\n newDecorations: DecorationItem[];\n options: RenderDiffOptions;\n highlighter: DiffsHighlighter;\n languageOverride: SupportedLanguages | undefined;\n}\n\nfunction renderTwoFiles({\n oldFile,\n newFile,\n oldInfo,\n newInfo,\n highlighter,\n oldDecorations,\n newDecorations,\n languageOverride,\n options: { theme: themeOrThemes = DEFAULT_THEMES, ...options },\n}: RenderTwoFilesProps) {\n const oldLang = languageOverride ?? getFiletypeFromFileName(oldFile.name);\n const newLang = languageOverride ?? getFiletypeFromFileName(newFile.name);\n const { state, transformers } = createTransformerWithState();\n const hastConfig: CodeToHastOptions<DiffsThemeNames> = (() => {\n return typeof themeOrThemes === 'string'\n ? {\n ...options,\n // language will be overwritten for each highlight\n lang: 'text',\n theme: themeOrThemes,\n transformers,\n decorations: undefined,\n defaultColor: false,\n cssVariablePrefix: formatCSSVariablePrefix(),\n }\n : {\n ...options,\n // language will be overwritten for each highlight\n lang: 'text',\n themes: themeOrThemes,\n transformers,\n decorations: undefined,\n defaultColor: false,\n cssVariablePrefix: formatCSSVariablePrefix(),\n };\n })();\n\n const oldLines = (() => {\n if (oldFile.contents === '') {\n return [];\n }\n hastConfig.lang = oldLang;\n state.lineInfo = oldInfo;\n hastConfig.decorations = oldDecorations;\n return getLineNodes(highlighter.codeToHast(oldFile.contents, hastConfig));\n })();\n const newLines = (() => {\n if (newFile.contents === '') {\n return [];\n }\n hastConfig.lang = newLang;\n hastConfig.decorations = newDecorations;\n state.lineInfo = newInfo;\n return getLineNodes(highlighter.codeToHast(newFile.contents, hastConfig));\n })();\n\n return { oldLines, newLines };\n}\n"],"mappings":"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"}
|