index.ts 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. /*-----------------------------------------------------------------------------
  2. | Copyright (c) Jupyter Development Team.
  3. | Distributed under the terms of the Modified BSD License.
  4. |----------------------------------------------------------------------------*/
  5. import {
  6. CodeEditor,
  7. CodeEditorWrapper,
  8. IEditorMimeTypeService,
  9. IEditorServices
  10. } from '@jupyterlab/codeeditor';
  11. import { find } from '@phosphor/algorithm';
  12. import { ISignal, Signal } from '@phosphor/signaling';
  13. import { TabPanel } from '@phosphor/widgets';
  14. import { Callstack } from '../callstack';
  15. import { Debugger } from '../debugger';
  16. import { IDebugger } from '../tokens';
  17. export class DebuggerEditors extends TabPanel {
  18. constructor(options: DebuggerEditors.IOptions) {
  19. super();
  20. this.tabsMovable = true;
  21. this.tabBar.insertBehavior = 'select-tab';
  22. this.model = new DebuggerEditors.IModel();
  23. this.debuggerModel = options.model;
  24. this.debuggerService = options.service;
  25. this.editorFactory = options.editorServices.factoryService.newInlineEditor;
  26. this.mimeTypeService = options.editorServices.mimeTypeService;
  27. this.debuggerModel.callstackModel.currentFrameChanged.connect(
  28. this.onCurrentFrameChanged,
  29. this
  30. );
  31. this.model.editorAdded.connect((sender, data) => {
  32. this.openEditor(data);
  33. });
  34. this.model.editors.forEach(editor => this.openEditor(editor));
  35. this.addClass('jp-DebuggerEditors');
  36. }
  37. /**
  38. * The debugger editors model.
  39. */
  40. model: DebuggerEditors.IModel;
  41. /**
  42. * Dispose the debug editors.
  43. */
  44. dispose(): void {
  45. if (this.isDisposed) {
  46. return;
  47. }
  48. Signal.clearData(this);
  49. }
  50. private async onCurrentFrameChanged(
  51. _: Callstack.Model,
  52. frame: Callstack.IFrame
  53. ) {
  54. if (!frame) {
  55. return;
  56. }
  57. const path = frame.source.path;
  58. const source = await this.debuggerService.getSource({
  59. sourceReference: 0,
  60. path
  61. });
  62. if (!source.success) {
  63. return;
  64. }
  65. const { content, mimeType } = source.body;
  66. this.model.addEditor({
  67. path,
  68. code: content,
  69. mimeType: mimeType || this.mimeTypeService.getMimeTypeByFilePath(path)
  70. });
  71. }
  72. private openEditor(data: DebuggerEditors.IEditor) {
  73. const { path, mimeType, code } = data;
  74. const tab = find(this.tabBar.titles, title => title.label === path);
  75. if (tab) {
  76. this.tabBar.currentTitle = tab;
  77. return;
  78. }
  79. let editor = new CodeEditorWrapper({
  80. model: new CodeEditor.Model({
  81. value: code,
  82. mimeType: mimeType
  83. }),
  84. factory: this.editorFactory,
  85. config: {
  86. readOnly: true,
  87. lineNumbers: true
  88. }
  89. });
  90. editor.title.label = path;
  91. editor.title.caption = path;
  92. editor.title.closable = true;
  93. this.tabBar.tabCloseRequested.connect((_, tab) => {
  94. const widget = tab.title.owner;
  95. widget.dispose();
  96. this.model.removeEditor(tab.title.label);
  97. });
  98. this.addWidget(editor);
  99. }
  100. private debuggerModel: Debugger.Model;
  101. private debuggerService: IDebugger;
  102. private editorFactory: CodeEditor.Factory;
  103. private mimeTypeService: IEditorMimeTypeService;
  104. }
  105. /**
  106. * A namespace for `DebuggerEditors` statics.
  107. */
  108. export namespace DebuggerEditors {
  109. /**
  110. * The options used to create a DebuggerEditors.
  111. */
  112. export interface IOptions {
  113. service: IDebugger;
  114. model: Debugger.Model;
  115. editorServices: IEditorServices;
  116. }
  117. /**
  118. * An interface for read only editors.
  119. */
  120. export interface IEditor {
  121. path: string;
  122. code: string;
  123. mimeType: string;
  124. }
  125. export interface IModel {}
  126. export class IModel implements IModel {
  127. /**
  128. * A signal emitted when a new editor is added.
  129. */
  130. get editorAdded(): ISignal<
  131. DebuggerEditors.IModel,
  132. DebuggerEditors.IEditor
  133. > {
  134. return this._editorAdded;
  135. }
  136. /**
  137. * Get all the editors currently opened.
  138. */
  139. get editors() {
  140. return this._state;
  141. }
  142. /**
  143. * Add a new editor to the editor TabPanel.
  144. * @param editor The read-only editor info to add.
  145. */
  146. addEditor(editor: DebuggerEditors.IEditor) {
  147. this._state.set(editor.path, editor);
  148. this._editorAdded.emit(editor);
  149. }
  150. /**
  151. * Remove an editor from the TabPanel.
  152. * @param path The path for the editor.
  153. */
  154. removeEditor(path: string) {
  155. this._state.delete(path);
  156. }
  157. private _state = new Map<string, DebuggerEditors.IEditor>();
  158. private _editorAdded = new Signal<this, DebuggerEditors.IEditor>(this);
  159. }
  160. }