xtralab 0.8.0 → 0.9.0
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 +13 -6
- package/lib/fileBrowser/commands.d.ts +7 -0
- package/lib/fileBrowser/commands.js +74 -1
- package/lib/fileBrowser/fileBrowser.js +4 -1
- package/lib/fileBrowser/icons.d.ts +5 -9
- package/lib/fileBrowser/icons.js +97 -13
- package/lib/fileBrowser/index.js +5 -3
- package/lib/fileTypeIcons/index.d.ts +6 -0
- package/lib/fileTypeIcons/index.js +144 -0
- package/lib/git/commands.d.ts +34 -33
- package/lib/git/commands.js +132 -10
- package/lib/git/diffModel.d.ts +14 -0
- package/lib/git/diffModel.js +75 -0
- package/lib/git/diffProvider.d.ts +0 -5
- package/lib/git/diffProvider.js +6 -376
- package/lib/git/diffSurface.d.ts +36 -26
- package/lib/git/diffSurface.js +13 -20
- package/lib/git/diffTheme.d.ts +9 -0
- package/lib/git/diffTheme.js +31 -0
- package/lib/git/diffWidget.d.ts +54 -91
- package/lib/git/diffWidget.js +184 -361
- package/lib/git/index.d.ts +1 -6
- package/lib/git/index.js +7 -23
- package/lib/git/notebookDiff.d.ts +6 -1
- package/lib/git/notebookDiff.js +4 -3
- package/lib/index.js +2 -0
- package/lib/terminals/model.d.ts +1 -1
- package/lib/terminals/model.js +1 -1
- package/lib/terminals/widget.d.ts +1 -1
- package/lib/terminals/widget.js +1 -1
- package/package.json +3 -3
- package/schema/plugin.json +6 -0
- package/src/fileBrowser/commands.ts +91 -2
- package/src/fileBrowser/fileBrowser.tsx +4 -1
- package/src/fileBrowser/icons.ts +103 -13
- package/src/fileBrowser/index.ts +9 -3
- package/src/fileTypeIcons/index.ts +174 -0
- package/src/git/commands.ts +177 -43
- package/src/git/diffModel.ts +102 -0
- package/src/git/diffProvider.tsx +8 -540
- package/src/git/diffSurface.tsx +44 -28
- package/src/git/diffTheme.ts +40 -0
- package/src/git/diffWidget.tsx +256 -448
- package/src/git/index.ts +14 -28
- package/src/git/notebookDiff.tsx +10 -3
- package/src/index.ts +2 -0
- package/src/terminals/model.ts +1 -1
- package/src/terminals/widget.tsx +1 -1
- package/style/git.css +12 -9
- package/style/index.css +1 -0
- package/style/index.js +1 -0
- package/style/launcher.css +46 -18
- package/style/sidebar.css +14 -0
package/src/git/index.ts
CHANGED
|
@@ -5,14 +5,15 @@ import {
|
|
|
5
5
|
import { IThemeManager, WidgetTracker } from '@jupyterlab/apputils';
|
|
6
6
|
import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
|
|
7
7
|
|
|
8
|
-
import { CommandArguments, CommandIDs, registerGitCommands } from './commands';
|
|
9
8
|
import {
|
|
10
|
-
|
|
9
|
+
CommandArguments,
|
|
10
|
+
CommandIDs,
|
|
11
|
+
DiffMainAreaWidget,
|
|
11
12
|
PREVIEW_DIFF_WIDGET_ID,
|
|
12
|
-
pinnedDiffWidgetId
|
|
13
|
-
|
|
13
|
+
pinnedDiffWidgetId,
|
|
14
|
+
registerGitCommands
|
|
15
|
+
} from './commands';
|
|
14
16
|
import diffProviderPlugin from './diffProvider';
|
|
15
|
-
import type { MainAreaWidget } from '@jupyterlab/apputils';
|
|
16
17
|
import { IFileChange } from './tokens';
|
|
17
18
|
|
|
18
19
|
const GIT_DIFF_COMMAND_PLUGIN_ID = 'xtralab:git-diff-command';
|
|
@@ -21,12 +22,8 @@ const GIT_DIFF_TRACKER_NAMESPACE = 'xtralab-git-diff';
|
|
|
21
22
|
/**
|
|
22
23
|
* The launcher's git diff command plugin.
|
|
23
24
|
*
|
|
24
|
-
* The
|
|
25
|
-
*
|
|
26
|
-
* user sees in the sidebar. This plugin is the launcher dashboard's
|
|
27
|
-
* independent diff path: the `xtralab:git:open-diff` command the
|
|
28
|
-
* dashboard's "Changes" section calls, plus a tracker so reopening a diff
|
|
29
|
-
* reveals the existing tab and the preview/pin behavior keeps working.
|
|
25
|
+
* The upstream git panel stays enabled; this plugin only gives the launcher
|
|
26
|
+
* its own `xtralab:git:open-diff` command and preview/pinned-tab tracking.
|
|
30
27
|
*/
|
|
31
28
|
const diffCommandPlugin: JupyterFrontEndPlugin<void> = {
|
|
32
29
|
id: GIT_DIFF_COMMAND_PLUGIN_ID,
|
|
@@ -39,17 +36,15 @@ const diffCommandPlugin: JupyterFrontEndPlugin<void> = {
|
|
|
39
36
|
themeManager: IThemeManager | null,
|
|
40
37
|
rendermime: IRenderMimeRegistry | null
|
|
41
38
|
): void => {
|
|
42
|
-
// Track open
|
|
43
|
-
|
|
44
|
-
// (and so a promoted preview can find its pinned twin).
|
|
45
|
-
const tracker = new WidgetTracker<MainAreaWidget<DiffContentWidget>>({
|
|
39
|
+
// Track open diffs so repeated opens reveal the existing tab.
|
|
40
|
+
const tracker = new WidgetTracker<DiffMainAreaWidget>({
|
|
46
41
|
namespace: GIT_DIFF_TRACKER_NAMESPACE
|
|
47
42
|
});
|
|
48
43
|
|
|
49
44
|
const findDiff = (
|
|
50
45
|
change: IFileChange,
|
|
51
46
|
pin = false
|
|
52
|
-
):
|
|
47
|
+
): DiffMainAreaWidget | undefined => {
|
|
53
48
|
const id = pin ? pinnedDiffWidgetId(change) : PREVIEW_DIFF_WIDGET_ID;
|
|
54
49
|
const existing = tracker.find(
|
|
55
50
|
widget => !widget.isDisposed && widget.id === id
|
|
@@ -62,13 +57,9 @@ const diffCommandPlugin: JupyterFrontEndPlugin<void> = {
|
|
|
62
57
|
themeManager,
|
|
63
58
|
contentsManager: app.serviceManager.contents,
|
|
64
59
|
rendermime,
|
|
65
|
-
// The launcher polls git status on its own cadence and the
|
|
66
|
-
// jupyterlab-git panel auto-refreshes on the contents `fileChanged`
|
|
67
|
-
// signal a hunk-discard save emits, so no extra refresh is needed.
|
|
68
|
-
onChanged: () => undefined,
|
|
69
60
|
trackDiff: widget => tracker.add(widget),
|
|
70
61
|
onPinned: current => {
|
|
71
|
-
const existing = findDiff(current.
|
|
62
|
+
const existing = findDiff(current.change, true);
|
|
72
63
|
if (
|
|
73
64
|
existing !== undefined &&
|
|
74
65
|
existing !== current &&
|
|
@@ -78,7 +69,7 @@ const diffCommandPlugin: JupyterFrontEndPlugin<void> = {
|
|
|
78
69
|
current.close();
|
|
79
70
|
return;
|
|
80
71
|
}
|
|
81
|
-
current.id = pinnedDiffWidgetId(current.
|
|
72
|
+
current.id = pinnedDiffWidgetId(current.change);
|
|
82
73
|
current.title.className = '';
|
|
83
74
|
app.shell.activateById(current.id);
|
|
84
75
|
},
|
|
@@ -88,12 +79,7 @@ const diffCommandPlugin: JupyterFrontEndPlugin<void> = {
|
|
|
88
79
|
};
|
|
89
80
|
|
|
90
81
|
/**
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
* 1. {@link diffCommandPlugin} — the launcher's `xtralab:git:open-diff`.
|
|
94
|
-
* 2. `diffProviderPlugin` — registers the `@pierre/diffs` rendering as
|
|
95
|
-
* jupyterlab-git's diff providers (replacing its disabled
|
|
96
|
-
* notebook/text diff plugins).
|
|
82
|
+
* Plugins contributed by xtralab's git integration.
|
|
97
83
|
*/
|
|
98
84
|
const plugins: JupyterFrontEndPlugin<unknown>[] = [
|
|
99
85
|
diffCommandPlugin,
|
package/src/git/notebookDiff.tsx
CHANGED
|
@@ -13,6 +13,8 @@ import {
|
|
|
13
13
|
type FileDiffMetadata
|
|
14
14
|
} from '@pierre/diffs';
|
|
15
15
|
|
|
16
|
+
import { resolveDiffTheme } from './diffTheme';
|
|
17
|
+
|
|
16
18
|
/**
|
|
17
19
|
* The CSS class added to the root of the notebook diff. Selectors that
|
|
18
20
|
* style cell sections, headers, and the per-cell diff blocks hang off this
|
|
@@ -151,7 +153,7 @@ function emptyNotebook(): INotebook {
|
|
|
151
153
|
* nbformat allows multiline string fields (`source`, stream `text`,
|
|
152
154
|
* `text/plain` outputs, …) to be either a single string or an array of
|
|
153
155
|
* strings. Normalize to one string so equality checks and diffs see the
|
|
154
|
-
* same shape regardless of how the writer chose to
|
|
156
|
+
* same shape regardless of how the writer chose to serialize it.
|
|
155
157
|
*/
|
|
156
158
|
export function joinMultiline(value: string | string[] | undefined): string {
|
|
157
159
|
if (value === undefined) {
|
|
@@ -836,6 +838,11 @@ function MarkdownPreviewSection(props: {
|
|
|
836
838
|
interface INotebookDiffViewProps {
|
|
837
839
|
diff: INotebookDiffResult;
|
|
838
840
|
dark: boolean;
|
|
841
|
+
/**
|
|
842
|
+
* Whether a Pierre JupyterLab theme is active; selects Pierre's rich
|
|
843
|
+
* highlighting vs the CSS-variable theme (see {@link resolveDiffTheme}).
|
|
844
|
+
*/
|
|
845
|
+
pierreTheme: boolean;
|
|
839
846
|
rendermime: IRenderMimeRegistry | null;
|
|
840
847
|
}
|
|
841
848
|
|
|
@@ -852,8 +859,8 @@ interface INotebookDiffViewProps {
|
|
|
852
859
|
export function NotebookDiffView(
|
|
853
860
|
props: INotebookDiffViewProps
|
|
854
861
|
): React.ReactElement {
|
|
855
|
-
const { diff, dark, rendermime } = props;
|
|
856
|
-
const theme: DiffsThemeNames = dark
|
|
862
|
+
const { diff, dark, pierreTheme, rendermime } = props;
|
|
863
|
+
const theme: DiffsThemeNames = resolveDiffTheme(dark, pierreTheme);
|
|
857
864
|
const summary = React.useMemo(() => summarize(diff.cells), [diff.cells]);
|
|
858
865
|
return (
|
|
859
866
|
<div className={NOTEBOOK_DIFF_CSS_CLASS}>
|
package/src/index.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { JupyterFrontEndPlugin } from '@jupyterlab/application';
|
|
|
2
2
|
|
|
3
3
|
import agentSessionsPlugin from './agentSessions';
|
|
4
4
|
import fileBrowserPlugin from './fileBrowser';
|
|
5
|
+
import fileTypeIconsPlugin from './fileTypeIcons';
|
|
5
6
|
import editorBreadcrumbsPlugin from './editorBreadcrumbs';
|
|
6
7
|
import editorIndentPlugin from './editorIndent';
|
|
7
8
|
import gitPlugins from './git';
|
|
@@ -25,6 +26,7 @@ const plugins: JupyterFrontEndPlugin<unknown>[] = [
|
|
|
25
26
|
editorBreadcrumbsPlugin,
|
|
26
27
|
editorIndentPlugin,
|
|
27
28
|
fileBrowserPlugin,
|
|
29
|
+
fileTypeIconsPlugin,
|
|
28
30
|
...gitPlugins,
|
|
29
31
|
...launcherPlugins,
|
|
30
32
|
menusPlugin,
|
package/src/terminals/model.ts
CHANGED
|
@@ -194,7 +194,7 @@ export class SessionRegistry implements IDisposable {
|
|
|
194
194
|
|
|
195
195
|
/**
|
|
196
196
|
* Return the open widget for a session, if any. The panel uses this to
|
|
197
|
-
* switch
|
|
197
|
+
* switch behavior between "activate existing tab" and "open a new tab
|
|
198
198
|
* connected to the live session".
|
|
199
199
|
*/
|
|
200
200
|
widgetFor(name: string): TerminalWidget | null {
|
package/src/terminals/widget.tsx
CHANGED
|
@@ -32,7 +32,7 @@ export const RUNNING_TERMINALS_ID = 'xtralab-running-terminals';
|
|
|
32
32
|
* Backed by {@link SessionRegistry}: a `UseSignal` re-renders the list
|
|
33
33
|
* whenever the registry emits `stateChanged`, so it tracks
|
|
34
34
|
* `runningChanged` and the agent-title cache without any local state.
|
|
35
|
-
* Click
|
|
35
|
+
* Click behavior (activate vs. reopen, shutdown, new terminal) is
|
|
36
36
|
* delegated to plugin-supplied callbacks so the widget never imports
|
|
37
37
|
* `app`.
|
|
38
38
|
*/
|
package/style/git.css
CHANGED
|
@@ -40,12 +40,7 @@
|
|
|
40
40
|
color: var(--jp-ui-font-color1);
|
|
41
41
|
|
|
42
42
|
/*
|
|
43
|
-
*
|
|
44
|
-
* properties the library exposes. The `*-override` variants take
|
|
45
|
-
* precedence over the library's defaults, so these values track the
|
|
46
|
-
* JupyterLab theme automatically — no JS needed when the theme
|
|
47
|
-
* switches. Theme-dependent colors (insertion green, deletion red, …)
|
|
48
|
-
* still come from the active Shiki theme passed via `options.theme`.
|
|
43
|
+
* Feed JupyterLab theme colors into @pierre/diffs.
|
|
49
44
|
*/
|
|
50
45
|
--diffs-bg-override: var(--jp-layout-color1);
|
|
51
46
|
--diffs-bg-buffer-override: var(--jp-layout-color1);
|
|
@@ -58,6 +53,8 @@
|
|
|
58
53
|
--diffs-fg-number-override: var(--jp-ui-font-color3);
|
|
59
54
|
--diffs-fg-conflict-marker-override: var(--jp-warn-color1);
|
|
60
55
|
--diffs-modified-color-override: var(--jp-warn-color1);
|
|
56
|
+
--diffs-addition-color-override: var(--jp-success-color1);
|
|
57
|
+
--diffs-deletion-color-override: var(--jp-error-color1);
|
|
61
58
|
}
|
|
62
59
|
|
|
63
60
|
/*
|
|
@@ -91,7 +88,9 @@
|
|
|
91
88
|
font-size: var(--jp-ui-font-size0);
|
|
92
89
|
}
|
|
93
90
|
|
|
94
|
-
/*
|
|
91
|
+
/*
|
|
92
|
+
* Breathing room when both toggles appear (notebook diff in JSON view).
|
|
93
|
+
*/
|
|
95
94
|
.jp-xtralab-DiffWidget-diffStyleToolbarItem {
|
|
96
95
|
margin-left: 4px;
|
|
97
96
|
}
|
|
@@ -589,7 +588,9 @@
|
|
|
589
588
|
|
|
590
589
|
.jp-xtralab-ImageDiff-frame,
|
|
591
590
|
.jp-xtralab-ImageDiff-stack {
|
|
592
|
-
/*
|
|
591
|
+
/*
|
|
592
|
+
* Checkerboard so transparent regions are obvious; theme-neutral.
|
|
593
|
+
*/
|
|
593
594
|
background-color: #fff;
|
|
594
595
|
background-image:
|
|
595
596
|
linear-gradient(45deg, #c8c8c8 25%, transparent 25%),
|
|
@@ -766,7 +767,9 @@
|
|
|
766
767
|
bottom: -14px;
|
|
767
768
|
}
|
|
768
769
|
|
|
769
|
-
/*
|
|
770
|
+
/*
|
|
771
|
+
* Chevron triangles drawn with borders so no asset is needed.
|
|
772
|
+
*/
|
|
770
773
|
.jp-xtralab-ImageDiff-swipeDividerArrow {
|
|
771
774
|
width: 0;
|
|
772
775
|
height: 0;
|
package/style/index.css
CHANGED
package/style/index.js
CHANGED
package/style/launcher.css
CHANGED
|
@@ -166,8 +166,8 @@
|
|
|
166
166
|
|
|
167
167
|
/*
|
|
168
168
|
* Changed files list. Each row is a button so click + keyboard activate
|
|
169
|
-
* both work; the
|
|
170
|
-
*
|
|
169
|
+
* both work; the letter on the left is the file's single-letter git status,
|
|
170
|
+
* colored to match the @pierre/trees file tree's decorations.
|
|
171
171
|
*/
|
|
172
172
|
.jp-xtralab-Launcher-changes {
|
|
173
173
|
list-style: none;
|
|
@@ -178,6 +178,27 @@
|
|
|
178
178
|
border: 1px solid var(--jp-border-color2);
|
|
179
179
|
border-radius: 4px;
|
|
180
180
|
overflow: hidden;
|
|
181
|
+
|
|
182
|
+
/*
|
|
183
|
+
* Git status letter palette, mirroring the @pierre/trees `--trees-status-*`
|
|
184
|
+
* defaults. The file tree resolves those through `light-dark()` under
|
|
185
|
+
* `color-scheme: light dark` — i.e. by OS appearance — so the
|
|
186
|
+
* `prefers-color-scheme` override below reproduces that exact resolution
|
|
187
|
+
* and keeps these letters in lockstep with the tree's.
|
|
188
|
+
*/
|
|
189
|
+
--xtralab-git-status-added: #16a994;
|
|
190
|
+
--xtralab-git-status-modified: #1ca1c7;
|
|
191
|
+
--xtralab-git-status-renamed: #d5a910;
|
|
192
|
+
--xtralab-git-status-deleted: #ff2e3f;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
@media (prefers-color-scheme: dark) {
|
|
196
|
+
.jp-xtralab-Launcher-changes {
|
|
197
|
+
--xtralab-git-status-added: #00cab1;
|
|
198
|
+
--xtralab-git-status-modified: #08c0ef;
|
|
199
|
+
--xtralab-git-status-renamed: #ffd452;
|
|
200
|
+
--xtralab-git-status-deleted: #ff6762;
|
|
201
|
+
}
|
|
181
202
|
}
|
|
182
203
|
|
|
183
204
|
.jp-xtralab-Launcher-changes > li + li {
|
|
@@ -207,35 +228,42 @@
|
|
|
207
228
|
outline-offset: -1px;
|
|
208
229
|
}
|
|
209
230
|
|
|
231
|
+
/*
|
|
232
|
+
* Bare colored letter, not a filled badge — the same treatment the
|
|
233
|
+
* @pierre/trees file tree gives its git status decorations. The fixed width
|
|
234
|
+
* keeps the letters in a tidy gutter so the paths stay column-aligned.
|
|
235
|
+
*/
|
|
210
236
|
.jp-xtralab-Launcher-change-badge {
|
|
211
237
|
display: inline-flex;
|
|
212
238
|
align-items: center;
|
|
213
239
|
justify-content: center;
|
|
214
|
-
width:
|
|
215
|
-
|
|
216
|
-
font-size: 10px;
|
|
217
|
-
font-weight: 700;
|
|
218
|
-
border-radius: 3px;
|
|
240
|
+
width: 14px;
|
|
241
|
+
flex: 0 0 auto;
|
|
219
242
|
font-family: var(--jp-code-font-family);
|
|
220
|
-
|
|
243
|
+
font-size: var(--jp-code-font-size);
|
|
244
|
+
font-weight: 600;
|
|
221
245
|
color: var(--jp-ui-font-color2);
|
|
222
|
-
flex: 0 0 auto;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
.jp-xtralab-Launcher-change-modified {
|
|
226
|
-
background-color: var(--jp-warn-color3, var(--jp-layout-color2));
|
|
227
|
-
color: var(--jp-warn-color1, var(--jp-ui-font-color1));
|
|
228
246
|
}
|
|
229
247
|
|
|
230
248
|
.jp-xtralab-Launcher-change-added,
|
|
231
249
|
.jp-xtralab-Launcher-change-untracked {
|
|
232
|
-
|
|
233
|
-
|
|
250
|
+
color: var(--xtralab-git-status-added);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/* The file tree folds unmerged/typechange/unknown onto modified; match it. */
|
|
254
|
+
.jp-xtralab-Launcher-change-modified,
|
|
255
|
+
.jp-xtralab-Launcher-change-unmerged,
|
|
256
|
+
.jp-xtralab-Launcher-change-typechange,
|
|
257
|
+
.jp-xtralab-Launcher-change-unknown {
|
|
258
|
+
color: var(--xtralab-git-status-modified);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
.jp-xtralab-Launcher-change-renamed {
|
|
262
|
+
color: var(--xtralab-git-status-renamed);
|
|
234
263
|
}
|
|
235
264
|
|
|
236
265
|
.jp-xtralab-Launcher-change-deleted {
|
|
237
|
-
|
|
238
|
-
color: var(--jp-error-color1, var(--jp-ui-font-color1));
|
|
266
|
+
color: var(--xtralab-git-status-deleted);
|
|
239
267
|
}
|
|
240
268
|
|
|
241
269
|
.jp-xtralab-Launcher-change-path {
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* The side activity bar is shipped horizontally (activityBarPosition: "top",
|
|
3
|
+
* see jupyter-config/labconfig). In that mode the TabBar content node spans
|
|
4
|
+
* the full width (@jupyterlab/application/style/sidepanel.css) with no
|
|
5
|
+
* justify-content, so the icons sit at the leading edge. Center them under
|
|
6
|
+
* the menu bar instead.
|
|
7
|
+
*
|
|
8
|
+
* `safe center` keeps the row start-aligned should the icons ever exceed the
|
|
9
|
+
* bar width, so none are pushed past the leading edge out of reach of the
|
|
10
|
+
* content node's horizontal overflow scroll.
|
|
11
|
+
*/
|
|
12
|
+
.jp-SideBar[data-orientation='horizontal'] .lm-TabBar-content {
|
|
13
|
+
justify-content: safe center;
|
|
14
|
+
}
|