@jupyterlab/notebook-extension 4.0.0-alpha.9 → 4.0.0-beta.0

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/lib/index.js CHANGED
@@ -4,31 +4,38 @@
4
4
  * @packageDocumentation
5
5
  * @module notebook-extension
6
6
  */
7
- import { ILabShell, ILayoutRestorer } from '@jupyterlab/application';
8
- import { createToolbarFactory, Dialog, ICommandPalette, IKernelStatusModel, InputDialog, ISessionContextDialogs, IToolbarWidgetRegistry, MainAreaWidget, sessionContextDialogs, showDialog, Toolbar, WidgetTracker } from '@jupyterlab/apputils';
7
+ import { ILabShell, ILayoutRestorer, IRouter } from '@jupyterlab/application';
8
+ import { createToolbarFactory, Dialog, ICommandPalette, IKernelStatusModel, InputDialog, ISanitizer, ISessionContextDialogs, IToolbarWidgetRegistry, MainAreaWidget, Sanitizer, SessionContextDialogs, showDialog, Toolbar, WidgetTracker } from '@jupyterlab/apputils';
9
9
  import { MarkdownCell } from '@jupyterlab/cells';
10
10
  import { IEditorServices, IPositionModel } from '@jupyterlab/codeeditor';
11
11
  import { PageConfig } from '@jupyterlab/coreutils';
12
+ import { IEditorExtensionRegistry, IEditorLanguageRegistry } from '@jupyterlab/codemirror';
13
+ import { ICompletionProviderManager } from '@jupyterlab/completer';
12
14
  import { IDocumentManager } from '@jupyterlab/docmanager';
13
15
  import { ToolbarItems as DocToolbarItems } from '@jupyterlab/docmanager-extension';
14
- import { IFileBrowserFactory } from '@jupyterlab/filebrowser';
16
+ import { ISearchProviderRegistry } from '@jupyterlab/documentsearch';
17
+ import { IDefaultFileBrowser } from '@jupyterlab/filebrowser';
15
18
  import { ILauncher } from '@jupyterlab/launcher';
19
+ import { ILSPCodeExtractorsManager, ILSPDocumentConnectionManager, ILSPFeatureManager } from '@jupyterlab/lsp';
16
20
  import { IMainMenu } from '@jupyterlab/mainmenu';
17
- import { CommandEditStatus, ExecutionIndicator, INotebookTools, INotebookTracker, INotebookWidgetFactory, NotebookActions, NotebookModelFactory, NotebookPanel, NotebookTools, NotebookTracker, NotebookTrustStatus, NotebookWidgetFactory, StaticNotebook, ToolbarItems } from '@jupyterlab/notebook';
21
+ import { IMetadataFormProvider } from '@jupyterlab/metadataform';
22
+ import { CommandEditStatus, ExecutionIndicator, INotebookTools, INotebookTracker, INotebookWidgetFactory, NotebookActions, NotebookAdapter, NotebookModelFactory, NotebookPanel, NotebookSearchProvider, NotebookToCFactory, NotebookTools, NotebookTracker, NotebookTrustStatus, NotebookWidgetFactory, StaticNotebook, ToolbarItems } from '@jupyterlab/notebook';
18
23
  import { IPropertyInspectorProvider } from '@jupyterlab/property-inspector';
19
- import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
24
+ import { IMarkdownParser, IRenderMimeRegistry } from '@jupyterlab/rendermime';
20
25
  import { ISettingRegistry } from '@jupyterlab/settingregistry';
21
26
  import { IStateDB } from '@jupyterlab/statedb';
22
27
  import { IStatusBar } from '@jupyterlab/statusbar';
28
+ import { ITableOfContentsRegistry } from '@jupyterlab/toc';
23
29
  import { ITranslator, nullTranslator } from '@jupyterlab/translation';
24
- import { addAboveIcon, addBelowIcon, buildIcon, copyIcon, cutIcon, duplicateIcon, moveDownIcon, moveUpIcon, notebookIcon, pasteIcon } from '@jupyterlab/ui-components';
25
- import { ICompletionProviderManager } from '@jupyterlab/completer';
30
+ import { addAboveIcon, addBelowIcon, buildIcon, copyIcon, cutIcon, duplicateIcon, fastForwardIcon, IFormRendererRegistry, moveDownIcon, moveUpIcon, notebookIcon, pasteIcon } from '@jupyterlab/ui-components';
26
31
  import { ArrayExt } from '@lumino/algorithm';
27
32
  import { JSONExt, UUID } from '@lumino/coreutils';
28
33
  import { DisposableSet } from '@lumino/disposable';
29
34
  import { MessageLoop } from '@lumino/messaging';
30
35
  import { Panel } from '@lumino/widgets';
31
36
  import { logNotebookOutput } from './nboutput';
37
+ import { ActiveCellTool } from './tool-widgets/activeCellToolWidget';
38
+ import { CellMetadataField, NotebookMetadataField } from './tool-widgets/metadataEditorFields';
32
39
  /**
33
40
  * The command IDs used by the notebook plugin.
34
41
  */
@@ -123,6 +130,7 @@ var CommandIDs;
123
130
  CommandIDs.copyToClipboard = 'notebook:copy-to-clipboard';
124
131
  CommandIDs.invokeCompleter = 'completer:invoke-notebook';
125
132
  CommandIDs.selectCompleter = 'completer:select-notebook';
133
+ CommandIDs.tocRunCells = 'toc:run-cells';
126
134
  })(CommandIDs || (CommandIDs = {}));
127
135
  /**
128
136
  * The name of the factory that creates notebooks.
@@ -147,15 +155,18 @@ const SIDE_BY_SIDE_STYLE_ID = 'jp-NotebookExtension-sideBySideMargins';
147
155
  const trackerPlugin = {
148
156
  id: '@jupyterlab/notebook-extension:tracker',
149
157
  provides: INotebookTracker,
150
- requires: [INotebookWidgetFactory, ITranslator],
158
+ requires: [INotebookWidgetFactory, IEditorExtensionRegistry],
151
159
  optional: [
152
160
  ICommandPalette,
153
- IFileBrowserFactory,
161
+ IDefaultFileBrowser,
154
162
  ILauncher,
155
163
  ILayoutRestorer,
156
164
  IMainMenu,
165
+ IRouter,
157
166
  ISettingRegistry,
158
- ISessionContextDialogs
167
+ ISessionContextDialogs,
168
+ ITranslator,
169
+ IFormRendererRegistry
159
170
  ],
160
171
  activate: activateNotebookHandler,
161
172
  autoStart: true
@@ -181,7 +192,13 @@ const tools = {
181
192
  provides: INotebookTools,
182
193
  id: '@jupyterlab/notebook-extension:tools',
183
194
  autoStart: true,
184
- requires: [INotebookTracker, IEditorServices, IStateDB, ITranslator],
195
+ requires: [
196
+ INotebookTracker,
197
+ IEditorServices,
198
+ IEditorLanguageRegistry,
199
+ IStateDB,
200
+ ITranslator
201
+ ],
185
202
  optional: [IPropertyInspectorProvider]
186
203
  };
187
204
  /**
@@ -311,6 +328,9 @@ export const exportPlugin = {
311
328
  };
312
329
  commands.addCommand(CommandIDs.exportToFormat, {
313
330
  label: args => {
331
+ if (args.label === undefined) {
332
+ return trans.__('Save and Export Notebook to the given `format`.');
333
+ }
314
334
  const formatLabel = args['label'];
315
335
  return args['isPalette']
316
336
  ? trans.__('Save and Export Notebook: %1', formatLabel)
@@ -348,43 +368,53 @@ export const exportPlugin = {
348
368
  ((_a = item.submenu) === null || _a === void 0 ? void 0 : _a.id) === 'jp-mainmenu-file-notebookexport';
349
369
  })) === null || _a === void 0 ? void 0 : _a.submenu;
350
370
  }
351
- void services.nbconvert.getExportFormats().then(response => {
352
- if (response) {
353
- const formatLabels = Private.getFormatLabels(translator);
354
- // Convert export list to palette and menu items.
355
- const formatList = Object.keys(response);
356
- formatList.forEach(function (key) {
357
- const capCaseKey = trans.__(key[0].toUpperCase() + key.substr(1));
358
- const labelStr = formatLabels[key] ? formatLabels[key] : capCaseKey;
359
- let args = {
360
- format: key,
361
- label: labelStr,
362
- isPalette: false
363
- };
364
- if (FORMAT_EXCLUDE.indexOf(key) === -1) {
365
- if (exportTo) {
366
- exportTo.addItem({
367
- command: CommandIDs.exportToFormat,
368
- args: args
369
- });
370
- }
371
- if (palette) {
372
- args = {
373
- format: key,
374
- label: labelStr,
375
- isPalette: true
376
- };
377
- const category = trans.__('Notebook Operations');
378
- palette.addItem({
379
- command: CommandIDs.exportToFormat,
380
- category,
381
- args
382
- });
383
- }
384
- }
385
- });
371
+ let formatsInitialized = false;
372
+ /** Request formats only when a notebook might use them. */
373
+ const maybeInitializeFormats = async () => {
374
+ if (formatsInitialized) {
375
+ return;
386
376
  }
387
- });
377
+ tracker.widgetAdded.disconnect(maybeInitializeFormats);
378
+ formatsInitialized = true;
379
+ const response = await services.nbconvert.getExportFormats(false);
380
+ if (!response) {
381
+ return;
382
+ }
383
+ const formatLabels = Private.getFormatLabels(translator);
384
+ // Convert export list to palette and menu items.
385
+ const formatList = Object.keys(response);
386
+ formatList.forEach(function (key) {
387
+ const capCaseKey = trans.__(key[0].toUpperCase() + key.substr(1));
388
+ const labelStr = formatLabels[key] ? formatLabels[key] : capCaseKey;
389
+ let args = {
390
+ format: key,
391
+ label: labelStr,
392
+ isPalette: false
393
+ };
394
+ if (FORMAT_EXCLUDE.indexOf(key) === -1) {
395
+ if (exportTo) {
396
+ exportTo.addItem({
397
+ command: CommandIDs.exportToFormat,
398
+ args: args
399
+ });
400
+ }
401
+ if (palette) {
402
+ args = {
403
+ format: key,
404
+ label: labelStr,
405
+ isPalette: true
406
+ };
407
+ const category = trans.__('Notebook Operations');
408
+ palette.addItem({
409
+ command: CommandIDs.exportToFormat,
410
+ category,
411
+ args
412
+ });
413
+ }
414
+ }
415
+ });
416
+ };
417
+ tracker.widgetAdded.connect(maybeInitializeFormats);
388
418
  }
