xtralab 0.15.0 → 0.15.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/README.md +65 -30
- 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.js +15 -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 +29 -19
- package/lib/fileBrowser/commands.js +83 -97
- package/lib/fileBrowser/contents.d.ts +3 -0
- package/lib/fileBrowser/dragAndDrop.d.ts +17 -4
- package/lib/fileBrowser/dragAndDrop.js +2 -7
- package/lib/fileBrowser/fileBrowser.d.ts +19 -9
- package/lib/fileBrowser/fileBrowser.js +70 -222
- package/lib/fileBrowser/gitStatus.d.ts +16 -10
- package/lib/fileBrowser/gitStatus.js +31 -30
- 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 +2 -4
- package/lib/fileBrowser/widget.d.ts +141 -48
- package/lib/fileBrowser/widget.js +102 -4
- 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 +45 -5
- package/lib/git/commands.js +20 -13
- package/lib/git/diffModel.js +4 -0
- package/lib/git/diffPreferences.d.ts +90 -0
- package/lib/git/diffPreferences.js +107 -0
- package/lib/git/diffProvider.js +10 -2
- package/lib/git/diffSurface.d.ts +64 -63
- package/lib/git/diffSurface.js +72 -213
- package/lib/git/diffTheme.d.ts +7 -0
- package/lib/git/diffTheme.js +23 -0
- package/lib/git/diffWidget.d.ts +70 -14
- package/lib/git/diffWidget.js +100 -94
- package/lib/git/imageDiff.d.ts +14 -6
- package/lib/git/imageDiff.js +19 -75
- package/lib/git/index.d.ts +0 -3
- package/lib/git/index.js +44 -10
- package/lib/git/notebookDiff.d.ts +110 -33
- package/lib/git/notebookDiff.js +55 -197
- 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 +0 -9
- package/lib/launcher/agents.d.ts +55 -51
- package/lib/launcher/agents.js +15 -57
- 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 +5 -39
- 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/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 -7
- package/lib/sidebar/index.js +5 -12
- 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 -35
- package/lib/terminals/index.js +12 -101
- 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 +43 -13
- package/lib/terminals/widget.js +33 -18
- 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 +5 -3
- package/schema/git-diff-preferences.json +42 -0
- 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 +15 -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 +119 -96
- package/src/fileBrowser/contents.ts +3 -0
- package/src/fileBrowser/dragAndDrop.ts +17 -7
- package/src/fileBrowser/fileBrowser.tsx +86 -230
- package/src/fileBrowser/gitStatus.ts +36 -33
- package/src/fileBrowser/gitignore.ts +4 -25
- package/src/fileBrowser/icons.ts +25 -80
- package/src/fileBrowser/index.ts +2 -4
- package/src/fileBrowser/widget.tsx +171 -50
- 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 +83 -11
- package/src/git/diffModel.ts +25 -0
- package/src/git/diffPreferences.ts +192 -0
- package/src/git/diffProvider.tsx +11 -2
- package/src/git/diffSurface.tsx +165 -286
- package/src/git/diffTheme.ts +24 -0
- package/src/git/diffWidget.tsx +194 -134
- package/src/git/imageDiff.tsx +56 -84
- package/src/git/index.ts +54 -10
- package/src/git/notebookDiff.tsx +214 -240
- package/src/git/tokens.ts +73 -31
- package/src/highlight/index.ts +10 -41
- package/src/index.ts +0 -9
- package/src/launcher/agents.ts +64 -95
- 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 +5 -39
- package/src/launcher/index.ts +12 -55
- package/src/launcher/invocation.ts +7 -22
- package/src/launcher/registry.ts +9 -7
- 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 +20 -12
- 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 +12 -101
- package/src/terminals/model.ts +130 -246
- package/src/terminals/tokens.ts +11 -22
- package/src/terminals/widget.tsx +48 -31
- 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 +9 -45
- package/style/chrome.css +108 -308
- package/style/commandBar.css +4 -20
- package/style/customPanel.css +1 -4
- package/style/git.css +26 -186
- package/style/highlight.css +1 -3
- 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 +6 -53
- package/style/topBar.css +2 -22
- package/style/walkthrough.css +0 -8
package/lib/git/diffSurface.js
CHANGED
|
@@ -1,129 +1,33 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { undoIcon } from '@jupyterlab/ui-components';
|
|
3
3
|
import { FileDiff } from '@pierre/diffs/react';
|
|
4
|
+
import { IconDiffSplit, IconDiffUnified, IconWordWrap } from '@pierre/icons';
|
|
4
5
|
import { diffAcceptRejectHunk, parseDiffFromFile } from '@pierre/diffs';
|
|
5
6
|
import { ImageDiffView, imageDataType } from './imageDiff';
|
|
6
7
|
import { buildNotebookDiff, NotebookDiffView } from './notebookDiff';
|
|
7
|
-
import {
|
|
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
|
-
*/
|
|
8
|
+
import { DEFAULT_SPLIT_RATIO, MAX_SPLIT_RATIO, MIN_SPLIT_RATIO } from './diffPreferences';
|
|
9
|
+
import { DIFF_SCROLLBAR_CSS, resolveDiffTheme } from './diffTheme';
|
|
12
10
|
export const DIFF_WIDGET_CSS_CLASS = 'jp-xtralab-DiffWidget';
|
|
13
11
|
/**
|
|
14
|
-
* `
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
|
|
18
|
-
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
|
-
const MIN_SPLIT_RATIO = 0.1;
|
|
25
|
-
const MAX_SPLIT_RATIO = 0.9;
|
|
26
|
-
const DEFAULT_SPLIT_RATIO = 0.5;
|
|
27
|
-
/**
|
|
28
|
-
* CSS injected via the `@pierre/diffs` `unsafeCSS` option. The library
|
|
29
|
-
* places it inside the shadow root under `@layer unsafe`, which beats
|
|
30
|
-
* the library's own `@layer base` rule that hardcodes
|
|
31
|
-
* `grid-template-columns: 1fr 1fr` on the split-mode container.
|
|
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.
|
|
12
|
+
* Injected via the `unsafeCSS` option into the shadow root's `@layer
|
|
13
|
+
* unsafe`, beating the library's base rule that hardcodes `1fr 1fr`. Reads
|
|
14
|
+
* `--xtralab-split-cols` set on the host — custom properties cross the
|
|
15
|
+
* shadow boundary, so resizing needs no re-render.
|
|
37
16
|
*/
|
|
38
17
|
const SPLIT_RESIZE_CSS = `pre[data-diff-type="split"][data-overflow="scroll"] {
|
|
39
18
|
grid-template-columns: var(--xtralab-split-cols, 1fr 1fr);
|
|
40
19
|
}`;
|
|
41
|
-
|
|
42
|
-
try {
|
|
43
|
-
const raw = window.localStorage.getItem(SPLIT_RATIO_STORAGE_KEY);
|
|
44
|
-
if (raw === null) {
|
|
45
|
-
return DEFAULT_SPLIT_RATIO;
|
|
46
|
-
}
|
|
47
|
-
const parsed = Number.parseFloat(raw);
|
|
48
|
-
if (Number.isFinite(parsed) &&
|
|
49
|
-
parsed >= MIN_SPLIT_RATIO &&
|
|
50
|
-
parsed <= MAX_SPLIT_RATIO) {
|
|
51
|
-
return parsed;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
catch (_a) {
|
|
55
|
-
// localStorage may throw in privacy mode or sandboxed contexts. Falling
|
|
56
|
-
// back to the default is fine — the user can resize again on this run.
|
|
57
|
-
}
|
|
58
|
-
return DEFAULT_SPLIT_RATIO;
|
|
59
|
-
}
|
|
60
|
-
function writeStoredSplitRatio(ratio) {
|
|
61
|
-
try {
|
|
62
|
-
window.localStorage.setItem(SPLIT_RATIO_STORAGE_KEY, ratio.toString());
|
|
63
|
-
}
|
|
64
|
-
catch (_a) {
|
|
65
|
-
// See readStoredSplitRatio — best-effort persistence.
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
const DIFF_STYLE_STORAGE_KEY = 'xtralab:diff-style';
|
|
69
|
-
export function readStoredDiffStyle() {
|
|
70
|
-
try {
|
|
71
|
-
const raw = window.localStorage.getItem(DIFF_STYLE_STORAGE_KEY);
|
|
72
|
-
if (raw === 'split' || raw === 'unified') {
|
|
73
|
-
return raw;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
catch (_a) {
|
|
77
|
-
// See readStoredSplitRatio — privacy-mode / sandboxed contexts can throw.
|
|
78
|
-
}
|
|
79
|
-
return 'split';
|
|
80
|
-
}
|
|
81
|
-
export function writeStoredDiffStyle(style) {
|
|
82
|
-
try {
|
|
83
|
-
window.localStorage.setItem(DIFF_STYLE_STORAGE_KEY, style);
|
|
84
|
-
}
|
|
85
|
-
catch (_a) {
|
|
86
|
-
// Best-effort.
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
const NOTEBOOK_DIFF_VIEW_MODE_STORAGE_KEY = 'xtralab:notebook-diff-view-mode';
|
|
90
|
-
export function readStoredNotebookViewMode() {
|
|
91
|
-
try {
|
|
92
|
-
const raw = window.localStorage.getItem(NOTEBOOK_DIFF_VIEW_MODE_STORAGE_KEY);
|
|
93
|
-
if (raw === 'json' || raw === 'notebook') {
|
|
94
|
-
return raw;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
catch (_a) {
|
|
98
|
-
// See readStoredSplitRatio — privacy-mode / sandboxed contexts can
|
|
99
|
-
// throw on access. The notebook view is the better default anyway.
|
|
100
|
-
}
|
|
101
|
-
return 'notebook';
|
|
102
|
-
}
|
|
103
|
-
export function writeStoredNotebookViewMode(mode) {
|
|
104
|
-
try {
|
|
105
|
-
window.localStorage.setItem(NOTEBOOK_DIFF_VIEW_MODE_STORAGE_KEY, mode);
|
|
106
|
-
}
|
|
107
|
-
catch (_a) {
|
|
108
|
-
// Best-effort.
|
|
109
|
-
}
|
|
110
|
-
}
|
|
20
|
+
const DIFF_SURFACE_CSS = `${SPLIT_RESIZE_CSS}\n${DIFF_SCROLLBAR_CSS}`;
|
|
111
21
|
/**
|
|
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.
|
|
22
|
+
* Extension-only check; a false positive is harmless because
|
|
23
|
+
* {@link buildNotebookDiff} validates the JSON and the file diff is the fallback.
|
|
117
24
|
*/
|
|
118
25
|
function isNotebookPath(path) {
|
|
119
26
|
return path.toLowerCase().endsWith('.ipynb');
|
|
120
27
|
}
|
|
121
28
|
/**
|
|
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, …).
|
|
29
|
+
* Dark-theme check via `IThemeManager`, falling back to the
|
|
30
|
+
* `data-jp-theme-light` body attribute for hosts without the token.
|
|
127
31
|
*/
|
|
128
32
|
export function isDarkTheme(themeManager) {
|
|
129
33
|
if (themeManager !== null && themeManager.theme !== null) {
|
|
@@ -143,16 +47,12 @@ export function isPierreTheme(themeManager) {
|
|
|
143
47
|
* Shared renderer for text, notebook and image diffs.
|
|
144
48
|
*/
|
|
145
49
|
export function DiffSurface(props) {
|
|
146
|
-
const { loading, error, isBinary, oldText, newText, newName, oldName, dark, pierreTheme, rendermime, notebookViewMode, diffStyle, onNotebookAvailabilityChange, onFileDiffActiveChange, onMetadataChange, hunkDiscard, onLineAsk, trans } = props;
|
|
50
|
+
const { loading, error, isBinary, oldText, newText, newName, oldName, dark, pierreTheme, rendermime, notebookViewMode, diffStyle, lineWrap, splitRatio, onSplitRatioChange, imageViewMode, onImageViewModeChange, onNotebookAvailabilityChange, onFileDiffActiveChange, onMetadataChange, hunkDiscard, onLineAsk, trans } = props;
|
|
147
51
|
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).
|
|
52
|
+
// For raster images the host passes both sides as base64 in oldText/newText.
|
|
151
53
|
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.
|
|
54
|
+
// Owning the metadata here keeps hunk indexes aligned between FileDiff
|
|
55
|
+
// and diffAcceptRejectHunk on discard.
|
|
156
56
|
const metadata = React.useMemo(() => {
|
|
157
57
|
if (!hasContent || imageType !== null) {
|
|
158
58
|
return null;
|
|
@@ -164,47 +64,35 @@ export function DiffSurface(props) {
|
|
|
164
64
|
const newFile = { name: newName, contents: newText };
|
|
165
65
|
return parseDiffFromFile(oldFile, newFile);
|
|
166
66
|
}, [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
67
|
const notebookDiff = React.useMemo(() => {
|
|
172
68
|
if (!hasContent || imageType !== null || !isNotebookPath(newName)) {
|
|
173
69
|
return null;
|
|
174
70
|
}
|
|
175
71
|
return buildNotebookDiff({ oldText, newText });
|
|
176
72
|
}, [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
73
|
React.useEffect(() => {
|
|
180
74
|
onNotebookAvailabilityChange === null || onNotebookAvailabilityChange === void 0 ? void 0 : onNotebookAvailabilityChange(notebookDiff !== null);
|
|
181
75
|
}, [onNotebookAvailabilityChange, notebookDiff]);
|
|
182
|
-
// Report the diff shape so hosts can react (e.g. auto-close on empty).
|
|
183
76
|
React.useEffect(() => {
|
|
184
77
|
onMetadataChange === null || onMetadataChange === void 0 ? void 0 : onMetadataChange({
|
|
185
78
|
hunkCount: metadata !== null ? metadata.hunks.length : null
|
|
186
79
|
});
|
|
187
80
|
}, [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.
|
|
81
|
+
// Computed before the early returns so the hooks below can depend on
|
|
82
|
+
// them without breaking the rules of hooks.
|
|
192
83
|
const hasNotebookView = notebookDiff !== null;
|
|
193
84
|
const showNotebookView = hasNotebookView && notebookViewMode === 'notebook';
|
|
194
85
|
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
86
|
React.useEffect(() => {
|
|
199
87
|
onFileDiffActiveChange === null || onFileDiffActiveChange === void 0 ? void 0 : onFileDiffActiveChange(showFileDiff);
|
|
200
88
|
}, [onFileDiffActiveChange, showFileDiff]);
|
|
201
|
-
//
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
89
|
+
// Local while dragging; the host hears the ratio when a drag ends.
|
|
90
|
+
const [leftRatio, setLeftRatio] = React.useState(splitRatio);
|
|
91
|
+
React.useEffect(() => {
|
|
92
|
+
setLeftRatio(splitRatio);
|
|
93
|
+
}, [splitRatio]);
|
|
205
94
|
const wrapperRef = React.useRef(null);
|
|
206
|
-
//
|
|
207
|
-
// attach on pointer-down don't capture a stale value across renders.
|
|
95
|
+
// Drag listeners read the live ratio from a ref to avoid stale captures.
|
|
208
96
|
const leftRatioRef = React.useRef(leftRatio);
|
|
209
97
|
React.useEffect(() => {
|
|
210
98
|
leftRatioRef.current = leftRatio;
|
|
@@ -216,8 +104,6 @@ export function DiffSurface(props) {
|
|
|
216
104
|
}
|
|
217
105
|
return metadata.hunks.map((hunk, hunkIndex) => ({
|
|
218
106
|
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
107
|
lineNumber: hunk.additionStart,
|
|
222
108
|
metadata: { hunkIndex }
|
|
223
109
|
}));
|
|
@@ -227,12 +113,8 @@ export function DiffSurface(props) {
|
|
|
227
113
|
return;
|
|
228
114
|
}
|
|
229
115
|
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.
|
|
116
|
+
// additionLines holds the full new file with the hunk reverted; lines keep
|
|
117
|
+
// their trailing `\n` (lookbehind split), so join('') rebuilds it verbatim.
|
|
236
118
|
const text = updated.additionLines.join('');
|
|
237
119
|
try {
|
|
238
120
|
await hunkDiscard.save(text);
|
|
@@ -256,15 +138,11 @@ export function DiffSurface(props) {
|
|
|
256
138
|
if (onLineAsk === undefined) {
|
|
257
139
|
return;
|
|
258
140
|
}
|
|
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.
|
|
141
|
+
// Anchor to the just-clicked gutter "+" button inside the library's open shadow root.
|
|
262
142
|
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
143
|
onLineAsk(range, slot instanceof Element ? slot.getBoundingClientRect() : null);
|
|
264
144
|
}, [onLineAsk]);
|
|
265
145
|
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
146
|
if (event.button !== 0) {
|
|
269
147
|
return;
|
|
270
148
|
}
|
|
@@ -293,18 +171,16 @@ export function DiffSurface(props) {
|
|
|
293
171
|
handle.removeEventListener('pointermove', onPointerMove);
|
|
294
172
|
handle.removeEventListener('pointerup', onPointerEnd);
|
|
295
173
|
handle.removeEventListener('pointercancel', onPointerEnd);
|
|
296
|
-
|
|
297
|
-
// burst of writes for every intermediate position.
|
|
298
|
-
writeStoredSplitRatio(leftRatioRef.current);
|
|
174
|
+
onSplitRatioChange(leftRatioRef.current);
|
|
299
175
|
};
|
|
300
176
|
handle.addEventListener('pointermove', onPointerMove);
|
|
301
177
|
handle.addEventListener('pointerup', onPointerEnd);
|
|
302
178
|
handle.addEventListener('pointercancel', onPointerEnd);
|
|
303
|
-
}, []);
|
|
179
|
+
}, [onSplitRatioChange]);
|
|
304
180
|
const handleResizerDoubleClick = React.useCallback(() => {
|
|
305
181
|
setLeftRatio(DEFAULT_SPLIT_RATIO);
|
|
306
|
-
|
|
307
|
-
}, []);
|
|
182
|
+
onSplitRatioChange(DEFAULT_SPLIT_RATIO);
|
|
183
|
+
}, [onSplitRatioChange]);
|
|
308
184
|
const handleResizerKeyDown = React.useCallback((event) => {
|
|
309
185
|
const step = event.shiftKey ? 0.1 : 0.01;
|
|
310
186
|
let next = null;
|
|
@@ -328,8 +204,8 @@ export function DiffSurface(props) {
|
|
|
328
204
|
event.preventDefault();
|
|
329
205
|
const clamped = Math.max(MIN_SPLIT_RATIO, Math.min(MAX_SPLIT_RATIO, next));
|
|
330
206
|
setLeftRatio(clamped);
|
|
331
|
-
|
|
332
|
-
}, []);
|
|
207
|
+
onSplitRatioChange(clamped);
|
|
208
|
+
}, [onSplitRatioChange]);
|
|
333
209
|
if (loading) {
|
|
334
210
|
return (React.createElement("div", { className: "jp-xtralab-DiffWidget-status" }, trans.__('Loading diff…')));
|
|
335
211
|
}
|
|
@@ -340,49 +216,32 @@ export function DiffSurface(props) {
|
|
|
340
216
|
return (React.createElement("div", { className: "jp-xtralab-DiffWidget-status" }, trans.__('Binary file — diff not supported.')));
|
|
341
217
|
}
|
|
342
218
|
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
219
|
return (React.createElement("div", { className: "jp-xtralab-DiffWidget-content" },
|
|
347
|
-
React.createElement(ImageDiffView, { reference: oldText, challenger: newText, fileType: imageType, trans: trans })));
|
|
220
|
+
React.createElement(ImageDiffView, { reference: oldText, challenger: newText, fileType: imageType, mode: imageViewMode, onModeChange: onImageViewModeChange, trans: trans })));
|
|
348
221
|
}
|
|
349
222
|
if (!showNotebookView && !showFileDiff) {
|
|
350
223
|
return (React.createElement("div", { className: "jp-xtralab-DiffWidget-status" }, trans.__('No content to diff.')));
|
|
351
224
|
}
|
|
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
225
|
const leftPercent = leftRatio * 100;
|
|
226
|
+
// The wrapped split grid sizes its gutter tracks to their content, so a
|
|
227
|
+
// percentage split cannot line up with the handle.
|
|
228
|
+
const showResizer = showFileDiff && diffStyle === 'split' && !lineWrap;
|
|
357
229
|
const hostStyle = {
|
|
358
230
|
'--xtralab-split-cols': `${leftPercent}% ${100 - leftPercent}%`
|
|
359
231
|
};
|
|
360
232
|
return (React.createElement("div", { className: "jp-xtralab-DiffWidget-content" },
|
|
361
233
|
React.createElement("div", { ref: wrapperRef, className: "jp-xtralab-DiffWidget-body" },
|
|
362
234
|
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.
|
|
235
|
+
// JupyterLab's federation pipeline can't serve the worker bundle
|
|
236
|
+
// at a resolvable URL, so the pool crashes; run on the main thread.
|
|
369
237
|
disableWorkerPool: true, options: {
|
|
370
238
|
diffStyle,
|
|
371
|
-
|
|
372
|
-
// file name and the panel header carries the change
|
|
373
|
-
// context.
|
|
239
|
+
overflow: lineWrap ? 'wrap' : 'scroll',
|
|
374
240
|
disableFileHeader: true,
|
|
375
241
|
theme: resolveDiffTheme(dark, pierreTheme),
|
|
376
242
|
themeType: dark ? 'dark' : 'light',
|
|
377
|
-
//
|
|
378
|
-
|
|
379
|
-
// string constant lets the library short-circuit the
|
|
380
|
-
// re-render path it uses when this option actually
|
|
381
|
-
// changes.
|
|
382
|
-
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.
|
|
243
|
+
// Constant string lets the library skip its unsafeCSS re-render path.
|
|
244
|
+
unsafeCSS: DIFF_SURFACE_CSS,
|
|
386
245
|
...(onLineAsk !== undefined
|
|
387
246
|
? {
|
|
388
247
|
enableLineSelection: true,
|
|
@@ -391,13 +250,11 @@ export function DiffSurface(props) {
|
|
|
391
250
|
}
|
|
392
251
|
: {})
|
|
393
252
|
} })) : null),
|
|
394
|
-
|
|
253
|
+
showResizer ? (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
254
|
}
|
|
396
255
|
/**
|
|
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}.
|
|
256
|
+
* Segmented Notebook/JSON selector. Hosts mount it into their own toolbar
|
|
257
|
+
* and drive value/visibility from the state they pass to {@link DiffSurface}.
|
|
401
258
|
*/
|
|
402
259
|
export function NotebookViewModeControl(props) {
|
|
403
260
|
const { mode, available, onChange, trans } = props;
|
|
@@ -409,37 +266,39 @@ export function NotebookViewModeControl(props) {
|
|
|
409
266
|
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
267
|
}
|
|
411
268
|
/**
|
|
412
|
-
* Split
|
|
413
|
-
*
|
|
414
|
-
*
|
|
415
|
-
* sprite sheet being injected into the document. `currentColor` lets the
|
|
416
|
-
* segmented-button styling drive the fill (including the active state).
|
|
417
|
-
*/
|
|
418
|
-
function DiffSplitIcon() {
|
|
419
|
-
return (React.createElement("svg", { viewBox: "0 0 16 16", fill: "currentColor", "aria-hidden": "true" },
|
|
420
|
-
React.createElement("path", { d: "M14 0H8.5v16H14a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2m-1.5 6.5v1h1a.5.5 0 0 1 0 1h-1v1a.5.5 0 0 1-1 0v-1h-1a.5.5 0 0 1 0-1h1v-1a.5.5 0 0 1 1 0" }),
|
|
421
|
-
React.createElement("path", { d: "M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h5.5V0zm.5 7.5h3a.5.5 0 0 1 0 1h-3a.5.5 0 0 1 0-1", opacity: ".3" })));
|
|
422
|
-
}
|
|
423
|
-
function DiffUnifiedIcon() {
|
|
424
|
-
return (React.createElement("svg", { viewBox: "0 0 16 16", fill: "currentColor", "aria-hidden": "true" },
|
|
425
|
-
React.createElement("path", { fillRule: "evenodd", d: "M16 14a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V8.5h16zm-8-4a.5.5 0 0 0-.5.5v1h-1a.5.5 0 0 0 0 1h1v1a.5.5 0 0 0 1 0v-1h1a.5.5 0 0 0 0-1h-1v-1A.5.5 0 0 0 8 10", clipRule: "evenodd" }),
|
|
426
|
-
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
|
-
}
|
|
428
|
-
/**
|
|
429
|
-
* Segmented Split/Unified selector. Mirrors {@link NotebookViewModeControl}:
|
|
430
|
-
* hosts mount it into their own toolbar and drive its value/visibility from
|
|
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`.
|
|
269
|
+
* Split/Unified selector: two segmented buttons, or with `control: 'toggle'`
|
|
270
|
+
* one button that shows the layout it switches to.
|
|
271
|
+
* `available` mirrors the surface's `onFileDiffActiveChange`.
|
|
434
272
|
*/
|
|
435
273
|
export function DiffStyleControl(props) {
|
|
436
|
-
const { diffStyle, available, onChange, trans } = props;
|
|
274
|
+
const { diffStyle, control, available, onChange, trans } = props;
|
|
437
275
|
if (!available) {
|
|
438
276
|
return React.createElement(React.Fragment, null);
|
|
439
277
|
}
|
|
278
|
+
if (control === 'toggle') {
|
|
279
|
+
const next = diffStyle === 'split' ? 'unified' : 'split';
|
|
280
|
+
const label = next === 'split'
|
|
281
|
+
? trans.__('Switch to split view')
|
|
282
|
+
: trans.__('Switch to unified view');
|
|
283
|
+
return (React.createElement("div", { className: "jp-xtralab-DiffWidget-segmented" },
|
|
284
|
+
React.createElement("button", { type: "button", className: "jp-xtralab-DiffWidget-segmentedButton jp-xtralab-DiffWidget-segmentedButton-icon", title: label, "aria-label": label, onClick: () => onChange(next) }, next === 'split' ? React.createElement(IconDiffSplit, null) : React.createElement(IconDiffUnified, null))));
|
|
285
|
+
}
|
|
440
286
|
return (React.createElement("div", { className: "jp-xtralab-DiffWidget-segmented", role: "tablist", "aria-label": trans.__('Diff view style') },
|
|
441
287
|
React.createElement("button", { type: "button", role: "tab", "aria-selected": diffStyle === 'split', "data-active": diffStyle === 'split', className: "jp-xtralab-DiffWidget-segmentedButton jp-xtralab-DiffWidget-segmentedButton-icon", title: trans.__('Split (side-by-side) view'), "aria-label": trans.__('Split view'), onClick: () => onChange('split') },
|
|
442
|
-
React.createElement(
|
|
288
|
+
React.createElement(IconDiffSplit, null)),
|
|
443
289
|
React.createElement("button", { type: "button", role: "tab", "aria-selected": diffStyle === 'unified', "data-active": diffStyle === 'unified', className: "jp-xtralab-DiffWidget-segmentedButton jp-xtralab-DiffWidget-segmentedButton-icon", title: trans.__('Unified (inline) view'), "aria-label": trans.__('Unified view'), onClick: () => onChange('unified') },
|
|
444
|
-
React.createElement(
|
|
290
|
+
React.createElement(IconDiffUnified, null))));
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Line-wrap toggle styled as a one-button segmented control.
|
|
294
|
+
* `available` mirrors the surface's `onFileDiffActiveChange`.
|
|
295
|
+
*/
|
|
296
|
+
export function LineWrapControl(props) {
|
|
297
|
+
const { lineWrap, available, onChange, trans } = props;
|
|
298
|
+
if (!available) {
|
|
299
|
+
return React.createElement(React.Fragment, null);
|
|
300
|
+
}
|
|
301
|
+
return (React.createElement("div", { className: "jp-xtralab-DiffWidget-segmented" },
|
|
302
|
+
React.createElement("button", { type: "button", "aria-pressed": lineWrap, "data-active": lineWrap, className: "jp-xtralab-DiffWidget-segmentedButton jp-xtralab-DiffWidget-segmentedButton-icon", title: trans.__('Wrap long lines'), "aria-label": trans.__('Wrap lines'), onClick: () => onChange(!lineWrap) },
|
|
303
|
+
React.createElement(IconWordWrap, null))));
|
|
445
304
|
}
|
package/lib/git/diffTheme.d.ts
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
import { type DiffsThemeNames } from '@pierre/diffs';
|
|
2
|
+
/**
|
|
3
|
+
* `unsafeCSS` for a taller, always-visible horizontal scrollbar. The library
|
|
4
|
+
* default is 6px and only paints the thumb on hover, in a color close to the
|
|
5
|
+
* background, so users miss that long lines scroll. Same thumb color as the
|
|
6
|
+
* app scrollbars in chrome.css.
|
|
7
|
+
*/
|
|
8
|
+
export declare const DIFF_SCROLLBAR_CSS = ":host {\n --diffs-scrollbar-gutter-override: 10px;\n --xtralab-diff-scrollbar-thumb: color-mix(in srgb, var(--jp-ui-font-color1) 28%, transparent);\n}\n[data-code]::-webkit-scrollbar-thumb {\n background-color: var(--xtralab-diff-scrollbar-thumb);\n border-width: 2px;\n border-radius: 999px;\n}\n[data-code]::-webkit-scrollbar-thumb:hover {\n background-color: color-mix(in srgb, var(--jp-ui-font-color1) 45%, transparent);\n}\n@supports (-moz-appearance: none) {\n [data-code] {\n scrollbar-color: var(--xtralab-diff-scrollbar-thumb) transparent;\n }\n}";
|
|
2
9
|
/**
|
|
3
10
|
* Choose Pierre's palette or the JupyterLab CSS-variable theme.
|
|
4
11
|
*/
|
package/lib/git/diffTheme.js
CHANGED
|
@@ -20,6 +20,29 @@ registerCustomCSSVariableTheme(JUPYTERLAB_DIFF_THEME, {
|
|
|
20
20
|
'token-punctuation': 'var(--jp-mirror-editor-punctuation-color)',
|
|
21
21
|
'token-link': 'var(--jp-mirror-editor-link-color)'
|
|
22
22
|
});
|
|
23
|
+
/**
|
|
24
|
+
* `unsafeCSS` for a taller, always-visible horizontal scrollbar. The library
|
|
25
|
+
* default is 6px and only paints the thumb on hover, in a color close to the
|
|
26
|
+
* background, so users miss that long lines scroll. Same thumb color as the
|
|
27
|
+
* app scrollbars in chrome.css.
|
|
28
|
+
*/
|
|
29
|
+
export const DIFF_SCROLLBAR_CSS = `:host {
|
|
30
|
+
--diffs-scrollbar-gutter-override: 10px;
|
|
31
|
+
--xtralab-diff-scrollbar-thumb: color-mix(in srgb, var(--jp-ui-font-color1) 28%, transparent);
|
|
32
|
+
}
|
|
33
|
+
[data-code]::-webkit-scrollbar-thumb {
|
|
34
|
+
background-color: var(--xtralab-diff-scrollbar-thumb);
|
|
35
|
+
border-width: 2px;
|
|
36
|
+
border-radius: 999px;
|
|
37
|
+
}
|
|
38
|
+
[data-code]::-webkit-scrollbar-thumb:hover {
|
|
39
|
+
background-color: color-mix(in srgb, var(--jp-ui-font-color1) 45%, transparent);
|
|
40
|
+
}
|
|
41
|
+
@supports (-moz-appearance: none) {
|
|
42
|
+
[data-code] {
|
|
43
|
+
scrollbar-color: var(--xtralab-diff-scrollbar-thumb) transparent;
|
|
44
|
+
}
|
|
45
|
+
}`;
|
|
23
46
|
/**
|
|
24
47
|
* Choose Pierre's palette or the JupyterLab CSS-variable theme.
|
|
25
48
|
*/
|
package/lib/git/diffWidget.d.ts
CHANGED
|
@@ -8,28 +8,55 @@ import { ReactWidget } from '@jupyterlab/ui-components';
|
|
|
8
8
|
import { ISignal } from '@lumino/signaling';
|
|
9
9
|
import { Widget } from '@lumino/widgets';
|
|
10
10
|
import type { IAskAgent } from '../askAgent/tokens';
|
|
11
|
-
import {
|
|
11
|
+
import { type IDiffPreferences } from './diffPreferences';
|
|
12
|
+
import { DIFF_WIDGET_CSS_CLASS } from './diffSurface';
|
|
12
13
|
export { DIFF_WIDGET_CSS_CLASS };
|
|
13
14
|
/**
|
|
14
15
|
* `Git.Diff.IModel` plus optional xtralab-only metadata.
|
|
15
16
|
*/
|
|
16
17
|
export interface IXtralabDiffModel extends Git.Diff.IModel {
|
|
18
|
+
/**
|
|
19
|
+
* Whether the file is binary, so no text contents are fetched.
|
|
20
|
+
*/
|
|
17
21
|
isBinary?: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Whether hunks may be discarded; when absent, a working-tree heuristic decides.
|
|
24
|
+
*/
|
|
18
25
|
canDiscard?: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* The old-side path when the diff represents a rename.
|
|
28
|
+
*/
|
|
19
29
|
oldFilename?: string;
|
|
20
30
|
}
|
|
21
31
|
/**
|
|
22
32
|
* Application-level services the diff model does not carry.
|
|
23
33
|
*/
|
|
24
34
|
export interface IXtralabDiffContext {
|
|
35
|
+
/**
|
|
36
|
+
* The contents manager used to save hunk-discard results.
|
|
37
|
+
*/
|
|
25
38
|
contentsManager: Contents.IManager;
|
|
39
|
+
/**
|
|
40
|
+
* The rendermime registry for rendered notebook diffs, or `null` to
|
|
41
|
+
* force the textual fallback.
|
|
42
|
+
*/
|
|
26
43
|
rendermime: IRenderMimeRegistry | null;
|
|
44
|
+
/**
|
|
45
|
+
* The theme manager used to track theme changes, or `null` to watch
|
|
46
|
+
* the body attribute instead.
|
|
47
|
+
*/
|
|
27
48
|
themeManager: IThemeManager | null;
|
|
28
49
|
/**
|
|
29
|
-
*
|
|
30
|
-
* "ask an agent about these lines" gutter button.
|
|
50
|
+
* When available, diff line selections get an "ask an agent" gutter button.
|
|
31
51
|
*/
|
|
32
52
|
askAgent: IAskAgent | null;
|
|
53
|
+
/**
|
|
54
|
+
* The display choices shared by all diff views.
|
|
55
|
+
*/
|
|
56
|
+
preferences: IDiffPreferences;
|
|
57
|
+
/**
|
|
58
|
+
* The application translation bundle.
|
|
59
|
+
*/
|
|
33
60
|
trans: TranslationBundle;
|
|
34
61
|
}
|
|
35
62
|
/**
|
|
@@ -37,6 +64,9 @@ export interface IXtralabDiffContext {
|
|
|
37
64
|
*/
|
|
38
65
|
export declare class XtralabDiffWidget extends ReactWidget implements Git.Diff.IDiffWidget {
|
|
39
66
|
constructor(model: Git.Diff.IModel, context: IXtralabDiffContext);
|
|
67
|
+
/**
|
|
68
|
+
* The git diff model being rendered.
|
|
69
|
+
*/
|
|
40
70
|
get model(): Git.Diff.IModel;
|
|
41
71
|
/**
|
|
42
72
|
* Swap the rendered model when the launcher reuses its preview tab.
|
|
@@ -54,41 +84,64 @@ export declare class XtralabDiffWidget extends ReactWidget implements Git.Diff.I
|
|
|
54
84
|
* Re-pull both sides of the model and re-render.
|
|
55
85
|
*/
|
|
56
86
|
refresh(): Promise<void>;
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
87
|
+
/**
|
|
88
|
+
* Whether a rendered notebook view is currently available.
|
|
89
|
+
*/
|
|
60
90
|
get hasNotebookView(): boolean;
|
|
91
|
+
/**
|
|
92
|
+
* Set whether a rendered notebook view is available.
|
|
93
|
+
*/
|
|
61
94
|
setHasNotebookView(value: boolean): void;
|
|
95
|
+
/**
|
|
96
|
+
* A signal emitted when rendered-notebook availability changes.
|
|
97
|
+
*/
|
|
62
98
|
get hasNotebookViewChanged(): ISignal<this, boolean>;
|
|
63
|
-
get diffStyle(): DiffStyle;
|
|
64
|
-
setDiffStyle(style: DiffStyle): void;
|
|
65
|
-
get diffStyleChanged(): ISignal<this, DiffStyle>;
|
|
66
99
|
/**
|
|
67
|
-
* Whether the Split/Unified toolbar
|
|
100
|
+
* Whether the Split/Unified and line-wrap toolbar controls currently apply.
|
|
68
101
|
*/
|
|
69
102
|
get fileDiffActive(): boolean;
|
|
103
|
+
/**
|
|
104
|
+
* Set whether the textual file diff is the active view.
|
|
105
|
+
*/
|
|
70
106
|
setFileDiffActive(value: boolean): void;
|
|
107
|
+
/**
|
|
108
|
+
* A signal emitted when {@link fileDiffActive} changes.
|
|
109
|
+
*/
|
|
71
110
|
get fileDiffActiveChanged(): ISignal<this, boolean>;
|
|
72
111
|
/**
|
|
73
112
|
* Emitted when a post-discard reload leaves the diff with no hunks.
|
|
74
113
|
*/
|
|
75
114
|
get emptied(): ISignal<this, void>;
|
|
115
|
+
/**
|
|
116
|
+
* Emit the {@link emptied} signal.
|
|
117
|
+
*/
|
|
76
118
|
notifyEmptied(): void;
|
|
119
|
+
/**
|
|
120
|
+
* Resolve and clear the pending `refresh()` promise, if any.
|
|
121
|
+
*/
|
|
77
122
|
settleRefresh(): void;
|
|
123
|
+
/**
|
|
124
|
+
* Dispose of the resources held by the widget.
|
|
125
|
+
*/
|
|
78
126
|
dispose(): void;
|
|
127
|
+
/**
|
|
128
|
+
* A counter incremented on each `refresh()` to trigger a content re-fetch.
|
|
129
|
+
*/
|
|
79
130
|
get reloadNonce(): number;
|
|
131
|
+
/**
|
|
132
|
+
* The application-level services used by the rendered diff.
|
|
133
|
+
*/
|
|
80
134
|
get context(): IXtralabDiffContext;
|
|
135
|
+
/**
|
|
136
|
+
* Render the diff view for the current model.
|
|
137
|
+
*/
|
|
81
138
|
protected render(): React.ReactElement;
|
|
82
139
|
private _model;
|
|
83
140
|
private _context;
|
|
84
141
|
private _reloadNonce;
|
|
85
142
|
private _pendingRefresh;
|
|
86
|
-
private _notebookViewMode;
|
|
87
|
-
private _notebookViewModeChanged;
|
|
88
143
|
private _hasNotebookView;
|
|
89
144
|
private _hasNotebookViewChanged;
|
|
90
|
-
private _diffStyle;
|
|
91
|
-
private _diffStyleChanged;
|
|
92
145
|
private _fileDiffActive;
|
|
93
146
|
private _fileDiffActiveChanged;
|
|
94
147
|
private _emptied;
|
|
@@ -97,6 +150,9 @@ export declare class XtralabDiffWidget extends ReactWidget implements Git.Diff.I
|
|
|
97
150
|
* Structural toolbar type shared across host package boundaries.
|
|
98
151
|
*/
|
|
99
152
|
interface IDiffToolbar {
|
|
153
|
+
/**
|
|
154
|
+
* Add an item to the toolbar under the given name.
|
|
155
|
+
*/
|
|
100
156
|
addItem(name: string, widget: Widget): boolean;
|
|
101
157
|
}
|
|
102
158
|
/**
|