Search in sources :

Example 1 with IPackageNode

use of org.apache.flex.compiler.tree.as.IPackageNode in project vscode-nextgenas by BowlerHatLLC.

the class ActionScriptTextDocumentService method getOffsetNode.

private IASNode getOffsetNode(TextDocumentIdentifier textDocument, Position position) {
    currentOffset = -1;
    if (!textDocument.getUri().endsWith(MXML_EXTENSION)) {
        //if we're in an <fx:Script> element, these will have been
        //previously calculated, so don't clear them
        importStartIndex = -1;
        importEndIndex = -1;
    }
    Path path = LanguageServerUtils.getPathFromLanguageServerURI(textDocument.getUri());
    if (path == null) {
        return null;
    }
    if (!isInWorkspaceOrSourcePath(path)) {
        //the path must be in the workspace or source-path
        return null;
    }
    String code;
    if (sourceByPath.containsKey(path)) {
        code = sourceByPath.get(path);
    } else {
        System.err.println("Could not find source " + path.toAbsolutePath().toString());
        System.err.println(sourceByPath.keySet().size());
        return null;
    }
    ICompilationUnit unit = getCompilationUnit(path);
    if (unit == null) {
        //should have been logged already
        return null;
    }
    IASNode ast = null;
    try {
        ast = unit.getSyntaxTreeRequest().get().getAST();
    } catch (InterruptedException e) {
        System.err.println("Interrupted while getting AST: " + path.toAbsolutePath().toString());
        return null;
    }
    if (ast == null) {
        //we couldn't find the root node for this file
        System.err.println("Could not find AST: " + path.toAbsolutePath().toString());
        return null;
    }
    currentOffset = lineAndCharacterToOffset(new StringReader(code), position.getLine(), position.getCharacter());
    if (currentOffset == -1) {
        System.err.println("Could not find code at position " + position.getLine() + ":" + position.getCharacter() + " in file " + path.toAbsolutePath().toString());
        return null;
    }
    IASNode offsetNode = getContainingNodeIncludingStart(ast, currentOffset);
    if (offsetNode != null) {
        //if we have an offset node, try to find where imports may be added
        IPackageNode packageNode = (IPackageNode) offsetNode.getAncestorOfType(IPackageNode.class);
        if (packageNode == null) {
            IFileNode fileNode = (IFileNode) offsetNode.getAncestorOfType(IFileNode.class);
            if (fileNode != null) {
                boolean foundPackage = false;
                for (int i = 0; i < fileNode.getChildCount(); i++) {
                    IASNode childNode = fileNode.getChild(i);
                    if (foundPackage) {
                        //this is the node following the package
                        importStartIndex = childNode.getAbsoluteStart();
                        break;
                    }
                    if (childNode instanceof IPackageNode) {
                        //use the start of the the next node after the
                        //package as the place where the import can be added
                        foundPackage = true;
                    }
                }
            }
        } else {
            importEndIndex = packageNode.getAbsoluteEnd();
        }
    }
    return offsetNode;
}
Also used : Path(java.nio.file.Path) ICompilationUnit(org.apache.flex.compiler.units.ICompilationUnit) IPackageNode(org.apache.flex.compiler.tree.as.IPackageNode) IFileNode(org.apache.flex.compiler.tree.as.IFileNode) IASNode(org.apache.flex.compiler.tree.as.IASNode) StringReader(java.io.StringReader)

Example 2 with IPackageNode

use of org.apache.flex.compiler.tree.as.IPackageNode in project vscode-nextgenas by BowlerHatLLC.

the class ActionScriptTextDocumentService method actionScriptCompletionWithNode.