389
419
  };
390
420
  /**
@@ -427,11 +457,9 @@ const widgetFactoryPlugin = {
427
457
  NotebookPanel.IContentFactory,
428
458
  IEditorServices,
429
459
  IRenderMimeRegistry,
430
- ISessionContextDialogs,
431
- IToolbarWidgetRegistry,
432
- ITranslator
460
+ IToolbarWidgetRegistry
433
461
  ],
434
- optional: [ISettingRegistry],
462
+ optional: [ISettingRegistry, ISessionContextDialogs, ITranslator],
435
463
  activate: activateWidgetFactory,
436
464
  autoStart: true
437
465
  };
@@ -488,20 +516,29 @@ const lineColStatus = {
488
516
  id: '@jupyterlab/notebook-extension:cursor-position',
489
517
  activate: (app, tracker, positionModel) => {
490
518
  let previousWidget = null;
491
- const provider = (widget) => {
492
- var _a, _b, _c, _d;
519
+ const provider = async (widget) => {
493
520
  let editor = null;
494
521
  if (widget !== previousWidget) {
495
522
  previousWidget === null || previousWidget === void 0 ? void 0 : previousWidget.content.activeCellChanged.disconnect(positionModel.update);
496
523
  previousWidget = null;
497
524
  if (widget && tracker.has(widget)) {
498
525
  widget.content.activeCellChanged.connect(positionModel.update);
499
- editor = (_b = (_a = widget.content.activeCell) === null || _a === void 0 ? void 0 : _a.editor) !== null && _b !== void 0 ? _b : null;
526
+ const activeCell = widget.content.activeCell;
527
+ editor = null;
528
+ if (activeCell) {
529
+ await activeCell.ready;
530
+ editor = activeCell.editor;
531
+ }
500
532
  previousWidget = widget;
501
533
  }
502
534
  }
503
535
  else if (widget) {
504
- editor = (_d = (_c = widget.content.activeCell) === null || _c === void 0 ? void 0 : _c.editor) !== null && _d !== void 0 ? _d : null;
536
+ const activeCell = widget.content.activeCell;
537
+ editor = null;
538
+ if (activeCell) {
539
+ await activeCell.ready;
540
+ editor = activeCell.editor;
541
+ }
505
542
  }
506
543
  return editor;
507
544
  };
@@ -513,10 +550,147 @@ const lineColStatus = {
513
550
  const completerPlugin = {
514
551
  id: '@jupyterlab/notebook-extension:completer',
515
552
  requires: [INotebookTracker],
516
- optional: [ICompletionProviderManager],
553
+ optional: [ICompletionProviderManager, ITranslator, ISanitizer],
517
554
  activate: activateNotebookCompleterService,
518
555
  autoStart: true
519
556
  };
557
+ /**
558
+ * A plugin to search notebook documents
559
+ */
560
+ const searchProvider = {
561
+ id: '@jupyterlab/notebook-extension:search',
562
+ requires: [ISearchProviderRegistry],
563
+ autoStart: true,
564
+ activate: (app, registry) => {
565
+ registry.add('jp-notebookSearchProvider', NotebookSearchProvider);
566
+ }
567
+ };
568
+ const tocPlugin = {
569
+ id: '@jupyterlab/notebook-extension:toc',
570
+ requires: [INotebookTracker, ITableOfContentsRegistry, ISanitizer],
571
+ optional: [IMarkdownParser],
572
+ autoStart: true,
573
+ activate: (app, tracker, tocRegistry, sanitizer, mdParser) => {
574
+ tocRegistry.add(new NotebookToCFactory(tracker, mdParser, sanitizer));
575
+ }
576
+ };
577
+ const languageServerPlugin = {
578
+ id: '@jupyterlab/notebook-extension:language-server',
579
+ requires: [
580
+ INotebookTracker,
581
+ ILSPDocumentConnectionManager,
582
+ ILSPFeatureManager,
583
+ ILSPCodeExtractorsManager
584
+ ],
585
+ activate: activateNotebookLanguageServer,
586
+ autoStart: true
587
+ };
588
+ const updateRawMimetype = {
589
+ id: '@jupyterlab/notebook-extension:update-raw-mimetype',
590
+ autoStart: true,
591
+ requires: [INotebookTracker, IMetadataFormProvider, ITranslator],
592
+ activate: (app, tracker, metadataForms, translator) => {
593
+ const trans = translator.load('jupyterlab');
594
+ let formatsInitialized = false;
595
+ async function maybeInitializeFormats() {
596
+ if (formatsInitialized) {
597
+ return;
598
+ }
599
+ if (!metadataForms.get('commonToolsSection')) {
600
+ return;
601
+ }
602
+ const properties = metadataForms
603
+ .get('commonToolsSection')
604
+ .getProperties('/raw_mimetype');
605
+ if (!properties) {
606
+ return;
607
+ }
608
+ tracker.widgetAdded.disconnect(maybeInitializeFormats);
609
+ formatsInitialized = true;
610
+ const services = app.serviceManager;
611
+ const response = await services.nbconvert.getExportFormats(false);
612
+ if (!response) {
613
+ return;
614
+ }
615
+ // convert exportList to palette and menu items
616
+ const formatList = Object.keys(response);
617
+ const formatLabels = Private.getFormatLabels(translator);
618
+ formatList.forEach(function (key) {
619
+ var _a;
620
+ const mimetypeExists = ((_a = properties.oneOf) === null || _a === void 0 ? void 0 : _a.filter(value => value.const === key).length) > 0;
621
+ if (!mimetypeExists) {
622
+ const altOption = trans.__(key[0].toUpperCase() + key.substr(1));
623
+ const option = formatLabels[key] ? formatLabels[key] : altOption;
624
+ const mimeTypeValue = response[key].output_mimetype;
625
+ properties.oneOf.push({
626
+ const: mimeTypeValue,
627
+ title: option
628
+ });
629
+ }
630
+ });
631
+ metadataForms
632
+ .get('commonToolsSection')
633
+ .setProperties('/raw_mimetype', properties);
634
+ }
635
+ tracker.widgetAdded.connect(maybeInitializeFormats);
636
+ }
637
+ };
638
+ /**
639
+ * Registering metadata editor fields.
640
+ */
641
+ const customMetadataEditorFields = {
642
+ id: '@jupyterlab/notebook-extension:metadata-editor',
643
+ autoStart: true,
644
+ requires: [INotebookTracker, IEditorServices, IFormRendererRegistry],
645
+ optional: [ITranslator],
646
+ activate: (app, tracker, editorServices, formRegistry, translator) => {
647
+ const editorFactory = options => editorServices.factoryService.newInlineEditor(options);
648
+ // Register the custom fields.
649
+ const cellComponent = {
650
+ fieldRenderer: (props) => {
651
+ return new CellMetadataField({
652
+ editorFactory,
653
+ tracker,
654
+ label: 'Cell metadata',
655
+ translator: translator
656
+ }).render(props);
657
+ }
658
+ };
659
+ formRegistry.addRenderer('notebook-extension:metadata-editor.cell-metadata', cellComponent);
660
+ const notebookComponent = {
661
+ fieldRenderer: (props) => {
662
+ return new NotebookMetadataField({
663
+ editorFactory,
664
+ tracker,
665
+ label: 'Notebook metadata',
666
+ translator: translator
667
+ }).render(props);
668
+ }
669
+ };
670
+ formRegistry.addRenderer('notebook-extension:metadata-editor.notebook-metadata', notebookComponent);
671
+ }
672
+ };
673
+ /**
674
+ * Registering active cell field.
675
+ */
676
+ const activeCellTool = {
677
+ id: '@jupyterlab/notebook-extension:active-cell-tool',
678
+ autoStart: true,
679
+ requires: [INotebookTracker, IFormRendererRegistry, IEditorLanguageRegistry],
680
+ activate: (
681
+ // Register the custom field.
682
+ app, tracker, formRegistry, languages) => {
683
+ const component = {
684
+ fieldRenderer: (props) => {
685
+ return new ActiveCellTool({
686
+ tracker,
687
+ languages
688
+ }).render(props);
689
+ }
690
+ };
691
+ formRegistry.addRenderer('notebook-extension:active-cell-tool.renderer', component);
692
+ }
693
+ };
520
694
  /**
521
695
  * Export the plugins as default.
522
696
  */
@@ -535,30 +709,22 @@ const plugins = [
535
709
  copyOutputPlugin,
536
710
  kernelStatus,
537
711
  lineColStatus,
538
- completerPlugin
712
+ completerPlugin,
713
+ searchProvider,
714
+ tocPlugin,
715
+ languageServerPlugin,
716
+ updateRawMimetype,
717
+ customMetadataEditorFields,
718
+ activeCellTool
539
719
  ];
540
720
  export default plugins;
541
721
  /**
542
722
  * Activate the notebook tools extension.
543
723
  */
