index.ts 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. // Copyright (c) Jupyter Development Team.
  2. // Distributed under the terms of the Modified BSD License.
  3. import {
  4. Widget
  5. } from '@phosphor/widgets';
  6. import {
  7. JupyterLab, JupyterLabPlugin
  8. } from '../application';
  9. import {
  10. COMPLETER_ACTIVE_CLASS, CompleterModel,
  11. CompleterWidget, CompletionHandler, ICompletionManager
  12. } from '../completer';
  13. import {
  14. IConsoleTracker
  15. } from '../console';
  16. import {
  17. INotebookTracker
  18. } from '../notebook';
  19. /**
  20. * The command IDs used by the completer plugin.
  21. */
  22. namespace CommandIDs {
  23. export
  24. const invoke = 'completer:invoke';
  25. export
  26. const invokeConsole = 'completer:invoke-console';
  27. export
  28. const invokeNotebook = 'completer:invoke-notebook';
  29. export
  30. const select = 'completer:select';
  31. export
  32. const selectConsole = 'completer:select-console';
  33. export
  34. const selectNotebook = 'completer:select-notebook';
  35. }
  36. /**
  37. * A service providing code completion for editors.
  38. */
  39. const service: JupyterLabPlugin<ICompletionManager> = {
  40. id: 'jupyter.services.completer',
  41. autoStart: true,
  42. provides: ICompletionManager,
  43. activate: (app: JupyterLab): ICompletionManager => {
  44. const handlers: { [id: string]: CompletionHandler } = {};
  45. app.commands.addCommand(CommandIDs.invoke, {
  46. execute: args => {
  47. let id = args && (args['id'] as string);
  48. if (!id) {
  49. return;
  50. }
  51. const handler = handlers[id];
  52. if (handler) {
  53. handler.invoke();
  54. }
  55. }
  56. });
  57. app.commands.addCommand(CommandIDs.select, {
  58. execute: args => {
  59. let id = args && (args['id'] as string);
  60. if (!id) {
  61. return;
  62. }
  63. const handler = handlers[id];
  64. if (handler) {
  65. handler.completer.selectActive();
  66. }
  67. }
  68. });
  69. return {
  70. register: (completable: ICompletionManager.ICompletable): ICompletionManager.ICompletableAttributes => {
  71. const { editor, kernel, parent } = completable;
  72. const model = new CompleterModel();
  73. const completer = new CompleterWidget({ editor, model });
  74. const handler = new CompletionHandler({ completer, kernel });
  75. const id = parent.id;
  76. // Hide the widget when it first loads.
  77. completer.hide();
  78. // Associate the handler with the parent widget.
  79. handlers[id] = handler;
  80. // Set the handler's editor.
  81. handler.editor = editor;
  82. // Attach the completer widget.
  83. Widget.attach(completer, document.body);
  84. // Listen for parent disposal.
  85. parent.disposed.connect(() => {
  86. delete handlers[id];
  87. model.dispose();
  88. completer.dispose();
  89. handler.dispose();
  90. });
  91. return handler;
  92. }
  93. };
  94. }
  95. };
  96. /**
  97. * An extension that registers consoles for code completion.
  98. */
  99. const consolePlugin: JupyterLabPlugin<void> = {
  100. id: 'jupyter.extensions.console-completer',
  101. requires: [ICompletionManager, IConsoleTracker],
  102. autoStart: true,
  103. activate: (app: JupyterLab, manager: ICompletionManager, consoles: IConsoleTracker): void => {
  104. // Create a handler for each console that is created.
  105. consoles.widgetAdded.connect((sender, panel) => {
  106. const anchor = panel.console;
  107. const cell = anchor.prompt;
  108. const editor = cell && cell.editor;
  109. const kernel = anchor.session.kernel;
  110. const parent = panel;
  111. const handler = manager.register({ editor, kernel, parent });
  112. // Listen for prompt creation.
  113. anchor.promptCreated.connect((sender, cell) => {
  114. handler.editor = cell && cell.editor;
  115. });
  116. // Listen for kernel changes.
  117. anchor.session.kernelChanged.connect((sender, kernel) => {
  118. handler.kernel = kernel;
  119. });
  120. });
  121. // Add console completer invoke command.
  122. app.commands.addCommand(CommandIDs.invokeConsole, {
  123. execute: () => {
  124. const id = consoles.currentWidget && consoles.currentWidget.id;
  125. if (!id) {
  126. return;
  127. }
  128. return app.commands.execute(CommandIDs.invoke, { id });
  129. }
  130. });
  131. // Add console completer select command.
  132. app.commands.addCommand(CommandIDs.selectConsole, {
  133. execute: () => {
  134. const id = consoles.currentWidget && consoles.currentWidget.id;
  135. if (!id) {
  136. return;
  137. }
  138. return app.commands.execute(CommandIDs.select, { id });
  139. }
  140. });
  141. // Set enter key for console completer select command.
  142. app.commands.addKeyBinding({
  143. command: CommandIDs.selectConsole,
  144. keys: ['Enter'],
  145. selector: `.jp-ConsolePanel .${COMPLETER_ACTIVE_CLASS}`
  146. });
  147. }
  148. };
  149. /**
  150. * An extension that registers notebooks for code completion.
  151. */
  152. const notebookPlugin: JupyterLabPlugin<void> = {
  153. id: 'jupyter.extensions.notebook-completer',
  154. requires: [ICompletionManager, INotebookTracker],
  155. autoStart: true,
  156. activate: (app: JupyterLab, manager: ICompletionManager, notebooks: INotebookTracker): void => {
  157. // Create a handler for each notebook that is created.
  158. notebooks.widgetAdded.connect((sender, panel) => {
  159. const cell = panel.notebook.activeCell;
  160. const editor = cell && cell.editor;
  161. const kernel = panel.kernel;
  162. const parent = panel;
  163. const handler = manager.register({ editor, kernel, parent });
  164. // Listen for active cell changes.
  165. panel.notebook.activeCellChanged.connect((sender, cell) => {
  166. handler.editor = cell && cell.editor;
  167. });
  168. // Listen for kernel changes.
  169. panel.kernelChanged.connect((sender, kernel) => {
  170. handler.kernel = kernel;
  171. });
  172. });
  173. // Add notebook completer command.
  174. app.commands.addCommand(CommandIDs.invokeNotebook, {
  175. execute: () => {
  176. const id = notebooks.currentWidget && notebooks.currentWidget.id;
  177. return app.commands.execute(CommandIDs.invoke, { id });
  178. }
  179. });
  180. // Add notebook completer select command.
  181. app.commands.addCommand(CommandIDs.selectNotebook, {
  182. execute: () => {
  183. const id = notebooks.currentWidget && notebooks.currentWidget.id;
  184. if (!id) {
  185. return;
  186. }
  187. return app.commands.execute(CommandIDs.select, { id });
  188. }
  189. });
  190. // Set enter key for notebook completer select command.
  191. app.commands.addKeyBinding({
  192. command: CommandIDs.selectNotebook,
  193. keys: ['Enter'],
  194. selector: `.jp-Notebook .${COMPLETER_ACTIVE_CLASS}`
  195. });
  196. }
  197. };
  198. /**
  199. * Export the plugins as default.
  200. */
  201. const plugins: JupyterLabPlugin<any>[] = [
  202. service, consolePlugin, notebookPlugin
  203. ];
  204. export default plugins;