Skip to content

Commit 3e2e88c

Browse files
Merge branch 'topic/als.1729.more_fallback_cases' into 'master'
Add fallback indenter for onTypeFormatting on IndentOnly is False See merge request eng/ide/ada_language_server!2157
2 parents cc3c613 + a6defb6 commit 3e2e88c

File tree

12 files changed

+214
-48
lines changed

12 files changed

+214
-48
lines changed

source/ada/lsp-ada_formatter.adb

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -219,23 +219,27 @@ package body LSP.Ada_Formatter is
219219
LSP.Ada_Handlers.Formatting.Get_Formatting_Options
220220
(Context.all, Value.options);
221221

222+
Prev_Line : constant Natural := Natural'Max (Value.position.line - 1, 0);
222223
Indent_Array :
223224
constant LSP.Formatters.Fallback_Indenter.Indentation_Array :=
224225
LSP.Ada_Handlers.Formatting.Get_Indentation
225226
(Filename => Context.URI_To_File (Document.URI),
226227
Buffer =>
228+
-- Add one more line because the fallback formatter ignore
229+
-- the last EOL as EOF
227230
Document.Get_Text ((0, 0), (Value.position.line + 1, 0)),
228231
Span =>
229-
((Value.position.line, 0), (Value.position.line + 1, 0)),
232+
-- We possibly want to reindent the previous line
233+
((Prev_Line, 0), (Value.position.line, 0)),
230234
Options => Full_Options);
231235
Indentation : constant VSS.Strings.Character_Count :=
232236
(declare
233237
Indentation_First_Guess : constant VSS.Strings.Character_Count :=
234-
((if Indent_Array (Value.position.line + 1) = -1
238+
((if Indent_Array (Value.position.line) = -1
235239
then 0
236240
else
237241
VSS.Strings.Character_Count
238-
(Indent_Array (Value.position.line + 1))));
242+
(Indent_Array (Value.position.line))));
239243
begin
240244
(if Indentation_First_Guess
241245
>= VSS.Strings.Character_Count (Value.position.character)
@@ -308,6 +312,20 @@ package body LSP.Ada_Formatter is
308312
(Filename => Context.URI_To_File (Document.URI),
309313
Options => Full_Options,
310314
S => Indentation * ' ')));
315+
316+
-- If not in indent-only mode, re-indent the previous line too
317+
if not Self.Parent.Context.Get_Configuration.Indent_Only
318+
and then Value.position.line > 0
319+
and then Indent_Array (Prev_Line) /= -1
320+
then
321+
Response.Append
322+
(LSP.Ada_Handlers.Formatting.Reindent_Line
323+
(Filename => Context.URI_To_File (Document.URI),
324+
Line => Document.Get_Line (Prev_Line),
325+
Pos => (Prev_Line, 0),
326+
Options => Full_Options,
327+
New_Indent => Indent_Array (Prev_Line)));
328+
end if;
311329
end Handle_Document_With_Diagnostics;
312330

313331
-----------------------------------------

source/ada/lsp-ada_handlers-formatting.adb

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,12 @@ package body LSP.Ada_Handlers.Formatting is
215215
Buffer : constant VSS.Strings.Virtual_String :=
216216
(if Span = Empty_Range
217217
then Document.Text
218-
else Document.Slice (((0, 0), Actual_Span.an_end)));
218+
else
219+
Document.Slice
220+
(((0, 0),
221+
(Natural'Min (Document.Line_Count - 1,
222+
Actual_Span.an_end.line + 1),
223+
0))));
219224
-- Get the relevant buffer to indent.
220225
-- If no span is provided, get the whole document buffer.
221226
-- Otherwise get the buffer from the start of the document
@@ -230,22 +235,17 @@ package body LSP.Ada_Handlers.Formatting is
230235
Options => Options);
231236
-- Get the indentation levels for each line in the span.
232237

233-
Pos : LSP.Structures.Position;
234238
begin
235239
Tracer.Trace_Text (Incorrect_Code_Msg & ", using the fallback indenter");
236240
for Line in Indent_Lines'Range loop
237241
if Indent_Lines (Line) /= -1 then
238-
-- LSP is 0-based, while the array returned by the fallback
239-
-- indenter is 1-based.
240-
Pos := (Line - 1, 0);
241-
242242
-- Generate a text edit to reindent the line.
243243
Response.Append
244244
(Reindent_Line
245245
(Filename => Filename,
246-
Line => Document.Get_Line (Pos.line),
246+
Line => Document.Get_Line (Line),
247247
Options => Options,
248-
Pos => Pos,
248+
Pos => (Line, 0),
249249
New_Indent => Indent_Lines (Line)));
250250
end if;
251251
end loop;

source/ada/lsp-formatters-fallback_indenter.adb

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -911,11 +911,11 @@ package body LSP.Formatters.Fallback_Indenter is
911911