544
- function activateNotebookTools(app, tracker, editorServices, state, translator, inspectorProvider) {
724
+ function activateNotebookTools(app, tracker, editorServices, languages, state, translator, inspectorProvider) {
545
725
  const trans = translator.load('jupyterlab');
546
726
  const id = 'notebook-tools';
547
727
  const notebookTools = new NotebookTools({ tracker, translator });
548
- const activeCellTool = new NotebookTools.ActiveCellTool();
549
- const editable = NotebookTools.createEditableToggle(translator);
550
- const slideShow = NotebookTools.createSlideShowSelector(translator);
551
- const editorFactory = editorServices.factoryService.newInlineEditor;
552
- const cellMetadataEditor = new NotebookTools.CellMetadataEditorTool({
553
- editorFactory,
554
- collapsed: false,
555
- translator
556
- });
557
- const notebookMetadataEditor = new NotebookTools.NotebookMetadataEditorTool({
558
- editorFactory,
559
- translator
560
- });
561
- const services = app.serviceManager;
562
728
  // Create message hook for triggers to save to the database.
563
729
  const hook = (sender, message) => {
564
730
  switch (message.type) {
@@ -574,59 +740,9 @@ function activateNotebookTools(app, tracker, editorServices, state, translator,
574
740
  }
575
741
  return true;
576
742
  };
577
- const optionsMap = {};
578
- optionsMap.None = null;
579
- void services.nbconvert.getExportFormats().then(response => {
580
- if (response) {
581
- /**
582
- * The excluded Cell Inspector Raw NbConvert Formats
583
- * (returned from nbconvert's export list)
584
- */
585
- const rawFormatExclude = [
586
- 'pdf',
587
- 'slides',
588
- 'script',
589
- 'notebook',
590
- 'custom'
591
- ];
592
- let optionValueArray = [
593
- [trans.__('PDF'), 'pdf'],
594
- [trans.__('Slides'), 'slides'],
595
- [trans.__('Script'), 'script'],
596
- [trans.__('Notebook'), 'notebook'],
597
- [trans.__('Custom'), 'custom']
598
- ];
599
- // convert exportList to palette and menu items
600
- const formatList = Object.keys(response);
601
- const formatLabels = Private.getFormatLabels(translator);
602
- formatList.forEach(function (key) {
603
- if (rawFormatExclude.indexOf(key) === -1) {
604
- const altOption = trans.__(key[0].toUpperCase() + key.substr(1));
605
- const option = formatLabels[key] ? formatLabels[key] : altOption;
606
- const mimeTypeValue = response[key].output_mimetype;
607
- optionValueArray.push([option, mimeTypeValue]);
608
- }
609
- });
610
- const nbConvert = NotebookTools.createNBConvertSelector(optionValueArray, translator);
611
- notebookTools.addItem({ tool: nbConvert, section: 'common', rank: 3 });
612
- }
613
- });
614
743
  notebookTools.title.icon = buildIcon;
615
744
  notebookTools.title.caption = trans.__('Notebook Tools');
616
745
  notebookTools.id = id;
617
- notebookTools.addItem({ tool: activeCellTool, section: 'common', rank: 1 });
618
- notebookTools.addItem({ tool: editable, section: 'common', rank: 2 });
619
- notebookTools.addItem({ tool: slideShow, section: 'common', rank: 3 });
620
- notebookTools.addItem({
621
- tool: cellMetadataEditor,
622
- section: 'advanced',
623
- rank: 1
624
- });
625
- notebookTools.addItem({
626
- tool: notebookMetadataEditor,
627
- section: 'advanced',
628
- rank: 2
629
- });
630
746
  MessageLoop.installMessageHook(notebookTools, hook);
631
747
  if (inspectorProvider) {
632
748
  tracker.widgetAdded.connect((sender, panel) => {
@@ -639,18 +755,27 @@ function activateNotebookTools(app, tracker, editorServices, state, translator,
639
755
  /**
640
756
  * Activate the notebook widget factory.
641
757
  */
642
- function activateWidgetFactory(app, contentFactory, editorServices, rendermime, sessionContextDialogs, toolbarRegistry, translator, settingRegistry) {
758
+ function activateWidgetFactory(app, contentFactory, editorServices, rendermime, toolbarRegistry, settingRegistry, sessionContextDialogs_, translator_) {
759
+ const translator = translator_ !== null && translator_ !== void 0 ? translator_ : nullTranslator;
760
+ const sessionContextDialogs = sessionContextDialogs_ !== null && sessionContextDialogs_ !== void 0 ? sessionContextDialogs_ : new SessionContextDialogs({ translator });
643
761
  const preferKernelOption = PageConfig.getOption('notebookStartsKernel');
644
762
  // If the option is not set, assume `true`
645
763
  const preferKernelValue = preferKernelOption === '' || preferKernelOption.toLowerCase() === 'true';
646
764
  const { commands } = app;
647
765
  let toolbarFactory;
648
766
  // Register notebook toolbar widgets
649
- toolbarRegistry.registerFactory(FACTORY, 'save', panel => DocToolbarItems.createSaveButton(commands, panel.context.fileChanged));
650
- toolbarRegistry.registerFactory(FACTORY, 'cellType', panel => ToolbarItems.createCellTypeItem(panel, translator));
651
- toolbarRegistry.registerFactory(FACTORY, 'kernelName', panel => Toolbar.createKernelNameItem(panel.sessionContext, sessionContextDialogs, translator));
652
- toolbarRegistry.registerFactory(FACTORY, 'executionProgress', panel => {
653
- return ExecutionIndicator.createExecutionIndicatorItem(panel, translator, settingRegistry === null || settingRegistry === void 0 ? void 0 : settingRegistry.load(trackerPlugin.id));
767
+ toolbarRegistry.addFactory(FACTORY, 'save', panel => DocToolbarItems.createSaveButton(commands, panel.context.fileChanged));
768
+ toolbarRegistry.addFactory(FACTORY, 'cellType', panel => ToolbarItems.createCellTypeItem(panel, translator));
769
+ toolbarRegistry.addFactory(FACTORY, 'kernelName', panel => Toolbar.createKernelNameItem(panel.sessionContext, sessionContextDialogs, translator));
770
+ toolbarRegistry.addFactory(FACTORY, 'executionProgress', panel => {
771
+ const loadingSettings = settingRegistry === null || settingRegistry === void 0 ? void 0 : settingRegistry.load(trackerPlugin.id);
772
+ const indicator = ExecutionIndicator.createExecutionIndicatorItem(panel, translator, loadingSettings);
773
+ void (loadingSettings === null || loadingSettings === void 0 ? void 0 : loadingSettings.then(settings => {
774
+ panel.disposed.connect(() => {
775
+ settings.dispose();
776
+ });
777
+ }));
778
+ return indicator;
654
779
  });
655
780
  if (settingRegistry) {
656
781
  // Create the factory
@@ -670,9 +795,8 @@ function activateWidgetFactory(app, contentFactory, editorServices, rendermime,
670
795
  editorConfig: StaticNotebook.defaultEditorConfig,
671
796
  notebookConfig: StaticNotebook.defaultNotebookConfig,
672
797
  mimeTypeService: editorServices.mimeTypeService,
673
- sessionDialogs: sessionContextDialogs,
674
798
  toolbarFactory,
675
- translator: translator
799
+ translator
676
800
  });
677
801
  app.docRegistry.addWidgetFactory(factory);
678
802
  return factory;
@@ -734,7 +858,8 @@ function activateClonedOutputs(app, docManager, notebookTracker, translator, res
734
858
  const widget = new MainAreaWidget({ content });
735
859
  current.context.addSibling(widget, {
736
860
  ref: current.id,
737
- mode: 'split-bottom'
861
+ mode: 'split-bottom',
862
+ type: 'Cloned Output'
738
863
  });
739
864
  const updateCloned = () => {
740
865
  void clonedOutputs.save(widget);
@@ -784,7 +909,7 @@ function activateCodeConsole(app, tracker, translator) {
784
909
  }
785
910
  const { context, content } = current;
786
911
  const cell = content.activeCell;
787
- const metadata = cell === null || cell === void 0 ? void 0 : cell.model.metadata.toJSON();
912
+ const metadata = cell === null || cell === void 0 ? void 0 : cell.model.metadata;
788
913
  const path = context.path;
789
914
  // ignore action in non-code cell
790
915
  if (!cell || cell.model.type !== 'code') {
@@ -792,6 +917,9 @@ function activateCodeConsole(app, tracker, translator) {
792
917
  }
793
918
  let code;
794
919
  const editor = cell.editor;
920
+ if (!editor) {
921
+ return;
922
+ }
795
923
  const selection = editor.getSelection();
796
924
  const { start, end } = selection;
797
925
  const selected = start.column !== end.column || start.line !== end.line;
@@ -799,12 +927,12 @@ function activateCodeConsole(app, tracker, translator) {
799
927
  // Get the selected code from the editor.
800
928
  const start = editor.getOffsetAt(selection.start);
801
929
  const end = editor.getOffsetAt(selection.end);
802
- code = editor.model.value.text.substring(start, end);
930
+ code = editor.model.sharedModel.getSource().substring(start, end);
803
931
  }
804
932
  else {
805
933
  // no selection, find the complete statement around the current line
806
934
  const cursor = editor.getCursorPosition();
807
- const srcLines = editor.model.value.text.split('\n');
935
+ const srcLines = editor.model.sharedModel.getSource().split('\n');
808
936
  let curLine = selection.start.line;
809
937
  while (curLine < editor.lineCount &&
810
938
  !srcLines[curLine].replace(/\s/g, '').length) {
@@ -939,14 +1067,24 @@ function activateCopyOutput(app, translator, tracker) {
939
1067
  /**
940
1068
  * Activate the notebook handler extension.
941
1069
  */
942
- function activateNotebookHandler(app, factory, translator, palette, browserFactory, launcher, restorer, mainMenu, settingRegistry, sessionDialogs) {
1070
+ function activateNotebookHandler(app, factory, extensions, palette, defaultBrowser, launcher, restorer, mainMenu, router, settingRegistry, sessionDialogs_, translator_, formRegistry) {
1071
+ const translator = translator_ !== null && translator_ !== void 0 ? translator_ : nullTranslator;
1072
+ const sessionDialogs = sessionDialogs_ !== null && sessionDialogs_ !== void 0 ? sessionDialogs_ : new SessionContextDialogs({ translator });
943
1073
  const trans = translator.load('jupyterlab');
944
1074
  const services = app.serviceManager;
945
1075
  const { commands, shell } = app;
946
1076
  const tracker = new NotebookTracker({ namespace: 'notebook' });
1077
+ // Use the router to deal with hash navigation
1078
+ function onRouted(router, location) {
1079
+ if (location.hash && tracker.currentWidget) {
1080
+ tracker.currentWidget.setFragment(location.hash);
1081
+ }
1082
+ }
1083
+ router === null || router === void 0 ? void 0 : router.routed.connect(onRouted);
947
1084
  const isEnabled = () => {
948
1085
  return Private.isEnabled(shell, tracker);
949
1086
  };
1087
+ const setSideBySideOutputRatio = (sideBySideOutputRatio) => document.documentElement.style.setProperty('--jp-side-by-side-output-size', `${sideBySideOutputRatio}fr`);
950
1088
  // Fetch settings if possible.
951
1089
  const fetchSettings = settingRegistry
952
1090
  ? settingRegistry.load(trackerPlugin.id)
@@ -957,6 +1095,38 @@ function activateNotebookHandler(app, factory, translator, palette, browserFacto
957
1095
  settings.changed.connect(() => {
958
1096
  updateConfig(settings);
959
1097
  });
1098
+ const updateSessionSettings = (session, changes) => {
1099
+ const { newValue, oldValue } = changes;
1100
+ const autoStartDefault = newValue.autoStartDefault;
1101
+ if (typeof autoStartDefault === 'boolean' &&
1102
+ autoStartDefault !== oldValue.autoStartDefault) {
1103
+ // Ensure we break the cycle
1104
+ if (autoStartDefault !==
1105
+ settings.get('autoStartDefaultKernel').composite)
1106
+ // Once the settings is changed `updateConfig` will take care
1107
+ // of the propagation to existing session context.
1108
+ settings
1109
+ .set('autoStartDefaultKernel', autoStartDefault)
1110
+ .catch(reason => {
1111
+ console.error(`Failed to set ${settings.id}.autoStartDefaultKernel`);
1112
+ });
1113
+ }
1114
+ };
1115
+ const sessionContexts = new WeakSet();
1116
+ const listenToKernelPreference = (panel) => {
1117
+ const session = panel.context.sessionContext;
1118
+ if (!session.isDisposed && !sessionContexts.has(session)) {
1119
+ sessionContexts.add(session);
1120
+ session.kernelPreferenceChanged.connect(updateSessionSettings);
1121
+ session.disposed.connect(() => {
1122
+ session.kernelPreferenceChanged.disconnect(updateSessionSettings);
1123
+ });
1124
+ }
1125
+ };
1126
+ tracker.forEach(listenToKernelPreference);
1127
+ tracker.widgetAdded.connect((tracker, panel) => {
1128
+ listenToKernelPreference(panel);
1129
+ });
960
1130
  commands.addCommand(CommandIDs.autoClosingBrackets, {
961
1131
  execute: args => {
962
1132
  var _a;
@@ -980,7 +1150,26 @@ function activateNotebookHandler(app, factory, translator, palette, browserFacto
980
1150
  void settings.set('rawCellConfig', rawConfig);
981
1151
  },
982
1152
  label: trans.__('Auto Close Brackets for All Notebook Cell Types'),
983
- isToggled: () => ['codeCellConfig', 'markdownCellConfig', 'rawCellConfig'].some(x => settings.get(x).composite.autoClosingBrackets)
1153
+ isToggled: () => ['codeCellConfig', 'markdownCellConfig', 'rawCellConfig'].some(x => {
1154
+ var _a;
1155
+ return ((_a = settings.get(x).composite.autoClosingBrackets) !== null && _a !== void 0 ? _a : extensions.baseConfiguration['autoClosingBrackets']) === true;
1156
+ })
1157
+ });
1158
+ commands.addCommand(CommandIDs.setSideBySideRatio, {
1159
+ label: trans.__('Set side-by-side ratio'),
1160
+ execute: args => {
1161
+ InputDialog.getNumber({
1162
+ title: trans.__('Width of the output in side-by-side mode'),
1163
+ value: settings.get('sideBySideOutputRatio').composite
1164
+ })
1165
+ .then(result => {
1166
+ setSideBySideOutputRatio(result.value);
1167
+ if (result.value) {
1168
+ void settings.set('sideBySideOutputRatio', result.value);
1169
+ }
1170
+ })
1171
+ .catch(console.error);
1172
+ }
984
1173
  });
985
1174
  })
986
1175
  .catch((reason) => {
@@ -988,9 +1177,18 @@ function activateNotebookHandler(app, factory, translator, palette, browserFacto
988
1177
  updateTracker({
989
1178
  editorConfig: factory.editorConfig,
990
1179
  notebookConfig: factory.notebookConfig,
991
- kernelShutdown: factory.shutdownOnClose
1180
+ kernelShutdown: factory.shutdownOnClose,
1181
+ autoStartDefault: factory.autoStartDefault
992
1182
  });
993
1183
  });
1184
+ if (formRegistry) {
1185
+ const CMRenderer = formRegistry.getRenderer('@jupyterlab/codemirror-extension:plugin.defaultConfig');
1186
+ if (CMRenderer) {
1187
+ formRegistry.addRenderer('@jupyterlab/notebook-extension:tracker.codeCellConfig', CMRenderer);
1188
+ formRegistry.addRenderer('@jupyterlab/notebook-extension:tracker.markdownCellConfig', CMRenderer);
1189
+ formRegistry.addRenderer('@jupyterlab/notebook-extension:tracker.rawCellConfig', CMRenderer);
1190
+ }
1191
+ }
994
1192
  // Handle state restoration.
995
1193
  if (restorer) {
996
1194
  void restorer.restore(tracker, {
@@ -1002,7 +1200,8 @@ function activateNotebookHandler(app, factory, translator, palette, browserFacto
1002
1200
  }
1003
1201
  const registry = app.docRegistry;
1004
1202
  const modelFactory = new NotebookModelFactory({
1005
- disableDocumentWideUndoRedo: factory.notebookConfig.disableDocumentWideUndoRedo
1203
+ disableDocumentWideUndoRedo: factory.notebookConfig.disableDocumentWideUndoRedo,
1204
+ collaborative: true
1006
1205
  });
1007
1206
  registry.addModelFactory(modelFactory);
1008
1207
  addCommands(app, tracker, translator, sessionDialogs, isEnabled);
@@ -1038,9 +1237,18 @@ function activateNotebookHandler(app, factory, translator, palette, browserFacto
1038
1237
  * Update the setting values.
1039
1238
  */
1040
1239
  function updateConfig(settings) {
1041
- const code = Object.assign(Object.assign({}, StaticNotebook.defaultEditorConfig.code), settings.get('codeCellConfig').composite);
1042
- const markdown = Object.assign(Object.assign({}, StaticNotebook.defaultEditorConfig.markdown), settings.get('markdownCellConfig').composite);
1043
- const raw = Object.assign(Object.assign({}, StaticNotebook.defaultEditorConfig.raw), settings.get('rawCellConfig').composite);
1240
+ const code = {
1241
+ ...StaticNotebook.defaultEditorConfig.code,
1242
+ ...settings.get('codeCellConfig').composite
1243
+ };
1244
+ const markdown = {
1245
+ ...StaticNotebook.defaultEditorConfig.markdown,
1246
+ ...settings.get('markdownCellConfig').composite
1247
+ };
1248
+ const raw = {
1249
+ ...StaticNotebook.defaultEditorConfig.raw,
1250
+ ...settings.get('rawCellConfig').composite
1251
+ };
1044
1252
  factory.editorConfig = { code, markdown, raw };
1045
1253
  factory.notebookConfig = {
1046
1254
  showHiddenCellsButton: settings.get('showHiddenCellsButton')
@@ -1048,21 +1256,21 @@ function activateNotebookHandler(app, factory, translator, palette, browserFacto
1048
1256
  scrollPastEnd: settings.get('scrollPastEnd').composite,
1049
1257
  defaultCell: settings.get('defaultCell').composite,
1050
1258
  recordTiming: settings.get('recordTiming').composite,
1051
- numberCellsToRenderDirectly: settings.get('numberCellsToRenderDirectly')
1052
- .composite,
1053
- remainingTimeBeforeRescheduling: settings.get('remainingTimeBeforeRescheduling').composite,
1054
- renderCellOnIdle: settings.get('renderCellOnIdle').composite,
1055
- observedTopMargin: settings.get('observedTopMargin').composite,
1056
- observedBottomMargin: settings.get('observedBottomMargin')
1057
- .composite,
1259
+ overscanCount: settings.get('overscanCount').composite,
1260
+ inputHistoryScope: settings.get('inputHistoryScope').composite,
1058
1261
  maxNumberOutputs: settings.get('maxNumberOutputs').composite,
1059
1262
  showEditorForReadOnlyMarkdown: settings.get('showEditorForReadOnlyMarkdown').composite,
1060
- disableDocumentWideUndoRedo: settings.get('experimentalDisableDocumentWideUndoRedo').composite,
1263
+ disableDocumentWideUndoRedo: !settings.get('documentWideUndoRedo')
1264
+ .composite,
1061
1265
  renderingLayout: settings.get('renderingLayout').composite,
1062
1266
  sideBySideLeftMarginOverride: settings.get('sideBySideLeftMarginOverride')
1063
1267
  .composite,
1064
- sideBySideRightMarginOverride: settings.get('sideBySideRightMarginOverride').composite
1268
+ sideBySideRightMarginOverride: settings.get('sideBySideRightMarginOverride').composite,
1269
+ sideBySideOutputRatio: settings.get('sideBySideOutputRatio')
1270
+ .composite,
1271
+ windowingMode: settings.get('windowingMode').composite
1065
1272
  };
1273
+ setSideBySideOutputRatio(factory.notebookConfig.sideBySideOutputRatio);
1066
1274
  const sideBySideMarginStyle = `.jp-mod-sideBySide.jp-Notebook .jp-Notebook-cell {
1067
1275
  margin-left: ${factory.notebookConfig.sideBySideLeftMarginOverride} !important;
1068
1276
  margin-right: ${factory.notebookConfig.sideBySideRightMarginOverride} !important;`;
@@ -1073,32 +1281,37 @@ function activateNotebookHandler(app, factory, translator, palette, browserFacto
1073
1281
  else {
1074
1282
  document.head.insertAdjacentHTML('beforeend', `<style id="${SIDE_BY_SIDE_STYLE_ID}">${sideBySideMarginStyle}}</style>`);
1075
1283
  }
1284
+ factory.autoStartDefault = settings.get('autoStartDefaultKernel')
1285
+ .composite;
1076
1286
  factory.shutdownOnClose = settings.get('kernelShutdown')
1077
1287
  .composite;
1078
- modelFactory.disableDocumentWideUndoRedo = settings.get('experimentalDisableDocumentWideUndoRedo').composite;
1288
+ modelFactory.disableDocumentWideUndoRedo = !settings.get('documentWideUndoRedo').composite;
1079
1289
  updateTracker({
1080
1290
  editorConfig: factory.editorConfig,
1081
1291
  notebookConfig: factory.notebookConfig,
1082
- kernelShutdown: factory.shutdownOnClose
1292
+ kernelShutdown: factory.shutdownOnClose,
1293
+ autoStartDefault: factory.autoStartDefault
1083
1294
  });
1084
1295
  }
1085
1296
  // Add main menu notebook menu.
1086
1297
  if (mainMenu) {
1087
- populateMenus(mainMenu, tracker, sessionDialogs, isEnabled);
1298
+ populateMenus(mainMenu, isEnabled);
1088
1299
  }
1089
1300
  // Utility function to create a new notebook.
1090
- const createNew = (cwd, kernelName) => {
1091
- return commands
1092
- .execute('docmanager:new-untitled', { path: cwd, type: 'notebook' })
1093
- .then(model => {
1094
- if (model != undefined) {
1095
- return commands.execute('docmanager:open', {
1096
- path: model.path,
1097
- factory: FACTORY,
1098
- kernel: { name: kernelName }
1099
- });
1100
- }
1301
+ const createNew = async (cwd, kernelId, kernelName) => {
1302
+ const model = await commands.execute('docmanager:new-untitled', {
1303
+ path: cwd,
1304
+ type: 'notebook'
1101
1305
  });
1306
+ if (model !== undefined) {
1307
+ const widget = (await commands.execute('docmanager:open', {
1308
+ path: model.path,
1309
+ factory: FACTORY,
1310
+ kernel: { id: kernelId, name: kernelName }
1311
+ }));
1312
+ widget.isUntitled = true;
1313
+ return widget;
1314
+ }
1102
1315
  };
1103
1316
  // Add a command for creating a new notebook.
1104
1317
  commands.addCommand(CommandIDs.createNew, {
@@ -1116,10 +1329,11 @@ function activateNotebookHandler(app, factory, translator, palette, browserFacto
1116
1329
  caption: trans.__('Create a new notebook'),
1117
1330
  icon: args => (args['isPalette'] ? undefined : notebookIcon),
1118
1331
  execute: args => {
1119
- const cwd = args['cwd'] ||
1120
- (browserFactory ? browserFactory.defaultBrowser.model.path : '');
1332
+ var _a;
1333
+ const cwd = args['cwd'] || ((_a = defaultBrowser === null || defaultBrowser === void 0 ? void 0 : defaultBrowser.model.path) !== null && _a !== void 0 ? _a : '');
1334
+ const kernelId = args['kernelId'] || '';
1121
1335
  const kernelName = args['kernelName'] || '';
1122
- return createNew(cwd, kernelName);
1336
+ return createNew(cwd, kernelId, kernelName);
1123
1337
  }
1124
1338
  });
1125
1339
  // Add a launcher item if the launcher is available.
@@ -1139,7 +1353,7 @@ function activateNotebookHandler(app, factory, translator, palette, browserFacto
1139
1353
  for (const name in specs.kernelspecs) {
1140
1354
  const rank = name === specs.default ? 0 : Infinity;
1141
1355
  const spec = specs.kernelspecs[name];
1142
- let kernelIconUrl = spec.resources['logo-64x64'];
1356
+ const kernelIconUrl = spec.resources['logo-svg'] || spec.resources['logo-64x64'];
1143
1357
  disposables.add(launcher.add({
1144
1358
  command: CommandIDs.createNew,
1145
1359
  args: { isLauncher: true, kernelName: name },
@@ -1161,11 +1375,14 @@ function activateNotebookHandler(app, factory, translator, palette, browserFacto
1161
1375
  /**
1162
1376
  * Activate the completer service for notebook.
1163
1377
  */
1164
- function activateNotebookCompleterService(app, notebooks, manager) {
1378
+ function activateNotebookCompleterService(app, notebooks, manager, translator, appSanitizer) {
1165
1379
  if (!manager) {
1166
1380
  return;
1167
1381
  }
1382
+ const trans = (translator !== null && translator !== void 0 ? translator : nullTranslator).load('jupyterlab');
1383
+ const sanitizer = appSanitizer !== null && appSanitizer !== void 0 ? appSanitizer : new Sanitizer();
1168
1384
  app.commands.addCommand(CommandIDs.invokeCompleter, {
1385
+ label: trans.__('Display the completion helper.'),
1169
1386
  execute: args => {
1170
1387
  var _a;
1171
1388
  const panel = notebooks.currentWidget;
@@ -1175,6 +1392,7 @@ function activateNotebookCompleterService(app, notebooks, manager) {
1175
1392
  }
1176
1393
  });
1177
1394
  app.commands.addCommand(CommandIDs.selectCompleter, {
1395
+ label: trans.__('Select the completion suggestion.'),
1178
1396
  execute: () => {
1179
1397
  const id = notebooks.currentWidget && notebooks.currentWidget.id;
1180
1398
  if (id) {
@@ -1192,25 +1410,34 @@ function activateNotebookCompleterService(app, notebooks, manager) {
1192
1410
  const completerContext = {
1193
1411
  editor: (_b = (_a = notebook.content.activeCell) === null || _a === void 0 ? void 0 : _a.editor) !== null && _b !== void 0 ? _b : null,
1194
1412
  session: notebook.sessionContext.session,
1195
- widget: notebook
1413
+ widget: notebook,
1414
+ sanitizer: sanitizer
1196
1415
  };
1197
1416
  await manager.updateCompleter(completerContext);
1198
1417
  notebook.content.activeCellChanged.connect((_, cell) => {
1199
- const newCompleterContext = {
1200
- editor: cell.editor,
1201
- session: notebook.sessionContext.session,
1202
- widget: notebook
1203
- };
1204
- manager.updateCompleter(newCompleterContext).catch(console.error);
1418
+ // Ensure the editor will exist on the cell before adding the completer
1419
+ cell === null || cell === void 0 ? void 0 : cell.ready.then(() => {
1420
+ const newCompleterContext = {
1421
+ editor: cell.editor,
1422
+ session: notebook.sessionContext.session,
1423
+ widget: notebook,
1424
+ sanitizer: sanitizer
1425
+ };
1426
+ return manager.updateCompleter(newCompleterContext);
1427
+ }).catch(console.error);
1205
1428
  });
1206
1429
  notebook.sessionContext.sessionChanged.connect(() => {
1207
- var _a, _b;
1208
- const newCompleterContext = {
1209
- editor: (_b = (_a = notebook.content.activeCell) === null || _a === void 0 ? void 0 : _a.editor) !== null && _b !== void 0 ? _b : null,
1210
- session: notebook.sessionContext.session,
1211
- widget: notebook
1212
- };
1213
- manager.updateCompleter(newCompleterContext).catch(console.error);
1430
+ var _a;
1431
+ // Ensure the editor will exist on the cell before adding the completer
1432
+ (_a = notebook.content.activeCell) === null || _a === void 0 ? void 0 : _a.ready.then(() => {
1433
+ var _a, _b;
1434
+ const newCompleterContext = {
1435
+ editor: (_b = (_a = notebook.content.activeCell) === null || _a === void 0 ? void 0 : _a.editor) !== null && _b !== void 0 ? _b : null,
1436
+ session: notebook.sessionContext.session,
1437
+ widget: notebook
1438
+ };
1439
+ return manager.updateCompleter(newCompleterContext);
1440
+ }).catch(console.error);
1214
1441
  });
1215
1442
  };
1216
1443
  notebooks.widgetAdded.connect(updateCompleter);
@@ -1220,6 +1447,19 @@ function activateNotebookCompleterService(app, notebooks, manager) {
1220
1447
  });
1221
1448
  });
1222
1449
  }
1450
+ /**
1451
+ * Activate the language server for notebook.
1452
+ */
1453
+ function activateNotebookLanguageServer(app, notebooks, connectionManager, featureManager, codeExtractorManager) {
1454
+ notebooks.widgetAdded.connect(async (_, notebook) => {
1455
+ const adapter = new NotebookAdapter(notebook, {
1456
+ connectionManager,
1457
+ featureManager,
1458
+ foreignCodeExtractorsManager: codeExtractorManager
1459
+ });
1460
+ connectionManager.registerAdapter(notebook.context.path, adapter);
1461
+ });
1462
+ }
1223
1463
  // Get the current widget and activate unless the args specify otherwise.
1224
1464
  function getCurrent(tracker, shell, args) {
1225
1465
  const widget = tracker.currentWidget;
@@ -1235,7 +1475,6 @@ function getCurrent(tracker, shell, args) {
1235
1475
  function addCommands(app, tracker, translator, sessionDialogs, isEnabled) {
1236
1476
  const trans = translator.load('jupyterlab');
1237
1477
  const { commands, shell } = app;
1238
- sessionDialogs = sessionDialogs !== null && sessionDialogs !== void 0 ? sessionDialogs : sessionContextDialogs;
1239
1478
  const isEnabledAndSingleSelected = () => {
1240
1479
  return Private.isEnabledAndSingleSelected(shell, tracker);
1241
1480
  };
@@ -1268,46 +1507,83 @@ function addCommands(app, tracker, translator, sessionDialogs, isEnabled) {
1268
1507
  NotebookActions.expandParent(cell, notebook);
1269
1508
  });
1270
1509
  });
1510
+ tracker.selectionChanged.connect(() => {
1511
+ commands.notifyCommandChanged(CommandIDs.duplicateBelow);
1512
+ commands.notifyCommandChanged(CommandIDs.deleteCell);
1513
+ commands.notifyCommandChanged(CommandIDs.copy);
1514
+ commands.notifyCommandChanged(CommandIDs.cut);
1515
+ commands.notifyCommandChanged(CommandIDs.pasteBelow);
1516
+ commands.notifyCommandChanged(CommandIDs.pasteAbove);
1517
+ commands.notifyCommandChanged(CommandIDs.pasteAndReplace);
1518
+ commands.notifyCommandChanged(CommandIDs.moveUp);
1519
+ commands.notifyCommandChanged(CommandIDs.moveDown);
1520
+ commands.notifyCommandChanged(CommandIDs.run);
1521
+ commands.notifyCommandChanged(CommandIDs.runAll);
1522
+ commands.notifyCommandChanged(CommandIDs.runAndAdvance);
1523
+ commands.notifyCommandChanged(CommandIDs.runAndInsert);
1524
+ });
1525
+ tracker.activeCellChanged.connect(() => {
1526
+ commands.notifyCommandChanged(CommandIDs.moveUp);
1527
+ commands.notifyCommandChanged(CommandIDs.moveDown);
1528
+ });
1271
1529
  commands.addCommand(CommandIDs.runAndAdvance, {
1272
- label: trans.__('Run Selected Cells'),
1530
+ label: args => {
1531
+ var _a;
1532
+ const current = getCurrent(tracker, shell, { ...args, activate: false });
1533
+ return trans._n('Run Selected Cell', 'Run Selected Cells', (_a = current === null || current === void 0 ? void 0 : current.content.selectedCells.length) !== null && _a !== void 0 ? _a : 1);
1534
+ },
1535
+ caption: args => {
1536
+ var _a;
1537
+ const current = getCurrent(tracker, shell, { ...args, activate: false });
1538
+ return trans._n('Run this cell and advance', 'Run these %1 cells and advance', (_a = current === null || current === void 0 ? void 0 : current.content.selectedCells.length) !== null && _a !== void 0 ? _a : 1);
1539
+ },
1273
1540
  execute: args => {
1274
1541
  const current = getCurrent(tracker, shell, args);
1275
1542
  if (current) {
1276
1543
  const { context, content } = current;
1277
- return NotebookActions.runAndAdvance(content, context.sessionContext);
1544
+ return NotebookActions.runAndAdvance(content, context.sessionContext, sessionDialogs, translator);
1278
1545
  }
1279
1546
  },
1280
1547
  isEnabled
1281
1548
  });
1282
1549
  commands.addCommand(CommandIDs.run, {
1283
- label: trans.__("Run Selected Cells and Don't Advance"),
1550
+ label: args => {
1551
+ var _a;
1552
+ const current = getCurrent(tracker, shell, { ...args, activate: false });
1553
+ return trans._n('Run Selected Cell and Do not Advance', 'Run Selected Cells and Do not Advance', (_a = current === null || current === void 0 ? void 0 : current.content.selectedCells.length) !== null && _a !== void 0 ? _a : 1);
1554
+ },
1284
1555
  execute: args => {
1285
1556
  const current = getCurrent(tracker, shell, args);
1286
1557
  if (current) {
1287
1558
  const { context, content } = current;
1288
- return NotebookActions.run(content, context.sessionContext);
1559
+ return NotebookActions.run(content, context.sessionContext, sessionDialogs, translator);
1289
1560
  }
1290
1561
  },
1291
1562
  isEnabled
1292
1563
  });
1293
1564
  commands.addCommand(CommandIDs.runAndInsert, {
1294
- label: trans.__('Run Selected Cells and Insert Below'),
1565
+ label: args => {
1566
+ var _a;
1567
+ const current = getCurrent(tracker, shell, { ...args, activate: false });
1568
+ return trans._n('Run Selected Cell and Insert Below', 'Run Selected Cells and Insert Below', (_a = current === null || current === void 0 ? void 0 : current.content.selectedCells.length) !== null && _a !== void 0 ? _a : 1);
1569
+ },
1295
1570
  execute: args => {
1296
1571
  const current = getCurrent(tracker, shell, args);
1297
1572
  if (current) {
1298
1573
  const { context, content } = current;
1299
- return NotebookActions.runAndInsert(content, context.sessionContext);
1574
+ return NotebookActions.runAndInsert(content, context.sessionContext, sessionDialogs, translator);
1300
1575
  }
1301
1576
  },
1302
1577
  isEnabled
1303
1578
  });
1304
1579
  commands.addCommand(CommandIDs.runAll, {
1305
1580
  label: trans.__('Run All Cells'),
1581
+ caption: trans.__('Run all cells'),
1306
1582
  execute: args => {
1307
1583
  const current = getCurrent(tracker, shell, args);
1308
1584
  if (current) {
1309
1585
  const { context, content } = current;
1310
- return NotebookActions.runAll(content, context.sessionContext);
1586
+ return NotebookActions.runAll(content, context.sessionContext, sessionDialogs, translator);
1311
1587
  }
1312
1588
  },
1313
1589
  isEnabled
@@ -1318,7 +1594,7 @@ function addCommands(app, tracker, translator, sessionDialogs, isEnabled) {
1318
1594
  const current = getCurrent(tracker, shell, args);
1319
1595
  if (current) {
1320
1596
  const { context, content } = current;
1321
- return NotebookActions.runAllAbove(content, context.sessionContext);
1597
+ return NotebookActions.runAllAbove(content, context.sessionContext, sessionDialogs, translator);
1322
1598
  }
1323
1599
  },
1324
1600
  isEnabled: () => {
@@ -1334,7 +1610,7 @@ function addCommands(app, tracker, translator, sessionDialogs, isEnabled) {
1334
1610
  const current = getCurrent(tracker, shell, args);
1335
1611
  if (current) {
1336
1612
  const { context, content } = current;
1337
- return NotebookActions.runAllBelow(content, context.sessionContext);
1613
+ return NotebookActions.runAllBelow(content, context.sessionContext, sessionDialogs, translator);
1338
1614
  }
1339
1615
  },
1340
1616
  isEnabled: () => {
@@ -1350,18 +1626,19 @@ function addCommands(app, tracker, translator, sessionDialogs, isEnabled) {
1350
1626
  execute: args => {
1351
1627
  const current = getCurrent(tracker, shell, args);
1352
1628
  if (current) {
1353
- const { context, content } = current;
1354
- return NotebookActions.renderAllMarkdown(content, context.sessionContext);
1629
+ const { content } = current;
1630
+ return NotebookActions.renderAllMarkdown(content);
1355
1631
  }
1356
1632
  },
1357
1633
  isEnabled
1358
1634
  });
1359
1635
  commands.addCommand(CommandIDs.restart, {
1360
1636
  label: trans.__('Restart Kernel…'),
1637
+ caption: trans.__('Restart the kernel'),
1361
1638
  execute: args => {
1362
1639
  const current = getCurrent(tracker, shell, args);
1363
1640
  if (current) {
1364
- return sessionDialogs.restart(current.sessionContext, translator);
1641
+ return sessionDialogs.restart(current.sessionContext);
1365
1642
  }
1366
1643
  },
1367
1644
  isEnabled
@@ -1442,6 +1719,7 @@ function addCommands(app, tracker, translator, sessionDialogs, isEnabled) {
1442
1719
  });
1443
1720
  commands.addCommand(CommandIDs.restartRunAll, {
1444
1721
  label: trans.__('Restart Kernel and Run All Cells…'),
1722
+ caption: trans.__('Restart the kernel and run all cells'),
1445
1723
  execute: async () => {
1446
1724
  const restarted = await commands.execute(CommandIDs.restart, {
1447
1725
  activate: false
@@ -1450,7 +1728,8 @@ function addCommands(app, tracker, translator, sessionDialogs, isEnabled) {
1450
1728
  await commands.execute(CommandIDs.runAll);
1451
1729
  }
1452
1730
  },
1453
- isEnabled
1731
+ isEnabled,
1732
+ icon: fastForwardIcon
1454
1733
  });
1455
1734
  commands.addCommand(CommandIDs.clearAllOutputs, {
1456
1735
  label: trans.__('Clear Outputs of All Cells'),
@@ -1476,6 +1755,7 @@ function addCommands(app, tracker, translator, sessionDialogs, isEnabled) {
1476
1755
  });
1477
1756
  commands.addCommand(CommandIDs.interrupt, {
1478
1757
  label: trans.__('Interrupt Kernel'),
1758
+ caption: trans.__('Interrupt the kernel'),
1479
1759
  execute: args => {
1480
1760
  var _a;
1481
1761
  const current = getCurrent(tracker, shell, args);
@@ -1520,8 +1800,16 @@ function addCommands(app, tracker, translator, sessionDialogs, isEnabled) {
1520
1800
  isEnabled
1521
1801
  });
1522
1802
  commands.addCommand(CommandIDs.cut, {
1523
- label: trans.__('Cut Cells'),
1524
- caption: trans.__('Cut the selected cells'),
1803
+ label: args => {
1804
+ var _a;
1805
+ const current = getCurrent(tracker, shell, { ...args, activate: false });
1806
+ return trans._n('Cut Cell', 'Cut Cells', (_a = current === null || current === void 0 ? void 0 : current.content.selectedCells.length) !== null && _a !== void 0 ? _a : 1);
1807
+ },
1808
+ caption: args => {
1809
+ var _a;
1810
+ const current = getCurrent(tracker, shell, { ...args, activate: false });
1811
+ return trans._n('Cut this cell', 'Cut these %1 cells', (_a = current === null || current === void 0 ? void 0 : current.content.selectedCells.length) !== null && _a !== void 0 ? _a : 1);
1812
+ },
1525
1813
  execute: args => {
1526
1814
  const current = getCurrent(tracker, shell, args);
1527
1815
  if (current) {
@@ -1532,20 +1820,36 @@ function addCommands(app, tracker, translator, sessionDialogs, isEnabled) {
1532
1820
  isEnabled
1533
1821
  });
1534
1822
  commands.addCommand(CommandIDs.copy, {
1535
- label: trans.__('Copy Cells'),
1536
- caption: trans.__('Copy the selected cells'),
1823
+ label: args => {
1824
+ var _a;
1825
+ const current = getCurrent(tracker, shell, { ...args, activate: false });
1826
+ return trans._n('Copy Cell', 'Copy Cells', (_a = current === null || current === void 0 ? void 0 : current.content.selectedCells.length) !== null && _a !== void 0 ? _a : 1);
1827
+ },
1828
+ caption: args => {
1829
+ var _a;
1830
+ const current = getCurrent(tracker, shell, { ...args, activate: false });
1831
+ return trans._n('Copy this cell', 'Copy these %1 cells', (_a = current === null || current === void 0 ? void 0 : current.content.selectedCells.length) !== null && _a !== void 0 ? _a : 1);
1832
+ },
1537
1833
  execute: args => {
1538
1834
  const current = getCurrent(tracker, shell, args);
1539
1835
  if (current) {
1540
1836
  return NotebookActions.copy(current.content);
1541
1837
  }
1542
1838
  },
1543
- icon: args => (args.toolbar ? copyIcon : ''),
1839
+ icon: args => (args.toolbar ? copyIcon : undefined),
1544
1840
  isEnabled
1545
1841
  });
1546
1842
  commands.addCommand(CommandIDs.pasteBelow, {
1547
- label: trans.__('Paste Cells Below'),
1548
- caption: trans.__('Paste cells from the clipboard'),
1843
+ label: args => {
1844
+ var _a;
1845
+ const current = getCurrent(tracker, shell, { ...args, activate: false });
1846
+ return trans._n('Paste Cell Below', 'Paste Cells Below', (_a = current === null || current === void 0 ? void 0 : current.content.selectedCells.length) !== null && _a !== void 0 ? _a : 1);
1847
+ },
1848
+ caption: args => {
1849
+ var _a;
1850
+ const current = getCurrent(tracker, shell, { ...args, activate: false });
1851
+ return trans._n('Paste this cell from the clipboard', 'Paste these %1 cells from the clipboard', (_a = current === null || current === void 0 ? void 0 : current.content.selectedCells.length) !== null && _a !== void 0 ? _a : 1);
1852
+ },
1549
1853
  execute: args => {
1550
1854
  const current = getCurrent(tracker, shell, args);
1551
1855
  if (current) {
@@ -1556,7 +1860,16 @@ function addCommands(app, tracker, translator, sessionDialogs, isEnabled) {
1556
1860
  isEnabled
1557
1861
  });
1558
1862
  commands.addCommand(CommandIDs.pasteAbove, {
1559
- label: trans.__('Paste Cells Above'),
1863
+ label: args => {
1864
+ var _a;
1865
+ const current = getCurrent(tracker, shell, { ...args, activate: false });
1866
+ return trans._n('Paste Cell Above', 'Paste Cells Above', (_a = current === null || current === void 0 ? void 0 : current.content.selectedCells.length) !== null && _a !== void 0 ? _a : 1);
1867
+ },
1868
+ caption: args => {
1869
+ var _a;
1870
+ const current = getCurrent(tracker, shell, { ...args, activate: false });
1871
+ return trans._n('Paste this cell from the clipboard', 'Paste these %1 cells from the clipboard', (_a = current === null || current === void 0 ? void 0 : current.content.selectedCells.length) !== null && _a !== void 0 ? _a : 1);
1872
+ },
1560
1873
  execute: args => {
1561
1874
  const current = getCurrent(tracker, shell, args);
1562
1875
  if (current) {
@@ -1566,19 +1879,31 @@ function addCommands(app, tracker, translator, sessionDialogs, isEnabled) {
1566
1879
  isEnabled
1567
1880
  });
1568
1881
  commands.addCommand(CommandIDs.duplicateBelow, {
1569
- label: trans.__('Duplicate Cells Below'),
1570
- caption: trans.__('Copy the selected cells and paste them below the selection'),
1882
+ label: args => {
1883
+ var _a;
1884
+ const current = getCurrent(tracker, shell, { ...args, activate: false });
1885
+ return trans._n('Duplicate Cell Below', 'Duplicate Cells Below', (_a = current === null || current === void 0 ? void 0 : current.content.selectedCells.length) !== null && _a !== void 0 ? _a : 1);
1886
+ },
1887
+ caption: args => {
1888
+ var _a;
1889
+ const current = getCurrent(tracker, shell, { ...args, activate: false });
1890
+ return trans._n('Create a duplicate of this cell below', 'Create duplicates of %1 cells below', (_a = current === null || current === void 0 ? void 0 : current.content.selectedCells.length) !== null && _a !== void 0 ? _a : 1);
1891
+ },
1571
1892
  execute: args => {
1572
1893
  const current = getCurrent(tracker, shell, args);
1573
1894
  if (current) {
1574
1895
  NotebookActions.duplicate(current.content, 'belowSelected');
1575
1896
  }
1576
1897
  },
1577
- icon: args => (args.toolbar ? duplicateIcon : ''),
1898
+ icon: args => (args.toolbar ? duplicateIcon : undefined),
1578
1899
  isEnabled
1579
1900
  });
1580
1901
  commands.addCommand(CommandIDs.pasteAndReplace, {
1581
- label: trans.__('Paste Cells and Replace'),
1902
+ label: args => {
1903
+ var _a;
1904
+ const current = getCurrent(tracker, shell, { ...args, activate: false });
1905
+ return trans._n('Paste Cell and Replace', 'Paste Cells and Replace', (_a = current === null || current === void 0 ? void 0 : current.content.selectedCells.length) !== null && _a !== void 0 ? _a : 1);
1906
+ },
1582
1907
  execute: args => {
1583
1908
  const current = getCurrent(tracker, shell, args);
1584
1909
  if (current) {
@@ -1588,7 +1913,16 @@ function addCommands(app, tracker, translator, sessionDialogs, isEnabled) {
1588
1913
  isEnabled
1589
1914
  });
1590
1915
  commands.addCommand(CommandIDs.deleteCell, {
1591
- label: trans.__('Delete Cells'),
1916
+ label: args => {
1917
+ var _a;
1918
+ const current = getCurrent(tracker, shell, { ...args, activate: false });
1919
+ return trans._n('Delete Cell', 'Delete Cells', (_a = current === null || current === void 0 ? void 0 : current.content.selectedCells.length) !== null && _a !== void 0 ? _a : 1);
1920
+ },
1921
+ caption: args => {
1922
+ var _a;
1923
+ const current = getCurrent(tracker, shell, { ...args, activate: false });
1924
+ return trans._n('Delete this cell', 'Delete these %1 cells', (_a = current === null || current === void 0 ? void 0 : current.content.selectedCells.length) !== null && _a !== void 0 ? _a : 1);
1925
+ },
1592
1926
  execute: args => {
1593
1927
  const current = getCurrent(tracker, shell, args);
1594
1928
  if (current) {
@@ -1639,6 +1973,7 @@ function addCommands(app, tracker, translator, sessionDialogs, isEnabled) {
1639
1973
  });
1640
1974
  commands.addCommand(CommandIDs.insertAbove, {
1641
1975
  label: trans.__('Insert Cell Above'),
1976
+ caption: trans.__('Insert a cell above'),
1642
1977
  execute: args => {
1643
1978
  const current = getCurrent(tracker, shell, args);
1644
1979
  if (current) {
@@ -1781,25 +2116,58 @@ function addCommands(app, tracker, translator, sessionDialogs, isEnabled) {
1781
2116
  isEnabled
1782
2117
  });
1783
2118
  commands.addCommand(CommandIDs.moveUp, {
1784
- label: trans.__('Move Cells Up'),
2119
+ label: args => {
2120
+ var _a;
2121
+ const current = getCurrent(tracker, shell, { ...args, activate: false });
2122
+ return trans._n('Move Cell Up', 'Move Cells Up', (_a = current === null || current === void 0 ? void 0 : current.content.selectedCells.length) !== null && _a !== void 0 ? _a : 1);
2123
+ },
2124
+ caption: args => {
2125
+ var _a;
2126
+ const current = getCurrent(tracker, shell, { ...args, activate: false });
2127
+ return trans._n('Move this cell up', 'Move these %1 cells up', (_a = current === null || current === void 0 ? void 0 : current.content.selectedCells.length) !== null && _a !== void 0 ? _a : 1);
2128
+ },
1785
2129
  execute: args => {
1786
2130
  const current = getCurrent(tracker, shell, args);
1787
2131
  if (current) {
1788
- return NotebookActions.moveUp(current.content);
2132
+ NotebookActions.moveUp(current.content);
2133
+ Private.raiseSilentNotification(trans.__('Notebook cell shifted up successfully'), current.node);
1789
2134
  }
1790
2135
  },
1791
- isEnabled,
2136
+ isEnabled: args => {
2137
+ const current = getCurrent(tracker, shell, { ...args, activate: false });
2138
+ if (!current) {
2139
+ return false;
2140
+ }
2141
+ return current.content.activeCellIndex >= 1;
2142
+ },
1792
2143
  icon: args => (args.toolbar ? moveUpIcon : undefined)
1793
2144
  });
1794
2145
  commands.addCommand(CommandIDs.moveDown, {
1795
- label: trans.__('Move Cells Down'),
2146
+ label: args => {
2147
+ var _a;
2148
+ const current = getCurrent(tracker, shell, { ...args, activate: false });
2149
+ return trans._n('Move Cell Down', 'Move Cells Down', (_a = current === null || current === void 0 ? void 0 : current.content.selectedCells.length) !== null && _a !== void 0 ? _a : 1);
2150
+ },
2151
+ caption: args => {
2152
+ var _a;
2153
+ const current = getCurrent(tracker, shell, { ...args, activate: false });
2154
+ return trans._n('Move this cell down', 'Move these %1 cells down', (_a = current === null || current === void 0 ? void 0 : current.content.selectedCells.length) !== null && _a !== void 0 ? _a : 1);
2155
+ },
1796
2156
  execute: args => {
1797
2157
  const current = getCurrent(tracker, shell, args);
1798
2158
  if (current) {
1799
- return NotebookActions.moveDown(current.content);
2159
+ NotebookActions.moveDown(current.content);
2160
+ Private.raiseSilentNotification(trans.__('Notebook cell shifted down successfully'), current.node);
1800
2161
  }
1801
2162
  },
1802
- isEnabled,
2163
+ isEnabled: args => {
2164
+ const current = getCurrent(tracker, shell, { ...args, activate: false });
2165
+ if (!current || !current.content.model) {
2166
+ return false;
2167
+ }
2168
+ const length = current.content.model.cells.length;
2169
+ return current.content.activeCellIndex < length - 1;
2170
+ },
1803
2171
  icon: args => (args.toolbar ? moveDownIcon : undefined)
1804
2172
  });
1805
2173
  commands.addCommand(CommandIDs.toggleAllLines, {
@@ -1812,7 +2180,7 @@ function addCommands(app, tracker, translator, sessionDialogs, isEnabled) {
1812
2180
  },
1813
2181
  isEnabled,
1814
2182
  isToggled: args => {
1815
- const current = getCurrent(tracker, shell, Object.assign(Object.assign({}, args), { activate: false }));
2183
+ const current = getCurrent(tracker, shell, { ...args, activate: false });
1816
2184
  if (current) {
1817
2185
  const config = current.content.editorConfig;
1818
2186
  return !!(config.code.lineNumbers &&
@@ -1870,7 +2238,11 @@ function addCommands(app, tracker, translator, sessionDialogs, isEnabled) {
1870
2238
  var _a;
1871
2239
  const current = getCurrent(tracker, shell, args);
1872
2240
  if (current) {
1873
- return (_a = current.content.activeCell) === null || _a === void 0 ? void 0 : _a.editor.redo();
2241
+ const cell = current.content.activeCell;
2242
+ if (cell) {
2243
+ cell.inputHidden = false;
2244
+ return (_a = cell.editor) === null || _a === void 0 ? void 0 : _a.redo();
2245
+ }
1874
2246
  }
1875
2247
  }
1876
2248
  });
@@ -1880,7 +2252,11 @@ function addCommands(app, tracker, translator, sessionDialogs, isEnabled) {
1880
2252
  var _a;
1881
2253
  const current = getCurrent(tracker, shell, args);
1882
2254
  if (current) {
1883
- return (_a = current.content.activeCell) === null || _a === void 0 ? void 0 : _a.editor.undo();
2255
+ const cell = current.content.activeCell;
2256
+ if (cell) {
2257
+ cell.inputHidden = false;
2258
+ return (_a = cell.editor) === null || _a === void 0 ? void 0 : _a.undo();
2259
+ }
1884
2260
  }
1885
2261
  }
1886
2262
  });
@@ -1889,7 +2265,7 @@ function addCommands(app, tracker, translator, sessionDialogs, isEnabled) {
1889
2265
  execute: args => {
1890
2266
  const current = getCurrent(tracker, shell, args);
1891
2267
  if (current) {
1892
- return sessionDialogs.selectKernel(current.context.sessionContext, translator);
2268
+ return sessionDialogs.selectKernel(current.context.sessionContext);
1893
2269
  }
1894
2270
  },
1895
2271
  isEnabled
@@ -1898,7 +2274,7 @@ function addCommands(app, tracker, translator, sessionDialogs, isEnabled) {
1898
2274
  label: trans.__('Get Kernel'),
1899
2275
  execute: args => {
1900
2276
  var _a;
1901
- const current = getCurrent(tracker, shell, Object.assign({ activate: false }, args));
2277
+ const current = getCurrent(tracker, shell, { activate: false, ...args });
1902
2278
  if (current) {
1903
2279
  return (_a = current.sessionContext.session) === null || _a === void 0 ? void 0 : _a.kernel;
1904
2280
  }
@@ -2063,7 +2439,7 @@ function addCommands(app, tracker, translator, sessionDialogs, isEnabled) {
2063
2439
  },
2064
2440
  isEnabled,
2065
2441
  isToggled: args => {
2066
- const current = getCurrent(tracker, shell, Object.assign(Object.assign({}, args), { activate: false }));
2442
+ const current = getCurrent(tracker, shell, { ...args, activate: false });
2067
2443
  if (current) {
2068
2444
  return current.content.renderingLayout === 'side-by-side';
2069
2445
  }
@@ -2072,21 +2448,6 @@ function addCommands(app, tracker, translator, sessionDialogs, isEnabled) {
2072
2448
  }
2073
2449
  }
2074
2450
  });
2075
- commands.addCommand(CommandIDs.setSideBySideRatio, {
2076
- label: trans.__('Set side-by-side ratio'),
2077
- execute: args => {
2078
- InputDialog.getNumber({
2079
- title: trans.__('Width of the output in side-by-side mode'),
2080
- value: 1
2081
- })
2082
- .then(result => {
2083
- if (result.value) {
2084
- document.documentElement.style.setProperty('--jp-side-by-side-output-size', `${result.value}fr`);
2085
- }
2086
- })
2087
- .catch(console.error);
2088
- }
2089
- });
2090
2451
  commands.addCommand(CommandIDs.showAllOutputs, {
2091
2452
  label: trans.__('Expand All Outputs'),
2092
2453
  execute: args => {
@@ -2139,7 +2500,7 @@ function addCommands(app, tracker, translator, sessionDialogs, isEnabled) {
2139
2500
  isEnabled
2140
2501
  });
2141
2502
  commands.addCommand(CommandIDs.toggleCollapseCmd, {
2142
- label: 'Toggle Collapse Notebook Heading',
2503
+ label: trans.__('Toggle Collapse Notebook Heading'),
2143
2504
  execute: args => {
2144
2505
  const current = getCurrent(tracker, shell, args);
2145
2506
  if (current) {
@@ -2149,7 +2510,7 @@ function addCommands(app, tracker, translator, sessionDialogs, isEnabled) {
2149
2510
  isEnabled: isEnabledAndHeadingSelected
2150
2511
  });
2151
2512
  commands.addCommand(CommandIDs.collapseAllCmd, {
2152
- label: 'Collapse All Headings',
2513
+ label: trans.__('Collapse All Headings'),
2153
2514
  execute: args => {
2154
2515
  const current = getCurrent(tracker, shell, args);
2155
2516
  if (current) {
@@ -2158,7 +2519,7 @@ function addCommands(app, tracker, translator, sessionDialogs, isEnabled) {
2158
2519
  }
2159
2520
  });
2160
2521
  commands.addCommand(CommandIDs.expandAllCmd, {
2161
- label: 'Expand All Headings',
2522
+ label: trans.__('Expand All Headings'),
2162
2523
  execute: args => {
2163
2524
  const current = getCurrent(tracker, shell, args);
2164
2525
  if (current) {
@@ -2166,6 +2527,33 @@ function addCommands(app, tracker, translator, sessionDialogs, isEnabled) {
2166
2527
  }
2167
2528
  }
2168
2529
  });
2530
+ commands.addCommand(CommandIDs.tocRunCells, {
2531
+ label: trans.__('Select and Run Cell(s) for this Heading'),
2532
+ execute: args => {
2533
+ const current = getCurrent(tracker, shell, { activate: false, ...args });
2534
+ if (current === null) {
2535
+ return;
2536
+ }
2537
+ const activeCell = current.content.activeCell;
2538
+ let lastIndex = current.content.activeCellIndex;
2539
+ if (activeCell instanceof MarkdownCell) {
2540
+ const cells = current.content.widgets;
2541
+ const level = activeCell.headingInfo.level;
2542
+ for (let i = current.content.activeCellIndex + 1; i < cells.length; i++) {
2543
+ const cell = cells[i];
2544
+ if (cell instanceof MarkdownCell &&
2545
+ // cell.headingInfo.level === -1 if no heading
2546
+ cell.headingInfo.level >= 0 &&
2547
+ cell.headingInfo.level <= level) {
2548
+ break;
2549
+ }
2550
+ lastIndex = i;
2551
+ }
2552
+ }
2553
+ current.content.extendContiguousSelectionTo(lastIndex);
2554
+ void NotebookActions.run(current.content, current.sessionContext, sessionDialogs, translator);
2555
+ }
2556
+ });
2169
2557
  }
2170
2558
  /**
2171
2559
  * Populate the application's command palette with notebook commands.
@@ -2266,8 +2654,7 @@ function populatePalette(palette, translator) {
2266
2654
  /**
2267
2655
  * Populates the application menus for the notebook.
2268
2656
  */
2269
- function populateMenus(mainMenu, tracker, sessionDialogs, isEnabled) {
2270
- sessionDialogs = sessionDialogs || sessionContextDialogs;
2657
+ function populateMenus(mainMenu, isEnabled) {
2271
2658
  // Add undo/redo hooks to the edit menu.
2272
2659
  mainMenu.editMenu.undoers.redo.add({
2273
2660
  id: CommandIDs.redo,
@@ -2360,7 +2747,8 @@ var Private;
2360
2747
  preferredLanguage: widget.context.model.defaultKernelLanguage,
2361
2748
  activate: activate,
2362
2749
  ref: widget.id,
2363
- insertMode: 'split-bottom'
2750
+ insertMode: 'split-bottom',
2751
+ type: 'Linked Console'
2364
2752
  };
2365
2753
  return commands.execute('console:create', options);
2366
2754
  }
@@ -2431,6 +2819,35 @@ var Private;
2431
2819
  };
2432
2820
  }
2433
2821
  Private.getFormatLabels = getFormatLabels;
2822
+ /**
2823
+ * Raises a silent notification that is read by screen readers
2824
+ *
2825
+ * FIXME: Once a notificatiom API is introduced (https://github.com/jupyterlab/jupyterlab/issues/689),
2826
+ * this can be refactored to use the same.
2827
+ *
2828
+ * More discussion at https://github.com/jupyterlab/jupyterlab/pull/9031#issuecomment-773541469
2829
+ *
2830
+ *
2831
+ * @param message Message to be relayed to screen readers
2832
+ * @param notebookNode DOM node to which the notification container is attached
2833
+ */
2834
+ function raiseSilentNotification(message, notebookNode) {
2835
+ const hiddenAlertContainerId = `sr-message-container-${notebookNode.id}`;
2836
+ const hiddenAlertContainer = document.getElementById(hiddenAlertContainerId) ||
2837
+ document.createElement('div');
2838
+ // If the container is not available, append the newly created container
2839
+ // to the current notebook panel and set related properties
2840
+ if (hiddenAlertContainer.getAttribute('id') !== hiddenAlertContainerId) {
2841
+ hiddenAlertContainer.classList.add('sr-only');
2842
+ hiddenAlertContainer.setAttribute('id', hiddenAlertContainerId);
2843
+ hiddenAlertContainer.setAttribute('role', 'alert');
2844
+ hiddenAlertContainer.hidden = true;
2845
+ notebookNode.appendChild(hiddenAlertContainer);
2846
+ }
2847
+ // Insert/Update alert container with the notification message
2848
+ hiddenAlertContainer.innerText = message;
2849
+ }
2850
+ Private.raiseSilentNotification = raiseSilentNotification;
2434
2851
  /**
2435
2852
  * A widget hosting a cloned output area.
2436
2853
  */