Exemple #1
0
        private string ReadArrayIndexExpression(ITextSnapshotReader reader)
        {
            // we're looking for an expression of the form [123] or [myVariable]
            // if we don't find one, return false.
            string indexValue = null;

            var token = reader.ReadTokenReverse();

            while (token != null)
            {
                var text = reader.PeekText(token.Length);

                if (token.Key == "Identifier" && indexValue == null)
                {
                    // substitute 0 for the name of the variable to give us
                    // the best chance of matching something when we look up the path in a document
                    indexValue = "0";
                }
                else if ((token.Key == "IntegerNumber") && indexValue == null)
                {
                    indexValue = text;
                }
                else if (token.Key == "Whitespace")
                {
                    // skip it
                }
                else if (token.Key == "OpenSquareBrace")
                {
                    if (indexValue == null)
                    {
                        // we didn't find a properly formed (and simple) index expression
                        // before hitting the square brace
                        return(null);
                    }
                    else
                    {
                        break;
                    }
                }

                token = reader.ReadTokenReverse();
            }

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

            return("[" + indexValue + "]");
        }
        /////////////////////////////////////////////////////////////////////////////////////////////////////
        // PUBLIC PROCEDURES
        /////////////////////////////////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Attempts to locate structural text, such as bracket pairs, at the specified offset.
        /// </summary>
        /// <param name="snapshotOffset">The <see cref="TextSnapshotOffset"/> to examine.</param>
        /// <param name="options">The <see cref="IStructureMatchOptions"/> to use.</param>
        /// <returns>An <see cref="IStructureMatchResultSet"/> that contains the results that were found, if any.</returns>
        /// <remarks>
        /// When the result set is empty, no structural delimiter was next to the specified offset.
        /// When the result set contains a single result, a structural delimiter such as a bracket was found next to the specified offset,
        /// but no matching structural delimiter was found.
        /// The result set may contain multiple entries in cases such as when a language wishes to flag <c>#if...#else...#endif</c> blocks as a structure.
        /// </remarks>
        public override IStructureMatchResultSet Match(TextSnapshotOffset snapshotOffset, IStructureMatchOptions options)
        {
            if (snapshotOffset.IsDeleted)
            {
                throw new ArgumentNullException("snapshotOffset");
            }

            // Get a snapshot reader and configure it for quick initial lookup
            ITextSnapshotReader reader = snapshotOffset.Snapshot.GetReader(snapshotOffset.Offset);

            reader.Options.DefaultTokenLoadBufferLength = 250;
            reader.Options.InitialTokenLoadBufferLength = 4;

            IToken token = reader.Token;

            if (token != null)
            {
                // If the token is not a multi-line comment but is at the start of a token, check the previous token
                if ((token.Id != SimpleTokenId.MultiLineCommentText) && (reader.IsAtTokenStart))
                {
                    token = reader.ReadTokenReverse();
                }

                // If the token is a multi-line comment...
                if (token.Id == SimpleTokenId.MultiLineCommentText)
                {
                    // The Simple language programmatic lexer variant only has a single token for the entire comment so
                    //   ensure the target offset is at a delimiter (and not within the body of the comment)...
                    //   For most other languages, you'd want to scan tokens to find a matching delimiter token instead
                    bool isAtStart = (snapshotOffset.Offset <= token.StartOffset + 2);
                    bool isAtEnd   = (snapshotOffset.Offset >= token.EndOffset - 2);
                    if (isAtStart || isAtEnd)
                    {
                        // Get the token's text and ensure it ends with a proper delimiter
                        string tokenText = reader.TokenText;
                        if ((token.Length >= 4) && (tokenText.EndsWith("*/", StringComparison.Ordinal)))
                        {
                            // Found a valid match
                            StructureMatchResultCollection results = new StructureMatchResultCollection();
                            results.Add(new StructureMatchResult(new TextSnapshotRange(reader.Snapshot, token.StartOffset, token.StartOffset + 2))
                            {
                                IsSource = isAtStart,
                                NavigationSnapshotOffset = new TextSnapshotOffset(reader.Snapshot, token.StartOffset)
                            });
                            results.Add(new StructureMatchResult(new TextSnapshotRange(reader.Snapshot, token.EndOffset - 2, token.EndOffset))
                            {
                                IsSource = !isAtStart,
                                NavigationSnapshotOffset = new TextSnapshotOffset(reader.Snapshot, token.EndOffset)
                            });
                            return(new StructureMatchResultSet(results));
                        }
                    }
                }
            }

            // Call the base method
            return(base.Match(snapshotOffset, options));
        }
