Java tutorial
/* * Copyright (c) 2018, WSO2 Inc. (http://wso2.com) All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ballerinalang.langserver.command; import com.google.gson.internal.LinkedTreeMap; import org.apache.commons.io.IOUtils; import org.ballerinalang.langserver.common.UtilSymbolKeys; import org.ballerinalang.langserver.common.constants.CommandConstants; import org.ballerinalang.langserver.common.utils.CommonUtil; import org.ballerinalang.langserver.common.utils.CommonUtil.FunctionGenerator; import org.ballerinalang.langserver.compiler.DocumentServiceKeys; import org.ballerinalang.langserver.compiler.LSCompiler; import org.ballerinalang.langserver.compiler.LSServiceOperationContext; import org.ballerinalang.langserver.compiler.common.LSCustomErrorStrategy; import org.ballerinalang.langserver.compiler.workspace.WorkspaceDocumentException; import org.ballerinalang.langserver.compiler.workspace.WorkspaceDocumentManager; import org.ballerinalang.langserver.diagnostic.DiagnosticsHelper; import org.ballerinalang.model.symbols.SymbolKind; import org.ballerinalang.model.tree.Node; import org.ballerinalang.model.tree.TopLevelNode; import org.eclipse.lsp4j.ApplyWorkspaceEditParams; import org.eclipse.lsp4j.ExecuteCommandParams; import org.eclipse.lsp4j.MessageParams; import org.eclipse.lsp4j.MessageType; import org.eclipse.lsp4j.Position; 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.services.LanguageClient; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.wso2.ballerinalang.compiler.tree.BLangAnnotationAttachment; import org.wso2.ballerinalang.compiler.tree.BLangEndpoint; import org.wso2.ballerinalang.compiler.tree.BLangFunction; import org.wso2.ballerinalang.compiler.tree.BLangImportPackage; import org.wso2.ballerinalang.compiler.tree.BLangNode; import org.wso2.ballerinalang.compiler.tree.BLangPackage; import org.wso2.ballerinalang.compiler.tree.BLangResource; import org.wso2.ballerinalang.compiler.tree.BLangService; import org.wso2.ballerinalang.compiler.tree.BLangTypeDefinition; import org.wso2.ballerinalang.compiler.tree.BLangVariable; import org.wso2.ballerinalang.compiler.tree.types.BLangObjectTypeNode; import org.wso2.ballerinalang.compiler.tree.types.BLangRecordTypeNode; import org.wso2.ballerinalang.compiler.util.diagnotic.DiagnosticPos; import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.SynchronousQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import static org.ballerinalang.langserver.common.utils.CommonUtil.createVariableDeclaration; import static org.ballerinalang.langserver.compiler.LSCompilerUtil.getUntitledFilePath; /** * Command Executor for Ballerina Workspace service execute command operation. * * @since v0.964.0 */ public class CommandExecutor { private static final Logger logger = LoggerFactory.getLogger(CommandExecutor.class); // A newCachedThreadPool with a limited max-threads private static ExecutorService executor = new ThreadPoolExecutor(0, Runtime.getRuntime().availableProcessors(), 60L, TimeUnit.SECONDS, new SynchronousQueue<>()); private static final String ARG_KEY = "argumentK"; private static final String ARG_VALUE = "argumentV"; private CommandExecutor() { } /** * Command Execution router. * * @param params Parameters for the command * @param context Workspace service context * @return Result object */ public static Object executeCommand(ExecuteCommandParams params, LSServiceOperationContext context) { Object result; try { switch (params.getCommand()) { case CommandConstants.CMD_IMPORT_PACKAGE: result = executeImportPackage(context); break; case CommandConstants.CMD_CREATE_FUNCTION: result = executeCreateFunction(context); break; case CommandConstants.CMD_CREATE_VARIABLE: result = executeCreateVariable(context); break; case CommandConstants.CMD_ADD_DOCUMENTATION: result = executeAddDocumentation(context); break; case CommandConstants.CMD_ADD_ALL_DOC: result = executeAddAllDocumentation(context); break; case CommandConstants.CMD_CREATE_CONSTRUCTOR: result = executeCreateObjectConstructor(context); break; case CommandConstants.CMD_PULL_PACKAGE: result = executePullPackage(context); break; default: // Do Nothing result = new Object(); break; } } catch (WorkspaceDocumentException | BallerinaCommandExecutionException e) { logger.error("Error occurred while executing command", e); result = new Object(); } return result; } /** * Execute the command, import package. * * @param context Workspace service context */ private static Object executeImportPackage(LSServiceOperationContext context) throws WorkspaceDocumentException { String documentUri = null; VersionedTextDocumentIdentifier textDocumentIdentifier = new VersionedTextDocumentIdentifier(); for (Object arg : context.get(ExecuteCommandKeys.COMMAND_ARGUMENTS_KEY)) { if (((LinkedTreeMap) arg).get(ARG_KEY).equals(CommandConstants.ARG_KEY_DOC_URI)) { documentUri = (String) ((LinkedTreeMap) arg).get(ARG_VALUE); textDocumentIdentifier.setUri(documentUri); context.put(DocumentServiceKeys.FILE_URI_KEY, documentUri); } else if (((LinkedTreeMap) arg).get(ARG_KEY).equals(CommandConstants.ARG_KEY_PKG_NAME)) { context.put(ExecuteCommandKeys.PKG_NAME_KEY, (String) ((LinkedTreeMap) arg).get(ARG_VALUE)); } } WorkspaceDocumentManager documentManager = context.get(ExecuteCommandKeys.DOCUMENT_MANAGER_KEY); if (documentUri != null && context.get(ExecuteCommandKeys.PKG_NAME_KEY) != null) { Path filePath = Paths.get(URI.create(documentUri)); Path compilationPath = getUntitledFilePath(filePath.toString()).orElse(filePath); String fileContent = documentManager.getFileContent(compilationPath); String[] contentComponents = fileContent.split(CommonUtil.LINE_SEPARATOR_SPLIT); int totalLines = contentComponents.length; int lastNewLineCharIndex = Math.max(fileContent.lastIndexOf('\n'), fileContent.lastIndexOf('\r')); int lastCharCol = fileContent.substring(lastNewLineCharIndex + 1).length(); LSCompiler lsCompiler = context.get(ExecuteCommandKeys.LS_COMPILER_KEY); BLangPackage bLangPackage = lsCompiler .getBLangPackage(context, documentManager, false, LSCustomErrorStrategy.class, false) .getRight(); context.put(DocumentServiceKeys.CURRENT_PACKAGE_NAME_KEY, bLangPackage.symbol.getName().getValue()); String pkgName = context.get(ExecuteCommandKeys.PKG_NAME_KEY); String currentFile = context.get(DocumentServiceKeys.FILE_NAME_KEY); DiagnosticPos pos; // Filter the imports except the runtime import List<BLangImportPackage> imports = bLangPackage.getImports().stream().filter( bLangImportPackage -> bLangImportPackage.getPosition().src.cUnitName.equals(currentFile)) .collect(Collectors.toList()); if (!imports.isEmpty()) { BLangImportPackage lastImport = CommonUtil.getLastItem(imports); pos = lastImport.getPosition(); } else { pos = null; } int endCol = pos == null ? -1 : pos.getEndColumn() - 1; int endLine = pos == null ? 0 : pos.getEndLine() - 1; String remainingTextToReplace; if (endCol != -1) { int contentLengthToReplaceStart = fileContent .substring(0, fileContent.indexOf(contentComponents[endLine])).length() + endCol + 1; remainingTextToReplace = fileContent.substring(contentLengthToReplaceStart); } else { remainingTextToReplace = fileContent; } String editText = (pos != null ? "\r\n" : "") + "import " + pkgName + ";" + (remainingTextToReplace.startsWith("\n") || remainingTextToReplace.startsWith("\r") ? "" : "\r\n") + remainingTextToReplace; Range range = new Range(new Position(endLine, endCol + 1), new Position(totalLines + 1, lastCharCol)); return applySingleTextEdit(editText, range, textDocumentIdentifier, context.get(ExecuteCommandKeys.LANGUAGE_SERVER_KEY).getClient()); } return new Object(); } /** * Execute the command, create function. * * @param context Workspace service context */ private static Object executeCreateFunction(LSServiceOperationContext context) throws WorkspaceDocumentException { String documentUri = null; String funcName = null; String returnType = null; String returnDefaultValue = null; String funcArgs = ""; VersionedTextDocumentIdentifier textDocumentIdentifier = new VersionedTextDocumentIdentifier(); for (Object arg : context.get(ExecuteCommandKeys.COMMAND_ARGUMENTS_KEY)) { String argKey = ((LinkedTreeMap) arg).get(ARG_KEY).toString(); String argVal = ((LinkedTreeMap) arg).get(ARG_VALUE).toString(); if (argKey.equals(CommandConstants.ARG_KEY_DOC_URI)) { documentUri = argVal; textDocumentIdentifier.setUri(documentUri); context.put(DocumentServiceKeys.FILE_URI_KEY, documentUri); } else if (argKey.equals(CommandConstants.ARG_KEY_FUNC_NAME)) { funcName = argVal; } else if (argKey.equals(CommandConstants.ARG_KEY_RETURN_TYPE)) { returnType = argVal; } else if (argKey.equals(CommandConstants.ARG_KEY_RETURN_DEFAULT_VAL)) { returnDefaultValue = argVal; } else if (argKey.equals(CommandConstants.ARG_KEY_FUNC_ARGS)) { funcArgs = argVal; } } if (documentUri == null || funcName == null) { return new Object(); } WorkspaceDocumentManager documentManager = context.get(ExecuteCommandKeys.DOCUMENT_MANAGER_KEY); Path filePath = Paths.get(URI.create(documentUri)); Path compilationPath = getUntitledFilePath(filePath.toString()).orElse(filePath); String fileContent = documentManager.getFileContent(compilationPath); String[] contentComponents = fileContent.split("\\n|\\r\\n|\\r"); int totalLines = contentComponents.length; int lastNewLineCharIndex = Math.max(fileContent.lastIndexOf('\n'), fileContent.lastIndexOf('\r')); int lastCharCol = fileContent.substring(lastNewLineCharIndex + 1).length(); LSCompiler lsCompiler = context.get(ExecuteCommandKeys.LS_COMPILER_KEY); BLangPackage bLangPackage = lsCompiler .getBLangPackage(context, documentManager, false, LSCustomErrorStrategy.class, false).getRight(); if (bLangPackage == null) { return new Object(); } String editText = FunctionGenerator.createFunction(funcName, funcArgs, returnType, returnDefaultValue); Range range = new Range(new Position(totalLines, lastCharCol + 1), new Position(totalLines + 3, lastCharCol)); LanguageClient client = context.get(ExecuteCommandKeys.LANGUAGE_SERVER_KEY).getClient(); return applySingleTextEdit(editText, range, textDocumentIdentifier, client); } /** * Execute the command, create variable. * * @param context Workspace service context */ private static Object executeCreateVariable(LSServiceOperationContext context) throws WorkspaceDocumentException { String documentUri = null; String variableType = null; String variableName = null; int sLine = -1; int sCol = -1; VersionedTextDocumentIdentifier textDocumentIdentifier = new VersionedTextDocumentIdentifier(); for (Object arg : context.get(ExecuteCommandKeys.COMMAND_ARGUMENTS_KEY)) { String argKey = ((LinkedTreeMap) arg).get(ARG_KEY).toString(); String argVal = ((LinkedTreeMap) arg).get(ARG_VALUE).toString(); switch (argKey) { case CommandConstants.ARG_KEY_DOC_URI: documentUri = argVal; textDocumentIdentifier.setUri(documentUri); context.put(DocumentServiceKeys.FILE_URI_KEY, documentUri); break; case CommandConstants.ARG_KEY_RETURN_TYPE: variableType = argVal; break; case CommandConstants.ARG_KEY_FUNC_LOCATION: String[] split = argVal.split(","); sLine = Integer.parseInt(split[0]); sCol = Integer.parseInt(split[1]); break; case CommandConstants.ARG_KEY_VAR_NAME: variableName = argVal; break; default: //do nothing } } if (documentUri == null) { return new Object(); } String editText = createVariableDeclaration(variableName, variableType); Position position = new Position(sLine - 1, sCol - 1); LanguageClient client = context.get(ExecuteCommandKeys.LANGUAGE_SERVER_KEY).getClient(); return applySingleTextEdit(editText, new Range(position, position), textDocumentIdentifier, client); } /** * Execute the add documentation command. * * @param context Workspace service context */ private static Object executeAddDocumentation(LSServiceOperationContext context) throws WorkspaceDocumentException { String topLevelNodeType = ""; String documentUri = ""; int line = 0; VersionedTextDocumentIdentifier textDocumentIdentifier = new VersionedTextDocumentIdentifier(); for (Object arg : context.get(ExecuteCommandKeys.COMMAND_ARGUMENTS_KEY)) { if (((LinkedTreeMap) arg).get(ARG_KEY).equals(CommandConstants.ARG_KEY_DOC_URI)) { documentUri = (String) ((LinkedTreeMap) arg).get(ARG_VALUE); textDocumentIdentifier.setUri(documentUri); context.put(DocumentServiceKeys.FILE_URI_KEY, documentUri); } else if (((LinkedTreeMap) arg).get(ARG_KEY).equals(CommandConstants.ARG_KEY_NODE_TYPE)) { topLevelNodeType = (String) ((LinkedTreeMap) arg).get(ARG_VALUE); } else if (((LinkedTreeMap) arg).get(ARG_KEY).equals(CommandConstants.ARG_KEY_NODE_LINE)) { line = Integer.parseInt((String) ((LinkedTreeMap) arg).get(ARG_VALUE)); } } LSCompiler lsCompiler = context.get(ExecuteCommandKeys.LS_COMPILER_KEY); WorkspaceDocumentManager documentManager = context.get(ExecuteCommandKeys.DOCUMENT_MANAGER_KEY); BLangPackage bLangPackage = lsCompiler .getBLangPackage(context, documentManager, false, LSCustomErrorStrategy.class, false).getRight(); context.put(DocumentServiceKeys.CURRENT_BLANG_PACKAGE_CONTEXT_KEY, bLangPackage); CommandUtil.DocAttachmentInfo docAttachmentInfo = getDocumentationEditForNodeByPosition(topLevelNodeType, bLangPackage, line); if (docAttachmentInfo != null) { Path filePath = Paths.get(URI.create(documentUri)); Path compilationPath = getUntitledFilePath(filePath.toString()).orElse(filePath); String fileContent = context.get(ExecuteCommandKeys.DOCUMENT_MANAGER_KEY) .getFileContent(compilationPath); String[] contentComponents = fileContent.split(CommonUtil.LINE_SEPARATOR_SPLIT); int replaceEndCol = contentComponents[line].length(); String textBeforeNode = String.join(CommonUtil.LINE_SEPARATOR, Arrays.asList(Arrays.copyOfRange(contentComponents, 0, line))); String replaceText = String.join(CommonUtil.LINE_SEPARATOR, Arrays.asList(textBeforeNode, docAttachmentInfo.getDocAttachment(), contentComponents[line])); Range range = new Range(new Position(0, 0), new Position(line, replaceEndCol)); return applySingleTextEdit(replaceText, range, textDocumentIdentifier, context.get(ExecuteCommandKeys.LANGUAGE_SERVER_KEY).getClient()); } return new Object(); } /** * Generate workspace edit for generating doc comments for all top level nodes and resources. * * @param context Workspace Service Context */ private static Object executeAddAllDocumentation(LSServiceOperationContext context) throws WorkspaceDocumentException { String documentUri = ""; VersionedTextDocumentIdentifier textDocumentIdentifier = new VersionedTextDocumentIdentifier(); for (Object arg : context.get(ExecuteCommandKeys.COMMAND_ARGUMENTS_KEY)) { if (((LinkedTreeMap) arg).get(ARG_KEY).equals(CommandConstants.ARG_KEY_DOC_URI)) { documentUri = (String) ((LinkedTreeMap) arg).get(ARG_VALUE); textDocumentIdentifier.setUri(documentUri); context.put(DocumentServiceKeys.FILE_URI_KEY, documentUri); } } LSCompiler lsCompiler = context.get(ExecuteCommandKeys.LS_COMPILER_KEY); BLangPackage bLangPackage = lsCompiler.getBLangPackage(context, context.get(ExecuteCommandKeys.DOCUMENT_MANAGER_KEY), false, LSCustomErrorStrategy.class, false) .getRight(); Path filePath = Paths.get(URI.create(documentUri)); Path compilationPath = getUntitledFilePath(filePath.toString()).orElse(filePath); String fileContent = context.get(ExecuteCommandKeys.DOCUMENT_MANAGER_KEY).getFileContent(compilationPath); String[] contentComponents = fileContent.split(CommonUtil.LINE_SEPARATOR_SPLIT); List<TextEdit> textEdits = new ArrayList<>(); String fileName = context.get(DocumentServiceKeys.FILE_NAME_KEY); bLangPackage.topLevelNodes.stream() .filter(node -> node.getPosition().getSource().getCompilationUnitName().equals(fileName)) .forEach(topLevelNode -> { CommandUtil.DocAttachmentInfo docAttachmentInfo = getDocumentationEditForNode(topLevelNode); if (docAttachmentInfo != null) { textEdits.add(getTextEdit(docAttachmentInfo, contentComponents)); } if (topLevelNode instanceof BLangService) { ((BLangService) topLevelNode).getResources().forEach(bLangResource -> { CommandUtil.DocAttachmentInfo resourceInfo = getDocumentationEditForNode(bLangResource); if (resourceInfo != null) { textEdits.add(getTextEdit(resourceInfo, contentComponents)); } }); } }); TextDocumentEdit textDocumentEdit = new TextDocumentEdit(textDocumentIdentifier, textEdits); return applyWorkspaceEdit(Collections.singletonList(textDocumentEdit), context.get(ExecuteCommandKeys.LANGUAGE_SERVER_KEY).getClient()); } /** * Execute the create object constructor. Generates the snippet for the new constructor and hence the text edit. * * @param context LsServiceOperationContext instance for command execution * @return {@link Object} ApplyWorkspaceEditParams related to text edit * @throws WorkspaceDocumentException Error while accessing the document manager * @throws BallerinaCommandExecutionException Error while the command Execution */ private static Object executeCreateObjectConstructor(LSServiceOperationContext context) throws WorkspaceDocumentException, BallerinaCommandExecutionException { String documentUri; int line = 0; VersionedTextDocumentIdentifier textDocumentIdentifier = new VersionedTextDocumentIdentifier(); for (Object arg : context.get(ExecuteCommandKeys.COMMAND_ARGUMENTS_KEY)) { if (((LinkedTreeMap) arg).get(ARG_KEY).equals(CommandConstants.ARG_KEY_DOC_URI)) { documentUri = (String) ((LinkedTreeMap) arg).get(ARG_VALUE); textDocumentIdentifier.setUri(documentUri); context.put(DocumentServiceKeys.FILE_URI_KEY, documentUri); } else if (((LinkedTreeMap) arg).get(ARG_KEY).equals(CommandConstants.ARG_KEY_NODE_LINE)) { line = Integer.parseInt((String) ((LinkedTreeMap) arg).get(ARG_VALUE)); } } LSCompiler lsCompiler = context.get(ExecuteCommandKeys.LS_COMPILER_KEY); WorkspaceDocumentManager documentManager = context.get(ExecuteCommandKeys.DOCUMENT_MANAGER_KEY); BLangPackage bLangPackage = lsCompiler .getBLangPackage(context, documentManager, false, LSCustomErrorStrategy.class, false).getRight(); context.put(DocumentServiceKeys.CURRENT_BLANG_PACKAGE_CONTEXT_KEY, bLangPackage); int finalLine = line; /* In the ideal situation Command execution exception should never throw. If thrown, create constructor command has been executed over a non object type node. */ TopLevelNode objectNode = bLangPackage.topLevelNodes.stream() .filter(topLevelNode -> topLevelNode instanceof BLangTypeDefinition && ((BLangTypeDefinition) topLevelNode).symbol.kind.equals(SymbolKind.OBJECT) && topLevelNode.getPosition().getStartLine() - 1 == finalLine) .findAny().orElseThrow( () -> new BallerinaCommandExecutionException("Error Executing Create Constructor Command")); List<BLangVariable> fields = ((BLangObjectTypeNode) ((BLangTypeDefinition) objectNode).typeNode).fields; DiagnosticPos zeroBasedIndex = CommonUtil.toZeroBasedPosition(CommonUtil.getLastItem(fields).getPosition()); int lastFieldLine = zeroBasedIndex.getEndLine(); int lastFieldOffset = zeroBasedIndex.getStartColumn(); String constructorSnippet = CommandUtil.getObjectConstructorSnippet(fields, lastFieldOffset); Range range = new Range(new Position(lastFieldLine + 1, 0), new Position(lastFieldLine + 1, 0)); return applySingleTextEdit(constructorSnippet, range, textDocumentIdentifier, context.get(ExecuteCommandKeys.LANGUAGE_SERVER_KEY).getClient()); } private static Object executePullPackage(LSServiceOperationContext context) { executor.submit(() -> { // Derive package name and document uri String packageName = ""; String documentUri = ""; for (Object arg : context.get(ExecuteCommandKeys.COMMAND_ARGUMENTS_KEY)) { String argKey = ((LinkedTreeMap) arg).get(ARG_KEY).toString(); String argVal = ((LinkedTreeMap) arg).get(ARG_VALUE).toString(); if (argKey.equals(CommandConstants.ARG_KEY_PKG_NAME)) { packageName = argVal; } else if (argKey.equals(CommandConstants.ARG_KEY_DOC_URI)) { documentUri = argVal; } } // If no package, or no doc uri; then just skip if (packageName.isEmpty() || documentUri.isEmpty()) { return; } // Execute `ballerina pull` command String ballerinaHome = Paths.get(CommonUtil.BALLERINA_HOME).resolve("bin").resolve("ballerina") .toString(); ProcessBuilder processBuilder = new ProcessBuilder(ballerinaHome, "pull", packageName); LanguageClient client = context.get(ExecuteCommandKeys.LANGUAGE_SERVER_KEY).getClient(); LSCompiler lsCompiler = context.get(ExecuteCommandKeys.LS_COMPILER_KEY); DiagnosticsHelper diagnosticsHelper = context.get(ExecuteCommandKeys.DIAGNOSTICS_HELPER_KEY); try { notifyClient(client, MessageType.Info, "Pulling '" + packageName + "' from the Ballerina Central..."); Process process = processBuilder.start(); InputStream inputStream = process.getInputStream(); // Consume and skip input-stream int data = inputStream.read(); while (data != -1) { data = inputStream.read(); } // Check error stream for errors InputStream errorStream = process.getErrorStream(); String error = IOUtils.toString(errorStream, StandardCharsets.UTF_8); if (error == null || error.isEmpty()) { notifyClient(client, MessageType.Info, "Pulling success for the '" + packageName + "' package!"); clearDiagnostics(client, lsCompiler, diagnosticsHelper, documentUri); } else { notifyClient(client, MessageType.Error, "Pulling failed for the '" + packageName + "' package!\n" + error); } } catch (IOException e) { notifyClient(client, MessageType.Error, "Pulling failed for the '" + packageName + "' package!"); } }); return new Object(); } /** * Sends a message to the language server client. * * @param client Language Server client * @param messageType message type * @param message message */ private static void notifyClient(LanguageClient client, MessageType messageType, String message) { client.showMessage(new MessageParams(messageType, message)); } /** * Clears diagnostics of the client by sending an text edit event. * * @param client Language Server client * @param diagnosticsHelper diagnostics helper */ private static void clearDiagnostics(LanguageClient client, LSCompiler lsCompiler, DiagnosticsHelper diagnosticsHelper, String documentUri) { Path filePath = Paths.get(URI.create(documentUri)); Path compilationPath = getUntitledFilePath(filePath.toString()).orElse(filePath); diagnosticsHelper.compileAndSendDiagnostics(client, lsCompiler, filePath, compilationPath); } /** * Get TextEdit from doc attachment info. * * @param attachmentInfo Doc attachment info * @param contentComponents file content component * @return {@link TextEdit} Text edit for attachment info */ private static TextEdit getTextEdit(CommandUtil.DocAttachmentInfo attachmentInfo, String[] contentComponents) { int replaceFrom = attachmentInfo.getReplaceStartFrom(); int replaceEndCol = contentComponents[attachmentInfo.getReplaceStartFrom()].length(); Range range = new Range(new Position(replaceFrom, 0), new Position(replaceFrom, replaceEndCol)); String replaceText = attachmentInfo.getDocAttachment() + System.lineSeparator() + contentComponents[replaceFrom]; return new TextEdit(range, replaceText); } /** * Get Documentation edit for node at a given position. * * @param topLevelNodeType top level node type * @param bLangPkg BLang package * @param line position to be compared with * @return Document attachment info */ private static CommandUtil.DocAttachmentInfo getDocumentationEditForNodeByPosition(String topLevelNodeType, BLangPackage bLangPkg, int line) { CommandUtil.DocAttachmentInfo docAttachmentInfo = null; switch (topLevelNodeType) { case UtilSymbolKeys.FUNCTION_KEYWORD_KEY: docAttachmentInfo = CommandUtil.getFunctionDocumentationByPosition(bLangPkg, line); break; case UtilSymbolKeys.ENDPOINT_KEYWORD_KEY: docAttachmentInfo = CommandUtil.getEndpointDocumentationByPosition(bLangPkg, line); break; case UtilSymbolKeys.SERVICE_KEYWORD_KEY: docAttachmentInfo = CommandUtil.getServiceDocumentationByPosition(bLangPkg, line); break; case UtilSymbolKeys.RECORD_KEYWORD_KEY: case UtilSymbolKeys.OBJECT_KEYWORD_KEY: docAttachmentInfo = CommandUtil.getTypeNodeDocumentationByPosition(bLangPkg, line); break; default: break; } return docAttachmentInfo; } /** * Get the documentation edit attachment info for a given particular node. * * @param node Node given * @return Doc Attachment Info */ private static CommandUtil.DocAttachmentInfo getDocumentationEditForNode(Node node) { CommandUtil.DocAttachmentInfo docAttachmentInfo = null; int replaceFrom; switch (node.getKind()) { case FUNCTION: if (((BLangFunction) node).markdownDocumentationAttachment == null) { replaceFrom = CommonUtil.toZeroBasedPosition(((BLangFunction) node).getPosition()).getStartLine(); docAttachmentInfo = CommandUtil.getFunctionNodeDocumentation((BLangFunction) node, replaceFrom); } break; case TYPE_DEFINITION: if (((BLangTypeDefinition) node).markdownDocumentationAttachment == null && (((BLangTypeDefinition) node).typeNode instanceof BLangRecordTypeNode || ((BLangTypeDefinition) node).typeNode instanceof BLangObjectTypeNode)) { replaceFrom = CommonUtil.toZeroBasedPosition(((BLangTypeDefinition) node).getPosition()) .getStartLine(); docAttachmentInfo = CommandUtil.getRecordOrObjectDocumentation((BLangTypeDefinition) node, replaceFrom); } break; case ENDPOINT: // TODO: Here we need to check for the doc attachments of the endpoint. replaceFrom = CommonUtil.toZeroBasedPosition(((BLangEndpoint) node).getPosition()).getStartLine(); docAttachmentInfo = CommandUtil.getEndpointNodeDocumentation((BLangEndpoint) node, replaceFrom); break; case RESOURCE: if (((BLangResource) node).markdownDocumentationAttachment == null) { BLangResource bLangResource = (BLangResource) node; replaceFrom = getReplaceFromForServiceOrResource(bLangResource, bLangResource.getAnnotationAttachments()); docAttachmentInfo = CommandUtil.getResourceNodeDocumentation(bLangResource, replaceFrom); } break; case SERVICE: if (((BLangService) node).markdownDocumentationAttachment == null) { BLangService bLangService = (BLangService) node; replaceFrom = getReplaceFromForServiceOrResource(bLangService, bLangService.getAnnotationAttachments()); docAttachmentInfo = CommandUtil.getServiceNodeDocumentation(bLangService, replaceFrom); } break; default: break; } return docAttachmentInfo; } private static int getReplaceFromForServiceOrResource(BLangNode bLangNode, List<BLangAnnotationAttachment> annotationAttachments) { if (!annotationAttachments.isEmpty()) { return CommonUtil.toZeroBasedPosition(CommonUtil.getLastItem(annotationAttachments).getPosition()) .getEndLine() + 1; } return CommonUtil.toZeroBasedPosition(bLangNode.getPosition()).getStartLine(); } private static ApplyWorkspaceEditParams applySingleTextEdit(String editText, Range range, VersionedTextDocumentIdentifier identifier, LanguageClient client) { WorkspaceEdit workspaceEdit = new WorkspaceEdit(); ApplyWorkspaceEditParams applyWorkspaceEditParams = new ApplyWorkspaceEditParams(); TextEdit textEdit = new TextEdit(range, editText); TextDocumentEdit textDocumentEdit = new TextDocumentEdit(identifier, Collections.singletonList(textEdit)); workspaceEdit.setDocumentChanges(Collections.singletonList(textDocumentEdit)); applyWorkspaceEditParams.setEdit(workspaceEdit); if (client != null) { client.applyEdit(applyWorkspaceEditParams); } return applyWorkspaceEditParams; } private static Object applyWorkspaceEdit(List<TextDocumentEdit> textDocumentEdits, LanguageClient client) { WorkspaceEdit workspaceEdit = new WorkspaceEdit(); workspaceEdit.setDocumentChanges(textDocumentEdits); ApplyWorkspaceEditParams applyWorkspaceEditParams = new ApplyWorkspaceEditParams(workspaceEdit); if (client != null) { client.applyEdit(applyWorkspaceEditParams); } return applyWorkspaceEditParams; } }