Skip to content

Commit d0d8e52

Browse files
committed
Features and bug fixes
* Reworked literal numbering sequence so the first generated object literal is not given a sequence number and subsequent sequence numbers start at 0. * Added the `--only` option to the generator so it can import single types * Added the `--roots` option so the generator can import entire dependency chains. This is very helpful when adding a new request or notification. * Added command line switches to set the proto and types modules * Improved the source code formatting
1 parent 1b7bba6 commit d0d8e52

File tree

15 files changed

+758
-460
lines changed

15 files changed

+758
-460
lines changed

apps/language_server/lib/language_server/experimental/protocol/proto/field.ex

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -152,12 +152,18 @@ defmodule ElixirLS.LanguageServer.Experimental.Protocol.Proto.Field do
152152
end
153153

154154
def encode({:one_of, types}, field_value) do
155-
Enum.reduce_while(types, nil, fn type, _ ->
156-
case encode(type, field_value) do
157-
{:ok, _} = success -> {:halt, success}
158-
error -> {:cont, error}
159-
end
160-
end)
155+
encoded =
156+
Enum.reduce_while(types, nil, fn type, _ ->
157+
case encode(type, field_value) do
158+
{:ok, _} = success -> {:halt, success}
159+
error -> {:cont, error}
160+
end
161+
end)
162+
163+
case encoded do
164+
encoded_list when is_list(encoded_list) -> {:ok, encoded_list}
165+
error -> error
166+
end
161167
end
162168

163169
def encode({:list, list_type}, field_value) when is_list(field_value) do
@@ -221,10 +227,21 @@ defmodule ElixirLS.LanguageServer.Experimental.Protocol.Proto.Field do
221227
end
222228

223229
def encode({:tuple, types}, field_value) when is_tuple(field_value) do
224-
field_value
225-
|> Tuple.to_list()
226-
|> Enum.zip(types)
227-
|> Enum.map(fn {value, type} -> encode(type, value) end)
230+
encoded =
231+
field_value
232+
|> Tuple.to_list()
233+
|> Enum.zip(types)
234+
|> Enum.reduce_while([], fn {value, type}, acc ->
235+
case encode(type, value) do
236+
{:ok, encoded} -> {:cont, [encoded | acc]}
237+
error -> {:halt, error}
238+
end
239+
end)
240+
241+
case encoded do
242+
encoded_list when is_list(encoded_list) -> {:ok, Enum.reverse(encoded_list)}
243+
error -> error
244+
end
228245
end
229246

230247
def encode({:params, param_defs}, field_value) when is_map(field_value) do

apps/language_server/lib/mix/tasks/lsp/data_model.ex

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,17 +36,20 @@ defmodule Mix.Tasks.Lsp.DataModel do
3636
end
3737

3838
def all_types(%__MODULE__{} = data_model) do
39-
data_model.type_aliases
40-
|> Map.merge(data_model.enumerations)
41-
|> Map.merge(data_model.structures)
39+
aliases = Map.values(data_model.type_aliases)
40+
structures = Map.values(data_model.structures)
41+
enumerations = Map.values(data_model.enumerations)
42+
43+
aliases ++ enumerations ++ structures
4244
end
4345

4446
def fetch(%__MODULE__{} = data_model, name) do
4547
field =
4648
case kind(data_model, name) do
47-
:structure -> :structures
48-
:type_alias -> :type_aliases
49-
:enumeration -> :enumerations
49+
{:ok, :structure} -> :structures
50+
{:ok, :type_alias} -> :type_aliases
51+
{:ok, :enumeration} -> :enumerations
52+
:error -> :error
5053
end
5154

5255
data_model
@@ -68,6 +71,29 @@ defmodule Mix.Tasks.Lsp.DataModel do
6871
end
6972
end
7073

74+
def references(%__MODULE__{} = data_model, %{name: name}) do
75+
references(data_model, name)
76+
end
77+
78+
def references(%__MODULE__{} = data_model, roots) do
79+
collect_references(data_model, List.wrap(roots), MapSet.new())
80+
end
81+
82+
defp collect_references(%__MODULE__{}, [], %MapSet{} = references) do
83+
MapSet.to_list(references)
84+
end
85+
86+
defp collect_references(%__MODULE__{} = data_model, [first | rest], %MapSet{} = references) do
87+
with false <- MapSet.member?(references, first),
88+
{:ok, %referred_type{} = referred} <- fetch(data_model, first) do
89+
new_refs = referred_type.references(referred)
90+
collect_references(data_model, rest ++ new_refs, MapSet.put(references, first))
91+
else
92+
_ ->
93+
collect_references(data_model, rest, references)
94+
end
95+
end
96+
7197
defp load_from_meta(root_meta, name, new_fn) do
7298
root_meta
7399
|> Map.get(name)
@@ -78,7 +104,7 @@ defmodule Mix.Tasks.Lsp.DataModel do
78104
end
79105

