浏览代码

Merge pull request #66 from KsavinN/debugger-ui

Create Service for control signals between session and UI
Jeremy Tuloup 5 年之前
父节点
当前提交
5f78e31c18
共有 10 个文件被更改,包括 343 次插入189 次删除
  1. 24 3
      src/callstack/body.tsx
  2. 27 26
      src/callstack/index.ts
  3. 25 4
      src/debugger.ts
  4. 5 2
      src/handlers/cell.ts
  5. 7 1
      src/handlers/notebook.ts
  6. 28 10
      src/index.ts
  7. 147 0
      src/service.ts
  8. 12 47
      src/variables/body/search.tsx
  9. 47 14
      src/variables/body/table.tsx
  10. 21 82
      src/variables/index.ts

+ 24 - 3
src/callstack/body.tsx

@@ -1,10 +1,14 @@
 // Copyright (c) Jupyter Development Team.
 // Distributed under the terms of the Modified BSD License.
 
-import React, { useState } from 'react';
+import React, { useEffect, useState } from 'react';
+
 import { Callstack } from '.';
+
 import { ReactWidget } from '@jupyterlab/apputils';
 
+import { ArrayExt } from '@phosphor/algorithm';
+
 export class Body extends ReactWidget {
   constructor(model: Callstack.IModel) {
     super();
@@ -20,12 +24,29 @@ export class Body extends ReactWidget {
 }
 
 const FramesComponent = ({ model }: { model: Callstack.IModel }) => {
-  const [frames] = useState(model.frames);
-  const [selected, setSelected] = useState();
+  const [frames, setFrames] = useState(model.frames);
+  const [selected, setSelected] = useState(model.frame);
+
   const onSelected = (frame: any) => {
     setSelected(frame);
+    model.frame = frame;
   };
 
+  useEffect(() => {
+    const updateFrames = (_: Callstack.IModel, updates: Callstack.IFrame[]) => {
+      if (ArrayExt.shallowEqual(frames, updates)) {
+        return;
+      }
+      setFrames(updates);
+      setSelected(updates[0]);
+    };
+    model.framesChanged.connect(updateFrames);
+
+    return () => {
+      model.framesChanged.disconnect(updateFrames);
+    };
+  });
+
   return (
     <ul>
       {frames.map(ele => (

+ 27 - 26
src/callstack/index.ts

@@ -6,12 +6,13 @@ import { Toolbar, ToolbarButton } from '@jupyterlab/apputils';
 import { Widget, Panel, PanelLayout } from '@phosphor/widgets';
 import { Body } from './body';
 import { DebugProtocol } from 'vscode-debugprotocol';
+import { Signal, ISignal } from '@phosphor/signaling';
 
 export class Callstack extends Panel {
   constructor(options: Callstack.IOptions = {}) {
     super();
 
-    this.model = new Callstack.IModel(MOCK_FRAMES);
+    this.model = new Callstack.IModel([]);
     this.addClass('jp-DebuggerCallstack');
     this.title.label = 'Callstack';
 
@@ -99,40 +100,40 @@ export namespace Callstack {
 
   export class IModel implements IModel {
     constructor(model: IFrame[]) {
-      this.state = model;
+      this._state = model;
     }
 
     set frames(newFrames: IFrame[]) {
-      this.state = newFrames;
+      this._state = newFrames;
+      this._framesChanged.emit(newFrames);
     }
 
     get frames(): IFrame[] {
-      return this.state;
+      return this._state;
     }
 
-    private state: IFrame[];
+    set frame(frame: IFrame) {
+      this._currentFrame = frame;
+      this._currentFrameChanged.emit(frame);
+    }
+
+    get frame(): IFrame {
+      return this._currentFrame;
+    }
+
+    get framesChanged(): ISignal<this, IFrame[]> {
+      return this._framesChanged;
+    }
+
+    get currentFrameChanged(): ISignal<this, IFrame> {
+      return this._currentFrameChanged;
+    }
+
+    private _state: IFrame[];
+    private _currentFrame: IFrame;
+    private _framesChanged = new Signal<this, IFrame[]>(this);
+    private _currentFrameChanged = new Signal<this, IFrame>(this);
   }
 
   export interface IOptions extends Panel.IOptions {}
 }
-
-const MOCK_FRAMES: Callstack.IFrame[] = [
-  {
-    id: 0,
-    name: 'test',
-    source: {
-      name: 'untitled.py'
-    },
-    line: 6,
-    column: 1
-  },
-  {
-    id: 1,
-    name: '<module>',
-    source: {
-      name: 'untitled.py'
-    },
-    line: 7,
-    column: 1
-  }
-];

+ 25 - 4
src/debugger.ts

@@ -3,7 +3,13 @@
 
 import { CodeEditor } from '@jupyterlab/codeeditor';
 
-import { IDataConnector } from '@jupyterlab/coreutils';
+import { DebugService } from './service';
+
+import { DebugSession } from './session';
+
+import { DebuggerEditors } from './editors';
+
+import { DebuggerSidebar } from './sidebar';
 
 import { ReadonlyJSONValue } from '@phosphor/coreutils';
 
@@ -17,12 +23,12 @@ import { ISignal, Signal } from '@phosphor/signaling';
 
 import { SplitPanel } from '@phosphor/widgets';
 
-import { DebuggerEditors } from './editors';
-
-import { DebuggerSidebar } from './sidebar';
+import { IObservableString } from '@jupyterlab/observables';
 
 import { IDebugger } from './tokens';
 
+import { IDataConnector } from '@jupyterlab/coreutils';
+
 export class Debugger extends SplitPanel {
   constructor(options: Debugger.IOptions) {
     super({ orientation: 'horizontal' });
@@ -122,9 +128,14 @@ export namespace Debugger {
         this._session.dispose();
       }
       this._session = session;
+      this._service.session = session as DebugSession;
       this._sessionChanged.emit(undefined);
     }
 
+    get service(): DebugService {
+      return this._service;
+    }
+
     get sessionChanged(): ISignal<this, void> {
       return this._sessionChanged;
     }
@@ -133,6 +144,14 @@ export namespace Debugger {
       return this._isDisposed;
     }
 
+    get codeValue() {
+      return this._codeValue;
+    }
+
+    set codeValue(observableString: IObservableString) {
+      this._codeValue = observableString;
+    }
+
     dispose(): void {
       this._isDisposed = true;
     }
@@ -145,12 +164,14 @@ export namespace Debugger {
       }
     }
 
+    private _codeValue: IObservableString;
     private _sidebar: DebuggerSidebar;
     private _isDisposed = false;
     private _mode: IDebugger.Mode;
     private _modeChanged = new Signal<this, IDebugger.Mode>(this);
     private _session: IDebugger.ISession | null;
     private _sessionChanged = new Signal<this, void>(this);
+    private _service = new DebugService(null, this);
   }
 
   export namespace Model {

+ 5 - 2
src/handlers/cell.ts

@@ -56,8 +56,11 @@ export class CellManager implements IDisposable {
   }
 
   set activeCell(cell: CodeCell) {
-    this._activeCell = cell;
-    this.onActiveCellChanged();
+    if (cell) {
+      this._activeCell = cell;
+      this._debuggerModel.codeValue = cell.model.value;
+      this.onActiveCellChanged();
+    }
   }
 
   get activeCell(): CodeCell {

+ 7 - 1
src/handlers/notebook.ts

@@ -21,6 +21,12 @@ export class DebuggerNotebookHandler implements IDisposable {
     this.notebookTracker = options.notebookTracker;
     this.breakpoints = this.debuggerModel.sidebar.breakpoints.model;
     this.notebookTracker.activeCellChanged.connect(this.onNewCell, this);
+    this.cellManager = new CellManager({
+      breakpointsModel: this.breakpoints,
+      activeCell: this.notebookTracker.activeCell as CodeCell,
+      debuggerModel: this.debuggerModel,
+      type: 'notebook'
+    });
   }
 
   private notebookTracker: INotebookTracker;
@@ -35,13 +41,13 @@ export class DebuggerNotebookHandler implements IDisposable {
     }
     this.isDisposed = true;
     this.cellManager.dispose();
+    this.notebookTracker.activeCellChanged.disconnect(this.onNewCell);
     Signal.clearData(this);
   }
 
   protected onNewCell(noteTracker: NotebookTracker, codeCell: CodeCell) {
     if (this.cellManager) {
       this.cellManager.activeCell = codeCell;
-      this.cellManager.onActiveCellChanged();
     } else {
       this.cellManager = new CellManager({
         breakpointsModel: this.breakpoints,

+ 28 - 10
src/index.ts

@@ -192,19 +192,21 @@ const notebooks: JupyterFrontEndPlugin<void> = {
         app.commands.notifyCommandChanged();
       }
       if (debug.tracker.currentWidget) {
-        const handler = new DebuggerNotebookHandler({
-          notebookTracker: tracker,
-          debuggerModel: debug.tracker.currentWidget.content.model
-        });
         if (!oldhandler) {
           oldhandler = {
             id: widget.id,
-            handler: handler
+            handler: new DebuggerNotebookHandler({
+              notebookTracker: tracker,
+              debuggerModel: debug.tracker.currentWidget.content.model
+            })
           };
         } else if (oldhandler.id !== widget.id) {
           oldhandler.id = widget.id;
           oldhandler.handler.dispose();
-          oldhandler.handler = handler;
+          oldhandler.handler = new DebuggerNotebookHandler({
+            notebookTracker: tracker,
+            debuggerModel: debug.tracker.currentWidget.content.model
+          });
         }
       }
     });
@@ -308,6 +310,20 @@ const main: JupyterFrontEndPlugin<IDebugger> = {
       }
     });
 
+    commands.addCommand(CommandIDs.debugNotebook, {
+      label: 'Launch',
+      isEnabled: () => {
+        const debuggerModel = getModel();
+        return (debuggerModel &&
+          debuggerModel.session !== null &&
+          debuggerModel.session.isStarted) as boolean;
+      },
+      execute: async () => {
+        const debuggerModel = getModel();
+        await debuggerModel.service.launch(debuggerModel.codeValue.text);
+      }
+    });
+
     commands.addCommand(CommandIDs.changeMode, {
       label: 'Change Mode',
       isEnabled: () => {
@@ -358,10 +374,12 @@ const main: JupyterFrontEndPlugin<IDebugger> = {
     });
 
     if (palette) {
-      palette.addItem({ command: CommandIDs.changeMode, category: 'Debugger' });
-      palette.addItem({ command: CommandIDs.create, category: 'Debugger' });
-      palette.addItem({ command: CommandIDs.start, category: 'Debugger' });
-      palette.addItem({ command: CommandIDs.stop, category: 'Debugger' });
+      const category = 'Debugger';
+      palette.addItem({ command: CommandIDs.changeMode, category });
+      palette.addItem({ command: CommandIDs.create, category });
+      palette.addItem({ command: CommandIDs.start, category });
+      palette.addItem({ command: CommandIDs.stop, category });
+      palette.addItem({ command: CommandIDs.debugNotebook, category });
     }
 
     if (restorer) {

+ 147 - 0
src/service.ts

@@ -0,0 +1,147 @@
+import { DebugSession } from './session';
+
+import { DebugProtocol } from 'vscode-debugprotocol';
+
+import { Debugger } from './debugger';
+
+import { IDebugger } from './tokens';
+
+import { Variables } from './variables';
+
+import { Callstack } from './callstack';
+
+export class DebugService {
+  constructor(session: DebugSession | null, debuggerModel: Debugger.Model) {
+    this.session = session;
+    this._model = debuggerModel;
+  }
+
+  private _session: DebugSession;
+  private _model: Debugger.Model;
+  private frames: Frame[];
+
+  set session(session: DebugSession) {
+    this._session = session;
+  }
+
+  get session() {
+    return this._session;
+  }
+
+  // this will change for after execute cell
+  async launch(code: string): Promise<void> {
+    let threadId: number = 1;
+    this.frames = [];
+    this.session.eventMessage.connect(
+      (sender: DebugSession, event: IDebugger.ISession.Event) => {
+        const eventName = event.event;
+        if (eventName === 'thread') {
+          const msg = event as DebugProtocol.ThreadEvent;
+          threadId = msg.body.threadId;
+        }
+      }
+    );
+
+    const breakpoints: DebugProtocol.SourceBreakpoint[] = this.setBreakpoints();
+    const reply = await this.session.sendRequest('dumpCell', {
+      code
+    });
+
+    await this.session.sendRequest('setBreakpoints', {
+      breakpoints: breakpoints,
+      source: { path: reply.body.sourcePath },
+      sourceModified: false
+    });
+    await this.session.sendRequest('configurationDone', {});
+
+    this.session.client.kernel.requestExecute({ code });
+
+    const stackFrames = await this.getFrames(threadId);
+
+    stackFrames.forEach(async (frame, index) => {
+      const scopes = await this.getScopes(frame);
+      const variables = await this.getVariables(scopes);
+      const values = this.convertScope(scopes, variables);
+      this.frames.push({
+        id: frame.id,
+        scopes: values
+      });
+      if (index === 0) {
+        this._model.sidebar.variables.model.scopes = values;
+      }
+    });
+
+    if (stackFrames) {
+      this._model.sidebar.callstack.model.frames = stackFrames;
+    }
+
+    this._model.sidebar.callstack.model.currentFrameChanged.connect(
+      this.onChangeFrame
+    );
+  }
+
+  onChangeFrame = (_: Callstack.IModel, update: Callstack.IFrame) => {
+    const frame = this.frames.find(ele => ele.id === update.id);
+    if (frame && frame.scopes) {
+      this._model.sidebar.variables.model.scopes = frame.scopes;
+    }
+  };
+
+  getFrames = async (threadId: number) => {
+    const reply = await this.session.sendRequest('stackTrace', {
+      threadId
+    });
+    const stackFrames = reply.body.stackFrames;
+    return stackFrames;
+  };
+
+  getScopes = async (frame: DebugProtocol.StackFrame) => {
+    if (!frame) {
+      return;
+    }
+    const reply = await this.session.sendRequest('scopes', {
+      frameId: frame.id
+    });
+    return reply.body.scopes;
+  };
+
+  getVariables = async (scopes: DebugProtocol.Scope[]) => {
+    if (!scopes || scopes.length === 0) {
+      return;
+    }
+    const reply = await this.session.sendRequest('variables', {
+      variablesReference: scopes[0].variablesReference
+    });
+    return reply.body.variables;
+  };
+
+  setBreakpoints = (): DebugProtocol.SourceBreakpoint[] => {
+    return this._model.sidebar.breakpoints.model.breakpoints.map(breakpoint => {
+      return {
+        line: breakpoint.line
+      };
+    });
+  };
+
+  protected convertScope = (
+    scopes: DebugProtocol.Scope[],
+    variables: DebugProtocol.Variable[]
+  ): Variables.IScope[] => {
+    if (!variables || !scopes) {
+      return;
+    }
+    return scopes.map(scope => {
+      return {
+        name: scope.name,
+        variables: variables.map(variable => {
+          return { ...variable, description: '' };
+        })
+      };
+    });
+  };
+}
+
+export type Frame = {
+  id: number;
+  scopes: Variables.IScope[];
+};

+ 12 - 47
src/variables/body/search.tsx

@@ -76,61 +76,26 @@ class ScopeSearch extends ReactWidget {
   }
 }
 
-const useOutsideClick = (ref: any, callback: any) => {
-  const handleClickOutside = (e: Event) => {
-    if (ref.current && !ref.current.contains(e.target)) {
-      callback();
-    }
-  };
+const ScopeMenuComponent = ({ model }: { model: Variables.IModel }) => {
+  const [scope, setScope] = useState(model.currentScope);
+  const wrapperRef = useRef(null);
 
   useEffect(() => {
-    document.addEventListener('mousedown', handleClickOutside);
+    const updateScopes = (_: Variables.IModel, updates: Variables.IScope[]) => {
+      const scope = !!updates && updates.length > 0 ? updates[0] : null;
+      setScope(scope);
+    };
+    model.scopesChanged.connect(updateScopes);
+
     return () => {
-      document.removeEventListener('mousedown', handleClickOutside);
+      model.scopesChanged.disconnect(updateScopes);
     };
   });
-};
-
-const ScopeMenuComponent = ({ model }: { model: Variables.IModel }) => {
-  const [toggleState, setToggle] = useState(false);
-  const [scope, setScope] = useState(model.currentScope);
-  const wrapperRef = useRef(null);
-  const scopes = model.scopes;
-
-  const onClickOutSide = () => {
-    setToggle(false);
-  };
-
-  const toggle = (e: any) => {
-    setToggle(!toggleState);
-  };
-
-  useOutsideClick(wrapperRef, onClickOutSide);
-
-  const changeScope = (newScope: Variables.IScope) => {
-    if (newScope === scope) {
-      return;
-    }
-    setScope(newScope);
-    model.currentScope = newScope;
-    setToggle(false);
-  };
-
-  const List = (
-    <ul>
-      {scopes.map(scope => (
-        <li key={scope.name} onClick={e => changeScope(scope)}>
-          {scope.name}
-        </li>
-      ))}
-    </ul>
-  );
 
   return (
-    <div onClick={e => toggle(e)} ref={wrapperRef}>
-      <span className="label">{scope.name}</span>
+    <div ref={wrapperRef}>
+      <span className="label">{scope ? scope.name : '-'}</span>
       <span className="fa fa-caret-down"></span>
-      {toggleState ? List : null}
     </div>
   );
 };

+ 47 - 14
src/variables/body/table.tsx

@@ -7,7 +7,7 @@ import { ArrayExt } from '@phosphor/algorithm';
 
 import { Widget, PanelLayout } from '@phosphor/widgets';
 
-import React, { useState } from 'react';
+import React, { useEffect, useState } from 'react';
 
 import { Variables } from '../index';
 
@@ -43,7 +43,7 @@ export class Table extends ReactWidget {
     }
   }
 
-  protected resizeBody(msg: Widget.ResizeMessage): void {
+  resizeBody(msg: Widget.ResizeMessage): void {
     const head = this.getHead();
     const body = this.getBody();
     if (body && head) {
@@ -58,15 +58,34 @@ export class Table extends ReactWidget {
 
 const TableComponent = ({ model }: { model: Variables.IModel }) => {
   const [variables, setVariables] = useState(model.variables);
-  const [variable, TableBody] = useTbody(variables, model.currentVariable);
+  const [longHeader, setLongHeader] = useState('value');
+  const [variable, TableBody] = useTbody(
+    variables,
+    model.currentVariable,
+    longHeader
+  );
 
-  model.variablesChanged.connect((_: any, updates) => {
-    if (ArrayExt.shallowEqual(variables, updates)) {
-      return;
-    }
-    setVariables(updates);
+  useEffect(() => {
+    const updateVariables = (
+      _: Variables.IModel,
+      updates: Variables.IVariable[]
+    ) => {
+      if (ArrayExt.shallowEqual(variables, updates)) {
+        return;
+      }
+      setVariables(updates);
+    };
+    model.variablesChanged.connect(updateVariables);
+
+    return () => {
+      model.variablesChanged.disconnect(updateVariables);
+    };
   });
 
+  const setWidth = (headerName: string): string => {
+    return headerName === longHeader ? '75%' : '25%';
+  };
+
   model.currentVariable = variable;
 
   return (
@@ -74,8 +93,18 @@ const TableComponent = ({ model }: { model: Variables.IModel }) => {
       <table>
         <thead>
           <tr>
-            <th style={{ width: '25%' }}>Name</th>
-            <th style={{ width: '75%' }}>Value</th>
+            <th
+              onClick={() => setLongHeader('name')}
+              style={{ width: setWidth('name') }}
+            >
+              Name
+            </th>
+            <th
+              onClick={() => setLongHeader('value')}
+              style={{ width: setWidth('value') }}
+            >
+              Value
+            </th>
           </tr>
         </thead>
       </table>
@@ -84,13 +113,17 @@ const TableComponent = ({ model }: { model: Variables.IModel }) => {
   );
 };
 
-const useTbody = (items: Array<any>, defaultState: any) => {
+const useTbody = (items: Array<any>, defaultState: any, header: any) => {
   const [state, setState] = useState(defaultState);
 
   const setClassIcon = (typeOf: string) => {
     return typeOf === 'class' ? 'jp-ClassIcon' : 'jp-VariableIcon';
   };
 
+  const setWidth = (headerName: string): string => {
+    return headerName === header ? '75%' : '25%';
+  };
+
   const List = () => (
     <div style={{ overflow: 'auto' }}>
       <table>
@@ -101,13 +134,13 @@ const useTbody = (items: Array<any>, defaultState: any) => {
               onClick={e => setState(item)}
               className={state === item ? ' selected' : ''}
             >
-              <td style={{ paddingLeft: `${12}px`, width: `${25}%` }}>
+              <td style={{ paddingLeft: `${12}px`, width: setWidth('name') }}>
                 <span
-                  className={`jp-Icon jp-Icon-16 ${setClassIcon(item.value)}`}
+                  className={`jp-Icon jp-Icon-16 ${setClassIcon(item.type)}`}
                 ></span>
                 {item.name}
               </td>
-              <td style={{ paddingLeft: `${12}px`, width: `${75}%` }}>
+              <td style={{ paddingLeft: `${12}px`, width: setWidth('value') }}>
                 {item.value}
               </td>
             </tr>

+ 21 - 82
src/variables/index.ts

@@ -13,7 +13,7 @@ export class Variables extends Panel {
   constructor(options: Variables.IOptions = {}) {
     super();
 
-    this.model = new Variables.IModel(MOCK_DATA_ROW.scopes);
+    this.model = new Variables.IModel();
     this.addClass('jp-DebuggerVariables');
     this.title.label = 'Variables';
 
@@ -54,9 +54,9 @@ export namespace Variables {
   export interface IModel {}
 
   export class IModel implements IModel {
-    constructor(model: IScope[]) {
+    constructor(model?: IScope[] | null) {
       this._state = model;
-      this._currentScope = this._state[0];
+      this._currentScope = !!this._state ? this._state[0] : null;
     }
 
     get currentScope(): IScope {
@@ -68,13 +68,18 @@ export namespace Variables {
         return;
       }
       this._currentScope = value;
-      this._variablesChanged.emit(value.variables);
+      const variables = !!value ? value.variables : [];
+      this._variablesChanged.emit(variables);
     }
 
     get currentChanged(): ISignal<this, IVariable> {
       return this._currentChanged;
     }
 
+    get scopesChanged(): ISignal<this, IScope[]> {
+      return this._scopesChanged;
+    }
+
     get currentVariable(): IVariable {
       return this._currentVariable;
     }
@@ -94,19 +99,28 @@ export namespace Variables {
         return;
       }
       this._filterState = value;
-      this._variablesChanged.emit(this._filterVariables());
+      if (this._currentScope) {
+        this._variablesChanged.emit(this._filterVariables());
+      }
     }
 
     get scopes(): IScope[] {
       return this._state;
     }
 
+    set scopes(scopes: IScope[]) {
+      this._state = scopes;
+      this._scopesChanged.emit(scopes);
+      this.currentScope = !!scopes ? scopes[0] : null;
+    }
+
     get variables(): IVariable[] {
       if (this._filterState) {
         return this._filterVariables();
       }
-      return this._currentScope.variables;
+      return this._currentScope ? this._currentScope.variables : [];
     }
+
     set variables(variables: IVariable[]) {
       this._currentScope.variables = variables;
     }
@@ -134,83 +148,8 @@ export namespace Variables {
     private _filterState: string = '';
     protected _state: IScope[];
     private _currentScope: IScope;
+    private _scopesChanged = new Signal<this, IScope[]>(this);
   }
 
   export interface IOptions extends Panel.IOptions {}
 }
-
-const MOCK_DATA_ROW = {
-  scopes: [
-    {
-      name: 'local',
-      variables: [
-        {
-          name: 'test 1',
-          value: 'function()',
-          type: 'function',
-          variablesReference: 0,
-          description: 'def test1(): return 0'
-        },
-        {
-          name: 'Classtest',
-          value: 'class',
-          type: 'class',
-          variablesReference: 1,
-          description: 'def test2(): return 0'
-        },
-        {
-          name: 'test 3',
-          value: 'function()',
-          type: 'function',
-          variablesReference: 0,
-          description: 'def test1(): return 0'
-        },
-        {
-          name: 'test 4',
-          value: 'function()',
-          type: 'function',
-          variablesReference: 0,
-          description: 'def test2(): return 0'
-        },
-        {
-          name: 'test 5',
-          value: 'function()',
-          type: 'function',
-          variablesReference: 0,
-          description: 'def test1(): return 0'
-        },
-        {
-          name: 'test 6',
-          value: 'function()',
-          type: 'function',
-          variablesReference: 0,
-          description: 'def test2(): return 0'
-        }
-      ]
-    },
-    {
-      name: 'global',
-      variables: [
-        {
-          name: 'exampleGlobal',
-          value: 'function()',
-          type: 'function',
-          variablesReference: 0,
-          description: 'def exampleGlobal(): return 0'
-        }
-      ] as Variables.IVariable[]
-    },
-    {
-      name: 'built-in',
-      variables: [
-        {
-          name: 'exmapleBuiltIn',
-          value: 'function()',
-          type: 'function',
-          variablesReference: 0,
-          description: 'def texmapleBuiltIn(): return 0'
-        }
-      ] as Variables.IVariable[]
-    }
-  ]
-};