Skip to content

Commit 7fac284

Browse files
authored
Merge pull request #2788 from 1c-syntax/feature/rename
RenameProvider
2 parents afdb554 + a48bd8b commit 7fac284

File tree

9 files changed

+427
-4
lines changed

9 files changed

+427
-4
lines changed

docs/en/index.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ Perfomance measurement - [SSL 3.1](../bench/index.html)
4949
* Quick fixes for several diagnostics
5050
* Run diagnostics engine from command line
5151
* Run formatter engine from command line
52+
* Rename symbol
5253

5354
## Supported protocol operations
5455

@@ -100,8 +101,8 @@ Perfomance measurement - [SSL 3.1](../bench/index.html)
100101
| [formatting](https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_formatting) | <img src="./assets/images/checkmark.svg" alt="yes" width="20"> | | |
101102
| [rangeFormatting](https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_rangeFormatting) | <img src="./assets/images/checkmark.svg" alt="yes" width="20"> | | |
102103
| [onTypeFormatting](https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_onTypeFormatting) | <img src="./assets/images/cross.svg" alt="no" width="20"> | | |
103-
| [rename](https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_rename) | <img src="./assets/images/cross.svg" alt="no" width="20"> | | |
104-
| [prepareRename](https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_prepareRename) | <img src="./assets/images/cross.svg" alt="no" width="20"> | | |
104+
| [rename](https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_rename) | <img src="./assets/images/checkmark.svg" alt="yes" width="20"> | | |
105+
| [prepareRename](https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_prepareRename) | <img src="./assets/images/checkmark.svg" alt="yes" width="20"> | | |
105106
| [foldingRange](https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_foldingRange) | <img src="./assets/images/checkmark.svg" alt="yes" width="20"> | | |
106107
| [selectionRange](https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_selectionRange) | <img src="./assets/images/checkmark.svg" alt="yes" width="20"> | | |
107108
| [prepareCallHierarchy](https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_prepareCallHierarchy) | <img src="./assets/images/checkmark.svg" alt="yes" width="20"> | | |

docs/index.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
* "Быстрые исправления" (quick fixes) для ряда диагностик и "быстрые действия" (code actions)
5050
* Запуск движка диагностик из командной строки
5151
* Запуск форматирования файлов в каталоге из командной строки
52+
* Переименование символов
5253

5354
## Поддерживаемые операции протокола
5455

@@ -100,8 +101,8 @@
100101
| [formatting](https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_formatting) | <img src="./assets/images/checkmark.svg" alt="yes" width="20"> | | |
101102
| [rangeFormatting](https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_rangeFormatting) | <img src="./assets/images/checkmark.svg" alt="yes" width="20"> | | |
102103
| [onTypeFormatting](https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_onTypeFormatting) | <img src="./assets/images/cross.svg" alt="no" width="20"> | | |
103-
| [rename](https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_rename) | <img src="./assets/images/cross.svg" alt="no" width="20"> | | |
104-
| [prepareRename](https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_prepareRename) | <img src="./assets/images/cross.svg" alt="no" width="20"> | | |
104+
| [rename](https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_rename) | <img src="./assets/images/checkmark.svg" alt="yes" width="20"> | | |
105+
| [prepareRename](https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_prepareRename) | <img src="./assets/images/checkmark.svg" alt="yes" width="20"> | | |
105106
| [foldingRange](https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_foldingRange) | <img src="./assets/images/checkmark.svg" alt="yes" width="20"> | | |
106107
| [selectionRange](https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_selectionRange) | <img src="./assets/images/checkmark.svg" alt="yes" width="20"> | | |
107108
| [prepareCallHierarchy](https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_prepareCallHierarchy) | <img src="./assets/images/checkmark.svg" alt="yes" width="20"> | | |

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

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import lombok.RequiredArgsConstructor;
3131
import lombok.extern.slf4j.Slf4j;
3232
import org.eclipse.lsp4j.CallHierarchyRegistrationOptions;
33+
import org.eclipse.lsp4j.ClientCapabilities;
3334
import org.eclipse.lsp4j.CodeActionKind;
3435
import org.eclipse.lsp4j.CodeActionOptions;
3536
import org.eclipse.lsp4j.CodeLensOptions;
@@ -44,13 +45,17 @@
4445
import org.eclipse.lsp4j.InitializeParams;
4546
import org.eclipse.lsp4j.InitializeResult;
4647
import org.eclipse.lsp4j.ReferenceOptions;
48+
import org.eclipse.lsp4j.RenameCapabilities;
49+
import org.eclipse.lsp4j.RenameOptions;
4750
import org.eclipse.lsp4j.SaveOptions;
4851
import org.eclipse.lsp4j.SelectionRangeRegistrationOptions;
4952
import org.eclipse.lsp4j.ServerCapabilities;
5053
import org.eclipse.lsp4j.ServerInfo;
54+
import org.eclipse.lsp4j.TextDocumentClientCapabilities;
5155
import org.eclipse.lsp4j.TextDocumentSyncKind;
5256
import org.eclipse.lsp4j.TextDocumentSyncOptions;
5357
import org.eclipse.lsp4j.WorkspaceSymbolOptions;
58+
import org.eclipse.lsp4j.jsonrpc.messages.Either;
5459
import org.eclipse.lsp4j.services.LanguageServer;
5560
import org.eclipse.lsp4j.services.TextDocumentService;
5661
import org.eclipse.lsp4j.services.WorkspaceService;
@@ -62,6 +67,7 @@
6267
import java.net.URISyntaxException;
6368
import java.nio.file.Path;
6469
import java.util.List;
70+
import java.util.Optional;
6571
import java.util.concurrent.CompletableFuture;
6672

