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.
Files changed (236) hide show
  1. package/README.md +10 -0
  2. package/lib/about/icons.d.ts +0 -5
  3. package/lib/about/icons.js +0 -5
  4. package/lib/about/index.d.ts +4 -8
  5. package/lib/about/index.js +6 -17
  6. package/lib/agentSessions.d.ts +9 -29
  7. package/lib/agentSessions.js +2 -7
  8. package/lib/askAgent/editorSelection.d.ts +20 -26
  9. package/lib/askAgent/editorSelection.js +11 -26
  10. package/lib/askAgent/icons.d.ts +2 -3
  11. package/lib/askAgent/icons.js +2 -3
  12. package/lib/askAgent/index.d.ts +4 -26
  13. package/lib/askAgent/index.js +54 -158
  14. package/lib/askAgent/popup.d.ts +12 -16
  15. package/lib/askAgent/popup.js +18 -37
  16. package/lib/askAgent/prompt.d.ts +3 -5
  17. package/lib/askAgent/prompt.js +6 -19
  18. package/lib/askAgent/queue.d.ts +11 -21
  19. package/lib/askAgent/queue.js +9 -19
  20. package/lib/askAgent/queuePanel.d.ts +13 -18
  21. package/lib/askAgent/queuePanel.js +15 -37
  22. package/lib/askAgent/targetPicker.d.ts +2 -9
  23. package/lib/askAgent/targetPicker.js +6 -11
  24. package/lib/askAgent/tokens.d.ts +32 -46
  25. package/lib/askAgent/tokens.js +4 -6
  26. package/lib/commandBar/index.d.ts +4 -13
  27. package/lib/commandBar/index.js +21 -39
  28. package/lib/customPanel/index.d.ts +7 -0
  29. package/lib/customPanel/index.js +89 -0
  30. package/lib/editorBreadcrumbs/index.d.ts +3 -6
  31. package/lib/editorBreadcrumbs/index.js +10 -6
  32. package/lib/editorBreadcrumbs/widget.d.ts +17 -4
  33. package/lib/editorBreadcrumbs/widget.js +11 -17
  34. package/lib/editorIndent/index.d.ts +4 -12
  35. package/lib/editorIndent/index.js +8 -23
  36. package/lib/fileBrowser/commands.d.ts +28 -19
  37. package/lib/fileBrowser/commands.js +51 -98
  38. package/lib/fileBrowser/contents.d.ts +14 -0
  39. package/lib/fileBrowser/contents.js +28 -0
  40. package/lib/fileBrowser/dragAndDrop.d.ts +79 -0
  41. package/lib/fileBrowser/dragAndDrop.js +110 -0
  42. package/lib/fileBrowser/fileBrowser.d.ts +21 -9
  43. package/lib/fileBrowser/fileBrowser.js +211 -405
  44. package/lib/fileBrowser/gitStatus.d.ts +4 -9
  45. package/lib/fileBrowser/gitStatus.js +7 -17
  46. package/lib/fileBrowser/gitignore.d.ts +4 -17
  47. package/lib/fileBrowser/gitignore.js +4 -25
  48. package/lib/fileBrowser/icons.d.ts +7 -17
  49. package/lib/fileBrowser/icons.js +25 -80
  50. package/lib/fileBrowser/index.js +41 -10
  51. package/lib/fileBrowser/widget.d.ts +170 -53
  52. package/lib/fileBrowser/widget.js +242 -18
  53. package/lib/fileTypeIcons/index.js +0 -10
  54. package/lib/git/api.d.ts +5 -13
  55. package/lib/git/api.js +10 -36
  56. package/lib/git/askRequest.d.ts +4 -8
  57. package/lib/git/askRequest.js +6 -20
  58. package/lib/git/commands.d.ts +40 -5
  59. package/lib/git/commands.js +16 -10
  60. package/lib/git/diffModel.js +4 -0
  61. package/lib/git/diffSurface.d.ts +41 -55
  62. package/lib/git/diffSurface.js +42 -117
  63. package/lib/git/diffWidget.d.ts +81 -2
  64. package/lib/git/diffWidget.js +62 -12
  65. package/lib/git/imageDiff.d.ts +5 -6
  66. package/lib/git/imageDiff.js +18 -48
  67. package/lib/git/index.d.ts +0 -3
  68. package/lib/git/index.js +3 -8
  69. package/lib/git/notebookDiff.d.ts +110 -33
  70. package/lib/git/notebookDiff.js +52 -195
  71. package/lib/git/tokens.d.ts +73 -31
  72. package/lib/git/tokens.js +2 -3
  73. package/lib/highlight/index.d.ts +4 -10
  74. package/lib/highlight/index.js +10 -41
  75. package/lib/index.d.ts +0 -9
  76. package/lib/index.js +2 -9
  77. package/lib/launcher/agents.d.ts +55 -51
  78. package/lib/launcher/agents.js +25 -54
  79. package/lib/launcher/availability.d.ts +3 -9
  80. package/lib/launcher/availability.js +3 -9
  81. package/lib/launcher/commands.d.ts +7 -32
  82. package/lib/launcher/commands.js +14 -45
  83. package/lib/launcher/dashboard.d.ts +19 -24
  84. package/lib/launcher/dashboard.js +21 -67
  85. package/lib/launcher/editorRegistry.d.ts +10 -22
  86. package/lib/launcher/editorRegistry.js +14 -18
  87. package/lib/launcher/editors.d.ts +39 -45
  88. package/lib/launcher/editors.js +8 -34
  89. package/lib/launcher/icons.d.ts +0 -12
  90. package/lib/launcher/icons.js +14 -37
  91. package/lib/launcher/index.js +12 -55
  92. package/lib/launcher/invocation.d.ts +4 -10
  93. package/lib/launcher/invocation.js +7 -22
  94. package/lib/launcher/registry.d.ts +9 -7
  95. package/lib/launcher/registry.js +9 -7
  96. package/lib/launcher/schemaDefaults.d.ts +2 -9
  97. package/lib/launcher/schemaDefaults.js +37 -13
  98. package/lib/launcher/tokens.d.ts +10 -22
  99. package/lib/launcher/tokens.js +5 -8
  100. package/lib/menuBar/index.d.ts +3 -10
  101. package/lib/menuBar/index.js +11 -28
  102. package/lib/menus/index.d.ts +3 -9
  103. package/lib/menus/index.js +14 -30
  104. package/lib/omnibox/files.d.ts +2 -4
  105. package/lib/omnibox/files.js +5 -11
  106. package/lib/omnibox/index.d.ts +4 -14
  107. package/lib/omnibox/index.js +9 -27
  108. package/lib/omnibox/model.d.ts +38 -10
  109. package/lib/omnibox/model.js +15 -33
  110. package/lib/omnibox/recents.d.ts +15 -17
  111. package/lib/omnibox/recents.js +12 -17
  112. package/lib/omnibox/tokens.d.ts +5 -10
  113. package/lib/omnibox/tokens.js +2 -6
  114. package/lib/omnibox/widget.d.ts +11 -7
  115. package/lib/omnibox/widget.js +8 -16
  116. package/lib/searchReplace/index.d.ts +4 -20
  117. package/lib/searchReplace/index.js +7 -27
  118. package/lib/showOutput/index.d.ts +3 -12
  119. package/lib/showOutput/index.js +6 -22
  120. package/lib/sidebar/index.d.ts +4 -13
  121. package/lib/sidebar/index.js +73 -46
  122. package/lib/terminalNotifications/index.d.ts +4 -10
  123. package/lib/terminalNotifications/index.js +6 -20
  124. package/lib/terminals/agentTerminals.d.ts +12 -5
  125. package/lib/terminals/agentTerminals.js +25 -44
  126. package/lib/terminals/detection.d.ts +4 -8
  127. package/lib/terminals/detection.js +4 -8
  128. package/lib/terminals/index.d.ts +0 -33
  129. package/lib/terminals/index.js +24 -102
  130. package/lib/terminals/model.d.ts +64 -139
  131. package/lib/terminals/model.js +80 -220
  132. package/lib/terminals/tokens.d.ts +11 -22
  133. package/lib/terminals/tokens.js +2 -2
  134. package/lib/terminals/widget.d.ts +72 -38
  135. package/lib/terminals/widget.js +173 -73
  136. package/lib/topBar/icons.d.ts +3 -8
  137. package/lib/topBar/icons.js +3 -8
  138. package/lib/topBar/index.d.ts +4 -11
  139. package/lib/topBar/index.js +10 -38
  140. package/lib/walkthrough/index.d.ts +4 -9
  141. package/lib/walkthrough/index.js +6 -20
  142. package/lib/walkthrough/panel.d.ts +40 -9
  143. package/lib/walkthrough/panel.js +4 -10
  144. package/package.json +2 -2
  145. package/schema/launcher.json +2 -2
  146. package/schema/sidebar.json +47 -7
  147. package/src/about/icons.ts +0 -5
  148. package/src/about/index.tsx +6 -17
  149. package/src/agentSessions.ts +9 -29
  150. package/src/askAgent/editorSelection.ts +22 -29
  151. package/src/askAgent/icons.ts +2 -3
  152. package/src/askAgent/index.ts +54 -158
  153. package/src/askAgent/popup.tsx +23 -45
  154. package/src/askAgent/prompt.ts +6 -19
  155. package/src/askAgent/queue.ts +13 -24
  156. package/src/askAgent/queuePanel.tsx +21 -46
  157. package/src/askAgent/targetPicker.tsx +5 -15
  158. package/src/askAgent/tokens.ts +32 -46
  159. package/src/commandBar/index.ts +24 -39
  160. package/src/customPanel/index.ts +119 -0
  161. package/src/editorBreadcrumbs/index.ts +10 -6
  162. package/src/editorBreadcrumbs/widget.ts +23 -17
  163. package/src/editorIndent/index.ts +17 -23
  164. package/src/fileBrowser/commands.ts +70 -98
  165. package/src/fileBrowser/contents.ts +33 -0
  166. package/src/fileBrowser/dragAndDrop.ts +188 -0
  167. package/src/fileBrowser/fileBrowser.tsx +259 -440
  168. package/src/fileBrowser/gitStatus.ts +7 -17
  169. package/src/fileBrowser/gitignore.ts +4 -25
  170. package/src/fileBrowser/icons.ts +25 -80
  171. package/src/fileBrowser/index.ts +43 -10
  172. package/src/fileBrowser/widget.tsx +344 -64
  173. package/src/fileTypeIcons/index.ts +0 -10
  174. package/src/git/api.ts +10 -36
  175. package/src/git/askRequest.ts +6 -20
  176. package/src/git/commands.ts +70 -10
  177. package/src/git/diffModel.ts +25 -0
  178. package/src/git/diffSurface.tsx +71 -159
  179. package/src/git/diffWidget.tsx +104 -14
  180. package/src/git/imageDiff.tsx +45 -51
  181. package/src/git/index.ts +3 -8
  182. package/src/git/notebookDiff.tsx +211 -238
  183. package/src/git/tokens.ts +73 -31
  184. package/src/highlight/index.ts +10 -41
  185. package/src/index.ts +2 -9
  186. package/src/launcher/agents.ts +74 -92
  187. package/src/launcher/availability.ts +3 -9
  188. package/src/launcher/commands.ts +14 -51
  189. package/src/launcher/dashboard.tsx +49 -88
  190. package/src/launcher/editorRegistry.ts +21 -29
  191. package/src/launcher/editors.ts +39 -58
  192. package/src/launcher/icons.ts +15 -37
  193. package/src/launcher/index.ts +12 -55
  194. package/src/launcher/invocation.ts +7 -22
  195. package/src/launcher/registry.ts +9 -7
  196. package/src/launcher/schemaDefaults.ts +43 -13
  197. package/src/launcher/tokens.ts +10 -22
  198. package/src/menuBar/index.ts +11 -28
  199. package/src/menus/index.ts +14 -30
  200. package/src/omnibox/files.ts +10 -14
  201. package/src/omnibox/index.ts +9 -27
  202. package/src/omnibox/model.ts +50 -38
  203. package/src/omnibox/recents.ts +17 -22
  204. package/src/omnibox/tokens.ts +5 -10
  205. package/src/omnibox/widget.tsx +14 -19
  206. package/src/searchReplace/index.ts +7 -27
  207. package/src/showOutput/index.ts +6 -22
  208. package/src/sidebar/index.ts +103 -52
  209. package/src/terminalNotifications/index.ts +42 -25
  210. package/src/terminals/agentTerminals.ts +25 -49
  211. package/src/terminals/detection.ts +4 -8
  212. package/src/terminals/index.ts +31 -102
  213. package/src/terminals/model.ts +130 -246
  214. package/src/terminals/tokens.ts +11 -22
  215. package/src/terminals/widget.tsx +229 -113
  216. package/src/topBar/icons.ts +3 -8
  217. package/src/topBar/index.ts +21 -44
  218. package/src/walkthrough/index.ts +6 -20
  219. package/src/walkthrough/panel.ts +40 -10
  220. package/style/about.css +2 -7
  221. package/style/askAgent.css +8 -40
  222. package/style/base.css +25 -73
  223. package/style/chrome.css +108 -308
  224. package/style/commandBar.css +4 -20
  225. package/style/customPanel.css +6 -0
  226. package/style/git.css +22 -184
  227. package/style/highlight.css +1 -3
  228. package/style/index.js +1 -0
  229. package/style/launcher.css +6 -70
  230. package/style/omnibox.css +2 -14
  231. package/style/showOutput.css +0 -6
  232. package/style/sidebar.css +29 -9
  233. package/style/tabs.css +5 -13
  234. package/style/terminals.css +18 -123
  235. package/style/topBar.css +2 -22
  236. package/style/walkthrough.css +0 -8
