xtralab 0.14.1 → 0.15.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 +10 -0
- 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.d.ts +7 -0
- package/lib/customPanel/index.js +89 -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 +28 -19
- package/lib/fileBrowser/commands.js +51 -98
- package/lib/fileBrowser/contents.d.ts +14 -0
- package/lib/fileBrowser/contents.js +28 -0
- package/lib/fileBrowser/dragAndDrop.d.ts +79 -0
- package/lib/fileBrowser/dragAndDrop.js +110 -0
- package/lib/fileBrowser/fileBrowser.d.ts +21 -9
- package/lib/fileBrowser/fileBrowser.js +211 -405
- package/lib/fileBrowser/gitStatus.d.ts +4 -9
- package/lib/fileBrowser/gitStatus.js +7 -17
- 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 +41 -10
- package/lib/fileBrowser/widget.d.ts +170 -53
- package/lib/fileBrowser/widget.js +242 -18
- 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 +40 -5
- package/lib/git/commands.js +16 -10
- package/lib/git/diffModel.js +4 -0
- package/lib/git/diffSurface.d.ts +41 -55
- package/lib/git/diffSurface.js +42 -117
- package/lib/git/diffWidget.d.ts +81 -2
- package/lib/git/diffWidget.js +62 -12
- package/lib/git/imageDiff.d.ts +5 -6
- package/lib/git/imageDiff.js +18 -48
- package/lib/git/index.d.ts +0 -3
- package/lib/git/index.js +3 -8
- package/lib/git/notebookDiff.d.ts +110 -33
- package/lib/git/notebookDiff.js +52 -195
- 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 +2 -9
- package/lib/launcher/agents.d.ts +55 -51
- package/lib/launcher/agents.js +25 -54
- 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 +14 -37
- 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/schemaDefaults.d.ts +2 -9
- package/lib/launcher/schemaDefaults.js +37 -13
- 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 -13
- package/lib/sidebar/index.js +73 -46
- 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 -33
- package/lib/terminals/index.js +24 -102
- 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 +72 -38
- package/lib/terminals/widget.js +173 -73
- 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 +2 -2
- package/schema/launcher.json +2 -2
- package/schema/sidebar.json +47 -7
- 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 +119 -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 +70 -98
- package/src/fileBrowser/contents.ts +33 -0
- package/src/fileBrowser/dragAndDrop.ts +188 -0
- package/src/fileBrowser/fileBrowser.tsx +259 -440
- package/src/fileBrowser/gitStatus.ts +7 -17
- package/src/fileBrowser/gitignore.ts +4 -25
- package/src/fileBrowser/icons.ts +25 -80
- package/src/fileBrowser/index.ts +43 -10
- package/src/fileBrowser/widget.tsx +344 -64
- 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 +70 -10
- package/src/git/diffModel.ts +25 -0
- package/src/git/diffSurface.tsx +71 -159
- package/src/git/diffWidget.tsx +104 -14
- package/src/git/imageDiff.tsx +45 -51
- package/src/git/index.ts +3 -8
- package/src/git/notebookDiff.tsx +211 -238
- package/src/git/tokens.ts +73 -31
- package/src/highlight/index.ts +10 -41
- package/src/index.ts +2 -9
- package/src/launcher/agents.ts +74 -92
- 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 +15 -37
- package/src/launcher/index.ts +12 -55
- package/src/launcher/invocation.ts +7 -22
- package/src/launcher/registry.ts +9 -7
- package/src/launcher/schemaDefaults.ts +43 -13
- 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 +103 -52
- 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 +31 -102
- package/src/terminals/model.ts +130 -246
- package/src/terminals/tokens.ts +11 -22
- package/src/terminals/widget.tsx +229 -113
- 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 +25 -73
- package/style/chrome.css +108 -308
- package/style/commandBar.css +4 -20
- package/style/customPanel.css +6 -0
- package/style/git.css +22 -184
- package/style/highlight.css +1 -3
- package/style/index.js +1 -0
- 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 +18 -123
- package/style/topBar.css +2 -22
- package/style/walkthrough.css +0 -8
|
@@ -1,13 +1,8 @@
|
|
|
1
1
|
import type { GitStatusEntry } from '@pierre/trees';
|
|
2
2
|
/**
|
|
3
|
-
* Fetch the porcelain status for `repoPath`
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* without git, so any error here is a no-op rather than a thrown exception.
|
|
8
|
-
*
|
|
9
|
-
* Files that have both a staged and an unstaged change are collapsed into a
|
|
10
|
-
* single entry: the unstaged status wins because that mirrors what is
|
|
11
|
-
* actually different on disk and matches VS Code's tree decoration behavior.
|
|
3
|
+
* Fetch the porcelain status for `repoPath` as `GitStatusEntry` values.
|
|
4
|
+
* Any failure yields an empty array — the file browser must work without
|
|
5
|
+
* git. A file both staged and unstaged gets one entry, the unstaged status
|
|
6
|
+
* winning (mirrors what is on disk, matching VS Code).
|
|
12
7
|
*/
|
|
13
8
|
export declare function loadGitStatusEntries(repoPath: string): Promise<GitStatusEntry[]>;
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import { expandStatusFiles, status } from '../git/api';
|
|
2
2
|
/**
|
|
3
|
-
* Translate a `jupyterlab_git` porcelain status into
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* so the rare ones (unmerged, typechange, unknown) collapse onto `modified`
|
|
7
|
-
* — they all denote a pending change the user should see decorated.
|
|
3
|
+
* Translate a `jupyterlab_git` porcelain status into a `@pierre/trees`
|
|
4
|
+
* `GitStatus`. The tree only supports the six common statuses, so the rare
|
|
5
|
+
* ones (unmerged, typechange, unknown) collapse onto `modified`.
|
|
8
6
|
*/
|
|
9
7
|
function toTreeStatus(value) {
|
|
10
8
|
switch (value) {
|
|
@@ -22,15 +20,10 @@ function toTreeStatus(value) {
|
|
|
22
20
|
}
|
|
23
21
|
}
|
|
24
22
|
/**
|
|
25
|
-
* Fetch the porcelain status for `repoPath`
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* without git, so any error here is a no-op rather than a thrown exception.
|
|
30
|
-
*
|
|
31
|
-
* Files that have both a staged and an unstaged change are collapsed into a
|
|
32
|
-
* single entry: the unstaged status wins because that mirrors what is
|
|
33
|
-
* actually different on disk and matches VS Code's tree decoration behavior.
|
|
23
|
+
* Fetch the porcelain status for `repoPath` as `GitStatusEntry` values.
|
|
24
|
+
* Any failure yields an empty array — the file browser must work without
|
|
25
|
+
* git. A file both staged and unstaged gets one entry, the unstaged status
|
|
26
|
+
* winning (mirrors what is on disk, matching VS Code).
|
|
34
27
|
*/
|
|
35
28
|
export async function loadGitStatusEntries(repoPath) {
|
|
36
29
|
try {
|
|
@@ -39,9 +32,6 @@ export async function loadGitStatusEntries(repoPath) {
|
|
|
39
32
|
return [];
|
|
40
33
|
}
|
|
41
34
|
const changes = expandStatusFiles(result.files);
|
|
42
|
-
// Collapse staged + unstaged into one decoration per file. Prefer the
|
|
43
|
-
// unstaged group when both exist; otherwise keep whichever group is
|
|
44
|
-
// present.
|
|
45
35
|
const byPath = new Map();
|
|
46
36
|
for (const change of changes) {
|
|
47
37
|
if (change.group === 'unstaged' || !byPath.has(change.path)) {
|
|
@@ -8,22 +8,9 @@ import type { GitStatusEntry } from '@pierre/trees';
|
|
|
8
8
|
*/
|
|
9
9
|
export declare function loadGitignoreMatcher(contentsManager: Contents.IManager): Promise<Ignore | null>;
|
|
10
10
|
/**
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* down to every descendant via its internal `ignoredDirectoryPaths` set, so
|
|
16
|
-
* we only emit one entry per ignored subtree root: emitting descendants
|
|
17
|
-
* would also pollute the library's `directoriesWithChanges` set, causing
|
|
18
|
-
* parent directories of nested ignored items to render a "contains git
|
|
19
|
-
* status items" dot.
|
|
20
|
-
*
|
|
21
|
-
* Paths are sorted lexicographically so a directory always precedes its
|
|
22
|
-
* descendants, allowing a simple ancestor-suppression check via
|
|
23
|
-
* `path.startsWith(dir)`. The trailing slash on canonical directory paths
|
|
24
|
-
* (required by `@pierre/trees`, also recognized by `ignore` as the
|
|
25
|
-
* "directory" indicator) keeps the prefix check from accidentally matching
|
|
26
|
-
* sibling paths that happen to share a name prefix (e.g. `node_modules_old`
|
|
27
|
-
* vs `node_modules/`).
|
|
11
|
+
* One `GitStatusEntry` per ignored subtree root: descendant entries would
|
|
12
|
+
* pollute the tree's `directoriesWithChanges` set (bogus dots on parents),
|
|
13
|
+
* and `ignored` already propagates downward. The trailing slash on directory
|
|
14
|
+
* paths keeps the sorted `startsWith` ancestor check off name-prefix siblings.
|
|
28
15
|
*/
|
|
29
16
|
export declare function buildIgnoredEntries(matcher: Ignore, canonicalPaths: Iterable<string>): GitStatusEntry[];
|
|
@@ -1,9 +1,4 @@
|
|
|
1
1
|
import ignore from 'ignore';
|
|
2
|
-
/**
|
|
3
|
-
* The path of the workspace `.gitignore` file. Loaded relative to the
|
|
4
|
-
* Jupyter contents root, which matches the directory the gitignore patterns
|
|
5
|
-
* are evaluated against — patterns and tested paths share the same base.
|
|
6
|
-
*/
|
|
7
2
|
const GITIGNORE_PATH = '.gitignore';
|
|
8
3
|
/**
|
|
9
4
|
* Load the workspace `.gitignore` and return an `ignore` matcher built from
|
|
@@ -20,9 +15,6 @@ export async function loadGitignoreMatcher(contentsManager) {
|
|
|
20
15
|
});
|
|
21
16
|
}
|
|
22
17
|
catch (_a) {
|
|
23
|
-
// The most common failure here is `.gitignore` simply not existing.
|
|
24
|
-
// Other transient errors (permission denied, server unreachable) are
|
|
25
|
-
// also treated as "no matcher" so the file browser still works.
|
|
26
18
|
return null;
|
|
27
19
|
}
|
|
28
20
|
if (model.type !== 'file' || typeof model.content !== 'string') {
|
|
@@ -34,23 +26,10 @@ export async function loadGitignoreMatcher(contentsManager) {
|
|
|
34
26
|
return ignore().add(model.content);
|
|
35
27
|
}
|
|
36
28
|
/**
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
* down to every descendant via its internal `ignoredDirectoryPaths` set, so
|
|
42
|
-
* we only emit one entry per ignored subtree root: emitting descendants
|
|
43
|
-
* would also pollute the library's `directoriesWithChanges` set, causing
|
|
44
|
-
* parent directories of nested ignored items to render a "contains git
|
|
45
|
-
* status items" dot.
|
|
46
|
-
*
|
|
47
|
-
* Paths are sorted lexicographically so a directory always precedes its
|
|
48
|
-
* descendants, allowing a simple ancestor-suppression check via
|
|
49
|
-
* `path.startsWith(dir)`. The trailing slash on canonical directory paths
|
|
50
|
-
* (required by `@pierre/trees`, also recognized by `ignore` as the
|
|
51
|
-
* "directory" indicator) keeps the prefix check from accidentally matching
|
|
52
|
-
* sibling paths that happen to share a name prefix (e.g. `node_modules_old`
|
|
53
|
-
* vs `node_modules/`).
|
|
29
|
+
* One `GitStatusEntry` per ignored subtree root: descendant entries would
|
|
30
|
+
* pollute the tree's `directoriesWithChanges` set (bogus dots on parents),
|
|
31
|
+
* and `ignored` already propagates downward. The trailing slash on directory
|
|
32
|
+
* paths keeps the sorted `startsWith` ancestor check off name-prefix siblings.
|
|
54
33
|
*/
|
|
55
34
|
export function buildIgnoredEntries(matcher, canonicalPaths) {
|
|
56
35
|
const sorted = Array.from(canonicalPaths).sort();
|
|
@@ -1,26 +1,16 @@
|
|
|
1
1
|
import { LabIcon } from '@jupyterlab/ui-components';
|
|
2
2
|
import type { FileTreeIconConfig } from '@pierre/trees';
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* sidebar.
|
|
9
|
-
*
|
|
10
|
-
* Source: `file-tree` from SVG Repo (https://www.svgrepo.com/svg/371275/file-tree).
|
|
11
|
-
* The original `fill="#444"` is replaced with `fill="currentColor"` and the
|
|
12
|
-
* root element is given the `jp-icon3` class so the icon picks up JupyterLab's
|
|
13
|
-
* theme color and the sidebar's inverse-color painting automatically.
|
|
4
|
+
* Sidebar tab icon, distinct from the core `folderIcon` so the xtralab
|
|
5
|
+
* browser is distinguishable from the built-in one. `file-tree` from SVG Repo
|
|
6
|
+
* (https://www.svgrepo.com/svg/371275/file-tree), refit to follow the theme
|
|
7
|
+
* (`currentColor`, `jp-icon3`) and padded to the size of the stock glyphs.
|
|
14
8
|
*/
|
|
15
9
|
export declare const xtralabFileBrowserIcon: LabIcon;
|
|
16
10
|
/**
|
|
17
|
-
* Icon
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* `set` must be set explicitly: when a config object includes any custom
|
|
22
|
-
* overrides without `set`, `@pierre/trees` defaults `set` to `'none'`, which
|
|
23
|
-
* disables the built-in icons entirely.
|
|
11
|
+
* Icon config: the built-in `complete` set plus the Jupyter notebook symbol
|
|
12
|
+
* for `.ipynb`. `set` must be explicit — with any custom overrides present,
|
|
13
|
+
* `@pierre/trees` defaults it to `'none'`, disabling the built-in icons.
|
|
24
14
|
*/
|
|
25
15
|
export declare const FILE_BROWSER_ICONS: FileTreeIconConfig;
|
|
26
16
|
/**
|
package/lib/fileBrowser/icons.js
CHANGED
|
@@ -2,36 +2,22 @@ var _a;
|
|
|
2
2
|
import { LabIcon, fileIcon } from '@jupyterlab/ui-components';
|
|
3
3
|
import { createFileTreeIconResolver, getBuiltInSpriteSheet } from '@pierre/trees';
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* sidebar.
|
|
10
|
-
*
|
|
11
|
-
* Source: `file-tree` from SVG Repo (https://www.svgrepo.com/svg/371275/file-tree).
|
|
12
|
-
* The original `fill="#444"` is replaced with `fill="currentColor"` and the
|
|
13
|
-
* root element is given the `jp-icon3` class so the icon picks up JupyterLab's
|
|
14
|
-
* theme color and the sidebar's inverse-color painting automatically.
|
|
5
|
+
* Sidebar tab icon, distinct from the core `folderIcon` so the xtralab
|
|
6
|
+
* browser is distinguishable from the built-in one. `file-tree` from SVG Repo
|
|
7
|
+
* (https://www.svgrepo.com/svg/371275/file-tree), refit to follow the theme
|
|
8
|
+
* (`currentColor`, `jp-icon3`) and padded to the size of the stock glyphs.
|
|
15
9
|
*/
|
|
16
10
|
export const xtralabFileBrowserIcon = new LabIcon({
|
|
17
11
|
name: 'xtralab:file-browser',
|
|
18
|
-
svgstr: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="
|
|
12
|
+
svgstr: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="-2 -2 20 20" class="jp-icon3" fill="currentColor">
|
|
19
13
|
<path d="M16 10v-4h-11v1h-2v-3h9v-4h-12v4h2v10h3v2h11v-4h-11v1h-2v-5h2v2z"/>
|
|
20
14
|
</svg>`
|
|
21
15
|
});
|
|
22
16
|
/**
|
|
23
|
-
* Sprite sheet injected into the
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* `@pierre/trees` does not ship a Jupyter token, so `.ipynb` files would
|
|
28
|
-
* otherwise fall through to the generic file icon. The symbol id below is
|
|
29
|
-
* referenced from `byFileExtension` in {@link FILE_BROWSER_ICONS}.
|
|
30
|
-
*
|
|
31
|
-
* The orange `#EF6C00` fill is set as a presentation attribute on the inner
|
|
32
|
-
* `<g>` so it survives the `fill: currentColor` rule the tree applies on the
|
|
33
|
-
* icon container — the inherited color does not override a presentation
|
|
34
|
-
* attribute set directly on a child.
|
|
17
|
+
* Sprite sheet injected into the tree's shadow DOM: the JupyterLab notebook
|
|
18
|
+
* glyph, since `@pierre/trees` ships no Jupyter token. The `#EF6C00` fill is
|
|
19
|
+
* a presentation attribute on the inner `<g>` so it survives the tree's
|
|
20
|
+
* `fill: currentColor` rule on the icon container.
|
|
35
21
|
*/
|
|
36
22
|
const JUPYTER_NOTEBOOK_SPRITE_SHEET = `<svg data-icon-sprite aria-hidden="true" width="0" height="0">
|
|
37
23
|
<symbol id="jupyter-notebook" viewBox="0 0 22 22">
|
|
@@ -42,13 +28,9 @@ const JUPYTER_NOTEBOOK_SPRITE_SHEET = `<svg data-icon-sprite aria-hidden="true"
|
|
|
42
28
|
</symbol>
|
|
43
29
|
</svg>`;
|
|
44
30
|
/**
|
|
45
|
-
* Icon
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
* `set` must be set explicitly: when a config object includes any custom
|
|
50
|
-
* overrides without `set`, `@pierre/trees` defaults `set` to `'none'`, which
|
|
51
|
-
* disables the built-in icons entirely.
|
|
31
|
+
* Icon config: the built-in `complete` set plus the Jupyter notebook symbol
|
|
32
|
+
* for `.ipynb`. `set` must be explicit — with any custom overrides present,
|
|
33
|
+
* `@pierre/trees` defaults it to `'none'`, disabling the built-in icons.
|
|
52
34
|
*/
|
|
53
35
|
export const FILE_BROWSER_ICONS = {
|
|
54
36
|
set: 'complete',
|
|
@@ -58,39 +40,19 @@ export const FILE_BROWSER_ICONS = {
|
|
|
58
40
|
ipynb: 'jupyter-notebook'
|
|
59
41
|
}
|
|
60
42
|
};
|
|
61
|
-
/**
|
|
62
|
-
* Concatenated sprite-sheet text. Combines the built-in sheet for the active
|
|
63
|
-
* icon set with our custom Jupyter notebook sheet so {@link extractSymbol}
|
|
64
|
-
* can find the body of any symbol the tree itself can render.
|
|
65
|
-
*/
|
|
66
43
|
const COMBINED_SPRITE_SHEETS = [
|
|
67
44
|
getBuiltInSpriteSheet((_a = FILE_BROWSER_ICONS.set) !== null && _a !== void 0 ? _a : 'complete'),
|
|
68
45
|
JUPYTER_NOTEBOOK_SPRITE_SHEET
|
|
69
46
|
].join('\n');
|
|
70
|
-
/**
|
|
71
|
-
* Resolver instance reused across calls to {@link getTreeIcon}. The resolver
|
|
72
|
-
* is pure relative to the icon config, so building it once at module load
|
|
73
|
-
* avoids re-walking the icon rules on every diff that opens.
|
|
74
|
-
*/
|
|
75
47
|
const treeIconResolver = createFileTreeIconResolver(FILE_BROWSER_ICONS);
|
|
76
48
|
/**
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
* caching by symbol id prevents repeated LabIcon registration warnings and
|
|
80
|
-
* keeps the JupyterLab icon registry small.
|
|
49
|
+
* LabIcons keyed by resolved symbol id — re-registering a LabIcon under the
|
|
50
|
+
* same name logs warnings.
|
|
81
51
|
*/
|
|
82
52
|
const TREE_ICON_CACHE = new Map();
|
|
83
|
-
/**
|
|
84
|
-
* Extract the inner SVG markup and viewBox of the `<symbol>` with the given
|
|
85
|
-
* id from {@link COMBINED_SPRITE_SHEETS}. Returns `null` if no matching
|
|
86
|
-
* symbol exists, in which case the caller falls back to JupyterLab's default
|
|
87
|
-
* file icon.
|
|
88
|
-
*/
|
|
89
53
|
function extractSymbol(symbolId) {
|
|
90
54
|
var _a;
|
|
91
|
-
//
|
|
92
|
-
// attributes in any order). The `[\s\S]*?` body is non-greedy so we stop
|
|
93
|
-
// at the first matching `</symbol>` even when multiple symbols sit
|
|
55
|
+
// Non-greedy body: stop at the first `</symbol>` when symbols sit
|
|
94
56
|
// back-to-back in the sheet.
|
|
95
57
|
const escaped = symbolId.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
96
58
|
const symbolRegex = new RegExp(`<symbol\\b[^>]*\\bid="${escaped}"[^>]*>([\\s\\S]*?)</symbol>`, 'i');
|
|
@@ -105,14 +67,10 @@ function extractSymbol(symbolId) {
|
|
|
105
67
|
};
|
|
106
68
|
}
|
|
107
69
|
/**
|
|
108
|
-
* Fallback colors
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
* variables scoped to its shadow host, so they resolve to nothing for the
|
|
113
|
-
* standalone {@link LabIcon}s {@link getTreeIcon} builds for main-area tabs.
|
|
114
|
-
* Mirroring them here lets {@link getBuiltInFileIconColor} bottom out in a
|
|
115
|
-
* real color. Each is a `light-dark(…)` pair for dark themes.
|
|
70
|
+
* Fallback colors keyed by the tree's icon token. The tree exposes its colors
|
|
71
|
+
* only as `--trees-file-icon-color-*` vars scoped to its shadow host, so the
|
|
72
|
+
* standalone LabIcons built for main-area tabs need these literals;
|
|
73
|
+
* `light-dark(…)` covers dark themes.
|
|
116
74
|
*/
|
|
117
75
|
const BUILT_IN_FILE_ICON_COLOR_FALLBACKS = {
|
|
118
76
|
astro: 'light-dark(#a631be, #d568ea)',
|
|
@@ -167,11 +125,8 @@ const BUILT_IN_FILE_ICON_COLOR_FALLBACKS = {
|
|
|
167
125
|
zip: 'light-dark(#d47628, #ffa359)'
|
|
168
126
|
};
|
|
169
127
|
/**
|
|
170
|
-
*
|
|
171
|
-
*
|
|
172
|
-
* `--trees-file-icon-color-*` properties when in scope, else the literal from
|
|
173
|
-
* {@link BUILT_IN_FILE_ICON_COLOR_FALLBACKS}. Returns `undefined` for unknown
|
|
174
|
-
* tokens.
|
|
128
|
+
* The tree's color for `token` as a self-contained CSS value: its CSS vars
|
|
129
|
+
* when in scope, else the mirrored literal. `undefined` for unknown tokens.
|
|
175
130
|
*/
|
|
176
131
|
function getBuiltInFileIconColor(token) {
|
|
177
132
|
const fallback = BUILT_IN_FILE_ICON_COLOR_FALLBACKS[token];
|
|
@@ -180,9 +135,6 @@ function getBuiltInFileIconColor(token) {
|
|
|
180
135
|
}
|
|
181
136
|
return `var(--trees-file-icon-color-${token}, var(--trees-file-icon-color, ${fallback}))`;
|
|
182
137
|
}
|
|
183
|
-
/**
|
|
184
|
-
* Resolve a tree glyph into a standalone `LabIcon`.
|
|
185
|
-
*/
|
|
186
138
|
function resolveTreeIcon(filePath) {
|
|
187
139
|
var _a;
|
|
188
140
|
const resolved = treeIconResolver.resolveIcon('file-tree-icon-file', filePath);
|
|
@@ -196,22 +148,15 @@ function resolveTreeIcon(filePath) {
|
|
|
196
148
|
if (symbol === null) {
|
|
197
149
|
return { icon: null, specific };
|
|
198
150
|
}
|
|
199
|
-
// Built-in
|
|
200
|
-
//
|
|
201
|
-
// element. Reproduce that here by setting the same color value as an
|
|
202
|
-
// inline `style="color: …"` on the outer `<svg>`. `getBuiltInFileIconColor`
|
|
203
|
-
// returns a `var(--trees-…)` chain that bottoms out in `light-dark(…)`,
|
|
204
|
-
// which respects the page's `color-scheme` declaration so dark themes pick
|
|
205
|
-
// up the brighter variants automatically.
|
|
151
|
+
// Built-in glyphs paint with `fill="currentColor"`; an inline `color`
|
|
152
|
+
// style reproduces the tree's colored tier outside its shadow DOM.
|
|
206
153
|
const colored = FILE_BROWSER_ICONS.colored === true;
|
|
207
154
|
const color = colored && resolved.token !== undefined
|
|
208
155
|
? getBuiltInFileIconColor(resolved.token)
|
|
209
156
|
: undefined;
|
|
210
157
|
const styleAttr = color !== undefined ? ` style="color: ${color};"` : '';
|
|
211
|
-
// Prefer
|
|
212
|
-
//
|
|
213
|
-
// the Jupyter notebook glyph render at the right scale rather than being
|
|
214
|
-
// cropped to a 16x16 box.
|
|
158
|
+
// Prefer the resolver's viewBox, then the symbol's own, so 22x22 sprites
|
|
159
|
+
// like the notebook glyph aren't cropped to a 16x16 box.
|
|
215
160
|
const viewBox = (_a = resolved.viewBox) !== null && _a !== void 0 ? _a : symbol.viewBox;
|
|
216
161
|
const svgstr = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="${viewBox}"${styleAttr}>${symbol.inner}</svg>`;
|
|
217
162
|
const icon = new LabIcon({
|
package/lib/fileBrowser/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { ILayoutRestorer } from '@jupyterlab/application';
|
|
2
|
-
import { ICommandPalette } from '@jupyterlab/apputils';
|
|
2
|
+
import { ICommandPalette, IMovableSectionRegistry } from '@jupyterlab/apputils';
|
|
3
3
|
import { IDocumentManager } from '@jupyterlab/docmanager';
|
|
4
4
|
import { ISettingRegistry } from '@jupyterlab/settingregistry';
|
|
5
|
-
import { ITranslator } from '@jupyterlab/translation';
|
|
5
|
+
import { ITranslator, nullTranslator } from '@jupyterlab/translation';
|
|
6
6
|
import { populateToolbar, registerCommands } from './commands';
|
|
7
|
-
import { XtralabFileBrowser } from './widget';
|
|
7
|
+
import { FILE_BROWSER_ID, XtralabFileBrowser } from './widget';
|
|
8
8
|
const PLUGIN_ID = 'xtralab:plugin';
|
|
9
9
|
/**
|
|
10
10
|
* The file browser plugin. Adds a `@pierre/trees`-powered file browser to the
|
|
@@ -15,25 +15,56 @@ const plugin = {
|
|
|
15
15
|
description: 'A path-first file browser for JupyterLab built on @pierre/trees.',
|
|
16
16
|
autoStart: true,
|
|
17
17
|
requires: [IDocumentManager],
|
|
18
|
-
optional: [
|
|
19
|
-
|
|
18
|
+
optional: [
|
|
19
|
+
ILayoutRestorer,
|
|
20
|
+
ISettingRegistry,
|
|
21
|
+
ICommandPalette,
|
|
22
|
+
ITranslator,
|
|
23
|
+
IMovableSectionRegistry
|
|
24
|
+
],
|
|
25
|
+
activate: (app, docManager, restorer, settingRegistry, palette, translator, movableSections) => {
|
|
20
26
|
const browser = new XtralabFileBrowser({
|
|
21
27
|
contentsManager: app.serviceManager.contents,
|
|
22
28
|
docManager,
|
|
23
29
|
onOpenFile: (serverPath) => {
|
|
24
30
|
void app.commands.execute('docmanager:open', { path: serverPath });
|
|
25
|
-
}
|
|
31
|
+
},
|
|
32
|
+
translator: translator !== null && translator !== void 0 ? translator : undefined
|
|
26
33
|
});
|
|
27
|
-
//
|
|
28
|
-
//
|
|
29
|
-
// so this browser stays movable via the "Move Widget" context menu; the
|
|
30
|
-
// `rank` here is the in-code fallback for when that setting is absent.
|
|
34
|
+
// Rank-only fallback for when the shipped `layout` setting is absent;
|
|
35
|
+
// no area pin, so the browser stays movable via "Move Widget".
|
|
31
36
|
app.shell.add(browser, 'left', { rank: 2 });
|
|
32
37
|
if (restorer) {
|
|
33
38
|
restorer.add(browser, browser.id);
|
|
34
39
|
}
|
|
35
40
|
registerCommands({ app, browser, docManager, palette, translator });
|
|
36
41
|
populateToolbar({ app, browser });
|
|
42
|
+
if (movableSections) {
|
|
43
|
+
const label = (translator !== null && translator !== void 0 ? translator : nullTranslator)
|
|
44
|
+
.load('jupyterlab')
|
|
45
|
+
.__('Files');
|
|
46
|
+
movableSections.registerSource(FILE_BROWSER_ID, label, browser);
|
|
47
|
+
movableSections.registerTarget(FILE_BROWSER_ID, label, browser);
|
|
48
|
+
// Only a user move should switch the sidebar, not the startup restoration.
|
|
49
|
+
let settled = false;
|
|
50
|
+
void app.restored.then(() => {
|
|
51
|
+
settled = true;
|
|
52
|
+
});
|
|
53
|
+
browser.contentChanged.connect(() => {
|
|
54
|
+
if (browser.isEmpty) {
|
|
55
|
+
if (browser.parent) {
|
|
56
|
+
browser.parent = null;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
else if (!browser.parent) {
|
|
60
|
+
app.shell.add(browser, 'left', { rank: 2 });
|
|
61
|
+
if (settled) {
|
|
62
|
+
app.shell.activateById(browser.id);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
browser.announceSections();
|
|
67
|
+
}
|
|
37
68
|
if (settingRegistry) {
|
|
38
69
|
settingRegistry.load(PLUGIN_ID).catch(reason => {
|
|
39
70
|
console.error('Failed to load settings for xtralab.', reason);
|