diff --git a/org.eclipse.xtext.ide.tests/src/org/eclipse/xtext/ide/tests/server/RenameTest.xtend b/org.eclipse.xtext.ide.tests/src/org/eclipse/xtext/ide/tests/server/RenameTest.xtend index 8ec9c6e28..54b0a19f3 100644 --- a/org.eclipse.xtext.ide.tests/src/org/eclipse/xtext/ide/tests/server/RenameTest.xtend +++ b/org.eclipse.xtext.ide.tests/src/org/eclipse/xtext/ide/tests/server/RenameTest.xtend @@ -39,13 +39,24 @@ class RenameTest extends AbstractTestLangLanguageServerTest { } @Test - def void testRenameOnDeclaration() { - doTest(firstFile, new Position(0,5)) + def void testRenameBeforeDeclaration() { + doTest(firstFile, new Position(0, 4)) } + @Test + def void testRenameOnDeclaration() { + doTest(firstFile, new Position(0, 5)) + } + + @Test + def void testRenameAfterDeclaration() { + doTest(firstFile, new Position(0, 8)) + } + + @Test def void testRenameOnReference() { - doTest(firstFile, new Position(1,5)) + doTest(firstFile, new Position(1, 5)) } @Test diff --git a/org.eclipse.xtext.ide.tests/src/org/eclipse/xtext/ide/tests/server/RenameTest2.xtend b/org.eclipse.xtext.ide.tests/src/org/eclipse/xtext/ide/tests/server/RenameTest2.xtend index 131bf34a8..ce57082f2 100644 --- a/org.eclipse.xtext.ide.tests/src/org/eclipse/xtext/ide/tests/server/RenameTest2.xtend +++ b/org.eclipse.xtext.ide.tests/src/org/eclipse/xtext/ide/tests/server/RenameTest2.xtend @@ -12,6 +12,9 @@ import org.eclipse.lsp4j.RenameParams import org.eclipse.lsp4j.TextDocumentIdentifier import org.eclipse.xtext.testing.AbstractLanguageServerTest import org.junit.Test +import org.eclipse.lsp4j.ClientCapabilities +import org.eclipse.lsp4j.WorkspaceClientCapabilities +import org.eclipse.lsp4j.WorkspaceEditCapabilities /** * @author koehnlein - Initial contribution and API @@ -38,9 +41,9 @@ class RenameTest2 extends AbstractLanguageServerTest { val workspaceEdit = languageServer.rename(params).get assertEquals(''' changes : - Foo.fileawaretestlanguage : Bar [[2, 8] .. [2, 11]] - Bar [[3, 5] .. [3, 8]] documentChanges : + Foo.fileawaretestlanguage <1> : Bar [[2, 8] .. [2, 11]] + Bar [[3, 5] .. [3, 8]] '''.toString, toExpectation(workspaceEdit)) } @@ -64,11 +67,21 @@ class RenameTest2 extends AbstractLanguageServerTest { val workspaceEdit = languageServer.rename(params).get assertEquals(''' changes : - Foo.fileawaretestlanguage : Baz [[2, 8] .. [2, 11]] + documentChanges : + Foo.fileawaretestlanguage <1> : Baz [[2, 8] .. [2, 11]] Bar [[5, 5] .. [5, 16]] Bar [[6, 5] .. [6, 12]] - documentChanges : '''.toString, toExpectation(workspaceEdit)) } + + override protected initialize() { + super.initialize([params | params.capabilities = new ClientCapabilities => [ + workspace = new WorkspaceClientCapabilities => [ + workspaceEdit = new WorkspaceEditCapabilities => [ + documentChanges = true + ] + ] + ]]) + } } \ No newline at end of file diff --git a/org.eclipse.xtext.ide.tests/xtend-gen/org/eclipse/xtext/ide/tests/server/CompletionTest.java b/org.eclipse.xtext.ide.tests/xtend-gen/org/eclipse/xtext/ide/tests/server/CompletionTest.java index 6279b6f5b..aaf6a8be6 100644 --- a/org.eclipse.xtext.ide.tests/xtend-gen/org/eclipse/xtext/ide/tests/server/CompletionTest.java +++ b/org.eclipse.xtext.ide.tests/xtend-gen/org/eclipse/xtext/ide/tests/server/CompletionTest.java @@ -28,7 +28,9 @@ import org.eclipse.lsp4j.Range; import org.eclipse.lsp4j.SemanticHighlightingInformation; import org.eclipse.lsp4j.SignatureHelp; import org.eclipse.lsp4j.SymbolInformation; +import org.eclipse.lsp4j.TextDocumentEdit; import org.eclipse.lsp4j.TextEdit; +import org.eclipse.lsp4j.VersionedTextDocumentIdentifier; import org.eclipse.lsp4j.WorkspaceEdit; import org.eclipse.lsp4j.jsonrpc.messages.Either; import org.eclipse.xtend2.lib.StringConcatenation; @@ -334,6 +336,8 @@ public class CompletionTest extends AbstractTestLangLanguageServerTest { return _toExpectation((DocumentHighlightKind)it); } else if (it instanceof String) { return _toExpectation((String)it); + } else if (it instanceof VersionedTextDocumentIdentifier) { + return _toExpectation((VersionedTextDocumentIdentifier)it); } else if (it instanceof Pair) { return _toExpectation((Pair>>)it); } else if (it == null) { @@ -366,6 +370,8 @@ public class CompletionTest extends AbstractTestLangLanguageServerTest { return _toExpectation((SignatureHelp)it); } else if (it instanceof SymbolInformation) { return _toExpectation((SymbolInformation)it); + } else if (it instanceof TextDocumentEdit) { + return _toExpectation((TextDocumentEdit)it); } else if (it instanceof TextEdit) { return _toExpectation((TextEdit)it); } else if (it instanceof WorkspaceEdit) { diff --git a/org.eclipse.xtext.ide.tests/xtend-gen/org/eclipse/xtext/ide/tests/server/RenameTest.java b/org.eclipse.xtext.ide.tests/xtend-gen/org/eclipse/xtext/ide/tests/server/RenameTest.java index 89e9052cd..a607e9747 100644 --- a/org.eclipse.xtext.ide.tests/xtend-gen/org/eclipse/xtext/ide/tests/server/RenameTest.java +++ b/org.eclipse.xtext.ide.tests/xtend-gen/org/eclipse/xtext/ide/tests/server/RenameTest.java @@ -51,12 +51,24 @@ public class RenameTest extends AbstractTestLangLanguageServerTest { this.initialize(); } + @Test + public void testRenameBeforeDeclaration() { + Position _position = new Position(0, 4); + this.doTest(this.firstFile, _position); + } + @Test public void testRenameOnDeclaration() { Position _position = new Position(0, 5); this.doTest(this.firstFile, _position); } + @Test + public void testRenameAfterDeclaration() { + Position _position = new Position(0, 8); + this.doTest(this.firstFile, _position); + } + @Test public void testRenameOnReference() { Position _position = new Position(1, 5); diff --git a/org.eclipse.xtext.ide.tests/xtend-gen/org/eclipse/xtext/ide/tests/server/RenameTest2.java b/org.eclipse.xtext.ide.tests/xtend-gen/org/eclipse/xtext/ide/tests/server/RenameTest2.java index d2906a260..07d9f0067 100644 --- a/org.eclipse.xtext.ide.tests/xtend-gen/org/eclipse/xtext/ide/tests/server/RenameTest2.java +++ b/org.eclipse.xtext.ide.tests/xtend-gen/org/eclipse/xtext/ide/tests/server/RenameTest2.java @@ -7,13 +7,20 @@ */ package org.eclipse.xtext.ide.tests.server; +import org.eclipse.lsp4j.ClientCapabilities; +import org.eclipse.lsp4j.InitializeParams; +import org.eclipse.lsp4j.InitializeResult; import org.eclipse.lsp4j.Position; import org.eclipse.lsp4j.RenameParams; import org.eclipse.lsp4j.TextDocumentIdentifier; +import org.eclipse.lsp4j.WorkspaceClientCapabilities; import org.eclipse.lsp4j.WorkspaceEdit; +import org.eclipse.lsp4j.WorkspaceEditCapabilities; import org.eclipse.xtend2.lib.StringConcatenation; import org.eclipse.xtext.testing.AbstractLanguageServerTest; import org.eclipse.xtext.xbase.lib.Exceptions; +import org.eclipse.xtext.xbase.lib.ObjectExtensions; +import org.eclipse.xtext.xbase.lib.Procedures.Procedure1; import org.junit.Test; /** @@ -49,14 +56,14 @@ public class RenameTest2 extends AbstractLanguageServerTest { StringConcatenation _builder_1 = new StringConcatenation(); _builder_1.append("changes :"); _builder_1.newLine(); + _builder_1.append("documentChanges : "); + _builder_1.newLine(); _builder_1.append(" "); - _builder_1.append("Foo.fileawaretestlanguage : Bar [[2, 8] .. [2, 11]]"); + _builder_1.append("Foo.fileawaretestlanguage <1> : Bar [[2, 8] .. [2, 11]]"); _builder_1.newLine(); _builder_1.append(" "); _builder_1.append("Bar [[3, 5] .. [3, 8]]"); _builder_1.newLine(); - _builder_1.append("documentChanges : "); - _builder_1.newLine(); this.assertEquals(_builder_1.toString(), this.toExpectation(workspaceEdit)); } catch (Throwable _e) { throw Exceptions.sneakyThrow(_e); @@ -99,8 +106,10 @@ public class RenameTest2 extends AbstractLanguageServerTest { StringConcatenation _builder_1 = new StringConcatenation(); _builder_1.append("changes :"); _builder_1.newLine(); + _builder_1.append("documentChanges : "); + _builder_1.newLine(); _builder_1.append(" "); - _builder_1.append("Foo.fileawaretestlanguage : Baz [[2, 8] .. [2, 11]]"); + _builder_1.append("Foo.fileawaretestlanguage <1> : Baz [[2, 8] .. [2, 11]]"); _builder_1.newLine(); _builder_1.append(" "); _builder_1.append("Bar [[5, 5] .. [5, 16]]"); @@ -108,11 +117,32 @@ public class RenameTest2 extends AbstractLanguageServerTest { _builder_1.append(" "); _builder_1.append("Bar [[6, 5] .. [6, 12]]"); _builder_1.newLine(); - _builder_1.append("documentChanges : "); - _builder_1.newLine(); this.assertEquals(_builder_1.toString(), this.toExpectation(workspaceEdit)); } catch (Throwable _e) { throw Exceptions.sneakyThrow(_e); } } + + @Override + protected InitializeResult initialize() { + final Procedure1 _function = (InitializeParams params) -> { + ClientCapabilities _clientCapabilities = new ClientCapabilities(); + final Procedure1 _function_1 = (ClientCapabilities it) -> { + WorkspaceClientCapabilities _workspaceClientCapabilities = new WorkspaceClientCapabilities(); + final Procedure1 _function_2 = (WorkspaceClientCapabilities it_1) -> { + WorkspaceEditCapabilities _workspaceEditCapabilities = new WorkspaceEditCapabilities(); + final Procedure1 _function_3 = (WorkspaceEditCapabilities it_2) -> { + it_2.setDocumentChanges(Boolean.valueOf(true)); + }; + WorkspaceEditCapabilities _doubleArrow = ObjectExtensions.operator_doubleArrow(_workspaceEditCapabilities, _function_3); + it_1.setWorkspaceEdit(_doubleArrow); + }; + WorkspaceClientCapabilities _doubleArrow = ObjectExtensions.operator_doubleArrow(_workspaceClientCapabilities, _function_2); + it.setWorkspace(_doubleArrow); + }; + ClientCapabilities _doubleArrow = ObjectExtensions.operator_doubleArrow(_clientCapabilities, _function_1); + params.setCapabilities(_doubleArrow); + }; + return super.initialize(_function); + } } diff --git a/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/server/LanguageServerImpl.xtend b/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/server/LanguageServerImpl.xtend index e2dcbf4bc..3b902e1f6 100644 --- a/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/server/LanguageServerImpl.xtend +++ b/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/server/LanguageServerImpl.xtend @@ -102,6 +102,7 @@ import static org.eclipse.xtext.diagnostics.Severity.* import com.google.common.collect.ImmutableMultimap import com.google.common.collect.ImmutableMap import org.eclipse.xtext.findReferences.IReferenceFinder.IResourceAccess +import org.eclipse.xtext.ide.server.rename.IRenameServiceExtension /** * @author Sven Efftinge - Initial contribution and API @@ -607,14 +608,19 @@ import org.eclipse.xtext.findReferences.IReferenceFinder.IResourceAccess throw new UnsupportedOperationException("TODO: auto-generated method stub") } - override rename(RenameParams params) { + override rename(RenameParams renameParams) { return requestManager.runRead[ cancelIndicator | - val uri = params.textDocument.uri.toUri + val uri = renameParams.textDocument.uri.toUri val resourceServiceProvider = uri.resourceServiceProvider val renameService = resourceServiceProvider?.get(IRenameService) if (renameService === null) return new WorkspaceEdit - renameService.rename(workspaceManager, params, cancelIndicator) + if (renameService instanceof IRenameServiceExtension) { + val options = new IRenameServiceExtension.Options(params?.capabilities?.workspace?.workspaceEdit?.documentChanges === Boolean.TRUE) + renameService.rename(workspaceManager, renameParams, options, cancelIndicator) + } else { + renameService.rename(workspaceManager, renameParams, cancelIndicator) + } ] } diff --git a/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/server/rename/ChangeConverter.xtend b/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/server/rename/ChangeConverter.xtend index 99dfb96a3..eb50f6040 100644 --- a/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/server/rename/ChangeConverter.xtend +++ b/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/server/rename/ChangeConverter.xtend @@ -14,10 +14,14 @@ import org.eclipse.emf.common.util.URI import org.eclipse.emf.ecore.resource.Resource import org.eclipse.emf.ecore.xmi.XMLResource import org.eclipse.lsp4j.Range +import org.eclipse.lsp4j.TextDocumentEdit import org.eclipse.lsp4j.TextEdit +import org.eclipse.lsp4j.VersionedTextDocumentIdentifier import org.eclipse.lsp4j.WorkspaceEdit +import org.eclipse.lsp4j.jsonrpc.messages.Either import org.eclipse.xtext.ide.serializer.IEmfResourceChange import org.eclipse.xtext.ide.serializer.ITextDocumentChange +import org.eclipse.xtext.ide.server.Document import org.eclipse.xtext.ide.server.WorkspaceManager import org.eclipse.xtext.parser.IEncodingProvider import org.eclipse.xtext.resource.IResourceServiceProvider @@ -31,21 +35,35 @@ class ChangeConverter implements IAcceptor { static class Factory { - @Inject IResourceServiceProvider.Registry registry + @Inject protected IResourceServiceProvider.Registry registry + /** + * @deprecated use {@link #create(WorkspaceManager, WorkspaceEdit, boolean} instead. + */ + @Deprecated def ChangeConverter create(WorkspaceManager workspaceManager, WorkspaceEdit edit) { - new ChangeConverter(workspaceManager, registry, edit) + new ChangeConverter(workspaceManager, registry, edit, null) + } + + def ChangeConverter create(WorkspaceManager workspaceManager, WorkspaceEdit edit, IRenameServiceExtension.Options options) { + new ChangeConverter(workspaceManager, registry, edit, options) } } val WorkspaceManager workspaceManager val IResourceServiceProvider.Registry registry val WorkspaceEdit edit + val IRenameServiceExtension.Options options - protected new(WorkspaceManager workspaceManager, IResourceServiceProvider.Registry registry, WorkspaceEdit edit) { + protected new(WorkspaceManager workspaceManager, IResourceServiceProvider.Registry registry, WorkspaceEdit edit, IRenameServiceExtension.Options options) { this.workspaceManager = workspaceManager this.registry = registry this.edit = edit + this.options = options + if (options?.clientSupportsVerisonedDocuments) + this.edit.documentChanges = newArrayList + else + this.edit.changes = newLinkedHashMap } override accept(IEmfResourceChange change) { @@ -61,7 +79,7 @@ class ChangeConverter implements IAcceptor { workspaceManager.doRead(uri) [ document, resource | val range = new Range(document.getPosition(0), document.getPosition(document.contents.length)) val textEdit = new TextEdit(range, newContent) - addTextEdit(uri, textEdit) + addTextEdit(uri, document, textEdit) ] } finally { outputStream.close @@ -88,12 +106,24 @@ class ChangeConverter implements IAcceptor { val range = new Range(start, end) new TextEdit(range, replacement.replacementText) ] - addTextEdit(uri, textEdits) + addTextEdit(uri, document, textEdits) ] } } - protected def addTextEdit(URI uri, TextEdit... textEdit) { - edit.changes.put(uri.toString, textEdit) + protected def addTextEdit(URI theUri, Document document, TextEdit... textEdits) { + if (options?.clientSupportsVerisonedDocuments) { + edit.documentChanges += + Either.forLeft(new TextDocumentEdit => [ + textDocument = new VersionedTextDocumentIdentifier => [ + uri = theUri.toString + version = document.version + ] + edits = textEdits + ]) + } else { + edit.changes.put(theUri.toString, textEdits) + } } + } diff --git a/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/server/rename/IRenameService.xtend b/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/server/rename/IRenameService.xtend index 7abca85fb..f06b76992 100644 --- a/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/server/rename/IRenameService.xtend +++ b/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/server/rename/IRenameService.xtend @@ -9,13 +9,34 @@ package org.eclipse.xtext.ide.server.rename import org.eclipse.lsp4j.RenameParams import org.eclipse.lsp4j.WorkspaceEdit +import org.eclipse.xtend.lib.annotations.Data import org.eclipse.xtext.ide.server.WorkspaceManager import org.eclipse.xtext.util.CancelIndicator /** * @author koehnlein - Initial contribution and API * @since 2.13 + * @deprectated implement IRenameService2 instead. */ +@Deprecated interface IRenameService { def WorkspaceEdit rename(WorkspaceManager workspaceManager, RenameParams renameParams, CancelIndicator cancelIndicator) +} + +/** + * The implementation of rename refactoring for a language. + * + * As opposed to {@link IRenameService} this returns {@link TextDocumentChanges} if the + * client supports versioned documents. + * + * @author koehnlein - Initial contribution and API + * @since 2.17 + */ +interface IRenameServiceExtension { + def WorkspaceEdit rename(WorkspaceManager workspaceManager, RenameParams renameParams, Options options, CancelIndicator cancelIndicator) + + @Data + class Options { + boolean clientSupportsVerisonedDocuments + } } \ No newline at end of file diff --git a/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/server/rename/RenameService.xtend b/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/server/rename/RenameService.xtend index 32caa768e..6680dd0e2 100644 --- a/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/server/rename/RenameService.xtend +++ b/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/server/rename/RenameService.xtend @@ -9,59 +9,86 @@ package org.eclipse.xtext.ide.server.rename import com.google.inject.Inject import com.google.inject.Provider +import org.eclipse.emf.ecore.EObject import org.eclipse.emf.ecore.util.EcoreUtil +import org.eclipse.lsp4j.Position import org.eclipse.lsp4j.RenameParams import org.eclipse.lsp4j.WorkspaceEdit +import org.eclipse.xtend.lib.annotations.Accessors +import org.eclipse.xtext.TerminalRule +import org.eclipse.xtext.ide.refactoring.IRenameStrategy2 import org.eclipse.xtext.ide.refactoring.RenameChange import org.eclipse.xtext.ide.refactoring.RenameContext import org.eclipse.xtext.ide.serializer.IChangeSerializer +import org.eclipse.xtext.ide.server.Document import org.eclipse.xtext.ide.server.UriExtensions import org.eclipse.xtext.ide.server.WorkspaceManager +import org.eclipse.xtext.nodemodel.ILeafNode +import org.eclipse.xtext.nodemodel.util.NodeModelUtils +import org.eclipse.xtext.parsetree.reconstr.impl.TokenUtil import org.eclipse.xtext.resource.EObjectAtOffsetHelper +import org.eclipse.xtext.resource.IResourceServiceProvider import org.eclipse.xtext.resource.XtextResource -import org.eclipse.xtext.util.CancelIndicator -import static org.eclipse.xtext.ide.refactoring.RefactoringIssueAcceptor.Severity.* -import org.eclipse.xtext.ide.refactoring.IRenameStrategy2 import org.eclipse.xtext.resource.impl.ResourceDescriptionsProvider +import org.eclipse.xtext.util.CancelIndicator + +import static org.eclipse.xtext.ide.refactoring.RefactoringIssueAcceptor.Severity.* /** * @author koehnlein - Initial contribution and API * @since 2.13 */ -class RenameService implements IRenameService { +@Accessors(PROTECTED_GETTER) +class RenameService implements IRenameService, IRenameServiceExtension { - @Inject extension EObjectAtOffsetHelper + @Inject extension EObjectAtOffsetHelper eObjectAtOffsetHelper @Inject IRenameStrategy2 renameStrategy @Inject ChangeConverter.Factory converterFactory - @Inject extension UriExtensions + @Inject extension UriExtensions uriExtensions @Inject Provider changeSerializerProvider @Inject Provider issueProvider + @Inject IResourceServiceProvider.Registry serviceProviderRegistry + + @Inject TokenUtil tokenUtil + + /** + * @deprecated use {@link #rename(WorkspaceManager, RenameParams, Options, CancelIndicator)} + * instead. + */ + @Deprecated override rename(WorkspaceManager workspaceManager, RenameParams renameParams, CancelIndicator cancelIndicator) { + rename(workspaceManager, renameParams, new Options(false), cancelIndicator) + } + + override rename(WorkspaceManager workspaceManager, RenameParams renameParams, Options options, CancelIndicator cancelIndicator) { val uri = renameParams.textDocument.uri.toUri val issueAcceptor = issueProvider.get - workspaceManager.doRead(uri) [ document, resource | + workspaceManager.doRead(uri) [ document, resource | val projectManager = workspaceManager.getProjectManager(uri) val resourceSet = projectManager.createNewResourceSet(projectManager.indexState.resourceDescriptions) resourceSet.loadOptions.put(ResourceDescriptionsProvider.LIVE_SCOPE, true) - val offset = document.getOffSet(renameParams.position) val workspaceEdit = new WorkspaceEdit val xtextResource = resourceSet.getResource(resource.URI, true) if (xtextResource instanceof XtextResource) { - val element = xtextResource.resolveElementAt(offset) + val element = xtextResource.getElementAtOffset(document, renameParams.position) if (element === null || element.eIsProxy) { - issueAcceptor.add(FATAL, '''No element found at position line:«renameParams.position.line» column:«renameParams.position.character»''') + issueAcceptor.add( + FATAL, '''No element found at position line:«renameParams.position.line» column:«renameParams.position.character»''') } else { + val services = serviceProviderRegistry.getResourceServiceProvider(element.eResource.URI) + val changeSerializer = services.get(IChangeSerializer) val change = new RenameChange(renameParams.newName, EcoreUtil.getURI(element)) - val changeSerializer = changeSerializerProvider.get val context = new RenameContext(#[change], resourceSet, changeSerializer, issueAcceptor) + val renameStrategy = services.get(IRenameStrategy2) renameStrategy.applyRename(context) - val changeConverter = converterFactory.create(workspaceManager, workspaceEdit) + val converterFactory = services.get(ChangeConverter.Factory) + val changeConverter = converterFactory.create(workspaceManager, workspaceEdit, options) changeSerializer.applyModifications(changeConverter) } } else { @@ -70,4 +97,19 @@ class RenameService implements IRenameService { return workspaceEdit ] } + + protected def EObject getElementAtOffset(XtextResource xtextResource, Document document, Position caretPosition) { + val caretOffset = document.getOffSet(caretPosition) + val leafNode = NodeModelUtils.findLeafNodeAtOffset(xtextResource.parseResult.rootNode, caretOffset) + val offset = if (caretOffset > 0 && leafNode.offset === caretOffset && !isIdentifier(leafNode)) + caretOffset - 1 + else + caretOffset + return xtextResource.resolveElementAt(offset) + } + + protected def isIdentifier(ILeafNode leafNode) { + return leafNode.grammarElement instanceof TerminalRule + && !tokenUtil.isWhitespaceOrCommentNode(leafNode) + } } \ No newline at end of file diff --git a/org.eclipse.xtext.ide/xtend-gen/org/eclipse/xtext/ide/server/LanguageServerImpl.java b/org.eclipse.xtext.ide/xtend-gen/org/eclipse/xtext/ide/server/LanguageServerImpl.java index 83122b623..f6574883f 100644 --- a/org.eclipse.xtext.ide/xtend-gen/org/eclipse/xtext/ide/server/LanguageServerImpl.java +++ b/org.eclipse.xtext.ide/xtend-gen/org/eclipse/xtext/ide/server/LanguageServerImpl.java @@ -83,6 +83,7 @@ import org.eclipse.lsp4j.TextDocumentSyncKind; import org.eclipse.lsp4j.TextEdit; import org.eclipse.lsp4j.WorkspaceClientCapabilities; import org.eclipse.lsp4j.WorkspaceEdit; +import org.eclipse.lsp4j.WorkspaceEditCapabilities; import org.eclipse.lsp4j.WorkspaceSymbolParams; import org.eclipse.lsp4j.jsonrpc.Endpoint; import org.eclipse.lsp4j.jsonrpc.json.JsonRpcMethod; @@ -120,6 +121,7 @@ import org.eclipse.xtext.ide.server.formatting.FormattingService; import org.eclipse.xtext.ide.server.hover.IHoverService; import org.eclipse.xtext.ide.server.occurrences.IDocumentHighlightService; import org.eclipse.xtext.ide.server.rename.IRenameService; +import org.eclipse.xtext.ide.server.rename.IRenameServiceExtension; import org.eclipse.xtext.ide.server.semanticHighlight.SemanticHighlightingRegistry; import org.eclipse.xtext.ide.server.signatureHelp.ISignatureHelpService; import org.eclipse.xtext.ide.server.symbol.DocumentSymbolService; @@ -925,11 +927,11 @@ public class LanguageServerImpl implements LanguageServer, WorkspaceService, Tex } @Override - public CompletableFuture rename(final RenameParams params) { + public CompletableFuture rename(final RenameParams renameParams) { final Function1 _function = (CancelIndicator cancelIndicator) -> { WorkspaceEdit _xblockexpression = null; { - final URI uri = this._uriExtensions.toUri(params.getTextDocument().getUri()); + final URI uri = this._uriExtensions.toUri(renameParams.getTextDocument().getUri()); final IResourceServiceProvider resourceServiceProvider = this.languagesRegistry.getResourceServiceProvider(uri); IRenameService _get = null; if (resourceServiceProvider!=null) { @@ -939,7 +941,35 @@ public class LanguageServerImpl implements LanguageServer, WorkspaceService, Tex if ((renameService == null)) { return new WorkspaceEdit(); } - _xblockexpression = renameService.rename(this.workspaceManager, params, cancelIndicator); + WorkspaceEdit _xifexpression = null; + if ((renameService instanceof IRenameServiceExtension)) { + WorkspaceEdit _xblockexpression_1 = null; + { + ClientCapabilities _capabilities = null; + if (this.params!=null) { + _capabilities=this.params.getCapabilities(); + } + WorkspaceClientCapabilities _workspace = null; + if (_capabilities!=null) { + _workspace=_capabilities.getWorkspace(); + } + WorkspaceEditCapabilities _workspaceEdit = null; + if (_workspace!=null) { + _workspaceEdit=_workspace.getWorkspaceEdit(); + } + Boolean _documentChanges = null; + if (_workspaceEdit!=null) { + _documentChanges=_workspaceEdit.getDocumentChanges(); + } + boolean _tripleEquals = (_documentChanges == Boolean.TRUE); + final IRenameServiceExtension.Options options = new IRenameServiceExtension.Options(_tripleEquals); + _xblockexpression_1 = ((IRenameServiceExtension)renameService).rename(this.workspaceManager, renameParams, options, cancelIndicator); + } + _xifexpression = _xblockexpression_1; + } else { + _xifexpression = renameService.rename(this.workspaceManager, renameParams, cancelIndicator); + } + _xblockexpression = _xifexpression; } return _xblockexpression; }; diff --git a/org.eclipse.xtext.ide/xtend-gen/org/eclipse/xtext/ide/server/rename/ChangeConverter.java b/org.eclipse.xtext.ide/xtend-gen/org/eclipse/xtext/ide/server/rename/ChangeConverter.java index 6d491ca9d..908d58e1b 100644 --- a/org.eclipse.xtext.ide/xtend-gen/org/eclipse/xtext/ide/server/rename/ChangeConverter.java +++ b/org.eclipse.xtext.ide/xtend-gen/org/eclipse/xtext/ide/server/rename/ChangeConverter.java @@ -17,22 +17,30 @@ import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.xmi.XMLResource; import org.eclipse.lsp4j.Position; import org.eclipse.lsp4j.Range; +import org.eclipse.lsp4j.ResourceOperation; +import org.eclipse.lsp4j.TextDocumentEdit; import org.eclipse.lsp4j.TextEdit; +import org.eclipse.lsp4j.VersionedTextDocumentIdentifier; import org.eclipse.lsp4j.WorkspaceEdit; +import org.eclipse.lsp4j.jsonrpc.messages.Either; import org.eclipse.xtext.formatting2.regionaccess.ITextReplacement; import org.eclipse.xtext.ide.serializer.IEmfResourceChange; import org.eclipse.xtext.ide.serializer.ITextDocumentChange; import org.eclipse.xtext.ide.server.Document; import org.eclipse.xtext.ide.server.WorkspaceManager; +import org.eclipse.xtext.ide.server.rename.IRenameServiceExtension; import org.eclipse.xtext.parser.IEncodingProvider; import org.eclipse.xtext.resource.IResourceServiceProvider; import org.eclipse.xtext.resource.XtextResource; import org.eclipse.xtext.util.IAcceptor; +import org.eclipse.xtext.xbase.lib.CollectionLiterals; import org.eclipse.xtext.xbase.lib.Conversions; import org.eclipse.xtext.xbase.lib.Exceptions; import org.eclipse.xtext.xbase.lib.Functions.Function1; import org.eclipse.xtext.xbase.lib.Functions.Function2; import org.eclipse.xtext.xbase.lib.ListExtensions; +import org.eclipse.xtext.xbase.lib.ObjectExtensions; +import org.eclipse.xtext.xbase.lib.Procedures.Procedure1; /** * @author koehnlein - Initial contribution and API @@ -42,10 +50,18 @@ import org.eclipse.xtext.xbase.lib.ListExtensions; public class ChangeConverter implements IAcceptor { public static class Factory { @Inject - private IResourceServiceProvider.Registry registry; + protected IResourceServiceProvider.Registry registry; + /** + * @deprecated use {@link #create(WorkspaceManager, WorkspaceEdit, boolean} instead. + */ + @Deprecated public ChangeConverter create(final WorkspaceManager workspaceManager, final WorkspaceEdit edit) { - return new ChangeConverter(workspaceManager, this.registry, edit); + return new ChangeConverter(workspaceManager, this.registry, edit, null); + } + + public ChangeConverter create(final WorkspaceManager workspaceManager, final WorkspaceEdit edit, final IRenameServiceExtension.Options options) { + return new ChangeConverter(workspaceManager, this.registry, edit, options); } } @@ -55,10 +71,22 @@ public class ChangeConverter implements IAcceptor { private final WorkspaceEdit edit; - protected ChangeConverter(final WorkspaceManager workspaceManager, final IResourceServiceProvider.Registry registry, final WorkspaceEdit edit) { + private final IRenameServiceExtension.Options options; + + protected ChangeConverter(final WorkspaceManager workspaceManager, final IResourceServiceProvider.Registry registry, final WorkspaceEdit edit, final IRenameServiceExtension.Options options) { this.workspaceManager = workspaceManager; this.registry = registry; this.edit = edit; + this.options = options; + boolean _isClientSupportsVerisonedDocuments = false; + if (options!=null) { + _isClientSupportsVerisonedDocuments=options.isClientSupportsVerisonedDocuments(); + } + if (_isClientSupportsVerisonedDocuments) { + this.edit.setDocumentChanges(CollectionLiterals.>newArrayList()); + } else { + this.edit.setChanges(CollectionLiterals.>newLinkedHashMap()); + } } @Override @@ -75,18 +103,18 @@ public class ChangeConverter implements IAcceptor { byte[] _byteArray = outputStream.toByteArray(); String _charset = this.getCharset(change.getResource()); final String newContent = new String(_byteArray, _charset); - final Function2> _function = (Document document, XtextResource resource) -> { - List _xblockexpression = null; + final Function2 _function = (Document document, XtextResource resource) -> { + Object _xblockexpression = null; { Position _position = document.getPosition(0); Position _position_1 = document.getPosition(document.getContents().length()); final Range range = new Range(_position, _position_1); final TextEdit textEdit = new TextEdit(range, newContent); - _xblockexpression = this.addTextEdit(uri, textEdit); + _xblockexpression = this.addTextEdit(uri, document, textEdit); } return _xblockexpression; }; - this.workspaceManager.>doRead(uri, _function); + this.workspaceManager.doRead(uri, _function); } finally { outputStream.close(); } @@ -121,8 +149,8 @@ public class ChangeConverter implements IAcceptor { boolean _greaterThan = (_size > 0); if (_greaterThan) { final URI uri = change.getNewURI(); - final Function2> _function = (Document document, XtextResource resource) -> { - List _xblockexpression = null; + final Function2 _function = (Document document, XtextResource resource) -> { + Object _xblockexpression = null; { final Function1 _function_1 = (ITextReplacement replacement) -> { TextEdit _xblockexpression_1 = null; @@ -139,16 +167,40 @@ public class ChangeConverter implements IAcceptor { return _xblockexpression_1; }; final List textEdits = ListExtensions.map(change.getReplacements(), _function_1); - _xblockexpression = this.addTextEdit(uri, ((TextEdit[])Conversions.unwrapArray(textEdits, TextEdit.class))); + _xblockexpression = this.addTextEdit(uri, document, ((TextEdit[])Conversions.unwrapArray(textEdits, TextEdit.class))); } return _xblockexpression; }; - this.workspaceManager.>doRead(uri, _function); + this.workspaceManager.doRead(uri, _function); } } - protected List addTextEdit(final URI uri, final TextEdit... textEdit) { - return this.edit.getChanges().put(uri.toString(), ((List)Conversions.doWrapArray(textEdit))); + protected Object addTextEdit(final URI theUri, final Document document, final TextEdit... textEdits) { + Object _xifexpression = null; + boolean _isClientSupportsVerisonedDocuments = false; + if (this.options!=null) { + _isClientSupportsVerisonedDocuments=this.options.isClientSupportsVerisonedDocuments(); + } + if (_isClientSupportsVerisonedDocuments) { + List> _documentChanges = this.edit.getDocumentChanges(); + TextDocumentEdit _textDocumentEdit = new TextDocumentEdit(); + final Procedure1 _function = (TextDocumentEdit it) -> { + VersionedTextDocumentIdentifier _versionedTextDocumentIdentifier = new VersionedTextDocumentIdentifier(); + final Procedure1 _function_1 = (VersionedTextDocumentIdentifier it_1) -> { + it_1.setUri(theUri.toString()); + it_1.setVersion(document.getVersion()); + }; + VersionedTextDocumentIdentifier _doubleArrow = ObjectExtensions.operator_doubleArrow(_versionedTextDocumentIdentifier, _function_1); + it.setTextDocument(_doubleArrow); + it.setEdits(((List)Conversions.doWrapArray(textEdits))); + }; + TextDocumentEdit _doubleArrow = ObjectExtensions.operator_doubleArrow(_textDocumentEdit, _function); + Either _forLeft = Either.forLeft(_doubleArrow); + _xifexpression = Boolean.valueOf(_documentChanges.add(_forLeft)); + } else { + _xifexpression = this.edit.getChanges().put(theUri.toString(), ((List)Conversions.doWrapArray(textEdits))); + } + return _xifexpression; } protected void handleReplacements(final IEmfResourceChange change) { diff --git a/org.eclipse.xtext.ide/xtend-gen/org/eclipse/xtext/ide/server/rename/IRenameService.java b/org.eclipse.xtext.ide/xtend-gen/org/eclipse/xtext/ide/server/rename/IRenameService.java index 8c13c2c24..f5514604d 100644 --- a/org.eclipse.xtext.ide/xtend-gen/org/eclipse/xtext/ide/server/rename/IRenameService.java +++ b/org.eclipse.xtext.ide/xtend-gen/org/eclipse/xtext/ide/server/rename/IRenameService.java @@ -15,7 +15,9 @@ import org.eclipse.xtext.util.CancelIndicator; /** * @author koehnlein - Initial contribution and API * @since 2.13 + * @deprectated implement IRenameService2 instead. */ +@Deprecated @SuppressWarnings("all") public interface IRenameService { public abstract WorkspaceEdit rename(final WorkspaceManager workspaceManager, final RenameParams renameParams, final CancelIndicator cancelIndicator); diff --git a/org.eclipse.xtext.ide/xtend-gen/org/eclipse/xtext/ide/server/rename/IRenameServiceExtension.java b/org.eclipse.xtext.ide/xtend-gen/org/eclipse/xtext/ide/server/rename/IRenameServiceExtension.java new file mode 100644 index 000000000..e6b5d26d1 --- /dev/null +++ b/org.eclipse.xtext.ide/xtend-gen/org/eclipse/xtext/ide/server/rename/IRenameServiceExtension.java @@ -0,0 +1,74 @@ +/** + * Copyright (c) 2017 TypeFox GmbH (http://www.typefox.io) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.xtext.ide.server.rename; + +import org.eclipse.lsp4j.RenameParams; +import org.eclipse.lsp4j.WorkspaceEdit; +import org.eclipse.xtend.lib.annotations.Data; +import org.eclipse.xtext.ide.server.WorkspaceManager; +import org.eclipse.xtext.util.CancelIndicator; +import org.eclipse.xtext.xbase.lib.Pure; +import org.eclipse.xtext.xbase.lib.util.ToStringBuilder; + +/** + * The implementation of rename refactoring for a language. + * + * As opposed to {@link IRenameService} this returns {@link TextDocumentChanges} if the + * client supports versioned documents. + * + * @author koehnlein - Initial contribution and API + * @since 2.17 + */ +@SuppressWarnings("all") +public interface IRenameServiceExtension { + @Data + public static class Options { + private final boolean clientSupportsVerisonedDocuments; + + public Options(final boolean clientSupportsVerisonedDocuments) { + super(); + this.clientSupportsVerisonedDocuments = clientSupportsVerisonedDocuments; + } + + @Override + @Pure + public int hashCode() { + return 31 * 1 + (this.clientSupportsVerisonedDocuments ? 1231 : 1237); + } + + @Override + @Pure + public boolean equals(final Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + IRenameServiceExtension.Options other = (IRenameServiceExtension.Options) obj; + if (other.clientSupportsVerisonedDocuments != this.clientSupportsVerisonedDocuments) + return false; + return true; + } + + @Override + @Pure + public String toString() { + ToStringBuilder b = new ToStringBuilder(this); + b.add("clientSupportsVerisonedDocuments", this.clientSupportsVerisonedDocuments); + return b.toString(); + } + + @Pure + public boolean isClientSupportsVerisonedDocuments() { + return this.clientSupportsVerisonedDocuments; + } + } + + public abstract WorkspaceEdit rename(final WorkspaceManager workspaceManager, final RenameParams renameParams, final IRenameServiceExtension.Options options, final CancelIndicator cancelIndicator); +} diff --git a/org.eclipse.xtext.ide/xtend-gen/org/eclipse/xtext/ide/server/rename/RenameService.java b/org.eclipse.xtext.ide/xtend-gen/org/eclipse/xtext/ide/server/rename/RenameService.java index e5ed9d7cb..a1d300fa5 100644 --- a/org.eclipse.xtext.ide/xtend-gen/org/eclipse/xtext/ide/server/rename/RenameService.java +++ b/org.eclipse.xtext.ide/xtend-gen/org/eclipse/xtext/ide/server/rename/RenameService.java @@ -14,9 +14,13 @@ import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.util.EcoreUtil; +import org.eclipse.lsp4j.Position; import org.eclipse.lsp4j.RenameParams; import org.eclipse.lsp4j.WorkspaceEdit; +import org.eclipse.xtend.lib.annotations.AccessorType; +import org.eclipse.xtend.lib.annotations.Accessors; import org.eclipse.xtend2.lib.StringConcatenation; +import org.eclipse.xtext.TerminalRule; import org.eclipse.xtext.ide.refactoring.IRenameStrategy2; import org.eclipse.xtext.ide.refactoring.RefactoringIssueAcceptor; import org.eclipse.xtext.ide.refactoring.RenameChange; @@ -28,8 +32,13 @@ import org.eclipse.xtext.ide.server.UriExtensions; import org.eclipse.xtext.ide.server.WorkspaceManager; import org.eclipse.xtext.ide.server.rename.ChangeConverter; import org.eclipse.xtext.ide.server.rename.IRenameService; +import org.eclipse.xtext.ide.server.rename.IRenameServiceExtension; import org.eclipse.xtext.ide.server.rename.ServerRefactoringIssueAcceptor; +import org.eclipse.xtext.nodemodel.ILeafNode; +import org.eclipse.xtext.nodemodel.util.NodeModelUtils; +import org.eclipse.xtext.parsetree.reconstr.impl.TokenUtil; import org.eclipse.xtext.resource.EObjectAtOffsetHelper; +import org.eclipse.xtext.resource.IResourceServiceProvider; import org.eclipse.xtext.resource.XtextResource; import org.eclipse.xtext.resource.XtextResourceSet; import org.eclipse.xtext.resource.impl.ResourceDescriptionsProvider; @@ -37,16 +46,18 @@ import org.eclipse.xtext.util.CancelIndicator; import org.eclipse.xtext.xbase.lib.CollectionLiterals; import org.eclipse.xtext.xbase.lib.Extension; import org.eclipse.xtext.xbase.lib.Functions.Function2; +import org.eclipse.xtext.xbase.lib.Pure; /** * @author koehnlein - Initial contribution and API * @since 2.13 */ +@Accessors(AccessorType.PROTECTED_GETTER) @SuppressWarnings("all") -public class RenameService implements IRenameService { +public class RenameService implements IRenameService, IRenameServiceExtension { @Inject @Extension - private EObjectAtOffsetHelper _eObjectAtOffsetHelper; + private EObjectAtOffsetHelper eObjectAtOffsetHelper; @Inject private IRenameStrategy2 renameStrategy; @@ -56,7 +67,7 @@ public class RenameService implements IRenameService { @Inject @Extension - private UriExtensions _uriExtensions; + private UriExtensions uriExtensions; @Inject private Provider changeSerializerProvider; @@ -64,21 +75,37 @@ public class RenameService implements IRenameService { @Inject private Provider issueProvider; + @Inject + private IResourceServiceProvider.Registry serviceProviderRegistry; + + @Inject + private TokenUtil tokenUtil; + + /** + * @deprecated use {@link #rename(WorkspaceManager, RenameParams, Options, CancelIndicator)} + * instead. + */ + @Deprecated @Override public WorkspaceEdit rename(final WorkspaceManager workspaceManager, final RenameParams renameParams, final CancelIndicator cancelIndicator) { + IRenameServiceExtension.Options _options = new IRenameServiceExtension.Options(false); + return this.rename(workspaceManager, renameParams, _options, cancelIndicator); + } + + @Override + public WorkspaceEdit rename(final WorkspaceManager workspaceManager, final RenameParams renameParams, final IRenameServiceExtension.Options options, final CancelIndicator cancelIndicator) { WorkspaceEdit _xblockexpression = null; { - final URI uri = this._uriExtensions.toUri(renameParams.getTextDocument().getUri()); + final URI uri = this.uriExtensions.toUri(renameParams.getTextDocument().getUri()); final ServerRefactoringIssueAcceptor issueAcceptor = this.issueProvider.get(); final Function2 _function = (Document document, XtextResource resource) -> { final ProjectManager projectManager = workspaceManager.getProjectManager(uri); final XtextResourceSet resourceSet = projectManager.createNewResourceSet(projectManager.getIndexState().getResourceDescriptions()); resourceSet.getLoadOptions().put(ResourceDescriptionsProvider.LIVE_SCOPE, Boolean.valueOf(true)); - final int offset = document.getOffSet(renameParams.getPosition()); final WorkspaceEdit workspaceEdit = new WorkspaceEdit(); final Resource xtextResource = resourceSet.getResource(resource.getURI(), true); if ((xtextResource instanceof XtextResource)) { - final EObject element = this._eObjectAtOffsetHelper.resolveElementAt(((XtextResource)xtextResource), offset); + final EObject element = this.getElementAtOffset(((XtextResource)xtextResource), document, renameParams.getPosition()); if (((element == null) || element.eIsProxy())) { StringConcatenation _builder = new StringConcatenation(); _builder.append("No element found at position line:"); @@ -87,15 +114,19 @@ public class RenameService implements IRenameService { _builder.append(" column:"); int _character = renameParams.getPosition().getCharacter(); _builder.append(_character); - issueAcceptor.add(RefactoringIssueAcceptor.Severity.FATAL, _builder.toString()); + issueAcceptor.add( + RefactoringIssueAcceptor.Severity.FATAL, _builder.toString()); } else { + final IResourceServiceProvider services = this.serviceProviderRegistry.getResourceServiceProvider(element.eResource().getURI()); + final IChangeSerializer changeSerializer = services.get(IChangeSerializer.class); String _newName = renameParams.getNewName(); URI _uRI = EcoreUtil.getURI(element); final RenameChange change = new RenameChange(_newName, _uRI); - final IChangeSerializer changeSerializer = this.changeSerializerProvider.get(); final RenameContext context = new RenameContext(Collections.unmodifiableList(CollectionLiterals.newArrayList(change)), resourceSet, changeSerializer, issueAcceptor); - this.renameStrategy.applyRename(context); - final ChangeConverter changeConverter = this.converterFactory.create(workspaceManager, workspaceEdit); + final IRenameStrategy2 renameStrategy = services.get(IRenameStrategy2.class); + renameStrategy.applyRename(context); + final ChangeConverter.Factory converterFactory = services.get(ChangeConverter.Factory.class); + final ChangeConverter changeConverter = converterFactory.create(workspaceManager, workspaceEdit, options); changeSerializer.applyModifications(changeConverter); } } else { @@ -107,4 +138,61 @@ public class RenameService implements IRenameService { } return _xblockexpression; } + + protected EObject getElementAtOffset(final XtextResource xtextResource, final Document document, final Position caretPosition) { + final int caretOffset = document.getOffSet(caretPosition); + final ILeafNode leafNode = NodeModelUtils.findLeafNodeAtOffset(xtextResource.getParseResult().getRootNode(), caretOffset); + int _xifexpression = (int) 0; + if ((((caretOffset > 0) && (leafNode.getOffset() == caretOffset)) && (!this.isIdentifier(leafNode)))) { + _xifexpression = (caretOffset - 1); + } else { + _xifexpression = caretOffset; + } + final int offset = _xifexpression; + return this.eObjectAtOffsetHelper.resolveElementAt(xtextResource, offset); + } + + protected boolean isIdentifier(final ILeafNode leafNode) { + return ((leafNode.getGrammarElement() instanceof TerminalRule) && (!this.tokenUtil.isWhitespaceOrCommentNode(leafNode))); + } + + @Pure + protected EObjectAtOffsetHelper getEObjectAtOffsetHelper() { + return this.eObjectAtOffsetHelper; + } + + @Pure + protected IRenameStrategy2 getRenameStrategy() { + return this.renameStrategy; + } + + @Pure + protected ChangeConverter.Factory getConverterFactory() { + return this.converterFactory; + } + + @Pure + protected UriExtensions getUriExtensions() { + return this.uriExtensions; + } + + @Pure + protected Provider getChangeSerializerProvider() { + return this.changeSerializerProvider; + } + + @Pure + protected Provider getIssueProvider() { + return this.issueProvider; + } + + @Pure + protected IResourceServiceProvider.Registry getServiceProviderRegistry() { + return this.serviceProviderRegistry; + } + + @Pure + protected TokenUtil getTokenUtil() { + return this.tokenUtil; + } } diff --git a/org.eclipse.xtext.testing/src/org/eclipse/xtext/testing/AbstractLanguageServerTest.xtend b/org.eclipse.xtext.testing/src/org/eclipse/xtext/testing/AbstractLanguageServerTest.xtend index dcd8e2246..b6e7b693d 100644 --- a/org.eclipse.xtext.testing/src/org/eclipse/xtext/testing/AbstractLanguageServerTest.xtend +++ b/org.eclipse.xtext.testing/src/org/eclipse/xtext/testing/AbstractLanguageServerTest.xtend @@ -54,10 +54,12 @@ import org.eclipse.lsp4j.SemanticHighlightingInformation import org.eclipse.lsp4j.SemanticHighlightingParams import org.eclipse.lsp4j.SignatureHelp import org.eclipse.lsp4j.SymbolInformation +import org.eclipse.lsp4j.TextDocumentEdit import org.eclipse.lsp4j.TextDocumentIdentifier import org.eclipse.lsp4j.TextDocumentItem import org.eclipse.lsp4j.TextDocumentPositionParams import org.eclipse.lsp4j.TextEdit +import org.eclipse.lsp4j.VersionedTextDocumentIdentifier import org.eclipse.lsp4j.WorkspaceEdit import org.eclipse.lsp4j.WorkspaceSymbolParams import org.eclipse.lsp4j.jsonrpc.Endpoint @@ -419,6 +421,15 @@ abstract class AbstractLanguageServerTest implements Endpoint { edit : «edit.toExpectation» ''' + protected def dispatch String toExpectation(TextDocumentEdit e) ''' + «e.textDocument.toExpectation» : «e.edits.toExpectation» + ''' + + protected def dispatch String toExpectation(VersionedTextDocumentIdentifier v) + '''«org.eclipse.emf.common.util.URI.createURI(v.uri).lastSegment» <«v.version»>''' + + + @Accessors static class TestCodeActionConfiguration extends TextDocumentPositionConfiguration { String expectedCodeActions = '' diff --git a/org.eclipse.xtext.testing/xtend-gen/org/eclipse/xtext/testing/AbstractLanguageServerTest.java b/org.eclipse.xtext.testing/xtend-gen/org/eclipse/xtext/testing/AbstractLanguageServerTest.java index 445b1d891..1474d514d 100644 --- a/org.eclipse.xtext.testing/xtend-gen/org/eclipse/xtext/testing/AbstractLanguageServerTest.java +++ b/org.eclipse.xtext.testing/xtend-gen/org/eclipse/xtext/testing/AbstractLanguageServerTest.java @@ -67,6 +67,7 @@ import org.eclipse.lsp4j.SignatureHelp; import org.eclipse.lsp4j.SignatureInformation; import org.eclipse.lsp4j.SymbolInformation; import org.eclipse.lsp4j.TextDocumentClientCapabilities; +import org.eclipse.lsp4j.TextDocumentEdit; import org.eclipse.lsp4j.TextDocumentIdentifier; import org.eclipse.lsp4j.TextDocumentItem; import org.eclipse.lsp4j.TextDocumentPositionParams; @@ -936,6 +937,28 @@ public abstract class AbstractLanguageServerTest implements Endpoint { return _builder.toString(); } + protected String _toExpectation(final TextDocumentEdit e) { + StringConcatenation _builder = new StringConcatenation(); + String _expectation = this.toExpectation(e.getTextDocument()); + _builder.append(_expectation); + _builder.append(" : "); + String _expectation_1 = this.toExpectation(e.getEdits()); + _builder.append(_expectation_1); + _builder.newLineIfNotEmpty(); + return _builder.toString(); + } + + protected String _toExpectation(final VersionedTextDocumentIdentifier v) { + StringConcatenation _builder = new StringConcatenation(); + String _lastSegment = org.eclipse.emf.common.util.URI.createURI(v.getUri()).lastSegment(); + _builder.append(_lastSegment); + _builder.append(" <"); + Integer _version = v.getVersion(); + _builder.append(_version); + _builder.append(">"); + return _builder.toString(); + } + protected void testCodeAction(final Procedure1 configurator) { try { @Extension @@ -1459,6 +1482,8 @@ public abstract class AbstractLanguageServerTest implements Endpoint { return _toExpectation((DocumentHighlightKind)it); } else if (it instanceof String) { return _toExpectation((String)it); + } else if (it instanceof VersionedTextDocumentIdentifier) { + return _toExpectation((VersionedTextDocumentIdentifier)it); } else if (it instanceof Pair) { return _toExpectation((Pair>>)it); } else if (it == null) { @@ -1491,6 +1516,8 @@ public abstract class AbstractLanguageServerTest implements Endpoint { return _toExpectation((SignatureHelp)it); } else if (it instanceof SymbolInformation) { return _toExpectation((SymbolInformation)it); + } else if (it instanceof TextDocumentEdit) { + return _toExpectation((TextDocumentEdit)it); } else if (it instanceof TextEdit) { return _toExpectation((TextEdit)it); } else if (it instanceof WorkspaceEdit) {