Browse Source

Backport PR #11540: Allow to link factory to file type when adding it (#11940)

Co-authored-by: Frédéric Collonval <fcollonval@users.noreply.github.com>
MeeseeksMachine 3 years ago
parent
commit
49aca2f67c
2 changed files with 165 additions and 12 deletions
  1. 51 12
      packages/docregistry/src/registry.ts
  2. 114 0
      packages/docregistry/test/registry.spec.ts

+ 51 - 12
packages/docregistry/src/registry.ts

@@ -278,14 +278,21 @@ export class DocumentRegistry implements IDisposable {
   /**
    * Add a file type to the document registry.
    *
-   * @params fileType - The file type object to register.
+   * @param fileType - The file type object to register.
+   * @param factories - Optional factories to use for the file type.
    *
    * @returns A disposable which will unregister the command.
    *
    * #### Notes
    * These are used to populate the "Create New" dialog.
+   *
+   * If no default factory exists for the file type, the first factory will
+   * be defined as default factory.
    */
-  addFileType(fileType: Partial<DocumentRegistry.IFileType>): IDisposable {
+  addFileType(
+    fileType: Partial<DocumentRegistry.IFileType>,
+    factories?: string[]
+  ): IDisposable {
     const value: DocumentRegistry.IFileType = {
       ...DocumentRegistry.getFileTypeDefaults(this.translator),
       ...fileType,
@@ -294,6 +301,29 @@ export class DocumentRegistry implements IDisposable {
     };
     this._fileTypes.push(value);
 
+    // Add the filetype to the factory - filetype mapping
+    //  We do not change the factory itself
+    if (factories) {
+      const fileTypeName = value.name.toLowerCase();
+      factories
+        .map(factory => factory.toLowerCase())
+        .forEach(factory => {
+          if (!this._widgetFactoriesForFileType[fileTypeName]) {
+            this._widgetFactoriesForFileType[fileTypeName] = [];
+          }
+          if (
+            !this._widgetFactoriesForFileType[fileTypeName].includes(factory)
+          ) {
+            this._widgetFactoriesForFileType[fileTypeName].push(factory);
+          }
+        });
+      if (!this._defaultWidgetFactories[fileTypeName]) {
+        this._defaultWidgetFactories[
+          fileTypeName
+        ] = this._widgetFactoriesForFileType[fileTypeName][0];
+      }
+    }
+
     this._changed.emit({
       type: 'fileType',
       name: value.name,
@@ -301,6 +331,21 @@ export class DocumentRegistry implements IDisposable {
     });
     return new DisposableDelegate(() => {
       ArrayExt.removeFirstOf(this._fileTypes, value);
+      if (factories) {
+        const fileTypeName = value.name.toLowerCase();
+        for (const name of factories.map(factory => factory.toLowerCase())) {
+          ArrayExt.removeFirstOf(
+            this._widgetFactoriesForFileType[fileTypeName],
+            name
+          );
+        }
+        if (
+          this._defaultWidgetFactories[fileTypeName] ===
+          factories[0].toLowerCase()
+        ) {
+          delete this._defaultWidgetFactories[fileTypeName];
+        }
+      }
       this._changed.emit({
         type: 'fileType',
         name: fileType.name,
@@ -665,17 +710,11 @@ export class DocumentRegistry implements IDisposable {
     // Then look by extension name, starting with the longest
     let ext = Private.extname(name);
     while (ext.length > 1) {
-      ft = find(
-        this._fileTypes,
-        ft =>
-          ft.extensions
-            // In Private.extname, the extension is transformed to lower case
-            .map(extension => extension.toLowerCase())
-            .indexOf(ext) !== -1
+      const ftSubset = this._fileTypes.filter(ft =>
+        // In Private.extname, the extension is transformed to lower case
+        ft.extensions.map(extension => extension.toLowerCase()).includes(ext)
       );
-      if (ft) {
-        fts.push(ft);
-      }
+      fts.push(...ftSubset);
       ext = '.' + ext.split('.').slice(2).join('.');
     }
     return fts;

+ 114 - 0
packages/docregistry/test/registry.spec.ts

@@ -229,6 +229,109 @@ describe('docregistry/registry', () => {
         disposable.dispose();
         expect(registry.fileTypes().next()!.name).toBe(fileType.name);
       });
+
+      it('should add a file type to some factories', () => {
+        registry = new DocumentRegistry({ initialFileTypes: [] });
+        const factory = createFactory();
+        registry.addWidgetFactory(factory);
+        const gFactory = new WidgetFactory({
+          name: 'global',
+          fileTypes: ['*'],
+          defaultFor: ['*']
+        });
+        registry.addWidgetFactory(gFactory);
+
+        expect(registry.defaultWidgetFactory('dummy.test').name).toEqual(
+          gFactory.name
+        );
+
+        const fileType = { name: 'test-file', extensions: ['.test'] };
+        registry.addFileType(fileType, [factory.name]);
+        expect(registry.defaultWidgetFactory('dummy.test').name).toEqual(
+          factory.name
+        );
+      });
+
+      it('should add a file type to some factories without changing the default', () => {
+        const factory = createFactory();
+        registry.addWidgetFactory(factory);
+        const gFactory = new WidgetFactory({
+          name: 'global',
+          fileTypes: ['*'],
+          defaultFor: ['*']
+        });
+        registry.addWidgetFactory(gFactory);
+
+        expect(registry.defaultWidgetFactory('dummy.foo.bar').name).toEqual(
+          factory.name
+        );
+
+        const newFactory = new WidgetFactory({
+          name: 'new-factory',
+          fileTypes: ['new-foobar']
+        });
+        registry.addWidgetFactory(newFactory);
+
+        const fileType = { name: 'test-file', extensions: ['.foo.bar'] };
+        registry.addFileType(fileType, [newFactory.name]);
+
+        expect(registry.defaultWidgetFactory('dummy.foo.bar').name).toEqual(
+          factory.name
+        );
+        expect(
+          registry.preferredWidgetFactories('dummy.foo.bar').map(f => f.name)
+        ).toContain(newFactory.name);
+      });
+
+      it('should remove the link to factory when disposed', () => {
+        registry = new DocumentRegistry({ initialFileTypes: [] });
+        const factory = createFactory();
+        registry.addWidgetFactory(factory);
+        const gFactory = new WidgetFactory({
+          name: 'global',
+          fileTypes: ['*'],
+          defaultFor: ['*']
+        });
+        registry.addWidgetFactory(gFactory);
+
+        const fileType = { name: 'test-file', extensions: ['.test'] };
+        const disposable = registry.addFileType(fileType, [factory.name]);
+
+        disposable.dispose();
+
+        expect(registry.defaultWidgetFactory('dummy.test').name).toBe(
+          gFactory.name
+        );
+      });
+
+      it('should remove the link to factory when disposed without changing the default', () => {
+        const factory = createFactory();
+        registry.addWidgetFactory(factory);
+        const gFactory = new WidgetFactory({
+          name: 'global',
+          fileTypes: ['*'],
+          defaultFor: ['*']
+        });
+        registry.addWidgetFactory(gFactory);
+
+        const newFactory = new WidgetFactory({
+          name: 'new-factory',
+          fileTypes: ['new-foobar']
+        });
+        registry.addWidgetFactory(newFactory);
+
+        const fileType = { name: 'test-file', extensions: ['.foo.bar'] };
+        const disposable = registry.addFileType(fileType, [newFactory.name]);
+
+        disposable.dispose();
+
+        expect(registry.defaultWidgetFactory('dummy.foo.bar').name).toEqual(
+          factory.name
+        );
+        expect(
+          registry.preferredWidgetFactories('dummy.foo.bar').map(f => f.name)
+        ).not.toContain(newFactory.name);
+      });
     });
 
     describe('#preferredWidgetFactories()', () => {
@@ -671,6 +774,17 @@ describe('docregistry/registry', () => {
         const ft2 = registry.getFileTypesForPath('foo/bar/baz.temp');
         expect(ft2[0].name).toBe('test');
       });
+
+      it('should returns all file types', () => {
+        registry.addFileType({
+          name: 'test',
+          extensions: ['.foo.bar']
+        });
+
+        const ft = registry.getFileTypesForPath('foo/bar/test.foo.bar');
+        expect(ft.length).toBeGreaterThanOrEqual(2);
+        expect(ft.map(f => f.name)).toContain('test');
+      });
     });
   });
 });