xtralab 0.15.1 → 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.
Files changed (39) hide show
  1. package/README.md +58 -33
  2. package/lib/fileBrowser/commands.d.ts +1 -0
  3. package/lib/fileBrowser/commands.js +46 -1
  4. package/lib/fileBrowser/fileBrowser.js +4 -8
  5. package/lib/fileBrowser/gitStatus.d.ts +16 -5
  6. package/lib/fileBrowser/gitStatus.js +28 -17
  7. package/lib/fileBrowser/widget.d.ts +15 -0
  8. package/lib/fileBrowser/widget.js +13 -0
  9. package/lib/git/commands.d.ts +5 -0
  10. package/lib/git/commands.js +4 -3
  11. package/lib/git/diffPreferences.d.ts +90 -0
  12. package/lib/git/diffPreferences.js +107 -0
  13. package/lib/git/diffProvider.js +10 -2
  14. package/lib/git/diffSurface.d.ts +34 -19
  15. package/lib/git/diffSurface.js +49 -115
  16. package/lib/git/diffTheme.d.ts +7 -0
  17. package/lib/git/diffTheme.js +23 -0
  18. package/lib/git/diffWidget.d.ts +7 -30
  19. package/lib/git/diffWidget.js +56 -100
  20. package/lib/git/imageDiff.d.ts +9 -0
  21. package/lib/git/imageDiff.js +2 -28
  22. package/lib/git/index.js +41 -2
  23. package/lib/git/notebookDiff.js +3 -2
  24. package/package.json +5 -3
  25. package/schema/git-diff-preferences.json +42 -0
  26. package/src/fileBrowser/commands.ts +64 -0
  27. package/src/fileBrowser/fileBrowser.tsx +4 -9
  28. package/src/fileBrowser/gitStatus.ts +33 -20
  29. package/src/fileBrowser/widget.tsx +22 -0
  30. package/src/git/commands.ts +13 -1
  31. package/src/git/diffPreferences.ts +192 -0
  32. package/src/git/diffProvider.tsx +11 -2
  33. package/src/git/diffSurface.tsx +113 -146
  34. package/src/git/diffTheme.ts +24 -0
  35. package/src/git/diffWidget.tsx +108 -138
  36. package/src/git/imageDiff.tsx +12 -34
  37. package/src/git/index.ts +51 -2
  38. package/src/git/notebookDiff.tsx +3 -2
  39. package/style/git.css +4 -2
@@ -15,19 +15,19 @@ import type { SelectedLineRange } from '@pierre/diffs';
15
15
  import type { IAskAgent } from '../askAgent/tokens';
16
16
 
17
17
  import { buildDiffAskRequest } from './askRequest';
18
+ import {
19
+ useDiffPreferences,
20
+ type IDiffPreferences,
21
+ type ImageDiffViewMode
22
+ } from './diffPreferences';
18
23
  import {
19
24
  DIFF_WIDGET_CSS_CLASS,
20
25
  DiffStyleControl,
21
26
  DiffSurface,
27
+ LineWrapControl,
22
28
  NotebookViewModeControl,
23
29
  isDarkTheme,
24
- isPierreTheme,
25
- readStoredDiffStyle,
26
- readStoredNotebookViewMode,
27
- writeStoredDiffStyle,
28
- writeStoredNotebookViewMode,
29
- type DiffStyle,
30
- type NotebookDiffViewMode
30
+ isPierreTheme
31
31
  } from './diffSurface';
32
32
  import { imageDataType } from './imageDiff';
33
33
 
@@ -73,6 +73,10 @@ export interface IXtralabDiffContext {
73
73
  * When available, diff line selections get an "ask an agent" gutter button.
74
74
  */
75
75
  askAgent: IAskAgent | null;
76
+ /**
77
+ * The display choices shared by all diff views.
78
+ */
79
+ preferences: IDiffPreferences;
76
80
  /**
77
81
  * The application translation bundle.
78
82
  */
@@ -90,8 +94,6 @@ export class XtralabDiffWidget
90
94
  super();
91
95
  this._model = model;
92
96
  this._context = context;
93
- this._notebookViewMode = readStoredNotebookViewMode();
94
- this._diffStyle = readStoredDiffStyle();
95
97
  // Reuse jupyterlab-git's host sizing while applying xtralab styling.
96
98
  this.addClass('jp-git-diff-root');
97
99
  this.addClass(DIFF_WIDGET_CSS_CLASS);
@@ -149,32 +151,6 @@ export class XtralabDiffWidget
149
151
  await done.promise;
150
152
  }
