Skip to content

Commit ce92db5

Browse files
committed
Merge branch 'develop'
2 parents e21b329 + f9f70a2 commit ce92db5

File tree

7 files changed

+352
-2
lines changed

7 files changed

+352
-2
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
* Форматирование файла
1818
* Форматирование выбранного диапазона
19+
* Определение сворачиваемых областей - `#Область`, `#Если`, процедуры и функции, блоки кода
1920
* Диагностики
2021
* Запуск движка диагностик из командной строки
2122

src/main/java/org/github/_1c_syntax/bsl/languageserver/BSLLanguageServer.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ public CompletableFuture<InitializeResult> initialize(InitializeParams params) {
6464
//capabilities.setHoverProvider(Boolean.TRUE);
6565
capabilities.setDocumentRangeFormattingProvider(Boolean.TRUE);
6666
capabilities.setDocumentFormattingProvider(Boolean.TRUE);
67+
capabilities.setFoldingRangeProvider(Boolean.TRUE);
6768

6869
InitializeResult result = new InitializeResult(capabilities);
6970

src/main/java/org/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@
3939
import org.eclipse.lsp4j.DocumentRangeFormattingParams;
4040
import org.eclipse.lsp4j.DocumentSymbol;
4141
import org.eclipse.lsp4j.DocumentSymbolParams;
42+
import org.eclipse.lsp4j.FoldingRange;
43+
import org.eclipse.lsp4j.FoldingRangeRequestParams;
4244
import org.eclipse.lsp4j.Hover;
4345
import org.eclipse.lsp4j.Location;
4446
import org.eclipse.lsp4j.ReferenceParams;
@@ -56,6 +58,7 @@
5658
import org.github._1c_syntax.bsl.languageserver.context.DocumentContext;
5759
import org.github._1c_syntax.bsl.languageserver.context.ServerContext;
5860
import org.github._1c_syntax.bsl.languageserver.providers.DiagnosticProvider;
61+
import org.github._1c_syntax.bsl.languageserver.providers.FoldingRangeProvider;
5962
import org.github._1c_syntax.bsl.languageserver.providers.FormatProvider;
6063
import org.github._1c_syntax.bsl.languageserver.providers.HoverProvider;
6164

@@ -170,6 +173,16 @@ public CompletableFuture<List<? extends TextEdit>> onTypeFormatting(DocumentOnTy
170173
throw new UnsupportedOperationException();
171174
}
172175

176+
@Override
177+
public CompletableFuture<List<FoldingRange>> foldingRange(FoldingRangeRequestParams params) {
178+
DocumentContext documentContext = context.getDocument(params.getTextDocument().getUri());
179+
if (documentContext == null) {
180+
return CompletableFuture.completedFuture(null);
181+
}
182+
183+
return CompletableFuture.supplyAsync(() -> FoldingRangeProvider.getFoldingRange(documentContext));
184+
}
185+
173186
@Override
174187
public CompletableFuture<WorkspaceEdit> rename(RenameParams params) {
175188
throw new UnsupportedOperationException();
Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
/*
2+
* This file is a part of BSL Language Server.
3+
*
4+
* Copyright © 2018-2019
5+
* Alexey Sosnoviy <[email protected]>, Nikita Gryzlov <[email protected]> and contributors
6+
*
7+
* SPDX-License-Identifier: LGPL-3.0-or-later
8+
*
9+
* BSL Language Server is free software; you can redistribute it and/or
10+
* modify it under the terms of the GNU Lesser General Public
11+
* License as published by the Free Software Foundation; either
12+
* version 3.0 of the License, or (at your option) any later version.
13+
*
14+
* BSL Language Server is distributed in the hope that it will be useful,
15+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17+
* Lesser General Public License for more details.
18+
*
19+
* You should have received a copy of the GNU Lesser General Public
20+
* License along with BSL Language Server.
21+
*/
22+
package org.github._1c_syntax.bsl.languageserver.providers;
23+
24+
import org.antlr.v4.runtime.Token;
25+
import org.antlr.v4.runtime.tree.ParseTree;
26+
import org.antlr.v4.runtime.tree.TerminalNode;
27+
import org.eclipse.lsp4j.FoldingRange;
28+
import org.github._1c_syntax.bsl.languageserver.context.DocumentContext;
29+
import org.github._1c_syntax.bsl.parser.BSLParser;
30+
import org.github._1c_syntax.bsl.parser.BSLParserBaseVisitor;
31+
32+
import java.util.ArrayDeque;
33+
import java.util.ArrayList;
34+
import java.util.Deque;
35+
import java.util.List;
36+
37+
public final class FoldingRangeProvider {
38+
39+
private static final String REGION_KIND = "region";
40+
private static final String COMMENT_KIND = "comment";
41+
42+
private FoldingRangeProvider() {
43+
// only statics
44+
}
45+
46+
public static List<FoldingRange> getFoldingRange(DocumentContext documentContext) {
47+
48+
List<FoldingRange> foldingRanges = getCommentRanges(documentContext);
49+
50+
CodeBlockRangeFinder codeBlockRangeFinder = new CodeBlockRangeFinder();
51+
codeBlockRangeFinder.visitFile(documentContext.getAst());
52+
List<FoldingRange> codeBlockRegionRanges = codeBlockRangeFinder.getRegionRanges();
53+
54+
RegionRangeFinder regionRangeFinder = new RegionRangeFinder();
55+
regionRangeFinder.visitFile(documentContext.getAst());
56+
List<FoldingRange> regionRanges = regionRangeFinder.getRegionRanges();
57+
58+
PreprocIfRegionRangeFinder preprocIfRegionRangeFinder = new PreprocIfRegionRangeFinder();
59+
preprocIfRegionRangeFinder.visitFile(documentContext.getAst());
60+
List<FoldingRange> preprocRegionRanges = preprocIfRegionRangeFinder.getRegionRanges();
61+
62+
foldingRanges.addAll(codeBlockRegionRanges);
63+
foldingRanges.addAll(regionRanges);
64+
foldingRanges.addAll(preprocRegionRanges);
65+
66+
return foldingRanges;
67+
}
68+
69+
private static List<FoldingRange> getCommentRanges(DocumentContext documentContext) {
70+
List<FoldingRange> foldingRanges = new ArrayList<>();
71+
72+
int lastRangeStart = -1;
73+
int previousLine = -1;
74+
List<Token> comments = documentContext.getComments();
75+
for (Token token : comments) {
76+
int tokenLine = token.getLine();
77+
78+
if (tokenLine != previousLine + 1) {
79+
if (lastRangeStart != previousLine) {
80+
FoldingRange foldingRange = new FoldingRange(lastRangeStart - 1, previousLine - 1);
81+
foldingRange.setKind(COMMENT_KIND);
82+
83+
foldingRanges.add(foldingRange);
84+
}
85+
// new range
86+
lastRangeStart = tokenLine;
87+
}
88+
89+
previousLine = tokenLine;
90+
}
91+
92+
// add last range
93+
if (lastRangeStart != previousLine) {
94+
FoldingRange foldingRange = new FoldingRange(lastRangeStart - 1, previousLine - 1);
95+
foldingRange.setKind(COMMENT_KIND);
96+
97+
foldingRanges.add(foldingRange);
98+
}
99+
return foldingRanges;
100+
}
101+
102+
private static class CodeBlockRangeFinder extends BSLParserBaseVisitor<ParseTree> {
103+
104+
private List<FoldingRange> regionRanges = new ArrayList<>();
105+
106+
public List<FoldingRange> getRegionRanges() {
107+
return new ArrayList<>(regionRanges);
108+
}
109+
110+
@Override
111+
public ParseTree visitProcedure(BSLParser.ProcedureContext ctx) {
112+
addRegionRange(ctx.procDeclaration().PROCEDURE_KEYWORD(), ctx.ENDPROCEDURE_KEYWORD());
113+
return super.visitProcedure(ctx);
114+
}
115+
116+
@Override
117+
public ParseTree visitFunction(BSLParser.FunctionContext ctx) {
118+
addRegionRange(ctx.funcDeclaration().FUNCTION_KEYWORD(), ctx.ENDFUNCTION_KEYWORD());
119+
return super.visitFunction(ctx);
120+
}
121+
122+
@Override
123+
public ParseTree visitIfStatement(BSLParser.IfStatementContext ctx) {
124+
addRegionRange(ctx.IF_KEYWORD(), ctx.ENDIF_KEYWORD());
125+
return super.visitIfStatement(ctx);
126+
}
127+
128+
@Override
129+
public ParseTree visitWhileStatement(BSLParser.WhileStatementContext ctx) {
130+
addRegionRange(ctx.WHILE_KEYWORD(), ctx.ENDDO_KEYWORD());
131+
return super.visitWhileStatement(ctx);
132+
}
133+
134+
@Override
135+
public ParseTree visitForStatement(BSLParser.ForStatementContext ctx) {
136+
addRegionRange(ctx.FOR_KEYWORD(), ctx.ENDDO_KEYWORD());
137+
return super.visitForStatement(ctx);
138+
}
139+
140+
@Override
141+
public ParseTree visitForEachStatement(BSLParser.ForEachStatementContext ctx) {
142+
addRegionRange(ctx.FOR_KEYWORD(), ctx.ENDDO_KEYWORD());
143+
return super.visitForEachStatement(ctx);
144+
}
145+
146+
@Override
147+
public ParseTree visitTryStatement(BSLParser.TryStatementContext ctx) {
148+
addRegionRange(ctx.TRY_KEYWORD(), ctx.ENDTRY_KEYWORD());
149+
return super.visitTryStatement(ctx);
150+
}
151+
152+
private void addRegionRange(TerminalNode start, TerminalNode stop) {
153+
int startLine = start.getSymbol().getLine();
154+
int stopLine = stop.getSymbol().getLine();
155+
156+
if (stopLine > startLine) {
157+
FoldingRange foldingRange = new FoldingRange(startLine - 1, stopLine - 1);
158+
foldingRange.setKind(REGION_KIND);
159+
160+
regionRanges.add(foldingRange);
161+
}
162+
}
163+
}
164+
165+
private static class RegionRangeFinder extends BSLParserBaseVisitor<ParseTree> {
166+
167+
private Deque<BSLParser.RegionStartContext> regionStack = new ArrayDeque<>();
168+
private List<FoldingRange> regionRanges = new ArrayList<>();
169+
170+
public List<FoldingRange> getRegionRanges() {
171+
return new ArrayList<>(regionRanges);
172+
}
173+
174+
@Override
175+
public ParseTree visitRegionStart(BSLParser.RegionStartContext ctx) {
176+
regionStack.push(ctx);
177+
return super.visitRegionStart(ctx);
178+
}
179+
180+
@Override
181+
public ParseTree visitRegionEnd(BSLParser.RegionEndContext ctx) {
182+
183+
BSLParser.RegionStartContext regionStart = regionStack.pop();
184+
185+
int start = regionStart.getStart().getLine();
186+
int stop = ctx.getStop().getLine();
187+
188+
FoldingRange foldingRange = new FoldingRange(start - 1, stop - 1);
189+
foldingRange.setKind(REGION_KIND);
190+
191+
regionRanges.add(foldingRange);
192+
193+
return super.visitRegionEnd(ctx);
194+
}
195+
}
196+
197+
private static class PreprocIfRegionRangeFinder extends BSLParserBaseVisitor<ParseTree> {
198+
199+
private Deque<BSLParser.Preproc_ifContext> preprocIfRegionStack = new ArrayDeque<>();
200+
private List<FoldingRange> regionRanges = new ArrayList<>();
201+
202+
public List<FoldingRange> getRegionRanges() {
203+
return new ArrayList<>(regionRanges);
204+
}
205+
206+
@Override
207+
public ParseTree visitPreproc_if(BSLParser.Preproc_ifContext ctx) {
208+
preprocIfRegionStack.push(ctx);
209+
return super.visitPreproc_if(ctx);
210+
}
211+
212+
@Override
213+
public ParseTree visitPreproc_endif(BSLParser.Preproc_endifContext ctx) {
214+
BSLParser.Preproc_ifContext regionStart = preprocIfRegionStack.pop();
215+
216+
int start = regionStart.getStart().getLine();
217+
int stop = ctx.getStop().getLine();
218+
219+
FoldingRange foldingRange = new FoldingRange(start - 1, stop - 1);
220+
foldingRange.setKind(REGION_KIND);
221+
222+
regionRanges.add(foldingRange);
223+
224+
return super.visitPreproc_endif(ctx);
225+
}
226+
227+
}
228+
}

src/main/java/org/github/_1c_syntax/bsl/languageserver/providers/FormatProvider.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,16 @@ private FormatProvider() {
7373
}
7474

7575
public static List<TextEdit> getFormatting(DocumentFormattingParams params, DocumentContext documentContext) {
76+
List<Token> tokens = documentContext.getTokens();
77+
if (tokens.isEmpty()) {
78+
return Collections.emptyList();
79+
}
80+
Token firstToken = tokens.get(0);
81+
Token lastToken = tokens.get(tokens.size() - 1);
82+
7683
return getTextEdits(
77-
documentContext.getTokens(),
78-
RangeHelper.newRange(documentContext.getAst()), 0, params.getOptions()
84+
tokens,
85+
RangeHelper.newRange(firstToken, lastToken), firstToken.getCharPositionInLine(), params.getOptions()
7986
);
8087
}
8188

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
* This file is a part of BSL Language Server.
3+
*
4+
* Copyright © 2018-2019
5+
* Alexey Sosnoviy <[email protected]>, Nikita Gryzlov <[email protected]> and contributors
6+
*
7+
* SPDX-License-Identifier: LGPL-3.0-or-later
8+
*
9+
* BSL Language Server is free software; you can redistribute it and/or
10+
* modify it under the terms of the GNU Lesser General Public
11+
* License as published by the Free Software Foundation; either
12+
* version 3.0 of the License, or (at your option) any later version.
13+
*
14+
* BSL Language Server is distributed in the hope that it will be useful,
15+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17+
* Lesser General Public License for more details.
18+
*
19+
* You should have received a copy of the GNU Lesser General Public
20+
* License along with BSL Language Server.
21+
*/
22+
package org.github._1c_syntax.bsl.languageserver.providers;
23+
24+
import org.apache.commons.io.FileUtils;
25+
import org.eclipse.lsp4j.FoldingRange;
26+
import org.github._1c_syntax.bsl.languageserver.context.DocumentContext;
27+
import org.junit.jupiter.api.Test;
28+
29+
import java.io.File;
30+
import java.io.IOException;
31+
import java.nio.charset.StandardCharsets;
32+
import java.util.List;
33+
34+
import static org.assertj.core.api.Java6Assertions.assertThat;
35+
36+
class FoldingRangeProviderTest {
37+
38+
@Test
39+
void testFoldingRange() throws IOException {
40+
41+
String fileContent = FileUtils.readFileToString(
42+
new File("./src/test/resources/providers/foldingRange.bsl"),
43+
StandardCharsets.UTF_8
44+
);
45+
DocumentContext documentContext = new DocumentContext("fake-uri.bsl", fileContent);
46+
47+
List<FoldingRange> foldingRanges = FoldingRangeProvider.getFoldingRange(documentContext);
48+
49+
assertThat(foldingRanges).hasSize(9);
50+
51+
// regions
52+
assertThat(foldingRanges)
53+
.filteredOn(foldingRange -> foldingRange.getKind().equals("region"))
54+
.anyMatch(foldingRange -> foldingRange.getStartLine() == 0 && foldingRange.getEndLine() == 23)
55+
.anyMatch(foldingRange -> foldingRange.getStartLine() == 2 && foldingRange.getEndLine() == 16)
56+
.anyMatch(foldingRange -> foldingRange.getStartLine() == 4 && foldingRange.getEndLine() == 14)
57+
.anyMatch(foldingRange -> foldingRange.getStartLine() == 8 && foldingRange.getEndLine() == 12)
58+
.anyMatch(foldingRange -> foldingRange.getStartLine() == 9 && foldingRange.getEndLine() == 11)
59+
.anyMatch(foldingRange -> foldingRange.getStartLine() == 20 && foldingRange.getEndLine() == 21)
60+
.anyMatch(foldingRange -> foldingRange.getStartLine() == 25 && foldingRange.getEndLine() == 26)
61+
;
62+
63+
64+
// comments
65+
assertThat(foldingRanges)
66+
.filteredOn(foldingRange -> foldingRange.getKind().equals("comment"))
67+
.hasSize(2)
68+
.anyMatch(foldingRange -> foldingRange.getStartLine() == 6 && foldingRange.getEndLine() == 7)
69+
.anyMatch(foldingRange -> foldingRange.getStartLine() == 18 && foldingRange.getEndLine() == 19)
70+
;
71+
72+
}
73+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#Область ИмяОбласти
2+
3+
#Если Сервер Тогда
4+
5+
#Область ВложеннаяОбласть
6+
7+
// Комментарий
8+
// многострочный
9+
Процедура ИмяПроцедуры()
10+
Если Истина Тогда
11+
А = 0;
12+
КонецЕсли;
13+
КонецПроцедуры
14+
15+
#КонецОбласти
16+
17+
#КонецЕсли
18+
19+
// Комментарий
20+
// многострочный
21+
Процедура ИмяПроцедуры2()
22+
КонецПроцедуры
23+
24+
#КонецОбласти
25+
26+
Процедура ИмяПроцедуры3()
27+
КонецПроцедуры

0 commit comments

Comments
 (0)