80106
defp kind(%__MODULE__{} = data_model, name) do
81-
Map.fetch!(data_model.names_to_types, name)
107+
Map.fetch(data_model.names_to_types, name)
82108
end
83109

84110
defp type_name("structures"), do: :structure

apps/language_server/lib/mix/tasks/lsp/data_model/enumeration.ex

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ defmodule Mix.Tasks.Lsp.DataModel.Enumeration do
3535
%Mappings{} = mappings,
3636
%DataModel{}
3737
) do
38+
proto_module = Mappings.proto_module(mappings)
39+
3840
with {:ok, destination_module} <-
3941
Mappings.fetch_destination_module(mappings, enumeration.name) do
4042
values =
@@ -46,7 +48,7 @@ defmodule Mix.Tasks.Lsp.DataModel.Enumeration do
4648
ast =
4749
quote do
4850
defmodule unquote(destination_module) do
49-
alias ElixirLS.LanguageServer.Experimental.Protocol.Proto
51+
alias unquote(proto_module)
5052
use Proto
5153

5254
defenum unquote(values)
@@ -56,4 +58,8 @@ defmodule Mix.Tasks.Lsp.DataModel.Enumeration do
5658
{:ok, ast}
5759
end
5860
end
61+
62+
def references(%__MODULE__{}) do
63+
[]
64+
end
5965
end

apps/language_server/lib/mix/tasks/lsp/data_model/property.ex

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,12 @@ defmodule Mix.Tasks.Lsp.DataModel.Property do
2626
quote(do: {unquote(underscored), optional(unquote(type_call))})
2727
end
2828
end
29+
30+
def references(%__MODULE__{} = property) do
31+
%type_module{} = property.type
32+
33+
property.type
34+
|> type_module.references()
35+
|> Enum.reject(fn name -> String.starts_with?(name, "LSP") end)
36+
end
2937
end

apps/language_server/lib/mix/tasks/lsp/data_model/structure.ex

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
defmodule Mix.Tasks.Lsp.DataModel.Structure do
2+
alias Mix.Tasks.Lsp.Mappings.NumberingContext
23
alias Mix.Tasks.Lsp.DataModel.Type.ObjectLiteral
34
alias Mix.Tasks.Lsp.Mappings
45
alias Mix.Tasks.Lsp.DataModel
@@ -8,6 +9,8 @@ defmodule Mix.Tasks.Lsp.DataModel.Structure do
89
defstruct name: nil, documentation: nil, properties: nil, definition: nil, module: nil
910

1011
def new(%{"name" => name, "properties" => _} = definition) do
12+
NumberingContext.new()
13+
1114
%__MODULE__{
1215
name: name,
1316
documentation: definition[:documentation],
@@ -26,19 +29,32 @@ defmodule Mix.Tasks.Lsp.DataModel.Structure do
2629
%DataModel{} = data_model
2730
) do
2831
with {:ok, destination_module} <- Mappings.fetch_destination_module(mappings, structure.name) do
32+
NumberingContext.new()
33+
types_module = Mappings.types_module(mappings)
34+
proto_module = Mappings.proto_module(mappings)
2935
structure = resolve(structure, data_model)
3036
object_literals = Type.collect_object_literals(structure, data_model)
3137

3238
literal_definitions =
3339
Enum.map(object_literals, &ObjectLiteral.build_definition(&1, data_model, mappings))
3440

3541
protocol_properties =
36-
Enum.map(structure.properties, &Property.to_protocol(&1, data_model, mappings))
42+
structure.properties
43+
|> Enum.sort_by(& &1.name)
44+
|> Enum.map(&Property.to_protocol(&1, data_model, mappings))
45+
46+
type_module_alias =
47+
case references(structure) do
48+
[] -> []
49+
_ -> [quote(do: alias(unquote(types_module)))]
50+
end
3751

3852
ast =
3953
quote do
4054
defmodule unquote(destination_module) do
41-
alias ElixirLS.LanguageServer.Experimental.Protocol.Proto
55+
alias unquote(proto_module)
56+
unquote_splicing(type_module_alias)
57+
4258
unquote_splicing(literal_definitions)
4359

4460
use Proto
@@ -50,6 +66,10 @@ defmodule Mix.Tasks.Lsp.DataModel.Structure do
5066
end
5167
end
5268

69+
def references(%__MODULE__{} = structure) do
70+
Enum.flat_map(structure.properties, &Property.references/1)
71+
end
72+
5373
def resolve(%__MODULE__{properties: properties} = structure) when is_list(properties) do
5474
structure
5575
end

0 commit comments

Comments
 (0)