-
Notifications
You must be signed in to change notification settings - Fork 109
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
232 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
86 changes: 86 additions & 0 deletions
86
src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/CompletionProvider.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
package com.github._1c_syntax.bsl.languageserver.providers; | ||
|
||
import com.github._1c_syntax.bsl.languageserver.context.DocumentContext; | ||
import com.github._1c_syntax.bsl.languageserver.context.symbol.SourceDefinedSymbol; | ||
import com.github._1c_syntax.bsl.languageserver.context.symbol.Symbol; | ||
import com.github._1c_syntax.bsl.languageserver.types.KnownTypes; | ||
import com.github._1c_syntax.bsl.languageserver.types.TypeResolver; | ||
import com.github._1c_syntax.bsl.languageserver.utils.Ranges; | ||
import com.github._1c_syntax.bsl.languageserver.utils.Trees; | ||
import com.github._1c_syntax.bsl.parser.BSLLexer; | ||
import lombok.RequiredArgsConstructor; | ||
import org.eclipse.lsp4j.CompletionItem; | ||
import org.eclipse.lsp4j.CompletionItemKind; | ||
import org.eclipse.lsp4j.CompletionList; | ||
import org.eclipse.lsp4j.CompletionParams; | ||
import org.eclipse.lsp4j.Range; | ||
import org.eclipse.lsp4j.SymbolKind; | ||
import org.eclipse.lsp4j.jsonrpc.messages.Either; | ||
import org.springframework.stereotype.Component; | ||
|
||
import java.util.Collection; | ||
import java.util.Collections; | ||
import java.util.List; | ||
import java.util.Optional; | ||
|
||
@Component | ||
@RequiredArgsConstructor | ||
public class CompletionProvider { | ||
|
||
private final TypeResolver typeResolver; | ||
private final KnownTypes knownTypes; | ||
|
||
public Either<List<CompletionItem>, CompletionList> getCompletions(DocumentContext documentContext, CompletionParams params) { | ||
|
||
var completionList = new CompletionList(); | ||
|
||
var position = params.getPosition(); | ||
var terminalNode = Trees.findTerminalNodeContainsPosition(documentContext.getAst(), position).orElseThrow(); | ||
|
||
if (terminalNode.getSymbol().getType() != BSLLexer.DOT) { | ||
return Either.forRight(completionList); | ||
} | ||
|
||
var previousToken = Trees.getPreviousTokenFromDefaultChannel(documentContext.getTokens(), terminalNode.getSymbol().getTokenIndex() - 1); | ||
var completionItems = previousToken | ||
.map(Ranges::create) | ||
.map(Range::getStart) | ||
.map(previousTokenPosition -> typeResolver.findTypes(documentContext.getUri(), previousTokenPosition)) | ||
.stream() | ||
.flatMap(Collection::stream) | ||
.map(knownTypes::getSymbolByType) | ||
.filter(Optional::isPresent) | ||
.map(Optional::get) | ||
.flatMap(symbol -> getChildren(symbol).stream()) | ||
.map(symbol -> { | ||
var completionItem = new CompletionItem(); | ||
completionItem.setLabel(symbol.getName()); | ||
completionItem.setKind(getCompletionItemKind(symbol.getSymbolKind())); | ||
|
||
return completionItem; | ||
}) | ||
.toList(); | ||
|
||
completionList.setItems(completionItems); | ||
|
||
return Either.forRight(completionList); | ||
} | ||
|
||
private CompletionItemKind getCompletionItemKind(SymbolKind symbolKind) { | ||
return switch (symbolKind) { | ||
case Class -> CompletionItemKind.Class; | ||
case Method -> CompletionItemKind.Method; | ||
case Variable -> CompletionItemKind.Variable; | ||
case Module -> CompletionItemKind.Module; | ||
default -> CompletionItemKind.Text; | ||
}; | ||
} | ||
|
||
private List<? extends Symbol> getChildren(Symbol symbol) { | ||
if (!(symbol instanceof SourceDefinedSymbol sourceDefinedSymbol)) { | ||
return Collections.emptyList(); | ||
} | ||
|
||
return sourceDefinedSymbol.getChildren(); | ||
} | ||
} |
39 changes: 39 additions & 0 deletions
39
src/main/java/com/github/_1c_syntax/bsl/languageserver/types/KnownTypes.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package com.github._1c_syntax.bsl.languageserver.types; | ||
|
||
import com.github._1c_syntax.bsl.languageserver.context.events.DocumentContextContentChangedEvent; | ||
import com.github._1c_syntax.bsl.languageserver.context.symbol.Symbol; | ||
import org.apache.commons.io.FilenameUtils; | ||
import org.springframework.context.event.EventListener; | ||
import org.springframework.stereotype.Component; | ||
|
||
import java.util.Map; | ||
import java.util.Optional; | ||
import java.util.concurrent.ConcurrentHashMap; | ||
|
||
@Component | ||
public class KnownTypes { | ||
|
||
private final Map<Type, Symbol> knownTypes = new ConcurrentHashMap<>(); | ||
|
||
public void addType(Type type, Symbol symbol) { | ||
knownTypes.put(type, symbol); | ||
} | ||
|
||
public Optional<Symbol> getSymbolByType(Type type) { | ||
return Optional.ofNullable(knownTypes.get(type)); | ||
} | ||
|
||
public void clear() { | ||
knownTypes.clear(); | ||
} | ||
|
||
@EventListener | ||
public void handleEvent(DocumentContextContentChangedEvent event) { | ||
var documentContext = event.getSource(); | ||
// TODO: this logic should be moved to somewhere else. It will break for BSL files. | ||
var typeName = FilenameUtils.getBaseName(documentContext.getUri().getPath()); | ||
var module = documentContext.getSymbolTree().getModule(); | ||
|
||
addType(new Type(typeName), module); | ||
} | ||
} |
57 changes: 57 additions & 0 deletions
57
src/test/java/com/github/_1c_syntax/bsl/languageserver/providers/CompletionProviderTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
package com.github._1c_syntax.bsl.languageserver.providers; | ||
|
||
import com.github._1c_syntax.bsl.languageserver.context.ServerContext; | ||
import com.github._1c_syntax.bsl.languageserver.util.CleanupContextBeforeClassAndAfterClass; | ||
import com.github._1c_syntax.bsl.languageserver.util.TestUtils; | ||
import jakarta.annotation.PostConstruct; | ||
import org.eclipse.lsp4j.CompletionItemKind; | ||
import org.eclipse.lsp4j.CompletionParams; | ||
import org.eclipse.lsp4j.Position; | ||
import org.junit.jupiter.api.Test; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.boot.test.context.SpringBootTest; | ||
|
||
import java.nio.file.Paths; | ||
|
||
import static com.github._1c_syntax.bsl.languageserver.util.Assertions.assertThat; | ||
import static org.junit.jupiter.api.Assertions.assertTrue; | ||
|
||
@SpringBootTest | ||
@CleanupContextBeforeClassAndAfterClass | ||
class CompletionProviderTest { | ||
|
||
@Autowired | ||
private CompletionProvider completionProvider; | ||
|
||
@Autowired | ||
private ServerContext serverContext; | ||
|
||
private static final String PATH_TO_FILE = "./src/test/resources/providers/completion.os"; | ||
|
||
@PostConstruct | ||
void prepareServerContext() { | ||
serverContext.setConfigurationRoot(Paths.get("src/test/resources/metadata/oslib")); | ||
serverContext.populateContext(); | ||
} | ||
|
||
@Test | ||
void completionAfterDotOnOSClass() { | ||
// given | ||
var documentContext = TestUtils.getDocumentContextFromFile(PATH_TO_FILE); | ||
|
||
var params = new CompletionParams(); | ||
params.setPosition(new Position(3, 13)); | ||
|
||
// when | ||
var completions = completionProvider.getCompletions(documentContext, params); | ||
|
||
// then | ||
assertTrue(completions.isRight()); | ||
|
||
var completionList = completions.getRight(); | ||
assertThat(completionList.getItems()).hasSize(1); | ||
assertThat(completionList.getItems().get(0).getLabel()).isEqualTo("NewObject"); | ||
assertThat(completionList.getItems().get(0).getKind()).isEqualTo(CompletionItemKind.Method); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
Перем ЭкспортнаяПеременная Экспорт; | ||
Перем НеЭкспортнаяПеременная; | ||
|
||
Функция ЭкспортнаяФункция() Экспорт | ||
Возврат ""; | ||
КонецФункции | ||
|
||
Функция НеЭкспортнаяФункция() | ||
Возврат ""; | ||
КонецФункции | ||
|
||
Процедура ЭкспортнаяПроцедура() Экспорт | ||
КонецПроцедуры | ||
|
||
Процедура НеЭкспортнаяПроцедура() | ||
КонецПроцедуры | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
#Использовать "metadata/oslib" | ||
|
||
КакойТоКласс = Новый МойКласс(); | ||
КакойТоКласс. |