Skip to content

Commit 25dc8f0

Browse files
lukaszsamsonscohen
andauthored
Return LSP 3.17 labelDetails on completion items (#787)
* return LSP 3.17 labelDetails on completion items annotate completions that require alias insertions deprioretize alias insertion fix crash when completing one line source file * Update apps/language_server/lib/language_server/source_file.ex Co-authored-by: Steve Cohen <scohen@scohen.org> * PR fix * deprioretize exceptions Co-authored-by: Steve Cohen <scohen@scohen.org>
1 parent c01d61b commit 25dc8f0

File tree

5 files changed

+143
-51
lines changed

5 files changed

+143
-51
lines changed

apps/language_server/lib/language_server/providers/completion.ex

Lines changed: 68 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
2121
:filter_text,
2222
# Lower priority is shown higher in the result list
2323
:priority,
24+
:label_details,
2425
:tags,
2526
:command,
2627
{:preselect, false},
@@ -304,6 +305,7 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
304305
%{
305306
type: :module,
306307
name: name,
308+
full_name: full_name,
307309
summary: summary,
308310
subtype: subtype,
309311
metadata: metadata,
@@ -317,14 +319,19 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
317319
) do
318320
completion_without_additional_text_edit =
319321
from_completion_item(
320-
%{type: :module, name: name, summary: summary, subtype: subtype, metadata: metadata},
322+
%{
323+
type: :module,
324+
name: name,
325+
full_name: full_name,
326+
summary: summary,
327+
subtype: subtype,
328+
metadata: metadata
329+
},
321330
%{def_before: nil},
322331
options
323332
)
324333

325-
alias_value =
326-
Atom.to_string(required_alias)
327-
|> String.replace_prefix("Elixir.", "")
334+
alias_value = inspect(required_alias)
328335

329336
indentation =
330337
if column_to_insert_alias >= 1,
@@ -333,17 +340,33 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
333340

334341
alias_edit = indentation <> "alias " <> alias_value <> "\n"
335342

343+
label_details =
344+
Map.update!(
345+
completion_without_additional_text_edit.label_details,
346+
"description",
347+
&("alias " <> &1)
348+
)
349+
336350
struct(completion_without_additional_text_edit,
337351
additional_text_edit: %TextEdit{
338352
range: range(line_to_insert_alias, 0, line_to_insert_alias, 0),
339353
newText: alias_edit
340354
},
341-
documentation: alias_value <> "\n" <> summary
355+
documentation: alias_value <> "\n" <> summary,
356+
label_details: label_details,
357+
priority: 24
342358
)
343359
end
344360

345361
defp from_completion_item(
346-
%{type: :module, name: name, summary: summary, subtype: subtype, metadata: metadata},
362+
%{
363+
type: :module,
364+
name: name,
365+
full_name: full_name,
366+
summary: summary,
367+
subtype: subtype,
368+
metadata: metadata
369+
},
347370
%{def_before: nil},
348371
_options
349372
) do
@@ -363,27 +386,38 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
363386
_ -> :module
364387
end
365388

366-
label =
367-
if subtype do
368-
"#{name} (#{subtype})"
369-
else
370-
name
371-
end
389+
label_details = %{
390+
"description" => full_name
391+
}
392+
393+
label_details =
394+
if detail != "module", do: Map.put(label_details, "detail", detail), else: label_details
372395

373396
insert_text =
374397
case name do
375398
":" <> rest -> rest
376399
other -> other
377400
end
378401

402+
priority =
403+
case subtype do
404+
:exception ->
405+
# show exceptions after functions
406+
18
407+
408+
_ ->
409+
14
410+
end
411+
379412
%__MODULE__{
380-
label: label,
413+
label: name,
381414
kind: kind,
382415
detail: detail,
383416
documentation: summary,
384417
insert_text: insert_text,
385418
filter_text: name,
386-
priority: 14,
419+
label_details: label_details,
420+
priority: priority,
387421
tags: metadata_to_tags(metadata)
388422
}
389423
end
@@ -546,8 +580,15 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
546580
_context,
547581
_options
548582
) do
549-
%{name: name, arity: arity, origin: _origin, doc: doc, signature: signature, spec: spec} =
550-
suggestion
583+
%{
584+
name: name,
585+
arity: arity,
586+
args_list: args_list,
587+
origin: origin,
588+
doc: doc,
589+
signature: signature,
590+
spec: spec
591+
} = suggestion
551592

552593
formatted_spec =
553594
if spec != "" do
@@ -564,8 +605,12 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
564605
end
565606

566607
%__MODULE__{
567-
label: signature,
608+
label: name,
568609
detail: "typespec #{signature}",
610+
label_details: %{
611+
"detail" => "(#{Enum.join(args_list, ", ")})",
612+
"description" => if(origin, do: "#{origin}.#{name}/#{arity}", else: "#{name}/#{arity}")
613+
},
569614
documentation: "#{doc}#{formatted_spec}",
570615
insert_text: snippet,
571616
priority: 10,
@@ -952,7 +997,7 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
952997
{name, name}
953998

954999
true ->
955-
label = "#{name}/#{arity}"
1000+
label = name
9561001

9571002
insert_text =
9581003
function_snippet(
@@ -997,6 +1042,10 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
9971042
label: label,
9981043
kind: :function,
9991044
detail: detail,
1045+
label_details: %{
1046+
"detail" => "(#{Enum.join(args_list, ", ")})",
1047+
"description" => "#{origin}.#{name}/#{arity}"
1048+
},
10001049
documentation: summary <> footer,
10011050
insert_text: insert_text,
10021051
priority: 17,
@@ -1044,6 +1093,7 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
10441093
"kind" => completion_kind(item.kind),
10451094
"detail" => item.detail,
10461095
"documentation" => %{"value" => item.documentation || "", kind: "markdown"},
1096+
"labelDetails" => item.label_details,
10471097
"filterText" => item.filter_text,
10481098
"sortText" => String.pad_leading(to_string(idx), 8, "0"),
10491099
"insertText" => item.insert_text,

apps/language_server/lib/language_server/source_file.ex

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -334,10 +334,11 @@ defmodule ElixirLS.LanguageServer.SourceFile do
334334
do: {max(elixir_line - 1, 0), 0}
335335

336336
def elixir_position_to_lsp(urf8_text, {elixir_line, elixir_character}) do
337-
utf16_character =
337+
line =
338338
lines(urf8_text)
339339
|> Enum.at(max(elixir_line - 1, 0))
340-
|> elixir_character_to_lsp(elixir_character)
340+
341+
utf16_character = elixir_character_to_lsp(line || "", elixir_character)
341342

342343
{elixir_line - 1, utf16_character}
343344
end

0 commit comments

Comments
 (0)