예제 #1
0
        public override Definition OnDefinition(TextDocumentPosition parameters)
        {
            AnalyticsWrapper.Telemetry.TrackEvent("[Definition]", EventType.Completion); //Send event to analytics
            var defaultDefinition = new Definition(parameters.uri, new Range());
            Uri objUri            = new Uri(parameters.uri);

            if (objUri.IsFile)
            {
                var fileCompiler = typeCobolWorkspace.OpenedFileCompiler[objUri];

                if (fileCompiler.CompilationResultsForProgram != null &&
                    fileCompiler.CompilationResultsForProgram.ProcessedTokensDocumentSnapshot != null)
                {
                    var matchingCodeElement =
                        fileCompiler.CompilationResultsForProgram.ProgramClassDocumentSnapshot.NodeCodeElementLinkers
                        .Keys.FirstOrDefault(c => c.ConsumedTokens.Any(
                                                 t => t.Line == parameters.position.line + 1 &&
                                                 parameters.position.character >= t.StartIndex &&
                                                 parameters.position.character <= t.StopIndex + 1));
                    if (matchingCodeElement == null)
                    {
                        return(defaultDefinition);
                    }

                    var matchingNode = fileCompiler.CompilationResultsForProgram.ProgramClassDocumentSnapshot.NodeCodeElementLinkers[matchingCodeElement];
                    if (matchingNode == null)
                    {
                        return(defaultDefinition);
                    }

                    var matchingToken = matchingCodeElement.ConsumedTokens.FirstOrDefault(t =>
                                                                                          t.Line == parameters.position.line + 1 &&
                                                                                          parameters.position.character >= t.StartIndex &&
                                                                                          parameters.position.character <= t.StopIndex + 1);
                    if (matchingToken == null)
                    {
                        return(defaultDefinition);
                    }

                    Token userFilterToken          = null;
                    Token lastSignificantToken     = null;
                    var   potentialDefinitionNodes = new List <Node>();

                    CodeElementMatcher.MatchCompletionCodeElement(parameters.position, new List <CodeElementWrapper>()
                    {
                        new CodeElementWrapper(matchingCodeElement)
                    }, out userFilterToken, out lastSignificantToken);                                                                                                                                               //Magic happens here
                    if (lastSignificantToken != null)
                    {
                        switch (lastSignificantToken.TokenType)
                        {
                        case TokenType.PERFORM:
                        {
                            potentialDefinitionNodes.AddRange(
                                matchingNode.SymbolTable.GetParagraphs(
                                    p => p.Name.Equals(matchingToken.Text, StringComparison.InvariantCultureIgnoreCase)));
                            break;
                        }

                        case TokenType.CALL:
                        {
                            potentialDefinitionNodes.AddRange(matchingNode.SymbolTable.GetFunctions(
                                                                  f => f.Name.Equals(matchingToken.Text, StringComparison.InvariantCultureIgnoreCase),
                                                                  new List <SymbolTable.Scope>()
                                {
                                    SymbolTable.Scope.Declarations,
                                    SymbolTable.Scope.Global
                                }));
                            break;
                        }

                        case TokenType.TYPE:
                        {
                            potentialDefinitionNodes.AddRange(matchingNode.SymbolTable.GetTypes(
                                                                  t => t.Name.Equals(matchingToken.Text, StringComparison.InvariantCultureIgnoreCase),
                                                                  new List <SymbolTable.Scope>()
                                {
                                    SymbolTable.Scope.Declarations,
                                    SymbolTable.Scope.Global
                                }));
                            break;
                        }

                        case TokenType.INPUT:
                        case TokenType.OUTPUT:
                        case TokenType.IN_OUT:
                        case TokenType.MOVE:
                        case TokenType.TO:
                        default:
                        {
                            potentialDefinitionNodes.AddRange(matchingNode.SymbolTable.GetVariables(
                                                                  v => v.Name.Equals(matchingToken.Text, StringComparison.InvariantCultureIgnoreCase),
                                                                  new List <SymbolTable.Scope>()
                                {
                                    SymbolTable.Scope.Declarations,
                                    SymbolTable.Scope.Global
                                }));
                            break;
                        }
                        }
                    }

                    if (potentialDefinitionNodes.Count > 0)
                    {
                        var nodeDefinition = potentialDefinitionNodes.FirstOrDefault();
                        if (nodeDefinition != null)
                        {
                            return(new Definition(parameters.uri,
                                                  new Range()
                            {
                                start = new Position(nodeDefinition.CodeElement.Line - 1, 0)
                            }));
                        }
                    }
                }
            }

            return(defaultDefinition);
        }
