handler.ts 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. // Copyright (c) Jupyter Development Team.
  2. // Distributed under the terms of the Modified BSD License.
  3. import {
  4. IKernel, KernelMessage
  5. } from 'jupyter-js-services';
  6. import {
  7. IDisposable
  8. } from 'phosphor/lib/core/disposable';
  9. import {
  10. clearSignalData, defineSignal, ISignal
  11. } from 'phosphor/lib/core/signaling';
  12. import {
  13. ICellEditorWidget, ITextChange
  14. } from '../notebook/cells/editor';
  15. import {
  16. BaseCellWidget
  17. } from '../notebook/cells/widget';
  18. import {
  19. RenderMime
  20. } from '../rendermime';
  21. import {
  22. Inspector
  23. } from './';
  24. /**
  25. * An object that handles code inspection.
  26. */
  27. export
  28. class InspectionHandler implements IDisposable, Inspector.IInspectable {
  29. /**
  30. * Construct a new inspection handler for a widget.
  31. */
  32. constructor(rendermime: RenderMime) {
  33. this._rendermime = rendermime;
  34. }
  35. /**
  36. * A signal emitted when the handler is disposed.
  37. */
  38. disposed: ISignal<InspectionHandler, void>;
  39. /**
  40. * A signal emitted when inspector should clear all items with no history.
  41. */
  42. ephemeralCleared: ISignal<InspectionHandler, void>;
  43. /**
  44. * A signal emitted when an inspector value is generated.
  45. */
  46. inspected: ISignal<InspectionHandler, Inspector.IInspectorUpdate>;
  47. /**
  48. * The cell widget used by the inspection handler.
  49. */
  50. get activeCell(): BaseCellWidget {
  51. return this._activeCell;
  52. }
  53. set activeCell(newValue: BaseCellWidget) {
  54. if (newValue === this._activeCell) {
  55. return;
  56. }
  57. if (this._activeCell && !this._activeCell.isDisposed) {
  58. const editor = this._activeCell.editor;
  59. editor.textChanged.disconnect(this.onTextChanged, this);
  60. }
  61. this._activeCell = newValue;
  62. if (this._activeCell) {
  63. // Clear ephemeral inspectors in preparation for a new editor.
  64. this.ephemeralCleared.emit(void 0);
  65. const editor = this._activeCell.editor;
  66. editor.textChanged.connect(this.onTextChanged, this);
  67. }
  68. }
  69. /**
  70. * The kernel used by the inspection handler.
  71. */
  72. get kernel(): IKernel {
  73. return this._kernel;
  74. }
  75. set kernel(value: IKernel) {
  76. this._kernel = value;
  77. }
  78. /**
  79. * Get whether the inspection handler is disposed.
  80. *
  81. * #### Notes
  82. * This is a read-only property.
  83. */
  84. get isDisposed(): boolean {
  85. return this._isDisposed;
  86. }
  87. /**
  88. * Dispose of the resources used by the handler.
  89. */
  90. dispose(): void {
  91. if (this.isDisposed) {
  92. return;
  93. }
  94. this._isDisposed = true;
  95. this._activeCell = null;
  96. this.disposed.emit(void 0);
  97. clearSignalData(this);
  98. }
  99. /**
  100. * Handle a text changed signal from an editor.
  101. *
  102. * #### Notes
  103. * Update the hints inspector based on a text change.
  104. */
  105. protected onTextChanged(editor: ICellEditorWidget, change: ITextChange): void {
  106. let update: Inspector.IInspectorUpdate = {
  107. content: null,
  108. type: 'hints'
  109. };
  110. // Clear hints if the new text value is empty or kernel is unavailable.
  111. if (!change.newValue || !this._kernel) {
  112. this.inspected.emit(update);
  113. return;
  114. }
  115. let contents: KernelMessage.IInspectRequest = {
  116. code: change.newValue,
  117. cursor_pos: change.position,
  118. detail_level: 0
  119. };
  120. let pending = ++this._pending;
  121. this._kernel.inspect(contents).then(msg => {
  122. let value = msg.content;
  123. // If handler has been disposed, bail.
  124. if (this.isDisposed) {
  125. this.inspected.emit(update);
  126. return;
  127. }
  128. // If a newer text change has created a pending request, bail.
  129. if (pending !== this._pending) {
  130. this.inspected.emit(update);
  131. return;
  132. }
  133. // Hint request failures or negative results fail silently.
  134. if (value.status !== 'ok' || !value.found) {
  135. this.inspected.emit(update);
  136. return;
  137. }
  138. let bundle = value.data as RenderMime.MimeMap<string>;
  139. let trusted = true;
  140. let widget = this._rendermime.render({ bundle, trusted });
  141. update.content = widget;
  142. this.inspected.emit(update);
  143. });
  144. }
  145. private _activeCell: BaseCellWidget = null;
  146. private _isDisposed = false;
  147. private _kernel: IKernel = null;
  148. private _pending = 0;
  149. private _rendermime: RenderMime = null;
  150. }
  151. // Define the signals for the `FileBrowserModel` class.
  152. defineSignal(InspectionHandler.prototype, 'ephemeralCleared');
  153. defineSignal(InspectionHandler.prototype, 'disposed');
  154. defineSignal(InspectionHandler.prototype, 'inspected');