6773
@Slf4j
@@ -101,6 +107,7 @@ public CompletableFuture<InitializeResult> initialize(InitializeParams params) {
101107
capabilities.setCallHierarchyProvider(getCallHierarchyProvider());
102108
capabilities.setSelectionRangeProvider(getSelectionRangeProvider());
103109
capabilities.setColorProvider(getColorProvider());
110+
capabilities.setRenameProvider(getRenameProvider(params));
104111

105112
var result = new InitializeResult(capabilities, serverInfo);
106113

@@ -273,4 +280,32 @@ private static ColorProviderOptions getColorProvider() {
273280
colorProviderOptions.setWorkDoneProgress(Boolean.FALSE);
274281
return colorProviderOptions;
275282
}
283+
284+
private static Either<Boolean, RenameOptions> getRenameProvider(InitializeParams params) {
285+
286+
if (Boolean.TRUE.equals(getRenamePrepareSupport(params))) {
287+
288+
var renameOptions = new RenameOptions();
289+
renameOptions.setWorkDoneProgress(Boolean.FALSE);
290+
renameOptions.setPrepareProvider(Boolean.TRUE);
291+
292+
return Either.forRight(renameOptions);
293+
294+
} else {
295+
296+
return Either.forLeft(Boolean.TRUE);
297+
298+
}
299+
300+
}
301+
302+
private static Boolean getRenamePrepareSupport(InitializeParams params) {
303+
return Optional.of(params)
304+
.map(InitializeParams::getCapabilities)
305+
.map(ClientCapabilities::getTextDocument)
306+
.map(TextDocumentClientCapabilities::getRename)
307+
.map(RenameCapabilities::getPrepareSupport)
308+
.orElse(false);
309+
}
310+
276311
}

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

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import com.github._1c_syntax.bsl.languageserver.providers.FormatProvider;
4141
import com.github._1c_syntax.bsl.languageserver.providers.HoverProvider;
4242
import com.github._1c_syntax.bsl.languageserver.providers.ReferencesProvider;
43+
import com.github._1c_syntax.bsl.languageserver.providers.RenameProvider;
4344
import com.github._1c_syntax.bsl.languageserver.providers.SelectionRangeProvider;
4445
import com.github._1c_syntax.bsl.languageserver.utils.Ranges;
4546
import lombok.RequiredArgsConstructor;
@@ -75,11 +76,16 @@
7576
import org.eclipse.lsp4j.HoverParams;
7677
import org.eclipse.lsp4j.Location;
7778
import org.eclipse.lsp4j.LocationLink;
79+
import org.eclipse.lsp4j.PrepareRenameParams;
80+
import org.eclipse.lsp4j.PrepareRenameResult;
81+
import org.eclipse.lsp4j.Range;
7882
import org.eclipse.lsp4j.ReferenceParams;
83+
import org.eclipse.lsp4j.RenameParams;
7984
import org.eclipse.lsp4j.SelectionRange;
8085
import org.eclipse.lsp4j.SelectionRangeParams;
8186
import org.eclipse.lsp4j.SymbolInformation;
8287
import org.eclipse.lsp4j.TextEdit;
88+
import org.eclipse.lsp4j.WorkspaceEdit;
8389
import org.eclipse.lsp4j.jsonrpc.messages.Either;
8490
import org.eclipse.lsp4j.services.TextDocumentService;
8591
import org.springframework.stereotype.Component;
@@ -108,6 +114,7 @@ public class BSLTextDocumentService implements TextDocumentService, ProtocolExte
108114
private final CallHierarchyProvider callHierarchyProvider;
109115
private final SelectionRangeProvider selectionRangeProvider;
110116
private final ColorProvider colorProvider;
117+
private final RenameProvider renameProvider;
111118

112119
@Override
113120
public CompletableFuture<Hover> hover(HoverParams params) {
@@ -372,6 +379,27 @@ public CompletableFuture<Diagnostics> diagnostics(DiagnosticParams params) {
372379
});
373380
}
374381

