diff --git a/lib/next_ls.ex b/lib/next_ls.ex index 4f252eac..98465641 100644 --- a/lib/next_ls.ex +++ b/lib/next_ls.ex @@ -10,6 +10,7 @@ defmodule NextLS do alias GenLSP.Notifications.TextDocumentDidChange alias GenLSP.Notifications.TextDocumentDidOpen alias GenLSP.Notifications.TextDocumentDidSave + alias GenLSP.Notifications.WorkspaceDidChangeWatchedFiles alias GenLSP.Notifications.WorkspaceDidChangeWorkspaceFolders alias GenLSP.Requests.Initialize alias GenLSP.Requests.Shutdown @@ -17,6 +18,7 @@ defmodule NextLS do alias GenLSP.Requests.TextDocumentDocumentSymbol alias GenLSP.Requests.TextDocumentFormatting alias GenLSP.Requests.WorkspaceSymbol + alias GenLSP.Structures.DidChangeWatchedFilesParams alias GenLSP.Structures.DidChangeWorkspaceFoldersParams alias GenLSP.Structures.DidOpenTextDocumentParams alias GenLSP.Structures.InitializeParams @@ -283,6 +285,25 @@ defmodule NextLS do ) end + nil = + GenLSP.request(lsp, %GenLSP.Requests.ClientRegisterCapability{ + id: System.unique_integer([:positive]), + params: %GenLSP.Structures.RegistrationParams{ + registrations: [ + %GenLSP.Structures.Registration{ + id: "file-watching", + method: "workspace/didChangeWatchedFiles", + register_options: %GenLSP.Structures.DidChangeWatchedFilesRegistrationOptions{ + watchers: + for ext <- ~W|ex exs leex eex heex sface| do + %GenLSP.Structures.FileSystemWatcher{kind: 7, glob_pattern: "**/*.#{ext}"} + end + } + } + ] + } + }) + GenLSP.log(lsp, "[NextLS] Booting runtimes...") for %{uri: uri, name: name} <- lsp.assigns.workspace_folders do @@ -435,6 +456,28 @@ defmodule NextLS do {:noreply, lsp} end + def handle_notification(%WorkspaceDidChangeWatchedFiles{params: %DidChangeWatchedFilesParams{changes: changes}}, lsp) do + type = GenLSP.Enumerations.FileChangeType.deleted() + + # TODO + # ✅ delete from documents + # ✅ delete all references that occur in this file + # ✅ delete all symbols from that file + lsp = + for %{type: ^type, uri: uri} <- changes, reduce: lsp do + lsp -> + dispatch(lsp.assigns.registry, :symbol_tables, fn entries -> + for {pid, _} <- entries do + SymbolTable.remove(pid, uri) + end + end) + + update_in(lsp.assigns.documents, &Map.drop(&1, [uri])) + end + + {:noreply, lsp} + end + def handle_notification(%Exit{}, lsp) do System.halt(lsp.assigns.exit_code) diff --git a/lib/next_ls/document_symbol.ex b/lib/next_ls/document_symbol.ex index 430fbbba..9d3f7e2b 100644 --- a/lib/next_ls/document_symbol.ex +++ b/lib/next_ls/document_symbol.ex @@ -1,5 +1,6 @@ defmodule NextLS.DocumentSymbol do @moduledoc false + alias GenLSP.Structures.DocumentSymbol alias GenLSP.Structures.Position alias GenLSP.Structures.Range diff --git a/lib/next_ls/symbol_table.ex b/lib/next_ls/symbol_table.ex index 249f2c67..09484d38 100644 --- a/lib/next_ls/symbol_table.ex +++ b/lib/next_ls/symbol_table.ex @@ -16,6 +16,8 @@ defmodule NextLS.SymbolTable do } end + @type uri :: String.t() + def start_link(args) do GenServer.start_link(__MODULE__, Keyword.take(args, [:path, :workspace, :registry]), Keyword.take(args, [:name])) end @@ -26,6 +28,9 @@ defmodule NextLS.SymbolTable do @spec put_reference(pid() | atom(), map()) :: :ok def put_reference(server, reference), do: GenServer.cast(server, {:put_reference, reference}) + @spec remove(pid() | atom(), uri()) :: :ok + def remove(server, uri), do: GenServer.cast(server, {:remove, uri}) + @spec symbols(pid() | atom()) :: list(struct()) def symbols(server), do: GenServer.call(server, :symbols) @@ -170,4 +175,13 @@ defmodule NextLS.SymbolTable do {:noreply, state} end + + def handle_cast({:remove, uri}, %{table: symbol_table, reference_table: reference_table} = state) do + file = URI.parse(uri).path + + :dets.select_delete(symbol_table, [{{:_, %{file: :"$1"}}, [], [{:==, :"$1", file}]}]) + :dets.select_delete(reference_table, [{{{:"$1", :_}, :_}, [], [{:==, :"$1", file}]}]) + + {:noreply, state} + end end diff --git a/mix.exs b/mix.exs index 67285d49..da06e9a7 100644 --- a/mix.exs +++ b/mix.exs @@ -34,7 +34,7 @@ defmodule NextLS.MixProject do # Run "mix help deps" to learn about dependencies. defp deps do [ - {:gen_lsp, "~> 0.4"}, + {:gen_lsp, "~> 0.5"}, {:styler, "~> 0.8", only: :dev}, {:ex_doc, ">= 0.0.0", only: :dev}, {:dialyxir, ">= 0.0.0", only: [:dev, :test], runtime: false} diff --git a/mix.lock b/mix.lock index f0b54fab..4c33c383 100644 --- a/mix.lock +++ b/mix.lock @@ -3,14 +3,14 @@ "earmark_parser": {:hex, :earmark_parser, "1.4.32", "fa739a0ecfa34493de19426681b23f6814573faee95dfd4b4aafe15a7b5b32c6", [:mix], [], "hexpm", "b8b0dd77d60373e77a3d7e8afa598f325e49e8663a51bcc2b88ef41838cca755"}, "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"}, "ex_doc": {:hex, :ex_doc, "0.29.4", "6257ecbb20c7396b1fe5accd55b7b0d23f44b6aa18017b415cb4c2b91d997729", [:mix], [{:earmark_parser, "~> 1.4.31", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "2c6699a737ae46cb61e4ed012af931b57b699643b24dabe2400a8168414bc4f5"}, - "gen_lsp": {:hex, :gen_lsp, "0.4.0", "e07e3c35890ae91ee624c5e2e888cef70bb046a8884b09675c33233d19d2ec1d", [:mix], [{:jason, "~> 1.3", [hex: :jason, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.5 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:schematic, "~> 0.2", [hex: :schematic, repo: "hexpm", optional: false]}, {:typed_struct, "~> 0.3.0", [hex: :typed_struct, repo: "hexpm", optional: false]}], "hexpm", "71e7ecd1295a9ba8c07659bc2241d3839ac97d5b1ffc0a86b8a2e08b09609079"}, + "gen_lsp": {:hex, :gen_lsp, "0.5.0", "463d25c2b81f64b95667e1e6fa9bf2a4ed00896f5e9abe2965bc50edeebae747", [:mix], [{:jason, "~> 1.3", [hex: :jason, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.5 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:schematic, "~> 0.2.1", [hex: :schematic, repo: "hexpm", optional: false]}, {:typed_struct, "~> 0.3.0", [hex: :typed_struct, repo: "hexpm", optional: false]}], "hexpm", "6d40e2315bd2206cb0e40e93c5d58b28ab15787214fea1066f6561df783ef7c9"}, "jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"}, "makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"}, "makeup_elixir": {:hex, :makeup_elixir, "0.16.1", "cc9e3ca312f1cfeccc572b37a09980287e243648108384b97ff2b76e505c3555", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "e127a341ad1b209bd80f7bd1620a15693a9908ed780c3b763bccf7d200c767c6"}, "makeup_erlang": {:hex, :makeup_erlang, "0.1.1", "3fcb7f09eb9d98dc4d208f49cc955a34218fc41ff6b84df7c75b3e6e533cc65f", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "174d0809e98a4ef0b3309256cbf97101c6ec01c4ab0b23e926a9e17df2077cbb"}, "nimble_options": {:hex, :nimble_options, "1.0.2", "92098a74df0072ff37d0c12ace58574d26880e522c22801437151a159392270e", [:mix], [], "hexpm", "fd12a8db2021036ce12a309f26f564ec367373265b53e25403f0ee697380f1b8"}, "nimble_parsec": {:hex, :nimble_parsec, "1.3.1", "2c54013ecf170e249e9291ed0a62e5832f70a476c61da16f6aac6dca0189f2af", [:mix], [], "hexpm", "2682e3c0b2eb58d90c6375fc0cc30bc7be06f365bf72608804fb9cffa5e1b167"}, - "schematic": {:hex, :schematic, "0.2.0", "ac710efbd98b8f4b3d137f8ebac6f9a17da917bb4d1296b487ac4157fb74c806", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d4bc93bac2e7d04869fd6ced9df82c092c154fc648677512bc7c75d9a2655be3"}, + "schematic": {:hex, :schematic, "0.2.1", "0b091df94146fd15a0a343d1bd179a6c5a58562527746dadd09477311698dbb1", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "0b255d65921e38006138201cd4263fd8bb807d9dfc511074615cd264a571b3b1"}, "styler": {:hex, :styler, "0.8.1", "f3c0f65023e4bfbf7e7aa752d128b8475fdabfd30f96ee7314b84480cc56e788", [:mix], [], "hexpm", "1aa48d3aa689a639289af3d8254d40e068e98c083d6e5e3d1a695e71a147b344"}, "telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"}, "typed_struct": {:hex, :typed_struct, "0.3.0", "939789e3c1dca39d7170c87f729127469d1315dcf99fee8e152bb774b17e7ff7", [:mix], [], "hexpm", "c50bd5c3a61fe4e198a8504f939be3d3c85903b382bde4865579bc23111d1b6d"}, diff --git a/priv/monkey/_next_ls_private_compiler.ex b/priv/monkey/_next_ls_private_compiler.ex index d46af52e..e50ebbbd 100644 --- a/priv/monkey/_next_ls_private_compiler.ex +++ b/priv/monkey/_next_ls_private_compiler.ex @@ -129,7 +129,14 @@ defmodule :_next_ls_private_compiler do # --no-compile, so nothing was compiled, but the # task was not re-enabled it seems Mix.Task.rerun("deps.loadpaths") - Mix.Task.rerun("compile", ["--no-protocol-consolidation", "--return-errors", "--tracer", "NextLSPrivate.Tracer"]) + + Mix.Task.rerun("compile", [ + "--ignore-module-conflict", + "--no-protocol-consolidation", + "--return-errors", + "--tracer", + "NextLSPrivate.Tracer" + ]) rescue e -> {:error, e} end diff --git a/test/next_ls_test.exs b/test/next_ls_test.exs index 708f694e..bc597ffd 100644 --- a/test/next_ls_test.exs +++ b/test/next_ls_test.exs @@ -62,6 +62,7 @@ defmodule NextLSTest do test "responds correctly to a shutdown request", %{client: client} do assert :ok == notify(client, %{method: "initialized", jsonrpc: "2.0", params: %{}}) + assert_request(client, "client/registerCapability", fn _params -> nil end) assert_notification "window/logMessage", %{"message" => "[NextLS] Runtime for folder my_proj is ready..."} @@ -78,12 +79,8 @@ defmodule NextLSTest do test "returns method not found for unimplemented requests", %{client: client} do id = System.unique_integer([:positive]) - assert :ok == - notify(client, %{ - method: "initialized", - jsonrpc: "2.0", - params: %{} - }) + assert :ok == notify(client, %{method: "initialized", jsonrpc: "2.0", params: %{}}) + assert_request(client, "client/registerCapability", fn _params -> nil end) assert :ok == request(client, %{ @@ -120,12 +117,8 @@ defmodule NextLSTest do end test "publishes diagnostics once the client has initialized", %{client: client, cwd: cwd} do - assert :ok == - notify(client, %{ - method: "initialized", - jsonrpc: "2.0", - params: %{} - }) + assert :ok == notify(client, %{method: "initialized", jsonrpc: "2.0", params: %{}}) + assert_request(client, "client/registerCapability", fn _params -> nil end) assert_notification "window/logMessage", %{ "message" => "[NextLS] NextLS v" <> _, @@ -181,12 +174,8 @@ defmodule NextLSTest do end test "formats", %{client: client, cwd: cwd} do - assert :ok == - notify(client, %{ - method: "initialized", - jsonrpc: "2.0", - params: %{} - }) + assert :ok == notify(client, %{method: "initialized", jsonrpc: "2.0", params: %{}}) + assert_request(client, "client/registerCapability", fn _params -> nil end) notify client, %{ method: "textDocument/didOpen", @@ -260,12 +249,8 @@ defmodule NextLSTest do end test "formatting gracefully handles files with syntax errors", %{client: client, cwd: cwd} do - assert :ok == - notify(client, %{ - method: "initialized", - jsonrpc: "2.0", - params: %{} - }) + assert :ok == notify(client, %{method: "initialized", jsonrpc: "2.0", params: %{}}) + assert_request(client, "client/registerCapability", fn _params -> nil end) notify client, %{ method: "textDocument/didOpen", @@ -308,12 +293,8 @@ defmodule NextLSTest do end test "workspace symbols", %{client: client, cwd: cwd} do - assert :ok == - notify(client, %{ - method: "initialized", - jsonrpc: "2.0", - params: %{} - }) + assert :ok == notify(client, %{method: "initialized", jsonrpc: "2.0", params: %{}}) + assert_request(client, "client/registerCapability", fn _params -> nil end) assert_notification "window/logMessage", %{"message" => "[NextLS] Runtime for folder my_proj is ready..."} assert_notification "window/logMessage", %{"message" => "[NextLS] Compiled!"} @@ -403,12 +384,8 @@ defmodule NextLSTest do end test "workspace symbols with query", %{client: client, cwd: cwd} do - assert :ok == - notify(client, %{ - method: "initialized", - jsonrpc: "2.0", - params: %{} - }) + assert :ok == notify(client, %{method: "initialized", jsonrpc: "2.0", params: %{}}) + assert_request(client, "client/registerCapability", fn _params -> nil end) assert_notification "window/logMessage", %{"message" => "[NextLS] Runtime for folder my_proj is ready..."} assert_notification "window/logMessage", %{"message" => "[NextLS] Compiled!"} @@ -461,6 +438,57 @@ defmodule NextLSTest do } ] == symbols end + + test "deletes symbols when a file is deleted", %{client: client, cwd: cwd} do + assert :ok == notify(client, %{method: "initialized", jsonrpc: "2.0", params: %{}}) + assert_request(client, "client/registerCapability", fn _params -> nil end) + + assert_notification "window/logMessage", %{"message" => "[NextLS] Runtime for folder my_proj is ready..."} + assert_notification "window/logMessage", %{"message" => "[NextLS] Compiled!"} + + request client, %{method: "workspace/symbol", id: 2, jsonrpc: "2.0", params: %{query: ""}} + + symbol = %{ + "kind" => 2, + "location" => %{ + "range" => %{ + "start" => %{ + "line" => 3, + "character" => 0 + }, + "end" => %{ + "line" => 3, + "character" => 0 + } + }, + "uri" => "file://#{cwd}/my_proj/lib/code_action.ex" + }, + "name" => "defmodule Foo.CodeAction.NestedMod" + } + + assert_result 2, symbols + + assert symbol in symbols + + notify(client, %{ + method: "workspace/didChangeWatchedFiles", + jsonrpc: "2.0", + params: %{ + changes: [ + %{ + type: GenLSP.Enumerations.FileChangeType.deleted(), + uri: "file://#{Path.join(cwd, "my_proj/lib/code_action.ex")}" + } + ] + } + }) + + request client, %{method: "workspace/symbol", id: 3, jsonrpc: "2.0", params: %{query: ""}} + + assert_result 3, symbols + + assert symbol not in symbols + end end describe "function go to definition" do @@ -515,12 +543,8 @@ defmodule NextLSTest do setup :with_lsp test "go to local function definition", %{client: client, bar: bar} do - assert :ok == - notify(client, %{ - method: "initialized", - jsonrpc: "2.0", - params: %{} - }) + assert :ok == notify(client, %{method: "initialized", jsonrpc: "2.0", params: %{}}) + assert_request(client, "client/registerCapability", fn _params -> nil end) assert_notification "window/logMessage", %{"message" => "[NextLS] Runtime for folder my_proj is ready..."} assert_notification "window/logMessage", %{"message" => "[NextLS] Compiled!"} @@ -553,12 +577,8 @@ defmodule NextLSTest do end test "go to imported function definition", %{client: client, bar: bar, imported: imported} do - assert :ok == - notify(client, %{ - method: "initialized", - jsonrpc: "2.0", - params: %{} - }) + assert :ok == notify(client, %{method: "initialized", jsonrpc: "2.0", params: %{}}) + assert_request(client, "client/registerCapability", fn _params -> nil end) assert_notification "window/logMessage", %{"message" => "[NextLS] Runtime for folder my_proj is ready..."} assert_notification "window/logMessage", %{"message" => "[NextLS] Compiled!"} @@ -593,12 +613,8 @@ defmodule NextLSTest do end test "go to remote function definition", %{client: client, bar: bar, remote: remote} do - assert :ok == - notify(client, %{ - method: "initialized", - jsonrpc: "2.0", - params: %{} - }) + assert :ok == notify(client, %{method: "initialized", jsonrpc: "2.0", params: %{}}) + assert_request(client, "client/registerCapability", fn _params -> nil end) assert_notification "window/logMessage", %{"message" => "[NextLS] Runtime for folder my_proj is ready..."} assert_notification "window/logMessage", %{"message" => "[NextLS] Compiled!"} @@ -694,12 +710,8 @@ defmodule NextLSTest do setup :with_lsp test "go to local macro definition", %{client: client, bar: bar} do - assert :ok == - notify(client, %{ - method: "initialized", - jsonrpc: "2.0", - params: %{} - }) + assert :ok == notify(client, %{method: "initialized", jsonrpc: "2.0", params: %{}}) + assert_request(client, "client/registerCapability", fn _params -> nil end) assert_notification "window/logMessage", %{"message" => "[NextLS] Compiled!"} @@ -731,12 +743,8 @@ defmodule NextLSTest do end test "go to imported macro definition", %{client: client, bar: bar, imported: imported} do - assert :ok == - notify(client, %{ - method: "initialized", - jsonrpc: "2.0", - params: %{} - }) + assert :ok == notify(client, %{method: "initialized", jsonrpc: "2.0", params: %{}}) + assert_request(client, "client/registerCapability", fn _params -> nil end) assert_notification "window/logMessage", %{"message" => "[NextLS] Runtime for folder my_proj is ready..."} assert_notification "window/logMessage", %{"message" => "[NextLS] Compiled!"} @@ -771,12 +779,8 @@ defmodule NextLSTest do end test "go to remote macro definition", %{client: client, bar: bar, remote: remote} do - assert :ok == - notify(client, %{ - method: "initialized", - jsonrpc: "2.0", - params: %{} - }) + assert :ok == notify(client, %{method: "initialized", jsonrpc: "2.0", params: %{}}) + assert_request(client, "client/registerCapability", fn _params -> nil end) assert_notification "window/logMessage", %{"message" => "[NextLS] Runtime for folder my_proj is ready..."} assert_notification "window/logMessage", %{"message" => "[NextLS] Compiled!"} @@ -848,6 +852,7 @@ defmodule NextLSTest do test "go to module definition", %{client: client, bar: bar, peace: peace} do assert :ok == notify(client, %{method: "initialized", jsonrpc: "2.0", params: %{}}) + assert_request(client, "client/registerCapability", fn _params -> nil end) assert_notification "window/logMessage", %{"message" => "[NextLS] Runtime for folder my_proj is ready..."} assert_notification "window/logMessage", %{"message" => "[NextLS] Compiled!"} @@ -921,6 +926,7 @@ defmodule NextLSTest do @tag root_paths: ["proj_one"] test "starts a new runtime when you add a workspace folder", %{client: client, cwd: cwd} do assert :ok == notify(client, %{method: "initialized", jsonrpc: "2.0", params: %{}}) + assert_request(client, "client/registerCapability", fn _params -> nil end) assert_notification "window/logMessage", %{"message" => "[NextLS] Runtime for folder proj_one is ready..."} assert_notification "window/logMessage", %{"message" => "[NextLS] Compiled!"} @@ -944,6 +950,7 @@ defmodule NextLSTest do @tag root_paths: ["proj_one", "proj_two"] test "stops the runtime when you remove a workspace folder", %{client: client, cwd: cwd} do assert :ok == notify(client, %{method: "initialized", jsonrpc: "2.0", params: %{}}) + assert_request(client, "client/registerCapability", fn _params -> nil end) assert_notification "window/logMessage", %{"message" => "[NextLS] Runtime for folder proj_one is ready..."} assert_notification "window/logMessage", %{"message" => "[NextLS] Runtime for folder proj_two is ready..."} assert_notification "window/logMessage", %{"message" => "[NextLS] Compiled!"} @@ -966,6 +973,53 @@ defmodule NextLSTest do "message" => "[NextLS] The runtime for proj_two has successfully shutdown." } end + + @tag root_paths: ["proj_one"] + test "can register for workspace/didChangedWatchedFiles", %{client: client} do + assert :ok == notify(client, %{method: "initialized", jsonrpc: "2.0", params: %{}}) + + assert_request(client, "client/registerCapability", fn params -> + assert params == %{ + "registrations" => [ + %{ + "id" => "file-watching", + "method" => "workspace/didChangeWatchedFiles", + "registerOptions" => %{ + "watchers" => [ + %{"kind" => 7, "globPattern" => "**/*.ex"}, + %{"kind" => 7, "globPattern" => "**/*.exs"}, + %{"kind" => 7, "globPattern" => "**/*.leex"}, + %{"kind" => 7, "globPattern" => "**/*.eex"}, + %{"kind" => 7, "globPattern" => "**/*.heex"}, + %{"kind" => 7, "globPattern" => "**/*.sface"} + ] + } + } + ] + } + + nil + end) + + assert_notification "window/logMessage", %{"message" => "[NextLS] Runtime for folder proj_one is ready..."} + assert_notification "window/logMessage", %{"message" => "[NextLS] Compiled!"} + end + + @tag root_paths: ["proj_one"] + test "can receive workspace/didChangeWatchedFiles notification", %{client: client, cwd: cwd} do + assert :ok == notify(client, %{method: "initialized", jsonrpc: "2.0", params: %{}}) + + assert_request(client, "client/registerCapability", fn _params -> nil end) + + assert_notification "window/logMessage", %{"message" => "[NextLS] Runtime for folder proj_one is ready..."} + assert_notification "window/logMessage", %{"message" => "[NextLS] Compiled!"} + + notify(client, %{ + method: "workspace/didChangeWatchedFiles", + jsonrpc: "2.0", + params: %{changes: [%{type: 3, uri: "file://#{Path.join(cwd, "proj_one/lib/peace.ex")}"}]} + }) + end end defp with_lsp(%{tmp_dir: tmp_dir} = context) do