xtralab 0.11.1 → 0.12.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 +38 -231
- 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.js +3 -4
- 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 +15 -5
- package/lib/launcher/icons.d.ts +0 -37
- package/lib/launcher/icons.js +11 -12
- package/lib/launcher/index.js +2 -1
- 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/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 +3 -4
- 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 +15 -5
- package/src/launcher/icons.ts +11 -12
- package/src/launcher/index.ts +2 -1
- 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
|
@@ -2,7 +2,7 @@ import * as React from 'react';
|
|
|
2
2
|
import { IDocumentManager } from '@jupyterlab/docmanager';
|
|
3
3
|
import { Contents } from '@jupyterlab/services';
|
|
4
4
|
import type { XtralabFileBrowser } from './widget';
|
|
5
|
-
|
|
5
|
+
interface IFileBrowserProps {
|
|
6
6
|
contentsManager: Contents.IManager;
|
|
7
7
|
docManager: IDocumentManager;
|
|
8
8
|
onOpenFile?: (serverPath: string) => void;
|
|
@@ -22,3 +22,4 @@ export interface IFileBrowserProps {
|
|
|
22
22
|
* state map.
|
|
23
23
|
*/
|
|
24
24
|
export declare function FileBrowserComponent(props: IFileBrowserProps): React.ReactElement;
|
|
25
|
+
export {};
|
|
@@ -4,14 +4,7 @@ import { Toolbar } from '@jupyterlab/ui-components';
|
|
|
4
4
|
import { ISignal } from '@lumino/signaling';
|
|
5
5
|
import { Widget } from '@lumino/widgets';
|
|
6
6
|
export declare const FILE_BROWSER_ID = "xtralab:file-browser";
|
|
7
|
-
|
|
8
|
-
* The CSS class added to the xtralab file browser widget. The selectors that
|
|
9
|
-
* bind application context menu items hang off this class, so it must remain
|
|
10
|
-
* specific enough not to clash with other browsers (such as the default
|
|
11
|
-
* `jp-FileBrowser`).
|
|
12
|
-
*/
|
|
13
|
-
export declare const FILE_BROWSER_CSS_CLASS = "jp-xtralab-FileBrowser";
|
|
14
|
-
export interface IXtralabFileBrowserOptions {
|
|
7
|
+
interface IXtralabFileBrowserOptions {
|
|
15
8
|
contentsManager: Contents.IManager;
|
|
16
9
|
docManager: IDocumentManager;
|
|
17
10
|
onOpenFile?: (serverPath: string) => void;
|
|
@@ -78,7 +71,9 @@ export interface IXtralabFileBrowser {
|
|
|
78
71
|
* directories, calling `.collapse()` on each expanded one.
|
|
79
72
|
*/
|
|
80
73
|
readonly collapseAllRequested: ISignal<IXtralabFileBrowser, void>;
|
|
81
|
-
/**
|
|
74
|
+
/**
|
|
75
|
+
* Trigger a refresh of every loaded directory in the tree.
|
|
76
|
+
*/
|
|
82
77
|
refresh(): void;
|
|
83
78
|
/**
|
|
84
79
|
* Notify the React component that a new path was created and should
|
|
@@ -143,3 +138,4 @@ export declare class XtralabFileBrowser extends Widget implements IXtralabFileBr
|
|
|
143
138
|
private _toolbar;
|
|
144
139
|
private _content;
|
|
145
140
|
}
|
|
141
|
+
export {};
|
|
@@ -11,7 +11,7 @@ export const FILE_BROWSER_ID = 'xtralab:file-browser';
|
|
|
11
11
|
* specific enough not to clash with other browsers (such as the default
|
|
12
12
|
* `jp-FileBrowser`).
|
|
13
13
|
*/
|
|
14
|
-
|
|
14
|
+
const FILE_BROWSER_CSS_CLASS = 'jp-xtralab-FileBrowser';
|
|
15
15
|
const TOOLBAR_CSS_CLASS = 'jp-xtralab-FileBrowser-toolbar';
|
|
16
16
|
const CONTENT_CSS_CLASS = 'jp-xtralab-FileBrowser-content';
|
|
17
17
|
/**
|
|
@@ -120,8 +120,12 @@ const plugin = {
|
|
|
120
120
|
}
|
|
121
121
|
};
|
|
122
122
|
setIcon();
|
|
123
|
-
// Keep the tab icon right after a rename
|
|
123
|
+
// Keep the tab icon right after a rename, and release the listener
|
|
124
|
+
// when the document closes.
|
|
124
125
|
widget.context.pathChanged.connect(setIcon);
|
|
126
|
+
widget.disposed.connect(() => {
|
|
127
|
+
widget.context.pathChanged.disconnect(setIcon);
|
|
128
|
+
});
|
|
125
129
|
});
|
|
126
130
|
}
|
|
127
131
|
if (gitExtension !== null) {
|
|
@@ -134,7 +138,6 @@ const plugin = {
|
|
|
134
138
|
if (icon === null) {
|
|
135
139
|
continue;
|
|
136
140
|
}
|
|
137
|
-
// Cross jupyterlab-git's nested `LabIcon` package boundary.
|
|
138
141
|
file.type = { ...file.type, icon };
|
|
139
142
|
}
|
|
140
143
|
});
|
package/lib/git/api.d.ts
CHANGED
|
@@ -1,11 +1,4 @@
|
|
|
1
1
|
import { GitReference, IFileChange, IGitContentResult, IGitStatusFile, IGitStatusResult } from './tokens';
|
|
2
|
-
/**
|
|
3
|
-
* Fetch the absolute filesystem path of the git top-level for the given
|
|
4
|
-
* server-relative path. Returns `null` when the path is not in a git
|
|
5
|
-
* repository — the server returns a non-zero `code` (or `path: null`) in
|
|
6
|
-
* that case, which is expected and not a fatal error.
|
|
7
|
-
*/
|
|
8
|
-
export declare function showTopLevel(repoPath: string): Promise<string | null>;
|
|
9
2
|
/**
|
|
10
3
|
* Fetch `git status --porcelain` for the repository the server resolves at
|
|
11
4
|
* `repoPath`. When `repoPath` is the empty string, git resolves the repo
|
|
@@ -18,16 +11,6 @@ export declare function status(repoPath: string): Promise<IGitStatusResult>;
|
|
|
18
11
|
* of {@link status}'s response).
|
|
19
12
|
*/
|
|
20
13
|
export declare function content(repoPath: string, filename: string, reference: GitReference): Promise<IGitContentResult>;
|
|
21
|
-
/** Stage a single file. */
|
|
22
|
-
export declare function add(repoPath: string, filename: string): Promise<void>;
|
|
23
|
-
/** Stage every changed file (including untracked). */
|
|
24
|
-
export declare function addAll(repoPath: string): Promise<void>;
|
|
25
|
-
/** Unstage a single file. */
|
|
26
|
-
export declare function reset(repoPath: string, filename: string): Promise<void>;
|
|
27
|
-
/** Unstage every file. */
|
|
28
|
-
export declare function resetAll(repoPath: string): Promise<void>;
|
|
29
|
-
/** Restore a single file to the version in the index (i.e. discard worktree changes). */
|
|
30
|
-
export declare function checkout(repoPath: string, filename: string): Promise<void>;
|
|
31
14
|
/**
|
|
32
15
|
* Expand the porcelain `files` array into one entry per logical change.
|
|
33
16
|
* A single porcelain row may map to two `IFileChange` rows (a file that's
|
|
@@ -39,12 +22,3 @@ export declare function checkout(repoPath: string, filename: string): Promise<vo
|
|
|
39
22
|
* don't pin our `tsconfig.lib` to ES2019.
|
|
40
23
|
*/
|
|
41
24
|
export declare function expandStatusFiles(files: IGitStatusFile[]): IFileChange[];
|
|
42
|
-
/**
|
|
43
|
-
* Translate one entry in the porcelain `files` array into the panel's
|
|
44
|
-
* preferred shape. A single porcelain entry may represent up to two changes
|
|
45
|
-
* (one in the index, one in the worktree); we emit one {@link IFileChange}
|
|
46
|
-
* per non-empty side, so a "modified-staged-and-then-modified-again" file
|
|
47
|
-
* shows up twice in the panel — once under "Staged Changes" and once under
|
|
48
|
-
* "Changes" — matching the layout the user sees in VS Code.
|
|
49
|
-
*/
|
|
50
|
-
export declare function porcelainToFileChanges(file: IGitStatusFile): IFileChange[];
|
package/lib/git/api.js
CHANGED
|
@@ -32,7 +32,7 @@ async function postWithPath(endpoint, repoPath, body) {
|
|
|
32
32
|
try {
|
|
33
33
|
data = JSON.parse(text);
|
|
34
34
|
}
|
|
35
|
-
catch (
|
|
35
|
+
catch (_c) {
|
|
36
36
|
// Fall through into the error handling below.
|
|
37
37
|
}
|
|
38
38
|
}
|
|
@@ -42,25 +42,6 @@ async function postWithPath(endpoint, repoPath, body) {
|
|
|
42
42
|
}
|
|
43
43
|
return (data !== null && data !== void 0 ? data : {});
|
|
44
44
|
}
|
|
45
|
-
/**
|
|
46
|
-
* Fetch the absolute filesystem path of the git top-level for the given
|
|
47
|
-
* server-relative path. Returns `null` when the path is not in a git
|
|
48
|
-
* repository — the server returns a non-zero `code` (or `path: null`) in
|
|
49
|
-
* that case, which is expected and not a fatal error.
|
|
50
|
-
*/
|
|
51
|
-
export async function showTopLevel(repoPath) {
|
|
52
|
-
let result;
|
|
53
|
-
try {
|
|
54
|
-
result = await postWithPath('show_top_level', repoPath, {});
|
|
55
|
-
}
|
|
56
|
-
catch (err) {
|
|
57
|
-
return null;
|
|
58
|
-
}
|
|
59
|
-
if (result.code !== 0 || !result.path) {
|
|
60
|
-
return null;
|
|
61
|
-
}
|
|
62
|
-
return result.path;
|
|
63
|
-
}
|
|
64
45
|
/**
|
|
65
46
|
* Fetch `git status --porcelain` for the repository the server resolves at
|
|
66
47
|
* `repoPath`. When `repoPath` is the empty string, git resolves the repo
|
|
@@ -80,29 +61,6 @@ export async function content(repoPath, filename, reference) {
|
|
|
80
61
|
reference
|
|
81
62
|
});
|
|
82
63
|
}
|
|
83
|
-
/** Stage a single file. */
|
|
84
|
-
export async function add(repoPath, filename) {
|
|
85
|
-
await postWithPath('add', repoPath, { add_all: false, filename });
|
|
86
|
-
}
|
|
87
|
-
/** Stage every changed file (including untracked). */
|
|
88
|
-
export async function addAll(repoPath) {
|
|
89
|
-
await postWithPath('add', repoPath, { add_all: true });
|
|
90
|
-
}
|
|
91
|
-
/** Unstage a single file. */
|
|
92
|
-
export async function reset(repoPath, filename) {
|
|
93
|
-
await postWithPath('reset', repoPath, { reset_all: false, filename });
|
|
94
|
-
}
|
|
95
|
-
/** Unstage every file. */
|
|
96
|
-
export async function resetAll(repoPath) {
|
|
97
|
-
await postWithPath('reset', repoPath, { reset_all: true });
|
|
98
|
-
}
|
|
99
|
-
/** Restore a single file to the version in the index (i.e. discard worktree changes). */
|
|
100
|
-
export async function checkout(repoPath, filename) {
|
|
101
|
-
await postWithPath('checkout', repoPath, {
|
|
102
|
-
checkout_branch: false,
|
|
103
|
-
filename
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
64
|
/**
|
|
107
65
|
* Expand the porcelain `files` array into one entry per logical change.
|
|
108
66
|
* A single porcelain row may map to two `IFileChange` rows (a file that's
|
|
@@ -130,7 +88,7 @@ export function expandStatusFiles(files) {
|
|
|
130
88
|
* shows up twice in the panel — once under "Staged Changes" and once under
|
|
131
89
|
* "Changes" — matching the layout the user sees in VS Code.
|
|
132
90
|
*/
|
|
133
|
-
|
|
91
|
+
function porcelainToFileChanges(file) {
|
|
134
92
|
const result = [];
|
|
135
93
|
// Untracked files are reported with `??` and only appear under "Changes".
|
|
136
94
|
if (file.x === '?' && file.y === '?') {
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { TranslationBundle } from '@jupyterlab/translation';
|
|
2
|
+
import type { SelectedLineRange } from '@pierre/diffs';
|
|
3
|
+
import type { IAskAgentRequest } from '../askAgent/tokens';
|
|
4
|
+
import type { IXtralabDiffModel } from './diffWidget';
|
|
5
|
+
/**
|
|
6
|
+
* Build the ask-agent request for a line range selected in a git diff.
|
|
7
|
+
*
|
|
8
|
+
* The range's `side` decides which file version the line numbers (and the
|
|
9
|
+
* embedded snippet) refer to: `deletions` reads from the reference text,
|
|
10
|
+
* anything else — including the sideless context rows of a unified diff,
|
|
11
|
+
* whose gutter shows new-side numbers — reads from the challenger text. A
|
|
12
|
+
* gutter drag that crosses the two split columns has endpoints in different
|
|
13
|
+
* line-number spaces, so it is described textually instead of as a numeric
|
|
14
|
+
* range.
|
|
15
|
+
*/
|
|
16
|
+
export declare function buildDiffAskRequest(options: {
|
|
17
|
+
model: IXtralabDiffModel;
|
|
18
|
+
oldText: string;
|
|
19
|
+
newText: string;
|
|
20
|
+
range: SelectedLineRange;
|
|
21
|
+
anchor: DOMRect | null;
|
|
22
|
+
trans: TranslationBundle;
|
|
23
|
+
}): IAskAgentRequest;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { Git } from '@jupyterlab/git';
|
|
2
|
+
/**
|
|
3
|
+
* Agent-facing name of a diff content source: the special refs get plain
|
|
4
|
+
* words, a git ref string is used verbatim, anything else falls back to the
|
|
5
|
+
* side name. English on purpose — this ends up in the agent prompt, not in
|
|
6
|
+
* the UI.
|
|
7
|
+
*/
|
|
8
|
+
function describeSource(source, fallback) {
|
|
9
|
+
if (source === Git.Diff.SpecialRef.WORKING) {
|
|
10
|
+
return 'working tree';
|
|
11
|
+
}
|
|
12
|
+
if (source === Git.Diff.SpecialRef.INDEX) {
|
|
13
|
+
return 'staged';
|
|
14
|
+
}
|
|
15
|
+
if (source === Git.Diff.SpecialRef.BASE) {
|
|
16
|
+
return 'merge base';
|
|
17
|
+
}
|
|
18
|
+
if (typeof source === 'string' && source.length > 0) {
|
|
19
|
+
return source;
|
|
20
|
+
}
|
|
21
|
+
return fallback;
|
|
22
|
+
}
|
|
23
|
+
function sideName(side) {
|
|
24
|
+
return side === 'deletions' ? 'old side' : 'new side';
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Extract lines `startLine`–`endLine` (1-indexed, inclusive) from `text`.
|
|
28
|
+
*/
|
|
29
|
+
function sliceLines(text, startLine, endLine) {
|
|
30
|
+
return text
|
|
31
|
+
.split('\n')
|
|
32
|
+
.slice(startLine - 1, endLine)
|
|
33
|
+
.join('\n');
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Build the ask-agent request for a line range selected in a git diff.
|
|
37
|
+
*
|
|
38
|
+
* The range's `side` decides which file version the line numbers (and the
|
|
39
|
+
* embedded snippet) refer to: `deletions` reads from the reference text,
|
|
40
|
+
* anything else — including the sideless context rows of a unified diff,
|
|
41
|
+
* whose gutter shows new-side numbers — reads from the challenger text. A
|
|
42
|
+
* gutter drag that crosses the two split columns has endpoints in different
|
|
43
|
+
* line-number spaces, so it is described textually instead of as a numeric
|
|
44
|
+
* range.
|
|
45
|
+
*/
|
|
46
|
+
export function buildDiffAskRequest(options) {
|
|
47
|
+
var _a, _b, _c;
|
|
48
|
+
const { model, oldText, newText, range, anchor, trans } = options;
|
|
49
|
+
const repositoryPath = (_a = model.repositoryPath) !== null && _a !== void 0 ? _a : '';
|
|
50
|
+
const base = {
|
|
51
|
+
path: model.filename,
|
|
52
|
+
...(repositoryPath.length > 0 ? { cwd: repositoryPath } : {})
|
|
53
|
+
};
|
|
54
|
+
const startSide = (_b = range.side) !== null && _b !== void 0 ? _b : 'additions';
|
|
55
|
+
const endSide = (_c = range.endSide) !== null && _c !== void 0 ? _c : startSide;
|
|
56
|
+
if (startSide !== endSide) {
|
|
57
|
+
return {
|
|
58
|
+
context: {
|
|
59
|
+
...base,
|
|
60
|
+
text: '',
|
|
61
|
+
location: `lines ${range.start} (${sideName(startSide)}) through ` +
|
|
62
|
+
`${range.end} (${sideName(endSide)}) of the current git diff`,
|
|
63
|
+
note: trans.__('diff selection')
|
|
64
|
+
},
|
|
65
|
+
anchor
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
const startLine = Math.min(range.start, range.end);
|
|
69
|
+
const endLine = Math.max(range.start, range.end);
|
|
70
|
+
const isOld = startSide === 'deletions';
|
|
71
|
+
const source = isOld ? model.reference.source : model.challenger.source;
|
|
72
|
+
const ref = describeSource(source, isOld ? 'old' : 'new');
|
|
73
|
+
return {
|
|
74
|
+
context: {
|
|
75
|
+
...base,
|
|
76
|
+
startLine,
|
|
77
|
+
endLine,
|
|
78
|
+
// Only new-side lines of a working-tree diff index the file on disk;
|
|
79
|
+
// old-side and historical line numbers must not be used to highlight
|
|
80
|
+
// the working file.
|
|
81
|
+
linesInWorkingFile: !isOld && model.challenger.source === Git.Diff.SpecialRef.WORKING,
|
|
82
|
+
text: sliceLines(isOld ? oldText : newText, startLine, endLine),
|
|
83
|
+
location: `the ${sideName(startSide)} (${ref}) of the current git diff`,
|
|
84
|
+
// New-side lines read as the file's current content, so only old-side
|
|
85
|
+
// ranges need a clarifying tag in the popup header.
|
|
86
|
+
...(isOld ? { note: trans.__('old version') } : {})
|
|
87
|
+
},
|
|
88
|
+
anchor
|
|
89
|
+
};
|
|
90
|
+
}
|
package/lib/git/commands.d.ts
CHANGED
|
@@ -2,7 +2,9 @@ import { JupyterFrontEnd } from '@jupyterlab/application';
|
|
|
2
2
|
import { IThemeManager, MainAreaWidget } from '@jupyterlab/apputils';
|
|
3
3
|
import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
|
|
4
4
|
import { Contents } from '@jupyterlab/services';
|
|
5
|
+
import type { TranslationBundle } from '@jupyterlab/translation';
|
|
5
6
|
import { ISignal } from '@lumino/signaling';
|
|
7
|
+
import type { IAskAgent } from '../askAgent/tokens';
|
|
6
8
|
import { XtralabDiffWidget } from './diffWidget';
|
|
7
9
|
import { IFileChange } from './tokens';
|
|
8
10
|
/**
|
|
@@ -33,7 +35,7 @@ export declare function pinnedDiffWidgetId(change: IFileChange): string;
|
|
|
33
35
|
* Launcher-owned host for a shared diff widget.
|
|
34
36
|
*/
|
|
35
37
|
export declare class DiffMainAreaWidget extends MainAreaWidget<XtralabDiffWidget> {
|
|
36
|
-
constructor(options: MainAreaWidget.IOptions<XtralabDiffWidget>, change: IFileChange, pinned: boolean);
|
|
38
|
+
constructor(options: MainAreaWidget.IOptions<XtralabDiffWidget>, change: IFileChange, pinned: boolean, trans: TranslationBundle);
|
|
37
39
|
get change(): IFileChange;
|
|
38
40
|
get pinned(): boolean;
|
|
39
41
|
pin(): void;
|
|
@@ -41,9 +43,10 @@ export declare class DiffMainAreaWidget extends MainAreaWidget<XtralabDiffWidget
|
|
|
41
43
|
setChange(repoPath: string, change: IFileChange): void;
|
|
42
44
|
private _change;
|
|
43
45
|
private _pinned;
|
|
46
|
+
private _trans;
|
|
44
47
|
private _pinnedChanged;
|
|
45
48
|
}
|
|
46
|
-
|
|
49
|
+
interface IRegisterGitCommandsOptions {
|
|
47
50
|
app: JupyterFrontEnd;
|
|
48
51
|
themeManager: IThemeManager | null;
|
|
49
52
|
/**
|
|
@@ -54,6 +57,14 @@ export interface IRegisterGitCommandsOptions {
|
|
|
54
57
|
* Rendermime registry used by notebook diffs; may be `null`.
|
|
55
58
|
*/
|
|
56
59
|
rendermime: IRenderMimeRegistry | null;
|
|
60
|
+
/**
|
|
61
|
+
* Ask-agent popup for prompting an agent about diff lines; may be `null`.
|
|
62
|
+
*/
|
|
63
|
+
askAgent: IAskAgent | null;
|
|
64
|
+
/**
|
|
65
|
+
* Translation bundle for user-facing strings.
|
|
66
|
+
*/
|
|
67
|
+
trans: TranslationBundle;
|
|
57
68
|
/**
|
|
58
69
|
* Track newly created diff widgets before they are added to the shell.
|
|
59
70
|
*/
|
|
@@ -69,3 +80,4 @@ export interface IRegisterGitCommandsOptions {
|
|
|
69
80
|
* registry.
|
|
70
81
|
*/
|
|
71
82
|
export declare function registerGitCommands(options: IRegisterGitCommandsOptions): void;
|
|
83
|
+
export {};
|
package/lib/git/commands.js
CHANGED
|
@@ -21,21 +21,22 @@ export const PREVIEW_DIFF_WIDGET_ID = 'xtralab:diff:preview';
|
|
|
21
21
|
export function pinnedDiffWidgetId(change) {
|
|
22
22
|
return `xtralab:diff:pinned:${change.group}:${change.path}`;
|
|
23
23
|
}
|
|
24
|
-
function formatTitle(change) {
|
|
24
|
+
function formatTitle(change, trans) {
|
|
25
25
|
var _a;
|
|
26
26
|
const name = (_a = change.path.split('/').pop()) !== null && _a !== void 0 ? _a : change.path;
|
|
27
|
-
const groupLabel = change.group === 'staged' ? 'Staged' : 'Working';
|
|
27
|
+
const groupLabel = change.group === 'staged' ? trans.__('Staged') : trans.__('Working');
|
|
28
28
|
return `${name} (${groupLabel})`;
|
|
29
29
|
}
|
|
30
30
|
/**
|
|
31
31
|
* Launcher-owned host for a shared diff widget.
|
|
32
32
|
*/
|
|
33
33
|
export class DiffMainAreaWidget extends MainAreaWidget {
|
|
34
|
-
constructor(options, change, pinned) {
|
|
34
|
+
constructor(options, change, pinned, trans) {
|
|
35
35
|
super(options);
|
|
36
36
|
this._pinnedChanged = new Signal(this);
|
|
37
37
|
this._change = change;
|
|
38
38
|
this._pinned = pinned;
|
|
39
|
+
this._trans = trans;
|
|
39
40
|
}
|
|
40
41
|
get change() {
|
|
41
42
|
return this._change;
|
|
@@ -56,7 +57,7 @@ export class DiffMainAreaWidget extends MainAreaWidget {
|
|
|
56
57
|
setChange(repoPath, change) {
|
|
57
58
|
this._change = change;
|
|
58
59
|
this.content.setModel(fileChangeToDiffModel(repoPath, change));
|
|
59
|
-
this.title.label = formatTitle(change);
|
|
60
|
+
this.title.label = formatTitle(change, this._trans);
|
|
60
61
|
this.title.caption = change.path;
|
|
61
62
|
this.title.icon = getTreeIcon(change.path);
|
|
62
63
|
}
|
|
@@ -66,12 +67,12 @@ export class DiffMainAreaWidget extends MainAreaWidget {
|
|
|
66
67
|
*/
|
|
67
68
|
function createDiffWidget(options) {
|
|
68
69
|
var _a;
|
|
69
|
-
const { repoPath, change, themeManager, contentsManager, rendermime } = options;
|
|
70
|
+
const { repoPath, change, themeManager, contentsManager, rendermime, askAgent, trans } = options;
|
|
70
71
|
const pinned = options.pinned === true;
|
|
71
|
-
const content = new XtralabDiffWidget(fileChangeToDiffModel(repoPath, change), { contentsManager, rendermime, themeManager });
|
|
72
|
-
const widget = new DiffMainAreaWidget({ content }, change, pinned);
|
|
72
|
+
const content = new XtralabDiffWidget(fileChangeToDiffModel(repoPath, change), { contentsManager, rendermime, themeManager, askAgent, trans });
|
|
73
|
+
const widget = new DiffMainAreaWidget({ content }, change, pinned, trans);
|
|
73
74
|
widget.id = pinned ? pinnedDiffWidgetId(change) : PREVIEW_DIFF_WIDGET_ID;
|
|
74
|
-
widget.title.label = formatTitle(change);
|
|
75
|
+
widget.title.label = formatTitle(change, trans);
|
|
75
76
|
widget.title.caption = change.path;
|
|
76
77
|
widget.title.closable = true;
|
|
77
78
|
widget.title.icon = getTreeIcon(change.path);
|
|
@@ -80,7 +81,7 @@ function createDiffWidget(options) {
|
|
|
80
81
|
const onPinned = (_a = options.onPinned) !== null && _a !== void 0 ? _a : (() => undefined);
|
|
81
82
|
const pinButton = new ToolbarButton({
|
|
82
83
|
icon: launchIcon,
|
|
83
|
-
tooltip: 'Pin tab',
|
|
84
|
+
tooltip: trans.__('Pin tab'),
|
|
84
85
|
onClick: () => widget.pin()
|
|
85
86
|
});
|
|
86
87
|
if (widget.pinned) {
|
|
@@ -100,7 +101,7 @@ function createDiffWidget(options) {
|
|
|
100
101
|
widget.toolbar.hide();
|
|
101
102
|
}
|
|
102
103
|
};
|
|
103
|
-
const onPinnedChanged = (
|
|
104
|
+
const onPinnedChanged = (sender, value) => {
|
|
104
105
|
if (widget.isDisposed) {
|
|
105
106
|
return;
|
|
106
107
|
}
|
|
@@ -138,11 +139,11 @@ function createDiffWidget(options) {
|
|
|
138
139
|
* registry.
|
|
139
140
|
*/
|
|
140
141
|
export function registerGitCommands(options) {
|
|
141
|
-
const { app, themeManager, contentsManager, rendermime, trackDiff, findDiff, onPinned } = options;
|
|
142
|
+
const { app, themeManager, contentsManager, rendermime, askAgent, trans, trackDiff, findDiff, onPinned } = options;
|
|
142
143
|
const { commands } = app;
|
|
143
144
|
commands.addCommand(CommandIDs.openDiff, {
|
|
144
|
-
label: 'Open Git Diff',
|
|
145
|
-
caption: 'Open a side-by-side diff for a changed file',
|
|
145
|
+
label: trans.__('Open Git Diff'),
|
|
146
|
+
caption: trans.__('Open a side-by-side diff for a changed file'),
|
|
146
147
|
execute: async (args) => {
|
|
147
148
|
const typed = args;
|
|
148
149
|
if ((typed === null || typed === void 0 ? void 0 : typed.change) === undefined) {
|
|
@@ -163,6 +164,8 @@ export function registerGitCommands(options) {
|
|
|
163
164
|
themeManager,
|
|
164
165
|
contentsManager,
|
|
165
166
|
rendermime,
|
|
167
|
+
askAgent,
|
|
168
|
+
trans,
|
|
166
169
|
pinned: pin,
|
|
167
170
|
onPinned
|
|
168
171
|
});
|
package/lib/git/diffModel.d.ts
CHANGED
|
@@ -1,13 +1,5 @@
|
|
|
1
1
|
import type { IXtralabDiffModel } from './diffWidget';
|
|
2
|
-
import type {
|
|
3
|
-
/**
|
|
4
|
-
* Resolve the old/new git refs for a launcher file change. Staged diffs are
|
|
5
|
-
* INDEX vs HEAD; unstaged diffs are WORKING vs INDEX.
|
|
6
|
-
*/
|
|
7
|
-
export declare function resolveReferences(change: IFileChange): {
|
|
8
|
-
oldRef: GitReference | null;
|
|
9
|
-
newRef: GitReference | null;
|
|
10
|
-
};
|
|
2
|
+
import type { IFileChange } from './tokens';
|
|
11
3
|
/**
|
|
12
4
|
* Build a diff model for a single {@link IFileChange}.
|
|
13
5
|
*/
|
package/lib/git/diffModel.js
CHANGED
|
@@ -5,7 +5,7 @@ import { content } from './api';
|
|
|
5
5
|
* Resolve the old/new git refs for a launcher file change. Staged diffs are
|
|
6
6
|
* INDEX vs HEAD; unstaged diffs are WORKING vs INDEX.
|
|
7
7
|
*/
|
|
8
|
-
|
|
8
|
+
function resolveReferences(change) {
|
|
9
9
|
if (change.status === 'untracked') {
|
|
10
10
|
return { oldRef: null, newRef: { special: 'WORKING' } };
|
|
11
11
|
}
|
package/lib/git/diffProvider.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { IThemeManager } from '@jupyterlab/apputils';
|
|
2
2
|
import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
|
|
3
|
+
import { ITranslator, nullTranslator } from '@jupyterlab/translation';
|
|
3
4
|
import { IGitExtension } from '@jupyterlab/git';
|
|
5
|
+
import { IAskAgent } from '../askAgent/tokens';
|
|
4
6
|
import { XtralabDiffWidget, addDiffToolbarItems } from './diffWidget';
|
|
5
7
|
import { IMAGE_DIFF_EXTENSIONS } from './imageDiff';
|
|
6
8
|
/**
|
|
@@ -20,12 +22,15 @@ const diffProviderPlugin = {
|
|
|
20
22
|
description: "Replaces jupyterlab-git's notebook, text and image diff plugins with xtralab's renderer.",
|
|
21
23
|
autoStart: true,
|
|
22
24
|
requires: [IGitExtension],
|
|
23
|
-
optional: [IRenderMimeRegistry, IThemeManager],
|
|
24
|
-
activate: (app, gitExtension, rendermime, themeManager) => {
|
|
25
|
+
optional: [IRenderMimeRegistry, IThemeManager, ITranslator, IAskAgent],
|
|
26
|
+
activate: (app, gitExtension, rendermime, themeManager, translator, askAgent) => {
|
|
27
|
+
const trans = (translator !== null && translator !== void 0 ? translator : nullTranslator).load('jupyterlab');
|
|
25
28
|
const factory = makeXtralabDiffFactory({
|
|
26
29
|
contentsManager: app.serviceManager.contents,
|
|
27
30
|
rendermime,
|
|
28
|
-
themeManager
|
|
31
|
+
themeManager,
|
|
32
|
+
askAgent,
|
|
33
|
+
trans
|
|
29
34
|
});
|
|
30
35
|
// Use one shared factory; the surface detects notebooks/images by filename.
|
|
31
36
|
gitExtension.registerDiffProvider('XtralabNotebook', ['.ipynb'], factory);
|
package/lib/git/diffSurface.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { IThemeManager } from '@jupyterlab/apputils';
|
|
3
3
|
import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
|
|
4
|
+
import type { TranslationBundle } from '@jupyterlab/translation';
|
|
5
|
+
import { type SelectedLineRange } from '@pierre/diffs';
|
|
4
6
|
/**
|
|
5
7
|
* The CSS class added to the diff main-area widget. The selectors that
|
|
6
8
|
* style the embedded `@pierre/diffs` viewer hang off this class.
|
|
@@ -42,12 +44,12 @@ export declare function isPierreTheme(themeManager: IThemeManager | null): boole
|
|
|
42
44
|
* the on-disk path) and triggers any follow-up refresh in
|
|
43
45
|
* {@link IHunkDiscard.onAfterSave}.
|
|
44
46
|
*/
|
|
45
|
-
|
|
47
|
+
interface IHunkDiscard {
|
|
46
48
|
enabled: boolean;
|
|
47
49
|
save: (fullText: string) => Promise<void>;
|
|
48
50
|
onAfterSave: () => void;
|
|
49
51
|
}
|
|
50
|
-
|
|
52
|
+
interface IDiffSurfaceProps {
|
|
51
53
|
/**
|
|
52
54
|
* Whether the host is still resolving the file contents.
|
|
53
55
|
*/
|
|
@@ -124,6 +126,18 @@ export interface IDiffSurfaceProps {
|
|
|
124
126
|
* Optional per-hunk discard wiring; omit for a read-only diff.
|
|
125
127
|
*/
|
|
126
128
|
hunkDiscard?: IHunkDiscard;
|
|
129
|
+
/**
|
|
130
|
+
* When provided, the textual/code file diff gets line selection: clicking
|
|
131
|
+
* or dragging over the line numbers selects a range, and a gutter "+"
|
|
132
|
+
* button appears on the hovered/selected lines. Clicking that button
|
|
133
|
+
* invokes this callback with the selected range and the button's viewport
|
|
134
|
+
* rectangle (to anchor a popup to), `null` when it cannot be measured.
|
|
135
|
+
*/
|
|
136
|
+
onLineAsk?: (range: SelectedLineRange, anchor: DOMRect | null) => void;
|
|
137
|
+
/**
|
|
138
|
+
* Translation bundle for user-facing strings.
|
|
139
|
+
*/
|
|
140
|
+
trans: TranslationBundle;
|
|
127
141
|
}
|
|
128
142
|
/**
|
|
129
143
|
* Shared renderer for text, notebook and image diffs.
|
|
@@ -139,6 +153,7 @@ export declare function NotebookViewModeControl(props: {
|
|
|
139
153
|
mode: NotebookDiffViewMode;
|
|
140
154
|
available: boolean;
|
|
141
155
|
onChange: (mode: NotebookDiffViewMode) => void;
|
|
156
|
+
trans: TranslationBundle;
|
|
142
157
|
}): React.ReactElement;
|
|
143
158
|
/**
|
|
144
159
|
* Segmented Split/Unified selector. Mirrors {@link NotebookViewModeControl}:
|
|
@@ -151,4 +166,6 @@ export declare function DiffStyleControl(props: {
|
|
|
151
166
|
diffStyle: DiffStyle;
|
|
152
167
|
available: boolean;
|
|
153
168
|
onChange: (style: DiffStyle) => void;
|
|
169
|
+
trans: TranslationBundle;
|
|
154
170
|
}): React.ReactElement;
|
|
171
|
+
export {};
|