xtralab 0.14.1 → 0.15.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -0
- package/lib/about/icons.d.ts +0 -5
- package/lib/about/icons.js +0 -5
- package/lib/about/index.d.ts +4 -8
- package/lib/about/index.js +6 -17
- package/lib/agentSessions.d.ts +9 -29
- package/lib/agentSessions.js +2 -7
- package/lib/askAgent/editorSelection.d.ts +20 -26
- package/lib/askAgent/editorSelection.js +11 -26
- package/lib/askAgent/icons.d.ts +2 -3
- package/lib/askAgent/icons.js +2 -3
- package/lib/askAgent/index.d.ts +4 -26
- package/lib/askAgent/index.js +54 -158
- package/lib/askAgent/popup.d.ts +12 -16
- package/lib/askAgent/popup.js +18 -37
- package/lib/askAgent/prompt.d.ts +3 -5
- package/lib/askAgent/prompt.js +6 -19
- package/lib/askAgent/queue.d.ts +11 -21
- package/lib/askAgent/queue.js +9 -19
- package/lib/askAgent/queuePanel.d.ts +13 -18
- package/lib/askAgent/queuePanel.js +15 -37
- package/lib/askAgent/targetPicker.d.ts +2 -9
- package/lib/askAgent/targetPicker.js +6 -11
- package/lib/askAgent/tokens.d.ts +32 -46
- package/lib/askAgent/tokens.js +4 -6
- package/lib/commandBar/index.d.ts +4 -13
- package/lib/commandBar/index.js +21 -39
- package/lib/customPanel/index.d.ts +7 -0
- package/lib/customPanel/index.js +89 -0
- package/lib/editorBreadcrumbs/index.d.ts +3 -6
- package/lib/editorBreadcrumbs/index.js +10 -6
- package/lib/editorBreadcrumbs/widget.d.ts +17 -4
- package/lib/editorBreadcrumbs/widget.js +11 -17
- package/lib/editorIndent/index.d.ts +4 -12
- package/lib/editorIndent/index.js +8 -23
- package/lib/fileBrowser/commands.d.ts +28 -19
- package/lib/fileBrowser/commands.js +51 -98
- package/lib/fileBrowser/contents.d.ts +14 -0
- package/lib/fileBrowser/contents.js +28 -0
- package/lib/fileBrowser/dragAndDrop.d.ts +79 -0
- package/lib/fileBrowser/dragAndDrop.js +110 -0
- package/lib/fileBrowser/fileBrowser.d.ts +21 -9
- package/lib/fileBrowser/fileBrowser.js +211 -405
- package/lib/fileBrowser/gitStatus.d.ts +4 -9
- package/lib/fileBrowser/gitStatus.js +7 -17
- package/lib/fileBrowser/gitignore.d.ts +4 -17
- package/lib/fileBrowser/gitignore.js +4 -25
- package/lib/fileBrowser/icons.d.ts +7 -17
- package/lib/fileBrowser/icons.js +25 -80
- package/lib/fileBrowser/index.js +41 -10
- package/lib/fileBrowser/widget.d.ts +170 -53
- package/lib/fileBrowser/widget.js +242 -18
- package/lib/fileTypeIcons/index.js +0 -10
- package/lib/git/api.d.ts +5 -13
- package/lib/git/api.js +10 -36
- package/lib/git/askRequest.d.ts +4 -8
- package/lib/git/askRequest.js +6 -20
- package/lib/git/commands.d.ts +40 -5
- package/lib/git/commands.js +16 -10
- package/lib/git/diffModel.js +4 -0
- package/lib/git/diffSurface.d.ts +41 -55
- package/lib/git/diffSurface.js +42 -117
- package/lib/git/diffWidget.d.ts +81 -2
- package/lib/git/diffWidget.js +62 -12
- package/lib/git/imageDiff.d.ts +5 -6
- package/lib/git/imageDiff.js +18 -48
- package/lib/git/index.d.ts +0 -3
- package/lib/git/index.js +3 -8
- package/lib/git/notebookDiff.d.ts +110 -33
- package/lib/git/notebookDiff.js +52 -195
- package/lib/git/tokens.d.ts +73 -31
- package/lib/git/tokens.js +2 -3
- package/lib/highlight/index.d.ts +4 -10
- package/lib/highlight/index.js +10 -41
- package/lib/index.d.ts +0 -9
- package/lib/index.js +2 -9
- package/lib/launcher/agents.d.ts +55 -51
- package/lib/launcher/agents.js +25 -54
- package/lib/launcher/availability.d.ts +3 -9
- package/lib/launcher/availability.js +3 -9
- package/lib/launcher/commands.d.ts +7 -32
- package/lib/launcher/commands.js +14 -45
- package/lib/launcher/dashboard.d.ts +19 -24
- package/lib/launcher/dashboard.js +21 -67
- package/lib/launcher/editorRegistry.d.ts +10 -22
- package/lib/launcher/editorRegistry.js +14 -18
- package/lib/launcher/editors.d.ts +39 -45
- package/lib/launcher/editors.js +8 -34
- package/lib/launcher/icons.d.ts +0 -12
- package/lib/launcher/icons.js +14 -37
- package/lib/launcher/index.js +12 -55
- package/lib/launcher/invocation.d.ts +4 -10
- package/lib/launcher/invocation.js +7 -22
- package/lib/launcher/registry.d.ts +9 -7
- package/lib/launcher/registry.js +9 -7
- package/lib/launcher/schemaDefaults.d.ts +2 -9
- package/lib/launcher/schemaDefaults.js +37 -13
- package/lib/launcher/tokens.d.ts +10 -22
- package/lib/launcher/tokens.js +5 -8
- package/lib/menuBar/index.d.ts +3 -10
- package/lib/menuBar/index.js +11 -28
- package/lib/menus/index.d.ts +3 -9
- package/lib/menus/index.js +14 -30
- package/lib/omnibox/files.d.ts +2 -4
- package/lib/omnibox/files.js +5 -11
- package/lib/omnibox/index.d.ts +4 -14
- package/lib/omnibox/index.js +9 -27
- package/lib/omnibox/model.d.ts +38 -10
- package/lib/omnibox/model.js +15 -33
- package/lib/omnibox/recents.d.ts +15 -17
- package/lib/omnibox/recents.js +12 -17
- package/lib/omnibox/tokens.d.ts +5 -10
- package/lib/omnibox/tokens.js +2 -6
- package/lib/omnibox/widget.d.ts +11 -7
- package/lib/omnibox/widget.js +8 -16
- package/lib/searchReplace/index.d.ts +4 -20
- package/lib/searchReplace/index.js +7 -27
- package/lib/showOutput/index.d.ts +3 -12
- package/lib/showOutput/index.js +6 -22
- package/lib/sidebar/index.d.ts +4 -13
- package/lib/sidebar/index.js +73 -46
- package/lib/terminalNotifications/index.d.ts +4 -10
- package/lib/terminalNotifications/index.js +6 -20
- package/lib/terminals/agentTerminals.d.ts +12 -5
- package/lib/terminals/agentTerminals.js +25 -44
- package/lib/terminals/detection.d.ts +4 -8
- package/lib/terminals/detection.js +4 -8
- package/lib/terminals/index.d.ts +0 -33
- package/lib/terminals/index.js +24 -102
- package/lib/terminals/model.d.ts +64 -139
- package/lib/terminals/model.js +80 -220
- package/lib/terminals/tokens.d.ts +11 -22
- package/lib/terminals/tokens.js +2 -2
- package/lib/terminals/widget.d.ts +72 -38
- package/lib/terminals/widget.js +173 -73
- package/lib/topBar/icons.d.ts +3 -8
- package/lib/topBar/icons.js +3 -8
- package/lib/topBar/index.d.ts +4 -11
- package/lib/topBar/index.js +10 -38
- package/lib/walkthrough/index.d.ts +4 -9
- package/lib/walkthrough/index.js +6 -20
- package/lib/walkthrough/panel.d.ts +40 -9
- package/lib/walkthrough/panel.js +4 -10
- package/package.json +2 -2
- package/schema/launcher.json +2 -2
- package/schema/sidebar.json +47 -7
- package/src/about/icons.ts +0 -5
- package/src/about/index.tsx +6 -17
- package/src/agentSessions.ts +9 -29
- package/src/askAgent/editorSelection.ts +22 -29
- package/src/askAgent/icons.ts +2 -3
- package/src/askAgent/index.ts +54 -158
- package/src/askAgent/popup.tsx +23 -45
- package/src/askAgent/prompt.ts +6 -19
- package/src/askAgent/queue.ts +13 -24
- package/src/askAgent/queuePanel.tsx +21 -46
- package/src/askAgent/targetPicker.tsx +5 -15
- package/src/askAgent/tokens.ts +32 -46
- package/src/commandBar/index.ts +24 -39
- package/src/customPanel/index.ts +119 -0
- package/src/editorBreadcrumbs/index.ts +10 -6
- package/src/editorBreadcrumbs/widget.ts +23 -17
- package/src/editorIndent/index.ts +17 -23
- package/src/fileBrowser/commands.ts +70 -98
- package/src/fileBrowser/contents.ts +33 -0
- package/src/fileBrowser/dragAndDrop.ts +188 -0
- package/src/fileBrowser/fileBrowser.tsx +259 -440
- package/src/fileBrowser/gitStatus.ts +7 -17
- package/src/fileBrowser/gitignore.ts +4 -25
- package/src/fileBrowser/icons.ts +25 -80
- package/src/fileBrowser/index.ts +43 -10
- package/src/fileBrowser/widget.tsx +344 -64
- package/src/fileTypeIcons/index.ts +0 -10
- package/src/git/api.ts +10 -36
- package/src/git/askRequest.ts +6 -20
- package/src/git/commands.ts +70 -10
- package/src/git/diffModel.ts +25 -0
- package/src/git/diffSurface.tsx +71 -159
- package/src/git/diffWidget.tsx +104 -14
- package/src/git/imageDiff.tsx +45 -51
- package/src/git/index.ts +3 -8
- package/src/git/notebookDiff.tsx +211 -238
- package/src/git/tokens.ts +73 -31
- package/src/highlight/index.ts +10 -41
- package/src/index.ts +2 -9
- package/src/launcher/agents.ts +74 -92
- package/src/launcher/availability.ts +3 -9
- package/src/launcher/commands.ts +14 -51
- package/src/launcher/dashboard.tsx +49 -88
- package/src/launcher/editorRegistry.ts +21 -29
- package/src/launcher/editors.ts +39 -58
- package/src/launcher/icons.ts +15 -37
- package/src/launcher/index.ts +12 -55
- package/src/launcher/invocation.ts +7 -22
- package/src/launcher/registry.ts +9 -7
- package/src/launcher/schemaDefaults.ts +43 -13
- package/src/launcher/tokens.ts +10 -22
- package/src/menuBar/index.ts +11 -28
- package/src/menus/index.ts +14 -30
- package/src/omnibox/files.ts +10 -14
- package/src/omnibox/index.ts +9 -27
- package/src/omnibox/model.ts +50 -38
- package/src/omnibox/recents.ts +17 -22
- package/src/omnibox/tokens.ts +5 -10
- package/src/omnibox/widget.tsx +14 -19
- package/src/searchReplace/index.ts +7 -27
- package/src/showOutput/index.ts +6 -22
- package/src/sidebar/index.ts +103 -52
- package/src/terminalNotifications/index.ts +42 -25
- package/src/terminals/agentTerminals.ts +25 -49
- package/src/terminals/detection.ts +4 -8
- package/src/terminals/index.ts +31 -102
- package/src/terminals/model.ts +130 -246
- package/src/terminals/tokens.ts +11 -22
- package/src/terminals/widget.tsx +229 -113
- package/src/topBar/icons.ts +3 -8
- package/src/topBar/index.ts +21 -44
- package/src/walkthrough/index.ts +6 -20
- package/src/walkthrough/panel.ts +40 -10
- package/style/about.css +2 -7
- package/style/askAgent.css +8 -40
- package/style/base.css +25 -73
- package/style/chrome.css +108 -308
- package/style/commandBar.css +4 -20
- package/style/customPanel.css +6 -0
- package/style/git.css +22 -184
- package/style/highlight.css +1 -3
- package/style/index.js +1 -0
- package/style/launcher.css +6 -70
- package/style/omnibox.css +2 -14
- package/style/showOutput.css +0 -6
- package/style/sidebar.css +29 -9
- package/style/tabs.css +5 -13
- package/style/terminals.css +18 -123
- package/style/topBar.css +2 -22
- package/style/walkthrough.css +0 -8
package/src/git/diffSurface.tsx
CHANGED
|
@@ -22,38 +22,19 @@ import {
|
|
|
22
22
|
} from './notebookDiff';
|
|
23
23
|
import { resolveDiffTheme } from './diffTheme';
|
|
24
24
|
|
|
25
|
-
/**
|
|
26
|
-
* The CSS class added to the diff main-area widget. The selectors that
|
|
27
|
-
* style the embedded `@pierre/diffs` viewer hang off this class.
|
|
28
|
-
*/
|
|
29
25
|
export const DIFF_WIDGET_CSS_CLASS = 'jp-xtralab-DiffWidget';
|
|
30
26
|
|
|
31
|
-
/**
|
|
32
|
-
* `localStorage` key for the user's last-chosen split ratio, persisted so
|
|
33
|
-
* the preference survives reloads (the library has no built-in way to
|
|
34
|
-
* remember it).
|
|
35
|
-
*/
|
|
36
27
|
const SPLIT_RATIO_STORAGE_KEY = 'xtralab:diff-split-ratio';
|
|
37
28
|
|
|
38
|
-
/**
|
|
39
|
-
* Bounds on the left-pane fraction. Keeping a few percent on either side
|
|
40
|
-
* guarantees both panes remain visible — dragging to 0/100 would hide a
|
|
41
|
-
* column and is almost never what the user wants.
|
|
42
|
-
*/
|
|
43
29
|
const MIN_SPLIT_RATIO = 0.1;
|
|
44
30
|
const MAX_SPLIT_RATIO = 0.9;
|
|
45
31
|
const DEFAULT_SPLIT_RATIO = 0.5;
|
|
46
32
|
|
|
47
33
|
/**
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
* the
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
* The override reads from `--xtralab-split-cols`, a custom property we set
|
|
54
|
-
* on the host element via the `style` prop. Custom properties inherit
|
|
55
|
-
* through the shadow DOM boundary, so adjusting it on the host instantly
|
|
56
|
-
* resizes the columns without re-rendering the diff.
|
|
34
|
+
* Injected via the `unsafeCSS` option into the shadow root's `@layer
|
|
35
|
+
* unsafe`, beating the library's base rule that hardcodes `1fr 1fr`. Reads
|
|
36
|
+
* `--xtralab-split-cols` set on the host — custom properties cross the
|
|
37
|
+
* shadow boundary, so resizing needs no re-render.
|
|
57
38
|
*/
|
|
58
39
|
const SPLIT_RESIZE_CSS = `pre[data-diff-type="split"][data-overflow="scroll"] {
|
|
59
40
|
grid-template-columns: var(--xtralab-split-cols, 1fr 1fr);
|
|
@@ -74,8 +55,7 @@ function readStoredSplitRatio(): number {
|
|
|
74
55
|
return parsed;
|
|
75
56
|
}
|
|
76
57
|
} catch {
|
|
77
|
-
// localStorage
|
|
78
|
-
// back to the default is fine — the user can resize again on this run.
|
|
58
|
+
// localStorage can throw in privacy mode or sandboxed contexts.
|
|
79
59
|
}
|
|
80
60
|
return DEFAULT_SPLIT_RATIO;
|
|
81
61
|
}
|
|
@@ -88,15 +68,13 @@ function writeStoredSplitRatio(ratio: number): void {
|
|
|
88
68
|
}
|
|
89
69
|
}
|
|
90
70
|
|
|
91
|
-
/**
|
|
92
|
-
* Layout for textual/code diffs, forwarded to `@pierre/diffs` as its
|
|
93
|
-
* `diffStyle` option. `split` is the side-by-side old|new view; `unified`
|
|
94
|
-
* is the single-column inline view (what diffs.com calls "stacked").
|
|
95
|
-
*/
|
|
96
71
|
export type DiffStyle = 'split' | 'unified';
|
|
97
72
|
|
|
98
73
|
const DIFF_STYLE_STORAGE_KEY = 'xtralab:diff-style';
|
|
99
74
|
|
|
75
|
+
/**
|
|
76
|
+
* Read the persisted diff style, defaulting to `'split'`.
|
|
77
|
+
*/
|
|
100
78
|
export function readStoredDiffStyle(): DiffStyle {
|
|
101
79
|
try {
|
|
102
80
|
const raw = window.localStorage.getItem(DIFF_STYLE_STORAGE_KEY);
|
|
@@ -104,11 +82,14 @@ export function readStoredDiffStyle(): DiffStyle {
|
|
|
104
82
|
return raw;
|
|
105
83
|
}
|
|
106
84
|
} catch {
|
|
107
|
-
// See readStoredSplitRatio
|
|
85
|
+
// See readStoredSplitRatio.
|
|
108
86
|
}
|
|
109
87
|
return 'split';
|
|
110
88
|
}
|
|
111
89
|
|
|
90
|
+
/**
|
|
91
|
+
* Persist the diff style to local storage (best-effort).
|
|
92
|
+
*/
|
|
112
93
|
export function writeStoredDiffStyle(style: DiffStyle): void {
|
|
113
94
|
try {
|
|
114
95
|
window.localStorage.setItem(DIFF_STYLE_STORAGE_KEY, style);
|
|
@@ -117,15 +98,13 @@ export function writeStoredDiffStyle(style: DiffStyle): void {
|
|
|
117
98
|
}
|
|
118
99
|
}
|
|
119
100
|
|
|
120
|
-
/**
|
|
121
|
-
* View modes available for `.ipynb` diffs. `notebook` is the cell-by-cell
|
|
122
|
-
* rendered view; `json` is the raw nbformat JSON file diff, for inspecting
|
|
123
|
-
* exactly which bytes changed.
|
|
124
|
-
*/
|
|
125
101
|
export type NotebookDiffViewMode = 'notebook' | 'json';
|
|
126
102
|
|
|
127
103
|
const NOTEBOOK_DIFF_VIEW_MODE_STORAGE_KEY = 'xtralab:notebook-diff-view-mode';
|
|
128
104
|
|
|
105
|
+
/**
|
|
106
|
+
* Read the persisted notebook view mode, defaulting to `'notebook'`.
|
|
107
|
+
*/
|
|
129
108
|
export function readStoredNotebookViewMode(): NotebookDiffViewMode {
|
|
130
109
|
try {
|
|
131
110
|
const raw = window.localStorage.getItem(
|
|
@@ -135,12 +114,14 @@ export function readStoredNotebookViewMode(): NotebookDiffViewMode {
|
|
|
135
114
|
return raw;
|
|
136
115
|
}
|
|
137
116
|
} catch {
|
|
138
|
-
// See readStoredSplitRatio
|
|
139
|
-
// throw on access. The notebook view is the better default anyway.
|
|
117
|
+
// See readStoredSplitRatio.
|
|
140
118
|
}
|
|
141
119
|
return 'notebook';
|
|
142
120
|
}
|
|
143
121
|
|
|
122
|
+
/**
|
|
123
|
+
* Persist the notebook view mode to local storage (best-effort).
|
|
124
|
+
*/
|
|
144
125
|
export function writeStoredNotebookViewMode(mode: NotebookDiffViewMode): void {
|
|
145
126
|
try {
|
|
146
127
|
window.localStorage.setItem(NOTEBOOK_DIFF_VIEW_MODE_STORAGE_KEY, mode);
|
|
@@ -150,31 +131,26 @@ export function writeStoredNotebookViewMode(mode: NotebookDiffViewMode): void {
|
|
|
150
131
|
}
|
|
151
132
|
|
|
152
133
|
/**
|
|
153
|
-
* Annotation payload threaded
|
|
154
|
-
* `renderAnnotation` callback. Carries the index of the hunk a particular
|
|
155
|
-
* action button targets.
|
|
134
|
+
* Annotation payload threaded back into `renderAnnotation`; carries the target hunk index.
|
|
156
135
|
*/
|
|
157
136
|
interface IHunkActionAnnotation {
|
|
137
|
+
/**
|
|
138
|
+
* The index of the hunk the action targets.
|
|
139
|
+
*/
|
|
158
140
|
hunkIndex: number;
|
|
159
141
|
}
|
|
160
142
|
|
|
161
143
|
/**
|
|
162
|
-
*
|
|
163
|
-
*
|
|
164
|
-
* another `.ipynb`-named file for a notebook is harmless because
|
|
165
|
-
* {@link buildNotebookDiff} validates the JSON shape and we fall back to
|
|
166
|
-
* the file diff if parsing fails.
|
|
144
|
+
* Extension-only check; a false positive is harmless because
|
|
145
|
+
* {@link buildNotebookDiff} validates the JSON and the file diff is the fallback.
|
|
167
146
|
*/
|
|
168
147
|
function isNotebookPath(path: string): boolean {
|
|
169
148
|
return path.toLowerCase().endsWith('.ipynb');
|
|
170
149
|
}
|
|
171
150
|
|
|
172
151
|
/**
|
|
173
|
-
*
|
|
174
|
-
* `
|
|
175
|
-
* `data-jp-theme-light` attribute that JupyterLab sets on `<body>` so the
|
|
176
|
-
* component still works in stripped-down hosts where the token isn't
|
|
177
|
-
* provided (lite, certain notebook configurations, …).
|
|
152
|
+
* Dark-theme check via `IThemeManager`, falling back to the
|
|
153
|
+
* `data-jp-theme-light` body attribute for hosts without the token.
|
|
178
154
|
*/
|
|
179
155
|
export function isDarkTheme(themeManager: IThemeManager | null): boolean {
|
|
180
156
|
if (themeManager !== null && themeManager.theme !== null) {
|
|
@@ -192,19 +168,27 @@ export function isPierreTheme(themeManager: IThemeManager | null): boolean {
|
|
|
192
168
|
}
|
|
193
169
|
|
|
194
170
|
/**
|
|
195
|
-
*
|
|
196
|
-
*
|
|
197
|
-
* reverts that hunk and hands the rebuilt full-file text back to the host
|
|
198
|
-
* via {@link IHunkDiscard.save}. The host owns the actual write (it knows
|
|
199
|
-
* the on-disk path) and triggers any follow-up refresh in
|
|
200
|
-
* {@link IHunkDiscard.onAfterSave}.
|
|
171
|
+
* Per-hunk discard wiring: discarding rebuilds the full file text and the
|
|
172
|
+
* host owns the write via `save`, then refreshes in `onAfterSave`.
|
|
201
173
|
*/
|
|
202
174
|
interface IHunkDiscard {
|
|
175
|
+
/**
|
|
176
|
+
* Whether hunk discarding is available.
|
|
177
|
+
*/
|
|
203
178
|
enabled: boolean;
|
|
179
|
+
/**
|
|
180
|
+
* Persist the full post-discard file text.
|
|
181
|
+
*/
|
|
204
182
|
save: (fullText: string) => Promise<void>;
|
|
183
|
+
/**
|
|
184
|
+
* Called after a successful save so the host can refresh the diff.
|
|
185
|
+
*/
|
|
205
186
|
onAfterSave: () => void;
|
|
206
187
|
}
|
|
207
188
|
|
|
189
|
+
/**
|
|
190
|
+
* The props for the {@link DiffSurface} component.
|
|
191
|
+
*/
|
|
208
192
|
interface IDiffSurfaceProps {
|
|
209
193
|
/**
|
|
210
194
|
* Whether the host is still resolving the file contents.
|
|
@@ -227,13 +211,11 @@ interface IDiffSurfaceProps {
|
|
|
227
211
|
*/
|
|
228
212
|
newText: string;
|
|
229
213
|
/**
|
|
230
|
-
* New-side path
|
|
231
|
-
* name on the additions side.
|
|
214
|
+
* New-side path; drives notebook detection and the highlighting filename.
|
|
232
215
|
*/
|
|
233
216
|
newName: string;
|
|
234
217
|
/**
|
|
235
|
-
* Old-side path
|
|
236
|
-
* to {@link newName} when the host does not track a previous path.
|
|
218
|
+
* Old-side path; differs from {@link newName} only for renames.
|
|
237
219
|
*/
|
|
238
220
|
oldName?: string;
|
|
239
221
|
/**
|
|
@@ -245,35 +227,28 @@ interface IDiffSurfaceProps {
|
|
|
245
227
|
*/
|
|
246
228
|
pierreTheme: boolean;
|
|
247
229
|
/**
|
|
248
|
-
*
|
|
249
|
-
* markdown cells. May be `null` in stripped-down hosts; the notebook
|
|
250
|
-
* diff falls back to a textual representation in that case.
|
|
230
|
+
* Used by the notebook view; `null` in stripped-down hosts, which forces a textual fallback.
|
|
251
231
|
*/
|
|
252
232
|
rendermime: IRenderMimeRegistry | null;
|
|
253
233
|
/**
|
|
254
|
-
*
|
|
234
|
+
* Rendered-vs-JSON choice for notebook diffs (host-controlled).
|
|
255
235
|
*/
|
|
256
236
|
notebookViewMode: NotebookDiffViewMode;
|
|
257
237
|
/**
|
|
258
|
-
* Split vs unified layout for the textual
|
|
238
|
+
* Split vs unified layout for the textual file diff (host-controlled).
|
|
259
239
|
*/
|
|
260
240
|
diffStyle: DiffStyle;
|
|
261
241
|
/**
|
|
262
|
-
*
|
|
263
|
-
* so the host can show/hide its Notebook/JSON toolbar toggle.
|
|
242
|
+
* Fires when rendered-notebook availability changes so the host can toggle its Notebook/JSON control.
|
|
264
243
|
*/
|
|
265
244
|
onNotebookAvailabilityChange?: (available: boolean) => void;
|
|
266
245
|
/**
|
|
267
|
-
*
|
|
268
|
-
* unified choice affects) becomes the active view, so the host can
|
|
269
|
-
* show/hide its Split/Unified toolbar toggle. False for image, binary,
|
|
270
|
-
* rendered-notebook, loading and error states.
|
|
246
|
+
* Fires when the textual file diff becomes (in)active — the only view the split/unified choice affects.
|
|
271
247
|
*/
|
|
272
248
|
onFileDiffActiveChange?: (active: boolean) => void;
|
|
273
249
|
/**
|
|
274
|
-
*
|
|
275
|
-
*
|
|
276
|
-
* post-discard behaviors such as auto-closing an emptied diff.
|
|
250
|
+
* Fires after each diff computation with the hunk count (`null` when no
|
|
251
|
+
* textual diff); hosts use it to auto-close emptied diffs.
|
|
277
252
|
*/
|
|
278
253
|
onMetadataChange?: (info: { hunkCount: number | null }) => void;
|
|
279
254
|
/**
|
|
@@ -281,11 +256,8 @@ interface IDiffSurfaceProps {
|
|
|
281
256
|
*/
|
|
282
257
|
hunkDiscard?: IHunkDiscard;
|
|
283
258
|
/**
|
|
284
|
-
*
|
|
285
|
-
*
|
|
286
|
-
* button appears on the hovered/selected lines. Clicking that button
|
|
287
|
-
* invokes this callback with the selected range and the button's viewport
|
|
288
|
-
* rectangle (to anchor a popup to), `null` when it cannot be measured.
|
|
259
|
+
* Enables line selection and the gutter "+" button; called with the
|
|
260
|
+
* selected range and the button's viewport rect (`null` when unmeasurable).
|
|
289
261
|
*/
|
|
290
262
|
onLineAsk?: (range: SelectedLineRange, anchor: DOMRect | null) => void;
|
|
291
263
|
/**
|
|
@@ -321,15 +293,11 @@ export function DiffSurface(props: IDiffSurfaceProps): React.ReactElement {
|
|
|
321
293
|
|
|
322
294
|
const hasContent = !loading && error === null && !isBinary;
|
|
323
295
|
|
|
324
|
-
//
|
|
325
|
-
// text/notebook diff; the host passes the two sides as base64 strings in
|
|
326
|
-
// `oldText`/`newText` (the git server base64-encodes binary content).
|
|
296
|
+
// For raster images the host passes both sides as base64 in oldText/newText.
|
|
327
297
|
const imageType = React.useMemo(() => imageDataType(newName), [newName]);
|
|
328
298
|
|
|
329
|
-
//
|
|
330
|
-
//
|
|
331
|
-
// {@link diffAcceptRejectHunk} when the user discards a hunk — so hunk
|
|
332
|
-
// indexes line up between what the user clicked and what we mutate.
|
|
299
|
+
// Owning the metadata here keeps hunk indexes aligned between FileDiff
|
|
300
|
+
// and diffAcceptRejectHunk on discard.
|
|
333
301
|
const metadata = React.useMemo<FileDiffMetadata | null>(() => {
|
|
334
302
|
if (!hasContent || imageType !== null) {
|
|
335
303
|
return null;
|
|
@@ -342,10 +310,6 @@ export function DiffSurface(props: IDiffSurfaceProps): React.ReactElement {
|
|
|
342
310
|
return parseDiffFromFile(oldFile, newFile);
|
|
343
311
|
}, [hasContent, imageType, oldText, newText, oldName, newName]);
|
|
344
312
|
|
|
345
|
-
// Cell-by-cell notebook diff for `.ipynb` files. When non-null the
|
|
346
|
-
// renderer uses a notebook-aware view instead of the line-oriented file
|
|
347
|
-
// diff — kept distinct from {@link metadata} so a notebook whose JSON we
|
|
348
|
-
// cannot parse can fall back to the file diff path.
|
|
349
313
|
const notebookDiff = React.useMemo<INotebookDiffResult | null>(() => {
|
|
350
314
|
if (!hasContent || imageType !== null || !isNotebookPath(newName)) {
|
|
351
315
|
return null;
|
|
@@ -353,43 +317,31 @@ export function DiffSurface(props: IDiffSurfaceProps): React.ReactElement {
|
|
|
353
317
|
return buildNotebookDiff({ oldText, newText });
|
|
354
318
|
}, [hasContent, imageType, oldText, newText, newName]);
|
|
355
319
|
|
|
356
|
-
// Tell the host whether a rendered notebook view is currently available
|
|
357
|
-
// so it can show/hide its Notebook/JSON toggle.
|
|
358
320
|
React.useEffect(() => {
|
|
359
321
|
onNotebookAvailabilityChange?.(notebookDiff !== null);
|
|
360
322
|
}, [onNotebookAvailabilityChange, notebookDiff]);
|
|
361
323
|
|
|
362
|
-
// Report the diff shape so hosts can react (e.g. auto-close on empty).
|
|
363
324
|
React.useEffect(() => {
|
|
364
325
|
onMetadataChange?.({
|
|
365
326
|
hunkCount: metadata !== null ? metadata.hunks.length : null
|
|
366
327
|
});
|
|
367
328
|
}, [onMetadataChange, metadata]);
|
|
368
329
|
|
|
369
|
-
//
|
|
370
|
-
//
|
|
371
|
-
// Computed before the early returns below so the file-diff-active effect
|
|
372
|
-
// can depend on it without violating the rules of hooks.
|
|
330
|
+
// Computed before the early returns so the hooks below can depend on
|
|
331
|
+
// them without breaking the rules of hooks.
|
|
373
332
|
const hasNotebookView = notebookDiff !== null;
|
|
374
333
|
const showNotebookView = hasNotebookView && notebookViewMode === 'notebook';
|
|
375
334
|
const showFileDiff = !showNotebookView && metadata !== null;
|
|
376
335
|
|
|
377
|
-
// The split vs unified choice only affects the textual/code file diff, so
|
|
378
|
-
// tell the host whether that view is active to drive its Split/Unified
|
|
379
|
-
// toolbar toggle.
|
|
380
336
|
React.useEffect(() => {
|
|
381
337
|
onFileDiffActiveChange?.(showFileDiff);
|
|
382
338
|
}, [onFileDiffActiveChange, showFileDiff]);
|
|
383
339
|
|
|
384
|
-
// Split ratio for the diff columns: fraction of width given to the
|
|
385
|
-
// deletions (left) pane. Persisted across sessions so the user only
|
|
386
|
-
// dials in their layout once.
|
|
387
340
|
const [leftRatio, setLeftRatio] = React.useState<number>(() =>
|
|
388
341
|
readStoredSplitRatio()
|
|
389
342
|
);
|
|
390
343
|
const wrapperRef = React.useRef<HTMLDivElement | null>(null);
|
|
391
|
-
//
|
|
392
|
-
// attach on pointer-down don't capture a stale value across renders.
|
|
344
|
+
// Drag listeners read the live ratio from a ref to avoid stale captures.
|
|
393
345
|
const leftRatioRef = React.useRef(leftRatio);
|
|
394
346
|
React.useEffect(() => {
|
|
395
347
|
leftRatioRef.current = leftRatio;
|
|
@@ -405,8 +357,6 @@ export function DiffSurface(props: IDiffSurfaceProps): React.ReactElement {
|
|
|
405
357
|
}
|
|
406
358
|
return metadata.hunks.map((hunk, hunkIndex) => ({
|
|
407
359
|
side: 'additions',
|
|
408
|
-
// The first line of each hunk in the new file. We anchor the button
|
|
409
|
-
// there so it sits at the top of the hunk's body.
|
|
410
360
|
lineNumber: hunk.additionStart,
|
|
411
361
|
metadata: { hunkIndex }
|
|
412
362
|
}));
|
|
@@ -418,12 +368,8 @@ export function DiffSurface(props: IDiffSurfaceProps): React.ReactElement {
|
|
|
418
368
|
return;
|
|
419
369
|
}
|
|
420
370
|
const updated = diffAcceptRejectHunk(metadata, hunkIndex, 'reject');
|
|
421
|
-
//
|
|
422
|
-
//
|
|
423
|
-
// file contents with `/(?<=\n)/` (a lookbehind that keeps the
|
|
424
|
-
// trailing `\n` on each line), so the entries already carry their
|
|
425
|
-
// own line endings — joining with `''` rebuilds the original text
|
|
426
|
-
// verbatim, while joining with `'\n'` would double every newline.
|
|
371
|
+
// additionLines holds the full new file with the hunk reverted; lines keep
|
|
372
|
+
// their trailing `\n` (lookbehind split), so join('') rebuilds it verbatim.
|
|
427
373
|
const text = updated.additionLines.join('');
|
|
428
374
|
try {
|
|
429
375
|
await hunkDiscard.save(text);
|
|
@@ -469,9 +415,7 @@ export function DiffSurface(props: IDiffSurfaceProps): React.ReactElement {
|
|
|
469
415
|
if (onLineAsk === undefined) {
|
|
470
416
|
return;
|
|
471
417
|
}
|
|
472
|
-
// Anchor to the gutter "+" button
|
|
473
|
-
// the `@pierre/diffs` shadow root (which is open), parked on the
|
|
474
|
-
// hovered/selected line's number element.
|
|
418
|
+
// Anchor to the just-clicked gutter "+" button inside the library's open shadow root.
|
|
475
419
|
const slot = wrapperRef.current
|
|
476
420
|
?.querySelector('diffs-container')
|
|
477
421
|
?.shadowRoot?.querySelector('[data-gutter-utility-slot]');
|
|
@@ -485,8 +429,6 @@ export function DiffSurface(props: IDiffSurfaceProps): React.ReactElement {
|
|
|
485
429
|
|
|
486
430
|
const handleResizerPointerDown = React.useCallback(
|
|
487
431
|
(event: React.PointerEvent<HTMLDivElement>) => {
|
|
488
|
-
// Only react to primary-button drags. Right-click / middle-click on
|
|
489
|
-
// the handle should pass through to the browser default.
|
|
490
432
|
if (event.button !== 0) {
|
|
491
433
|
return;
|
|
492
434
|
}
|
|
@@ -519,8 +461,6 @@ export function DiffSurface(props: IDiffSurfaceProps): React.ReactElement {
|
|
|
519
461
|
handle.removeEventListener('pointermove', onPointerMove);
|
|
520
462
|
handle.removeEventListener('pointerup', onPointerEnd);
|
|
521
463
|
handle.removeEventListener('pointercancel', onPointerEnd);
|
|
522
|
-
// Only persist on drag-end so a quick drag isn't followed by a
|
|
523
|
-
// burst of writes for every intermediate position.
|
|
524
464
|
writeStoredSplitRatio(leftRatioRef.current);
|
|
525
465
|
};
|
|
526
466
|
handle.addEventListener('pointermove', onPointerMove);
|
|
@@ -589,9 +529,6 @@ export function DiffSurface(props: IDiffSurfaceProps): React.ReactElement {
|
|
|
589
529
|
);
|
|
590
530
|
}
|
|
591
531
|
if (imageType !== null) {
|
|
592
|
-
// `oldText`/`newText` carry the two revisions as base64 here. The
|
|
593
|
-
// image view owns its own layout and mode selector, so it does not
|
|
594
|
-
// use the split resizer or the notebook/JSON toggle.
|
|
595
532
|
return (
|
|
596
533
|
<div className="jp-xtralab-DiffWidget-content">
|
|
597
534
|
<ImageDiffView
|
|
@@ -611,10 +548,6 @@ export function DiffSurface(props: IDiffSurfaceProps): React.ReactElement {
|
|
|
611
548
|
);
|
|
612
549
|
}
|
|
613
550
|
|
|
614
|
-
// Custom property set on the diffs-container host. The library's
|
|
615
|
-
// shadow-root rule consumes it via `var(--xtralab-split-cols, …)` (see
|
|
616
|
-
// SPLIT_RESIZE_CSS) and recomputes the column tracks instantly. Only
|
|
617
|
-
// relevant in the file-diff path; the notebook view doesn't use it.
|
|
618
551
|
const leftPercent = leftRatio * 100;
|
|
619
552
|
const hostStyle = {
|
|
620
553
|
'--xtralab-split-cols': `${leftPercent}% ${100 - leftPercent}%`
|
|
@@ -638,30 +571,16 @@ export function DiffSurface(props: IDiffSurfaceProps): React.ReactElement {
|
|
|
638
571
|
lineAnnotations={lineAnnotations}
|
|
639
572
|
renderAnnotation={renderAnnotation}
|
|
640
573
|
style={hostStyle}
|
|
641
|
-
//
|
|
642
|
-
//
|
|
643
|
-
// `@pierre/diffs/worker/worker.js` file at a URL the worker
|
|
644
|
-
// bootstrap can resolve from, so leaving the pool enabled
|
|
645
|
-
// crashes on instantiation. Running on the main thread is
|
|
646
|
-
// fine for the small files git diffs typically operate on.
|
|
574
|
+
// JupyterLab's federation pipeline can't serve the worker bundle
|
|
575
|
+
// at a resolvable URL, so the pool crashes; run on the main thread.
|
|
647
576
|
disableWorkerPool={true}
|
|
648
577
|
options={{
|
|
649
578
|
diffStyle,
|
|
650
|
-
// Drop the file header — the tab title already shows the
|
|
651
|
-
// file name and the panel header carries the change
|
|
652
|
-
// context.
|
|
653
579
|
disableFileHeader: true,
|
|
654
580
|
theme: resolveDiffTheme(dark, pierreTheme),
|
|
655
581
|
themeType: dark ? 'dark' : 'light',
|
|
656
|
-
//
|
|
657
|
-
// via the library's `@layer unsafe` channel. Keeping the
|
|
658
|
-
// string constant lets the library short-circuit the
|
|
659
|
-
// re-render path it uses when this option actually
|
|
660
|
-
// changes.
|
|
582
|
+
// Constant string lets the library skip its unsafeCSS re-render path.
|
|
661
583
|
unsafeCSS: SPLIT_RESIZE_CSS,
|
|
662
|
-
// Line selection + the gutter "+" button feed the
|
|
663
|
-
// ask-agent popup; only wired up when a handler exists so
|
|
664
|
-
// a plain diff keeps its passive gutter.
|
|
665
584
|
...(onLineAsk !== undefined
|
|
666
585
|
? {
|
|
667
586
|
enableLineSelection: true,
|
|
@@ -698,10 +617,8 @@ export function DiffSurface(props: IDiffSurfaceProps): React.ReactElement {
|
|
|
698
617
|
}
|
|
699
618
|
|
|
700
619
|
/**
|
|
701
|
-
* Segmented Notebook/JSON selector. Hosts mount
|
|
702
|
-
*
|
|
703
|
-
* `jupyterlab-git`-provided diff toolbar) and drive its value/visibility
|
|
704
|
-
* from the same state they pass to {@link DiffSurface}.
|
|
620
|
+
* Segmented Notebook/JSON selector. Hosts mount it into their own toolbar
|
|
621
|
+
* and drive value/visibility from the state they pass to {@link DiffSurface}.
|
|
705
622
|
*/
|
|
706
623
|
export function NotebookViewModeControl(props: {
|
|
707
624
|
mode: NotebookDiffViewMode;
|
|
@@ -744,11 +661,9 @@ export function NotebookViewModeControl(props: {
|
|
|
744
661
|
}
|
|
745
662
|
|
|
746
663
|
/**
|
|
747
|
-
* Split / unified glyphs
|
|
748
|
-
*
|
|
749
|
-
*
|
|
750
|
-
* sprite sheet being injected into the document. `currentColor` lets the
|
|
751
|
-
* segmented-button styling drive the fill (including the active state).
|
|
664
|
+
* Split / unified glyphs inlined from the `@pierre/diffs` icon sprite so
|
|
665
|
+
* the toggle matches the library's docs site without the sprite sheet;
|
|
666
|
+
* `currentColor` lets the button styling drive the fill.
|
|
752
667
|
*/
|
|
753
668
|
function DiffSplitIcon(): React.ReactElement {
|
|
754
669
|
return (
|
|
@@ -781,11 +696,8 @@ function DiffUnifiedIcon(): React.ReactElement {
|
|
|
781
696
|
}
|
|
782
697
|
|
|
783
698
|
/**
|
|
784
|
-
* Segmented Split/Unified selector
|
|
785
|
-
*
|
|
786
|
-
* the same state they pass to {@link DiffSurface}. Only meaningful while the
|
|
787
|
-
* textual/code file diff is the active view, so `available` mirrors the
|
|
788
|
-
* surface's `onFileDiffActiveChange`.
|
|
699
|
+
* Segmented Split/Unified selector; mirrors {@link NotebookViewModeControl}.
|
|
700
|
+
* `available` mirrors the surface's `onFileDiffActiveChange`.
|
|
789
701
|
*/
|
|
790
702
|
export function DiffStyleControl(props: {
|
|
791
703
|
diffStyle: DiffStyle;
|