Repository: elm-tooling/elm-language-server
Pull request #423 (2020-12-29 03:33:21)

Use onDidCreateFiles instead of onWillCreateFiles so that it works


Patch:
diff --git a/src/capabilityCalculator.ts b/src/capabilityCalculator.ts
index bff7fcc..43f22b1 100644
--- a/src/capabilityCalculator.ts
+++ b/src/capabilityCalculator.ts
@@ -42,7 +42,7 @@ export class CapabilityCalculator {
       workspaceSymbolProvider: true,
       workspace: {
         fileOperations: {
-          willCreate: {
+          didCreate: {
             filters: [
               {
                 scheme: "file",
diff --git a/src/providers/handlers/fileEventsHandler.ts b/src/providers/handlers/fileEventsHandler.ts
index e2d2430..12e3175 100644
--- a/src/providers/handlers/fileEventsHandler.ts
+++ b/src/providers/handlers/fileEventsHandler.ts
@@ -34,12 +34,12 @@ export class FileEventsHandler {
     this.connection = container.resolve<Connection>("Connection");
     this.astProvider = container.resolve(ASTProvider);
 
-    this.connection.workspace.onWillCreateFiles((params: CreateFilesParams) => {
+    this.connection.workspace.onDidCreateFiles((params: CreateFilesParams) => {
       const edit: WorkspaceEdit = { changes: {} };
       for (const { uri } of params.files) {
         const changes = new ElmWorkspaceMatcher(({ uri }: FileCreate) =>
           URI.parse(uri),
-        ).handle(this.onWillCreateFile.bind(this))({
+        ).handle(this.onDidCreateFile.bind(this))({
           uri,
         });
 
@@ -47,7 +47,8 @@ export class FileEventsHandler {
           edit.changes[uri] = changes;
         }
       }
-      return edit;
+
+      void this.connection.workspace.applyEdit(edit);
     });
 
     this.connection.workspace.onWillRenameFiles((params: RenameFilesParams) => {
@@ -80,7 +81,7 @@ export class FileEventsHandler {
     });
   }
 
-  private onWillCreateFile({
+  private onDidCreateFile({
     uri,
     program,
   }: ICreateFileParams): TextEdit[] | undefined {
diff --git a/src/util/types/recordFieldReferenceTable.ts b/src/util/types/recordFieldReferenceTable.ts
index e5637b4..cf72f66 100644
--- a/src/util/types/recordFieldReferenceTable.ts
+++ b/src/util/types/recordFieldReferenceTable.ts
@@ -1,36 +1,35 @@
 import { SyntaxNode } from "web-tree-sitter";
 import { EFieldType } from "./expressionTree";
-import { SyntaxNodeSet } from "./syntaxNodeSet";
 
 export class RecordFieldReferenceTable {
-  private refsByField: Map<string, SyntaxNodeSet>;
+  private refsByField: Map<string, SyntaxNode[]>;
   private _frozen = false;
 
   public get frozen(): boolean {
     return this._frozen;
   }
 
-  constructor(refsByField?: Map<string, SyntaxNodeSet>) {
-    this.refsByField = refsByField ?? new Map<string, SyntaxNodeSet>();
+  constructor(refsByField?: Map<string, SyntaxNode[]>) {
+    this.refsByField = refsByField ?? new Map<string, SyntaxNode[]>();
   }
 
   public static fromExpressions(
     fieldExpressions: EFieldType[],
   ): RecordFieldReferenceTable {
-    const fieldRefs: Map<string, SyntaxNodeSet> = new Map<
+    const fieldRefs: Map<string, SyntaxNode[]> = new Map<
       string,
-      SyntaxNodeSet
+      SyntaxNode[]
     >();
 
     fieldExpressions.forEach((field) => {
-      fieldRefs.set(field.name, new SyntaxNodeSet(field));
+      fieldRefs.set(field.name, [field]);
     });
 
     return new RecordFieldReferenceTable(fieldRefs);
   }
 
   public get(field: string): SyntaxNode[] {
-    return this.refsByField.get(field)?.toArray() ?? [];
+    return this.refsByField.get(field) ?? [];
   }
 
   public addAll(other: RecordFieldReferenceTable): void {
@@ -42,26 +41,20 @@ export class RecordFieldReferenceTable {
       let set = this.refsByField.get(field);
 
       if (!set) {
-        set = new SyntaxNodeSet();
-        this.refsByField.set(field, set);
+        this.refsByField.set(field, []);
+        set = this.refsByField.get(field) ?? [];
       }
 
-      set.addAll(refs);
+      set.push(...refs);
     });
   }
 
   public plus(other: RecordFieldReferenceTable): RecordFieldReferenceTable {
-    const newRefs = new Map<string, SyntaxNodeSet>();
+    const newRefs = new Map<string, SyntaxNode[]>();
 
     this.refsByField.forEach((set, field) => {
-      const newRefSet = new SyntaxNodeSet().addAll(set);
-      const otherSet = other.refsByField.get(field);
-
-      if (otherSet) {
-        newRefSet.addAll(otherSet);
-      }
-
-      newRefs.set(field, newRefSet);
+      const otherSet = other.refsByField.get(field) ?? [];
+      newRefs.set(field, [...set, ...otherSet]);
     });
     other.refsByField.forEach((set, field) => {
       if (!newRefs.get(field)) {
diff --git a/src/util/types/syntaxNodeSet.ts b/src/util/types/syntaxNodeSet.ts
deleted file mode 100644
index e83f65c..0000000
--- a/src/util/types/syntaxNodeSet.ts
+++ /dev/null
@@ -1,50 +0,0 @@
-import { SyntaxNode } from "web-tree-sitter";
-
-export class SyntaxNodeSet<K extends SyntaxNode = SyntaxNode> {
-  private map = new Map<number, K>();
-
-  constructor(...items: K[]) {
-    items.forEach((value) => {
-      this.add(value);
-    });
-  }
-  public get size(): number {
-    return this.map.size;
-  }
-
-  public add(value: K): this {
-    this.map.set(value.id, value);
-    return this;
-  }
-
-  public clear(): void {
-    this.map.clear();
-  }
-
-  public delete(value: K): boolean {
-    return this.map.delete(value.id);
-  }
-
-  public forEach(callbackfn: (value: K) => void): void {
-    this.map.forEach((value) => {
-      callbackfn(value);
-    });
-  }
-
-  public has(value: K): boolean {
-    return this.map.has(value.id);
-  }
-
-  public values(): IterableIterator<K> {
-    return this.map.values();
-  }
-
-  public toArray(): K[] {
-    return Array.from(this.values());
-  }
-
-  public addAll(other: SyntaxNodeSet<K>): this {
-    other.forEach((value) => this.add(value));
-    return this;
-  }
-}


Test patch:
diff --git a/test/diagnosticTests/elmDiagnostics.test.ts b/test/diagnosticTests/elmDiagnostics.test.ts
index b023e56..889fa7b 100644
--- a/test/diagnosticTests/elmDiagnostics.test.ts
+++ b/test/diagnosticTests/elmDiagnostics.test.ts
@@ -18,12 +18,11 @@ import { baseUri, SourceTreeParser } from "../utils/sourceTreeParser";
 
 const basicsSources = `
 --@ Basics.elm
-module Basics exposing ((+), (|>), (>>), (==), Int, Float, Bool(..), Order(..), negate)
+module Basics exposing ((+), (|>), (==), Int, Float, Bool(..), Order(..))
 
 infix left  0 (|>) = apR
 infix non   4 (==) = eq
 infix left  6 (+)  = add
-infix right 9 (>>) = composeR
 
 type Int = Int
 
@@ -43,15 +42,7 @@ eq : a -> a -> Bool
 eq =
   Elm.Kernel.Utils.equal
 
-composeR : (a -> b) -> (b -> c) -> (a -> c)
-composeR f g x =
-  g (f x)
-
 type Order = LT | EQ | GT
-
-negate : number -> number
-negate n =
-  -n
 `;
 describe("test elm diagnostics", () => {
   const treeParser = new SourceTreeParser();
@@ -228,59 +219,4 @@ field =
   `;
     await testTypeInference(basicsSources + source, []);
   });
-
-  test("field references accessed in complex ways", async () => {
-    const source = `
---@ Test.elm
-module Test exposing (..)
-
-type alias TopChart a comparable =
-    { toValue : a -> Int
-    , items : List a
-    , toValueLabel : a -> Int
-    , toLabel : a -> Int
-    , sorter : a -> comparable
-    , filter : a -> Bool
-    }
-
-
-topChart : List { name : Int, amount : Int } -> TopChart { name : Int, amount : Int } Int
-topChart items =
-    default
-        { toValue = .amount
-        , items = items
-        }
-        |> withSorter (.amount >> negate)
-        |> withFilter (.amount >> (\\x -> x > 0))
-
-
-default : { toValue : a -> Int, items : List a } -> TopChart a Int
-default { toValue, items } =
-    { toValue = toValue
-    , items = items
-    , toValueLabel = \\_ -> 1
-    , toLabel = toValue
-    , sorter = toValue
-    , filter = \\_ -> True
-    }
-
-
-withSorter : (a -> comparable2) -> TopChart a comparable -> TopChart a comparable2
-withSorter sorter chart =
-    { toValue = chart.toValue
-    , items = chart.items
-    , toValueLabel = chart.toValueLabel
-    , toLabel = chart.toLabel
-    , sorter = sorter
-    , filter = chart.filter
-    }
-
-
-withFilter : (a -> Bool) -> TopChart a comparable -> TopChart a comparable
-withFilter filter chart =
-    { chart | filter = filter }
-    `;
-
-    await testTypeInference(basicsSources + source, []);
-  });
 });
diff --git a/test/fileEventsHandler.test.ts b/test/fileEventsHandler.test.ts
index a8a0f64..6a9466a 100644
--- a/test/fileEventsHandler.test.ts
+++ b/test/fileEventsHandler.test.ts
@@ -7,6 +7,7 @@ import {
   CreateFilesParams,
   DeleteFilesParams,
   HandlerResult,
+  NotificationHandler,
   Position,
   Range,
   RenameFilesParams,
@@ -23,11 +24,7 @@ import { baseUri, SourceTreeParser } from "./utils/sourceTreeParser";
 describe("fileEventsHandler", () => {
   const treeParser = new SourceTreeParser();
 
-  let createFilesHandler: RequestHandler<
-    CreateFilesParams,
-    WorkspaceEdit | null,
-    never
-  >;
+  let createFilesHandler: NotificationHandler<CreateFilesParams>;
   let renameFilesHandler: RequestHandler<
     RenameFilesParams,
     WorkspaceEdit | null,
@@ -38,13 +35,21 @@ describe("fileEventsHandler", () => {
     WorkspaceEdit | null,
     never
   >;
+  let appliedWorkspaceEdit: WorkspaceEdit;
 
   container.register("Connection", {
     useValue: mockDeep<Connection>({
       workspace: {
-        onWillCreateFiles: (handler) => (createFilesHandler = handler),
+        onDidCreateFiles: (handler) => (createFilesHandler = handler),
         onWillRenameFiles: (handler) => (renameFilesHandler = handler),
         onWillDeleteFiles: (handler) => (deleteFilesHandler = handler),
+        applyEdit: (edit) => {
+          if (WorkspaceEdit.is(edit)) {
+            appliedWorkspaceEdit = edit;
+          }
+
+          return Promise.resolve({ applied: true });
+        },
       },
     }),
   });
@@ -95,9 +100,9 @@ describe("fileEventsHandler", () => {
   it("handles file create event", async () => {
     await createProgram("");
     const newPath = uri("New/Module.elm");
-    const result = createFilesHandler({ files: [{ uri: newPath }] }, token);
+    createFilesHandler({ files: [{ uri: newPath }] });
 
-    const edit = await getEditFromResult(result);
+    const edit = appliedWorkspaceEdit;
 
     if (!edit.changes) {
       fail();
@@ -122,12 +127,9 @@ describe("fileEventsHandler", () => {
     await createProgram("");
     const newPath = uri("New/Module.elm");
     const newPath2 = uri("New/Another/Module.elm");
-    const result = createFilesHandler(
-      { files: [{ uri: newPath }, { uri: newPath2 }] },
-      token,
-    );
+    createFilesHandler({ files: [{ uri: newPath }, { uri: newPath2 }] });
 
-    const edit = await getEditFromResult(result);
+    const edit = appliedWorkspaceEdit;
 
     if (!edit.changes) {
       fail();