Ver código fonte

Merge pull request #61 from jtpio/editors-main-area

Add editors to the main area widget
Jeremy Tuloup 5 anos atrás
pai
commit
4d2691b2ac
6 arquivos alterados com 226 adições e 7 exclusões
  1. 14 3
      src/debugger.ts
  2. 124 0
      src/editors/index.ts
  3. 8 2
      src/index.ts
  4. 72 0
      style/editors.css
  5. 2 1
      style/index.css
  6. 6 1
      tests/src/debugger.spec.ts

+ 14 - 3
src/debugger.ts

@@ -1,6 +1,8 @@
 // Copyright (c) Jupyter Development Team.
 // Distributed under the terms of the Modified BSD License.
 
+import { CodeEditor } from '@jupyterlab/codeeditor';
+
 import { IDataConnector } from '@jupyterlab/coreutils';
 
 import { ReadonlyJSONValue } from '@phosphor/coreutils';
@@ -13,23 +15,31 @@ import { ISignal, Signal } from '@phosphor/signaling';
 
 import { BoxPanel } from '@phosphor/widgets';
 
-import { IDebugger } from './tokens';
+import { DebuggerEditors } from './editors';
 
 import { DebuggerSidebar } from './sidebar';
 
+import { IDebugger } from './tokens';
+
 export class Debugger extends BoxPanel {
   constructor(options: Debugger.IOptions) {
     super({ direction: 'left-to-right' });
+    this.title.label = 'Debugger';
+    this.title.iconClass = 'jp-BugIcon';
+
     this.model = new Debugger.Model(options);
 
     this.sidebar = new DebuggerSidebar(this.model);
-
-    this.title.label = 'Debugger';
     this.model.sidebar = this.sidebar;
 
+    const { editorFactory } = options;
+    this.editors = new DebuggerEditors({ editorFactory });
+    this.addWidget(this.editors);
+
     this.addClass('jp-Debugger');
   }
 
+  readonly editors: DebuggerEditors;
   readonly model: Debugger.Model;
   readonly sidebar: DebuggerSidebar;
 
@@ -47,6 +57,7 @@ export class Debugger extends BoxPanel {
  */
 export namespace Debugger {
   export interface IOptions {
+    editorFactory: CodeEditor.Factory;
     connector?: IDataConnector<ReadonlyJSONValue>;
     id?: string;
     session?: IClientSession;

+ 124 - 0
src/editors/index.ts

@@ -0,0 +1,124 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) Jupyter Development Team.
+| Distributed under the terms of the Modified BSD License.
+|----------------------------------------------------------------------------*/
+
+import { CodeEditorWrapper, CodeEditor } from '@jupyterlab/codeeditor';
+
+import { ISignal, Signal } from '@phosphor/signaling';
+
+import { TabPanel } from '@phosphor/widgets';
+
+export class DebuggerEditors extends TabPanel {
+  constructor(options: DebuggerEditors.IOptions) {
+    super();
+
+    this.tabsMovable = true;
+
+    this.model = new DebuggerEditors.IModel();
+    this.model.editorAdded.connect((sender, data) => {
+      let editor = new CodeEditorWrapper({
+        model: new CodeEditor.Model({
+          value: data.code,
+          mimeType: data.mimeType
+        }),
+        factory: options.editorFactory,
+        config: {
+          readOnly: true,
+          lineNumbers: true
+        }
+      });
+
+      editor.title.label = data.title;
+      editor.title.closable = true;
+
+      this.addWidget(editor);
+    });
+
+    MOCK_EDITORS.forEach(editor => this.model.addEditor(editor));
+
+    this.addClass('jp-DebuggerEditors');
+  }
+
+  /**
+   * The debugger editors model.
+   */
+  model: DebuggerEditors.IModel;
+
+  /**
+   * Dispose the debug editors.
+   */
+  dispose(): void {
+    if (this.isDisposed) {
+      return;
+    }
+    Signal.clearData(this);
+  }
+}
+
+/**
+ * A namespace for `DebuggerEditors` statics.
+ */
+export namespace DebuggerEditors {
+  /**
+   * The options used to create a DebuggerEditors.
+   */
+  export interface IOptions {
+    editorFactory: CodeEditor.Factory;
+  }
+
+  /**
+   * An interface for read only editors.
+   */
+  export interface IEditor {
+    title: string;
+    code: string;
+    mimeType: string;
+  }
+
+  export interface IModel {}
+
+  export class IModel implements IModel {
+    /**
+     * A signal emitted when a new editor is added.
+     */
+    get editorAdded(): ISignal<
+      DebuggerEditors.IModel,
+      DebuggerEditors.IEditor
+    > {
+      return this._editorAdded;
+    }
+
+    /**
+     * Get all the editors currently opened.
+     */
+    get editors() {
+      return this._state;
+    }
+
+    /**
+     * Add a new editor to the editor TabPanel.
+     * @param editor The read-only editor info to add.
+     */
+    addEditor(editor: DebuggerEditors.IEditor) {
+      this._state.push(editor);
+      this._editorAdded.emit(editor);
+    }
+
+    private _state: DebuggerEditors.IEditor[] = [];
+    private _editorAdded = new Signal<this, DebuggerEditors.IEditor>(this);
+  }
+}
+
+const MOCK_EDITORS = [
+  {
+    title: 'untitled.py',
+    mimeType: 'text/x-ipython',
+    code: 'import math\nprint(math.pi)'
+  },
+  {
+    title: 'test.py',
+    mimeType: 'text/x-ipython',
+    code: 'import sys\nprint(sys.version)'
+  }
+];

+ 8 - 2
src/index.ts

@@ -33,6 +33,7 @@ import { DebuggerNotebookHandler } from './handlers/notebook';
 import { DebuggerConsoleHandler } from './handlers/console';
 
 import { Kernel } from '@jupyterlab/services';
+import { IEditorServices } from '@jupyterlab/codeeditor';
 
 /**
  * The command IDs used by the debugger plugin.
@@ -208,19 +209,23 @@ const notebooks: JupyterFrontEndPlugin<void> = {
 const main: JupyterFrontEndPlugin<IDebugger> = {
   id: '@jupyterlab/debugger:main',
   optional: [ILayoutRestorer, ICommandPalette],
-  requires: [IStateDB],
+  requires: [IStateDB, IEditorServices],
   provides: IDebugger,
   autoStart: true,
   activate: (
     app: JupyterFrontEnd,
     state: IStateDB,
+    editorServices: IEditorServices,
     restorer: ILayoutRestorer | null,
     palette: ICommandPalette | null
   ): IDebugger => {
     const tracker = new WidgetTracker<MainAreaWidget<Debugger>>({
       namespace: 'debugger'
     });
+
     const { commands, shell } = app;
+    const editorFactory = editorServices.factoryService.newInlineEditor;
+
     let widget: MainAreaWidget<Debugger>;
 
     const getModel = () => {
@@ -335,7 +340,8 @@ const main: JupyterFrontEndPlugin<IDebugger> = {
           widget = new MainAreaWidget({
             content: new Debugger({
               connector: state,
-              id: id
+              editorFactory,
+              id
             })
           });
 

+ 72 - 0
style/editors.css

@@ -0,0 +1,72 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) Jupyter Development Team.
+| Distributed under the terms of the Modified BSD License.
+|----------------------------------------------------------------------------*/
+
+/* Values inspired by http://phosphorjs.github.io/examples/tabs/ */
+
+.jp-DebuggerEditors .p-TabBar {
+  min-height: 24px;
+  max-height: 24px;
+}
+
+.jp-DebuggerEditors .p-TabBar-content {
+  min-width: 0;
+  min-height: 0;
+  align-items: flex-end;
+  border-bottom: var(--jp-border-width) solid var(--jp-border-color1);
+}
+
+.jp-DebuggerEditors .p-TabBar-tab {
+  background: var(--jp-layout-color2);
+  color: var(--jp-ui-font-color1);
+  padding: 0px 10px;
+  border: var(--jp-border-width) solid var(--jp-border-color1);
+  border-bottom: none;
+  font: 12px Helvetica, Arial, sans-serif;
+  flex: 0 1 125px;
+  min-height: 24px;
+  max-height: 24px;
+  min-width: 35px;
+  margin-left: -1px;
+  line-height: 24px;
+}
+
+.jp-DebuggerEditors .p-TabBar-tab:first-child {
+  margin-left: 0;
+}
+
+.jp-DebuggerEditors .p-TabBar-tab.p-mod-current {
+  min-height: 24px;
+  max-height: 24px;
+  background: var(--jp-layout-color1);
+  color: var(--jp-ui-font-color1);
+}
+
+.jp-DebuggerEditors .p-TabBar-tab:hover:not(.p-mod-current) {
+  background: var(--jp-layout-color1);
+}
+
+.jp-DebuggerEditors .p-TabBar-tabIcon,
+.jp-DebuggerEditors .p-TabBar-tabText,
+.jp-DebuggerEditors .p-TabBar-tabCloseIcon {
+  line-height: 24px;
+}
+
+.jp-DebuggerEditors .p-TabBar-tab.p-mod-closable > .p-TabBar-tabCloseIcon {
+  margin-left: 4px;
+  padding-top: 8px;
+  background-size: 16px;
+  height: 16px;
+  width: 16px;
+  background-image: var(--jp-icon-close);
+  background-position: center;
+  background-repeat: no-repeat;
+}
+
+.jp-DebuggerEditors
+  .p-TabBar-tab.p-mod-closable
+  > .p-TabBar-tabCloseIcon:hover {
+  background-size: 16px;
+  background-image: var(--jp-icon-close-circle);
+}

+ 2 - 1
style/index.css

@@ -8,6 +8,7 @@
 
 @import './icons.css';
 @import './sidebar.css';
+@import './editors.css';
 
 .jp-Debugger {
   background: var(--jp-layout-color1);
@@ -15,7 +16,7 @@
   bottom: 0;
 }
 
-/* font awsome */
+/* font awesome */
 
 .fa {
   display: inline-block;

+ 6 - 1
tests/src/debugger.spec.ts

@@ -1,14 +1,19 @@
 import { expect } from 'chai';
 
+import { CodeMirrorEditorFactory } from '@jupyterlab/codemirror';
+
 import { Debugger } from '../../lib/debugger';
 
 class TestPanel extends Debugger {}
 
 describe('Debugger', () => {
+  const editorServices = new CodeMirrorEditorFactory();
+  const editorFactory = editorServices.newInlineEditor;
+
   let panel: TestPanel;
 
   beforeEach(() => {
-    panel = new TestPanel({});
+    panel = new TestPanel({ editorFactory });
   });
 
   afterEach(() => {