@davmash/bygone 0.8.14 → 0.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +40 -0
- package/README.md +2 -2
- package/cli/commandSpec.js +12 -2
- package/cli/completions.js +1 -1
- package/cli/present.js +89 -7
- package/cli/tour.js +13 -2
- package/cli/tourFile.js +9 -0
- package/cli/tourHistory.js +432 -0
- package/completions/_bygone +2 -1
- package/completions/bygone +1 -1
- package/completions/bygone.fish +1 -0
- package/docs/change-tour-format.md +199 -7
- package/docs/explore.md +21 -1
- package/docs/generating-change-tours.md +70 -17
- package/docs/present.md +134 -5
- package/docs/product-surface.md +64 -8
- package/docs/releasing.md +25 -29
- package/examples/bygone-history.bygone +52 -10
- package/examples/navigation-lab.bygone.yaml +420 -0
- package/media/diff.worker.js +3 -3
- package/media/webview.css +1 -1
- package/media/webview.js +546 -178
- package/out/changeTour.js +1391 -469
- package/out/gitComparison.js +354 -0
- package/out/standalone-main.js +13989 -4749
- package/out/tourCoverage.js +1434 -461
- package/package.json +2 -2
- package/schemas/change-tour-source.schema.json +222 -3
- package/skills/pr-tour-guide/SKILL.md +111 -11
- package/standalone/index.html +6 -1
- package/web/index.html +114 -73
- package/web/presenter.css +658 -230
- package/web/web-host.js +374 -5
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
version: 3
|
|
2
|
+
title: Navigation lab
|
|
3
|
+
windowTitle: Bygone navigation lab
|
|
4
|
+
range:
|
|
5
|
+
base: 1f8fdc07d56fc7a0e50dcab0383a63159c77178c
|
|
6
|
+
head: 901a193203e4840dbf6e06c6a273fac7f2d713bd
|
|
7
|
+
anchors:
|
|
8
|
+
path-host:
|
|
9
|
+
file: web/index.html
|
|
10
|
+
revision: head
|
|
11
|
+
contains: <nav id="tour-reading-path" class="tour-reading-path" aria-label="Reading hierarchy"></nav>
|
|
12
|
+
path-levels:
|
|
13
|
+
file: web/host.js
|
|
14
|
+
revision: head
|
|
15
|
+
contains: " if (tour.scenes.length > 1) levels.push(['tour', tour.title]);\n if (tour.chapters.length\
|
|
16
|
+
\ > 1 && chapter && (chapter.sceneIds.length > 1 || state.narrativeParent === 'chapter')) levels.push(['chapter',\
|
|
17
|
+
\ chapter.title]);\n levels.push(['scene', scene.title]);\n if (hasStep) levels.push(['step',\
|
|
18
|
+
\ `Step ${state.activeStepIndex + 1}`]);"
|
|
19
|
+
path-children:
|
|
20
|
+
file: web/host.js
|
|
21
|
+
revision: head
|
|
22
|
+
contains: " children.append(readingButton(item.title, `Read chapter: ${item.title}`,\
|
|
23
|
+
\ () => {\n if (!item.sceneIds.includes(scene.id)) showTourScene(first, 0,\
|
|
24
|
+
\ { userNavigation: true, showIntro: true });\n setNarrativeView(item.sceneIds.length\
|
|
25
|
+
\ > 1 ? 'chapter' : 'scene');\n }));"
|
|
26
|
+
remember-step:
|
|
27
|
+
file: web/host.js
|
|
28
|
+
revision: head
|
|
29
|
+
contains: " if (step) parameters.set('step', step.id);\n else parameters.delete('step');\n\
|
|
30
|
+
\ if (state.narrativeParent) parameters.set('view', state.narrativeParent);\n else\
|
|
31
|
+
\ if (step && state.sceneIntroVisible) parameters.set('view', 'overview');\n else parameters.delete('view');"
|
|
32
|
+
resume-parent:
|
|
33
|
+
file: web/host.js
|
|
34
|
+
revision: head
|
|
35
|
+
contains: " if (direction === 1 && state.narrativeParent) {\n showTourScene(state.activeSceneIndex,\
|
|
36
|
+
\ state.activeStepIndex, { userNavigation: true, showIntro: false });\n return true;\n\
|
|
37
|
+
\ }"
|
|
38
|
+
restore-parent:
|
|
39
|
+
file: web/host.js
|
|
40
|
+
revision: head
|
|
41
|
+
contains: ' if ([''tour'', ''chapter''].includes(parameters.get(''view''))) setNarrativeView(parameters.get(''view''));'
|
|
42
|
+
ignore-layout:
|
|
43
|
+
file: media/script.js
|
|
44
|
+
revision: head
|
|
45
|
+
contains: " if (suppressEditorEvents || (!event.scrollTopChanged && !event.scrollLeftChanged))\
|
|
46
|
+
\ {\n connectorController.scheduleDrawConnections();\n return;\n }"
|
|
47
|
+
keep-sync:
|
|
48
|
+
file: media/script.js
|
|
49
|
+
revision: head
|
|
50
|
+
contains: " if (editorMode === MODE_MULTI_WAY) {\n synchronizeMultiScroll(editor);\n\
|
|
51
|
+
\ } else {\n synchronizeEditorScroll(editor);\n }"
|
|
52
|
+
width-test:
|
|
53
|
+
file: test/runTests.js
|
|
54
|
+
revision: head
|
|
55
|
+
contains: " assert.deepEqual(\n invokeScrollHandler({ scrollTopChanged: false, scrollLeftChanged:\
|
|
56
|
+
\ false, scrollWidthChanged: true }),\n ['draw']\n );"
|
|
57
|
+
vertical-test:
|
|
58
|
+
file: test/runTests.js
|
|
59
|
+
revision: head
|
|
60
|
+
contains: " assert.deepEqual(\n invokeScrollHandler({ scrollTopChanged: true, scrollLeftChanged:\
|
|
61
|
+
\ false }),\n ['two-way-scroll', 'draw']\n );"
|
|
62
|
+
horizontal-test:
|
|
63
|
+
file: test/runTests.js
|
|
64
|
+
revision: head
|
|
65
|
+
contains: " assert.deepEqual(\n invokeScrollHandler({ scrollTopChanged: false, scrollLeftChanged:\
|
|
66
|
+
\ true }, 'multi-way'),\n ['multi-scroll', 'draw']\n );"
|
|
67
|
+
connections: []
|
|
68
|
+
chapters:
|
|
69
|
+
- id: reading
|
|
70
|
+
title: Reading levels
|
|
71
|
+
scenes:
|
|
72
|
+
- id: reading-path
|
|
73
|
+
overview:
|
|
74
|
+
kind: directory-diff
|
|
75
|
+
title: Explore the reading path
|
|
76
|
+
summary: The directory comparison shows the combined changes across this scene’s constructed stages. Open a file to inspect it, then select Overview above the diff to return; Start steps follows the explanation. Use the breadcrumb above this text to move through Tour, Chapter, Scene, and Step. The sidebar
|
|
77
|
+
provides a second route to the same content.
|
|
78
|
+
bullets: []
|
|
79
|
+
tags:
|
|
80
|
+
- navigation-demo
|
|
81
|
+
takeaway: Mode chooses the representation of the change; the breadcrumb chooses your reading depth
|
|
82
|
+
within it.
|
|
83
|
+
steps:
|
|
84
|
+
- id: path-host
|
|
85
|
+
title: Keep navigation beside narration
|
|
86
|
+
body: The reading path occupies the same toolbar as narration, so moving up a level does not require
|
|
87
|
+
opening another panel. Try hiding narration to give the path more room.
|
|
88
|
+
focus: path-host
|
|
89
|
+
- id: path-levels
|
|
90
|
+
title: Show levels with useful choices
|
|
91
|
+
body: This tour has two chapters with two scenes each, so every parent level appears. A smaller
|
|
92
|
+
tour omits levels that add no navigation choice.
|
|
93
|
+
focus: path-levels
|
|
94
|
+
- id: path-children
|
|
95
|
+
title: Let a parent show its children
|
|
96
|
+
body: Select the chapter title above to see its scenes, or select the tour title to see both chapters.
|
|
97
|
+
These buttons enter the selected chapter while keeping the current scene when it already belongs
|
|
98
|
+
there.
|
|
99
|
+
focus: path-children
|
|
100
|
+
kind: deconstructed-diff
|
|
101
|
+
base: 1f8fdc07d56fc7a0e50dcab0383a63159c77178c
|
|
102
|
+
target: 901a193203e4840dbf6e06c6a273fac7f2d713bd
|
|
103
|
+
stack:
|
|
104
|
+
- id: before
|
|
105
|
+
ref: 1f8fdc07d56fc7a0e50dcab0383a63159c77178c
|
|
106
|
+
label: Before hierarchy
|
|
107
|
+
- id: hierarchy
|
|
108
|
+
ref: a50c2a6f58a2dfd7f85039105a27e4b92b98a3f7
|
|
109
|
+
label: Hierarchy added
|
|
110
|
+
- id: marker
|
|
111
|
+
ref: 901a193203e4840dbf6e06c6a273fac7f2d713bd
|
|
112
|
+
label: Marker fix added
|
|
113
|
+
stages:
|
|
114
|
+
- id: surface
|
|
115
|
+
title: Place the reading controls
|
|
116
|
+
narration: Add the breadcrumb, parent container, child list, and their styling. These are synthetic
|
|
117
|
+
cumulative panels, not historical commits.
|
|
118
|
+
changes:
|
|
119
|
+
- file: web/index.html
|
|
120
|
+
hunks:
|
|
121
|
+
- hunk-2828c9627055
|
|
122
|
+
- hunk-68a3bdc9f262
|
|
123
|
+
- hunk-ad7073e10ed7
|
|
124
|
+
- file: web/presenter.css
|
|
125
|
+
hunks:
|
|
126
|
+
- hunk-3d4093808d4b
|
|
127
|
+
- id: navigation
|
|
128
|
+
title: Connect parents and return positions
|
|
129
|
+
narration: Wire the hierarchy to the selected scene and step, then document the reading behavior.
|
|
130
|
+
changes:
|
|
131
|
+
- file: docs/present.md
|
|
132
|
+
hunks:
|
|
133
|
+
- hunk-5b7f86aadb64
|
|
134
|
+
- hunk-635769fc5c13
|
|
135
|
+
- hunk-d3f94ec64c1f
|
|
136
|
+
- file: web/host.js
|
|
137
|
+
hunks:
|
|
138
|
+
- hunk-3bd48ca387ae
|
|
139
|
+
- hunk-069a2fee2f36
|
|
140
|
+
- hunk-e7def68037d5
|
|
141
|
+
- hunk-755dbc1b8067
|
|
142
|
+
- hunk-82249952520f
|
|
143
|
+
- hunk-db24a55e418e
|
|
144
|
+
- hunk-87209fb2e340
|
|
145
|
+
- hunk-5ebccafb6522
|
|
146
|
+
- hunk-b62a3aedf12b
|
|
147
|
+
- hunk-50d651bf7762
|
|
148
|
+
- hunk-3a1c863cc48a
|
|
149
|
+
- hunk-1d2fb5f32ab9
|
|
150
|
+
- hunk-df6ed3ebba70
|
|
151
|
+
- hunk-5106426d3c27
|
|
152
|
+
- hunk-8d0ffe62e5b7
|
|
153
|
+
- hunk-fc04b2890333
|
|
154
|
+
- id: focus
|
|
155
|
+
title: Protect the code marker
|
|
156
|
+
narration: Ignore layout-only scroll events so revealing a marker is not undone by panel resizing.
|
|
157
|
+
changes:
|
|
158
|
+
- file: media/script.js
|
|
159
|
+
hunks:
|
|
160
|
+
- hunk-636df0304da5
|
|
161
|
+
- id: proof
|
|
162
|
+
title: Check scrolling behavior
|
|
163
|
+
narration: Test that width-only changes redraw connectors while actual scrolling still synchronizes
|
|
164
|
+
editors.
|
|
165
|
+
changes:
|
|
166
|
+
- file: test/runTests.js
|
|
167
|
+
hunks:
|
|
168
|
+
- hunk-acbf72ffb0da
|
|
169
|
+
- hunk-c6c53c72b8b1
|
|
170
|
+
- id: return-position
|
|
171
|
+
title: Return without losing your place
|
|
172
|
+
summary: Move to a later step, select its scene or chapter in the breadcrumb, then use Resume. Refresh
|
|
173
|
+
the parent view to exercise the saved URL position.
|
|
174
|
+
bullets: []
|
|
175
|
+
tags:
|
|
176
|
+
- navigation-demo
|
|
177
|
+
takeaway: The reading level and the return step are separate pieces of state.
|
|
178
|
+
steps:
|
|
179
|
+
- id: remember-step
|
|
180
|
+
title: Keep your step ready to resume
|
|
181
|
+
body: Selecting a parent keeps your current step ready to resume. The URL preserves the step and
|
|
182
|
+
selected reading level, so refreshing restores both.
|
|
183
|
+
focus: remember-step
|
|
184
|
+
- id: resume-parent
|
|
185
|
+
title: Resume from a parent
|
|
186
|
+
body: Next from a parent returns to the remembered step instead of advancing past it. The button
|
|
187
|
+
label becomes Resume to make that behavior explicit.
|
|
188
|
+
focus: resume-parent
|
|
189
|
+
- id: restore-parent
|
|
190
|
+
title: Restore the parent after refresh
|
|
191
|
+
body: Loading the URL restores the selected tour or chapter view after establishing the saved scene
|
|
192
|
+
and step. Try refreshing while viewing this chapter.
|
|
193
|
+
focus: restore-parent
|
|
194
|
+
- id: evidence
|
|
195
|
+
title: Code focus
|
|
196
|
+
scenes:
|
|
197
|
+
- id: marker-focus
|
|
198
|
+
title: Keep the marker in view
|
|
199
|
+
summary: Panel layout changes can emit scroll events without a scroll-position change. The renderer
|
|
200
|
+
must not treat those events as reader navigation.
|
|
201
|
+
bullets: []
|
|
202
|
+
tags:
|
|
203
|
+
- navigation-demo
|
|
204
|
+
takeaway: The fix filters layout noise without disabling synchronized scrolling.
|
|
205
|
+
steps:
|
|
206
|
+
- id: ignore-layout
|
|
207
|
+
title: Ignore extent-only scroll events
|
|
208
|
+
body: The guard exits when neither vertical nor horizontal position changed. A panel-width change
|
|
209
|
+
therefore cannot synchronize an old position back into the focused editor.
|
|
210
|
+
focus: ignore-layout
|
|
211
|
+
- id: keep-sync
|
|
212
|
+
title: Continue synchronizing real scrolling
|
|
213
|
+
body: After the guard, actual scroll events still dispatch to the appropriate two-panel or multi-panel
|
|
214
|
+
synchronization path.
|
|
215
|
+
focus: keep-sync
|
|
216
|
+
- id: scroll-proof
|
|
217
|
+
title: Inspect the regression checks
|
|
218
|
+
summary: These tests invoke the renderer scroll callback with different event shapes. Use the Files
|
|
219
|
+
section to explore the complete change set, then return to the tour.
|
|
220
|
+
bullets: []
|
|
221
|
+
tags:
|
|
222
|
+
- navigation-demo
|
|
223
|
+
takeaway: Use the mode buttons to open either tour or live History. To inspect the final result without narration,
|
|
224
|
+
open Compare and choose Final diff.
|
|
225
|
+
steps:
|
|
226
|
+
- id: width-test
|
|
227
|
+
title: A width change only redraws
|
|
228
|
+
body: A width-only event must draw connectors without requesting either kind of synchronized scroll.
|
|
229
|
+
focus: width-test
|
|
230
|
+
- id: vertical-test
|
|
231
|
+
title: Vertical scrolling still synchronizes
|
|
232
|
+
body: A real vertical movement in a two-panel comparison still synchronizes and redraws.
|
|
233
|
+
focus: vertical-test
|
|
234
|
+
- id: horizontal-test
|
|
235
|
+
title: Multi-panel scrolling still synchronizes
|
|
236
|
+
body: A horizontal movement in multi-panel mode reaches the multi-panel synchronizer. This is callback
|
|
237
|
+
coverage; the panel-switch landing was also checked manually in the browser.
|
|
238
|
+
focus: horizontal-test
|
|
239
|
+
|
|
240
|
+
tours:
|
|
241
|
+
historical:
|
|
242
|
+
chapters:
|
|
243
|
+
- id: historical-reading
|
|
244
|
+
title: The hierarchy commit
|
|
245
|
+
scenes:
|
|
246
|
+
- id: hierarchy-revision
|
|
247
|
+
overview:
|
|
248
|
+
kind: directory-diff
|
|
249
|
+
path: web
|
|
250
|
+
comparison:
|
|
251
|
+
from: before
|
|
252
|
+
to: hierarchy
|
|
253
|
+
kind: stacked-diff
|
|
254
|
+
title: Add reading levels in a real commit
|
|
255
|
+
summary: >-
|
|
256
|
+
This overview compares the web directory before and after the hierarchy commit. Open a file without leaving the overview, or start the steps to see the real revision panels. Its changes to markup, styling, and
|
|
257
|
+
navigation landed together; they are split into conceptual stages only in
|
|
258
|
+
Deconstructed tour.
|
|
259
|
+
bullets: []
|
|
260
|
+
tags:
|
|
261
|
+
- real-revisions
|
|
262
|
+
- navigation-demo
|
|
263
|
+
takeaway: >-
|
|
264
|
+
Historical tour keeps the real commit boundaries, even when one commit contains
|
|
265
|
+
several concepts.
|
|
266
|
+
stack:
|
|
267
|
+
- id: before
|
|
268
|
+
ref: 1f8fdc07d56fc7a0e50dcab0383a63159c77178c
|
|
269
|
+
label: Before hierarchy
|
|
270
|
+
- id: hierarchy
|
|
271
|
+
ref: a50c2a6f58a2dfd7f85039105a27e4b92b98a3f7
|
|
272
|
+
label: Hierarchy added
|
|
273
|
+
- id: marker
|
|
274
|
+
ref: 901a193203e4840dbf6e06c6a273fac7f2d713bd
|
|
275
|
+
label: Marker fix added
|
|
276
|
+
files:
|
|
277
|
+
- web/index.html
|
|
278
|
+
- web/host.js
|
|
279
|
+
- web/presenter.css
|
|
280
|
+
steps:
|
|
281
|
+
- id: historical-markup
|
|
282
|
+
title: Give the hierarchy a home
|
|
283
|
+
body: >-
|
|
284
|
+
The hierarchy commit adds the reading path and parent-view containers to the
|
|
285
|
+
presenter. This is the same committed markup shown in the synthetic surface stage,
|
|
286
|
+
now in its original revision context.
|
|
287
|
+
file: web/index.html
|
|
288
|
+
pair:
|
|
289
|
+
- before
|
|
290
|
+
- hierarchy
|
|
291
|
+
side: right
|
|
292
|
+
- id: historical-behavior
|
|
293
|
+
title: Connect the reading levels
|
|
294
|
+
body: >-
|
|
295
|
+
The same commit wires parent navigation and return positions in the host. The
|
|
296
|
+
hierarchy was introduced as a coherent UI change, rather than as separate Git
|
|
297
|
+
commits for each explanation stage.
|
|
298
|
+
file: web/host.js
|
|
299
|
+
pair:
|
|
300
|
+
- before
|
|
301
|
+
- hierarchy
|
|
302
|
+
side: right
|
|
303
|
+
- id: historical-style
|
|
304
|
+
title: Style the parent choices
|
|
305
|
+
body: >-
|
|
306
|
+
The reading controls and child choices receive their layout in this commit as
|
|
307
|
+
well. Change modes to Deconstructed to inspect those changes in a different
|
|
308
|
+
teaching order.
|
|
309
|
+
file: web/presenter.css
|
|
310
|
+
pair:
|
|
311
|
+
- before
|
|
312
|
+
- hierarchy
|
|
313
|
+
side: right
|
|
314
|
+
- id: historical-return
|
|
315
|
+
title: Return without losing your place
|
|
316
|
+
summary: >-
|
|
317
|
+
Move to a later step, select its scene or chapter in the breadcrumb, then use Resume.
|
|
318
|
+
Refresh the parent view to exercise the saved URL position.
|
|
319
|
+
bullets: []
|
|
320
|
+
tags:
|
|
321
|
+
- navigation-demo
|
|
322
|
+
takeaway: The reading level and the return step are separate pieces of state.
|
|
323
|
+
steps:
|
|
324
|
+
- id: remember-step
|
|
325
|
+
title: Keep your step ready to resume
|
|
326
|
+
body: >-
|
|
327
|
+
Selecting a parent keeps your current step ready to resume. The URL preserves the step and
|
|
328
|
+
selected reading level, so refreshing restores both.
|
|
329
|
+
focus: remember-step
|
|
330
|
+
- id: resume-parent
|
|
331
|
+
title: Resume from a parent
|
|
332
|
+
body: >-
|
|
333
|
+
Next from a parent returns to the remembered step instead of advancing past it.
|
|
334
|
+
The button label becomes Resume to make that behavior explicit.
|
|
335
|
+
focus: resume-parent
|
|
336
|
+
- id: restore-parent
|
|
337
|
+
title: Restore the parent after refresh
|
|
338
|
+
body: >-
|
|
339
|
+
Loading the URL restores the selected tour or chapter view after establishing the
|
|
340
|
+
saved scene and step. Try refreshing while viewing this chapter.
|
|
341
|
+
focus: restore-parent
|
|
342
|
+
- id: historical-correction
|
|
343
|
+
title: The follow-up correction
|
|
344
|
+
scenes:
|
|
345
|
+
- id: marker-revision
|
|
346
|
+
kind: stacked-diff
|
|
347
|
+
title: Fix marker focus after the hierarchy change
|
|
348
|
+
summary: >-
|
|
349
|
+
The last panel is a separate follow-up commit. It changes scroll-event handling and
|
|
350
|
+
adds regression assertions; it does not rewrite the earlier hierarchy implementation.
|
|
351
|
+
bullets: []
|
|
352
|
+
tags:
|
|
353
|
+
- real-revisions
|
|
354
|
+
- navigation-demo
|
|
355
|
+
takeaway: The later commit repairs code focus while retaining the new reading hierarchy.
|
|
356
|
+
stack:
|
|
357
|
+
- id: before
|
|
358
|
+
ref: 1f8fdc07d56fc7a0e50dcab0383a63159c77178c
|
|
359
|
+
label: Before hierarchy
|
|
360
|
+
- id: hierarchy
|
|
361
|
+
ref: a50c2a6f58a2dfd7f85039105a27e4b92b98a3f7
|
|
362
|
+
label: Hierarchy added
|
|
363
|
+
- id: marker
|
|
364
|
+
ref: 901a193203e4840dbf6e06c6a273fac7f2d713bd
|
|
365
|
+
label: Marker fix added
|
|
366
|
+
files:
|
|
367
|
+
- media/script.js
|
|
368
|
+
- test/runTests.js
|
|
369
|
+
steps:
|
|
370
|
+
- id: historical-marker
|
|
371
|
+
title: Ignore layout-only scroll events
|
|
372
|
+
body: >-
|
|
373
|
+
Panel resizing can emit scroll events without moving either scroll position. This
|
|
374
|
+
revision redraws connections and returns early for those events, preserving the
|
|
375
|
+
tour marker focus.
|
|
376
|
+
file: media/script.js
|
|
377
|
+
pair:
|
|
378
|
+
- hierarchy
|
|
379
|
+
- marker
|
|
380
|
+
side: right
|
|
381
|
+
- id: historical-proof
|
|
382
|
+
title: Keep actual scrolling synchronized
|
|
383
|
+
body: >-
|
|
384
|
+
The follow-up includes assertions for width-only events and real vertical or
|
|
385
|
+
horizontal scrolling. These checks distinguish a layout update from a user scroll
|
|
386
|
+
that must still synchronize editors.
|
|
387
|
+
file: test/runTests.js
|
|
388
|
+
pair:
|
|
389
|
+
- hierarchy
|
|
390
|
+
- marker
|
|
391
|
+
side: right
|
|
392
|
+
- id: historical-checks
|
|
393
|
+
title: Inspect the regression checks
|
|
394
|
+
summary: >-
|
|
395
|
+
These tests invoke the renderer scroll callback with different event shapes. Use the
|
|
396
|
+
Files section to explore the complete change set, then return to the tour.
|
|
397
|
+
bullets: []
|
|
398
|
+
tags:
|
|
399
|
+
- navigation-demo
|
|
400
|
+
takeaway: >-
|
|
401
|
+
Use the mode buttons to open either tour or live History. To inspect the final result without
|
|
402
|
+
narration, open Compare and choose Final diff.
|
|
403
|
+
steps:
|
|
404
|
+
- id: width-test
|
|
405
|
+
title: A width change only redraws
|
|
406
|
+
body: >-
|
|
407
|
+
A width-only event must draw connectors without requesting either kind of
|
|
408
|
+
synchronized scroll.
|
|
409
|
+
focus: width-test
|
|
410
|
+
- id: vertical-test
|
|
411
|
+
title: Vertical scrolling still synchronizes
|
|
412
|
+
body: A real vertical movement in a two-panel comparison still synchronizes and redraws.
|
|
413
|
+
focus: vertical-test
|
|
414
|
+
- id: horizontal-test
|
|
415
|
+
title: Multi-panel scrolling still synchronizes
|
|
416
|
+
body: >-
|
|
417
|
+
A horizontal movement in multi-panel mode reaches the multi-panel synchronizer.
|
|
418
|
+
This is callback coverage; the panel-switch landing was also checked manually in
|
|
419
|
+
the browser.
|
|
420
|
+
focus: horizontal-test
|
package/media/diff.worker.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
"use strict";(()=>{function
|
|
2
|
-
`));var e=[],t=n.split(/(\n|\r\n)/);t[t.length-1]||t.pop();for(var r=0;r<t.length;r++){var o=t[r];r%2&&!this.options.newlineIsToken?e[e.length-1]+=o:(this.options.ignoreWhitespace&&(o=o.trim()),e.push(o))}return e};var
|
|
1
|
+
"use strict";(()=>{function E(){}E.prototype={diff:function(e,t){var r,o=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{},i=o.callback;typeof o=="function"&&(i=o,o={}),this.options=o;var l=this;function a(v){return i?(setTimeout(function(){i(void 0,v)},0),!0):v}e=this.castInput(e),t=this.castInput(t),e=this.removeEmpty(this.tokenize(e)),t=this.removeEmpty(this.tokenize(t));var c=t.length,f=e.length,s=1,u=c+f;o.maxEditLength&&(u=Math.min(u,o.maxEditLength));var m=(r=o.timeout)!==null&&r!==void 0?r:1/0,L=Date.now()+m,w=[{oldPos:-1,lastComponent:void 0}],g=this.extractCommon(w[0],t,e,0);if(w[0].oldPos+1>=f&&g+1>=c)return a([{value:this.join(t),count:t.length}]);var d=-1/0,p=1/0;function h(){for(var v=Math.max(d,-s);v<=Math.min(p,s);v+=2){var x=void 0,y=w[v-1],A=w[v+1];y&&(w[v-1]=void 0);var R=!1;if(A){var V=A.oldPos-v;R=A&&0<=V&&V<c}var J=y&&y.oldPos+1<f;if(!R&&!J){w[v]=void 0;continue}if(!J||R&&y.oldPos+1<A.oldPos?x=l.addToPath(A,!0,void 0,0):x=l.addToPath(y,void 0,!0,1),g=l.extractCommon(x,t,e,v),x.oldPos+1>=f&&g+1>=c)return a(Ne(l,x.lastComponent,t,e,l.useLongestToken));w[v]=x,x.oldPos+1>=f&&(p=Math.min(p,v-1)),g+1>=c&&(d=Math.max(d,v+1))}s++}if(i)(function v(){setTimeout(function(){if(s>u||Date.now()>L)return i();h()||v()},0)})();else for(;s<=u&&Date.now()<=L;){var b=h();if(b)return b}},addToPath:function(e,t,r,o){var i=e.lastComponent;return i&&i.added===t&&i.removed===r?{oldPos:e.oldPos+o,lastComponent:{count:i.count+1,added:t,removed:r,previousComponent:i.previousComponent}}:{oldPos:e.oldPos+o,lastComponent:{count:1,added:t,removed:r,previousComponent:i}}},extractCommon:function(e,t,r,o){for(var i=t.length,l=r.length,a=e.oldPos,c=a-o,f=0;c+1<i&&a+1<l&&this.equals(t[c+1],r[a+1]);)c++,a++,f++;return f&&(e.lastComponent={count:f,previousComponent:e.lastComponent}),e.oldPos=a,c},equals:function(e,t){return this.options.comparator?this.options.comparator(e,t):e===t||this.options.ignoreCase&&e.toLowerCase()===t.toLowerCase()},removeEmpty:function(e){for(var t=[],r=0;r<e.length;r++)e[r]&&t.push(e[r]);return t},castInput:function(e){return e},tokenize:function(e){return e.split("")},join:function(e){return e.join("")}};function Ne(n,e,t,r,o){for(var i=[],l;e;)i.push(e),l=e.previousComponent,delete e.previousComponent,e=l;i.reverse();for(var a=0,c=i.length,f=0,s=0;a<c;a++){var u=i[a];if(u.removed){if(u.value=n.join(r.slice(s,s+u.count)),s+=u.count,a&&i[a-1].added){var L=i[a-1];i[a-1]=i[a],i[a]=L}}else{if(!u.added&&o){var m=t.slice(f,f+u.count);m=m.map(function(g,d){var p=r[s+d];return p.length>g.length?p:g}),u.value=n.join(m)}else u.value=n.join(t.slice(f,f+u.count));f+=u.count,u.added||(s+=u.count)}}var w=i[c-1];return c>1&&typeof w.value=="string"&&(w.added||w.removed)&&n.equals("",w.value)&&(i[c-2].value+=w.value,i.pop()),i}var Ie=new E;function Q(n,e,t){return Ie.diff(n,e,t)}var j=/^[A-Za-z\xC0-\u02C6\u02C8-\u02D7\u02DE-\u02FF\u1E00-\u1EFF]+$/,Z=/\S/,P=new E;P.equals=function(n,e){return this.options.ignoreCase&&(n=n.toLowerCase(),e=e.toLowerCase()),n===e||this.options.ignoreWhitespace&&!Z.test(n)&&!Z.test(e)};P.tokenize=function(n){for(var e=n.split(/([^\S\r\n]+|[()[\]{}'"\r\n]|\b)/),t=0;t<e.length-1;t++)!e[t+1]&&e[t+2]&&j.test(e[t])&&j.test(e[t+2])&&(e[t]+=e[t+2],e.splice(t+1,2),t--);return e};function ee(n,e,t){return P.diff(n,e,t)}var ne=new E;ne.tokenize=function(n){this.options.stripTrailingCr&&(n=n.replace(/\r\n/g,`
|
|
2
|
+
`));var e=[],t=n.split(/(\n|\r\n)/);t[t.length-1]||t.pop();for(var r=0;r<t.length;r++){var o=t[r];r%2&&!this.options.newlineIsToken?e[e.length-1]+=o:(this.options.ignoreWhitespace&&(o=o.trim()),e.push(o))}return e};var Se=new E;Se.tokenize=function(n){return n.split(/(\S.+?[.!?])(?=\s+|$)/)};var Ee=new E;Ee.tokenize=function(n){return n.split(/([{}:;,]|\s+)/)};function F(n){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?F=function(e){return typeof e}:F=function(e){return e&&typeof Symbol=="function"&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},F(n)}var Ae=Object.prototype.toString,D=new E;D.useLongestToken=!0;D.tokenize=ne.tokenize;D.castInput=function(n){var e=this.options,t=e.undefinedReplacement,r=e.stringifyReplacer,o=r===void 0?function(i,l){return typeof l>"u"?t:l}:r;return typeof n=="string"?n:JSON.stringify(B(n,null,null,o),o," ")};D.equals=function(n,e){return E.prototype.equals.call(D,n.replace(/,([\r\n])/g,"$1"),e.replace(/,([\r\n])/g,"$1"))};function B(n,e,t,r,o){e=e||[],t=t||[],r&&(n=r(o,n));var i;for(i=0;i<e.length;i+=1)if(e[i]===n)return t[i];var l;if(Ae.call(n)==="[object Array]"){for(e.push(n),l=new Array(n.length),t.push(l),i=0;i<n.length;i+=1)l[i]=B(n[i],e,t,r,o);return e.pop(),t.pop(),l}if(n&&n.toJSON&&(n=n.toJSON()),F(n)==="object"&&n!==null){e.push(n),l={},t.push(l);var a=[],c;for(c in n)n.hasOwnProperty(c)&&a.push(c);for(a.sort(),i=0;i<a.length;i+=1)c=a[i],l[c]=B(n[c],e,t,r,c);e.pop(),t.pop()}else l=n;return l}var H=new E;H.tokenize=function(n){return n.slice()};H.join=H.removeEmpty=function(n){return n};function te(n,e,t){return H.diff(n,e,t)}var Te=500,Re=100,re=ye("BYGONE_MAX_INLINE_HIGHLIGHT_LINE_LENGTH",Te),De=ye("BYGONE_DIFF_TIMEOUT_MS",Re);function me(n,e,t={}){let r=ie(n),o=ie(e);if(n===e)return _e(r);let i=Ce(r,o),l=te(i.left,i.right,{timeout:t.timeoutMs??De});if(!l)return Oe(r,o);let a=l.map(g=>({...g,value:g.value.map(d=>i.lines[d])})),c=[],f=[],s=[],u=[],m=1,L=1;for(let g=0;g<a.length;g++){let d=a[g],p=d.removed?d.value:[],h=d.added?d.value:[];if(!d.added&&!d.removed){for(let b of d.value)f.push(I("context",b,m)),s.push(I("context",b,L)),c.push(M(N("context",b,m++),N("context",b,L++)));continue}if(d.removed&&g+1<a.length&&a[g+1].added){let b=a[g+1],v=Fe(p,b.value,m,L,c,f,s,u);m=v.left,L=v.right,g++;continue}if(d.removed){let b=f.length,v=s.length;for(let x of p)f.push(I("removed",x,m)),c.push(M(N("removed",x,m++),T()));u.push(z("delete",b,f.length,v,s.length));continue}if(d.added){let b=f.length,v=s.length;for(let x of h)s.push(I("added",x,L)),c.push(M(T(),N("added",x,L++)));u.push(z("insert",b,f.length,v,s.length))}}let w=c.some(g=>g.left.kind!=="context"||g.right.kind!=="context");return{rows:c,leftLines:f,rightLines:s,blocks:u,hasChanges:w,quality:"exact"}}function Ce(n,e){let t=new Map,r=[],o=i=>{let l=t.get(i);if(l!==void 0)return l;let a=r.length;return t.set(i,a),r.push(i),a};return{left:n.map(o),right:e.map(o),lines:r}}function _e(n){return{rows:n.map((e,t)=>M(N("context",e,t+1),N("context",e,t+1))),leftLines:n.map((e,t)=>I("context",e,t+1)),rightLines:n.map((e,t)=>I("context",e,t+1)),blocks:[],hasChanges:!1,quality:"exact"}}function Oe(n,e){let t=n.map((l,a)=>I("removed",l,a+1)),r=e.map((l,a)=>I("added",l,a+1)),o=[...n.map((l,a)=>M(N("removed",l,a+1),T())),...e.map((l,a)=>M(T(),N("added",l,a+1)))],i="replace";return n.length===0?i="insert":e.length===0&&(i="delete"),{rows:o,leftLines:t,rightLines:r,blocks:o.length===0?[]:[z(i,0,n.length,0,e.length)],hasChanges:o.length>0,quality:"fallback"}}function ie(n){if(n.length===0)return[];let e=n.replace(/\r\n/g,`
|
|
3
3
|
`).split(`
|
|
4
|
-
`);return e[e.length-1]===""&&e.pop(),e}var pe=1e4,ie=2e3,Te=.52,De=.35,he=.38,Ce=.33,me=.86,G=.08,O=.05,H=-.12,oe=5e3,_e=2e3,se=4,Fe=8,z=4;function ve(n,e){if(n.length===0)return e.map(s=>({right:s}));if(e.length===0)return n.map(s=>({left:s}));if(n.length===1&&e.length===1){let s=Y(n[0],e[0]);return(s.eligible||s.score>=De)&&B(n[0],e[0])&&C(M(n[0]))&&C(M(e[0]))?[{left:n[0],right:e[0]}]:[{left:n[0]},{right:e[0]}]}if(n.length*e.length>pe)return Ge(n,e);let t=Oe(n,e),r=Array.from({length:n.length+1},()=>new Array(e.length+1).fill(Number.NEGATIVE_INFINITY)),o=Array.from({length:n.length+1},()=>new Array(e.length+1).fill(null));r[0][0]=0;for(let s=1;s<=n.length;s++)r[s][0]=r[s-1][0]+H,o[s][0]="left";for(let s=1;s<=e.length;s++)r[0][s]=r[0][s-1]+H,o[0][s]="right";for(let s=1;s<=n.length;s++)for(let f=1;f<=e.length;f++){let c=t[s-1][f-1],v=[{move:"left",score:r[s-1][f]+H},{move:"right",score:r[s][f-1]+H},{move:"match",score:c===null?Number.NEGATIVE_INFINITY:r[s-1][f-1]+c}].reduce((b,m)=>m.score>b.score?m:b);r[s][f]=v.score,o[s][f]=v.move}let i=[],l=n.length,a=e.length;for(;l>0||a>0;){let s=o[l][a];s==="match"?i.push({left:n[--l],right:e[--a]}):s==="left"?i.push({left:n[--l]}):i.push({right:e[--a]})}return i.reverse()}function Y(n,e){let t=M(n),r=M(e),o=C(t),i=C(r);if(!o||!i||t.length>ie||r.length>ie)return{score:0,eligible:!1,characterSimilarity:0,tokenSimilarity:0,lengthSimilarity:0};if(t===r)return{score:1,eligible:!0,characterSimilarity:1,tokenSimilarity:1,lengthSimilarity:1};let l=q(t),a=q(r),s=Ye(t,r),f=Xe(l,a),c=Math.min(t.length,r.length)/Math.max(t.length,r.length),u=qe(l,a),v=s*.52+f*.32+c*.1+u*.06,b=s>=.52||f>=.45||s>=.48&&f>=.28;return{score:v,eligible:b&&v>=Te,characterSimilarity:s,tokenSimilarity:f,lengthSimilarity:c}}function Oe(n,e){let t=n.map(p=>e.map(g=>Y(p,g))),r=be(n,e),o=t.map(p=>P(p)),i=e.map((p,g)=>P(t.map(d=>d[g]))),l=t.map((p,g)=>p.map((d,h)=>{if(r.has(`${g}:${h}`))return Math.max(d.score,1);if(!d.eligible)return null;let w=o[g],L=i[h],x=d.score===w.best&&d.score===L.best,y=d.score>=me?G/2:G,I=w.best-w.second>=y,N=L.best-L.second>=y;return x&&I&&N?d.score:null}));if(Math.max(n.length,e.length)>Fe||Math.abs(n.length-e.length)>z)return l;let a=(p,g,d)=>p.score>=he&&B(n[g],e[d])&&Math.abs(g-d)<=z,s=t.map((p,g)=>W(p,(d,h)=>a(d,g,h))),f=e.map((p,g)=>W(t.map(d=>d[g]),(d,h)=>a(d,h,g))),c=(p,g,d)=>p.score>=Ce&&B(n[g],e[d])&&Math.abs(g-d)<=z,u=t.map((p,g)=>W(p,(d,h)=>c(d,g,h))),v=e.map((p,g)=>W(t.map(d=>d[g]),(d,h)=>c(d,h,g))),b=(p,g)=>{let d=t[p][g];if(!a(d,p,g))return!1;let h=s[p],w=f[g];return d.score===h.best&&d.score===w.best&&h.best-h.second>=O&&w.best-w.second>=O},m=(p,g)=>{let d=t[p][g];if(!c(d,p,g))return!1;let h=u[p],w=v[g];return d.score===h.best&&d.score===w.best&&h.best-h.second>=O&&w.best-w.second>=O};return l.map((p,g)=>p.map((d,h)=>{if(d!==null)return d;let w=b(g,h)&&(He(l,g,h)||We(t,g,h,b)),L=ke(t,g,h,(x,y)=>c(t[x][y],x,y),m);return!w&&!L?null:t[g][h].score}))}function He(n,e,t){return e>0&&t>0&&n[e-1][t-1]!==null||e+1<n.length&&t+1<n[e+1].length&&n[e+1][t+1]!==null}function We(n,e,t,r){return e>0&&t>0&&r(e-1,t-1)||e+1<n.length&&t+1<n[e+1].length&&r(e+1,t+1)}function ke(n,e,t,r,o){let i=e,l=t;for(;i>0&&l>0&&r(i-1,l-1);)i--,l--;let a=e,s=t,f=n[e][t].score,c=1;for(;a+1<n.length&&s+1<n[a+1].length&&r(a+1,s+1);)a++,s++,f+=n[a][s].score,c++;for(let u=e-1,v=t-1;u>=i&&v>=l;u--,v--)f+=n[u][v].score,c++;return c>=3&&f/c>=he&&o(i,l)&&o(a,s)}function W(n,e){let t=Number.NEGATIVE_INFINITY,r=Number.NEGATIVE_INFINITY;return n.forEach((o,i)=>{e(o,i)&&(o.score>t?(r=t,t=o.score):o.score>r&&(r=o.score))}),{best:t,second:r}}function P(n){let e=Number.NEGATIVE_INFINITY,t=Number.NEGATIVE_INFINITY;for(let r of n)r.eligible&&(r.score>e?(t=e,e=r.score):r.score>t&&(t=r.score));return{best:e,second:t}}function Ge(n,e){let t=$e(n,e),r=[],o=0,i=0;for(let l of t)ce(r,n.slice(o,l.leftIndex),e.slice(i,l.rightIndex)),r.push({left:n[l.leftIndex],right:e[l.rightIndex]}),o=l.leftIndex+1,i=l.rightIndex+1;return ce(r,n.slice(o),e.slice(i)),r}function $e(n,e){let t=Ue(n,e);if(t===null)return[];let r=be(n,e),o=t.map(({leftIndex:f,rightIndex:c,exact:u})=>({leftIndex:f,rightIndex:c,exact:u,structural:r.has(`${f}:${c}`),match:Y(n[f],e[c])})).filter(f=>f.exact||f.structural||f.match.eligible),i=ae(o,"leftIndex"),l=ae(o,"rightIndex"),a=o.filter(f=>{if(f.exact||f.structural)return!0;let c=i.get(f.leftIndex),u=l.get(f.rightIndex);if(!c||!u||f.match.score!==c.best||f.match.score!==u.best)return!1;let v=f.match.score>=me?G/2:G;return c.best-c.second>=v&&u.best-u.second>=v}),s=Pe(a,e.length);return s.length<=_e?s:[]}function Ue(n,e){let t=le(n,M),r=le(e,M),o=new Map;for(let[a,s]of t){let f=r.get(a);if(!C(a)||s.length!==1||f?.length!==1)continue;let c=s[0],u=f[0];if(o.set(`${c}:${u}`,{leftIndex:c,rightIndex:u,exact:!0}),o.size>oe)return null}let i=fe(n),l=fe(e);for(let[a,s]of i){let f=l.get(a);if(!(!f||s.length>se||f.length>se))for(let c of s)for(let u of f){let v=`${c}:${u}`;if(!o.has(v)&&(o.set(v,{leftIndex:c,rightIndex:u,exact:!1}),o.size>oe))return null}}return[...o.values()]}function le(n,e){let t=new Map;return n.forEach((r,o)=>{let i=e(r),l=t.get(i)??[];l.push(o),t.set(i,l)}),t}function fe(n){let e=new Map;return n.forEach((t,r)=>{let o=new Set(q(M(t)).filter(ze));for(let i of o){let l=e.get(i)??[];l.push(r),e.set(i,l)}}),e}function ze(n){return n.length>=2&&/[\p{L}\p{N}_$]/u.test(n)}function ae(n,e){let t=new Map;for(let r of n){let o=t.get(r[e])??[];o.push(r.match),t.set(r[e],o)}return new Map([...t].map(([r,o])=>[r,P(o)]))}function Pe(n,e){let t=[...n].sort((f,c)=>f.leftIndex-c.leftIndex||f.rightIndex-c.rightIndex),r=new Array(e+2).fill(0),o=new Array(e+2).fill(-1),i=new Array(t.length).fill(0),l=new Array(t.length).fill(-1);for(let f=0;f<t.length;){let c=f+1;for(;c<t.length&&t[c].leftIndex===t[f].leftIndex;)c++;for(let u=f;u<c;u++){let v=ue(r,o,t[u].rightIndex),b=t[u].exact||t[u].structural?.5:0;i[u]=v.score+t[u].match.score+b,l[u]=v.candidateIndex}for(let u=f;u<c;u++)Be(r,o,t[u].rightIndex+1,i[u],u);f=c}let a=ue(r,o,e+1),s=[];for(let f=a.candidateIndex;f>=0;f=l[f])s.push({leftIndex:t[f].leftIndex,rightIndex:t[f].rightIndex});return s.reverse()}function ue(n,e,t){let r=0,o=-1;for(let i=t;i>0;i-=i&-i)n[i]>r&&(r=n[i],o=e[i]);return{score:r,candidateIndex:o}}function Be(n,e,t,r,o){for(let i=t;i<n.length;i+=i&-i)r>n[i]&&(n[i]=r,e[i]=o)}function ce(n,e,t){if(e.length*t.length<=pe){n.push(...ve(e,t));return}n.push(...e.map(r=>({left:r}))),n.push(...t.map(r=>({right:r})))}function M(n){return n.trim().replace(/\s+/g," ")}function be(n,e){let t=de(n),r=de(e),o=new Set;for(let[i,l]of t){let a=r.get(i);l.length===1&&a?.length===1&&o.add(`${l[0]}:${a[0]}`)}return o}function de(n){let e=new Map;return n.forEach((t,r)=>{let o=X(t);if(!o)return;let i=e.get(o)??[];i.push(r),e.set(o,i)}),e}function B(n,e){let t=X(n),r=X(e);return!t||!r?t===r:t.split(":",1)[0]===r.split(":",1)[0]}function X(n){let e=M(n),t=[["function",/^(?:(?:export|default)\s+)*(?:async\s+)?function\s*\*?\s*([\p{L}_$][\p{L}\p{N}_$]*)\s*\(/u],["function",/^(?:async\s+)?def\s+([\p{L}_][\p{L}\p{N}_]*)\s*\(/u],["function",/^(?:pub(?:\([^)]*\))?\s+)?(?:async\s+)?fn\s+([\p{L}_][\p{L}\p{N}_]*)\s*(?:<[^>]*>)?\s*\(/u],["function",/^func\s+(?:\([^)]*\)\s*)?([\p{L}_][\p{L}\p{N}_]*)\s*\(/u],["class",/^(?:(?:export|default|abstract|public)\s+)*class\s+([\p{L}_$][\p{L}\p{N}_$]*)\b/u]];for(let[r,o]of t){let i=e.match(o);if(i)return`${r}:${i[1]}`}return null}function C(n){return n.length<3?!1:/[\p{L}\p{N}_$]/u.test(n)&&!/^[\s()[\]{};,.:+\-*/=>|&!?'"`]+$/.test(n)}function q(n){return n.toLowerCase().match(/[\p{L}_$][\p{L}\p{N}_$]*|\p{N}+(?:\.\p{N}+)?|[^\s\p{L}\p{N}_$]/gu)??[]}function Xe(n,e){if(n.length+e.length===0)return 1;let t=new Map;n.forEach(o=>t.set(o,(t.get(o)??0)+1));let r=0;for(let o of e){let i=t.get(o)??0;i>0&&(r++,t.set(o,i-1))}return 2*r/(n.length+e.length)}function qe(n,e){if(n.length===0||e.length===0)return 0;let t=n[0]===e[0]?.5:0,r=n[n.length-1]===e[e.length-1]?.5:0;return t+r}function Ye(n,e){let t=n.length+e.length;return t===0?1:2*Z(n,e).filter(o=>!o.added&&!o.removed).reduce((o,i)=>o+i.value.length,0)/t}function Ve(n,e){if(n.content.length>te||e.content.length>te)return;let{leftSegments:t,rightSegments:r,hasInlineChanges:o}=Ke(n.content,e.content);o&&(n.segments=t,e.segments=r)}function Ke(n,e){let t=Q(n,e),r=[],o=[],i=!1;for(let l of t){let a=l.value;if(!l.added&&!l.removed){let f={kind:"context",text:a,emphasis:!1};r.push(f),o.push(f);continue}let s=/[^\s]/.test(a);i=i||s,l.removed&&r.push({kind:"removed",text:a,emphasis:s}),l.added&&o.push({kind:"added",text:a,emphasis:s})}return{leftSegments:r,rightSegments:o,hasInlineChanges:i}}function R(){return{kind:"placeholder",content:"",lineNumber:null}}function E(n,e,t){return{kind:n,content:e,lineNumber:t}}function A(n,e,t){return{kind:n,content:e,lineNumber:t}}function T(n,e){return{left:n,right:e}}function k(n,e,t,r,o){return{kind:n,leftStart:e,leftEnd:t,rightStart:r,rightEnd:o}}function we(n,e){let t=typeof process<"u"?process.env?.[n]:void 0,r=Number.parseInt(t??"",10);return Number.isFinite(r)&&r>0?r:e}self.addEventListener("message",n=>{let{id:e,leftContent:t,rightContent:r}=n.data||{};if(!(typeof e!="number"||typeof t!="string"||typeof r!="string"))try{let o=ge(t,r);self.postMessage({id:e,model:o})}catch(o){self.postMessage({id:e,error:o&&o.message||String(o)})}});})();
|
|
4
|
+
`);return e[e.length-1]===""&&e.pop(),e}function Fe(n,e,t,r,o,i,l,a){let c=xe(n,e),f=c.filter(h=>h.left!==void 0&&h.right!==void 0&&X(h.left,h.right)).length,s=ke(n,e,f),u=c.flatMap(h=>h.left===void 0||h.right===void 0||X(h.left,h.right)?[h]:[{left:h.left},{right:h.right}]),m=t,L=r,w,g=i.length,d=l.length,p=()=>{w&&a.push(z(w,g,i.length,d,l.length))};for(let{left:h,right:b}of u){let v=s||h!==void 0&&b!==void 0?"replace":h!==void 0?"delete":"insert";w!==v&&(p(),w=v,g=i.length,d=l.length);let x,y;h!==void 0&&(x=I("removed",h,m),i.push(x)),b!==void 0&&(y=I("added",b,L),l.push(y)),x&&y?on(x,y):s&&(x&&he(x),y&&he(y)),o.push(M(h===void 0?T():N("removed",h,m++),b===void 0?T():N("added",b,L++)))}return p(),{left:m,right:L}}function X(n,e){if(U(n,e).eligible)return!0;let r=C(n);if(r&&r===C(e))return!0;let o=new Set(O(S(n)).filter(oe));return O(S(e)).some(i=>o.has(i)&&oe(i))}var He=new Set(["and","are","for","from","into","that","the","this","to","with"]);function oe(n){return n.length>=3&&/^[\p{L}\p{N}_$]+$/u.test(n)&&!He.has(n)}function ke(n,e,t){if(t===0)return!1;let r=Math.max(n.length,e.length);if(r<=2||t*2>=r)return!0;let o=[...n,...e].map(We);return o[0]!==null&&o.every(i=>i===o[0])}function We(n){let e=n.trimStart();return/^[-*+]\s+/.test(e)?"bullet":/^\d+[.)]\s+/.test(e)?"ordered":/^>\s+/.test(e)?"quote":null}var be=1e4,se=2e3,Ge=.52,$e=.35,ve=.38,ze=.33,we=.86,$=.08,k=.05,W=-.12,le=5e3,Ue=2e3,Be=5e7,fe=4,Pe=8,q=4;function xe(n,e){if(n.length===0)return e.map(s=>({right:s}));if(e.length===0)return n.map(s=>({left:s}));let t=n.reduce((s,u)=>s+u.length,0),r=e.reduce((s,u)=>s+u.length,0);if(t*r>Be)return[...n.map(s=>({left:s})),...e.map(s=>({right:s}))];if(n.length===1&&e.length===1){let s=U(n[0],e[0]);return(s.eligible||s.score>=$e)&&X(n[0],e[0])&&K(n[0],e[0])&&_(S(n[0]))&&_(S(e[0]))?[{left:n[0],right:e[0]}]:[{left:n[0]},{right:e[0]}]}if(n.length*e.length>be)return Ve(n,e);let o=qe(n,e),i=Array.from({length:n.length+1},()=>new Array(e.length+1).fill(Number.NEGATIVE_INFINITY)),l=Array.from({length:n.length+1},()=>new Array(e.length+1).fill(null));i[0][0]=0;for(let s=1;s<=n.length;s++)i[s][0]=i[s-1][0]+W,l[s][0]="left";for(let s=1;s<=e.length;s++)i[0][s]=i[0][s-1]+W,l[0][s]="right";for(let s=1;s<=n.length;s++)for(let u=1;u<=e.length;u++){let m=o[s-1][u-1],w=[{move:"left",score:i[s-1][u]+W},{move:"right",score:i[s][u-1]+W},{move:"match",score:m===null?Number.NEGATIVE_INFINITY:i[s-1][u-1]+m}].reduce((g,d)=>d.score>g.score?d:g);i[s][u]=w.score,l[s][u]=w.move}let a=[],c=n.length,f=e.length;for(;c>0||f>0;){let s=l[c][f];s==="match"?a.push({left:n[--c],right:e[--f]}):s==="left"?a.push({left:n[--c]}):a.push({right:e[--f]})}return a.reverse()}function U(n,e){let t=S(n),r=S(e),o=_(t),i=_(r);if(!o||!i||t.length>se||r.length>se)return{score:0,eligible:!1,characterSimilarity:0,tokenSimilarity:0,lengthSimilarity:0};if(t===r)return{score:1,eligible:!0,characterSimilarity:1,tokenSimilarity:1,lengthSimilarity:1};let l=O(t),a=O(r),c=rn(t,r),f=nn(l,a),s=Math.min(t.length,r.length)/Math.max(t.length,r.length),u=tn(l,a),m=c*.52+f*.32+s*.1+u*.06,L=c>=.52||f>=.45||c>=.48&&f>=.28;return{score:m,eligible:L&&m>=Ge,characterSimilarity:c,tokenSimilarity:f,lengthSimilarity:s}}function qe(n,e){let t=n.map(g=>e.map(d=>U(g,d))),r=Le(n,e),o=t.map(g=>Y(g)),i=e.map((g,d)=>Y(t.map(p=>p[d]))),l=t.map((g,d)=>g.map((p,h)=>{if(r.has(`${d}:${h}`))return Math.max(p.score,1);if(!p.eligible)return null;let b=o[d],v=i[h],x=p.score===b.best&&p.score===v.best,y=p.score>=we?$/2:$,A=b.best-b.second>=y,R=v.best-v.second>=y;return x&&A&&R?p.score:null}));if(Math.max(n.length,e.length)>Pe||Math.abs(n.length-e.length)>q)return l;let a=(g,d,p)=>g.score>=ve&&K(n[d],e[p])&&Math.abs(d-p)<=q,c=t.map((g,d)=>G(g,(p,h)=>a(p,d,h))),f=e.map((g,d)=>G(t.map(p=>p[d]),(p,h)=>a(p,h,d))),s=(g,d,p)=>g.score>=ze&&K(n[d],e[p])&&Math.abs(d-p)<=q,u=t.map((g,d)=>G(g,(p,h)=>s(p,d,h))),m=e.map((g,d)=>G(t.map(p=>p[d]),(p,h)=>s(p,h,d))),L=(g,d)=>{let p=t[g][d];if(!a(p,g,d))return!1;let h=c[g],b=f[d];return p.score===h.best&&p.score===b.best&&h.best-h.second>=k&&b.best-b.second>=k},w=(g,d)=>{let p=t[g][d];if(!s(p,g,d))return!1;let h=u[g],b=m[d];return p.score===h.best&&p.score===b.best&&h.best-h.second>=k&&b.best-b.second>=k};return l.map((g,d)=>g.map((p,h)=>{if(p!==null)return p;let b=L(d,h)&&(Xe(l,d,h)||Ye(t,d,h,L)),v=Ke(t,d,h,(x,y)=>s(t[x][y],x,y),w);return!b&&!v?null:t[d][h].score}))}function Xe(n,e,t){return e>0&&t>0&&n[e-1][t-1]!==null||e+1<n.length&&t+1<n[e+1].length&&n[e+1][t+1]!==null}function Ye(n,e,t,r){return e>0&&t>0&&r(e-1,t-1)||e+1<n.length&&t+1<n[e+1].length&&r(e+1,t+1)}function Ke(n,e,t,r,o){let i=e,l=t;for(;i>0&&l>0&&r(i-1,l-1);)i--,l--;let a=e,c=t,f=n[e][t].score,s=1;for(;a+1<n.length&&c+1<n[a+1].length&&r(a+1,c+1);)a++,c++,f+=n[a][c].score,s++;for(let u=e-1,m=t-1;u>=i&&m>=l;u--,m--)f+=n[u][m].score,s++;return s>=3&&f/s>=ve&&o(i,l)&&o(a,c)}function G(n,e){let t=Number.NEGATIVE_INFINITY,r=Number.NEGATIVE_INFINITY;return n.forEach((o,i)=>{e(o,i)&&(o.score>t?(r=t,t=o.score):o.score>r&&(r=o.score))}),{best:t,second:r}}function Y(n){let e=Number.NEGATIVE_INFINITY,t=Number.NEGATIVE_INFINITY;for(let r of n)r.eligible&&(r.score>e?(t=e,e=r.score):r.score>t&&(t=r.score));return{best:e,second:t}}function Ve(n,e){let t=Je(n,e),r=[],o=0,i=0;for(let l of t)ge(r,n.slice(o,l.leftIndex),e.slice(i,l.rightIndex)),r.push({left:n[l.leftIndex],right:e[l.rightIndex]}),o=l.leftIndex+1,i=l.rightIndex+1;return ge(r,n.slice(o),e.slice(i)),r}function Je(n,e){let t=je(n,e);if(t===null)return[];let r=Le(n,e),o=t.map(({leftIndex:f,rightIndex:s,exact:u})=>({leftIndex:f,rightIndex:s,exact:u,structural:r.has(`${f}:${s}`),match:U(n[f],e[s])})).filter(f=>f.exact||f.structural||f.match.eligible),i=ce(o,"leftIndex"),l=ce(o,"rightIndex"),a=o.filter(f=>{if(f.exact||f.structural)return!0;let s=i.get(f.leftIndex),u=l.get(f.rightIndex);if(!s||!u||f.match.score!==s.best||f.match.score!==u.best)return!1;let m=f.match.score>=we?$/2:$;return s.best-s.second>=m&&u.best-u.second>=m}),c=Qe(a,e.length);return c.length<=Ue?c:[]}function je(n,e){let t=ae(n,S),r=ae(e,S),o=new Map;for(let[a,c]of t){let f=r.get(a);if(!_(a)||c.length!==1||f?.length!==1)continue;let s=c[0],u=f[0];if(o.set(`${s}:${u}`,{leftIndex:s,rightIndex:u,exact:!0}),o.size>le)return null}let i=ue(n),l=ue(e);for(let[a,c]of i){let f=l.get(a);if(!(!f||c.length>fe||f.length>fe))for(let s of c)for(let u of f){let m=`${s}:${u}`;if(!o.has(m)&&(o.set(m,{leftIndex:s,rightIndex:u,exact:!1}),o.size>le))return null}}return[...o.values()]}function ae(n,e){let t=new Map;return n.forEach((r,o)=>{let i=e(r),l=t.get(i)??[];l.push(o),t.set(i,l)}),t}function ue(n){let e=new Map;return n.forEach((t,r)=>{let o=new Set(O(S(t)).filter(Ze));for(let i of o){let l=e.get(i)??[];l.push(r),e.set(i,l)}}),e}function Ze(n){return n.length>=2&&/[\p{L}\p{N}_$]/u.test(n)}function ce(n,e){let t=new Map;for(let r of n){let o=t.get(r[e])??[];o.push(r.match),t.set(r[e],o)}return new Map([...t].map(([r,o])=>[r,Y(o)]))}function Qe(n,e){let t=[...n].sort((f,s)=>f.leftIndex-s.leftIndex||f.rightIndex-s.rightIndex),r=new Array(e+2).fill(0),o=new Array(e+2).fill(-1),i=new Array(t.length).fill(0),l=new Array(t.length).fill(-1);for(let f=0;f<t.length;){let s=f+1;for(;s<t.length&&t[s].leftIndex===t[f].leftIndex;)s++;for(let u=f;u<s;u++){let m=de(r,o,t[u].rightIndex),L=t[u].exact||t[u].structural?.5:0;i[u]=m.score+t[u].match.score+L,l[u]=m.candidateIndex}for(let u=f;u<s;u++)en(r,o,t[u].rightIndex+1,i[u],u);f=s}let a=de(r,o,e+1),c=[];for(let f=a.candidateIndex;f>=0;f=l[f])c.push({leftIndex:t[f].leftIndex,rightIndex:t[f].rightIndex});return c.reverse()}function de(n,e,t){let r=0,o=-1;for(let i=t;i>0;i-=i&-i)n[i]>r&&(r=n[i],o=e[i]);return{score:r,candidateIndex:o}}function en(n,e,t,r,o){for(let i=t;i<n.length;i+=i&-i)r>n[i]&&(n[i]=r,e[i]=o)}function ge(n,e,t){if(e.length*t.length<=be){n.push(...xe(e,t));return}n.push(...e.map(r=>({left:r}))),n.push(...t.map(r=>({right:r})))}function S(n){return n.trim().replace(/\s+/g," ")}function Le(n,e){let t=pe(n),r=pe(e),o=new Set;for(let[i,l]of t){let a=r.get(i);l.length===1&&a?.length===1&&o.add(`${l[0]}:${a[0]}`)}return o}function pe(n){let e=new Map;return n.forEach((t,r)=>{let o=C(t);if(!o)return;let i=e.get(o)??[];i.push(r),e.set(o,i)}),e}function K(n,e){let t=C(n),r=C(e);return!t||!r?t===r:t.split(":",1)[0]===r.split(":",1)[0]}function C(n){let e=S(n),t=[["function",/^(?:(?:export|default)\s+)*(?:async\s+)?function\s*\*?\s*([\p{L}_$][\p{L}\p{N}_$]*)\s*\(/u],["function",/^(?:async\s+)?def\s+([\p{L}_][\p{L}\p{N}_]*)\s*\(/u],["function",/^(?:pub(?:\([^)]*\))?\s+)?(?:async\s+)?fn\s+([\p{L}_][\p{L}\p{N}_]*)\s*(?:<[^>]*>)?\s*\(/u],["function",/^func\s+(?:\([^)]*\)\s*)?([\p{L}_][\p{L}\p{N}_]*)\s*\(/u],["class",/^(?:(?:export|default|abstract|public)\s+)*class\s+([\p{L}_$][\p{L}\p{N}_$]*)\b/u]];for(let[r,o]of t){let i=e.match(o);if(i)return`${r}:${i[1]}`}return null}function _(n){return n.length<3?!1:/[\p{L}\p{N}_$]/u.test(n)&&!/^[\s()[\]{};,.:+\-*/=>|&!?'"`]+$/.test(n)}function O(n){return n.toLowerCase().match(/[\p{L}_$][\p{L}\p{N}_$]*|\p{N}+(?:\.\p{N}+)?|[^\s\p{L}\p{N}_$]/gu)??[]}function nn(n,e){if(n.length+e.length===0)return 1;let t=new Map;n.forEach(o=>t.set(o,(t.get(o)??0)+1));let r=0;for(let o of e){let i=t.get(o)??0;i>0&&(r++,t.set(o,i-1))}return 2*r/(n.length+e.length)}function tn(n,e){if(n.length===0||e.length===0)return 0;let t=n[0]===e[0]?.5:0,r=n[n.length-1]===e[e.length-1]?.5:0;return t+r}function rn(n,e){let t=n.length+e.length;return t===0?1:2*Q(n,e).filter(o=>!o.added&&!o.removed).reduce((o,i)=>o+i.value.length,0)/t}function on(n,e){if(n.content.length>re||e.content.length>re)return;let{leftSegments:t,rightSegments:r,hasInlineChanges:o}=sn(n.content,e.content);o&&(n.segments=t,e.segments=r)}function he(n){/[^\s]/.test(n.content)&&(n.segments=[{kind:n.kind,text:n.content,emphasis:!0}])}function sn(n,e){let t=ee(n,e),r=[],o=[],i=!1;for(let l of t){let a=l.value;if(!l.added&&!l.removed){let f={kind:"context",text:a,emphasis:!1};r.push(f),o.push(f);continue}let c=/[^\s]/.test(a);i=i||c,l.removed&&r.push({kind:"removed",text:a,emphasis:c}),l.added&&o.push({kind:"added",text:a,emphasis:c})}return{leftSegments:r,rightSegments:o,hasInlineChanges:i}}function T(){return{kind:"placeholder",content:"",lineNumber:null}}function N(n,e,t){return{kind:n,content:e,lineNumber:t}}function I(n,e,t){return{kind:n,content:e,lineNumber:t}}function M(n,e){return{left:n,right:e}}function z(n,e,t,r,o){return{kind:n,leftStart:e,leftEnd:t,rightStart:r,rightEnd:o}}function ye(n,e){let t=typeof process<"u"?process.env?.[n]:void 0,r=Number.parseInt(t??"",10);return Number.isFinite(r)&&r>0?r:e}self.addEventListener("message",n=>{let{id:e,leftContent:t,rightContent:r}=n.data||{};if(!(typeof e!="number"||typeof t!="string"||typeof r!="string"))try{let o=me(t,r);self.postMessage({id:e,model:o})}catch(o){self.postMessage({id:e,error:o&&o.message||String(o)})}});})();
|
|
5
5
|
//# sourceMappingURL=diff.worker.js.map
|