private CompletableFuture<CompletionList> actionScriptCompletionWithNode(TextDocumentPositionParams position, IASNode offsetNode) {
    CompletionList result = new CompletionList();
    result.setIsIncomplete(false);
    result.setItems(new ArrayList<>());
    if (offsetNode == null) {
        //we couldn't find a node at the specified location
        autoCompletePackageBlock(result);
        return CompletableFuture.completedFuture(result);
    }
    IASNode parentNode = offsetNode.getParent();
    IASNode nodeAtPreviousOffset = null;
    if (parentNode != null) {
        nodeAtPreviousOffset = parentNode.getContainingNode(currentOffset - 1);
    }
    if (!isActionScriptCompletionAllowedInNode(position, offsetNode)) {
        //if we're inside a node that shouldn't have completion!
        return CompletableFuture.completedFuture(new CompletionList());
    }
    //variable types
    if (offsetNode instanceof IVariableNode) {
        IVariableNode variableNode = (IVariableNode) offsetNode;
        IExpressionNode nameExpression = variableNode.getNameExpressionNode();
        IExpressionNode typeNode = variableNode.getVariableTypeNode();
        int line = position.getPosition().getLine();
        int column = position.getPosition().getCharacter();
        if (line >= nameExpression.getEndLine() && line <= typeNode.getLine()) {
            if ((line != nameExpression.getEndLine() && line != typeNode.getLine()) || (line == nameExpression.getEndLine() && column > nameExpression.getEndColumn()) || (line == typeNode.getLine() && column <= typeNode.getColumn())) {
                autoCompleteTypes(offsetNode, result);
            }
            return CompletableFuture.completedFuture(result);
        }
    }
    if (parentNode != null && parentNode instanceof IVariableNode) {
        IVariableNode variableNode = (IVariableNode) parentNode;
        if (offsetNode == variableNode.getVariableTypeNode()) {
            autoCompleteTypes(parentNode, result);
            return CompletableFuture.completedFuture(result);
        }
    }
    //function return types
    if (offsetNode instanceof IFunctionNode) {
        IFunctionNode functionNode = (IFunctionNode) offsetNode;
        IContainerNode parameters = functionNode.getParametersContainerNode();
        IExpressionNode typeNode = functionNode.getReturnTypeNode();
        if (typeNode != null) {
            int line = position.getPosition().getLine();
            int column = position.getPosition().getCharacter();
            if (line >= parameters.getEndLine() && column > parameters.getEndColumn() && line <= typeNode.getLine() && column <= typeNode.getColumn()) {
                autoCompleteTypes(offsetNode, result);
                return CompletableFuture.completedFuture(result);
            }
        }
    }
    if (parentNode != null && parentNode instanceof IFunctionNode) {
        IFunctionNode functionNode = (IFunctionNode) parentNode;
        if (offsetNode == functionNode.getReturnTypeNode()) {
            autoCompleteTypes(parentNode, result);
            return CompletableFuture.completedFuture(result);
        }
    }
    //new keyword types
    if (parentNode != null && parentNode instanceof IFunctionCallNode) {
        IFunctionCallNode functionCallNode = (IFunctionCallNode) parentNode;
        if (functionCallNode.getNameNode() == offsetNode && functionCallNode.isNewExpression()) {
            autoCompleteTypes(parentNode, result);
            return CompletableFuture.completedFuture(result);
        }
    }
    if (nodeAtPreviousOffset != null && nodeAtPreviousOffset instanceof IKeywordNode && nodeAtPreviousOffset.getNodeID() == ASTNodeID.KeywordNewID) {
        autoCompleteTypes(nodeAtPreviousOffset, result);
        return CompletableFuture.completedFuture(result);
    }
    //as and is keyword types
    if (parentNode != null && parentNode instanceof IBinaryOperatorNode && (parentNode.getNodeID() == ASTNodeID.Op_AsID || parentNode.getNodeID() == ASTNodeID.Op_IsID)) {
        IBinaryOperatorNode binaryOperatorNode = (IBinaryOperatorNode) parentNode;
        if (binaryOperatorNode.getRightOperandNode() == offsetNode) {
            autoCompleteTypes(parentNode, result);
            return CompletableFuture.completedFuture(result);
        }
    }
    if (nodeAtPreviousOffset != null && nodeAtPreviousOffset instanceof IBinaryOperatorNode && (nodeAtPreviousOffset.getNodeID() == ASTNodeID.Op_AsID || nodeAtPreviousOffset.getNodeID() == ASTNodeID.Op_IsID)) {
        autoCompleteTypes(nodeAtPreviousOffset, result);
        return CompletableFuture.completedFuture(result);
    }
    //class extends keyword
    if (offsetNode instanceof IClassNode && nodeAtPreviousOffset != null && nodeAtPreviousOffset instanceof IKeywordNode && nodeAtPreviousOffset.getNodeID() == ASTNodeID.KeywordExtendsID) {
        autoCompleteTypes(offsetNode, result);
        return CompletableFuture.completedFuture(result);
    }
    //class implements keyword
    if (offsetNode instanceof IClassNode && nodeAtPreviousOffset != null && nodeAtPreviousOffset instanceof IKeywordNode && nodeAtPreviousOffset.getNodeID() == ASTNodeID.KeywordImplementsID) {
        autoCompleteTypes(offsetNode, result);
        return CompletableFuture.completedFuture(result);
    }
    //interface extends keyword
    if (offsetNode instanceof IInterfaceNode && nodeAtPreviousOffset != null && nodeAtPreviousOffset instanceof IKeywordNode && nodeAtPreviousOffset.getNodeID() == ASTNodeID.KeywordExtendsID) {
        autoCompleteTypes(offsetNode, result);
        return CompletableFuture.completedFuture(result);
    }
    //package (must be before member access)
    if (offsetNode instanceof IPackageNode) {
        IPackageNode packageNode = (IPackageNode) offsetNode;
        autoCompletePackageName(packageNode.getPackageName(), result);
        return CompletableFuture.completedFuture(result);
    }
    if (parentNode != null && parentNode instanceof FullNameNode) {
        IASNode gpNode = parentNode.getParent();
        if (gpNode != null && gpNode instanceof IPackageNode) {
            IPackageNode packageNode = (IPackageNode) gpNode;
            autoCompletePackageName(packageNode.getPackageName(), result);
        }
    }
    if (parentNode != null && parentNode instanceof IPackageNode) {
        //we'll get here if the last character in the package name is .
        IPackageNode packageNode = (IPackageNode) parentNode;
        IExpressionNode nameNode = packageNode.getNameExpressionNode();
        if (offsetNode == nameNode) {
            autoCompletePackageName(packageNode.getPackageName(), result);
            return CompletableFuture.completedFuture(result);
        }
    }
    //import (must be before member access)
    if (parentNode != null && parentNode instanceof IImportNode) {
        IImportNode importNode = (IImportNode) parentNode;
        IExpressionNode nameNode = importNode.getImportNameNode();
        if (offsetNode == nameNode) {
            String importName = importNode.getImportName();
            importName = importName.substring(0, position.getPosition().getCharacter() - nameNode.getColumn());
            autoCompleteImport(importName, result);
            return CompletableFuture.completedFuture(result);
        }
    }
    if (parentNode != null && parentNode instanceof FullNameNode) {
        IASNode gpNode = parentNode.getParent();
        if (gpNode != null && gpNode instanceof IImportNode) {
            IImportNode importNode = (IImportNode) gpNode;
            IExpressionNode nameNode = importNode.getImportNameNode();
            if (parentNode == nameNode) {
                String importName = importNode.getImportName();
                importName = importName.substring(0, position.getPosition().getCharacter() - nameNode.getColumn());
                autoCompleteImport(importName, result);
                return CompletableFuture.completedFuture(result);
            }
        }
    }
    if (nodeAtPreviousOffset != null && nodeAtPreviousOffset instanceof IImportNode) {
        autoCompleteImport("", result);
        return CompletableFuture.completedFuture(result);
    }
    //member access
    if (offsetNode instanceof IMemberAccessExpressionNode) {
        IMemberAccessExpressionNode memberAccessNode = (IMemberAccessExpressionNode) offsetNode;
        IExpressionNode leftOperand = memberAccessNode.getLeftOperandNode();
        IExpressionNode rightOperand = memberAccessNode.getRightOperandNode();
        int line = position.getPosition().getLine();
        int column = position.getPosition().getCharacter();
        if (line >= leftOperand.getEndLine() && line <= rightOperand.getLine()) {
            if ((line != leftOperand.getEndLine() && line != rightOperand.getLine()) || (line == leftOperand.getEndLine() && column > leftOperand.getEndColumn()) || (line == rightOperand.getLine() && column <= rightOperand.getColumn())) {
                autoCompleteMemberAccess(memberAccessNode, result);
                return CompletableFuture.completedFuture(result);
            }
        }
    }
    if (parentNode != null && parentNode instanceof IMemberAccessExpressionNode) {
        IMemberAccessExpressionNode memberAccessNode = (IMemberAccessExpressionNode) parentNode;
        //you would expect that the offset node could only be the right
        //operand, but it's actually possible for it to be the left operand,
        //even if the . has been typed! only sometimes, though.
        boolean isValidLeft = true;
        if (offsetNode == memberAccessNode.getLeftOperandNode() && memberAccessNode.getRightOperandNode() instanceof IIdentifierNode) {
            //if the left and right operands both exist, then this is not
            //member access and we should skip ahead
            isValidLeft = false;
        }
        if (offsetNode == memberAccessNode.getRightOperandNode() || isValidLeft) {
            autoCompleteMemberAccess(memberAccessNode, result);
            return CompletableFuture.completedFuture(result);
        }
    }
    if (nodeAtPreviousOffset != null && nodeAtPreviousOffset instanceof IMemberAccessExpressionNode) {
        //depending on the left operand, if a . is typed, the member access
        //may end up being the previous node instead of the parent or offset
        //node, so check if the right operand is empty
        IMemberAccessExpressionNode memberAccessNode = (IMemberAccessExpressionNode) nodeAtPreviousOffset;
        IExpressionNode rightOperandNode = memberAccessNode.getRightOperandNode();
        if (rightOperandNode instanceof IIdentifierNode) {
            IIdentifierNode identifierNode = (IIdentifierNode) rightOperandNode;
            if (identifierNode.getName().equals("")) {
                autoCompleteMemberAccess(memberAccessNode, result);
                return CompletableFuture.completedFuture(result);
            }
        }
    }
    //local scope
    do {
        //nodes to check
        if (offsetNode instanceof IScopedNode) {
            IScopedNode scopedNode = (IScopedNode) offsetNode;
            //include all members and local things that are in scope
            autoCompleteScope(scopedNode, false, result);
            //include all public definitions
            IASScope scope = scopedNode.getScope();
            IDefinition definitionToSkip = scope.getDefinition();
            autoCompleteDefinitions(result, false, false, null, definitionToSkip);
            return CompletableFuture.completedFuture(result);
        }
        offsetNode = offsetNode.getParent();
    } while (offsetNode != null);
    return CompletableFuture.completedFuture(result);
}
Also used : CompletionList(org.eclipse.lsp4j.CompletionList) IScopedNode(org.apache.flex.compiler.tree.as.IScopedNode) IPackageNode(org.apache.flex.compiler.tree.as.IPackageNode) IImportNode(org.apache.flex.compiler.tree.as.IImportNode) IIdentifierNode(org.apache.flex.compiler.tree.as.IIdentifierNode) IKeywordNode(org.apache.flex.compiler.tree.as.IKeywordNode) IVariableNode(org.apache.flex.compiler.tree.as.IVariableNode) IFunctionNode(org.apache.flex.compiler.tree.as.IFunctionNode) IContainerNode(org.apache.flex.compiler.tree.as.IContainerNode) IFunctionCallNode(org.apache.flex.compiler.tree.as.IFunctionCallNode) IInterfaceNode(org.apache.flex.compiler.tree.as.IInterfaceNode) IDefinition(org.apache.flex.compiler.definitions.IDefinition) IASScope(org.apache.flex.compiler.scopes.IASScope) IASNode(org.apache.flex.compiler.tree.as.IASNode) FullNameNode(org.apache.flex.compiler.internal.tree.as.FullNameNode) IClassNode(org.apache.flex.compiler.tree.as.IClassNode) IExpressionNode(org.apache.flex.compiler.tree.as.IExpressionNode) IBinaryOperatorNode(org.apache.flex.compiler.tree.as.IBinaryOperatorNode) IMemberAccessExpressionNode(org.apache.flex.compiler.tree.as.IMemberAccessExpressionNode)

