registry.ts 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955
  1. // Copyright (c) Jupyter Development Team.
  2. // Distributed under the terms of the Modified BSD License.
  3. import {
  4. IKernel, Contents, Kernel, Session
  5. } from '@jupyterlab/services';
  6. import {
  7. EmptyIterator, IIterator, each, iter
  8. } from 'phosphor/lib/algorithm/iteration';
  9. import {
  10. find, findIndex, indexOf
  11. } from 'phosphor/lib/algorithm/searching';
  12. import {
  13. Vector
  14. } from 'phosphor/lib/collections/vector';
  15. import {
  16. IDisposable, DisposableDelegate
  17. } from 'phosphor/lib/core/disposable';
  18. import {
  19. ISignal, defineSignal
  20. } from 'phosphor/lib/core/signaling';
  21. import {
  22. Token
  23. } from 'phosphor/lib/core/token';
  24. import {
  25. Widget
  26. } from 'phosphor/lib/ui/widget';
  27. import {
  28. IChangedArgs as IChangedArgsGeneric
  29. } from '../common/interfaces';
  30. /* tslint:disable */
  31. /**
  32. * The document registry token.
  33. */
  34. export
  35. const IDocumentRegistry = new Token<IDocumentRegistry>('jupyter.services.document-registry');
  36. /* tslint:enable */
  37. /**
  38. * The interface for a document registry.
  39. */
  40. export
  41. interface IDocumentRegistry extends DocumentRegistry {}
  42. /**
  43. * The document registry.
  44. */
  45. export
  46. class DocumentRegistry {
  47. /**
  48. * A signal emitted when the registry has changed.
  49. */
  50. readonly changed: ISignal<this, DocumentRegistry.IChangedArgs>;
  51. /**
  52. * Get whether the document registry has been disposed.
  53. */
  54. get isDisposed(): boolean {
  55. return this._widgetFactories === null;
  56. }
  57. /**
  58. * Dispose of the resources held by the document registery.
  59. */
  60. dispose(): void {
  61. if (this.isDisposed) {
  62. return;
  63. }
  64. for (let modelName in this._modelFactories) {
  65. this._modelFactories[modelName].dispose();
  66. }
  67. this._modelFactories = null;
  68. for (let widgetName in this._widgetFactories) {
  69. this._widgetFactories[widgetName].dispose();
  70. }
  71. this._widgetFactories = null;
  72. this._fileTypes.clear();
  73. this._creators.clear();
  74. for (let widgetName in this._extenders) {
  75. this._extenders[widgetName].clear();
  76. }
  77. }
  78. /**
  79. * Add a widget factory to the registry.
  80. *
  81. * @param factory - The factory instance to register.
  82. *
  83. * @returns A disposable which will unregister the factory.
  84. *
  85. * #### Notes
  86. * If a factory with the given `'displayName'` is already registered,
  87. * a warning will be logged, and this will be a no-op.
  88. * If `'*'` is given as a default extension, the factory will be registered
  89. * as the global default.
  90. * If an extension or global default is already registered, this factory
  91. * will override the existing default.
  92. */
  93. addWidgetFactory(factory: DocumentRegistry.IWidgetFactory<Widget, DocumentRegistry.IModel>): IDisposable {
  94. let name = factory.name.toLowerCase();
  95. if (this._widgetFactories[name]) {
  96. console.warn(`Duplicate registered factory ${name}`);
  97. return new DisposableDelegate(null);
  98. }
  99. this._widgetFactories[name] = factory;
  100. for (let ext of factory.defaultFor) {
  101. if (factory.fileExtensions.indexOf(ext) === -1) {
  102. continue;
  103. }
  104. if (ext === '*') {
  105. this._defaultWidgetFactory = name;
  106. } else {
  107. this._defaultWidgetFactories[ext] = name;
  108. }
  109. }
  110. // For convenience, store a mapping of ext -> name
  111. for (let ext of factory.fileExtensions) {
  112. if (!this._widgetFactoryExtensions[ext]) {
  113. this._widgetFactoryExtensions[ext] = new Vector<string>();
  114. }
  115. this._widgetFactoryExtensions[ext].pushBack(name);
  116. }
  117. this.changed.emit({
  118. type: 'widgetFactory',
  119. name,
  120. change: 'added'
  121. });
  122. return new DisposableDelegate(() => {
  123. delete this._widgetFactories[name];
  124. if (this._defaultWidgetFactory === name) {
  125. this._defaultWidgetFactory = '';
  126. }
  127. for (let ext of Object.keys(this._defaultWidgetFactories)) {
  128. if (this._defaultWidgetFactories[ext] === name) {
  129. delete this._defaultWidgetFactories[ext];
  130. }
  131. }
  132. for (let ext of Object.keys(this._widgetFactoryExtensions)) {
  133. this._widgetFactoryExtensions[ext].remove(name);
  134. if (this._widgetFactoryExtensions[ext].length === 0) {
  135. delete this._widgetFactoryExtensions[ext];
  136. }
  137. }
  138. this.changed.emit({
  139. type: 'widgetFactory',
  140. name,
  141. change: 'removed'
  142. });
  143. });
  144. }
  145. /**
  146. * Add a model factory to the registry.
  147. *
  148. * @param factory - The factory instance.
  149. *
  150. * @returns A disposable which will unregister the factory.
  151. *
  152. * #### Notes
  153. * If a factory with the given `name` is already registered, or
  154. * the given factory is already registered, a warning will be logged
  155. * and this will be a no-op.
  156. */
  157. addModelFactory(factory: DocumentRegistry.IModelFactory<DocumentRegistry.IModel>): IDisposable {
  158. let name = factory.name.toLowerCase();
  159. if (this._modelFactories[name]) {
  160. console.warn(`Duplicate registered factory ${name}`);
  161. return new DisposableDelegate(null);
  162. }
  163. this._modelFactories[name] = factory;
  164. this.changed.emit({
  165. type: 'modelFactory',
  166. name,
  167. change: 'added'
  168. });
  169. return new DisposableDelegate(() => {
  170. delete this._modelFactories[name];
  171. this.changed.emit({
  172. type: 'modelFactory',
  173. name,
  174. change: 'removed'
  175. });
  176. });
  177. }
  178. /**
  179. * Add a widget extension to the registry.
  180. *
  181. * @param widgetName - The name of the widget factory.
  182. *
  183. * @param extension - A widget extension.
  184. *
  185. * @returns A disposable which will unregister the extension.
  186. *
  187. * #### Notes
  188. * If the extension is already registered for the given
  189. * widget name, a warning will be logged and this will be a no-op.
  190. */
  191. addWidgetExtension(widgetName: string, extension: DocumentRegistry.IWidgetExtension<Widget, DocumentRegistry.IModel>): IDisposable {
  192. widgetName = widgetName.toLowerCase();
  193. if (!(widgetName in this._extenders)) {
  194. this._extenders[widgetName] = new Vector<DocumentRegistry.IWidgetExtension<Widget, DocumentRegistry.IModel>>();
  195. }
  196. let extenders = this._extenders[widgetName];
  197. let index = indexOf(extenders, extension);
  198. if (index !== -1) {
  199. console.warn(`Duplicate registered extension for ${widgetName}`);
  200. return new DisposableDelegate(null);
  201. }
  202. this._extenders[widgetName].pushBack(extension);
  203. this.changed.emit({
  204. type: 'widgetExtension',
  205. name: null,
  206. change: 'added'
  207. });
  208. return new DisposableDelegate(() => {
  209. this._extenders[widgetName].remove(extension);
  210. this.changed.emit({
  211. type: 'widgetExtension',
  212. name: null,
  213. change: 'removed'
  214. });
  215. });
  216. }
  217. /**
  218. * Add a file type to the document registry.
  219. *
  220. * @params fileType - The file type object to register.
  221. *
  222. * @returns A disposable which will unregister the command.
  223. *
  224. * #### Notes
  225. * These are used to populate the "Create New" dialog.
  226. */
  227. addFileType(fileType: DocumentRegistry.IFileType): IDisposable {
  228. this._fileTypes.pushBack(fileType);
  229. this.changed.emit({
  230. type: 'fileType',
  231. name: fileType.name,
  232. change: 'added'
  233. });
  234. return new DisposableDelegate(() => {
  235. this._fileTypes.remove(fileType);
  236. this.changed.emit({
  237. type: 'fileType',
  238. name: fileType.name,
  239. change: 'removed'
  240. });
  241. });
  242. }
  243. /**
  244. * Add a creator to the registry.
  245. *
  246. * @params creator - The file creator object to register.
  247. *
  248. * @returns A disposable which will unregister the creator.
  249. */
  250. addCreator(creator: DocumentRegistry.IFileCreator): IDisposable {
  251. let index = findIndex(this._creators, (value) => {
  252. return value.name.localeCompare(creator.name) > 0;
  253. });
  254. if (index !== -1) {
  255. this._creators.insert(index, creator);
  256. } else {
  257. this._creators.pushBack(creator);
  258. }
  259. this.changed.emit({
  260. type: 'fileCreator',
  261. name: creator.name,
  262. change: 'added'
  263. });
  264. return new DisposableDelegate(() => {
  265. this._creators.remove(creator);
  266. this.changed.emit({
  267. type: 'fileCreator',
  268. name: creator.name,
  269. change: 'removed'
  270. });
  271. });
  272. }
  273. /**
  274. * Get an iterator over the preferred widget factories.
  275. *
  276. * @param ext - An optional file extension to filter the results.
  277. *
  278. * @returns A new iterator of widget factories.
  279. *
  280. * #### Notes
  281. * Only the widget factories whose associated model factory have
  282. * been registered will be returned.
  283. * The first item is considered the default. The returned iterator
  284. * has widget factories in the following order:
  285. * - extension-specific default factory
  286. * - global default factory
  287. * - all other extension-specific factories
  288. * - all other global factories
  289. */
  290. preferredWidgetFactories(ext: string = '*'): IIterator<DocumentRegistry.IWidgetFactory<Widget, DocumentRegistry.IModel>> {
  291. let factories = new Set<string>();
  292. ext = Private.normalizeExtension(ext);
  293. // Start with the extension-specific default factory.
  294. if (ext.length > 1) {
  295. if (ext in this._defaultWidgetFactories) {
  296. factories.add(this._defaultWidgetFactories[ext]);
  297. }
  298. }
  299. // Add the global default factory.
  300. if (this._defaultWidgetFactory) {
  301. factories.add(this._defaultWidgetFactory);
  302. }
  303. // Add the extension-specific factories in registration order.
  304. if (ext.length > 1) {
  305. if (ext in this._widgetFactoryExtensions) {
  306. each(this._widgetFactoryExtensions[ext], n => {
  307. factories.add(n);
  308. });
  309. }
  310. }
  311. // Add the rest of the global factories, in registration order.
  312. if ('*' in this._widgetFactoryExtensions) {
  313. each(this._widgetFactoryExtensions['*'], n => {
  314. factories.add(n);
  315. });
  316. }
  317. // Construct the return list, checking to make sure the corresponding
  318. // model factories are registered.
  319. let factoryList: DocumentRegistry.IWidgetFactory<Widget, DocumentRegistry.IModel>[] = [];
  320. factories.forEach(name => {
  321. if (this._widgetFactories[name].modelName in this._modelFactories) {
  322. factoryList.push(this._widgetFactories[name]);
  323. }
  324. });
  325. return iter(factoryList);
  326. }
  327. /**
  328. * Create an iterator over the widget factories that have been registered.
  329. *
  330. * @returns A new iterator of widget factories.
  331. */
  332. getWidgetFactories(): IIterator<DocumentRegistry.IWidgetFactory<Widget, DocumentRegistry.IModel>> {
  333. let factories: DocumentRegistry.IWidgetFactory<Widget, DocumentRegistry.IModel>[] = [];
  334. for (let name in this._widgetFactories) {
  335. factories.push(this._widgetFactories[name]);
  336. }
  337. return iter(factories);
  338. }
  339. /**
  340. * Create an iterator over the model factories that have been registered.
  341. *
  342. * @returns A new iterator of model factories.
  343. */
  344. getModelFactories(): IIterator<DocumentRegistry.IModelFactory<DocumentRegistry.IModel>> {
  345. let factories: DocumentRegistry.IModelFactory<DocumentRegistry.IModel>[] = [];
  346. for (let name in this._modelFactories) {
  347. factories.push(this._modelFactories[name]);
  348. }
  349. return iter(factories);
  350. }
  351. /**
  352. * Create an iterator over the registered extensions for a given widget.
  353. *
  354. * @param widgetName - The name of the widget factory.
  355. *
  356. * @returns A new iterator over the widget extensions.
  357. */
  358. getWidgetExtensions(widgetName: string): IIterator<DocumentRegistry.IWidgetExtension<Widget, DocumentRegistry.IModel>> {
  359. widgetName = widgetName.toLowerCase();
  360. if (!(widgetName in this._extenders)) {
  361. return EmptyIterator.instance;
  362. }
  363. return this._extenders[widgetName].iter();
  364. }
  365. /**
  366. * Create an iterator over the file types that have been registered.
  367. *
  368. * @returns A new iterator of file types.
  369. */
  370. getFileTypes(): IIterator<DocumentRegistry.IFileType> {
  371. return this._fileTypes.iter();
  372. }
  373. /**
  374. * Create an iterator over the file creators that have been registered.
  375. *
  376. * @returns A new iterator of file creatores.
  377. */
  378. getCreators(): IIterator<DocumentRegistry.IFileCreator> {
  379. return this._creators.iter();
  380. }
  381. /**
  382. * Get a widget factory by name.
  383. *
  384. * @param widgetName - The name of the widget factory.
  385. *
  386. * @returns A widget factory instance.
  387. */
  388. getWidgetFactory(widgetName: string): DocumentRegistry.IWidgetFactory<Widget, DocumentRegistry.IModel> {
  389. return this._widgetFactories[widgetName.toLowerCase()];
  390. }
  391. /**
  392. * Get a model factory by name.
  393. *
  394. * @param name - The name of the model factory.
  395. *
  396. * @returns A model factory instance.
  397. */
  398. getModelFactory(name: string): DocumentRegistry.IModelFactory<DocumentRegistry.IModel> {
  399. return this._modelFactories[name.toLowerCase()];
  400. }
  401. /**
  402. * Get a file type by name.
  403. */
  404. getFileType(name: string): DocumentRegistry.IFileType {
  405. name = name.toLowerCase();
  406. return find(this._fileTypes, fileType => {
  407. return fileType.name.toLowerCase() === name;
  408. });
  409. }
  410. /**
  411. * Get a creator by name.
  412. */
  413. getCreator(name: string): DocumentRegistry.IFileCreator {
  414. name = name.toLowerCase();
  415. return find(this._creators, creator => {
  416. return creator.name.toLowerCase() === name;
  417. });
  418. }
  419. /**
  420. * Get a kernel preference.
  421. *
  422. * @param ext - The file extension.
  423. *
  424. * @param widgetName - The name of the widget factory.
  425. *
  426. * @returns A kernel preference.
  427. */
  428. getKernelPreference(ext: string, widgetName: string): DocumentRegistry.IKernelPreference {
  429. ext = Private.normalizeExtension(ext);
  430. widgetName = widgetName.toLowerCase();
  431. let widgetFactory = this._widgetFactories[widgetName];
  432. if (!widgetFactory) {
  433. return void 0;
  434. }
  435. let modelFactory = this.getModelFactory(widgetFactory.modelName);
  436. if (!modelFactory) {
  437. return void 0;
  438. }
  439. let language = modelFactory.preferredLanguage(ext);
  440. return {
  441. language,
  442. preferKernel: widgetFactory.preferKernel,
  443. canStartKernel: widgetFactory.canStartKernel
  444. };
  445. }
  446. private _modelFactories: { [key: string]: DocumentRegistry.IModelFactory<DocumentRegistry.IModel> } = Object.create(null);
  447. private _widgetFactories: { [key: string]: DocumentRegistry.IWidgetFactory<Widget, DocumentRegistry.IModel> } = Object.create(null);
  448. private _defaultWidgetFactory = '';
  449. private _defaultWidgetFactories: { [key: string]: string } = Object.create(null);
  450. private _widgetFactoryExtensions: {[key: string]: Vector<string> } = Object.create(null);
  451. private _fileTypes = new Vector<DocumentRegistry.IFileType>();
  452. private _creators = new Vector<DocumentRegistry.IFileCreator>();
  453. private _extenders: { [key: string] : Vector<DocumentRegistry.IWidgetExtension<Widget, DocumentRegistry.IModel>> } = Object.create(null);
  454. }
  455. /**
  456. * The namespace for the `DocumentRegistry` class statics.
  457. */
  458. export
  459. namespace DocumentRegistry {
  460. /**
  461. * The interface for a document model.
  462. */
  463. export
  464. interface IModel extends IDisposable {
  465. /**
  466. * A signal emitted when the document content changes.
  467. */
  468. contentChanged: ISignal<this, void>;
  469. /**
  470. * A signal emitted when the model state changes.
  471. */
  472. stateChanged: ISignal<this, IChangedArgsGeneric<any>>;
  473. /**
  474. * The dirty state of the model.
  475. *
  476. * #### Notes
  477. * This should be cleared when the document is loaded from
  478. * or saved to disk.
  479. */
  480. dirty: boolean;
  481. /**
  482. * The read-only state of the model.
  483. */
  484. readOnly: boolean;
  485. /**
  486. * The default kernel name of the document.
  487. */
  488. readonly defaultKernelName: string;
  489. /**
  490. * The default kernel language of the document.
  491. */
  492. readonly defaultKernelLanguage: string;
  493. /**
  494. * Serialize the model to a string.
  495. */
  496. toString(): string;
  497. /**
  498. * Deserialize the model from a string.
  499. *
  500. * #### Notes
  501. * Should emit a [contentChanged] signal.
  502. */
  503. fromString(value: string): void;
  504. /**
  505. * Serialize the model to JSON.
  506. */
  507. toJSON(): any;
  508. /**
  509. * Deserialize the model from JSON.
  510. *
  511. * #### Notes
  512. * Should emit a [contentChanged] signal.
  513. */
  514. fromJSON(value: any): void;
  515. }
  516. /**
  517. * The document context object.
  518. */
  519. export
  520. interface IContext<T extends IModel> extends IDisposable {
  521. /**
  522. * A signal emitted when the kernel changes.
  523. */
  524. kernelChanged: ISignal<this, IKernel>;
  525. /**
  526. * A signal emitted when the path changes.
  527. */
  528. pathChanged: ISignal<this, string>;
  529. /**
  530. * A signal emitted when the contentsModel changes.
  531. */
  532. fileChanged: ISignal<this, Contents.IModel>;
  533. /**
  534. * A signal emitted when the context is fully populated for the first time.
  535. */
  536. populated: ISignal<this, void>;
  537. /**
  538. * A signal emitted when the context is disposed.
  539. */
  540. disposed: ISignal<this, void>;
  541. /**
  542. * Get the model associated with the document.
  543. */
  544. readonly model: T;
  545. /**
  546. * The current kernel associated with the document.
  547. */
  548. readonly kernel: IKernel;
  549. /**
  550. * The current path associated with the document.
  551. */
  552. readonly path: string;
  553. /**
  554. * The current contents model associated with the document
  555. *
  556. * #### Notes
  557. * The model will have an empty `contents` field.
  558. * It will be `null` until the context is populated.
  559. */
  560. readonly contentsModel: Contents.IModel;
  561. /**
  562. * Get the kernel spec information.
  563. */
  564. readonly kernelspecs: Kernel.ISpecModels;
  565. /**
  566. * Test whether the context is fully populated.
  567. */
  568. readonly isPopulated: boolean;
  569. /**
  570. * Change the current kernel associated with the document.
  571. *
  572. * #### Notes
  573. * If no options are given, the session is shut down.
  574. */
  575. changeKernel(options?: Kernel.IModel): Promise<IKernel>;
  576. /**
  577. * Save the document contents to disk.
  578. */
  579. save(): Promise<void>;
  580. /**
  581. * Save the document to a different path chosen by the user.
  582. */
  583. saveAs(): Promise<void>;
  584. /**
  585. * Revert the document contents to disk contents.
  586. */
  587. revert(): Promise<void>;
  588. /**
  589. * Create a checkpoint for the file.
  590. *
  591. * @returns A promise which resolves with the new checkpoint model when the
  592. * checkpoint is created.
  593. */
  594. createCheckpoint(): Promise<Contents.ICheckpointModel>;
  595. /**
  596. * Delete a checkpoint for the file.
  597. *
  598. * @param checkpointID - The id of the checkpoint to delete.
  599. *
  600. * @returns A promise which resolves when the checkpoint is deleted.
  601. */
  602. deleteCheckpoint(checkpointID: string): Promise<void>;
  603. /**
  604. * Restore the file to a known checkpoint state.
  605. *
  606. * @param checkpointID - The optional id of the checkpoint to restore,
  607. * defaults to the most recent checkpoint.
  608. *
  609. * @returns A promise which resolves when the checkpoint is restored.
  610. */
  611. restoreCheckpoint(checkpointID?: string): Promise<void>;
  612. /**
  613. * List available checkpoints for the file.
  614. *
  615. * @returns A promise which resolves with a list of checkpoint models for
  616. * the file.
  617. */
  618. listCheckpoints(): Promise<Contents.ICheckpointModel[]>;
  619. /**
  620. * Get the list of running sessions.
  621. */
  622. listSessions(): Promise<Session.IModel[]>;
  623. /**
  624. * Resolve a url to a correct server path.
  625. */
  626. resolveUrl(url: string): string;
  627. /**
  628. * Add a sibling widget to the document manager.
  629. *
  630. * @param widget - The widget to add to the document manager.
  631. *
  632. * @returns A disposable used to remove the sibling if desired.
  633. *
  634. * #### Notes
  635. * It is assumed that the widget has the same model and context
  636. * as the original widget.
  637. */
  638. addSibling(widget: Widget): IDisposable;
  639. }
  640. /**
  641. * The interface for a widget factory.
  642. */
  643. export
  644. interface IWidgetFactory<T extends Widget, U extends IModel> extends IDisposable {
  645. /**
  646. * A signal emitted when a widget is created.
  647. */
  648. widgetCreated: ISignal<IWidgetFactory<T, U>, T>;
  649. /**
  650. * The file extensions the widget can view.
  651. *
  652. * #### Notes
  653. * Use "*" to denote all files. Specific file extensions must be preceded
  654. * with '.', like '.png', '.txt', etc.
  655. */
  656. readonly fileExtensions: string[];
  657. /**
  658. * The name of the widget to display in dialogs.
  659. */
  660. readonly name: string;
  661. /**
  662. * The registered name of the model type used to create the widgets.
  663. */
  664. readonly modelName: string;
  665. /**
  666. * The file extensions for which the factory should be the default.
  667. *
  668. * #### Notes
  669. * Use "*" to denote all files. Specific file extensions must be preceded
  670. * with '.', like '.png', '.txt', etc. Entries in this attribute must also
  671. * be included in the fileExtensions attribute.
  672. * The default is an empty array.
  673. *
  674. * **See also:** [[fileExtensions]].
  675. */
  676. readonly defaultFor: string[];
  677. /**
  678. * Whether the widgets prefer having a kernel started.
  679. */
  680. readonly preferKernel: boolean;
  681. /**
  682. * Whether the widgets can start a kernel when opened.
  683. */
  684. readonly canStartKernel: boolean;
  685. /**
  686. * Create a new widget.
  687. *
  688. * #### Notes
  689. * It should emit the [widgetCreated] signal with the new widget.
  690. */
  691. createNew(context: IContext<U>, kernel?: Kernel.IModel): T;
  692. }
  693. /**
  694. * An interface for a widget extension.
  695. */
  696. export
  697. interface IWidgetExtension<T extends Widget, U extends IModel> {
  698. /**
  699. * Create a new extension for a given widget.
  700. */
  701. createNew(widget: T, context: IContext<U>): IDisposable;
  702. }
  703. /**
  704. * The interface for a model factory.
  705. */
  706. export
  707. interface IModelFactory<T extends IModel> extends IDisposable {
  708. /**
  709. * The name of the model.
  710. */
  711. readonly name: string;
  712. /**
  713. * The content type of the file (defaults to `"file"`).
  714. */
  715. readonly contentType: Contents.ContentType;
  716. /**
  717. * The format of the file (defaults to `"text"`).
  718. */
  719. readonly fileFormat: Contents.FileFormat;
  720. /**
  721. * Create a new model for a given path.
  722. *
  723. * @param languagePreference - An optional kernel language preference.
  724. *
  725. * @returns A new document model.
  726. */
  727. createNew(languagePreference?: string): T;
  728. /**
  729. * Get the preferred kernel language given an extension.
  730. */
  731. preferredLanguage(ext: string): string;
  732. }
  733. /**
  734. * A kernel preference for a given file path and widget.
  735. */
  736. export
  737. interface IKernelPreference {
  738. /**
  739. * The preferred kernel language.
  740. */
  741. readonly language: string;
  742. /**
  743. * Whether to prefer having a kernel started when opening.
  744. */
  745. readonly preferKernel: boolean;
  746. /**
  747. * Whether a kernel when can be started when opening.
  748. */
  749. readonly canStartKernel: boolean;
  750. }
  751. /**
  752. * An interface for a file type.
  753. */
  754. export
  755. interface IFileType {
  756. /**
  757. * The name of the file type.
  758. */
  759. readonly name: string;
  760. /**
  761. * The extension of the file type (e.g. `".txt"`).
  762. */
  763. readonly extension: string;
  764. /**
  765. * The optional mimetype of the file type.
  766. */
  767. readonly mimetype?: string;
  768. /**
  769. * The optional icon class to use for the file type.
  770. */
  771. readonly icon?: string;
  772. /**
  773. * The content type of the new file (defaults to `"file"`).
  774. */
  775. readonly contentType?: Contents.ContentType;
  776. /**
  777. * The format of the new file (default to `"text"`).
  778. */
  779. readonly fileFormat?: Contents.FileFormat;
  780. }
  781. /**
  782. * An interface for a "Create New" item.
  783. */
  784. export
  785. interface IFileCreator {
  786. /**
  787. * The name of the file creator.
  788. */
  789. readonly name: string;
  790. /**
  791. * The filetype name associated with the creator.
  792. */
  793. readonly fileType: string;
  794. /**
  795. * The optional widget name.
  796. */
  797. readonly widgetName?: string;
  798. /**
  799. * The optional kernel name.
  800. */
  801. readonly kernelName?: string;
  802. }
  803. /**
  804. * An arguments object for the `changed` signal.
  805. */
  806. export
  807. interface IChangedArgs {
  808. /**
  809. * The type of the changed item.
  810. */
  811. readonly type: 'widgetFactory' | 'modelFactory' | 'widgetExtension' | 'fileCreator' | 'fileType';
  812. /**
  813. * The name of the item.
  814. */
  815. readonly name: string;
  816. /**
  817. * Whether the item was added or removed.
  818. */
  819. readonly change: 'added' | 'removed';
  820. }
  821. }
  822. // Define the signals for the `DocumentRegistry` class.
  823. defineSignal(DocumentRegistry.prototype, 'changed');
  824. /**
  825. * A private namespace for DocumentRegistry data.
  826. */
  827. namespace Private {
  828. /**
  829. * Normalize a file extension to be of the type `'.foo'`.
  830. *
  831. * Adds a leading dot if not present and converts to lower case.
  832. */
  833. export
  834. function normalizeExtension(extension: string): string {
  835. if (extension === '*') {
  836. return extension;
  837. }
  838. if (extension === '.*') {
  839. return '*';
  840. }
  841. if (extension.indexOf('.') !== 0) {
  842. extension = `.${extension}`;
  843. }
  844. return extension.toLowerCase();
  845. }
  846. }