382+
@Override
383+
public CompletableFuture<Either<Range, PrepareRenameResult>> prepareRename(PrepareRenameParams params) {
384+
var documentContext = context.getDocument(params.getTextDocument().getUri());
385+
if (documentContext == null) {
386+
return CompletableFuture.completedFuture(null);
387+
}
388+
389+
return CompletableFuture.supplyAsync(() ->
390+
Either.forLeft(renameProvider.getPrepareRename(documentContext, params)));
391+
}
392+
393+
@Override
394+
public CompletableFuture<WorkspaceEdit> rename(RenameParams params) {
395+
var documentContext = context.getDocument(params.getTextDocument().getUri());
396+
if (documentContext == null) {
397+
return CompletableFuture.completedFuture(null);
398+
}
399+
400+
return CompletableFuture.supplyAsync(() -> renameProvider.getRename(documentContext, params));
401+
}
402+
375403
public void reset() {
376404
context.clear();
377405
}
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/*
2+
* This file is a part of BSL Language Server.
3+
*
4+
* Copyright (c) 2018-2022
5+
* Alexey Sosnoviy <labotamy@gmail.com>, Nikita Fedkin <nixel2007@gmail.com> 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 com.github._1c_syntax.bsl.languageserver.providers;
23+
24+
import com.github._1c_syntax.bsl.languageserver.context.DocumentContext;
25+
import com.github._1c_syntax.bsl.languageserver.context.symbol.SourceDefinedSymbol;
26+
import com.github._1c_syntax.bsl.languageserver.references.ReferenceIndex;
27+
import com.github._1c_syntax.bsl.languageserver.references.ReferenceResolver;
28+
import com.github._1c_syntax.bsl.languageserver.references.model.OccurrenceType;
29+
import com.github._1c_syntax.bsl.languageserver.references.model.Reference;
30+
import lombok.RequiredArgsConstructor;
31+
import org.eclipse.lsp4j.Location;
32+
import org.eclipse.lsp4j.Range;
33+
import org.eclipse.lsp4j.RenameParams;
34+
import org.eclipse.lsp4j.TextDocumentPositionParams;
35+
import org.eclipse.lsp4j.TextEdit;
36+
import org.eclipse.lsp4j.WorkspaceEdit;
37+
import org.springframework.stereotype.Component;
38+
39+
import java.util.Collection;
40+
import java.util.List;
41+
import java.util.Map;
42+
import java.util.stream.Collector;
43+
import java.util.stream.Collectors;
44+
import java.util.stream.Stream;
45+
46+
/**
47+
* Провайдер, обрабатывающий запросы {@code textDocument/rename}
48+
* и {@code textDocument/prepareRename}.
49+
*
50+
* @see <a href="https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_rename">Rename Request specification</a>.
51+
* @see <a href="https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_prepareRename">Prepare Document Request specification</a>.
52+
*/
53+
@Component
54+
@RequiredArgsConstructor
55+
public final class RenameProvider {
56+
57+
private final ReferenceResolver referenceResolver;
58+
private final ReferenceIndex referenceIndex;
59+
60+
/**
61+
* {@link WorkspaceEdit}
62+
*
63+
* @param documentContext Контекст документа.
64+
* @param params Параметры вызова.
65+
* @return Изменения документов
66+
*/
67+
public WorkspaceEdit getRename(DocumentContext documentContext, RenameParams params) {
68+
69+
var position = params.getPosition();
70+
var sourceDefinedSymbol = referenceResolver.findReference(documentContext.getUri(), position)
71+
.flatMap(Reference::getSourceDefinedSymbol);
72+
73+
Map<String, List<TextEdit>> changes = Stream.concat(
74+
sourceDefinedSymbol
75+
.stream()
76+
.map(referenceIndex::getReferencesTo)
77+
.flatMap(Collection::stream),
78+
sourceDefinedSymbol
79+
.stream().map(RenameProvider::referenceOf)
80+
).collect(Collectors.groupingBy(ref -> ref.getUri().toString(), getTexEdits(params)));
81+
82+
return new WorkspaceEdit(changes);
83+
}
84+
85+
private static Reference referenceOf(SourceDefinedSymbol symbol) {
86+
return Reference.of(
87+
symbol,
88+
symbol,
89+
new Location(symbol.getOwner().getUri().toString(), symbol.getSelectionRange()),
90+
OccurrenceType.DEFINITION
91+
);
92+
}
93+
94+
/**
95+
* {@link Range}
96+
*
97+
* @param documentContext Контекст документа.
98+
* @param params Параметры вызова.
99+
* @return Range
100+
*/
101+
public Range getPrepareRename(DocumentContext documentContext, TextDocumentPositionParams params) {
102+
103+
return referenceResolver.findReference(
104+
documentContext.getUri(), params.getPosition())
105+
.filter(Reference::isSourceDefinedSymbolReference)
106+
.map(Reference::getSelectionRange)
107+
.orElse(null);
108+
}
109+
110+
private static Collector<Reference, ?, List<TextEdit>> getTexEdits(RenameParams params) {
111+
return Collectors.mapping(
112+
Reference::getSelectionRange,
113+
Collectors.mapping(range -> newTextEdit(params, range), Collectors.toList())
114+
);
115+
}
116+
117+
private static TextEdit newTextEdit(RenameParams params, Range range) {
118+
return new TextEdit(range, params.getNewName());
119+
}
120+
121+
}