912912
function Get_Indentation
913913
(Buffer : String;
914-
From, To : Natural;
914+
From, To : Positive;
915915
Indent_Level : Natural := 3;
916916
Indent_Continue : Natural := 2) return Indentation_Array
917917
is
918-
Result : Indentation_Array (From .. To) := (others => -1);
918+
Result : Indentation_Array (From - 1 .. To - 1) := (others => -1);
919919

920920
---------------
921921
-- Constants --
@@ -1189,9 +1189,9 @@ package body LSP.Formatters.Fallback_Indenter is
11891189
Continuation_Val := 0;
11901190
end if;
11911191

1192-
if Line_Count in Result'Range then
1193-
Result (Line_Count) := Indentation;
1194-
if Line_Count = Result'Last then
1192+
if Line_Count - 1 in Result'Range then
1193+
Result (Line_Count - 1) := Indentation;
1194+
if Line_Count - 1 = Result'Last then
11951195
raise Finished;
11961196
end if;
11971197
end if;
@@ -2996,7 +2996,6 @@ package body LSP.Formatters.Fallback_Indenter is
29962996
-- first line.
29972997

29982998
if Ref_Indent = Num_Spaces
2999-
and then To /= 0
30002999
and then L not in From .. To
30013000
then
30023001
Ref_Indent := Integer'Max (P - Start_Of_Line, 0);

source/ada/lsp-formatters-fallback_indenter.ads

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ package LSP.Formatters.Fallback_Indenter is
2121

2222
function Get_Indentation
2323
(Buffer : String;
24-
From, To : Natural;
24+
From, To : Positive;
2525
Indent_Level : Natural := 3;
2626
Indent_Continue : Natural := 2) return Indentation_Array;
2727
-- Return an array of indentation levels for each line in Buffer, from

source/gpr/lsp-gpr_handlers.adb

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -655,21 +655,22 @@ package body LSP.GPR_Handlers is
655655
Filename : constant GNATCOLL.VFS.Virtual_File :=
656656
Self.To_File (Value.textDocument.uri);
657657

658+
Prev_Line : constant Natural := Natural'Max (Value.position.line - 1, 0);
658659
Indent_Array :
659660
constant LSP.Formatters.Fallback_Indenter.Indentation_Array :=
660661
LSP.Ada_Handlers.Formatting.Get_Indentation
661662
(Filename => Filename,
662663
Buffer =>
663664
Document.Slice (((0, 0), (Value.position.line + 1, 0))),
664665
Span =>
665-
((0, 0), (Value.position.line + 1, 0)),
666+
((Prev_Line, 0), (Value.position.line, 0)),
666667
Options => Options);
667668
Indentation : constant VSS.Strings.Character_Count :=
668-
(if Indent_Array (Value.position.line + 1) = -1
669+
(if Indent_Array (Value.position.line) = -1
669670
then 0
670671
else
671672
VSS.Strings.Character_Count
672-
(Indent_Array (Value.position.line + 1)));
673+
(Indent_Array (Value.position.line)));
673674
begin
674675
-- First set the indentation for the new line
675676
Response.Append
@@ -683,23 +684,17 @@ package body LSP.GPR_Handlers is
683684
S => Indentation * ' ')));
684685

685686
-- If not in indent-only mode, re-indent the previous line too
686-
if not Self.Configuration.Indent_Only then
687-
declare
688-
Prev_Line : constant Natural :=
689-
Natural'Max (Value.position.line - 1, 0);
690-
Indentation : constant Natural :=
691-
(if Indent_Array (Prev_Line + 1) = -1
692-
then 0
693-
else Indent_Array (Prev_Line + 1));
694-
begin
695-
Response.Append
696-
(LSP.Ada_Handlers.Formatting.Reindent_Line
697-
(Filename => Filename,
698-
Line => Document.Get_Line (Prev_Line),
699-
Pos => (Prev_Line, 0),
700-
Options => Options,
701-
New_Indent => Indentation));
702-
end;
687+
if not Self.Configuration.Indent_Only
688+
and then Value.position.line > 0
689+
and then Indent_Array (Prev_Line) /= -1
690+
then
691+
Response.Append
692+
(LSP.Ada_Handlers.Formatting.Reindent_Line
693+
(Filename => Filename,
694+
Line => Document.Get_Line (Prev_Line),
695+
Pos => (Prev_Line, 0),
696+
Options => Options,
697+
New_Indent => Indent_Array (Prev_Line)));
703698
end if;
704699

