/******************************************************************************* * Copyright (c) 2012-2017 Codenvy, S.A. * 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 * * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ package org.eclipse.che.api.languageserver.service; import com.google.inject.Singleton; import org.eclipse.che.api.languageserver.exception.LanguageServerException; import org.eclipse.che.api.languageserver.registry.LanguageServerRegistry; import org.eclipse.che.api.languageserver.registry.LanguageServerRegistryImpl; import org.eclipse.che.api.languageserver.server.dto.DtoServerImpls.CompletionItemDto; import org.eclipse.che.api.languageserver.server.dto.DtoServerImpls.CompletionListDto; import org.eclipse.che.api.languageserver.server.dto.DtoServerImpls.ExtendedCompletionItemDto; import org.eclipse.che.api.languageserver.server.dto.DtoServerImpls.HoverDto; import org.eclipse.che.api.languageserver.server.dto.DtoServerImpls.LocationDto; import org.eclipse.che.api.languageserver.server.dto.DtoServerImpls.SignatureHelpDto; import org.eclipse.che.api.languageserver.server.dto.DtoServerImpls.SymbolInformationDto; import org.eclipse.che.api.languageserver.server.dto.DtoServerImpls.TextEditDto; import org.eclipse.lsp4j.CompletionList; import org.eclipse.lsp4j.DidChangeTextDocumentParams; import org.eclipse.lsp4j.DidCloseTextDocumentParams; import org.eclipse.lsp4j.DidOpenTextDocumentParams; import org.eclipse.lsp4j.DidSaveTextDocumentParams; import org.eclipse.lsp4j.DocumentFormattingParams; import org.eclipse.lsp4j.DocumentHighlight; import org.eclipse.lsp4j.DocumentOnTypeFormattingParams; import org.eclipse.lsp4j.DocumentRangeFormattingParams; import org.eclipse.lsp4j.DocumentSymbolParams; import org.eclipse.lsp4j.Location; import org.eclipse.lsp4j.ReferenceParams; import org.eclipse.lsp4j.TextDocumentPositionParams; import org.eclipse.lsp4j.services.LanguageServer; import javax.inject.Inject; import javax.ws.rs.Consumes; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import java.util.Collections; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; /** * REST API for the textDoc * <p> * Dispatches onto the {@link LanguageServerRegistryImpl}. */ @Singleton @Path("languageserver/textDocument") public class TextDocumentService { private static final String FILE_PROJECTS = "file:///projects"; private final LanguageServerRegistry languageServerRegistry; @Inject public TextDocumentService(LanguageServerRegistry languageServerRegistry) { this.languageServerRegistry = languageServerRegistry; } static String prefixURI(String relativePath) { return FILE_PROJECTS + relativePath; } static String removePrefixUri(String uri) { if (uri.startsWith(FILE_PROJECTS)) { return uri.substring(FILE_PROJECTS.length()); } return uri; } @SuppressWarnings("deprecation") @POST @Path("completion") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public CompletionListDto completion(TextDocumentPositionParams textDocumentPositionParams) throws InterruptedException, ExecutionException, LanguageServerException { textDocumentPositionParams.getTextDocument().setUri(prefixURI(textDocumentPositionParams.getTextDocument().getUri())); textDocumentPositionParams.setUri(prefixURI(textDocumentPositionParams.getUri())); LanguageServer server = getServer(textDocumentPositionParams.getTextDocument().getUri()); if (server == null) { return null; } CompletionList result = server.getTextDocumentService().completion(textDocumentPositionParams).get(); return new CompletionListDto(result); } @POST @Path("documentSymbol") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public List<? extends SymbolInformationDto> documentSymbol(DocumentSymbolParams documentSymbolParams) throws ExecutionException, InterruptedException, LanguageServerException { documentSymbolParams.getTextDocument().setUri(prefixURI(documentSymbolParams.getTextDocument().getUri())); LanguageServer server = getServer(documentSymbolParams.getTextDocument().getUri()); if (server == null) { return Collections.emptyList(); } return server.getTextDocumentService().documentSymbol(documentSymbolParams).get().stream().map(o -> new SymbolInformationDto(o)) .collect(Collectors.toList()); } @POST @Path("references") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public List<? extends LocationDto> references(ReferenceParams params) throws ExecutionException, InterruptedException, LanguageServerException { params.getTextDocument().setUri(prefixURI(params.getTextDocument().getUri())); LanguageServer server = getServer(params.getTextDocument().getUri()); if (server == null) { return Collections.emptyList(); } List<? extends Location> locations = server.getTextDocumentService().references(params).get(); locations.forEach(o -> { o.setUri(removePrefixUri(o.getUri())); }); return locations.stream().map(o -> new LocationDto(o)).collect(Collectors.toList()); } @POST @Path("definition") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public List<? extends LocationDto> definition(TextDocumentPositionParams params) throws ExecutionException, InterruptedException, LanguageServerException { params.getTextDocument().setUri(prefixURI(params.getTextDocument().getUri())); LanguageServer server = getServer(params.getTextDocument().getUri()); if (server == null) { return Collections.emptyList(); } List<? extends Location> locations = server.getTextDocumentService().definition(params).get(); locations.forEach(o -> { o.setUri(removePrefixUri(o.getUri())); }); return locations.stream().map(o -> new LocationDto(o)).collect(Collectors.toList()); } @POST @Path("completionItem/resolve") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public CompletionItemDto resolveCompletionItem(ExtendedCompletionItemDto unresolved) throws InterruptedException, ExecutionException, LanguageServerException { LanguageServer server = getServer(prefixURI(unresolved.getTextDocumentIdentifier().getUri())); if (server != null) { return new CompletionItemDto(server.getTextDocumentService().resolveCompletionItem(unresolved).get()); } else { return new CompletionItemDto(unresolved); } } @SuppressWarnings("deprecation") @POST @Path("hover") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public HoverDto hover(TextDocumentPositionParams positionParams) throws LanguageServerException, ExecutionException, InterruptedException { positionParams.getTextDocument().setUri(prefixURI(positionParams.getTextDocument().getUri())); positionParams.setUri(prefixURI(positionParams.getUri())); LanguageServer server = getServer(positionParams.getTextDocument().getUri()); if (server != null) { return new HoverDto(server.getTextDocumentService().hover(positionParams).get()); } else { return null; } } @SuppressWarnings("deprecation") @POST @Path("signatureHelp") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public SignatureHelpDto signatureHelp(TextDocumentPositionParams positionParams) throws LanguageServerException, ExecutionException, InterruptedException { positionParams.getTextDocument().setUri(prefixURI(positionParams.getTextDocument().getUri())); positionParams.setUri(prefixURI(positionParams.getUri())); LanguageServer server = getServer(positionParams.getTextDocument().getUri()); if (server != null) { return new SignatureHelpDto(server.getTextDocumentService().signatureHelp(positionParams).get()); } else { return null; } } @POST @Path("formatting") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public List<? extends TextEditDto> formatting(DocumentFormattingParams params) throws InterruptedException, ExecutionException, LanguageServerException { params.getTextDocument().setUri(prefixURI(params.getTextDocument().getUri())); LanguageServer server = getServer(params.getTextDocument().getUri()); if (server == null) { return Collections.emptyList(); } return server.getTextDocumentService().formatting(params).get().stream().map(o -> new TextEditDto(o)).collect(Collectors.toList()); } @POST @Path("rangeFormatting") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public List<? extends TextEditDto> rangeFormatting(DocumentRangeFormattingParams params) throws InterruptedException, ExecutionException, LanguageServerException { params.getTextDocument().setUri(prefixURI(params.getTextDocument().getUri())); LanguageServer server = getServer(params.getTextDocument().getUri()); if (server == null) { return Collections.emptyList(); } return server.getTextDocumentService().rangeFormatting(params).get().stream().map(o -> new TextEditDto(o)) .collect(Collectors.toList()); } @POST @Path("onTypeFormatting") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public List<? extends TextEditDto> onTypeFormatting(DocumentOnTypeFormattingParams params) throws InterruptedException, ExecutionException, LanguageServerException { params.getTextDocument().setUri(prefixURI(params.getTextDocument().getUri())); LanguageServer server = getServer(params.getTextDocument().getUri()); if (server == null) { return Collections.emptyList(); } return server.getTextDocumentService().onTypeFormatting(params).get().stream().map(o -> new TextEditDto(o)) .collect(Collectors.toList()); } @SuppressWarnings("deprecation") @POST @Path("didChange") @Consumes(MediaType.APPLICATION_JSON) public void didChange(DidChangeTextDocumentParams change) throws LanguageServerException { change.getTextDocument().setUri(prefixURI(change.getTextDocument().getUri())); change.setUri(prefixURI(change.getUri())); LanguageServer server = getServer(change.getTextDocument().getUri()); if (server != null) { server.getTextDocumentService().didChange(change); } } @POST @Path("didOpen") @Consumes(MediaType.APPLICATION_JSON) public void didOpen(DidOpenTextDocumentParams openEvent) throws LanguageServerException { openEvent.getTextDocument().setUri(prefixURI(openEvent.getTextDocument().getUri())); LanguageServer server = getServer(openEvent.getTextDocument().getUri()); if (server != null) { server.getTextDocumentService().didOpen(openEvent); } } @POST @Path("didClose") @Consumes(MediaType.APPLICATION_JSON) public void didClose(DidCloseTextDocumentParams closeEvent) throws LanguageServerException { closeEvent.getTextDocument().setUri(prefixURI(closeEvent.getTextDocument().getUri())); LanguageServer server = getServer(closeEvent.getTextDocument().getUri()); if (server != null) { server.getTextDocumentService().didClose(closeEvent); } } @POST @Path("didSave") @Consumes(MediaType.APPLICATION_JSON) public void didSave(DidSaveTextDocumentParams saveEvent) throws LanguageServerException { saveEvent.getTextDocument().setUri(prefixURI(saveEvent.getTextDocument().getUri())); LanguageServer server = getServer(saveEvent.getTextDocument().getUri()); if (server != null) { server.getTextDocumentService().didSave(saveEvent); } } @POST @Path("documentHighlight") @Consumes(MediaType.APPLICATION_JSON) public DocumentHighlight documentHighlight(TextDocumentPositionParams positionParams) throws LanguageServerException, InterruptedException, ExecutionException { positionParams.getTextDocument().setUri(prefixURI(positionParams.getTextDocument().getUri())); LanguageServer server = getServer(positionParams.getTextDocument().getUri()); if (server != null) { return server.getTextDocumentService().documentHighlight(positionParams).get().get(0); } return null; } private LanguageServer getServer(String uri) throws LanguageServerException { return languageServerRegistry.findServer(uri); } }