handler.ts 4.8 KB

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