xtralab 0.11.0 → 0.12.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 +37 -229
- package/lib/agentSessions.d.ts +6 -2
- package/lib/askAgent/editorSelection.d.ts +53 -0
- package/lib/askAgent/editorSelection.js +95 -0
- package/lib/askAgent/icons.d.ts +7 -0
- package/lib/askAgent/icons.js +15 -0
- package/lib/askAgent/index.d.ts +32 -0
- package/lib/askAgent/index.js +741 -0
- package/lib/askAgent/popup.d.ts +83 -0
- package/lib/askAgent/popup.js +221 -0
- package/lib/askAgent/prompt.d.ts +24 -0
- package/lib/askAgent/prompt.js +116 -0
- package/lib/askAgent/queue.d.ts +93 -0
- package/lib/askAgent/queue.js +207 -0
- package/lib/askAgent/queuePanel.d.ts +76 -0
- package/lib/askAgent/queuePanel.js +188 -0
- package/lib/askAgent/targetPicker.d.ts +58 -0
- package/lib/askAgent/targetPicker.js +74 -0
- package/lib/askAgent/tokens.d.ts +124 -0
- package/lib/askAgent/tokens.js +13 -0
- package/lib/commandBar/index.d.ts +12 -8
- package/lib/commandBar/index.js +58 -41
- package/lib/editorBreadcrumbs/index.js +9 -4
- package/lib/editorBreadcrumbs/widget.d.ts +7 -7
- package/lib/editorBreadcrumbs/widget.js +6 -8
- package/lib/fileBrowser/commands.d.ts +2 -8
- package/lib/fileBrowser/commands.js +39 -30
- package/lib/fileBrowser/contents.d.ts +8 -3
- package/lib/fileBrowser/fileBrowser.d.ts +2 -1
- package/lib/fileBrowser/widget.d.ts +5 -9
- package/lib/fileBrowser/widget.js +1 -1
- package/lib/fileTypeIcons/index.js +5 -2
- package/lib/git/api.d.ts +0 -26
- package/lib/git/api.js +2 -44
- package/lib/git/askRequest.d.ts +23 -0
- package/lib/git/askRequest.js +90 -0
- package/lib/git/commands.d.ts +14 -2
- package/lib/git/commands.js +16 -13
- package/lib/git/diffModel.d.ts +1 -9
- package/lib/git/diffModel.js +1 -1
- package/lib/git/diffProvider.js +8 -3
- package/lib/git/diffSurface.d.ts +19 -2
- package/lib/git/diffSurface.js +64 -18
- package/lib/git/diffTheme.d.ts +0 -4
- package/lib/git/diffTheme.js +1 -1
- package/lib/git/diffWidget.d.ts +9 -0
- package/lib/git/diffWidget.js +38 -10
- package/lib/git/imageDiff.d.ts +17 -4
- package/lib/git/imageDiff.js +90 -30
- package/lib/git/index.js +7 -2
- package/lib/git/notebookDiff.d.ts +10 -67
- package/lib/git/notebookDiff.js +62 -69
- package/lib/git/tokens.d.ts +5 -2
- package/lib/highlight/index.js +12 -8
- package/lib/index.js +2 -0
- package/lib/launcher/agents.d.ts +11 -1
- package/lib/launcher/agents.js +26 -8
- package/lib/launcher/commands.d.ts +6 -2
- package/lib/launcher/dashboard.d.ts +8 -1
- package/lib/launcher/dashboard.js +39 -33
- package/lib/launcher/editorRegistry.js +5 -3
- package/lib/launcher/editors.d.ts +24 -7
- package/lib/launcher/editors.js +14 -5
- package/lib/launcher/icons.d.ts +0 -37
- package/lib/launcher/icons.js +11 -12
- package/lib/launcher/index.js +5 -2
- package/lib/launcher/invocation.d.ts +0 -15
- package/lib/launcher/invocation.js +1 -1
- package/lib/launcher/schemaDefaults.d.ts +3 -1
- package/lib/launcher/schemaDefaults.js +3 -1
- package/lib/mimeData.d.ts +7 -0
- package/lib/mimeData.js +16 -0
- package/lib/omnibox/index.d.ts +4 -0
- package/lib/omnibox/index.js +43 -2
- package/lib/omnibox/model.d.ts +43 -14
- package/lib/omnibox/model.js +117 -14
- package/lib/omnibox/recents.d.ts +65 -0
- package/lib/omnibox/recents.js +109 -0
- package/lib/omnibox/tokens.d.ts +6 -2
- package/lib/omnibox/widget.d.ts +23 -6
- package/lib/omnibox/widget.js +26 -7
- package/lib/showOutput/index.js +15 -18
- package/lib/terminals/agentTerminals.d.ts +63 -0
- package/lib/terminals/agentTerminals.js +157 -0
- package/lib/terminals/index.d.ts +7 -1
- package/lib/terminals/index.js +50 -30
- package/lib/terminals/model.d.ts +11 -2
- package/lib/terminals/model.js +27 -8
- package/lib/terminals/tokens.d.ts +66 -0
- package/lib/terminals/tokens.js +7 -0
- package/lib/terminals/widget.d.ts +3 -6
- package/lib/terminals/widget.js +1 -1
- package/lib/topBar/index.js +3 -3
- package/lib/walkthrough/index.js +14 -3
- package/lib/walkthrough/panel.d.ts +12 -4
- package/lib/walkthrough/panel.js +9 -3
- package/package.json +49 -51
- package/schema/command-bar.json +10 -0
- package/schema/launcher.json +4 -4
- package/schema/omnibox.json +15 -0
- package/src/agentSessions.ts +6 -2
- package/src/askAgent/editorSelection.ts +138 -0
- package/src/askAgent/icons.ts +16 -0
- package/src/askAgent/index.ts +915 -0
- package/src/askAgent/popup.tsx +407 -0
- package/src/askAgent/prompt.ts +144 -0
- package/src/askAgent/queue.ts +269 -0
- package/src/askAgent/queuePanel.tsx +418 -0
- package/src/askAgent/targetPicker.tsx +209 -0
- package/src/askAgent/tokens.ts +139 -0
- package/src/commandBar/index.ts +75 -49
- package/src/editorBreadcrumbs/index.ts +14 -4
- package/src/editorBreadcrumbs/widget.ts +11 -9
- package/src/fileBrowser/commands.ts +45 -31
- package/src/fileBrowser/contents.ts +7 -3
- package/src/fileBrowser/fileBrowser.tsx +1 -1
- package/src/fileBrowser/widget.tsx +5 -3
- package/src/fileTypeIcons/index.ts +6 -3
- package/src/git/api.ts +2 -61
- package/src/git/askRequest.ts +113 -0
- package/src/git/commands.ts +41 -14
- package/src/git/diffModel.ts +1 -1
- package/src/git/diffProvider.tsx +11 -3
- package/src/git/diffSurface.tsx +114 -22
- package/src/git/diffTheme.ts +1 -1
- package/src/git/diffWidget.tsx +54 -7
- package/src/git/imageDiff.tsx +169 -58
- package/src/git/index.ts +10 -2
- package/src/git/notebookDiff.tsx +91 -57
- package/src/git/tokens.ts +4 -2
- package/src/highlight/index.ts +12 -8
- package/src/index.ts +2 -0
- package/src/launcher/agents.ts +31 -7
- package/src/launcher/commands.ts +6 -2
- package/src/launcher/dashboard.tsx +86 -38
- package/src/launcher/editorRegistry.ts +10 -4
- package/src/launcher/editors.ts +34 -9
- package/src/launcher/icons.ts +11 -12
- package/src/launcher/index.ts +5 -2
- package/src/launcher/invocation.ts +1 -1
- package/src/launcher/schemaDefaults.ts +3 -1
- package/src/mimeData.ts +20 -0
- package/src/omnibox/index.ts +48 -1
- package/src/omnibox/model.ts +173 -33
- package/src/omnibox/recents.ts +155 -0
- package/src/omnibox/tokens.ts +6 -2
- package/src/omnibox/widget.tsx +54 -13
- package/src/showOutput/index.ts +20 -23
- package/src/terminals/agentTerminals.ts +238 -0
- package/src/terminals/index.ts +54 -30
- package/src/terminals/model.ts +28 -7
- package/src/terminals/tokens.ts +77 -0
- package/src/terminals/widget.tsx +4 -2
- package/src/topBar/index.ts +12 -6
- package/src/walkthrough/index.ts +19 -4
- package/src/walkthrough/panel.ts +15 -5
- package/style/askAgent.css +544 -0
- package/style/commandBar.css +12 -33
- package/style/git.css +72 -31
- package/style/index.css +1 -0
- package/style/index.js +2 -0
- package/style/topBar.css +4 -4
package/src/git/diffProvider.tsx
CHANGED
|
@@ -4,8 +4,11 @@ import {
|
|
|
4
4
|
} from '@jupyterlab/application';
|
|
5
5
|
import { IThemeManager } from '@jupyterlab/apputils';
|
|
6
6
|
import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
|
|
7
|
+
import { ITranslator, nullTranslator } from '@jupyterlab/translation';
|
|
7
8
|
import { Git, IGitExtension } from '@jupyterlab/git';
|
|
8
9
|
|
|
10
|
+
import { IAskAgent } from '../askAgent/tokens';
|
|
11
|
+
|
|
9
12
|
import {
|
|
10
13
|
IXtralabDiffContext,
|
|
11
14
|
XtralabDiffWidget,
|
|
@@ -34,17 +37,22 @@ const diffProviderPlugin: JupyterFrontEndPlugin<void> = {
|
|
|
34
37
|
"Replaces jupyterlab-git's notebook, text and image diff plugins with xtralab's renderer.",
|
|
35
38
|
autoStart: true,
|
|
36
39
|
requires: [IGitExtension],
|
|
37
|
-
optional: [IRenderMimeRegistry, IThemeManager],
|
|
40
|
+
optional: [IRenderMimeRegistry, IThemeManager, ITranslator, IAskAgent],
|
|
38
41
|
activate: (
|
|
39
42
|
app: JupyterFrontEnd,
|
|
40
43
|
gitExtension: IGitExtension,
|
|
41
44
|
rendermime: IRenderMimeRegistry | null,
|
|
42
|
-
themeManager: IThemeManager | null
|
|
45
|
+
themeManager: IThemeManager | null,
|
|
46
|
+
translator: ITranslator | null,
|
|
47
|
+
askAgent: IAskAgent | null
|
|
43
48
|
): void => {
|
|
49
|
+
const trans = (translator ?? nullTranslator).load('jupyterlab');
|
|
44
50
|
const factory = makeXtralabDiffFactory({
|
|
45
51
|
contentsManager: app.serviceManager.contents,
|
|
46
52
|
rendermime,
|
|
47
|
-
themeManager
|
|
53
|
+
themeManager,
|
|
54
|
+
askAgent,
|
|
55
|
+
trans
|
|
48
56
|
});
|
|
49
57
|
|
|
50
58
|
// Use one shared factory; the surface detects notebooks/images by filename.
|
package/src/git/diffSurface.tsx
CHANGED
|
@@ -2,6 +2,7 @@ import * as React from 'react';
|
|
|
2
2
|
|
|
3
3
|
import { IThemeManager } from '@jupyterlab/apputils';
|
|
4
4
|
import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
|
|
5
|
+
import type { TranslationBundle } from '@jupyterlab/translation';
|
|
5
6
|
import { undoIcon } from '@jupyterlab/ui-components';
|
|
6
7
|
import { FileDiff } from '@pierre/diffs/react';
|
|
7
8
|
import {
|
|
@@ -9,7 +10,8 @@ import {
|
|
|
9
10
|
parseDiffFromFile,
|
|
10
11
|
type DiffLineAnnotation,
|
|
11
12
|
type FileContents,
|
|
12
|
-
type FileDiffMetadata
|
|
13
|
+
type FileDiffMetadata,
|
|
14
|
+
type SelectedLineRange
|
|
13
15
|
} from '@pierre/diffs';
|
|
14
16
|
|
|
15
17
|
import { ImageDiffView, imageDataType } from './imageDiff';
|
|
@@ -197,13 +199,13 @@ export function isPierreTheme(themeManager: IThemeManager | null): boolean {
|
|
|
197
199
|
* the on-disk path) and triggers any follow-up refresh in
|
|
198
200
|
* {@link IHunkDiscard.onAfterSave}.
|
|
199
201
|
*/
|
|
200
|
-
|
|
202
|
+
interface IHunkDiscard {
|
|
201
203
|
enabled: boolean;
|
|
202
204
|
save: (fullText: string) => Promise<void>;
|
|
203
205
|
onAfterSave: () => void;
|
|
204
206
|
}
|
|
205
207
|
|
|
206
|
-
|
|
208
|
+
interface IDiffSurfaceProps {
|
|
207
209
|
/**
|
|
208
210
|
* Whether the host is still resolving the file contents.
|
|
209
211
|
*/
|
|
@@ -278,6 +280,18 @@ export interface IDiffSurfaceProps {
|
|
|
278
280
|
* Optional per-hunk discard wiring; omit for a read-only diff.
|
|
279
281
|
*/
|
|
280
282
|
hunkDiscard?: IHunkDiscard;
|
|
283
|
+
/**
|
|
284
|
+
* When provided, the textual/code file diff gets line selection: clicking
|
|
285
|
+
* or dragging over the line numbers selects a range, and a gutter "+"
|
|
286
|
+
* button appears on the hovered/selected lines. Clicking that button
|
|
287
|
+
* invokes this callback with the selected range and the button's viewport
|
|
288
|
+
* rectangle (to anchor a popup to), `null` when it cannot be measured.
|
|
289
|
+
*/
|
|
290
|
+
onLineAsk?: (range: SelectedLineRange, anchor: DOMRect | null) => void;
|
|
291
|
+
/**
|
|
292
|
+
* Translation bundle for user-facing strings.
|
|
293
|
+
*/
|
|
294
|
+
trans: TranslationBundle;
|
|
281
295
|
}
|
|
282
296
|
|
|
283
297
|
/**
|
|
@@ -300,7 +314,9 @@ export function DiffSurface(props: IDiffSurfaceProps): React.ReactElement {
|
|
|
300
314
|
onNotebookAvailabilityChange,
|
|
301
315
|
onFileDiffActiveChange,
|
|
302
316
|
onMetadataChange,
|
|
303
|
-
hunkDiscard
|
|
317
|
+
hunkDiscard,
|
|
318
|
+
onLineAsk,
|
|
319
|
+
trans
|
|
304
320
|
} = props;
|
|
305
321
|
|
|
306
322
|
const hasContent = !loading && error === null && !isBinary;
|
|
@@ -432,8 +448,8 @@ export function DiffSurface(props: IDiffSurfaceProps): React.ReactElement {
|
|
|
432
448
|
<button
|
|
433
449
|
type="button"
|
|
434
450
|
className="jp-xtralab-DiffWidget-hunkButton"
|
|
435
|
-
title="Discard this hunk's changes"
|
|
436
|
-
aria-label=
|
|
451
|
+
title={trans.__("Discard this hunk's changes")}
|
|
452
|
+
aria-label={trans.__('Discard hunk')}
|
|
437
453
|
onClick={() => void handleDiscardHunk(hunkIndex)}
|
|
438
454
|
>
|
|
439
455
|
<undoIcon.react
|
|
@@ -445,7 +461,26 @@ export function DiffSurface(props: IDiffSurfaceProps): React.ReactElement {
|
|
|
445
461
|
</div>
|
|
446
462
|
);
|
|
447
463
|
},
|
|
448
|
-
[handleDiscardHunk]
|
|
464
|
+
[handleDiscardHunk, trans]
|
|
465
|
+
);
|
|
466
|
+
|
|
467
|
+
const handleGutterUtilityClick = React.useCallback(
|
|
468
|
+
(range: SelectedLineRange) => {
|
|
469
|
+
if (onLineAsk === undefined) {
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
472
|
+
// Anchor to the gutter "+" button that was just clicked. It lives in
|
|
473
|
+
// the `@pierre/diffs` shadow root (which is open), parked on the
|
|
474
|
+
// hovered/selected line's number element.
|
|
475
|
+
const slot = wrapperRef.current
|
|
476
|
+
?.querySelector('diffs-container')
|
|
477
|
+
?.shadowRoot?.querySelector('[data-gutter-utility-slot]');
|
|
478
|
+
onLineAsk(
|
|
479
|
+
range,
|
|
480
|
+
slot instanceof Element ? slot.getBoundingClientRect() : null
|
|
481
|
+
);
|
|
482
|
+
},
|
|
483
|
+
[onLineAsk]
|
|
449
484
|
);
|
|
450
485
|
|
|
451
486
|
const handleResizerPointerDown = React.useCallback(
|
|
@@ -500,8 +535,44 @@ export function DiffSurface(props: IDiffSurfaceProps): React.ReactElement {
|
|
|
500
535
|
writeStoredSplitRatio(DEFAULT_SPLIT_RATIO);
|
|
501
536
|
}, []);
|
|
502
537
|
|
|
538
|
+
const handleResizerKeyDown = React.useCallback(
|
|
539
|
+
(event: React.KeyboardEvent<HTMLDivElement>) => {
|
|
540
|
+
const step = event.shiftKey ? 0.1 : 0.01;
|
|
541
|
+
let next: number | null = null;
|
|
542
|
+
switch (event.key) {
|
|
543
|
+
case 'ArrowLeft':
|
|
544
|
+
next = leftRatioRef.current - step;
|
|
545
|
+
break;
|
|
546
|
+
case 'ArrowRight':
|
|
547
|
+
next = leftRatioRef.current + step;
|
|
548
|
+
break;
|
|
549
|
+
case 'Home':
|
|
550
|
+
next = MIN_SPLIT_RATIO;
|
|
551
|
+
break;
|
|
552
|
+
case 'End':
|
|
553
|
+
next = MAX_SPLIT_RATIO;
|
|
554
|
+
break;
|
|
555
|
+
}
|
|
556
|
+
if (next === null) {
|
|
557
|
+
return;
|
|
558
|
+
}
|
|
559
|
+
event.preventDefault();
|
|
560
|
+
const clamped = Math.max(
|
|
561
|
+
MIN_SPLIT_RATIO,
|
|
562
|
+
Math.min(MAX_SPLIT_RATIO, next)
|
|
563
|
+
);
|
|
564
|
+
setLeftRatio(clamped);
|
|
565
|
+
writeStoredSplitRatio(clamped);
|
|
566
|
+
},
|
|
567
|
+
[]
|
|
568
|
+
);
|
|
569
|
+
|
|
503
570
|
if (loading) {
|
|
504
|
-
return
|
|
571
|
+
return (
|
|
572
|
+
<div className="jp-xtralab-DiffWidget-status">
|
|
573
|
+
{trans.__('Loading diff…')}
|
|
574
|
+
</div>
|
|
575
|
+
);
|
|
505
576
|
}
|
|
506
577
|
if (error !== null) {
|
|
507
578
|
return (
|
|
@@ -513,7 +584,7 @@ export function DiffSurface(props: IDiffSurfaceProps): React.ReactElement {
|
|
|
513
584
|
if (isBinary) {
|
|
514
585
|
return (
|
|
515
586
|
<div className="jp-xtralab-DiffWidget-status">
|
|
516
|
-
Binary file — diff not supported.
|
|
587
|
+
{trans.__('Binary file — diff not supported.')}
|
|
517
588
|
</div>
|
|
518
589
|
);
|
|
519
590
|
}
|
|
@@ -527,13 +598,16 @@ export function DiffSurface(props: IDiffSurfaceProps): React.ReactElement {
|
|
|
527
598
|
reference={oldText}
|
|
528
599
|
challenger={newText}
|
|
529
600
|
fileType={imageType}
|
|
601
|
+
trans={trans}
|
|
530
602
|
/>
|
|
531
603
|
</div>
|
|
532
604
|
);
|
|
533
605
|
}
|
|
534
606
|
if (!showNotebookView && !showFileDiff) {
|
|
535
607
|
return (
|
|
536
|
-
<div className="jp-xtralab-DiffWidget-status">
|
|
608
|
+
<div className="jp-xtralab-DiffWidget-status">
|
|
609
|
+
{trans.__('No content to diff.')}
|
|
610
|
+
</div>
|
|
537
611
|
);
|
|
538
612
|
}
|
|
539
613
|
|
|
@@ -556,6 +630,7 @@ export function DiffSurface(props: IDiffSurfaceProps): React.ReactElement {
|
|
|
556
630
|
dark={dark}
|
|
557
631
|
pierreTheme={pierreTheme}
|
|
558
632
|
rendermime={rendermime}
|
|
633
|
+
trans={trans}
|
|
559
634
|
/>
|
|
560
635
|
) : showFileDiff && metadata !== null ? (
|
|
561
636
|
<FileDiff<IHunkActionAnnotation>
|
|
@@ -583,7 +658,17 @@ export function DiffSurface(props: IDiffSurfaceProps): React.ReactElement {
|
|
|
583
658
|
// string constant lets the library short-circuit the
|
|
584
659
|
// re-render path it uses when this option actually
|
|
585
660
|
// changes.
|
|
586
|
-
unsafeCSS: SPLIT_RESIZE_CSS
|
|
661
|
+
unsafeCSS: SPLIT_RESIZE_CSS,
|
|
662
|
+
// Line selection + the gutter "+" button feed the
|
|
663
|
+
// ask-agent popup; only wired up when a handler exists so
|
|
664
|
+
// a plain diff keeps its passive gutter.
|
|
665
|
+
...(onLineAsk !== undefined
|
|
666
|
+
? {
|
|
667
|
+
enableLineSelection: true,
|
|
668
|
+
enableGutterUtility: true,
|
|
669
|
+
onGutterUtilityClick: handleGutterUtilityClick
|
|
670
|
+
}
|
|
671
|
+
: {})
|
|
587
672
|
}}
|
|
588
673
|
/>
|
|
589
674
|
) : null}
|
|
@@ -597,9 +682,14 @@ export function DiffSurface(props: IDiffSurfaceProps): React.ReactElement {
|
|
|
597
682
|
aria-valuenow={Math.round(leftPercent)}
|
|
598
683
|
aria-valuemin={Math.round(MIN_SPLIT_RATIO * 100)}
|
|
599
684
|
aria-valuemax={Math.round(MAX_SPLIT_RATIO * 100)}
|
|
600
|
-
|
|
685
|
+
aria-label={trans.__('Resize the diff panes')}
|
|
686
|
+
tabIndex={0}
|
|
687
|
+
title={trans.__(
|
|
688
|
+
'Drag to resize the diff panes (double-click to reset)'
|
|
689
|
+
)}
|
|
601
690
|
onPointerDown={handleResizerPointerDown}
|
|
602
691
|
onDoubleClick={handleResizerDoubleClick}
|
|
692
|
+
onKeyDown={handleResizerKeyDown}
|
|
603
693
|
/>
|
|
604
694
|
) : null}
|
|
605
695
|
</div>
|
|
@@ -617,8 +707,9 @@ export function NotebookViewModeControl(props: {
|
|
|
617
707
|
mode: NotebookDiffViewMode;
|
|
618
708
|
available: boolean;
|
|
619
709
|
onChange: (mode: NotebookDiffViewMode) => void;
|
|
710
|
+
trans: TranslationBundle;
|
|
620
711
|
}): React.ReactElement {
|
|
621
|
-
const { mode, available, onChange } = props;
|
|
712
|
+
const { mode, available, onChange, trans } = props;
|
|
622
713
|
if (!available) {
|
|
623
714
|
return <></>;
|
|
624
715
|
}
|
|
@@ -626,7 +717,7 @@ export function NotebookViewModeControl(props: {
|
|
|
626
717
|
<div
|
|
627
718
|
className="jp-xtralab-DiffWidget-segmented"
|
|
628
719
|
role="tablist"
|
|
629
|
-
aria-label=
|
|
720
|
+
aria-label={trans.__('Notebook diff view mode')}
|
|
630
721
|
>
|
|
631
722
|
<button
|
|
632
723
|
type="button"
|
|
@@ -636,7 +727,7 @@ export function NotebookViewModeControl(props: {
|
|
|
636
727
|
className="jp-xtralab-DiffWidget-segmentedButton"
|
|
637
728
|
onClick={() => onChange('notebook')}
|
|
638
729
|
>
|
|
639
|
-
Notebook
|
|
730
|
+
{trans.__('Notebook')}
|
|
640
731
|
</button>
|
|
641
732
|
<button
|
|
642
733
|
type="button"
|
|
@@ -646,7 +737,7 @@ export function NotebookViewModeControl(props: {
|
|
|
646
737
|
className="jp-xtralab-DiffWidget-segmentedButton"
|
|
647
738
|
onClick={() => onChange('json')}
|
|
648
739
|
>
|
|
649
|
-
JSON
|
|
740
|
+
{trans.__('JSON')}
|
|
650
741
|
</button>
|
|
651
742
|
</div>
|
|
652
743
|
);
|
|
@@ -700,8 +791,9 @@ export function DiffStyleControl(props: {
|
|
|
700
791
|
diffStyle: DiffStyle;
|
|
701
792
|
available: boolean;
|
|
702
793
|
onChange: (style: DiffStyle) => void;
|
|
794
|
+
trans: TranslationBundle;
|
|
703
795
|
}): React.ReactElement {
|
|
704
|
-
const { diffStyle, available, onChange } = props;
|
|
796
|
+
const { diffStyle, available, onChange, trans } = props;
|
|
705
797
|
if (!available) {
|
|
706
798
|
return <></>;
|
|
707
799
|
}
|
|
@@ -709,7 +801,7 @@ export function DiffStyleControl(props: {
|
|
|
709
801
|
<div
|
|
710
802
|
className="jp-xtralab-DiffWidget-segmented"
|
|
711
803
|
role="tablist"
|
|
712
|
-
aria-label=
|
|
804
|
+
aria-label={trans.__('Diff view style')}
|
|
713
805
|
>
|
|
714
806
|
<button
|
|
715
807
|
type="button"
|
|
@@ -717,8 +809,8 @@ export function DiffStyleControl(props: {
|
|
|
717
809
|
aria-selected={diffStyle === 'split'}
|
|
718
810
|
data-active={diffStyle === 'split'}
|
|
719
811
|
className="jp-xtralab-DiffWidget-segmentedButton jp-xtralab-DiffWidget-segmentedButton-icon"
|
|
720
|
-
title=
|
|
721
|
-
aria-label=
|
|
812
|
+
title={trans.__('Split (side-by-side) view')}
|
|
813
|
+
aria-label={trans.__('Split view')}
|
|
722
814
|
onClick={() => onChange('split')}
|
|
723
815
|
>
|
|
724
816
|
<DiffSplitIcon />
|
|
@@ -729,8 +821,8 @@ export function DiffStyleControl(props: {
|
|
|
729
821
|
aria-selected={diffStyle === 'unified'}
|
|
730
822
|
data-active={diffStyle === 'unified'}
|
|
731
823
|
className="jp-xtralab-DiffWidget-segmentedButton jp-xtralab-DiffWidget-segmentedButton-icon"
|
|
732
|
-
title=
|
|
733
|
-
aria-label=
|
|
824
|
+
title={trans.__('Unified (inline) view')}
|
|
825
|
+
aria-label={trans.__('Unified view')}
|
|
734
826
|
onClick={() => onChange('unified')}
|
|
735
827
|
>
|
|
736
828
|
<DiffUnifiedIcon />
|
package/src/git/diffTheme.ts
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
/**
|
|
7
7
|
* Shiki CSS-variable theme used for non-Pierre JupyterLab themes.
|
|
8
8
|
*/
|
|
9
|
-
|
|
9
|
+
const JUPYTERLAB_DIFF_THEME: DiffsThemeNames = 'jupyterlab';
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Register a Shiki theme whose token colors read JupyterLab's editor
|
package/src/git/diffWidget.tsx
CHANGED
|
@@ -5,11 +5,16 @@ import { PathExt } from '@jupyterlab/coreutils';
|
|
|
5
5
|
import { Git } from '@jupyterlab/git';
|
|
6
6
|
import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
|
|
7
7
|
import { Contents } from '@jupyterlab/services';
|
|
8
|
+
import type { TranslationBundle } from '@jupyterlab/translation';
|
|
8
9
|
import { ReactWidget } from '@jupyterlab/ui-components';
|
|
9
10
|
import { PromiseDelegate } from '@lumino/coreutils';
|
|
10
11
|
import { ISignal, Signal } from '@lumino/signaling';
|
|
11
12
|
import { Widget } from '@lumino/widgets';
|
|
13
|
+
import type { SelectedLineRange } from '@pierre/diffs';
|
|
12
14
|
|
|
15
|
+
import type { IAskAgent } from '../askAgent/tokens';
|
|
16
|
+
|
|
17
|
+
import { buildDiffAskRequest } from './askRequest';
|
|
13
18
|
import {
|
|
14
19
|
DIFF_WIDGET_CSS_CLASS,
|
|
15
20
|
DiffStyleControl,
|
|
@@ -44,6 +49,12 @@ export interface IXtralabDiffContext {
|
|
|
44
49
|
contentsManager: Contents.IManager;
|
|
45
50
|
rendermime: IRenderMimeRegistry | null;
|
|
46
51
|
themeManager: IThemeManager | null;
|
|
52
|
+
/**
|
|
53
|
+
* The ask-agent popup; when available, diff line selections get an
|
|
54
|
+
* "ask an agent about these lines" gutter button.
|
|
55
|
+
*/
|
|
56
|
+
askAgent: IAskAgent | null;
|
|
57
|
+
trans: TranslationBundle;
|
|
47
58
|
}
|
|
48
59
|
|
|
49
60
|
/**
|
|
@@ -103,6 +114,9 @@ export class XtralabDiffWidget
|
|
|
103
114
|
* Re-pull both sides of the model and re-render.
|
|
104
115
|
*/
|
|
105
116
|
async refresh(): Promise<void> {
|
|
117
|
+
// Settle any refresh still awaiting so a rapid second call cannot orphan
|
|
118
|
+
// the earlier caller's promise.
|
|
119
|
+
this.settleRefresh();
|
|
106
120
|
const done = new PromiseDelegate<void>();
|
|
107
121
|
this._pendingRefresh = done;
|
|
108
122
|
this._reloadNonce += 1;
|
|
@@ -196,6 +210,14 @@ export class XtralabDiffWidget
|
|
|
196
210
|
pending?.resolve();
|
|
197
211
|
}
|
|
198
212
|
|
|
213
|
+
dispose(): void {
|
|
214
|
+
// Release any in-flight refresh awaiter so a host that awaits refresh()
|
|
215
|
+
// (jupyterlab-git re-shows its diff button only once it resolves) does not
|
|
216
|
+
// hang when the widget is torn down mid-fetch.
|
|
217
|
+
this.settleRefresh();
|
|
218
|
+
super.dispose();
|
|
219
|
+
}
|
|
220
|
+
|
|
199
221
|
get reloadNonce(): number {
|
|
200
222
|
return this._reloadNonce;
|
|
201
223
|
}
|
|
@@ -237,7 +259,8 @@ function ModelDiffView(props: {
|
|
|
237
259
|
}): React.ReactElement {
|
|
238
260
|
const { widget } = props;
|
|
239
261
|
const model = widget.model as IXtralabDiffModel;
|
|
240
|
-
const { contentsManager, rendermime, themeManager } =
|
|
262
|
+
const { contentsManager, rendermime, themeManager, askAgent, trans } =
|
|
263
|
+
widget.context;
|
|
241
264
|
const nonce = widget.reloadNonce;
|
|
242
265
|
|
|
243
266
|
const [state, setState] = React.useState<IModelDiffState>({
|
|
@@ -252,7 +275,7 @@ function ModelDiffView(props: {
|
|
|
252
275
|
React.useState<NotebookDiffViewMode>(() => widget.notebookViewMode);
|
|
253
276
|
React.useEffect(() => {
|
|
254
277
|
const handler = (
|
|
255
|
-
|
|
278
|
+
sender: XtralabDiffWidget,
|
|
256
279
|
mode: NotebookDiffViewMode
|
|
257
280
|
): void => {
|
|
258
281
|
setNotebookViewMode(mode);
|
|
@@ -276,7 +299,7 @@ function ModelDiffView(props: {
|
|
|
276
299
|
() => widget.diffStyle
|
|
277
300
|
);
|
|
278
301
|
React.useEffect(() => {
|
|
279
|
-
const handler = (
|
|
302
|
+
const handler = (sender: XtralabDiffWidget, style: DiffStyle): void => {
|
|
280
303
|
setDiffStyle(style);
|
|
281
304
|
};
|
|
282
305
|
widget.diffStyleChanged.connect(handler);
|
|
@@ -428,6 +451,24 @@ function ModelDiffView(props: {
|
|
|
428
451
|
[canDiscardHunk, contentsManager, serverPath, widget]
|
|
429
452
|
);
|
|
430
453
|
|
|
454
|
+
const handleLineAsk = React.useMemo(() => {
|
|
455
|
+
if (askAgent === null) {
|
|
456
|
+
return undefined;
|
|
457
|
+
}
|
|
458
|
+
return (range: SelectedLineRange, anchor: DOMRect | null): void => {
|
|
459
|
+
askAgent.open(
|
|
460
|
+
buildDiffAskRequest({
|
|
461
|
+
model,
|
|
462
|
+
oldText: state.oldText,
|
|
463
|
+
newText: state.newText,
|
|
464
|
+
range,
|
|
465
|
+
anchor,
|
|
466
|
+
trans
|
|
467
|
+
})
|
|
468
|
+
);
|
|
469
|
+
};
|
|
470
|
+
}, [askAgent, model, state.oldText, state.newText, trans]);
|
|
471
|
+
|
|
431
472
|
return (
|
|
432
473
|
<DiffSurface
|
|
433
474
|
loading={state.loading}
|
|
@@ -446,6 +487,8 @@ function ModelDiffView(props: {
|
|
|
446
487
|
onFileDiffActiveChange={handleFileDiffActiveChange}
|
|
447
488
|
onMetadataChange={handleMetadataChange}
|
|
448
489
|
hunkDiscard={hunkDiscard}
|
|
490
|
+
onLineAsk={handleLineAsk}
|
|
491
|
+
trans={trans}
|
|
449
492
|
/>
|
|
450
493
|
);
|
|
451
494
|
}
|
|
@@ -479,12 +522,12 @@ function NotebookViewModeToolbarControl(props: {
|
|
|
479
522
|
);
|
|
480
523
|
React.useEffect(() => {
|
|
481
524
|
const onMode = (
|
|
482
|
-
|
|
525
|
+
sender: XtralabDiffWidget,
|
|
483
526
|
next: NotebookDiffViewMode
|
|
484
527
|
): void => {
|
|
485
528
|
setMode(next);
|
|
486
529
|
};
|
|
487
|
-
const onAvailable = (
|
|
530
|
+
const onAvailable = (sender: XtralabDiffWidget, next: boolean): void => {
|
|
488
531
|
setAvailable(next);
|
|
489
532
|
};
|
|
490
533
|
widget.notebookViewModeChanged.connect(onMode);
|
|
@@ -497,11 +540,13 @@ function NotebookViewModeToolbarControl(props: {
|
|
|
497
540
|
};
|
|
498
541
|
}, [widget]);
|
|
499
542
|
|
|
543
|
+
const trans = widget.context.trans;
|
|
500
544
|
return (
|
|
501
545
|
<NotebookViewModeControl
|
|
502
546
|
mode={mode}
|
|
503
547
|
available={available}
|
|
504
548
|
onChange={next => widget.setNotebookViewMode(next)}
|
|
549
|
+
trans={trans}
|
|
505
550
|
/>
|
|
506
551
|
);
|
|
507
552
|
}
|
|
@@ -532,10 +577,10 @@ function DiffStyleToolbarControl(props: {
|
|
|
532
577
|
() => widget.fileDiffActive
|
|
533
578
|
);
|
|
534
579
|
React.useEffect(() => {
|
|
535
|
-
const onStyle = (
|
|
580
|
+
const onStyle = (sender: XtralabDiffWidget, next: DiffStyle): void => {
|
|
536
581
|
setStyle(next);
|
|
537
582
|
};
|
|
538
|
-
const onAvailable = (
|
|
583
|
+
const onAvailable = (sender: XtralabDiffWidget, next: boolean): void => {
|
|
539
584
|
setAvailable(next);
|
|
540
585
|
};
|
|
541
586
|
widget.diffStyleChanged.connect(onStyle);
|
|
@@ -548,11 +593,13 @@ function DiffStyleToolbarControl(props: {
|
|
|
548
593
|
};
|
|
549
594
|
}, [widget]);
|
|
550
595
|
|
|
596
|
+
const trans = widget.context.trans;
|
|
551
597
|
return (
|
|
552
598
|
<DiffStyleControl
|
|
553
599
|
diffStyle={style}
|
|
554
600
|
available={available}
|
|
555
601
|
onChange={next => widget.setDiffStyle(next)}
|
|
602
|
+
trans={trans}
|
|
556
603
|
/>
|
|
557
604
|
);
|
|
558
605
|
}
|