Exemple #3
0
        private string DetermineFullMemberExpression(string tokenText, ITextSnapshotReader reader)
        {
            var sb    = new StringBuilder(tokenText);
            var token = reader.ReadTokenReverse();

            while (token != null)
            {
                var text = reader.PeekText(token.Length);

                if (token.Key == "Identifier" || (token.Key == "Punctuation" && text == ".") || (token.Key == "Keyword" && text == "this"))
                {
                    sb.Insert(0, text);
                }
                else if (token.Key == "CloseSquareBrace")
                {
                    var indexExpression = ReadArrayIndexExpression(reader);
                    if (indexExpression == null)
                    {
                        // we're not going to be able to make sense
                        // of the rest of the expression, so bail out.
                        break;
                    }

                    sb.Insert(0, indexExpression);
                }
                else if (token.Key == "Whitespace")
                {
                    // skip it
                }
                else
                {
                    break;
                }

                token = reader.ReadTokenReverse();
            }

            return(sb.ToString());
        }
Exemple #4
0
        public void OnEditorDocumentTextChanged(object sender, EditorSnapshotChangedEventArgs e)
        {
            string typedText = e.TypedText;

            if (typedText != null && typedText == ".")
            {
                ITextSnapshotReader reader = this.nitriqSyntaxEditor_0.ActiveView.GetReader();
                reader.ReadCharacterReverseThrough('.');
                IToken token = reader.ReadTokenReverse();
                if (token != null)
                {
                    this.method_2(false, reader.TokenText);
                }
            }
        }
        private static string FindPrecedingField(ITextSnapshotReader reader)
        {
            while (true)
            {
                var token = reader.ReadTokenReverse();

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

                if (token.Key == "Field")
                {
                    return(GetFieldName(reader.PeekText(token.Length)));
                }
            }
        }
		private string ReadArrayIndexExpression(ITextSnapshotReader reader)
		{
			// we're looking for an expression of the form [123] or [myVariable]
			// if we don't find one, return false.
			string indexValue = null;

			var token = reader.ReadTokenReverse();
			while (token != null)
			{
				var text = reader.PeekText(token.Length);

				if (token.Key == "Identifier" && indexValue == null)
				{
					// substitute 0 for the name of the variable to give us 
					// the best chance of matching something when we look up the path in a document
					indexValue = "0";
				}
				else if ((token.Key == "IntegerNumber") && indexValue == null)
				{
					indexValue = text;
				}
				else if (token.Key == "Whitespace")
				{
					// skip it
				}
				else if (token.Key == "OpenSquareBrace")
				{
					if (indexValue == null)
					{
						// we didn't find a properly formed (and simple) index expression
						// before hitting the square brace
						return null;
					}

					break;
				}

				token = reader.ReadTokenReverse();
			}

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

			return "[" + indexValue + "]";
		}
		private string DetermineFullMemberExpression(string tokenText, ITextSnapshotReader reader)
		{
			var sb = new StringBuilder(tokenText);
			var token = reader.ReadTokenReverse();
			while (token != null)
			{
				var text = reader.PeekText(token.Length);

				if (token.Key == "Identifier" || (token.Key == "Punctuation" && text == ".") || (token.Key == "Keyword" && text == "this"))
				{
					sb.Insert(0, text);
				}
				else if (token.Key == "CloseSquareBrace")
				{
					var indexExpression = ReadArrayIndexExpression(reader);
					if (indexExpression == null)
					{
						// we're not going to be able to make sense
						// of the rest of the expression, so bail out.
						break;
					}

					sb.Insert(0, indexExpression);
				}
				else if (token.Key == "Whitespace")
				{
					// skip it
				}
				else
				{
					break;
				}

				token = reader.ReadTokenReverse();
			}

			return sb.ToString();
		}
	    private static string FindPrecedingField(ITextSnapshotReader reader)
	    {
	        while (true)
	        {
                var token = reader.ReadTokenReverse();

                if (token == null)
                    return null;
                
                if (token.Key == "Field")
                    return GetFieldName(reader.PeekText(token.Length));
	        }
	    }
        /// <summary>
        /// Examines the snapshot text to determine more detail about the context.
        /// </summary>
        /// <param name="context">The <see cref="SimpleContext"/> to update.</param>
        /// <param name="includeArgumentInfo">Whether to populate the argument-related context properties, for use with parameter info.</param>
        private static void UpdateFromSnapshotText(SimpleContext context, bool includeArgumentInfo)
        {
            // Get the snapshot offset
            TextSnapshotOffset snapshotOffset = context.SnapshotOffset;

            // Create a default initialization range
            context.InitializationSnapshotRange = new TextSnapshotRange(snapshotOffset);

            // Get a snapshot reader
            ITextSnapshotReader reader = snapshotOffset.Snapshot.GetReader(snapshotOffset.Offset);

            if (reader == null)
            {
                return;
            }

            IToken token = reader.ReadToken();

            if (token != null)
            {
                // If the current token is a comment, flag no context
                switch (token.Id)
                {
                case SimpleTokenId.MultiLineCommentEndDelimiter:
                case SimpleTokenId.MultiLineCommentLineTerminator:
                case SimpleTokenId.MultiLineCommentStartDelimiter:
                case SimpleTokenId.MultiLineCommentText:
                case SimpleTokenId.SingleLineCommentEndDelimiter:
                case SimpleTokenId.SingleLineCommentStartDelimiter:
                case SimpleTokenId.SingleLineCommentText:
                    context.Type = SimpleContextType.None;
                    return;
                }
            }

            // If we are in a function declaration block...
            if (context.Type == SimpleContextType.FunctionDeclarationBlock)
            {
                // Get the AST
                ICodeDocument document = snapshotOffset.Snapshot.Document as ICodeDocument;
                if (document == null)
                {
                    return;
                }
                ILLParseData parseData = document.ParseData as ILLParseData;
                if (parseData == null)
                {
                    return;
                }
                CompilationUnit compilationUnit = parseData.Ast as CompilationUnit;
                if ((compilationUnit == null) || (!compilationUnit.HasMembers))
                {
                    return;
                }

                // If argument data should be scanned...
                if (includeArgumentInfo)
                {
                    // Scan backward to look for argument data
                    reader.Offset = snapshotOffset.Offset;
                    reader.GoToCurrentTokenStart();
                    var startOffset = reader.Offset;
                    token = reader.ReadTokenReverse();
                    while (token != null)
                    {
                        // Quit if we look behind too far (for performance reasons) - 500 is arbitrary number and could be tweaked
                        if ((!context.ArgumentIndex.HasValue) && (startOffset - reader.Offset > 500))
                        {
                            return;
                        }

                        switch (token.Id)
                        {
                        case SimpleTokenId.CloseParenthesis:
                            // Skip over ( ... ) pair
                            if (!reader.GoToPreviousMatchingTokenById(SimpleTokenId.CloseParenthesis, SimpleTokenId.OpenParenthesis))
                            {
                                return;
                            }
                            break;

                        case SimpleTokenId.Comma:
                            // Update the context data
                            if (context.ArgumentIndex.HasValue)
                            {
                                context.ArgumentIndex++;
                            }
                            else
                            {
                                context.ArgumentIndex          = 1;
                                context.ArgumentSnapshotOffset = new TextSnapshotOffset(reader.Snapshot, token.EndOffset);
                            }
                            break;

                        case SimpleTokenId.OpenParenthesis:
                            // Update the context data
                            context.ArgumentListSnapshotOffset = new TextSnapshotOffset(reader.Snapshot, token.EndOffset);
                            if (!context.ArgumentIndex.HasValue)
                            {
                                context.ArgumentIndex          = 0;
                                context.ArgumentSnapshotOffset = context.ArgumentListSnapshotOffset;
                            }

                            // Go to the previous token
                            reader.GoToPreviousToken();
                            token = reader.Token;
                            if ((token != null) && (token.Id == SimpleTokenId.Identifier))
                            {
                                // Loop through the AST nodes to ensure that the identifier text matches a declared function name
                                string functionName = reader.TokenText;
                                foreach (FunctionDeclaration functionAstNode in compilationUnit.Members)
                                {
                                    // If the name matches the function's name...
                                    if (functionAstNode.Name == functionName)
                                    {
                                        // Update the target function
                                        context.TargetFunction = functionAstNode;
                                        break;
                                    }
                                }
                            }
                            return;

                        default:
                            // Quit if any tokens are found that aren't allowed in invocations
                            if (!IsTokenAllowedInInvocation(token.Id))
                            {
                                return;
                            }
                            else
                            {
                                break;
                            }
                        }

                        // Move back a token
                        token = reader.ReadTokenReverse();
                    }
                }
                else
                {
                    // If the current token is an identifier...
                    if ((token != null) && (token.Id == SimpleTokenId.Identifier))
                    {
                        // Store the identifier snapshot range in case this is a function reference token
                        TextSnapshotRange identifierSnapshotRange = new TextSnapshotRange(reader.Snapshot, token.TextRange);

                        // Next, check to ensure the next non-whitespace token is a '('
                        token = reader.ReadToken();
                        while (!reader.IsAtSnapshotEnd)
                        {
                            if (token != null)
                            {
                                switch (token.Id)
                                {
                                case SimpleTokenId.Whitespace:
                                    // Continue
                                    break;

                                case SimpleTokenId.OpenParenthesis: {
                                    // Loop through the AST nodes to ensure that the identifier text matches a declared function name
                                    foreach (FunctionDeclaration functionAstNode in compilationUnit.Members)
                                    {
                                        // If the name matches the function's name...
                                        if (functionAstNode.Name == identifierSnapshotRange.Text)
                                        {
                                            // Update the context type
                                            context.Type = SimpleContextType.FunctionReference;
                                            context.InitializationSnapshotRange = identifierSnapshotRange;
                                            context.TargetFunction = functionAstNode;
                                            break;
                                        }
                                    }
                                    return;
                                }

                                default:
                                    // Quit
                                    return;
                                }
                            }

                            // Advance
                            token = reader.ReadToken();
                        }
                    }
                }
            }
        }