예제 #2
0
        public static IEnumerable <CompletionItem> GetCompletionForQualifiedName(Position position, FileCompiler fileCompiler, CodeElement codeElement, Token qualifiedNameSeparatorToken, Token userFilterToken, Dictionary <SignatureInformation, FunctionDeclaration> functionDeclarationSignatureDictionary)
        {
            var completionItems     = new List <CompletionItem>();
            var arrangedCodeElement = codeElement as CodeElementWrapper;
            var node           = GetMatchingNode(fileCompiler, codeElement);
            var userFilterText = userFilterToken == null ? string.Empty : userFilterToken.Text;

            //Get the token before MatchingToken
            var userTokenToSeek =
                arrangedCodeElement?.ArrangedConsumedTokens.ElementAt(
                    arrangedCodeElement.ArrangedConsumedTokens.IndexOf(qualifiedNameSeparatorToken) - 1);
            var qualifiedNameTokens = new List <Token>();

            if (arrangedCodeElement != null)
            {
                qualifiedNameTokens.AddRange(
                    arrangedCodeElement.ArrangedConsumedTokens?.Where(
                        t => (t?.TokenType == TokenType.UserDefinedWord || t?.TokenType == TokenType.QualifiedNameSeparator) && (t.EndColumn <= position.character && t.Line == position.line + 1) || t.Line < position.line + 1));
                //Remove all the userdefinedword token and also QualifiedNameToken
                arrangedCodeElement.ArrangedConsumedTokens = arrangedCodeElement.ArrangedConsumedTokens.Except(qualifiedNameTokens).ToList();
                //We only wants the token that in front of any QualifiedName
                //Get the first significant token (i.e CALL/TYPE/...)
                Token firstSignificantToken, tempUserFilterToken;
                CodeElementMatcher.MatchCompletionCodeElement(position, new List <CodeElementWrapper> {
                    arrangedCodeElement
                }, out tempUserFilterToken,
                                                              out firstSignificantToken);


                //Select the qualifiedName chain closest to cursor
                Token previousToken = null;
                qualifiedNameTokens.Reverse();
                var filteredQualifiedNameTokens = new List <Token>(); //Will contains all the tokens forming the qualifiedName chain.
                foreach (var token in qualifiedNameTokens)
                {
                    if (previousToken == null ||
                        ((previousToken.TokenType == TokenType.QualifiedNameSeparator && token.TokenType == TokenType.UserDefinedWord) ||
                         (token.TokenType == TokenType.QualifiedNameSeparator && previousToken.TokenType == TokenType.UserDefinedWord)))
                    {
                        filteredQualifiedNameTokens.Add(token);
                    }
                    else
                    {
                        break;
                    }

                    previousToken = token;
                }
                filteredQualifiedNameTokens.Reverse();

                //For MOVE INPUT OUTPUT variables etc.. , get all the children of a variable that are accessible
                //Try to find corresponding variables
                var qualifiedName = string.Join(".",
                                                filteredQualifiedNameTokens.Where(
                                                    t =>
                                                    t.TokenType == TokenType.UserDefinedWord &&
                                                    !(t.Text == userFilterText && userFilterToken != null &&
                                                      t.StartIndex == userFilterToken.StartIndex && t.EndColumn == userFilterToken.EndColumn) &&
                                                    ((firstSignificantToken != null && ((t.StartIndex >= firstSignificantToken.EndColumn && t.Line == firstSignificantToken.Line) || t.Line > firstSignificantToken.Line)) ||
                                                     firstSignificantToken == null) &&
                                                    ((t.EndColumn <= position.character && t.Line == position.line + 1) || t.Line < position.line + 1))
                                                .Select(t => t.Text));
                var possibleVariables = node.SymbolTable.GetVariablesExplicit(new URI(qualifiedName));

                if (possibleVariables != null && possibleVariables.Any())
                {
                    //Get children of a type to get completion possibilities
                    foreach (var variable in possibleVariables)
                    {
                        var children = new List <Node>();
                        if (variable.Children != null && variable.Children.Count > 0) //It's a variable with levels inside
                        {
                            children.AddRange(variable.Children);
                        }
                        else //It's a typed variable, we have to search for children in the type
                        {
                            var typeChildren = GetTypeChildrens(node.SymbolTable, variable);
                            if (typeChildren != null)
                            {
                                children.AddRange(typeChildren.Where(t => t.Name != null));
                            }
                        }

                        var computedChildrenList = new List <Node>();
                        foreach (var child in children)
                        {
                            GetNextRelevantChildren(child, computedChildrenList);
                        }

                        completionItems.AddRange(CompletionFactoryHelpers.CreateCompletionItemsForVariables(
                                                     computedChildrenList.Where(
                                                         c => c.Name.StartsWith(userFilterText, StringComparison.InvariantCultureIgnoreCase)) //Filter on user text
                                                     .Select(child => child as DataDefinition), false));
                    }
                }
                else
                { //If no variables found, it's could be a children declared in a typedef..
                    var children       = new List <Node>();
                    var potentialTypes =
                        node.SymbolTable.GetTypes(
                            t =>
                            t.Children != null &&
                            t.Children.Any(
                                tc => tc.Name != null && tc.Name.Equals(userTokenToSeek.Text, StringComparison.InvariantCultureIgnoreCase)),
                            new List <SymbolTable.Scope>
                    {
                        SymbolTable.Scope.Declarations,
                        SymbolTable.Scope.Global,
                        SymbolTable.Scope.Intrinsic,
                        SymbolTable.Scope.Namespace
                    });

                    foreach (var nodeType in potentialTypes.SelectMany(t => t.Children).Where(c => c != null && c.Name != null && c.Name.Equals(userTokenToSeek.Text, StringComparison.InvariantCultureIgnoreCase)))
                    {
                        var nodeDataDef = nodeType as DataDefinition;
                        if (nodeDataDef == null)
                        {
                            continue;
                        }

                        var typeChildrens = GetTypeChildrens(node.SymbolTable, nodeDataDef);
                        if (typeChildrens != null)
                        {
                            children.AddRange(typeChildrens);
                        }
                    }

                    completionItems.AddRange(CompletionFactoryHelpers.CreateCompletionItemsForVariables(
                                                 children.Where(
                                                     c => c.Name.StartsWith(userFilterText, StringComparison.InvariantCultureIgnoreCase)) //Filter on user text
                                                 .Select(child => child as DataDefinition), false));
                }

                if (firstSignificantToken != null)
                {
                    switch (firstSignificantToken.TokenType)
                    {
                    case TokenType.CALL:
                    {
                        functionDeclarationSignatureDictionary.Clear();     //Clear to avoid key collision
                        //On CALL get possible procedures and functions in the seeked program
                        var programs = node.SymbolTable.GetPrograms(userTokenToSeek.Text);
                        if (programs != null && programs.Any())
                        {
                            var procedures =
                                programs.First()
                                .SymbolTable.GetFunctions(
                                    f =>
                                    f.Name.StartsWith(userFilterText,
                                                      StringComparison.InvariantCultureIgnoreCase) ||
                                    f.VisualQualifiedName.ToString()
                                    .StartsWith(userFilterText, StringComparison.InvariantCultureIgnoreCase),
                                    new List <SymbolTable.Scope>
                                {
                                    SymbolTable.Scope.Declarations
                                });
                            completionItems.AddRange(CompletionFactoryHelpers.CreateCompletionItemsForProcedures(procedures, node, functionDeclarationSignatureDictionary, false));
                        }
                        break;
                    }

                    case TokenType.TYPE:
                    {
                        //On TYPE get possible public types in the seeked program
                        var programs = node.SymbolTable.GetPrograms(userTokenToSeek.Text);
                        if (programs != null && programs.Any())
                        {
                            var types =
                                programs.First()
                                .SymbolTable.GetTypes(
                                    t =>
                                    t.Name.StartsWith(userFilterText,
                                                      StringComparison.InvariantCultureIgnoreCase),
                                    new List <SymbolTable.Scope>
                                {
                                    SymbolTable.Scope.Declarations,
                                    SymbolTable.Scope.Global
                                });
                            completionItems.AddRange(CompletionFactoryHelpers.CreateCompletionItemsForType(types, node, false));
                        }
                        break;
                    }
                    }
                }
            }

            return(completionItems.Distinct());
        }
