|
77 | 77 | import org.eclipse.lsp4j.RenameFilesParams;
|
78 | 78 | import org.eclipse.lsp4j.RenameOptions;
|
79 | 79 | import org.eclipse.lsp4j.RenameParams;
|
| 80 | +import org.eclipse.lsp4j.SelectionRange; |
| 81 | +import org.eclipse.lsp4j.SelectionRangeParams; |
80 | 82 | import org.eclipse.lsp4j.SemanticTokens;
|
81 | 83 | import org.eclipse.lsp4j.SemanticTokensDelta;
|
82 | 84 | import org.eclipse.lsp4j.SemanticTokensDeltaParams;
|
@@ -190,6 +192,7 @@ public void initializeServerCapabilities(ServerCapabilities result) {
|
190 | 192 | result.setRenameProvider(new RenameOptions(true));
|
191 | 193 | result.setCodeActionProvider(true);
|
192 | 194 | result.setExecuteCommandProvider(new ExecuteCommandOptions(Collections.singletonList(RascalWorkspaceService.RASCAL_COMMAND)));
|
| 195 | + result.setSelectionRangeProvider(true); |
193 | 196 | }
|
194 | 197 |
|
195 | 198 | @Override
|
@@ -517,6 +520,36 @@ public CompletableFuture<SemanticTokens> semanticTokensRange(SemanticTokensRange
|
517 | 520 | return getSemanticTokens(params.getTextDocument());
|
518 | 521 | }
|
519 | 522 |
|
| 523 | + @Override |
| 524 | + public CompletableFuture<List<SelectionRange>> selectionRange(SelectionRangeParams params) { |
| 525 | + logger.debug("Selection range: {}", params); |
| 526 | + TextDocumentState file = getFile(params.getTextDocument()); |
| 527 | + return file.getCurrentTreeAsync() |
| 528 | + .thenApply(Versioned::get) |
| 529 | + .handle((t, r) -> (t == null ? file.getLastTreeWithoutErrors().get() : t)) |
| 530 | + .thenApply(tr -> params.getPositions().stream() |
| 531 | + .map(p -> { |
| 532 | + Position rascalCursorPos = Locations.toRascalPosition(file.getLocation(), p, columns); |
| 533 | + // Compute focus list for cursor position |
| 534 | + var focus = TreeSearch.computeFocusList(tr, rascalCursorPos.getLine(), rascalCursorPos.getCharacter()); |
| 535 | + // Iterate in reverse order, starting with the outermost location |
| 536 | + var ranges = focus.reverse().stream() |
| 537 | + .map(ITree.class::cast) |
| 538 | + .map(TreeAdapter::getLocation) |
| 539 | + // Map to distinct ranges |
| 540 | + .map(l -> Locations.toRange(l, columns)).distinct() |
| 541 | + .collect(Collectors.toList()); |
| 542 | + |
| 543 | + // reduce to a single, nested SelectionRange |
| 544 | + SelectionRange parent = null; |
| 545 | + for (var r : ranges) { |
| 546 | + parent = new SelectionRange(r, parent); |
| 547 | + } |
| 548 | + return parent; |
| 549 | + }) |
| 550 | + .collect(Collectors.toList())); |
| 551 | + } |
| 552 | + |
520 | 553 | @Override
|
521 | 554 | public void registerLanguage(LanguageParameter lang) {
|
522 | 555 | throw new UnsupportedOperationException("registering language is a feature of the language parametric server, not of the Rascal server");
|
|
0 commit comments