From 591d4522cc0349f091a3053b81f17ca060cf6949 Mon Sep 17 00:00:00 2001 From: Alex Bozarth Date: Sun, 6 Oct 2019 20:54:54 -0700 Subject: [PATCH] Added missing File Editor functionality (#131) Some functionality of the file editor is in the activate function of fileeditor-extension. This adds that missing functionality. - Checks for changes and updates the extension config when there are changes to the fileeditor-extension settings. This enables all missing functionality based on settings values. - Enables Undo/Redo functionality. - Enables some editor view options not controlled by configs Fixes #43 --- packages/python-runner/src/index.ts | 118 +++++++++++++++++++++++++--- 1 file changed, 108 insertions(+), 10 deletions(-) diff --git a/packages/python-runner/src/index.ts b/packages/python-runner/src/index.ts index bb151a121..dc1145e30 100644 --- a/packages/python-runner/src/index.ts +++ b/packages/python-runner/src/index.ts @@ -17,11 +17,15 @@ import '../style/index.css'; import {JupyterFrontEnd, JupyterFrontEndPlugin, ILayoutRestorer} from '@jupyterlab/application'; -import {IEditorServices} from '@jupyterlab/codeeditor'; +import {CodeEditor, IEditorServices} from '@jupyterlab/codeeditor'; +import {ISettingRegistry} from '@jupyterlab/coreutils'; +import {FileEditor} from '@jupyterlab/fileeditor'; import {ILauncher} from '@jupyterlab/launcher'; import {IMainMenu} from '@jupyterlab/mainmenu'; import {WidgetTracker, ICommandPalette} from '@jupyterlab/apputils'; +import {JSONObject} from '@phosphor/coreutils'; + import {PythonFileEditorFactory, PythonFileEditor} from "./widget"; const PYTHON_ICON_CLASS = 'jp-PythonIcon'; @@ -42,12 +46,13 @@ const commandIDs = { const extension: JupyterFrontEndPlugin = { id: PYTHON_EDITOR_NAMESPACE, autoStart: true, - requires: [IEditorServices, ICommandPalette, ILayoutRestorer, IMainMenu], - optional: [ILauncher], + requires: [IEditorServices, ICommandPalette, ISettingRegistry], + optional: [ILayoutRestorer, IMainMenu, ILauncher], activate: ( app: JupyterFrontEnd, editorServices: IEditorServices, palette: ICommandPalette, + settingRegistry: ISettingRegistry, restorer: ILayoutRestorer | null, menu: IMainMenu | null, launcher: ILauncher | null @@ -63,15 +68,18 @@ const extension: JupyterFrontEndPlugin = { } }); - /* - * Track PythonFileEditor widget on page refresh - **/ + const { restored } = app; + /** + * Track PythonFileEditor widget on page refresh + */ const tracker = new WidgetTracker({ namespace: PYTHON_EDITOR_NAMESPACE }); - if (restorer){ + let config: CodeEditor.IConfig = { ...CodeEditor.defaultConfig }; + + if (restorer) { // Handle state restoration void restorer.restore(tracker, { @@ -82,7 +90,56 @@ const extension: JupyterFrontEndPlugin = { }), name: widget => widget.context.path }); - } + } + + /** + * Update the setting values. Adapted from fileeditor-extension. + */ + function updateSettings(settings: ISettingRegistry.ISettings): void { + config = { + ...CodeEditor.defaultConfig, + ...(settings.get('editorConfig').composite as JSONObject) + }; + + // Trigger a refresh of the rendered commands + app.commands.notifyCommandChanged(); + } + + /** + * Update the settings of the current tracker instances. Adapted from fileeditor-extension. + */ + function updateTracker(): void { + tracker.forEach(widget => { + updateWidget(widget.content); + }); + } + + /** + * Update the settings of a widget. Adapted from fileeditor-extension. + */ + function updateWidget(widget: FileEditor): void { + const editor = widget.editor; + Object.keys(config).forEach((keyStr: string) => { + let key = keyStr as keyof CodeEditor.IConfig; + editor.setOption(key, config[key]); + }); + } + + // Fetch the initial state of the settings. Adapted from fileeditor-extension. + Promise.all([settingRegistry.load('@jupyterlab/fileeditor-extension:plugin'), restored]) + .then(([settings]) => { + updateSettings(settings); + updateTracker(); + settings.changed.connect(() => { + updateSettings(settings); + updateTracker(); + }); + }) + .catch((reason: Error) => { + console.error(reason.message); + updateTracker(); + }); + app.docRegistry.addWidgetFactory(factory); @@ -93,11 +150,17 @@ const extension: JupyterFrontEndPlugin = { widget.context.pathChanged.connect(() => { void tracker.save(widget); }); + updateWidget(widget.content); }); - /* + // Handle the settings of new widgets. Adapted from fileeditor-extension. + tracker.widgetAdded.connect((sender, widget) => { + updateWidget(widget.content); + }); + + /** * Create new python file from launcher and file menu - **/ + */ // Add a python launcher if (launcher) { @@ -114,6 +177,41 @@ const extension: JupyterFrontEndPlugin = { [{ command: commandIDs.createNewPython }], 30 ); + + // Add undo/redo hooks to the edit menu. Adapted from fileeditor-extension. + menu.editMenu.undoers.add({ + tracker, + undo: (widget: any) => { + widget.content.editor.undo(); + }, + redo: (widget: any) => { + widget.content.editor.redo(); + } + }); + + // Add editor view options. Adapted from fileeditor-extension. + menu.viewMenu.editorViewers.add({ + tracker, + toggleLineNumbers: (widget: any) => { + const lineNumbers = !widget.content.editor.getOption('lineNumbers'); + widget.content.editor.setOption('lineNumbers', lineNumbers); + }, + toggleWordWrap: (widget: any) => { + const oldValue = widget.content.editor.getOption('lineWrap'); + const newValue = oldValue === 'off' ? 'on' : 'off'; + widget.content.editor.setOption('lineWrap', newValue); + }, + toggleMatchBrackets: (widget: any) => { + const matchBrackets = !widget.content.editor.getOption('matchBrackets'); + widget.content.editor.setOption('matchBrackets', matchBrackets); + }, + lineNumbersToggled: (widget: any) => + widget.content.editor.getOption('lineNumbers'), + wordWrapToggled: (widget: any) => + widget.content.editor.getOption('lineWrap') !== 'off', + matchBracketsToggled: (widget: any) => + widget.content.editor.getOption('matchBrackets') + }); } // Function to create a new untitled python file, given the current working directory