예제 #3
0
        /// <summary>
        /// Request to request completion at a given text document position. The request's
        /// parameter is of type[TextDocumentPosition](#TextDocumentPosition) the response
        /// is of type[CompletionItem[]](#CompletionItem) or a Thenable that resolves to such.
        /// </summary>
        public override List <CompletionItem> OnCompletion(TextDocumentPosition parameters)
        {
            var fileCompiler = GetFileCompilerFromStringUri(parameters.uri);

            if (fileCompiler == null)
            {
                return(null);
            }

            List <CompletionItem> items = new List <CompletionItem>();

            if (fileCompiler.CompilationResultsForProgram != null &&
                fileCompiler.CompilationResultsForProgram.ProcessedTokensDocumentSnapshot != null)
            {
                var wrappedCodeElements = CodeElementFinder(fileCompiler, parameters.position);
                if (wrappedCodeElements == null)
                {
                    return(new List <CompletionItem>());
                }

                Token userFilterToken      = null;
                Token lastSignificantToken = null;
                //Try to get a significant token for competion and return the codeelement containing the matching token.
                CodeElement matchingCodeElement = CodeElementMatcher.MatchCompletionCodeElement(parameters.position,
                                                                                                wrappedCodeElements,
                                                                                                out userFilterToken, out lastSignificantToken); //Magic happens here
                var userFilterText = userFilterToken == null ? string.Empty : userFilterToken.Text;

                if (lastSignificantToken != null)
                {
                    AnalyticsWrapper.Telemetry.TrackEvent("[Completion] " + lastSignificantToken.TokenType, EventType.Completion);
                    switch (lastSignificantToken.TokenType)
                    {
                    case TokenType.PERFORM:
                    {
                        items.AddRange(CompletionFactory.GetCompletionPerformParagraph(fileCompiler,
                                                                                       matchingCodeElement, userFilterToken));
                        break;
                    }

                    case TokenType.CALL:
                    {
                        _FunctionDeclarationSignatureDictionary.Clear();     //Clear to avoid key collision
                        items.AddRange(CompletionFactory.GetCompletionForProcedure(fileCompiler, matchingCodeElement,
                                                                                   userFilterToken, _FunctionDeclarationSignatureDictionary));
                        items.AddRange(CompletionFactory.GetCompletionForLibrary(fileCompiler, matchingCodeElement,
                                                                                 userFilterToken));
                        break;
                    }

                    case TokenType.TYPE:
                    {
                        items.AddRange(CompletionFactory.GetCompletionForType(fileCompiler, matchingCodeElement,
                                                                              userFilterToken));
                        items.AddRange(CompletionFactory.GetCompletionForLibrary(fileCompiler, matchingCodeElement,
                                                                                 userFilterToken));
                        break;
                    }

                    case TokenType.QualifiedNameSeparator:
                    {
                        items.AddRange(CompletionFactory.GetCompletionForQualifiedName(parameters.position,
                                                                                       fileCompiler, matchingCodeElement, lastSignificantToken, userFilterToken, _FunctionDeclarationSignatureDictionary));
                        break;
                    }

                    case TokenType.INPUT:
                    case TokenType.OUTPUT:
                    case TokenType.IN_OUT:
                    {
                        items.AddRange(CompletionFactory.GetCompletionForProcedureParameter(parameters.position,
                                                                                            fileCompiler, matchingCodeElement, userFilterToken, lastSignificantToken, _SignatureCompletionContext));
                        break;
                    }

                    case TokenType.MOVE:
                    {
                        items.AddRange(CompletionFactory.GetCompletionForVariable(fileCompiler, matchingCodeElement,
                                                                                  da =>
                                                                                  da.Name.StartsWith(userFilterText, StringComparison.InvariantCultureIgnoreCase) &&
                                                                                  ((da.CodeElement != null &&
                                                                                    (da.CodeElement as DataDefinitionEntry).LevelNumber.Value < 88) ||
                                                                                   (da.CodeElement == null && da is IndexDefinition))));
                        //Ignore 88 level variable
                        break;
                    }

                    case TokenType.TO:
                    {
                        items.AddRange(CompletionFactory.GetCompletionForTo(fileCompiler, matchingCodeElement,
                                                                            userFilterToken, lastSignificantToken));
                        break;
                    }

                    case TokenType.INTO:
                    {
                        items.AddRange(CompletionFactory.GetCompletionForVariable(fileCompiler, matchingCodeElement,
                                                                                  v => v.Name.StartsWith(userFilterText, StringComparison.CurrentCultureIgnoreCase) &&
                                                                                  ((v.CodeElement as DataDefinitionEntry) != null &&
                                                                                   v.DataType == DataType.Alphabetic ||
                                                                                   v.DataType == DataType.Alphanumeric ||
                                                                                   v.DataType == DataType.AlphanumericEdited)
                                                                                  ));
                        break;
                    }

                    case TokenType.SET:
                    {
                        items.AddRange(CompletionFactory.GetCompletionForVariable(fileCompiler, matchingCodeElement,
                                                                                  v => v.Name.StartsWith(userFilterText, StringComparison.CurrentCultureIgnoreCase)
                                                                                  &&
                                                                                  (((v.CodeElement as DataDefinitionEntry) != null &&
                                                                                    (v.CodeElement as DataDefinitionEntry).LevelNumber.Value == 88)
                                                                                                                 //Level 88 Variable
                                                                                   || v.DataType == DataType.Numeric || //Numeric Integer Variable
                                                                                   v.Usage == DataUsage.Pointer) //Or usage is pointer
                                                                                  ));
                        break;
                    }

                    case TokenType.OF:
                    {
                        items.AddRange(CompletionFactory.GetCompletionForOf(fileCompiler, matchingCodeElement,
                                                                            userFilterToken, parameters.position));
                        break;
                    }

                    default:
                        break;
                    }
                }
                else
                {
                    //If no known keyword has been found, let's try to get the context and return available variables.
                    if (matchingCodeElement == null && wrappedCodeElements.Any())
                    {
                        userFilterToken =
                            wrappedCodeElements.First().ArrangedConsumedTokens.FirstOrDefault(
                                t =>
                                parameters.position.character <= t.StopIndex + 1 && parameters.position.character > t.StartIndex &&
                                t.Line == parameters.position.line + 1 &&
                                t.TokenType == TokenType.UserDefinedWord);                              //Get the userFilterToken to filter the results

                        userFilterText = userFilterToken == null ? string.Empty : userFilterToken.Text; //Convert token to text

                        items.AddRange(CompletionFactory.GetCompletionForVariable(fileCompiler,
                                                                                  wrappedCodeElements.First(), da => da.Name.StartsWith(userFilterText, StringComparison.InvariantCultureIgnoreCase)));
                    }
                    else
                    {
                        //Return a default text to inform the user that completion is not available after the given token
                        items.Add(new CompletionItem("Completion is not available in this context")
                        {
                            insertText = ""
                        });
                    }
                }

                if (userFilterToken != null)
                {
                    //Add the range object to let the client know the position of the user filter token
                    var range = new Range(userFilterToken.Line - 1, userFilterToken.StartIndex,
                                          userFilterToken.Line - 1, userFilterToken.StopIndex + 1);
                    //-1 on lne to 0 based / +1 on stop index to include the last character
                    items = items.Select(c =>
                    {
                        if (c.data != null && c.data.GetType().IsArray)
                        {
                            ((object[])c.data)[0] = range;
                        }
                        else
                        {
                            c.data = range;
                        }
                        return(c);
                    }).ToList();
                }
            }


            return(items);
        }