Aggregations

IASNode (org.apache.flex.compiler.tree.as.IASNode)2 IPackageNode (org.apache.flex.compiler.tree.as.IPackageNode)2 StringReader (java.io.StringReader)1 Path (java.nio.file.Path)1 IDefinition (org.apache.flex.compiler.definitions.IDefinition)1 FullNameNode (org.apache.flex.compiler.internal.tree.as.FullNameNode)1 IASScope (org.apache.flex.compiler.scopes.IASScope)1 IBinaryOperatorNode (org.apache.flex.compiler.tree.as.IBinaryOperatorNode)1 IClassNode (org.apache.flex.compiler.tree.as.IClassNode)1 IContainerNode (org.apache.flex.compiler.tree.as.IContainerNode)1 IExpressionNode (org.apache.flex.compiler.tree.as.IExpressionNode)1 IFileNode (org.apache.flex.compiler.tree.as.IFileNode)1 IFunctionCallNode (org.apache.flex.compiler.tree.as.IFunctionCallNode)1 IFunctionNode (org.apache.flex.compiler.tree.as.IFunctionNode)1 IIdentifierNode (org.apache.flex.compiler.tree.as.IIdentifierNode)1 IImportNode (org.apache.flex.compiler.tree.as.IImportNode)1 IInterfaceNode (org.apache.flex.compiler.tree.as.IInterfaceNode)1 IKeywordNode (org.apache.flex.compiler.tree.as.IKeywordNode)1 IMemberAccessExpressionNode (org.apache.flex.compiler.tree.as.IMemberAccessExpressionNode)1 IScopedNode (org.apache.flex.compiler.tree.as.IScopedNode)1