705700
Self.Sender.On_OnTypeFormatting_Response (Id, Response);
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
procedure T is
2+
X : Integer := 1;
3+
YYY : Natural := 2;
4+
begin
5+
if X = YYY or else X + X > YYY and then (X < YYY and then Y > 2) then
6+
null;
7+
end if;
8+
9+
for I in 1 .. X loop
10+
if X > 2 then
11+
Y := Y + 1;
12+
end if;
13+
end loop;
14+
15+
case X is
16+
when X > 10 =>
17+
null;
18+
19+
when X > 20 =>
20+
null;
21+
22+
when X > 30 | Y > 10 =>
23+
null;
24+
25+
when others =>
26+
null;
27+
end case;
28+
29+
this_statement_is_missing_a_semicolon
30+
end T;
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?xml version="1.0"?>
2+
<Locations>
3+
<Project>
4+
<vfs_file>/home/boulanger/adacore/ancr/src/als/testsuite/ada_lsp/onTypeFormatting/indentOnlyFalse_fallback/test.gpr</vfs_file>
5+
<file_marker current="true" column=" 1" line=" 1" >
6+
<vfs_project>/home/boulanger/adacore/ancr/src/als/testsuite/ada_lsp/onTypeFormatting/indentOnlyFalse_fallback/test.gpr</vfs_project>
7+
<vfs_file>/home/boulanger/adacore/ancr/src/als/testsuite/ada_lsp/onTypeFormatting/indentOnlyFalse_fallback/t.adb</vfs_file>
8+
</file_marker>
9+
</Project>
10+
</Locations>
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
project Test is
2+
3+
end Test;
4+
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
"""Test the onTypeFormatting in format mode when there are diagnostics"""
2+
3+
import os
4+
from drivers.pylsp import URI, ALSLanguageClient, OnTypeFormattingSetting, test
5+
from drivers.lsp_ada_requests import run_indentation_testcases, IndentationTestCase
6+
from lsprotocol.types import (
7+
ClientCapabilities,
8+
DocumentOnTypeFormattingOptions,
9+
FormattingOptions,
10+
InitializedParams,
11+
InitializeParams,
12+
Position,
13+
Range,
14+
TextEdit,
15+
)
16+
17+
18+
@test(initialize=False)
19+
async def test_on_type_formatting_indentation(lsp: ALSLanguageClient) -> None:
20+
"""
21+
Test the onTypeFormatting feature of ALS.
22+
23+
This test verifies that ALS correctly estimates the indentation that should
24+
be added after a line break.
25+
26+
Tests should be added to the indentation_tests list.
27+
"""
28+
29+
# Send the initialize request
30+
31+
response = await lsp.initialize_session(
32+
InitializeParams(
33+
capabilities=ClientCapabilities(),
34+
root_uri=URI(os.getcwd()),
35+
)
36+
)
37+
38+
# Verify that the right capability is advertised
39+
40+
lsp.assertEqual(
41+
response.capabilities.document_on_type_formatting_provider,
42+
DocumentOnTypeFormattingOptions(
43+
first_trigger_character="\n", more_trigger_character=None
44+
),
45+
)
46+
47+
# Send the initialized notification and the didChangeConfiguration
48+
# notification, configuring ALS to only indent when it receives an
49+
# onTypeFormattingRequest
50+
51+
lsp.initialized(InitializedParams())
52+
53+
lsp.didChangeConfig({"onTypeFormatting": OnTypeFormattingSetting(indentOnly=False)})
54+
await lsp.awaitIndexingEnd()
55+
56+
# Test list
57+
indentation_tests = [
58+
IndentationTestCase(
59+
"Indentation after when",
60+
"t.adb",
61+
Position(15, 29),
62+
" ",
63+
[TextEdit(Range(Position(15, 0), Position(15, 6)), " ")],
64+
),
65+
IndentationTestCase(
66+
"Indentation after case",
67+
"t.adb",
68+
Position(14, 11),
69+
" ",
70+
[TextEdit(Range(Position(14, 0), Position(14, 2)), " ")],
71+
),
72+
IndentationTestCase(
73+
"Indentation after for+if/then",
74+
"t.adb",
75+
Position(9, 19),
76+
" ",
77+
[TextEdit(Range(Position(9, 0), Position(9, 6)), " ")],
78+
),
79+
IndentationTestCase(
80+
"Indentation after for",
81+
"t.adb",
82+
Position(8, 23),
83+
" ",
84+
[TextEdit(Range(Position(8, 0), Position(8, 3)), " ")],
85+
),
86+
IndentationTestCase(
87+
"Indentation after end if",
88+
"t.adb",
89+
Position(6, 10),
90+
" ",
91+
[TextEdit(Range(Position(6, 0), Position(6, 3)), " ")],
92+
),
93+
IndentationTestCase(
94+
"Indentation after if/then",
95+
"t.adb",
96+
Position(4, 70),
97+
" ",
98+
[TextEdit(Range(Position(4, 0), Position(4, 1)), " ")],
99+
),
100+
]
101+
102+
failed_tests = await run_indentation_testcases(
103+
lsp, indentation_tests, FormattingOptions(tab_size=3, insert_spaces=True)
104+
)
105+
106+
if len(failed_tests) > 0:
107+
fail_messages = "\n\n".join(failed_tests)
108+
message = f"Indentation tests failed\n\n{fail_messages}"
109+
raise Exception(message) # pylint: disable=broad-exception-raised
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
driver: pylsp

0 commit comments

Comments
 (0)