Skip to content
This repository was archived by the owner on Aug 15, 2025. It is now read-only.

Commit 284ec99

Browse files
committed
Working prototype for indenting entire function on .
Co-authored-by: Andreas Hasselberg <andreas.hasselberg@gmail.com> Delete iostr.erl Fix linter complaints Fix proper error Fix typespec Maybe make Dialyzer happy? Temp fixes to get dialyzer to run Add spec Better fix for dialyzer errors Add config to enable on type formatting, defaulting to false Skip formatting if . is on a commented out line
1 parent 51a48ef commit 284ec99

File tree

7 files changed

+99
-9
lines changed

7 files changed

+99
-9
lines changed

apps/els_core/include/els_core.hrl

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -548,8 +548,8 @@
548548
}.
549549

550550
-type document_ontypeformatting_options() :: false |
551-
#{ first_trigger_character := string()
552-
, more_trigger_character => string()
551+
#{ firstTriggerCharacter := binary()
552+
, moreTriggerCharacter => [binary()]
553553
}.
554554

555555
%%------------------------------------------------------------------------------
@@ -612,7 +612,8 @@
612612
| {atom(), atom()} %% record_def_field, record_field
613613
| string() %% include, include_lib
614614
| {atom(), arity()}
615-
| {module(), atom(), arity()}.
615+
| {module(), atom(), arity()}
616+
| pos().
616617
-type poi() :: #{ kind := poi_kind()
617618
, id := poi_id()
618619
, data := any()

apps/els_core/src/els_client.erl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,10 @@ request_params({initialize, {RootUri, InitOptions}}) ->
452452
#{ <<"contextSupport">> => 'true' }
453453
, <<"hover">> =>
454454
#{ <<"contentFormat">> => ContentFormat }
455+
, <<"documentOnTypeFormattingProvider">> =>
456+
#{ firstTriggerCharacter => <<",">>
457+
, moreTriggercharacter => []
458+
}
455459
},
456460
#{ <<"rootUri">> => RootUri
457461
, <<"initializationOptions">> => InitOptions

apps/els_core/src/els_config.erl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ do_initialize(RootUri, Capabilities, InitOptions, {ConfigPath, Config}) ->
125125
= maps:get("compiler_telemetry_enabled", Config, false),
126126

127127
IndexingEnabled = maps:get(<<"indexingEnabled">>, InitOptions, true),
128+
FormatOnTypeEnabled = maps:get("format_on_type", Config, false),
128129

129130
%% Passed by the LSP client
130131
ok = set(root_uri , RootUri),
@@ -138,6 +139,7 @@ do_initialize(RootUri, Capabilities, InitOptions, {ConfigPath, Config}) ->
138139
ok = set(macros , Macros),
139140
ok = set(plt_path , DialyzerPltPath),
140141
ok = set(code_reload , CodeReload),
142+
ok = set(format_on_type , FormatOnTypeEnabled),
141143
?LOG_INFO("Config=~p", [Config]),
142144
ok = set(runtime, maps:merge( els_config_runtime:default_config()
143145
, Runtime)),

apps/els_lsp/src/els_dt_document.erl

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,16 @@
2121
, lookup/1
2222
]).
2323