151
153
 
152
- /**
153
- * The current rendered-vs-JSON choice for notebook diffs.
154
- */
155
- get notebookViewMode(): NotebookDiffViewMode {
156
- return this._notebookViewMode;
157
- }
158
-
159
- /**
160
- * Set the notebook view mode and persist it.
161
- */
162
- setNotebookViewMode(mode: NotebookDiffViewMode): void {
163
- if (mode === this._notebookViewMode) {
164
- return;
165
- }
166
- this._notebookViewMode = mode;
167
- writeStoredNotebookViewMode(mode);
168
- this._notebookViewModeChanged.emit(mode);
169
- }
170
-
171
- /**
172
- * A signal emitted when the notebook view mode changes.
173
- */
174
- get notebookViewModeChanged(): ISignal<this, NotebookDiffViewMode> {
175
- return this._notebookViewModeChanged;
176
- }
177
-
178
154
  /**
179
155
  * Whether a rendered notebook view is currently available.
180
156
  */
@@ -201,33 +177,7 @@ export class XtralabDiffWidget
201
177
  }
202
178
 
203
179
  /**
204
- * The current split/unified layout for textual file diffs.
205
- */
206
- get diffStyle(): DiffStyle {
207
- return this._diffStyle;
208
- }
209
-
210
- /**
211
- * Set the diff style and persist it.
212
- */
213
- setDiffStyle(style: DiffStyle): void {
214
- if (style === this._diffStyle) {
215
- return;
216
- }
217
- this._diffStyle = style;
218
- writeStoredDiffStyle(style);
219
- this._diffStyleChanged.emit(style);
220
- }
221
-
222
- /**
223
- * A signal emitted when the diff style changes.
224
- */
225
- get diffStyleChanged(): ISignal<this, DiffStyle> {
226
- return this._diffStyleChanged;
227
- }
228
-
229
- /**
230
- * Whether the Split/Unified toolbar selector currently applies.
180
+ * Whether the Split/Unified and line-wrap toolbar controls currently apply.
231
181
  */
