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
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
import { Signal, ISignal } from '@lumino/signaling';
|
|
18
18
|
import { AccordionPanel, PanelLayout, Widget } from '@lumino/widgets';
|
|
19
19
|
|
|
20
|
+
import type { IFileChange } from '../git/tokens';
|
|
20
21
|
import { FileBrowserComponent } from './fileBrowser';
|
|
21
22
|
import { xtralabFileBrowserIcon } from './icons';
|
|
22
23
|
|
|
@@ -42,10 +43,26 @@ const ACCORDION_CSS_CLASS = 'jp-xtralab-FileBrowser-accordion';
|
|
|
42
43
|
|
|
43
44
|
const MOVABLE_SECTION_CLASS = 'jp-movable-section';
|
|
44
45
|
|
|
46
|
+
/**
|
|
47
|
+
* The options used to create an {@link XtralabFileBrowser}.
|
|
48
|
+
*/
|
|
45
49
|
interface IXtralabFileBrowserOptions {
|
|
50
|
+
/**
|
|
51
|
+
* The contents manager backing the tree.
|
|
52
|
+
*/
|
|
46
53
|
contentsManager: Contents.IManager;
|
|
54
|
+
/**
|
|
55
|
+
* The document manager used to open files from the tree.
|
|
56
|
+
*/
|
|
47
57
|
docManager: IDocumentManager;
|
|
58
|
+
/**
|
|
59
|
+
* Callback invoked with a file's server path when its row is
|
|
60
|
+
* double-clicked. No double-click handler is installed when absent.
|
|
61
|
+
*/
|
|
48
62
|
onOpenFile?: (serverPath: string) => void;
|
|
63
|
+
/**
|
|
64
|
+
* The application language translator.
|
|
65
|
+
*/
|
|
49
66
|
translator?: ITranslator;
|
|
50
67
|
}
|
|
51
68
|
|
|
@@ -56,82 +73,68 @@ interface IXtralabFileBrowserOptions {
|
|
|
56
73
|
*/
|
|
57
74
|
export interface IXtralabFileBrowser {
|
|
58
75
|
/**
|
|
59
|
-
* The contents manager backing the tree
|
|
60
|
-
*
|
|
61
|
-
* drive the tree was loaded from.
|
|
76
|
+
* The contents manager backing the tree; command handlers issue rename,
|
|
77
|
+
* delete, copy, … against the same drive.
|
|
62
78
|
*/
|
|
63
79
|
readonly contentsManager: Contents.IManager;
|
|
64
80
|
|
|
65
81
|
/**
|
|
66
|
-
* The toolbar
|
|
67
|
-
* buttons after the widget is constructed.
|
|
82
|
+
* The toolbar above the tree, populated by plugin code after construction.
|
|
68
83
|
*/
|
|
69
84
|
readonly toolbar: Toolbar;
|
|
70
85
|
|
|
71
86
|
/**
|
|
72
|
-
* Canonical paths
|
|
73
|
-
* paths carry a trailing slash; file paths do not.
|
|
87
|
+
* Canonical selected paths; folder paths carry a trailing slash.
|
|
74
88
|
*/
|
|
75
89
|
readonly selectedPaths: readonly string[];
|
|
76
90
|
|
|
77
91
|
/**
|
|
78
|
-
* Emits when the tree's selection changes.
|
|
79
|
-
* `isVisible` / `isEnabled` predicate should listen so they re-evaluate.
|
|
92
|
+
* Emits when the tree's selection changes.
|
|
80
93
|
*/
|
|
81
94
|
readonly selectionChanged: ISignal<IXtralabFileBrowser, readonly string[]>;
|
|
82
95
|
|
|
83
96
|
/**
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
|
|
97
|
+
* Git changes from the latest status poll, one per staged or unstaged
|
|
98
|
+
* change; paths are repo-relative.
|
|
99
|
+
*/
|
|
100
|
+
readonly gitChanges: readonly IFileChange[];
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Emits when {@link refresh} is called.
|
|
87
104
|
*/
|
|
88
105
|
readonly refreshRequested: ISignal<IXtralabFileBrowser, void>;
|
|
89
106
|
|
|
90
107
|
/**
|
|
91
|
-
* Emits
|
|
92
|
-
*
|
|
93
|
-
* component listens and inserts the path into the model so the user
|
|
94
|
-
* sees the new item without a full refresh.
|
|
108
|
+
* Emits a newly-created canonical path so the tree inserts it without a
|
|
109
|
+
* full refresh.
|
|
95
110
|
*/
|
|
96
111
|
readonly pathAdded: ISignal<IXtralabFileBrowser, string>;
|
|
97
112
|
|
|
98
113
|
/**
|
|
99
|
-
* Emits
|
|
100
|
-
* the
|
|
101
|
-
* any unloaded ancestor directories, expands them, and selects the
|
|
102
|
-
* target. Used by the editor breadcrumbs to jump back to a file or
|
|
103
|
-
* folder shown in the breadcrumb trail.
|
|
114
|
+
* Emits a canonical path to load, expand, select, and scroll to. Used by
|
|
115
|
+
* the editor breadcrumbs.
|
|
104
116
|
*/
|
|
105
117
|
readonly revealRequested: ISignal<IXtralabFileBrowser, string>;
|
|
106
118
|
|
|
107
119
|
/**
|
|
108
|
-
* Emits when
|
|
109
|
-
*
|
|
110
|
-
* first row. Distinct from {@link revealRequested} because the
|
|
111
|
-
* workspace root has no tree row of its own — it cannot be reached
|
|
112
|
-
* by passing a path.
|
|
120
|
+
* Emits when the tree should return to the workspace root — the root has
|
|
121
|
+
* no tree row of its own, so it cannot be revealed by path.
|
|
113
122
|
*/
|
|
114
123
|
readonly rootRequested: ISignal<IXtralabFileBrowser, void>;
|
|
115
124
|
|
|
116
125
|
/**
|
|
117
|
-
* Emits when
|
|
118
|
-
* expanded folder. The React component listens and walks the loaded
|
|
119
|
-
* directories, calling `.collapse()` on each expanded one.
|
|
126
|
+
* Emits when every expanded folder should collapse.
|
|
120
127
|
*/
|
|
121
128
|
readonly collapseAllRequested: ISignal<IXtralabFileBrowser, void>;
|
|
122
129
|
|
|
123
130
|
/**
|
|
124
|
-
* Whether the filter box above the tree is shown
|
|
125
|
-
*
|
|
126
|
-
* toolbar toggle. Also forced to `true` when the tree opens a search
|
|
127
|
-
* session on its own — typing a letter while the tree has focus.
|
|
131
|
+
* Whether the filter box above the tree is shown; also forced `true` when
|
|
132
|
+
* the tree opens a search session itself (typing while it has focus).
|
|
128
133
|
*/
|
|
129
134
|
readonly fileFilterVisible: boolean;
|
|
130
135
|
|
|
131
136
|
/**
|
|
132
|
-
* Emits when {@link fileFilterVisible} changes.
|
|
133
|
-
* listens to show or hide the filter box; the toggle command listens
|
|
134
|
-
* to refresh its toggled state.
|
|
137
|
+
* Emits when {@link fileFilterVisible} changes.
|
|
135
138
|
*/
|
|
136
139
|
readonly fileFilterVisibleChanged: ISignal<IXtralabFileBrowser, boolean>;
|
|
137
140
|
|
|
@@ -141,24 +144,19 @@ export interface IXtralabFileBrowser {
|
|
|
141
144
|
refresh(): void;
|
|
142
145
|
|
|
143
146
|
/**
|
|
144
|
-
* Notify the React component that a new path was created and
|
|
145
|
-
* appear in the tree.
|
|
146
|
-
* convention: directories carry a trailing slash, files do not.
|
|
147
|
+
* Notify the React component that a new canonical path was created and
|
|
148
|
+
* should appear in the tree.
|
|
147
149
|
*/
|
|
148
150
|
notifyPathAdded(canonicalPath: string): void;
|
|
149
151
|
|
|
150
152
|
/**
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
* into view. `canonicalPath` follows the `@pierre/trees` convention
|
|
154
|
-
* (directories carry a trailing slash, files do not). Must be a
|
|
155
|
-
* non-empty path — use {@link scrollToRoot} for the root gesture.
|
|
153
|
+
* Reveal a non-empty canonical path: load and expand ancestors, then
|
|
154
|
+
* select and scroll to it. Use {@link scrollToRoot} for the root gesture.
|
|
156
155
|
*/
|
|
157
156
|
reveal(canonicalPath: string): void;
|
|
158
157
|
|
|
159
158
|
/**
|
|
160
|
-
*
|
|
161
|
-
* selection and scroll back to the top of the tree.
|
|
159
|
+
* Return to the workspace root: clear the selection and scroll to the top.
|
|
162
160
|
*/
|
|
163
161
|
scrollToRoot(): void;
|
|
164
162
|
|
|
@@ -177,6 +175,10 @@ export interface IXtralabFileBrowser {
|
|
|
177
175
|
*/
|
|
178
176
|
toggleFileFilter(): void;
|
|
179
177
|
|
|
178
|
+
/**
|
|
179
|
+
* The DOM node of the movable "Files" section, used to locate the panel
|
|
180
|
+
* currently hosting the tree.
|
|
181
|
+
*/
|
|
180
182
|
readonly sectionNode: HTMLElement;
|
|
181
183
|
}
|
|
182
184
|
|
|
@@ -228,67 +230,123 @@ export class XtralabFileBrowser
|
|
|
228
230
|
layout.addWidget(this._section);
|
|
229
231
|
}
|
|
230
232
|
|
|
233
|
+
/**
|
|
234
|
+
* The contents manager backing the tree.
|
|
235
|
+
*/
|
|
231
236
|
get contentsManager(): Contents.IManager {
|
|
232
237
|
return this._contentsManager;
|
|
233
238
|
}
|
|
234
239
|
|
|
240
|
+
/**
|
|
241
|
+
* The toolbar above the tree.
|
|
242
|
+
*/
|
|
235
243
|
get toolbar(): Toolbar {
|
|
236
244
|
return this._toolbar;
|
|
237
245
|
}
|
|
238
246
|
|
|
247
|
+
/**
|
|
248
|
+
* Canonical selected paths; folder paths carry a trailing slash.
|
|
249
|
+
*/
|
|
239
250
|
get selectedPaths(): readonly string[] {
|
|
240
251
|
return this._selectedPaths;
|
|
241
252
|
}
|
|
242
253
|
|
|
254
|
+
/**
|
|
255
|
+
* A signal emitted when the tree's selection changes.
|
|
256
|
+
*/
|
|
243
257
|
get selectionChanged(): ISignal<this, readonly string[]> {
|
|
244
258
|
return this._selectionChanged;
|
|
245
259
|
}
|
|
246
260
|
|
|
261
|
+
/**
|
|
262
|
+
* Git changes from the latest status poll.
|
|
263
|
+
*/
|
|
264
|
+
get gitChanges(): readonly IFileChange[] {
|
|
265
|
+
return this._gitChanges;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* A signal emitted when {@link refresh} is called.
|
|
270
|
+
*/
|
|
247
271
|
get refreshRequested(): ISignal<this, void> {
|
|
248
272
|
return this._refreshRequested;
|
|
249
273
|
}
|
|
250
274
|
|
|
275
|
+
/**
|
|
276
|
+
* A signal emitting a newly-created canonical path for the tree to insert.
|
|
277
|
+
*/
|
|
251
278
|
get pathAdded(): ISignal<this, string> {
|
|
252
279
|
return this._pathAdded;
|
|
253
280
|
}
|
|
254
281
|
|
|
282
|
+
/**
|
|
283
|
+
* A signal emitting a canonical path to load, expand, select, and scroll to.
|
|
284
|
+
*/
|
|
255
285
|
get revealRequested(): ISignal<this, string> {
|
|
256
286
|
return this._revealRequested;
|
|
257
287
|
}
|
|
258
288
|
|
|
289
|
+
/**
|
|
290
|
+
* A signal emitted when the tree should return to the workspace root.
|
|
291
|
+
*/
|
|
259
292
|
get rootRequested(): ISignal<this, void> {
|
|
260
293
|
return this._rootRequested;
|
|
261
294
|
}
|
|
262
295
|
|
|
296
|
+
/**
|
|
297
|
+
* A signal emitted when every expanded folder should collapse.
|
|
298
|
+
*/
|
|
263
299
|
get collapseAllRequested(): ISignal<this, void> {
|
|
264
300
|
return this._collapseAllRequested;
|
|
265
301
|
}
|
|
266
302
|
|
|
303
|
+
/**
|
|
304
|
+
* Whether the filter box above the tree is shown.
|
|
305
|
+
*/
|
|
267
306
|
get fileFilterVisible(): boolean {
|
|
268
307
|
return this._fileFilterVisible;
|
|
269
308
|
}
|
|
270
309
|
|
|
310
|
+
/**
|
|
311
|
+
* A signal emitted when {@link fileFilterVisible} changes.
|
|
312
|
+
*/
|
|
271
313
|
get fileFilterVisibleChanged(): ISignal<this, boolean> {
|
|
272
314
|
return this._fileFilterVisibleChanged;
|
|
273
315
|
}
|
|
274
316
|
|
|
275
317
|
/**
|
|
276
|
-
* Update the cached selection
|
|
277
|
-
* underlying `@pierre/trees` model emits a selection change.
|
|
318
|
+
* Update the cached selection from the React tree.
|
|
278
319
|
*/
|
|
279
320
|
updateSelection(paths: readonly string[]): void {
|
|
280
321
|
this._selectedPaths = paths;
|
|
281
322
|
this._selectionChanged.emit(paths);
|
|
282
323
|
}
|
|
283
324
|
|
|
325
|
+
/**
|
|
326
|
+
* Update the cached git changes from the React tree's status poll.
|
|
327
|
+
*/
|
|
328
|
+
updateGitChanges(changes: readonly IFileChange[]): void {
|
|
329
|
+
this._gitChanges = changes;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Trigger a refresh of every loaded directory in the tree.
|
|
334
|
+
*/
|
|
284
335
|
refresh(): void {
|
|
285
336
|
this._refreshRequested.emit();
|
|
286
337
|
}
|
|
287
338
|
|
|
339
|
+
/**
|
|
340
|
+
* Notify the tree that a new canonical path was created.
|
|
341
|
+
*/
|
|
288
342
|
notifyPathAdded(canonicalPath: string): void {
|
|
289
343
|
this._pathAdded.emit(canonicalPath);
|
|
290
344
|
}
|
|
291
345
|
|
|
346
|
+
/**
|
|
347
|
+
* Reveal a non-empty canonical path in the tree; use {@link scrollToRoot}
|
|
348
|
+
* for the workspace root, which has no tree row of its own.
|
|
349
|
+
*/
|
|
292
350
|
reveal(canonicalPath: string): void {
|
|
293
351
|
if (canonicalPath.length === 0) {
|
|
294
352
|
throw new Error(
|
|
@@ -298,14 +356,23 @@ export class XtralabFileBrowser
|
|
|
298
356
|
this._revealRequested.emit(canonicalPath);
|
|
299
357
|
}
|
|
300
358
|
|
|
359
|
+
/**
|
|
360
|
+
* Return to the workspace root: clear the selection and scroll to the top.
|
|
361
|
+
*/
|
|
301
362
|
scrollToRoot(): void {
|
|
302
363
|
this._rootRequested.emit();
|
|
303
364
|
}
|
|
304
365
|
|
|
366
|
+
/**
|
|
367
|
+
* Ask the tree to collapse every currently expanded folder.
|
|
368
|
+
*/
|
|
305
369
|
collapseAll(): void {
|
|
306
370
|
this._collapseAllRequested.emit();
|
|
307
371
|
}
|
|
308
372
|
|
|
373
|
+
/**
|
|
374
|
+
* Show or hide the filter box above the tree.
|
|
375
|
+
*/
|
|
309
376
|
setFileFilterVisible(visible: boolean): void {
|
|
310
377
|
if (this._fileFilterVisible === visible) {
|
|
311
378
|
return;
|
|
@@ -314,30 +381,51 @@ export class XtralabFileBrowser
|
|
|
314
381
|
this._fileFilterVisibleChanged.emit(visible);
|
|
315
382
|
}
|
|
316
383
|
|
|
384
|
+
/**
|
|
385
|
+
* Toggle the filter box above the tree.
|
|
386
|
+
*/
|
|
317
387
|
toggleFileFilter(): void {
|
|
318
388
|
this.setFileFilterVisible(!this._fileFilterVisible);
|
|
319
389
|
}
|
|
320
390
|
|
|
391
|
+
/**
|
|
392
|
+
* The DOM node of the movable "Files" section.
|
|
393
|
+
*/
|
|
321
394
|
get sectionNode(): HTMLElement {
|
|
322
395
|
return this._section.node;
|
|
323
396
|
}
|
|
324
397
|
|
|
398
|
+
/**
|
|
399
|
+
* Whether the panel currently holds no sections, its own tree included.
|
|
400
|
+
*/
|
|
325
401
|
get isEmpty(): boolean {
|
|
326
402
|
return this._panelLayout.widgets.length === 0;
|
|
327
403
|
}
|
|
328
404
|
|
|
405
|
+
/**
|
|
406
|
+
* A signal emitted when a section is added to or removed from the panel.
|
|
407
|
+
*/
|
|
329
408
|
get contentChanged(): ISignal<this, void> {
|
|
330
409
|
return this._contentChanged;
|
|
331
410
|
}
|
|
332
411
|
|
|
412
|
+
/**
|
|
413
|
+
* A signal emitting each section entry announced to the move plugin.
|
|
414
|
+
*/
|
|
333
415
|
get sectionAdded(): ISignal<this, ISectionEntry> {
|
|
334
416
|
return this._sectionAdded;
|
|
335
417
|
}
|
|
336
418
|
|
|
419
|
+
/**
|
|
420
|
+
* The accordion hosting the sections, or `null` while the tree sits alone.
|
|
421
|
+
*/
|
|
337
422
|
get accordionPanel(): AccordionPanel | null {
|
|
338
423
|
return this._accordion;
|
|
339
424
|
}
|
|
340
425
|
|
|
426
|
+
/**
|
|
427
|
+
* Section widgets hosted from other panels; the tree section is excluded.
|
|
428
|
+
*/
|
|
341
429
|
get sections(): ReadonlyArray<Widget> {
|
|
342
430
|
if (!this._accordion) {
|
|
343
431
|
return [];
|
|
@@ -361,6 +449,10 @@ export class XtralabFileBrowser
|
|
|
361
449
|
: [];
|
|
362
450
|
}
|
|
363
451
|
|
|
452
|
+
/**
|
|
453
|
+
* Detach and return the tree section so the move plugin can re-host it;
|
|
454
|
+
* `null` for any other id or when the section is already away from home.
|
|
455
|
+
*/
|
|
364
456
|
removeSectionById(sectionId: string): Widget | null {
|
|
365
457
|
if (sectionId !== TREE_SECTION_ID || !this._isSectionHome()) {
|
|
366
458
|
return null;
|
|
@@ -377,6 +469,9 @@ export class XtralabFileBrowser
|
|
|
377
469
|
return this._section;
|
|
378
470
|
}
|
|
379
471
|
|
|
472
|
+
/**
|
|
473
|
+
* Re-attach the tree section after a move back to this panel.
|
|
474
|
+
*/
|
|
380
475
|
reinsertSection(widget: Widget): void {
|
|
381
476
|
if (this._accordion) {
|
|
382
477
|
this._accordion.insertWidget(0, widget);
|
|
@@ -418,6 +513,10 @@ export class XtralabFileBrowser
|
|
|
418
513
|
this._contentChanged.emit();
|
|
419
514
|
}
|
|
420
515
|
|
|
516
|
+
/**
|
|
517
|
+
* Remove a hosted section; the accordion is torn down once only the
|
|
518
|
+
* panel's own tree section (or nothing) remains.
|
|
519
|
+
*/
|
|
421
520
|
removeSectionWidget(widget: Widget): void {
|
|
422
521
|
if (!this._accordion || widget.parent !== this._accordion) {
|
|
423
522
|
return;
|
|
@@ -459,6 +558,7 @@ export class XtralabFileBrowser
|
|
|
459
558
|
private _translator: ITranslator | undefined;
|
|
460
559
|
private _selectedPaths: readonly string[] = [];
|
|
461
560
|
private _selectionChanged = new Signal<this, readonly string[]>(this);
|
|
561
|
+
private _gitChanges: readonly IFileChange[] = [];
|
|
462
562
|
private _refreshRequested = new Signal<this, void>(this);
|
|
463
563
|
private _pathAdded = new Signal<this, string>(this);
|
|
464
564
|
private _revealRequested = new Signal<this, string>(this);
|
|
@@ -475,17 +575,35 @@ export class XtralabFileBrowser
|
|
|
475
575
|
private _sectionAdded = new Signal<this, ISectionEntry>(this);
|
|
476
576
|
}
|
|
477
577
|
|
|
578
|
+
/**
|
|
579
|
+
* The options used to create an {@link XtralabFileTreeContent}.
|
|
580
|
+
*/
|
|
478
581
|
interface IFileTreeContentOptions {
|
|
582
|
+
/**
|
|
583
|
+
* The contents manager backing the tree.
|
|
584
|
+
*/
|
|
479
585
|
contentsManager: Contents.IManager;
|
|
586
|
+
/**
|
|
587
|
+
* The document manager used to open files from the tree.
|
|
588
|
+
*/
|
|
480
589
|
docManager: IDocumentManager;
|
|
590
|
+
/**
|
|
591
|
+
* Callback invoked with a file's server path when its row is
|
|
592
|
+
* double-clicked. No double-click handler is installed when absent.
|
|
593
|
+
*/
|
|
481
594
|
onOpenFile?: (serverPath: string) => void;
|
|
595
|
+
/**
|
|
596
|
+
* The application language translator.
|
|
597
|
+
*/
|
|
482
598
|
translator?: ITranslator;
|
|
599
|
+
/**
|
|
600
|
+
* The host widget the React tree reports selection and state changes to.
|
|
601
|
+
*/
|
|
483
602
|
browser: XtralabFileBrowser;
|
|
484
603
|
}
|
|
485
604
|
|
|
486
605
|
/**
|
|
487
|
-
* The React-rendered region
|
|
488
|
-
* widget below the toolbar and renders the actual tree.
|
|
606
|
+
* The React-rendered region below the toolbar that hosts the actual tree.
|
|
489
607
|
*/
|
|
490
608
|
class XtralabFileTreeContent extends ReactWidget {
|
|
491
609
|
constructor(options: IFileTreeContentOptions) {
|
|
@@ -493,6 +611,9 @@ class XtralabFileTreeContent extends ReactWidget {
|
|
|
493
611
|
this._options = options;
|
|
494
612
|
}
|
|
495
613
|
|
|
614
|
+
/**
|
|
615
|
+
* Render the file browser React component.
|
|
616
|
+
*/
|
|
496
617
|
protected render(): React.ReactElement {
|
|
497
618
|
return (
|
|
498
619
|
<FileBrowserComponent
|
|
@@ -25,13 +25,9 @@ function representativePath(
|
|
|
25
25
|
if (extension === undefined || extension === '') {
|
|
26
26
|
return null;
|
|
27
27
|
}
|
|
28
|
-
// Extensions are stored with a leading dot (e.g. `.py`, `.tar.gz`).
|
|
29
28
|
return `file${extension.startsWith('.') ? extension : `.${extension}`}`;
|
|
30
29
|
}
|
|
31
30
|
|
|
32
|
-
/**
|
|
33
|
-
* Point a file type's icon at the tree glyph for its extension.
|
|
34
|
-
*/
|
|
35
31
|
function applyTreeIcon(fileType: DocumentRegistry.IFileType): void {
|
|
36
32
|
const path = representativePath(fileType);
|
|
37
33
|
if (path === null) {
|
|
@@ -79,9 +75,6 @@ const EXTRA_FILE_TYPE_EXTENSIONS = [
|
|
|
79
75
|
'.wasm'
|
|
80
76
|
];
|
|
81
77
|
|
|
82
|
-
/**
|
|
83
|
-
* Register icon-only file types for unclaimed source extensions.
|
|
84
|
-
*/
|
|
85
78
|
function registerExtraFileTypes(docRegistry: DocumentRegistry): void {
|
|
86
79
|
for (const extension of EXTRA_FILE_TYPE_EXTENSIONS) {
|
|
87
80
|
const icon = getSpecificTreeIcon(`file${extension}`);
|
|
@@ -125,7 +118,6 @@ const plugin: JupyterFrontEndPlugin<void> = {
|
|
|
125
118
|
applyTreeIcon(fileType);
|
|
126
119
|
}
|
|
127
120
|
registerExtraFileTypes(docRegistry);
|
|
128
|
-
// Pick up file types registered after this plugin activates.
|
|
129
121
|
docRegistry.changed.connect((_, args) => {
|
|
130
122
|
if (
|
|
131
123
|
args.type === 'fileType' &&
|
|
@@ -148,8 +140,6 @@ const plugin: JupyterFrontEndPlugin<void> = {
|
|
|
148
140
|
}
|
|
149
141
|
};
|
|
150
142
|
setIcon();
|
|
151
|
-
// Keep the tab icon right after a rename, and release the listener
|
|
152
|
-
// when the document closes.
|
|
153
143
|
widget.context.pathChanged.connect(setIcon);
|
|
154
144
|
widget.disposed.connect(() => {
|
|
155
145
|
widget.context.pathChanged.disconnect(setIcon);
|
package/src/git/api.ts
CHANGED
|
@@ -9,29 +9,15 @@ import {
|
|
|
9
9
|
IGitStatusResult
|
|
10
10
|
} from './tokens';
|
|
11
11
|
|
|
12
|
-
/**
|
|
13
|
-
* Root URL segment used by the `jupyterlab_git` server extension. Every
|
|
14
|
-
* endpoint hangs off this prefix; the `<repoPath>` between it and the
|
|
15
|
-
* endpoint suffix is the JupyterLab server-relative path of the git
|
|
16
|
-
* repository (URL-encoded). For an empty `repoPath` the URL collapses to
|
|
17
|
-
* `/git/<endpoint>` — a shape git's URL routing also accepts.
|
|
18
|
-
*/
|
|
19
12
|
const GIT_NAMESPACE = 'git';
|
|
20
13
|
|
|
21
|
-
/**
|
|
22
|
-
* Issue a `POST` against a `jupyterlab_git` endpoint that takes a `<path>`
|
|
23
|
-
* prefix (e.g. `/git/<path>/status`). The response body is decoded as JSON;
|
|
24
|
-
* non-2xx responses are surfaced via the JupyterLab `ServerConnection`
|
|
25
|
-
* machinery so callers can show their `message` field as-is.
|
|
26
|
-
*/
|
|
27
14
|
async function postWithPath<T>(
|
|
28
15
|
endpoint: string,
|
|
29
16
|
repoPath: string,
|
|
30
17
|
body: unknown
|
|
31
18
|
): Promise<T> {
|
|
32
19
|
const settings = ServerConnection.makeSettings();
|
|
33
|
-
//
|
|
34
|
-
// between them — the server expects the path to look like a posix path.
|
|
20
|
+
// encodeParts keeps the slashes the server's posix-path routing expects.
|
|
35
21
|
const encodedPath = repoPath.length > 0 ? URLExt.encodeParts(repoPath) : '';
|
|
36
22
|
const url = URLExt.join(
|
|
37
23
|
settings.baseUrl,
|
|
@@ -50,7 +36,7 @@ async function postWithPath<T>(
|
|
|
50
36
|
try {
|
|
51
37
|
data = JSON.parse(text) as T;
|
|
52
38
|
} catch {
|
|
53
|
-
//
|
|
39
|
+
// Non-JSON bodies still surface via the ResponseError below.
|
|
54
40
|
}
|
|
55
41
|
}
|
|
56
42
|
if (!response.ok) {
|
|
@@ -62,18 +48,16 @@ async function postWithPath<T>(
|
|
|
62
48
|
}
|
|
63
49
|
|
|
64
50
|
/**
|
|
65
|
-
* Fetch `git status --porcelain` for the
|
|
66
|
-
*
|
|
67
|
-
* from the JupyterLab server's root directory.
|
|
51
|
+
* Fetch `git status --porcelain` for the repo at `repoPath` (empty string
|
|
52
|
+
* resolves from the server's root directory).
|
|
68
53
|
*/
|
|
69
54
|
export async function status(repoPath: string): Promise<IGitStatusResult> {
|
|
70
55
|
return postWithPath<IGitStatusResult>('status', repoPath, {});
|
|
71
56
|
}
|
|
72
57
|
|
|
73
58
|
/**
|
|
74
|
-
* Fetch a file's contents at a
|
|
75
|
-
*
|
|
76
|
-
* of {@link status}'s response).
|
|
59
|
+
* Fetch a file's contents at a git reference; `filename` is relative to the
|
|
60
|
+
* git repository root.
|
|
77
61
|
*/
|
|
78
62
|
export async function content(
|
|
79
63
|
repoPath: string,
|
|
@@ -88,13 +72,7 @@ export async function content(
|
|
|
88
72
|
|
|
89
73
|
/**
|
|
90
74
|
* Expand the porcelain `files` array into one entry per logical change.
|
|
91
|
-
*
|
|
92
|
-
* both staged and modified again in the worktree); callers that just want
|
|
93
|
-
* a flat list of all changes — without any staged-vs-unstaged grouping —
|
|
94
|
-
* can use this helper.
|
|
95
|
-
*
|
|
96
|
-
* Provided as a manual concat rather than `Array.prototype.flatMap` so we
|
|
97
|
-
* don't pin our `tsconfig.lib` to ES2019.
|
|
75
|
+
* Manual concat rather than `flatMap` so `tsconfig.lib` need not be ES2019.
|
|
98
76
|
*/
|
|
99
77
|
export function expandStatusFiles(files: IGitStatusFile[]): IFileChange[] {
|
|
100
78
|
const result: IFileChange[] = [];
|
|
@@ -107,16 +85,12 @@ export function expandStatusFiles(files: IGitStatusFile[]): IFileChange[] {
|
|
|
107
85
|
}
|
|
108
86
|
|
|
109
87
|
/**
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
* per non-empty side, so a "modified-staged-and-then-modified-again" file
|
|
114
|
-
* shows up twice in the panel — once under "Staged Changes" and once under
|
|
115
|
-
* "Changes" — matching the layout the user sees in VS Code.
|
|
88
|
+
* Map one porcelain entry to up to two {@link IFileChange} rows — one per
|
|
89
|
+
* non-empty index/worktree side — so a staged-then-modified-again file
|
|
90
|
+
* appears under both groups, as in VS Code.
|
|
116
91
|
*/
|
|
117
92
|
function porcelainToFileChanges(file: IGitStatusFile): IFileChange[] {
|
|
118
93
|
const result: IFileChange[] = [];
|
|
119
|
-
// Untracked files are reported with `??` and only appear under "Changes".
|
|
120
94
|
if (file.x === '?' && file.y === '?') {
|
|
121
95
|
return [
|
|
122
96
|
{
|
package/src/git/askRequest.ts
CHANGED
|
@@ -9,10 +9,8 @@ import type { IXtralabDiffModel } from './diffWidget';
|
|
|
9
9
|
type DiffSide = 'deletions' | 'additions';
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
|
-
* Agent-facing name of a diff content source
|
|
13
|
-
*
|
|
14
|
-
* side name. English on purpose — this ends up in the agent prompt, not in
|
|
15
|
-
* the UI.
|
|
12
|
+
* Agent-facing name of a diff content source. English on purpose — this
|
|
13
|
+
* ends up in the agent prompt, not in the UI.
|
|
16
14
|
*/
|
|
17
15
|
function describeSource(source: unknown, fallback: string): string {
|
|
18
16
|
if (source === Git.Diff.SpecialRef.WORKING) {
|
|
@@ -34,9 +32,6 @@ function sideName(side: DiffSide): string {
|
|
|
34
32
|
return side === 'deletions' ? 'old side' : 'new side';
|
|
35
33
|
}
|
|
36
34
|
|
|
37
|
-
/**
|
|
38
|
-
* Extract lines `startLine`–`endLine` (1-indexed, inclusive) from `text`.
|
|
39
|
-
*/
|
|
40
35
|
function sliceLines(text: string, startLine: number, endLine: number): string {
|
|
41
36
|
return text
|
|
42
37
|
.split('\n')
|
|
@@ -46,14 +41,10 @@ function sliceLines(text: string, startLine: number, endLine: number): string {
|
|
|
46
41
|
|
|
47
42
|
/**
|
|
48
43
|
* Build the ask-agent request for a line range selected in a git diff.
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
* whose gutter shows new-side numbers — reads from the challenger text. A
|
|
54
|
-
* gutter drag that crosses the two split columns has endpoints in different
|
|
55
|
-
* line-number spaces, so it is described textually instead of as a numeric
|
|
56
|
-
* range.
|
|
44
|
+
* `deletions` ranges index the reference text; other ranges — including
|
|
45
|
+
* sideless unified context rows, whose gutter shows new-side numbers —
|
|
46
|
+
* index the challenger. A drag across the two split columns mixes
|
|
47
|
+
* line-number spaces, so it is described textually instead of numerically.
|
|
57
48
|
*/
|
|
58
49
|
export function buildDiffAskRequest(options: {
|
|
59
50
|
model: IXtralabDiffModel;
|
|
@@ -97,15 +88,10 @@ export function buildDiffAskRequest(options: {
|
|
|
97
88
|
...base,
|
|
98
89
|
startLine,
|
|
99
90
|
endLine,
|
|
100
|
-
// Only new-side lines of a working-tree diff index the file on disk;
|
|
101
|
-
// old-side and historical line numbers must not be used to highlight
|
|
102
|
-
// the working file.
|
|
103
91
|
linesInWorkingFile:
|
|
104
92
|
!isOld && model.challenger.source === Git.Diff.SpecialRef.WORKING,
|
|
105
93
|
text: sliceLines(isOld ? oldText : newText, startLine, endLine),
|
|
106
94
|
location: `the ${sideName(startSide)} (${ref}) of the current git diff`,
|
|
107
|
-
// New-side lines read as the file's current content, so only old-side
|
|
108
|
-
// ranges need a clarifying tag in the popup header.
|
|
109
95
|
...(isOld ? { note: trans.__('old version') } : {})
|
|
110
96
|
},
|
|
111
97
|
anchor
|