src/test/java/com/github/_1c_syntax/bsl/languageserver/BSLLanguageServerTest.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,11 @@
2424
import com.ginsberg.junit.exit.ExpectSystemExitWithStatus;
2525
import com.github._1c_syntax.bsl.languageserver.util.CleanupContextBeforeClassAndAfterEachTestMethod;
2626
import com.github._1c_syntax.utils.Absolute;
27+
import org.eclipse.lsp4j.ClientCapabilities;
2728
import org.eclipse.lsp4j.InitializeParams;
2829
import org.eclipse.lsp4j.InitializeResult;
30+
import org.eclipse.lsp4j.RenameCapabilities;
31+
import org.eclipse.lsp4j.TextDocumentClientCapabilities;
2932
import org.eclipse.lsp4j.WorkspaceFolder;
3033
import org.junit.jupiter.api.Test;
3134
import org.springframework.beans.factory.annotation.Autowired;
@@ -61,6 +64,28 @@ void initialize() throws ExecutionException, InterruptedException {
6164
assertThat(initialize.getCapabilities().getWorkspaceSymbolProvider().isRight()).isTrue();
6265
}
6366

67+
@Test
68+
void initializeRename() throws ExecutionException, InterruptedException {
69+
// given
70+
InitializeParams params = new InitializeParams();
71+
72+
WorkspaceFolder workspaceFolder = new WorkspaceFolder(Absolute.path(PATH_TO_METADATA).toUri().toString());
73+
List<WorkspaceFolder> workspaceFolders = List.of(workspaceFolder);
74+
params.setWorkspaceFolders(workspaceFolders);
75+
76+
var capabilities = new ClientCapabilities();
77+
params.setCapabilities(capabilities);
78+
capabilities.setTextDocument(new TextDocumentClientCapabilities());
79+
var textDocument = capabilities.getTextDocument();
80+
textDocument.setRename(new RenameCapabilities());
81+
textDocument.getRename().setPrepareSupport(true);
82+
// when
83+
InitializeResult initialize = server.initialize(params).get();
84+
85+
// then
86+
assertThat(initialize.getCapabilities().getRenameProvider().isRight()).isTrue();
87+
}
88+
6489
@Test
6590
void shutdown() throws ExecutionException, InterruptedException {
6691
CompletableFuture<Object> shutdown = server.shutdown();

src/test/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentServiceTest.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@
2929
import org.eclipse.lsp4j.DidCloseTextDocumentParams;
3030
import org.eclipse.lsp4j.DidOpenTextDocumentParams;
3131
import org.eclipse.lsp4j.DidSaveTextDocumentParams;
32+
import org.eclipse.lsp4j.Position;
33+
import org.eclipse.lsp4j.PrepareRenameParams;
34+
import org.eclipse.lsp4j.RenameParams;
3235
import org.eclipse.lsp4j.TextDocumentContentChangeEvent;
3336
import org.eclipse.lsp4j.TextDocumentIdentifier;
3437
import org.eclipse.lsp4j.TextDocumentItem;
@@ -137,6 +140,28 @@ void testDiagnosticsKnownFileFilteredRange() throws ExecutionException, Interrup
137140
assertThat(diagnostics.getDiagnostics()).hasSize(2);
138141
}
139142

143+
@Test
144+
void testRename() throws ExecutionException, InterruptedException, IOException {
145+
var params = new RenameParams();
146+
params.setTextDocument(getTextDocumentIdentifier());
147+
params.setPosition(new Position(0, 16));
148+
149+
var result = textDocumentService.rename(params);
150+
151+
assertThat(result).isNotNull();
152+
}
153+
154+
@Test
155+
void testRenamePrepare() throws ExecutionException, InterruptedException, IOException {
156+
var params = new PrepareRenameParams();
157+
params.setTextDocument(getTextDocumentIdentifier());
158+
params.setPosition(new Position(0, 16));
159+
160+
var result = textDocumentService.prepareRename(params);
161+
162+
assertThat(result).isNotNull();
163+
}
164+
140165
private File getTestFile() {
141166
return new File("./src/test/resources/BSLTextDocumentServiceTest.bsl");
142167
}

0 commit comments

Comments
 (0)