24-
-export([ new/2
24+
-export([ get_element_at_pos/3
25+
, new/2
2526
, pois/1
2627
, pois/2
27-
, get_element_at_pos/3
2828
, uri/1
2929
, functions_at_pos/3
3030
, applications_at_pos/3
3131
, wrapping_functions/2
3232
, wrapping_functions/3
33+
, text/1
3334
]).
3435

3536
%%==============================================================================
@@ -63,6 +64,7 @@
6364
, md5 => binary()
6465
, pois => [poi()]
6566
}.
67+
6668
-export_type([ id/0
6769
, item/0
6870
, kind/0
@@ -155,6 +157,10 @@ new(Uri, Text, Id, Kind) ->
155157
pois(#{ pois := POIs }) ->
156158
POIs.
157159

160+
-spec text(item()) -> binary().
161+
text(#{text := Text}) ->
162+
Text.
163+
158164
%% @doc Returns the list of POIs of the given types for the current
159165
%% document
160166
-spec pois(item(), [poi_kind()]) -> [poi()].

apps/els_lsp/src/els_formatting_provider.erl

Lines changed: 74 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,17 @@ is_enabled_document() -> true.
4949

5050
-spec is_enabled_range() -> boolean().
5151
is_enabled_range() ->
52-
false.
52+
true.
5353

5454
%% NOTE: because erlang_ls does not send incremental document changes
5555
%% via `textDocument/didChange`, this kind of formatting does not
5656
%% make sense.
5757
-spec is_enabled_on_type() -> document_ontypeformatting_options().
58-
is_enabled_on_type() -> false.
58+
is_enabled_on_type() ->
59+
case els_config:get(format_on_type) of
60+
true -> #{firstTriggerCharacter => <<".">>, moreTriggerCharacter => []};
61+
false -> false
62+
end.
5963

6064
-spec handle_request(any(), state()) -> {any(), state()}.
6165
handle_request({document_formatting, Params}, State) ->
@@ -157,5 +161,71 @@ rangeformat_document(_Uri, _Document, _Range, _Options) ->
157161
-spec ontypeformat_document(binary(), map()
158162
, number(), number(), string(), formatting_options())
159163
-> {ok, [text_edit()]}.
160-
ontypeformat_document(_Uri, _Document, _Line, _Col, _Char, _Options) ->
161-
{ok, []}.
164+
ontypeformat_document(_Uri, Document, Line, Col, <<".">>, _Options) ->
165+
case find_matching_range(Document, Line) of
166+
[] ->
167+
{ok, []};
168+
[MatchingRange] ->
169+
{StartLine, _} = Id = els_poi:id(MatchingRange),
170+
Text = els_dt_document:text(Document),
171+
RangeText = els_text:range(Text, Id, {Line, Col}),
172+
% Skip formatting if the . is on a commented line.
173+
case string:trim(els_text:line(Text, Line - 1), both) of
174+
<<"%", _/binary>> ->
175+
{ok, []};
176+
_ ->
177+
ParseF =
178+
fun(Dir) ->
179+
TmpFile = tmp_file(Dir),
180+
ok = file:write_file(TmpFile, RangeText),
181+
Opts = #{break_indent => 2, output_dir => current},
182+
RebarState = #{},
183+
T = rebar3_formatter:new(default_formatter, Opts, RebarState),
184+
rebar3_formatter:format_file(TmpFile, T),
185+
{ok, Bin} = file:read_file(TmpFile),
186+
Bin
187+
end,
188+
%% rebar3_formatter adds a newline, since we terminate on .
189+
%% We want to leave the cursor at the current char rather
190+
%% than jumping to a newline
191+
NewText =
192+
string:trim(
193+
tempdir:mktmp(ParseF), trailing, "\n"),
194+
{ok,
195+
[#{range =>
196+
#{start => #{line => StartLine - 1, character => 0},
197+
'end' => #{line => Line - 1, character => Col}},
198+
newText => NewText}]}
199+
end
200+
end;
201+
ontypeformat_document(_Uri, _Document, _Line, _Col, Char, _Options) ->
202+
?LOG_INFO("Got unhandled character in ontypeformat_document. No formatter "
203+
"configured for char: ~p",
204+
[Char]),
205+
{ok, []}.
206+
207+
-spec find_foldable_ranges(els_dt_document:item()) -> [poi()].
208+
find_foldable_ranges(Document) ->
209+
Pois = els_dt_document:pois(Document),
210+
lists:filter(fun (#{kind := folding_range}) ->
211+
true;
212+
(_) ->
213+
false
214+
end,
215+
Pois).
216+
217+
-spec find_matching_range(els_dt_document:item(), number()) -> [poi()].
218+
find_matching_range(Document, Line) ->
219+
lists:filter(fun(#{range := #{from := {FromLine, _}, to := {ToLine, _}}}) ->
220+
Line >= FromLine andalso Line =< ToLine
221+
end,
222+
find_foldable_ranges(Document)).
223+
224+
-spec tmp_file(string()) -> any().
225+
tmp_file(Dir) ->
226+
Unique = erlang:unique_integer([positive]),
227+
{A, B, C} = os:timestamp(),
228+
N = node(),
229+
filename:join(Dir,
230+
lists:flatten(
231+
io_lib:format("~p-~p.~p.~p.~p", [N, A, B, C, Unique]))).

apps/els_lsp/src/els_general_provider.erl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,8 @@ server_capabilities() ->
157157
els_formatting_provider:is_enabled_document()
158158
, documentRangeFormattingProvider =>
159159
els_formatting_provider:is_enabled_range()
160+
, documentOnTypeFormattingProvider =>
161+
els_formatting_provider:is_enabled_on_type()
160162
, foldingRangeProvider =>
161163
els_folding_range_provider:is_enabled()
162164
, implementationProvider =>

apps/els_lsp/src/els_poi.erl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
-export([ match_pos/2
1212
, sort/1
13+
, id/1
1314
]).
1415

1516
%%==============================================================================
@@ -42,6 +43,10 @@ match_pos(POIs, Pos) ->
4243
, to := To
4344
}} = POI <- POIs, (From =< Pos) andalso (Pos =< To)].
4445

46+
-spec id(poi()) -> poi_id().
47+
id(#{id := Id}) ->
48+
Id.
49+
4550
%% @doc Sorts pois based on their range
4651
%%
4752
%% Order is defined using els_range:compare/2.

0 commit comments

Comments
 (0)