@@ -31,6 +31,9 @@ export class XtralabDiffWidget extends ReactWidget {
31
31
  this.addClass('jp-git-diff-root');
32
32
  this.addClass(DIFF_WIDGET_CSS_CLASS);
33
33
  }
34
+ /**
35
+ * The git diff model being rendered.
36
+ */
34
37
  get model() {
35
38
  return this._model;
36
39
  }
@@ -74,9 +77,15 @@ export class XtralabDiffWidget extends ReactWidget {
74
77
  this.update();
75
78
  await done.promise;
76
79
  }
80
+ /**
81
+ * The current rendered-vs-JSON choice for notebook diffs.
82
+ */
77
83
  get notebookViewMode() {
78
84
  return this._notebookViewMode;
79
85
  }
86
+ /**
87
+ * Set the notebook view mode and persist it.
88
+ */
80
89
  setNotebookViewMode(mode) {
81
90
  if (mode === this._notebookViewMode) {
82
91
  return;
@@ -85,12 +94,21 @@ export class XtralabDiffWidget extends ReactWidget {
85
94
  writeStoredNotebookViewMode(mode);
86
95
  this._notebookViewModeChanged.emit(mode);
87
96
  }
97
+ /**
98
+ * A signal emitted when the notebook view mode changes.
99
+ */
88
100
  get notebookViewModeChanged() {
89
101
  return this._notebookViewModeChanged;
90
102
  }
103
+ /**
104
+ * Whether a rendered notebook view is currently available.
105
+ */
91
106
  get hasNotebookView() {
92
107
  return this._hasNotebookView;
93
108
  }
109
+ /**
110
+ * Set whether a rendered notebook view is available.
111
+ */
94
112
  setHasNotebookView(value) {
95
113
  if (value === this._hasNotebookView) {
96
114
  return;
@@ -98,12 +116,21 @@ export class XtralabDiffWidget extends ReactWidget {
98
116
  this._hasNotebookView = value;
99
117
  this._hasNotebookViewChanged.emit(value);
100
118
  }
119
+ /**
120
+ * A signal emitted when rendered-notebook availability changes.
121
+ */
101
122
  get hasNotebookViewChanged() {
102
123
  return this._hasNotebookViewChanged;
103
124
  }
125
+ /**
126
+ * The current split/unified layout for textual file diffs.
127
+ */
104
128
  get diffStyle() {
105
129
  return this._diffStyle;
106
130
  }
131
+ /**
132
+ * Set the diff style and persist it.
133
+ */
107
134
  setDiffStyle(style) {
108
135
  if (style === this._diffStyle) {
109
136
  return;
@@ -112,6 +139,9 @@ export class XtralabDiffWidget extends ReactWidget {
112
139
  writeStoredDiffStyle(style);
113
140
  this._diffStyleChanged.emit(style);
114
141
  }
142
+ /**
143
+ * A signal emitted when the diff style changes.
144
+ */
115
145
  get diffStyleChanged() {
116
146
  return this._diffStyleChanged;
117
147
  }
@@ -121,6 +151,9 @@ export class XtralabDiffWidget extends ReactWidget {
121
151
  get fileDiffActive() {
122
152
  return this._fileDiffActive;
123
153
  }
154
+ /**
155
+ * Set whether the textual file diff is the active view.
156
+ */
124
157
  setFileDiffActive(value) {
125
158
  if (value === this._fileDiffActive) {
126
159
  return;
@@ -128,6 +161,9 @@ export class XtralabDiffWidget extends ReactWidget {
128
161
  this._fileDiffActive = value;
129
162
  this._fileDiffActiveChanged.emit(value);
130
163
  }
164
+ /**
165
+ * A signal emitted when {@link fileDiffActive} changes.
166
+ */
131
167
  get fileDiffActiveChanged() {
132
168
  return this._fileDiffActiveChanged;
133
169
  }
@@ -137,27 +173,44 @@ export class XtralabDiffWidget extends ReactWidget {
137
173
  get emptied() {
138
174
  return this._emptied;
139
175
  }
176
+ /**
177
+ * Emit the {@link emptied} signal.
178
+ */
140
179
  notifyEmptied() {
141
180
  this._emptied.emit();
142
181
  }
182
+ /**
183
+ * Resolve and clear the pending `refresh()` promise, if any.
184
+ */
143
185
  settleRefresh() {
144
186
  const pending = this._pendingRefresh;
145
187
  this._pendingRefresh = null;
146
188
  pending === null || pending === void 0 ? void 0 : pending.resolve();
147
189
  }
190
+ /**
191
+ * Dispose of the resources held by the widget.
192
+ */
148
193
  dispose() {
149
- // Release any in-flight refresh awaiter so a host that awaits refresh()
150
- // (jupyterlab-git re-shows its diff button only once it resolves) does not
151
- // hang when the widget is torn down mid-fetch.
194
+ // jupyterlab-git awaits refresh() to re-show its diff button; release any
195
+ // in-flight awaiter so it does not hang on mid-fetch teardown.
152
196
  this.settleRefresh();
153
197
  super.dispose();
154
198
  }
199
+ /**
200
+ * A counter incremented on each `refresh()` to trigger a content re-fetch.
201
+ */
155
202
  get reloadNonce() {
156
203
  return this._reloadNonce;
157
204
  }
205
+ /**
206
+ * The application-level services used by the rendered diff.
207
+ */
158
208
  get context() {
159
209
  return this._context;
160
210
  }
211
+ /**
212
+ * Render the diff view for the current model.
213
+ */
161
214
  render() {
162
215
  return React.createElement(ModelDiffView, { widget: this });
163
216
  }
@@ -174,7 +227,6 @@ function ModelDiffView(props) {
174
227
  newText: '',
175
228
  error: null
176
229
  });
177
- // Mirror toolbar-driven notebook view changes into React state.
178
230
  const [notebookViewMode, setNotebookViewMode] = React.useState(() => widget.notebookViewMode);
179
231
  React.useEffect(() => {
180
232
  const handler = (sender, mode) => {
@@ -189,7 +241,6 @@ function ModelDiffView(props) {
189
241
  const handleNotebookAvailabilityChange = React.useCallback((available) => {
190
242
  widget.setHasNotebookView(available);
191
243
  }, [widget]);
192
- // Mirror toolbar-driven diff-style changes into React state.
193
244
  const [diffStyle, setDiffStyle] = React.useState(() => widget.diffStyle);
194
245
  React.useEffect(() => {
195
246
  const handler = (sender, style) => {
@@ -226,18 +277,14 @@ function ModelDiffView(props) {
226
277
  observer.disconnect();
227
278
  };
228
279
  }, [themeManager]);
229
- // Image diffs use the server's base64 payloads; other binaries show a placeholder.
230
280
  const isImage = React.useMemo(() => imageDataType(model.filename) !== null, [model.filename]);
231
281
  const isBinary = model.isBinary === true && !isImage;
232
- // Used by the launcher to auto-close an emptied diff after discard.
233
282
  const [hunkCount, setHunkCount] = React.useState(null);
234
283
  const handleMetadataChange = React.useCallback((info) => {
235
284
  setHunkCount(info.hunkCount);
236
285
  }, []);
237
- // Fetch both sides whenever the model or reload nonce changes.
238
286
  React.useEffect(() => {
239
287
  let cancelled = false;
240
- // Non-image binaries do not need content fetches.
241
288
  if (isBinary) {
242
289
  setState({ loading: false, oldText: '', newText: '', error: null });
243
290
  // An in-flight `refresh()` still has to resolve.
@@ -276,7 +323,6 @@ function ModelDiffView(props) {
276
323
  }
277
324
  finally {
278
325
  if (!cancelled) {
279
- // Let `refresh()` settle once content has loaded.
280
326
  widget.settleRefresh();
281
327
  }
282
328
  }
@@ -295,7 +341,6 @@ function ModelDiffView(props) {
295
341
  widget.notifyEmptied();
296
342
  }
297
343
  }, [state.loading, state.error, isBinary, hunkCount, nonce, widget]);
298
- // The launcher sets `canDiscard`; jupyterlab-git models fall back to source.
299
344
  const canDiscardHunk = (_a = model.canDiscard) !== null && _a !== void 0 ? _a : (model.challenger.source === Git.Diff.SpecialRef.WORKING &&
300
345
  model.hasConflict !== true);
301
346
  const serverPath = React.useMemo(() => { var _a; return PathExt.join((_a = model.repositoryPath) !== null && _a !== void 0 ? _a : '', model.filename); }, [model.repositoryPath, model.filename]);
@@ -309,7 +354,6 @@ function ModelDiffView(props) {
309
354
  });
310
355
  },
311
356
  onAfterSave: () => {
312
- // Re-pull so the diff reflects the reverted hunk.
313
357
  void widget.refresh();
314
358
  }
315
359
  }), [canDiscardHunk, contentsManager, serverPath, widget]);
@@ -339,6 +383,9 @@ class NotebookViewModeToolbarItem extends ReactWidget {
339
383
  this._widget = widget;
340
384
  this.addClass('jp-xtralab-DiffWidget-viewModeToolbarItem');
341
385
  }
386
+ /**
387
+ * Render the Notebook/JSON toggle.
388
+ */
342
389
  render() {
343
390
  return React.createElement(NotebookViewModeToolbarControl, { widget: this._widget });
344
391
  }
@@ -375,6 +422,9 @@ class DiffStyleToolbarItem extends ReactWidget {
375
422
  this._widget = widget;
376
423
  this.addClass('jp-xtralab-DiffWidget-diffStyleToolbarItem');
377
424
  }
425
+ /**
426
+ * Render the Split/Unified toggle.
427
+ */
378
428
  render() {
379
429
  return React.createElement(DiffStyleToolbarControl, { widget: this._widget });
380
430
  }
@@ -1,14 +1,14 @@
1
1
  import * as React from 'react';
2
2
  import type { TranslationBundle } from '@jupyterlab/translation';
3
- /**
4
- * The file extensions registered as the xtralab image diff provider.
5
- */
6
3
  export declare const IMAGE_DIFF_EXTENSIONS: string[];
7
4
  /**
8
5
  * The `data:` MIME subtype for a path xtralab renders as an image, or
9
6
  * `null` when the path is not a supported raster image.
10
7
  */
11
8
  export declare function imageDataType(path: string): string | null;
9
+ /**
10
+ * Props for {@link ImageDiffView}.
11
+ */
12
12
  interface IImageDiffViewProps {
13
13
  /**
14
14
  * Base64 of the reference (old) revision; empty when added.
@@ -28,9 +28,8 @@ interface IImageDiffViewProps {
28
28
  trans: TranslationBundle;
29
29
  }
30
30
  /**
31
- * The image comparison surface: a segmented mode selector (reusing the
32
- * diff segmented-control styling so it matches the Notebook/JSON toggle)
33
- * plus the selected 2-up / swipe / onion-skin view.
31
+ * The image comparison surface: a mode selector (reusing the diff widget's
32
+ * segmented-control styling) plus the selected 2-up / swipe / onion view.
34
33
  */
35
34
  export declare function ImageDiffView(props: IImageDiffViewProps): React.ReactElement;
36
35
  export {};
@@ -1,20 +1,14 @@
1
1
  import * as React from 'react';
2
2
  /**
3
3
  * xtralab's image diff, registered in place of `@jupyterlab/git:image-diff`.
4
- *
5
- * The git server base64-encodes binary content, so both diff hosts receive
6
- * the two sides as base64 strings through the same `content()` getters used
7
- * for text. This module turns those strings into `<img>` elements and
8
- * offers the 2-up / swipe / onion-skin comparison modes; no diffing library
9
- * is involved (`@pierre/diffs` is text-only).
4
+ * Both sides arrive base64-encoded through the same `content()` getters used
5
+ * for text; the 2-up/swipe/onion views are hand-rolled (`@pierre/diffs` is
6
+ * text-only).
10
7
  */
11
8
  /**
12
- * Raster image extensions xtralab renders as an image diff, mapped to the
13
- * MIME subtype used in the `data:image/<subtype>;base64,…` URL.
14
- *
15
- * `.svg` is intentionally absent: it is XML text, so the `@pierre/diffs`
16
- * text diff (the fallback provider) is more useful for it than an image
17
- * comparison.
9
+ * Raster extensions mapped to the `data:image/<subtype>` MIME subtype.
10
+ * `.svg` is intentionally absent: it is XML text, so the fallback text diff
11
+ * is more useful than an image comparison.
18
12
  */
19
13
  const IMAGE_DATA_TYPES = {
20
14
  '.png': 'png',
@@ -25,9 +19,6 @@ const IMAGE_DATA_TYPES = {
25
19
  '.bmp': 'bmp',
26
20
  '.ico': 'x-icon'
27
21
  };
28
- /**
29
- * The file extensions registered as the xtralab image diff provider.
30
- */
31
22
  export const IMAGE_DIFF_EXTENSIONS = Object.keys(IMAGE_DATA_TYPES);
32
23
  /**
33
24
  * The `data:` MIME subtype for a path xtralab renders as an image, or
@@ -51,8 +42,7 @@ function readStoredImageViewMode() {
51
42
  }
52
43
  }
53
44
  catch (_a) {
54
- // localStorage can throw in privacy/sandboxed contexts — 2-up is the
55
- // sensible default anyway.
45
+ // localStorage can throw in privacy/sandboxed contexts.
56
46
  }
57
47
  return '2-up';
58
48
  }
@@ -65,17 +55,13 @@ function writeStoredImageViewMode(mode) {
65
55
  }
66
56
  }
67
57
  /**
68
- * Strip whitespace from a base64 payload. Python's `base64.encodebytes`
69
- * (used by the git server) inserts a newline every 76 characters; most
70
- * browsers tolerate that inside a `data:` URL but some are stricter, and
71
- * the cleaned length also lets us size the file accurately.
58
+ * Strip whitespace from a base64 payload: the server's `base64.encodebytes`
59
+ * inserts newlines some browsers reject in `data:` URLs, and the cleaned
60
+ * length sizes the file accurately.
72
61
  */
73
62
  function cleanBase64(value) {
74
63
  return value.replace(/\s+/g, '');
75
64
  }
76
- /**
77
- * Decoded byte length of a (whitespace-free) base64 string.
78
- */
79
65
  function base64ByteLength(clean) {
80
66
  if (clean.length === 0) {
81
67
  return 0;
@@ -107,9 +93,8 @@ function toSide(raw, fileType) {
107
93
  };
108
94
  }
109
95
  /**
110
- * The image comparison surface: a segmented mode selector (reusing the
111
- * diff segmented-control styling so it matches the Notebook/JSON toggle)
112
- * plus the selected 2-up / swipe / onion-skin view.
96
+ * The image comparison surface: a mode selector (reusing the diff widget's
97
+ * segmented-control styling) plus the selected 2-up / swipe / onion view.
113
98
  */
114
99
  export function ImageDiffView(props) {
115
100
  const { reference, challenger, fileType, trans } = props;
@@ -157,21 +142,14 @@ function TwoUp({ reference, challenger, trans }) {
157
142
  React.createElement("div", { className: "jp-xtralab-ImageDiff-frame", "data-side": "challenger" }, challenger.uri !== null ? (React.createElement("img", { className: "jp-xtralab-ImageDiff-img", src: challenger.uri, alt: trans.__('Challenger revision'), onLoad: onChallLoad })) : (React.createElement("div", { className: "jp-xtralab-ImageDiff-empty" }, trans.__('Deleted')))),
158
143
  React.createElement("figcaption", { className: "jp-xtralab-ImageDiff-caption" }, caption(challenger, challSize, trans.__('Deleted'))))));
159
144
  }
160
- /**
161
- * Range slider shared by the swipe and onion-skin views. A native
162
- * `<input type="range">` (styled via CSS) keeps the bundle free of a UI
163
- * component dependency.
164
- */
165
145
  function RangeSlider(props) {
166
146
  const { value, onChange, ariaLabel } = props;
167
147
  return (React.createElement("input", { className: "jp-xtralab-ImageDiff-slider", type: "range", min: 0, max: 100, step: 1, value: value, "aria-label": ariaLabel, onChange: event => onChange(Number(event.target.value)) }));
168
148
  }
169
149
  /**
170
- * Fit a `naturalWidth × naturalHeight` image inside an `areaWidth ×
171
- * areaHeight` box without upscaling past its intrinsic size — the same
172
- * "contain, never enlarge" rule the 2-up and onion views get for free from
173
- * `max-width/height: 100%; width/height: auto`. Returns the displayed pixel
174
- * box, or `null` until both the image and the area have been measured.
150
+ * Fit an image inside an area without upscaling past its intrinsic size —
151
+ * the "contain, never enlarge" rule the other views get from CSS. Returns
152
+ * the displayed pixel box, or `null` until both sizes are measured.
175
153
  */
176
154
  function containBox(naturalWidth, naturalHeight, areaWidth, areaHeight) {
177
155
  if (naturalWidth <= 0 ||
@@ -183,9 +161,6 @@ function containBox(naturalWidth, naturalHeight, areaWidth, areaHeight) {
183
161
  const scale = Math.min(areaWidth / naturalWidth, areaHeight / naturalHeight, 1);
184
162
  return { width: naturalWidth * scale, height: naturalHeight * scale };
185
163
  }
186
- /**
187
- * Track an element's content-box size, kept current across layout changes.
188
- */
189
164
  function useElementSize() {
190
165
  const ref = React.useRef(null);
191
166
  const [size, setSize] = React.useState({ width: 0, height: 0 });
@@ -214,13 +189,9 @@ function Swipe({ reference, challenger, trans }) {
214
189
  const [challSize, onChallLoad] = useNaturalSize();
215
190
  const [areaRef, area] = useElementSize();
216
191
  const frameRef = React.useRef(null);
217
- // Display both revisions in a single box — the union of their intrinsic
218
- // sizes, scaled down to fit but never enlarged — and size the frame to
219
- // exactly that box. The divider's `left: N%`, the pointer-to-percent
220
- // mapping (below) and each image's `clip-path` inset then all resolve
221
- // against the same width, so the white line sits precisely on the seam
222
- // between the two revisions at every position. A full-width frame instead
223
- // let the line drift off the seam by as much as half the letterbox.
192
+ // Size the frame to the union box of both revisions so the divider %, the
193
+ // pointer mapping and the clip-paths all resolve against the same width;
194
+ // a full-width frame lets the line drift off the seam.
224
195
  const naturalWidth = Math.max((_a = refSize === null || refSize === void 0 ? void 0 : refSize[0]) !== null && _a !== void 0 ? _a : 0, (_b = challSize === null || challSize === void 0 ? void 0 : challSize[0]) !== null && _b !== void 0 ? _b : 0);
225
196
  const naturalHeight = Math.max((_c = refSize === null || refSize === void 0 ? void 0 : refSize[1]) !== null && _c !== void 0 ? _c : 0, (_d = challSize === null || challSize === void 0 ? void 0 : challSize[1]) !== null && _d !== void 0 ? _d : 0);
226
197
  const box = containBox(naturalWidth, naturalHeight, area.width, area.height);
@@ -237,7 +208,6 @@ function Swipe({ reference, challenger, trans }) {
237
208
  setPosition(Math.max(0, Math.min(100, next)));
238
209
  }, []);
239
210
  const onPointerDown = React.useCallback((event) => {
240
- // Only react to the primary pointer (left click / touch / pen tip).
241
211
  if (event.button !== 0) {
242
212
  return;
243
213
  }
@@ -1,8 +1,5 @@
1
1
  import { JupyterFrontEndPlugin } from '@jupyterlab/application';
2
2
  import { CommandArguments, CommandIDs } from './commands';
3
- /**
4
- * Plugins contributed by xtralab's git integration.
5
- */
6
3
  declare const plugins: JupyterFrontEndPlugin<unknown>[];
7
4
  export { CommandArguments, CommandIDs };
8
5
  export default plugins;
package/lib/git/index.js CHANGED
@@ -7,10 +7,9 @@ import diffProviderPlugin from './diffProvider';
7
7
  const GIT_DIFF_COMMAND_PLUGIN_ID = 'xtralab:git-diff-command';
8
8
  const GIT_DIFF_TRACKER_NAMESPACE = 'xtralab-git-diff';
9
9
  /**
10
- * The launcher's git diff command plugin.
11
- *
12
- * The upstream git panel stays enabled; this plugin only gives the launcher
13
- * its own `xtralab:git:open-diff` command and preview/pinned-tab tracking.
10
+ * The launcher's git diff command plugin. The upstream git panel stays
11
+ * enabled; this only adds `xtralab:git:open-diff` and preview/pinned-tab
12
+ * tracking.
14
13
  */
15
14
  const diffCommandPlugin = {
16
15
  id: GIT_DIFF_COMMAND_PLUGIN_ID,
@@ -19,7 +18,6 @@ const diffCommandPlugin = {
19
18
  optional: [IThemeManager, IRenderMimeRegistry, ITranslator, IAskAgent],
20
19
  activate: (app, themeManager, rendermime, translator, askAgent) => {
21
20
  const trans = (translator !== null && translator !== void 0 ? translator : nullTranslator).load('jupyterlab');
22
- // Track open diffs so repeated opens reveal the existing tab.
23
21
  const tracker = new WidgetTracker({
24
22
  namespace: GIT_DIFF_TRACKER_NAMESPACE
25
23
  });
@@ -53,9 +51,6 @@ const diffCommandPlugin = {
53
51
  });
54
52
  }
55
53
  };
56
- /**
57
- * Plugins contributed by xtralab's git integration.
58
- */
59
54
  const plugins = [
60
55
  diffCommandPlugin,
61
56
  diffProviderPlugin
@@ -3,42 +3,103 @@ import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
3
3
  import type { TranslationBundle } from '@jupyterlab/translation';
4
4
  import { type FileDiffMetadata } from '@pierre/diffs';
5
5
  /**
6
- * Minimal slice of nbformat 4.x that the diff inspects. Fields we don't
7
- * read (attachments, e.g.) are intentionally not narrowed — we still pass
8
- * them around as part of the cell, but we never project them into the diff.
6
+ * Minimal slice of nbformat 4.x that the diff inspects.
9
7
  */
10
8
  interface INotebookCell {
9
+ /**
10
+ * The cell type ('code', 'markdown', or 'raw').
11
+ */
11
12
  cell_type: string;
13
+ /**
14
+ * Stable cell id (nbformat >= 4.5); absent in older notebooks.
15
+ */
12
16
  id?: string;
17
+ /**
18
+ * The cell source, as a single string or an array of lines.
19
+ */
13
20
  source: string | string[];
21
+ /**
22
+ * Execution outputs; present on code cells only.
23
+ */
14
24
  outputs?: INotebookOutput[];
25
+ /**
26
+ * The cell-level metadata.
27
+ */
15
28
  metadata?: Record<string, unknown>;
29
+ /**
30
+ * Execution count of a code cell; `null` when the cell has not run.
31
+ */
16
32
  execution_count?: number | null;
33
+ /**
34
+ * Media attachments keyed by name (markdown and raw cells).
35
+ */
17
36
  attachments?: Record<string, unknown>;
18
37
  }
38
+ /**
39
+ * Minimal slice of an nbformat 4.x cell output that the diff inspects.
40
+ */
19
41
  interface INotebookOutput {
42
+ /**
43
+ * The output type ('stream', 'execute_result', 'display_data', or 'error').
44
+ */
20
45
  output_type: string;
46
+ /**
47
+ * The mime bundle of an `execute_result` or `display_data` output.
48
+ */
21
49
  data?: Record<string, unknown>;
50
+ /**
51
+ * The text of a `stream` output.
52
+ */
22
53
  text?: string | string[];
54
+ /**
55
+ * The stream name ('stdout' or 'stderr') of a `stream` output.
56
+ */
23
57
  name?: string;
58
+ /**
59
+ * The exception name of an `error` output.
60
+ */
24
61
  ename?: string;
62
+ /**
63
+ * The exception message of an `error` output.
64
+ */
25
65
  evalue?: string;
66
+ /**
67
+ * The traceback lines of an `error` output; may contain ANSI escapes.
68
+ */
26
69
  traceback?: string[];
70
+ /**
71
+ * The execution count of an `execute_result` output.
72
+ */
27
73
  execution_count?: number | null;
74
+ /**
75
+ * The output-level metadata.
76
+ */
28
77
  metadata?: Record<string, unknown>;
29
78
  }
79
+ /**
80
+ * Minimal slice of an nbformat 4.x notebook that the diff inspects.
81
+ */
30
82
  interface INotebook {
83
+ /**
84
+ * The notebook cells.
85
+ */
31
86
  cells: INotebookCell[];
87
+ /**
88
+ * The notebook-level metadata.
89
+ */
32
90
  metadata: Record<string, unknown>;
91
+ /**
92
+ * The nbformat major version.
93
+ */
33
94
  nbformat: number;
95
+ /**
96
+ * The nbformat minor version.
97
+ */
34
98
  nbformat_minor: number;
35
99
  }
36
100
  /**
37
- * One entry in the per-cell diff. `unchanged` cells are rendered as a
38
- * collapsed summary; the other variants render their source / outputs /
39
- * metadata via {@link FileDiff}. The `modified` and `unchanged` branches
40
- * carry the same payload but live on separate union members so `Extract`
41
- * narrowing works on `kind` literals downstream.
101
+ * One entry in the per-cell diff. `modified` and `unchanged` carry the same
102
+ * payload on separate union members so `Extract` narrowing on `kind` works.
42
103
  */
43
104
  type NotebookCellDiff = {
44
105
  kind: 'modified';
@@ -62,48 +123,69 @@ type NotebookCellDiff = {
62
123
  oldIndex: number;
63
124
  };
64
125
  /**
65
- * Notebook-level diff result returned by {@link buildNotebookDiff}. Returns
66
- * `null` from the builder when either side fails to parse — the caller then
67
- * falls back to a raw JSON file diff.
126
+ * Notebook-level diff result returned by {@link buildNotebookDiff}.
68
127
  */
69
128
  export interface INotebookDiffResult {
129
+ /**
130
+ * The parsed old revision of the notebook.
131
+ */
70
132
  oldNotebook: INotebook;
133
+ /**
134
+ * The parsed new revision of the notebook.
135
+ */
71
136
  newNotebook: INotebook;
137
+ /**
138
+ * Per-cell diff entries, in new-notebook order with removed cells appended.
139
+ */
72
140
  cells: NotebookCellDiff[];
73
141
  /**
74
- * Kernel language pulled from `metadata.language_info.name`, used to pick
75
- * a syntax-highlighting filename for code cells.
142
+ * Kernel language from `metadata.language_info.name`; picks the highlighting filename.
76
143
  */
77
144
  language: string | undefined;
78
145
  /**
79
- * Pre-computed diff for notebook-level metadata (kernelspec, language_info,
80
- * nbformat) when it differs between revisions; `null` otherwise so the
81
- * section can be hidden without further checks.
146
+ * Diff of notebook-level metadata when it differs between revisions; `null` otherwise.
82
147
  */
83
148
  notebookMetadataDiff: FileDiffMetadata | null;
84
149
  }
150
+ /**
151
+ * Options for {@link buildNotebookDiff}.
152
+ */
85
153
  interface IBuildNotebookDiffOptions {
154
+ /**
155
+ * The raw text of the old notebook revision.
156
+ */
86
157
  oldText: string;
158
+ /**
159
+ * The raw text of the new notebook revision.
160
+ */
87
161
  newText: string;
88
162
  }
89
163
  /**
90
- * Build a complete notebook diff from the textual contents of two
91
- * revisions. Returns `null` if either side fails to parse as a notebook;
92
- * the caller is expected to fall back to a raw text diff in that case.
93
- *
94
- * An empty string on either side is treated as an empty notebook (no
95
- * cells, default metadata) so a freshly-added or deleted notebook still
96
- * produces a sensible cell-by-cell diff.
164
+ * Build a notebook diff from the text of two revisions. Returns `null` when
165
+ * either side fails to parse (caller falls back to a raw text diff); an
166
+ * empty string counts as an empty notebook so added/deleted notebooks still
167
+ * diff cell by cell.
97
168
  */
98
169
  export declare function buildNotebookDiff(options: IBuildNotebookDiffOptions): INotebookDiffResult | null;
170
+ /**
171
+ * Props for {@link NotebookDiffView}.
172
+ */
99
173
  interface INotebookDiffViewProps {
174
+ /**
175
+ * The notebook diff to render.
176
+ */
100
177
  diff: INotebookDiffResult;
178
+ /**
179
+ * Whether the active JupyterLab theme is dark.
180
+ */
101
181
  dark: boolean;
102
182
  /**
103
- * Whether a Pierre JupyterLab theme is active; selects Pierre's rich
104
- * highlighting vs the CSS-variable theme (see {@link resolveDiffTheme}).
183
+ * Whether a Pierre JupyterLab theme is active; selects Pierre highlighting vs the CSS-variable theme.
105
184
  */
106
185
  pierreTheme: boolean;
186
+ /**
187
+ * Registry rendering markdown and output previews; `null` falls back to plain text.
188
+ */
107
189
  rendermime: IRenderMimeRegistry | null;
108
190
  /**
109
191
  * Translation bundle for user-facing strings.
@@ -111,14 +193,9 @@ interface INotebookDiffViewProps {
111
193
  trans: TranslationBundle;
112
194
  }
113
195
  /**
114
- * The notebook-level diff view. Lays out cells in a 2-column grid where
115
- * the left column tracks the *old* notebook and the right column tracks
116
- * the *new* one — modified and unchanged cells span both columns (their
117
- * internal split-mode FileDiff aligns with the outer columns), added
118
- * cells live in the right column with an empty placeholder on the left,
119
- * and removed cells live in the left column with an empty placeholder on
120
- * the right. The diff library's red/green tint within each cell makes
121
- * the orientation clear without a separate column header.
196
+ * Notebook-level diff view: a 2-column grid where the left column tracks
197
+ * the old notebook and the right the new one — modified/unchanged cells
198
+ * span both, added cells sit right, removed cells sit left.
122
199
  */
123
200
  export declare function NotebookDiffView(props: INotebookDiffViewProps): React.ReactElement;
124
201
  export {};