232
182
  get fileDiffActive(): boolean {
233
183
  return this._fileDiffActive;
@@ -309,14 +259,8 @@ export class XtralabDiffWidget
309
259
  private _context: IXtralabDiffContext;
310
260
  private _reloadNonce = 0;
311
261
  private _pendingRefresh: PromiseDelegate<void> | null = null;
312
- private _notebookViewMode: NotebookDiffViewMode;
313
- private _notebookViewModeChanged = new Signal<this, NotebookDiffViewMode>(
314
- this
315
- );
316
262
  private _hasNotebookView = false;
317
263
  private _hasNotebookViewChanged = new Signal<this, boolean>(this);
318
- private _diffStyle: DiffStyle;
319
- private _diffStyleChanged = new Signal<this, DiffStyle>(this);
320
264
  private _fileDiffActive = false;
321
265
  private _fileDiffActiveChanged = new Signal<this, boolean>(this);
322
266
  private _emptied = new Signal<this, void>(this);
@@ -349,8 +293,15 @@ function ModelDiffView(props: {
349
293
  }): React.ReactElement {
350
294
  const { widget } = props;
351
295
  const model = widget.model as IXtralabDiffModel;
352
- const { contentsManager, rendermime, themeManager, askAgent, trans } =
353
- widget.context;
296
+ const {
297
+ contentsManager,
298
+ rendermime,
299
+ themeManager,
300
+ askAgent,
301
+ preferences,
302
+ trans
303
+ } = widget.context;
304
+ const values = useDiffPreferences(preferences);
354
305
  const nonce = widget.reloadNonce;
355
306
 
356
307
  const [state, setState] = React.useState<IModelDiffState>({
@@ -360,22 +311,6 @@ function ModelDiffView(props: {
360
311
  error: null
361
312
  });
362
313
 
363
- const [notebookViewMode, setNotebookViewMode] =
364
- React.useState<NotebookDiffViewMode>(() => widget.notebookViewMode);
365
- React.useEffect(() => {
366
- const handler = (
367
- sender: XtralabDiffWidget,
368
- mode: NotebookDiffViewMode
369
- ): void => {
370
- setNotebookViewMode(mode);
371
- };
372
- widget.notebookViewModeChanged.connect(handler);
373
- setNotebookViewMode(widget.notebookViewMode);
374
- return () => {
375
- widget.notebookViewModeChanged.disconnect(handler);
376
- };
377
- }, [widget]);
378
-
379
314
  const handleNotebookAvailabilityChange = React.useCallback(
380
315
  (available: boolean) => {
381
316
  widget.setHasNotebookView(available);
@@ -383,19 +318,19 @@ function ModelDiffView(props: {
383
318
  [widget]
384
319
  );
385
320
 
386
- const [diffStyle, setDiffStyle] = React.useState<DiffStyle>(
387
- () => widget.diffStyle
321
+ const handleSplitRatioChange = React.useCallback(
322
+ (splitRatio: number) => {
323
+ preferences.update({ splitRatio });
324
+ },
325
+ [preferences]
326
+ );
327
+
328
+ const handleImageViewModeChange = React.useCallback(
329
+ (imageViewMode: ImageDiffViewMode) => {
330
+ preferences.update({ imageViewMode });
331
+ },
332
+ [preferences]
388
333
  );
389
- React.useEffect(() => {
390
- const handler = (sender: XtralabDiffWidget, style: DiffStyle): void => {
391
- setDiffStyle(style);
392
- };
393
- widget.diffStyleChanged.connect(handler);
394
- setDiffStyle(widget.diffStyle);
395
- return () => {
396
- widget.diffStyleChanged.disconnect(handler);
397
- };
398
- }, [widget]);
399
334
 
400
335
  const handleFileDiffActiveChange = React.useCallback(
401
336
  (active: boolean) => {
@@ -562,8 +497,13 @@ function ModelDiffView(props: {
562
497
  dark={dark}
563
498
  pierreTheme={pierre}
564
499
  rendermime={rendermime}
565
- notebookViewMode={notebookViewMode}
566
- diffStyle={diffStyle}
500
+ notebookViewMode={values.notebookViewMode}
501
+ diffStyle={values.diffStyle}
502
+ lineWrap={values.lineWrap}
503
+ splitRatio={values.splitRatio}
504
+ onSplitRatioChange={handleSplitRatioChange}
505
+ imageViewMode={values.imageViewMode}
506
+ onImageViewModeChange={handleImageViewModeChange}
567
507
  onNotebookAvailabilityChange={handleNotebookAvailabilityChange}
568
508
  onFileDiffActiveChange={handleFileDiffActiveChange}
569
509
  onMetadataChange={handleMetadataChange}
@@ -598,38 +538,27 @@ function NotebookViewModeToolbarControl(props: {
598
538
  widget: XtralabDiffWidget;
599
539
  }): React.ReactElement {
600
540
  const { widget } = props;
601
- const [mode, setMode] = React.useState<NotebookDiffViewMode>(
602
- () => widget.notebookViewMode
603
- );
541
+ const { preferences, trans } = widget.context;
542
+ const { notebookViewMode } = useDiffPreferences(preferences);
604
543
  const [available, setAvailable] = React.useState<boolean>(
605
544
  () => widget.hasNotebookView
606
545
  );
607
546
  React.useEffect(() => {
608
- const onMode = (
609
- sender: XtralabDiffWidget,
610
- next: NotebookDiffViewMode
611
- ): void => {
612
- setMode(next);
613
- };
614
547
  const onAvailable = (sender: XtralabDiffWidget, next: boolean): void => {
615
548
  setAvailable(next);
616
549
  };
617
- widget.notebookViewModeChanged.connect(onMode);
618
550
  widget.hasNotebookViewChanged.connect(onAvailable);
619
- setMode(widget.notebookViewMode);
620
551
  setAvailable(widget.hasNotebookView);
621
552
  return () => {
622
- widget.notebookViewModeChanged.disconnect(onMode);
623
553
  widget.hasNotebookViewChanged.disconnect(onAvailable);
624
554
  };
625
555
  }, [widget]);
626
556
 
627
- const trans = widget.context.trans;
628
557
  return (
629
558
  <NotebookViewModeControl
630
- mode={mode}
559
+ mode={notebookViewMode}
631
560
  available={available}
632
- onChange={next => widget.setNotebookViewMode(next)}
561
+ onChange={next => preferences.update({ notebookViewMode: next })}
633
562
  trans={trans}
634
563
  />
635
564
  );
@@ -659,38 +588,78 @@ function DiffStyleToolbarControl(props: {
659
588
  widget: XtralabDiffWidget;
660
589
  }): React.ReactElement {
661
590
  const { widget } = props;
662
- const [style, setStyle] = React.useState<DiffStyle>(() => widget.diffStyle);
663
- const [available, setAvailable] = React.useState<boolean>(
664
- () => widget.fileDiffActive
591
+ const { preferences, trans } = widget.context;
592
+ const { diffStyle, diffStyleControl } = useDiffPreferences(preferences);
593
+ const available = useFileDiffActive(widget);
594
+ return (
595
+ <DiffStyleControl
596
+ diffStyle={diffStyle}
597
+ control={diffStyleControl}
598
+ available={available}
599
+ onChange={next => preferences.update({ diffStyle: next })}
600
+ trans={trans}
601
+ />
665
602
  );
666
- React.useEffect(() => {
667
- const onStyle = (sender: XtralabDiffWidget, next: DiffStyle): void => {
668
- setStyle(next);
669
- };
670
- const onAvailable = (sender: XtralabDiffWidget, next: boolean): void => {
671
- setAvailable(next);
672
- };
673
- widget.diffStyleChanged.connect(onStyle);
674
- widget.fileDiffActiveChanged.connect(onAvailable);
675
- setStyle(widget.diffStyle);
676
- setAvailable(widget.fileDiffActive);
677
- return () => {
678
- widget.diffStyleChanged.disconnect(onStyle);
679
- widget.fileDiffActiveChanged.disconnect(onAvailable);
680
- };
681
- }, [widget]);
603
+ }
604
+
605
+ /**
606
+ * Line-wrap toggle mounted into a host-owned toolbar.
607
+ */
608
+ class LineWrapToolbarItem extends ReactWidget {
609
+ constructor(widget: XtralabDiffWidget) {
610
+ super();
611
+ this._widget = widget;
612
+ this.addClass('jp-xtralab-DiffWidget-lineWrapToolbarItem');
613
+ }
614
+
615
+ /**
616
+ * Render the line-wrap toggle.
617
+ */
618
+ protected render(): React.ReactElement {
619
+ return <LineWrapToolbarControl widget={this._widget} />;
620
+ }
682
621
 
683
- const trans = widget.context.trans;
622
+ private _widget: XtralabDiffWidget;
623
+ }
624
+
625
+ function LineWrapToolbarControl(props: {
626
+ widget: XtralabDiffWidget;
627
+ }): React.ReactElement {
628
+ const { widget } = props;
629
+ const { preferences, trans } = widget.context;
630
+ const { lineWrap } = useDiffPreferences(preferences);
631
+ const available = useFileDiffActive(widget);
684
632
  return (
685
- <DiffStyleControl
686
- diffStyle={style}
633
+ <LineWrapControl
634
+ lineWrap={lineWrap}
687
635
  available={available}
688
- onChange={next => widget.setDiffStyle(next)}
636
+ onChange={next => preferences.update({ lineWrap: next })}
689
637
  trans={trans}
690
638
  />
691
639
  );
692
640
  }
693
641
 
642
+ /**
643
+ * Track {@link XtralabDiffWidget.fileDiffActive} for the split/unified and
644
+ * line-wrap controls.
645
+ */
646
+ function useFileDiffActive(widget: XtralabDiffWidget): boolean {
647
+ const [active, setActive] = React.useState<boolean>(
648
+ () => widget.fileDiffActive
649
+ );
650
+ React.useEffect(() => {
651
+ const onActive = (sender: XtralabDiffWidget, next: boolean): void => {
652
+ setActive(next);
653
+ };
654
+ widget.fileDiffActiveChanged.connect(onActive);
655
+ setActive(widget.fileDiffActive);
656
+ return () => {
657
+ widget.fileDiffActiveChanged.disconnect(onActive);
658
+ };
659
+ }, [widget]);
660
+ return active;
661
+ }
662
+
694
663
  /**
695
664
  * Structural toolbar type shared across host package boundaries.
696
665
  */
@@ -713,4 +682,5 @@ export function addDiffToolbarItems(
713
682
  new NotebookViewModeToolbarItem(widget)
714
683
  );
715
684
  toolbar.addItem('xtralab-diff-style', new DiffStyleToolbarItem(widget));
685
+ toolbar.addItem('xtralab-diff-line-wrap', new LineWrapToolbarItem(widget));
716
686
  }
@@ -2,6 +2,8 @@ import * as React from 'react';
2
2
 
3
3
  import type { TranslationBundle } from '@jupyterlab/translation';
4
4
 
5
+ import type { ImageDiffViewMode } from './diffPreferences';
6
+
5
7
  /**
6
8
  * xtralab's image diff, registered in place of `@jupyterlab/git:image-diff`.
7
9
  * Both sides arrive base64-encoded through the same `content()` getters used
@@ -39,30 +41,6 @@ export function imageDataType(path: string): string | null {
39
41
  return IMAGE_DATA_TYPES[lower.slice(dot)] ?? null;
40
42
  }
41
43
 
42
- type ImageDiffViewMode = '2-up' | 'swipe' | 'onion';
43
-
44
- const IMAGE_DIFF_VIEW_MODE_STORAGE_KEY = 'xtralab:image-diff-view-mode';
45
-
46
- function readStoredImageViewMode(): ImageDiffViewMode {
47
- try {
48
- const raw = window.localStorage.getItem(IMAGE_DIFF_VIEW_MODE_STORAGE_KEY);
49
- if (raw === '2-up' || raw === 'swipe' || raw === 'onion') {
50
- return raw;
51
- }
52
- } catch {
53
- // localStorage can throw in privacy/sandboxed contexts.
54
- }
55
- return '2-up';
56
- }
57
-
58
- function writeStoredImageViewMode(mode: ImageDiffViewMode): void {
59
- try {
60
- window.localStorage.setItem(IMAGE_DIFF_VIEW_MODE_STORAGE_KEY, mode);
61
- } catch {
62
- // Best-effort.
63
- }
64
- }
65
-
66
44
  /**
67
45
  * Strip whitespace from a base64 payload: the server's `base64.encodebytes`
68
46
  * inserts newlines some browsers reject in `data:` URLs, and the cleaned
@@ -143,6 +121,14 @@ interface IImageDiffViewProps {
143
121
  * MIME subtype from {@link imageDataType}.
144
122
  */
145
123
  fileType: string;
124
+ /**
125
+ * The selected comparison mode (host-controlled).
126
+ */
127
+ mode: ImageDiffViewMode;
128
+ /**
129
+ * Called when the user picks another comparison mode.
130
+ */
131
+ onModeChange: (mode: ImageDiffViewMode) => void;
146
132
  /**
147
133
  * Translation bundle for user-facing strings.
148
134
  */
@@ -154,7 +140,7 @@ interface IImageDiffViewProps {
154
140
  * segmented-control styling) plus the selected 2-up / swipe / onion view.
155
141
  */
156
142
  export function ImageDiffView(props: IImageDiffViewProps): React.ReactElement {
157
- const { reference, challenger, fileType, trans } = props;
143
+ const { reference, challenger, fileType, mode, onModeChange, trans } = props;
158
144
  const ref = React.useMemo(
159
145
  () => toSide(reference, fileType),
160
146
  [reference, fileType]
@@ -164,14 +150,6 @@ export function ImageDiffView(props: IImageDiffViewProps): React.ReactElement {
164
150
  [challenger, fileType]
165
151
  );
166
152
 
167
- const [mode, setMode] = React.useState<ImageDiffViewMode>(() =>
168
- readStoredImageViewMode()
169
- );
170
- const changeMode = React.useCallback((next: ImageDiffViewMode) => {
171
- setMode(next);
172
- writeStoredImageViewMode(next);
173
- }, []);
174
-
175
153
  return (
176
154
  <div className="jp-xtralab-ImageDiff">
177
155
  <div className="jp-xtralab-ImageDiff-header">
@@ -194,7 +172,7 @@ export function ImageDiffView(props: IImageDiffViewProps): React.ReactElement {
194
172
  aria-selected={mode === value}
195
173
  data-active={mode === value}
196
174
  className="jp-xtralab-DiffWidget-segmentedButton"
197
- onClick={() => changeMode(value)}
175
+ onClick={() => onModeChange(value)}
198
176
  >
199
177
  {label}
200
178
  </button>
package/src/git/index.ts CHANGED
@@ -4,6 +4,8 @@ import {
4
4
  } from '@jupyterlab/application';
5
5
  import { IThemeManager, WidgetTracker } from '@jupyterlab/apputils';
6
6
  import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
7
+ import { ISettingRegistry } from '@jupyterlab/settingregistry';
8
+ import { IStateDB } from '@jupyterlab/statedb';
7
9
  import { ITranslator, nullTranslator } from '@jupyterlab/translation';
8
10
 
9
11
  import { IAskAgent } from '../askAgent/tokens';
@@ -16,12 +18,50 @@ import {
16
18
  pinnedDiffWidgetId,
17
19
  registerGitCommands
18
20
  } from './commands';
21
+ import { DiffPreferences, IDiffPreferences } from './diffPreferences';
19
22
  import diffProviderPlugin from './diffProvider';
20
23
  import { IFileChange } from './tokens';
21
24
 
22
25
  const GIT_DIFF_COMMAND_PLUGIN_ID = 'xtralab:git-diff-command';
26
+ const GIT_DIFF_PREFERENCES_PLUGIN_ID = 'xtralab:git-diff-preferences';
23
27
  const GIT_DIFF_TRACKER_NAMESPACE = 'xtralab-git-diff';
24
28
 
29
+ /**
30
+ * The display choices shared by the launcher diff and the Git panel diff.
31
+ */
32
+ const diffPreferencesPlugin: JupyterFrontEndPlugin<IDiffPreferences> = {
33
+ id: GIT_DIFF_PREFERENCES_PLUGIN_ID,
34
+ description:
35
+ 'Keeps the git diff display choices in the settings and the state database.',
36
+ autoStart: true,
37
+ provides: IDiffPreferences,
38
+ optional: [ISettingRegistry, IStateDB],
39
+ activate: (
40
+ app: JupyterFrontEnd,
41
+ settingRegistry: ISettingRegistry | null,
42
+ state: IStateDB | null
43
+ ): IDiffPreferences => {
44
+ const preferences = new DiffPreferences();
45
+ if (settingRegistry !== null) {
46
+ settingRegistry
47
+ .load(GIT_DIFF_PREFERENCES_PLUGIN_ID)
48
+ .then(settings => preferences.connectSettings(settings))
49
+ .catch(reason => {
50
+ console.error(
51
+ `xtralab: failed to load settings for ${GIT_DIFF_PREFERENCES_PLUGIN_ID}`,
52
+ reason
53
+ );
54
+ });
55
+ }
56
+ if (state !== null) {
57
+ preferences.connectState(state).catch(reason => {
58
+ console.error('xtralab: failed to restore the diff split', reason);
59
+ });
60
+ }
61
+ return preferences;
62
+ }
63
+ };
64
+
25
65
  /**
26
66
  * The launcher's git diff command plugin. The upstream git panel stays
27
67
  * enabled; this only adds `xtralab:git:open-diff` and preview/pinned-tab
@@ -32,13 +72,20 @@ const diffCommandPlugin: JupyterFrontEndPlugin<void> = {
32
72
  description:
33
73
  "The launcher dashboard's side-by-side git diff command, powered by @pierre/diffs.",
34
74
  autoStart: true,
35
- optional: [IThemeManager, IRenderMimeRegistry, ITranslator, IAskAgent],
75
+ optional: [
76
+ IThemeManager,
77
+ IRenderMimeRegistry,
78
+ ITranslator,
79
+ IAskAgent,
80
+ IDiffPreferences
81
+ ],
36
82
  activate: (
37
83
  app: JupyterFrontEnd,
38
84
  themeManager: IThemeManager | null,
39
85
  rendermime: IRenderMimeRegistry | null,
40
86
  translator: ITranslator | null,
41
- askAgent: IAskAgent | null
87
+ askAgent: IAskAgent | null,
88
+ preferences: IDiffPreferences | null
42
89
  ): void => {
43
90
  const trans = (translator ?? nullTranslator).load('jupyterlab');
44
91
  const tracker = new WidgetTracker<DiffMainAreaWidget>({
@@ -62,6 +109,7 @@ const diffCommandPlugin: JupyterFrontEndPlugin<void> = {
62
109
  contentsManager: app.serviceManager.contents,
63
110
  rendermime,
64
111
  askAgent,
112
+ preferences: preferences ?? new DiffPreferences(),
65
113
  trans,
66
114
  trackDiff: widget => tracker.add(widget),
67
115
  onPinned: current => {
@@ -85,6 +133,7 @@ const diffCommandPlugin: JupyterFrontEndPlugin<void> = {
85
133
  };
86
134
 
87
135
  const plugins: JupyterFrontEndPlugin<unknown>[] = [
136
+ diffPreferencesPlugin,
88
137
  diffCommandPlugin,
89
138
  diffProviderPlugin
90
139
  ];
@@ -13,7 +13,7 @@ import {
13
13
  type FileDiffMetadata
14
14
  } from '@pierre/diffs';
15
15
 
16
- import { resolveDiffTheme } from './diffTheme';
16
+ import { DIFF_SCROLLBAR_CSS, resolveDiffTheme } from './diffTheme';
17
17
 
18
18
  const NOTEBOOK_DIFF_CSS_CLASS = 'jp-xtralab-NotebookDiff';
19
19
 
@@ -560,7 +560,8 @@ function diffLibraryOptions(theme: DiffsThemeNames, dark: boolean) {
560
560
  diffStyle: 'split' as const,
561
561
  disableFileHeader: true,
562
562
  theme,
563
- themeType: dark ? ('dark' as const) : ('light' as const)
563
+ themeType: dark ? ('dark' as const) : ('light' as const),
564
+ unsafeCSS: DIFF_SCROLLBAR_CSS
564
565
  };
565
566
  }
566
567
 
package/style/git.css CHANGED
@@ -50,13 +50,15 @@
50
50
  }
51
51
 
52
52
  .jp-xtralab-DiffWidget-viewModeToolbarItem,
53
- .jp-xtralab-DiffWidget-diffStyleToolbarItem {
53
+ .jp-xtralab-DiffWidget-diffStyleToolbarItem,
54
+ .jp-xtralab-DiffWidget-lineWrapToolbarItem {
54
55
  display: flex;
55
56
  align-items: center;
56
57
  font-size: var(--jp-ui-font-size0);
57
58
  }
58
59
 
59
- .jp-xtralab-DiffWidget-diffStyleToolbarItem {
60
+ .jp-xtralab-DiffWidget-diffStyleToolbarItem,
61
+ .jp-xtralab-DiffWidget-lineWrapToolbarItem {
60
62
  margin-left: 4px;
61
63
  }
62
64