Skip to content

Commit e21832b

Browse files
committed
feat: formatting
1 parent fafb2ca commit e21832b

File tree

3 files changed

+112
-8
lines changed

3 files changed

+112
-8
lines changed

lib/next_ls.ex

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,23 @@ defmodule NextLS do
1717
TextDocumentDidSave
1818
}
1919

20-
alias GenLSP.Requests.{Initialize, Shutdown}
20+
alias GenLSP.Requests.{
21+
Initialize,
22+
Shutdown,
23+
TextDocumentFormatting
24+
}
2125

2226
alias GenLSP.Structures.{
2327
DidOpenTextDocumentParams,
2428
InitializeParams,
2529
InitializeResult,
30+
Position,
31+
Range,
2632
SaveOptions,
2733
ServerCapabilities,
2834
TextDocumentItem,
29-
TextDocumentSyncOptions
35+
TextDocumentSyncOptions,
36+
TextEdit
3037
}
3138

3239
alias NextLS.Runtime
@@ -80,12 +87,35 @@ defmodule NextLS do
8087
open_close: true,
8188
save: %SaveOptions{include_text: true},
8289
change: TextDocumentSyncKind.full()
83-
}
90+
},
91+
document_formatting_provider: true
8492
},
8593
server_info: %{name: "NextLS"}
8694
}, assign(lsp, root_uri: root_uri)}
8795
end
8896

97+
def handle_request(%TextDocumentFormatting{params: %{text_document: %{uri: uri}}}, lsp) do
98+
document = lsp.assigns.documents[uri]
99+
100+
working_dir = URI.parse(lsp.assigns.root_uri).path
101+
{opts, _} = Code.eval_file(".formatter.exs", working_dir)
102+
new_document = Code.format_string!(Enum.join(document, "\n"), opts) |> IO.iodata_to_binary()
103+
104+
{:reply,
105+
[
106+
%TextEdit{
107+
new_text: new_document,
108+
range: %Range{
109+
start: %Position{line: 0, character: 0},
110+
end: %Position{
111+
line: length(document),
112+
character: document |> List.last() |> String.length() |> Kernel.-(1) |> max(0)
113+
}
114+
}
115+
}
116+
], lsp}
117+
end
118+
89119
def handle_request(%Shutdown{}, lsp) do
90120
{:reply, nil, assign(lsp, exit_code: 0)}
91121
end
@@ -172,13 +202,21 @@ defmodule NextLS do
172202
{:noreply, lsp}
173203
end
174204

175-
def handle_notification(%TextDocumentDidChange{}, lsp) do
205+
def handle_notification(
206+
%TextDocumentDidChange{
207+
params: %{
208+
text_document: %{uri: uri},
209+
content_changes: [%{text: text}]
210+
}
211+
},
212+
lsp
213+
) do
176214
for task <- Task.Supervisor.children(lsp.assigns.task_supervisor),
177215
task != lsp.assigns.runtime_task.pid do
178216
Process.exit(task, :kill)
179217
end
180218

181-
{:noreply, lsp}
219+
{:noreply, put_in(lsp.assigns.documents[uri], String.split(text, "\n"))}
182220
end
183221

184222
def handle_notification(

lib/next_ls/runtime.ex

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ defmodule NextLS.Runtime do
3333
end
3434

3535
def compile(server) do
36-
GenServer.call(server, :compile)
36+
GenServer.call(server, :compile, :infinity)
3737
end
3838

3939
@impl GenServer
@@ -111,8 +111,6 @@ defmodule NextLS.Runtime do
111111
def handle_call(:compile, _, %{node: node} = state) do
112112
{_, errors} = :rpc.call(node, :_next_ls_private_compiler, :compile, [])
113113

114-
foo = "foo"
115-
116114
Registry.dispatch(state.extension_registry, :extension, fn entries ->
117115
for {pid, _} <- entries do
118116
send(pid, {:compiler, errors})

test/next_ls_test.exs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,4 +181,72 @@ defmodule NextLSTest do
181181
# }
182182
# )
183183
end
184+
185+
test "formats", %{client: client} do
186+
assert :ok ==
187+
notify(client, %{
188+
method: "initialized",
189+
jsonrpc: "2.0",
190+
params: %{}
191+
})
192+
193+
notify client, %{
194+
method: "textDocument/didOpen",
195+
jsonrpc: "2.0",
196+
params: %{
197+
textDocument: %{
198+
uri: "file://lib/foo/bar.ex",
199+
languageId: "elixir",
200+
version: 1,
201+
text: """
202+
defmodule Foo.Bar do
203+
def run() do
204+
205+
206+
:ok
207+
end
208+
end
209+
"""
210+
}
211+
}
212+
}
213+
214+
request client, %{
215+
method: "textDocument/formatting",
216+
id: 2,
217+
jsonrpc: "2.0",
218+
params: %{
219+
textDocument: %{
220+
uri: "file://lib/foo/bar.ex"
221+
},
222+
options: %{
223+
insertSpaces: true,
224+
tabSize: 2
225+
}
226+
}
227+
}
228+
229+
new_text =
230+
"""
231+
defmodule Foo.Bar do
232+
def run() do
233+
:ok
234+
end
235+
end
236+
"""
237+
|> String.trim()
238+
239+
assert_result(
240+
2,
241+
[
242+
%{
243+
"newText" => ^new_text,
244+
"range" => %{
245+
"start" => %{"character" => 0, "line" => 0},
246+
"end" => %{"character" => 0, "line" => 8}
247+
}
248+
}
249+
]
250+
)
251+
end
184252
end

0 commit comments

Comments
 (0)