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/lib/git/diffSurface.js
CHANGED
|
@@ -5,35 +5,16 @@ import { diffAcceptRejectHunk, parseDiffFromFile } from '@pierre/diffs';
|
|
|
5
5
|
import { ImageDiffView, imageDataType } from './imageDiff';
|
|
6
6
|
import { buildNotebookDiff, NotebookDiffView } from './notebookDiff';
|
|
7
7
|
import { resolveDiffTheme } from './diffTheme';
|
|
8
|
-
/**
|
|
9
|
-
* The CSS class added to the diff main-area widget. The selectors that
|
|
10
|
-
* style the embedded `@pierre/diffs` viewer hang off this class.
|
|
11
|
-
*/
|
|
12
8
|
export const DIFF_WIDGET_CSS_CLASS = 'jp-xtralab-DiffWidget';
|
|
13
|
-
/**
|
|
14
|
-
* `localStorage` key for the user's last-chosen split ratio, persisted so
|
|
15
|
-
* the preference survives reloads (the library has no built-in way to
|
|
16
|
-
* remember it).
|
|
17
|
-
*/
|
|
18
9
|
const SPLIT_RATIO_STORAGE_KEY = 'xtralab:diff-split-ratio';
|
|
19
|
-
/**
|
|
20
|
-
* Bounds on the left-pane fraction. Keeping a few percent on either side
|
|
21
|
-
* guarantees both panes remain visible — dragging to 0/100 would hide a
|
|
22
|
-
* column and is almost never what the user wants.
|
|
23
|
-
*/
|
|
24
10
|
const MIN_SPLIT_RATIO = 0.1;
|
|
25
11
|
const MAX_SPLIT_RATIO = 0.9;
|
|
26
12
|
const DEFAULT_SPLIT_RATIO = 0.5;
|
|
27
13
|
/**
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* the
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
* The override reads from `--xtralab-split-cols`, a custom property we set
|
|
34
|
-
* on the host element via the `style` prop. Custom properties inherit
|
|
35
|
-
* through the shadow DOM boundary, so adjusting it on the host instantly
|
|
36
|
-
* resizes the columns without re-rendering the diff.
|
|
14
|
+
* Injected via the `unsafeCSS` option into the shadow root's `@layer
|
|
15
|
+
* unsafe`, beating the library's base rule that hardcodes `1fr 1fr`. Reads
|
|
16
|
+
* `--xtralab-split-cols` set on the host — custom properties cross the
|
|
17
|
+
* shadow boundary, so resizing needs no re-render.
|
|
37
18
|
*/
|
|
38
19
|
const SPLIT_RESIZE_CSS = `pre[data-diff-type="split"][data-overflow="scroll"] {
|
|
39
20
|
grid-template-columns: var(--xtralab-split-cols, 1fr 1fr);
|
|
@@ -52,8 +33,7 @@ function readStoredSplitRatio() {
|
|
|
52
33
|
}
|
|
53
34
|
}
|
|
54
35
|
catch (_a) {
|
|
55
|
-
// localStorage
|
|
56
|
-
// back to the default is fine — the user can resize again on this run.
|
|
36
|
+
// localStorage can throw in privacy mode or sandboxed contexts.
|
|
57
37
|
}
|
|
58
38
|
return DEFAULT_SPLIT_RATIO;
|
|
59
39
|
}
|
|
@@ -66,6 +46,9 @@ function writeStoredSplitRatio(ratio) {
|
|
|
66
46
|
}
|
|
67
47
|
}
|
|
68
48
|
const DIFF_STYLE_STORAGE_KEY = 'xtralab:diff-style';
|
|
49
|
+
/**
|
|
50
|
+
* Read the persisted diff style, defaulting to `'split'`.
|
|
51
|
+
*/
|
|
69
52
|
export function readStoredDiffStyle() {
|
|
70
53
|
try {
|
|
71
54
|
const raw = window.localStorage.getItem(DIFF_STYLE_STORAGE_KEY);
|
|
@@ -74,10 +57,13 @@ export function readStoredDiffStyle() {
|
|
|
74
57
|
}
|
|
75
58
|
}
|
|
76
59
|
catch (_a) {
|
|
77
|
-
// See readStoredSplitRatio
|
|
60
|
+
// See readStoredSplitRatio.
|
|
78
61
|
}
|
|
79
62
|
return 'split';
|
|
80
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* Persist the diff style to local storage (best-effort).
|
|
66
|
+
*/
|
|
81
67
|
export function writeStoredDiffStyle(style) {
|
|
82
68
|
try {
|
|
83
69
|
window.localStorage.setItem(DIFF_STYLE_STORAGE_KEY, style);
|
|
@@ -87,6 +73,9 @@ export function writeStoredDiffStyle(style) {
|
|
|
87
73
|
}
|
|
88
74
|
}
|
|
89
75
|
const NOTEBOOK_DIFF_VIEW_MODE_STORAGE_KEY = 'xtralab:notebook-diff-view-mode';
|
|
76
|
+
/**
|
|
77
|
+
* Read the persisted notebook view mode, defaulting to `'notebook'`.
|
|
78
|
+
*/
|
|
90
79
|
export function readStoredNotebookViewMode() {
|
|
91
80
|
try {
|
|
92
81
|
const raw = window.localStorage.getItem(NOTEBOOK_DIFF_VIEW_MODE_STORAGE_KEY);
|
|
@@ -95,11 +84,13 @@ export function readStoredNotebookViewMode() {
|
|
|
95
84
|
}
|
|
96
85
|
}
|
|
97
86
|
catch (_a) {
|
|
98
|
-
// See readStoredSplitRatio
|
|
99
|
-
// throw on access. The notebook view is the better default anyway.
|
|
87
|
+
// See readStoredSplitRatio.
|
|
100
88
|
}
|
|
101
89
|
return 'notebook';
|
|
102
90
|
}
|
|
91
|
+
/**
|
|
92
|
+
* Persist the notebook view mode to local storage (best-effort).
|
|
93
|
+
*/
|
|
103
94
|
export function writeStoredNotebookViewMode(mode) {
|
|
104
95
|
try {
|
|
105
96
|
window.localStorage.setItem(NOTEBOOK_DIFF_VIEW_MODE_STORAGE_KEY, mode);
|
|
@@ -109,21 +100,15 @@ export function writeStoredNotebookViewMode(mode) {
|
|
|
109
100
|
}
|
|
110
101
|
}
|
|
111
102
|
/**
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
* another `.ipynb`-named file for a notebook is harmless because
|
|
115
|
-
* {@link buildNotebookDiff} validates the JSON shape and we fall back to
|
|
116
|
-
* the file diff if parsing fails.
|
|
103
|
+
* Extension-only check; a false positive is harmless because
|
|
104
|
+
* {@link buildNotebookDiff} validates the JSON and the file diff is the fallback.
|
|
117
105
|
*/
|
|
118
106
|
function isNotebookPath(path) {
|
|
119
107
|
return path.toLowerCase().endsWith('.ipynb');
|
|
120
108
|
}
|
|
121
109
|
/**
|
|
122
|
-
*
|
|
123
|
-
* `
|
|
124
|
-
* `data-jp-theme-light` attribute that JupyterLab sets on `<body>` so the
|
|
125
|
-
* component still works in stripped-down hosts where the token isn't
|
|
126
|
-
* provided (lite, certain notebook configurations, …).
|
|
110
|
+
* Dark-theme check via `IThemeManager`, falling back to the
|
|
111
|
+
* `data-jp-theme-light` body attribute for hosts without the token.
|
|
127
112
|
*/
|
|
128
113
|
export function isDarkTheme(themeManager) {
|
|
129
114
|
if (themeManager !== null && themeManager.theme !== null) {
|
|
@@ -145,14 +130,10 @@ export function isPierreTheme(themeManager) {
|
|
|
145
130
|
export function DiffSurface(props) {
|
|
146
131
|
const { loading, error, isBinary, oldText, newText, newName, oldName, dark, pierreTheme, rendermime, notebookViewMode, diffStyle, onNotebookAvailabilityChange, onFileDiffActiveChange, onMetadataChange, hunkDiscard, onLineAsk, trans } = props;
|
|
147
132
|
const hasContent = !loading && error === null && !isBinary;
|
|
148
|
-
//
|
|
149
|
-
// text/notebook diff; the host passes the two sides as base64 strings in
|
|
150
|
-
// `oldText`/`newText` (the git server base64-encodes binary content).
|
|
133
|
+
// For raster images the host passes both sides as base64 in oldText/newText.
|
|
151
134
|
const imageType = React.useMemo(() => imageDataType(newName), [newName]);
|
|
152
|
-
//
|
|
153
|
-
//
|
|
154
|
-
// {@link diffAcceptRejectHunk} when the user discards a hunk — so hunk
|
|
155
|
-
// indexes line up between what the user clicked and what we mutate.
|
|
135
|
+
// Owning the metadata here keeps hunk indexes aligned between FileDiff
|
|
136
|
+
// and diffAcceptRejectHunk on discard.
|
|
156
137
|
const metadata = React.useMemo(() => {
|
|
157
138
|
if (!hasContent || imageType !== null) {
|
|
158
139
|
return null;
|
|
@@ -164,47 +145,31 @@ export function DiffSurface(props) {
|
|
|
164
145
|
const newFile = { name: newName, contents: newText };
|
|
165
146
|
return parseDiffFromFile(oldFile, newFile);
|
|
166
147
|
}, [hasContent, imageType, oldText, newText, oldName, newName]);
|
|
167
|
-
// Cell-by-cell notebook diff for `.ipynb` files. When non-null the
|
|
168
|
-
// renderer uses a notebook-aware view instead of the line-oriented file
|
|
169
|
-
// diff — kept distinct from {@link metadata} so a notebook whose JSON we
|
|
170
|
-
// cannot parse can fall back to the file diff path.
|
|
171
148
|
const notebookDiff = React.useMemo(() => {
|
|
172
149
|
if (!hasContent || imageType !== null || !isNotebookPath(newName)) {
|
|
173
150
|
return null;
|
|
174
151
|
}
|
|
175
152
|
return buildNotebookDiff({ oldText, newText });
|
|
176
153
|
}, [hasContent, imageType, oldText, newText, newName]);
|
|
177
|
-
// Tell the host whether a rendered notebook view is currently available
|
|
178
|
-
// so it can show/hide its Notebook/JSON toggle.
|
|
179
154
|
React.useEffect(() => {
|
|
180
155
|
onNotebookAvailabilityChange === null || onNotebookAvailabilityChange === void 0 ? void 0 : onNotebookAvailabilityChange(notebookDiff !== null);
|
|
181
156
|
}, [onNotebookAvailabilityChange, notebookDiff]);
|
|
182
|
-
// Report the diff shape so hosts can react (e.g. auto-close on empty).
|
|
183
157
|
React.useEffect(() => {
|
|
184
158
|
onMetadataChange === null || onMetadataChange === void 0 ? void 0 : onMetadataChange({
|
|
185
159
|
hunkCount: metadata !== null ? metadata.hunks.length : null
|
|
186
160
|
});
|
|
187
161
|
}, [onMetadataChange, metadata]);
|
|
188
|
-
//
|
|
189
|
-
//
|
|
190
|
-
// Computed before the early returns below so the file-diff-active effect
|
|
191
|
-
// can depend on it without violating the rules of hooks.
|
|
162
|
+
// Computed before the early returns so the hooks below can depend on
|
|
163
|
+
// them without breaking the rules of hooks.
|
|
192
164
|
const hasNotebookView = notebookDiff !== null;
|
|
193
165
|
const showNotebookView = hasNotebookView && notebookViewMode === 'notebook';
|
|
194
166
|
const showFileDiff = !showNotebookView && metadata !== null;
|
|
195
|
-
// The split vs unified choice only affects the textual/code file diff, so
|
|
196
|
-
// tell the host whether that view is active to drive its Split/Unified
|
|
197
|
-
// toolbar toggle.
|
|
198
167
|
React.useEffect(() => {
|
|
199
168
|
onFileDiffActiveChange === null || onFileDiffActiveChange === void 0 ? void 0 : onFileDiffActiveChange(showFileDiff);
|
|
200
169
|
}, [onFileDiffActiveChange, showFileDiff]);
|
|
201
|
-
// Split ratio for the diff columns: fraction of width given to the
|
|
202
|
-
// deletions (left) pane. Persisted across sessions so the user only
|
|
203
|
-
// dials in their layout once.
|
|
204
170
|
const [leftRatio, setLeftRatio] = React.useState(() => readStoredSplitRatio());
|
|
205
171
|
const wrapperRef = React.useRef(null);
|
|
206
|
-
//
|
|
207
|
-
// attach on pointer-down don't capture a stale value across renders.
|
|
172
|
+
// Drag listeners read the live ratio from a ref to avoid stale captures.
|
|
208
173
|
const leftRatioRef = React.useRef(leftRatio);
|
|
209
174
|
React.useEffect(() => {
|
|
210
175
|
leftRatioRef.current = leftRatio;
|
|
@@ -216,8 +181,6 @@ export function DiffSurface(props) {
|
|
|
216
181
|
}
|
|
217
182
|
return metadata.hunks.map((hunk, hunkIndex) => ({
|
|
218
183
|
side: 'additions',
|
|
219
|
-
// The first line of each hunk in the new file. We anchor the button
|
|
220
|
-
// there so it sits at the top of the hunk's body.
|
|
221
184
|
lineNumber: hunk.additionStart,
|
|
222
185
|
metadata: { hunkIndex }
|
|
223
186
|
}));
|
|
@@ -227,12 +190,8 @@ export function DiffSurface(props) {
|
|
|
227
190
|
return;
|
|
228
191
|
}
|
|
229
192
|
const updated = diffAcceptRejectHunk(metadata, hunkIndex, 'reject');
|
|
230
|
-
//
|
|
231
|
-
//
|
|
232
|
-
// file contents with `/(?<=\n)/` (a lookbehind that keeps the
|
|
233
|
-
// trailing `\n` on each line), so the entries already carry their
|
|
234
|
-
// own line endings — joining with `''` rebuilds the original text
|
|
235
|
-
// verbatim, while joining with `'\n'` would double every newline.
|
|
193
|
+
// additionLines holds the full new file with the hunk reverted; lines keep
|
|
194
|
+
// their trailing `\n` (lookbehind split), so join('') rebuilds it verbatim.
|
|
236
195
|
const text = updated.additionLines.join('');
|
|
237
196
|
try {
|
|
238
197
|
await hunkDiscard.save(text);
|
|
@@ -256,15 +215,11 @@ export function DiffSurface(props) {
|
|
|
256
215
|
if (onLineAsk === undefined) {
|
|
257
216
|
return;
|
|
258
217
|
}
|
|
259
|
-
// Anchor to the gutter "+" button
|
|
260
|
-
// the `@pierre/diffs` shadow root (which is open), parked on the
|
|
261
|
-
// hovered/selected line's number element.
|
|
218
|
+
// Anchor to the just-clicked gutter "+" button inside the library's open shadow root.
|
|
262
219
|
const slot = (_c = (_b = (_a = wrapperRef.current) === null || _a === void 0 ? void 0 : _a.querySelector('diffs-container')) === null || _b === void 0 ? void 0 : _b.shadowRoot) === null || _c === void 0 ? void 0 : _c.querySelector('[data-gutter-utility-slot]');
|
|
263
220
|
onLineAsk(range, slot instanceof Element ? slot.getBoundingClientRect() : null);
|
|
264
221
|
}, [onLineAsk]);
|
|
265
222
|
const handleResizerPointerDown = React.useCallback((event) => {
|
|
266
|
-
// Only react to primary-button drags. Right-click / middle-click on
|
|
267
|
-
// the handle should pass through to the browser default.
|
|
268
223
|
if (event.button !== 0) {
|
|
269
224
|
return;
|
|
270
225
|
}
|
|
@@ -293,8 +248,6 @@ export function DiffSurface(props) {
|
|
|
293
248
|
handle.removeEventListener('pointermove', onPointerMove);
|
|
294
249
|
handle.removeEventListener('pointerup', onPointerEnd);
|
|
295
250
|
handle.removeEventListener('pointercancel', onPointerEnd);
|
|
296
|
-
// Only persist on drag-end so a quick drag isn't followed by a
|
|
297
|
-
// burst of writes for every intermediate position.
|
|
298
251
|
writeStoredSplitRatio(leftRatioRef.current);
|
|
299
252
|
};
|
|
300
253
|
handle.addEventListener('pointermove', onPointerMove);
|
|
@@ -340,19 +293,12 @@ export function DiffSurface(props) {
|
|
|
340
293
|
return (React.createElement("div", { className: "jp-xtralab-DiffWidget-status" }, trans.__('Binary file — diff not supported.')));
|
|
341
294
|
}
|
|
342
295
|
if (imageType !== null) {
|
|
343
|
-
// `oldText`/`newText` carry the two revisions as base64 here. The
|
|
344
|
-
// image view owns its own layout and mode selector, so it does not
|
|
345
|
-
// use the split resizer or the notebook/JSON toggle.
|
|
346
296
|
return (React.createElement("div", { className: "jp-xtralab-DiffWidget-content" },
|
|
347
297
|
React.createElement(ImageDiffView, { reference: oldText, challenger: newText, fileType: imageType, trans: trans })));
|
|
348
298
|
}
|
|
349
299
|
if (!showNotebookView && !showFileDiff) {
|
|
350
300
|
return (React.createElement("div", { className: "jp-xtralab-DiffWidget-status" }, trans.__('No content to diff.')));
|
|
351
301
|
}
|
|
352
|
-
// Custom property set on the diffs-container host. The library's
|
|
353
|
-
// shadow-root rule consumes it via `var(--xtralab-split-cols, …)` (see
|
|
354
|
-
// SPLIT_RESIZE_CSS) and recomputes the column tracks instantly. Only
|
|
355
|
-
// relevant in the file-diff path; the notebook view doesn't use it.
|
|
356
302
|
const leftPercent = leftRatio * 100;
|
|
357
303
|
const hostStyle = {
|
|
358
304
|
'--xtralab-split-cols': `${leftPercent}% ${100 - leftPercent}%`
|
|
@@ -360,29 +306,15 @@ export function DiffSurface(props) {
|
|
|
360
306
|
return (React.createElement("div", { className: "jp-xtralab-DiffWidget-content" },
|
|
361
307
|
React.createElement("div", { ref: wrapperRef, className: "jp-xtralab-DiffWidget-body" },
|
|
362
308
|
React.createElement("div", { className: "jp-xtralab-DiffWidget-scroll" }, showNotebookView && notebookDiff !== null ? (React.createElement(NotebookDiffView, { diff: notebookDiff, dark: dark, pierreTheme: pierreTheme, rendermime: rendermime, trans: trans })) : showFileDiff && metadata !== null ? (React.createElement(FileDiff, { fileDiff: metadata, lineAnnotations: lineAnnotations, renderAnnotation: renderAnnotation, style: hostStyle,
|
|
363
|
-
//
|
|
364
|
-
//
|
|
365
|
-
// `@pierre/diffs/worker/worker.js` file at a URL the worker
|
|
366
|
-
// bootstrap can resolve from, so leaving the pool enabled
|
|
367
|
-
// crashes on instantiation. Running on the main thread is
|
|
368
|
-
// fine for the small files git diffs typically operate on.
|
|
309
|
+
// JupyterLab's federation pipeline can't serve the worker bundle
|
|
310
|
+
// at a resolvable URL, so the pool crashes; run on the main thread.
|
|
369
311
|
disableWorkerPool: true, options: {
|
|
370
312
|
diffStyle,
|
|
371
|
-
// Drop the file header — the tab title already shows the
|
|
372
|
-
// file name and the panel header carries the change
|
|
373
|
-
// context.
|
|
374
313
|
disableFileHeader: true,
|
|
375
314
|
theme: resolveDiffTheme(dark, pierreTheme),
|
|
376
315
|
themeType: dark ? 'dark' : 'light',
|
|
377
|
-
//
|
|
378
|
-
// via the library's `@layer unsafe` channel. Keeping the
|
|
379
|
-
// string constant lets the library short-circuit the
|
|
380
|
-
// re-render path it uses when this option actually
|
|
381
|
-
// changes.
|
|
316
|
+
// Constant string lets the library skip its unsafeCSS re-render path.
|
|
382
317
|
unsafeCSS: SPLIT_RESIZE_CSS,
|
|
383
|
-
// Line selection + the gutter "+" button feed the
|
|
384
|
-
// ask-agent popup; only wired up when a handler exists so
|
|
385
|
-
// a plain diff keeps its passive gutter.
|
|
386
318
|
...(onLineAsk !== undefined
|
|
387
319
|
? {
|
|
388
320
|
enableLineSelection: true,
|
|
@@ -394,10 +326,8 @@ export function DiffSurface(props) {
|
|
|
394
326
|
showFileDiff && diffStyle === 'split' ? (React.createElement("div", { className: "jp-xtralab-DiffWidget-resizer", style: { left: `${leftPercent}%` }, role: "separator", "aria-orientation": "vertical", "aria-valuenow": Math.round(leftPercent), "aria-valuemin": Math.round(MIN_SPLIT_RATIO * 100), "aria-valuemax": Math.round(MAX_SPLIT_RATIO * 100), "aria-label": trans.__('Resize the diff panes'), tabIndex: 0, title: trans.__('Drag to resize the diff panes (double-click to reset)'), onPointerDown: handleResizerPointerDown, onDoubleClick: handleResizerDoubleClick, onKeyDown: handleResizerKeyDown })) : null)));
|
|
395
327
|
}
|
|
396
328
|
/**
|
|
397
|
-
* Segmented Notebook/JSON selector. Hosts mount
|
|
398
|
-
*
|
|
399
|
-
* `jupyterlab-git`-provided diff toolbar) and drive its value/visibility
|
|
400
|
-
* from the same state they pass to {@link DiffSurface}.
|
|
329
|
+
* Segmented Notebook/JSON selector. Hosts mount it into their own toolbar
|
|
330
|
+
* and drive value/visibility from the state they pass to {@link DiffSurface}.
|
|
401
331
|
*/
|
|
402
332
|
export function NotebookViewModeControl(props) {
|
|
403
333
|
const { mode, available, onChange, trans } = props;
|
|
@@ -409,11 +339,9 @@ export function NotebookViewModeControl(props) {
|
|
|
409
339
|
React.createElement("button", { type: "button", role: "tab", "aria-selected": mode === 'json', "data-active": mode === 'json', className: "jp-xtralab-DiffWidget-segmentedButton", onClick: () => onChange('json') }, trans.__('JSON'))));
|
|
410
340
|
}
|
|
411
341
|
/**
|
|
412
|
-
* Split / unified glyphs
|
|
413
|
-
*
|
|
414
|
-
*
|
|
415
|
-
* sprite sheet being injected into the document. `currentColor` lets the
|
|
416
|
-
* segmented-button styling drive the fill (including the active state).
|
|
342
|
+
* Split / unified glyphs inlined from the `@pierre/diffs` icon sprite so
|
|
343
|
+
* the toggle matches the library's docs site without the sprite sheet;
|
|
344
|
+
* `currentColor` lets the button styling drive the fill.
|
|
417
345
|
*/
|
|
418
346
|
function DiffSplitIcon() {
|
|
419
347
|
return (React.createElement("svg", { viewBox: "0 0 16 16", fill: "currentColor", "aria-hidden": "true" },
|
|
@@ -426,11 +354,8 @@ function DiffUnifiedIcon() {
|
|
|
426
354
|
React.createElement("path", { fillRule: "evenodd", d: "M14 0a2 2 0 0 1 2 2v5.5H0V2a2 2 0 0 1 2-2zM6.5 3.5a.5.5 0 0 0 0 1h3a.5.5 0 0 0 0-1z", clipRule: "evenodd", opacity: ".4" })));
|
|
427
355
|
}
|
|
428
356
|
/**
|
|
429
|
-
* Segmented Split/Unified selector
|
|
430
|
-
*
|
|
431
|
-
* the same state they pass to {@link DiffSurface}. Only meaningful while the
|
|
432
|
-
* textual/code file diff is the active view, so `available` mirrors the
|
|
433
|
-
* surface's `onFileDiffActiveChange`.
|
|
357
|
+
* Segmented Split/Unified selector; mirrors {@link NotebookViewModeControl}.
|
|
358
|
+
* `available` mirrors the surface's `onFileDiffActiveChange`.
|
|
434
359
|
*/
|
|
435
360
|
export function DiffStyleControl(props) {
|
|
436
361
|
const { diffStyle, available, onChange, trans } = props;
|
package/lib/git/diffWidget.d.ts
CHANGED
|
@@ -14,22 +14,44 @@ export { DIFF_WIDGET_CSS_CLASS };
|
|
|
14
14
|
* `Git.Diff.IModel` plus optional xtralab-only metadata.
|
|
15
15
|
*/
|
|
16
16
|
export interface IXtralabDiffModel extends Git.Diff.IModel {
|
|
17
|
+
/**
|
|
18
|
+
* Whether the file is binary, so no text contents are fetched.
|
|
19
|
+
*/
|
|
17
20
|
isBinary?: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Whether hunks may be discarded; when absent, a working-tree heuristic decides.
|
|
23
|
+
*/
|
|
18
24
|
canDiscard?: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* The old-side path when the diff represents a rename.
|
|
27
|
+
*/
|
|
19
28
|
oldFilename?: string;
|
|
20
29
|
}
|
|
21
30
|
/**
|
|
22
31
|
* Application-level services the diff model does not carry.
|
|
23
32
|
*/
|
|
24
33
|
export interface IXtralabDiffContext {
|
|
34
|
+
/**
|
|
35
|
+
* The contents manager used to save hunk-discard results.
|
|
36
|
+
*/
|
|
25
37
|
contentsManager: Contents.IManager;
|
|
38
|
+
/**
|
|
39
|
+
* The rendermime registry for rendered notebook diffs, or `null` to
|
|
40
|
+
* force the textual fallback.
|
|
41
|
+
*/
|
|
26
42
|
rendermime: IRenderMimeRegistry | null;
|
|
43
|
+
/**
|
|
44
|
+
* The theme manager used to track theme changes, or `null` to watch
|
|
45
|
+
* the body attribute instead.
|
|
46
|
+
*/
|
|
27
47
|
themeManager: IThemeManager | null;
|
|
28
48
|
/**
|
|
29
|
-
*
|
|
30
|
-
* "ask an agent about these lines" gutter button.
|
|
49
|
+
* When available, diff line selections get an "ask an agent" gutter button.
|
|
31
50
|
*/
|
|
32
51
|
askAgent: IAskAgent | null;
|
|
52
|
+
/**
|
|
53
|
+
* The application translation bundle.
|
|
54
|
+
*/
|
|
33
55
|
trans: TranslationBundle;
|
|
34
56
|
}
|
|
35
57
|
/**
|
|
@@ -37,6 +59,9 @@ export interface IXtralabDiffContext {
|
|
|
37
59
|
*/
|
|
38
60
|
export declare class XtralabDiffWidget extends ReactWidget implements Git.Diff.IDiffWidget {
|
|
39
61
|
constructor(model: Git.Diff.IModel, context: IXtralabDiffContext);
|
|
62
|
+
/**
|
|
63
|
+
* The git diff model being rendered.
|
|
64
|
+
*/
|
|
40
65
|
get model(): Git.Diff.IModel;
|
|
41
66
|
/**
|
|
42
67
|
* Swap the rendered model when the launcher reuses its preview tab.
|
|
@@ -54,30 +79,81 @@ export declare class XtralabDiffWidget extends ReactWidget implements Git.Diff.I
|
|
|
54
79
|
* Re-pull both sides of the model and re-render.
|
|
55
80
|
*/
|
|
56
81
|
refresh(): Promise<void>;
|
|
82
|
+
/**
|
|
83
|
+
* The current rendered-vs-JSON choice for notebook diffs.
|
|
84
|
+
*/
|
|
57
85
|
get notebookViewMode(): NotebookDiffViewMode;
|
|
86
|
+
/**
|
|
87
|
+
* Set the notebook view mode and persist it.
|
|
88
|
+
*/
|
|
58
89
|
setNotebookViewMode(mode: NotebookDiffViewMode): void;
|
|
90
|
+
/**
|
|
91
|
+
* A signal emitted when the notebook view mode changes.
|
|
92
|
+
*/
|
|
59
93
|
get notebookViewModeChanged(): ISignal<this, NotebookDiffViewMode>;
|
|
94
|
+
/**
|
|
95
|
+
* Whether a rendered notebook view is currently available.
|
|
96
|
+
*/
|
|
60
97
|
get hasNotebookView(): boolean;
|
|
98
|
+
/**
|
|
99
|
+
* Set whether a rendered notebook view is available.
|
|
100
|
+
*/
|
|
61
101
|
setHasNotebookView(value: boolean): void;
|
|
102
|
+
/**
|
|
103
|
+
* A signal emitted when rendered-notebook availability changes.
|
|
104
|
+
*/
|
|
62
105
|
get hasNotebookViewChanged(): ISignal<this, boolean>;
|
|
106
|
+
/**
|
|
107
|
+
* The current split/unified layout for textual file diffs.
|
|
108
|
+
*/
|
|
63
109
|
get diffStyle(): DiffStyle;
|
|
110
|
+
/**
|
|
111
|
+
* Set the diff style and persist it.
|
|
112
|
+
*/
|
|
64
113
|
setDiffStyle(style: DiffStyle): void;
|
|
114
|
+
/**
|
|
115
|
+
* A signal emitted when the diff style changes.
|
|
116
|
+
*/
|
|
65
117
|
get diffStyleChanged(): ISignal<this, DiffStyle>;
|
|
66
118
|
/**
|
|
67
119
|
* Whether the Split/Unified toolbar selector currently applies.
|
|
68
120
|
*/
|
|
69
121
|
get fileDiffActive(): boolean;
|
|
122
|
+
/**
|
|
123
|
+
* Set whether the textual file diff is the active view.
|
|
124
|
+
*/
|
|
70
125
|
setFileDiffActive(value: boolean): void;
|
|
126
|
+
/**
|
|
127
|
+
* A signal emitted when {@link fileDiffActive} changes.
|
|
128
|
+
*/
|
|
71
129
|
get fileDiffActiveChanged(): ISignal<this, boolean>;
|
|
72
130
|
/**
|
|
73
131
|
* Emitted when a post-discard reload leaves the diff with no hunks.
|
|
74
132
|
*/
|
|
75
133
|
get emptied(): ISignal<this, void>;
|
|
134
|
+
/**
|
|
135
|
+
* Emit the {@link emptied} signal.
|
|
136
|
+
*/
|
|
76
137
|
notifyEmptied(): void;
|
|
138
|
+
/**
|
|
139
|
+
* Resolve and clear the pending `refresh()` promise, if any.
|
|
140
|
+
*/
|
|
77
141
|
settleRefresh(): void;
|
|
142
|
+
/**
|
|
143
|
+
* Dispose of the resources held by the widget.
|
|
144
|
+
*/
|
|
78
145
|
dispose(): void;
|
|
146
|
+
/**
|
|
147
|
+
* A counter incremented on each `refresh()` to trigger a content re-fetch.
|
|
148
|
+
*/
|
|
79
149
|
get reloadNonce(): number;
|
|
150
|
+
/**
|
|
151
|
+
* The application-level services used by the rendered diff.
|
|
152
|
+
*/
|
|
80
153
|
get context(): IXtralabDiffContext;
|
|
154
|
+
/**
|
|
155
|
+
* Render the diff view for the current model.
|
|
156
|
+
*/
|
|
81
157
|
protected render(): React.ReactElement;
|
|
82
158
|
private _model;
|
|
83
159
|
private _context;
|
|
@@ -97,6 +173,9 @@ export declare class XtralabDiffWidget extends ReactWidget implements Git.Diff.I
|
|
|
97
173
|
* Structural toolbar type shared across host package boundaries.
|
|
98
174
|
*/
|
|
99
175
|
interface IDiffToolbar {
|
|
176
|
+
/**
|
|
177
|
+
* Add an item to the toolbar under the given name.
|
|
178
|
+
*/
|
|
100
179
|
addItem(name: string, widget: Widget): boolean;
|
|
101
180
|
}
|
|
102
181
|
/**
|