예제 #1
0
        /////////////////////////////////////////////////////////////////////////////////////////////////////
        // PUBLIC PROCEDURES
        /////////////////////////////////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Sets the current statement indicator, by finding the next breakpoint after the specified snapshot offset.
        /// </summary>
        /// <param name="document">The editor document.</param>
        /// <param name="startSnapshotOffset">The starting snapshot offset to examine.</param>
        /// <returns>The current statement snapshot offset.</returns>
        public static TextSnapshotOffset SetCurrentStatement(IEditorDocument document, TextSnapshotOffset startSnapshotOffset)
        {
            if (!startSnapshotOffset.IsDeleted)
            {
                // Create search options (only allow enabled breakpoints)
                var options = new TagSearchOptions <BreakpointIndicatorTag>();
                options.Filter = (tr => tr.Tag.IsEnabled);

                // Find the next breakpoint
                var tagRange = document.IndicatorManager.Breakpoints.FindNext(startSnapshotOffset, options);
                if (tagRange != null)
                {
                    // Get the snapshot range of the breakpoint
                    var snapshotRange = tagRange.VersionRange.Translate(startSnapshotOffset.Snapshot);
                    var currentStatementSnapshotOffset = new TextSnapshotOffset(snapshotRange.Snapshot, snapshotRange.EndOffset);

                    // Set the current statement indicator range
                    document.IndicatorManager.CurrentStatement.SetInstance(snapshotRange);

                    return(currentStatementSnapshotOffset);
                }
            }

            // Remove any current statement indicator
            document.IndicatorManager.CurrentStatement.Clear();

            return(TextSnapshotOffset.Deleted);
        }
예제 #2
0
        /////////////////////////////////////////////////////////////////////////////////////////////////////
        // NON-PUBLIC PROCEDURES
        /////////////////////////////////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Finds the statement AST node that contains the specified offset.
        /// </summary>
        /// <param name="parseData">The parse data.</param>
        /// <param name="snapshotOffset">The target snapshot offset.</param>
        /// <returns>The statement AST node that contains the specified offset.</returns>
        private static IAstNode FindContainingStatement(IDotNetParseData parseData, TextSnapshotOffset snapshotOffset)
        {
            // Get the offset relative to the AST's snapshot
            var offset = snapshotOffset.Offset;

            if (parseData.Snapshot != null)
            {
                offset = snapshotOffset.TranslateTo(parseData.Snapshot, TextOffsetTrackingMode.Negative);
            }

            // Loop upwards through the AST to find a containing statement
            var       node         = parseData.Ast.FindDescendantNode(offset);
            Statement statmentNode = null;

            while (node != null)
            {
                statmentNode = node as Statement;
                if (statmentNode != null)
                {
                    return(statmentNode);
                }

                node = node.Parent;
            }

            return(null);
        }
예제 #3
0
        public IStructureMatchResultSet Match(TextSnapshotOffset snapshotOffset, IStructureMatchOptions options)
        {
            var snapshot = snapshotOffset.GetDocumentView();

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

            SyntaxTree syntaxTree;

            if (!snapshot.Document.TryGetSyntaxTree(out syntaxTree))
            {
                return(null);
            }

            var position = snapshot.Position;

            var result = syntaxTree.MatchBraces(position, Matchers);

            if (!result.IsValid)
            {
                return(null);
            }

            var leftRange  = snapshot.ToSnapshotRange(result.Left);
            var rightRange = snapshot.ToSnapshotRange(result.Right);
            var results    = new StructureMatchResultCollection
            {
                new StructureMatchResult(leftRange),
                new StructureMatchResult(rightRange)
            };

            return(new StructureMatchResultSet(results));
        }
예제 #4
0
        public static DocumentView GetDocumentView(this TextSnapshotOffset offset)
        {
            var position = offset.ToOffset();
            var document = offset.Snapshot.ToDocument();

            return(new DocumentView(document, position));
        }
예제 #5
0
        public static int ToOffset(this TextSnapshotOffset offset)
        {
            var sourceText   = offset.Snapshot.ToSourceText();
            var textPosition = offset.Position;
            var line         = sourceText.Lines[textPosition.Line];

            return(line.Span.Start + textPosition.Character);
        }
        /////////////////////////////////////////////////////////////////////////////////////////////////////
        // 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));
        }
        /// <summary>
        /// Examines the AST data to determine the context type and insert the containing function declaration.
        /// </summary>
        /// <param name="context">The <see cref="SimpleContext"/> to update.</param>
        private static void UpdateFromAst(SimpleContext context)
        {
            // Get the snapshot offset
            TextSnapshotOffset snapshotOffset = context.SnapshotOffset;

            // Get the document
            ICodeDocument document = snapshotOffset.Snapshot.Document as ICodeDocument;

            if (document == null)
            {
                return;
            }

            ILLParseData parseData = document.ParseData as ILLParseData;

            if (parseData != null)
            {
                CompilationUnit compilationUnit = parseData.Ast as CompilationUnit;
                if ((compilationUnit != null) && (compilationUnit.HasMembers))
                {
                    // Translate the snapshot offset to the AST's snapshot
                    if (parseData.Snapshot != null)
                    {
                        snapshotOffset = snapshotOffset.TranslateTo(parseData.Snapshot, TextOffsetTrackingMode.Negative);
                    }

                    // Loop through AST nodes
                    foreach (FunctionDeclaration functionAstNode in compilationUnit.Members)
                    {
                        // If the child node is a function declaration with valid offsets...
                        if ((functionAstNode.StartOffset.HasValue) && (functionAstNode.EndOffset.HasValue))
                        {
                            // If the function's text range contains the offset...
                            TextRange functionTextRange = new TextRange(functionAstNode.StartOffset.Value, functionAstNode.EndOffset.Value);
                            if (functionTextRange.Contains(snapshotOffset.Offset))
                            {
                                // Initially assume we are in a header
                                context.Type = SimpleContextType.FunctionDeclarationHeader;
                                context.ContainingFunctionDeclaration = functionAstNode;

                                // If the function has a body with a range...
                                if ((functionAstNode.Body != null) && (functionAstNode.Body.StartOffset.HasValue) && (functionAstNode.Body.EndOffset.HasValue))
                                {
                                    // If the block's text range contains the offset...
                                    TextRange blockTextRange = new TextRange(functionAstNode.Body.StartOffset.Value + 1, functionAstNode.Body.EndOffset.Value - 1);
                                    if (blockTextRange.Contains(snapshotOffset.Offset))
                                    {
                                        // Mark that we are in a block instead
                                        context.Type = SimpleContextType.FunctionDeclarationBlock;
                                    }
                                }
                                break;
                            }
                        }
                    }
                }
            }
        }
예제 #8
0
        /// <summary>
        /// Occurs when the button is clicked.
        /// </summary>
        /// <param name="sender">The sender of the event.</param>
        /// <param name="e">A <see cref="RoutedEventArgs"/> that contains the event data.</param>
        private void OnStopDebuggingButtonClick(object sender, RoutedEventArgs e)
        {
            // Flag as not debugging
            currentStatementSnapshotOffset = DebuggingHelper.SetCurrentStatement(editor.Document, TextSnapshotOffset.Deleted);
            stopDebuggingButton.IsEnabled  = false;

            // Focus the editor
            editor.Focus();
        }
예제 #9
0
        public static TextSpan ToTextSpan(this TextSnapshotRange range)
        {
            var startOffset = new TextSnapshotOffset(range.Snapshot, range.StartOffset);
            var endOffset   = new TextSnapshotOffset(range.Snapshot, range.EndOffset);
            var start       = startOffset.ToOffset();
            var end         = endOffset.ToOffset();

            return(TextSpan.FromBounds(start, end));
        }
예제 #10
0
        public static DocumentView GetDocumentView(this SyntaxEditor syntaxEditor)
        {
            var document  = syntaxEditor.Document.GetDocument();
            var snapshot  = document.Text.ToTextSnapshot();
            var offset    = syntaxEditor.Caret.Offset;
            var selection = syntaxEditor.ActiveView.Selection.SnapshotRange.TranslateTo(snapshot, TextRangeTrackingModes.Default).ToTextSpan();
            var position  = new TextSnapshotOffset(snapshot, offset).ToOffset();

            return(new DocumentView(document, position, selection));
        }
예제 #11
0
        /////////////////////////////////////////////////////////////////////////////////////////////////////
        // OBJECT
        /////////////////////////////////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Initializes a new instance of the <c>SimpleContext</c> class.
        /// </summary>
        /// <param name="snapshotOffset">The <see cref="TextSnapshotOffset"/> that indicates the location to examine.</param>
        public SimpleContext(TextSnapshotOffset snapshotOffset)
        {
            if (snapshotOffset.IsDeleted)
            {
                throw new ArgumentNullException("snapshotOffset");
            }

            // Initialize
            this.snapshotOffset = snapshotOffset;
        }
예제 #12
0
        /////////////////////////////////////////////////////////////////////////////////////////////////////
        // OBJECT
        /////////////////////////////////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Initializes a new instance of the <c>CodeLensDeclaration</c> class.
        /// </summary>
        /// <param name="snapshotOffset">The snapshot offset at which the declaration occurs.</param>
        /// <param name="astNode">The <see cref="IAstNode"/> for the declaration.</param>
        public CodeLensDeclaration(TextSnapshotOffset snapshotOffset, IAstNode astNode)
        {
            if (astNode == null)
            {
                throw new ArgumentNullException("astNode");
            }

            // Initialize
            this.VersionRange = new TextSnapshotRange(snapshotOffset).ToVersionRange(TextRangeTrackingModes.Default);
            this.AstNode      = astNode;
            this.CreateKey();
        }
        /////////////////////////////////////////////////////////////////////////////////////////////////////
        // PUBLIC PROCEDURES
        /////////////////////////////////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Creates a <see cref="SimpleContext"/> for the specified <see cref="TextSnapshotOffset"/>.
        /// </summary>
        /// <param name="snapshotOffset">The <see cref="TextSnapshotOffset"/> for which to create a context.</param>
        /// <param name="includeArgumentInfo">Whether to populate the argument-related context properties, for use with parameter info.</param>
        /// <returns>The <see cref="SimpleContext"/> that was created.</returns>
        public SimpleContext CreateContext(TextSnapshotOffset snapshotOffset, bool includeArgumentInfo)
        {
            // Create a context
            SimpleContext context = new SimpleContext(snapshotOffset);

            // Update the context from the AST
            UpdateFromAst(context);

            // Update the context from the snapshot text
            UpdateFromSnapshotText(context, includeArgumentInfo);

            return(context);
        }
예제 #14
0
        /// <summary>
        /// Occurs when the button is clicked.
        /// </summary>
        /// <param name="sender">The sender of the event.</param>
        /// <param name="e">A <see cref="RoutedEventArgs"/> that contains the event data.</param>
        private void OnStartDebuggingButtonClick(object sender, RoutedEventArgs e)
        {
            // If starting debugging from a stopped state, begin looking at the document start
            if (currentStatementSnapshotOffset.IsDeleted)
            {
                currentStatementSnapshotOffset = new TextSnapshotOffset(editor.ActiveView.CurrentSnapshot, 0);
            }

            // Flag as debugging
            currentStatementSnapshotOffset = DebuggingHelper.SetCurrentStatement(editor.Document, currentStatementSnapshotOffset);
            stopDebuggingButton.IsEnabled  = !currentStatementSnapshotOffset.IsDeleted;

            // Focus the editor
            editor.Focus();
        }
예제 #15
0
        /// <summary>
        /// Translates from a generated snapshot to an editor snapshot.
        /// </summary>
        /// <param name="snapshotOffset">The snapshot offset.</param>
        /// <returns>The translated snapshot, if within a child language section.</returns>
        public TextSnapshotOffset?TranslateGeneratedToEditor(TextSnapshotOffset snapshotOffset)
        {
            if ((generatedParseData != null) && (generatedParseData.Snapshot != null))
            {
                // Translate back to the generated parse data's snapshot
                snapshotOffset = snapshotOffset.TranslateTo(generatedParseData.Snapshot, TextOffsetTrackingMode.Negative);

                foreach (var mapping in textRangeMappings)
                {
                    if (mapping.Item2.IntersectsWith(snapshotOffset.Offset))
                    {
                        var editorSnapshotOffset = new TextSnapshotOffset(snapshot, mapping.Item1.StartOffset + (snapshotOffset.Offset - mapping.Item2.StartOffset));
                        return(editorSnapshotOffset);
                    }
                }
            }

            return(null);
        }
예제 #16
0
        /// <summary>
        /// Toggles a breakpoint.
        /// </summary>
        /// <param name="snapshotOffset">The <see cref="TextSnapshotOffset"/> of the indicator.</param>
        /// <param name="isEnabled">Whether a new breakpoint should be enabled.</param>
        public static void ToggleBreakpoint(TextSnapshotOffset snapshotOffset, bool isEnabled)
        {
            var document = snapshotOffset.Snapshot.Document as IEditorDocument;

            if (document == null)
            {
                return;
            }

            var parseData = document.ParseData as IDotNetParseData;

            if (parseData == null)
            {
                return;
            }

            // Find the containing statement
            var node = FindContainingStatement(parseData, snapshotOffset);

            if ((node == null) || (!node.StartOffset.HasValue) || (!node.EndOffset.HasValue))
            {
                MessageBox.Show("Please move the caret inside of a valid C# statement.", "Toggle Breakpoint", MessageBoxButton.OK, MessageBoxImage.Exclamation);
                return;
            }

            // Get the snapshot range of the statement
            var snapshotRange = new TextSnapshotRange(parseData.Snapshot ?? snapshotOffset.Snapshot, node.StartOffset.Value, node.EndOffset.Value);

            // Create a breakpoint tag
            var tag = new BreakpointIndicatorTag();

            tag.IsEnabled = isEnabled;

            // Toggle the indicator
            var tagRange = document.IndicatorManager.Breakpoints.Toggle(snapshotRange, tag);

            // Set the tag's content provider (quick info for the glyph) if a tag was added
            if (tagRange != null)
            {
                tag.ContentProvider = new BreakpointIndicatorTagContentProvider(tagRange);
            }
        }
        public override object GetContext(IEditorView view, int offset)
        {
            var documentView = view.SyntaxEditor.GetDocumentView();
            var document     = documentView.Document;

            SemanticModel semanticModel;

            if (!document.TryGetSemanticModel(out semanticModel))
            {
                return(null);
            }

            var snapshot       = document.Text.ToTextSnapshot();
            var snapshotOffset = new TextSnapshotOffset(snapshot, offset);
            var position       = snapshotOffset.ToOffset();

            var model = semanticModel.GetQuickInfoModel(position, Providers);

            return(model);
        }
        /////////////////////////////////////////////////////////////////////////////////////////////////////
        // PUBLIC PROCEDURES
        /////////////////////////////////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Returns a set of <see cref="INavigableSymbol"/> objects that are accessible within the optional parent <see cref="INavigableSymbol"/>.
        /// </summary>
        /// <param name="context">An <see cref="INavigableRequestContext"/> that provides the context of the request.</param>
        /// <param name="snapshotOffset">The <see cref="TextSnapshotOffset"/> that contains the <see cref="ITextSnapshot"/> to examine, along with a contextual offset.</param>
        /// <param name="parentSymbol">The optional parent <see cref="INavigableSymbol"/> to examine, or a null value if the root symbols are requested.</param>
        /// <returns>An <see cref="INavigableSymbolSet"/> containing the <see cref="INavigableSymbol"/> objects that were located.</returns>
        public INavigableSymbolSet GetSymbols(INavigableRequestContext context, TextSnapshotOffset snapshotOffset, INavigableSymbol parentSymbol)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }
            if (snapshotOffset.IsDeleted)
            {
                throw new ArgumentOutOfRangeException("snapshotOffset");
            }

            if (context == NavigableRequestContexts.NavigableSymbolSelector)
            {
                var document = snapshotOffset.Snapshot.Document as ICodeDocument;
                if (document != null)
                {
                    // If there is AST data...
                    var parseData = document.ParseData as ILLParseData;
                    if ((parseData != null) && (parseData.Ast != null))
                    {
                        // Recurse into the AST
                        var symbols = new List <INavigableSymbol>();

                        // NOTE: Normally here you would return either root symbols or member symbols depending on if a parentSymbol is passed...
                        //   In this Simple language though, we only ever need root symbols
                        if (parentSymbol == null)
                        {
                            this.AddFunctionDeclarationSymbolsFromAst(symbols, parseData.Snapshot ?? snapshotOffset.Snapshot, parseData.Ast as CompilationUnit);
                        }

                        // Sort
                        symbols.Sort(navigationSymbolComparer);

                        return(new NavigableSymbolSet(symbols));
                    }
                }
            }

            // No results
            return(new NavigableSymbolSet(null));
        }
예제 #19
0
        /////////////////////////////////////////////////////////////////////////////////////////////////////
        // PUBLIC PROCEDURES
        /////////////////////////////////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Returns the ideal amount of indent, always in columns, for the line containing the snapshot offset.
        /// </summary>
        /// <param name="snapshotOffset">The <see cref="TextSnapshotOffset"/> whose line should be examined.</param>
        /// <param name="defaultAmount">The default indent amount, which is the amount used in <c>Block</c> mode.</param>
        /// <returns>The ideal amount of indent, always in columns, for the line containing the snapshot offset.</returns>
        /// <remarks>
        /// This method is called when the <see cref="IndentMode"/> is <c>Smart</c>.
        /// The containing <see cref="ITextDocument"/> is accessible via the snapshot range's <see cref="ITextSnapshot"/>.
        /// </remarks>
        public override int GetIndentAmount(TextSnapshotOffset snapshotOffset, int defaultAmount)
        {
            // If the snapshot offset is deleted, return the default amount
            if (snapshotOffset.IsDeleted)
            {
                return(defaultAmount);
            }

            // Get the ICodeDocument from the snapshot
            ICodeDocument document = snapshotOffset.Snapshot.Document as ICodeDocument;

            if (document == null)
            {
                return(defaultAmount);
            }

            // Get the tab size
            int tabSize = document.TabSize;

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

            if (reader == null)
            {
                return(defaultAmount);
            }

            // Get the indentation base line index
            int indentationBaseLineIndex = Math.Max(0, snapshotOffset.Line.Index - 1);

            // Ensure we are at the start of the current token
            if (!reader.IsAtTokenStart)
            {
                reader.GoToCurrentTokenStart();
            }

            // If finding indentation for an open curly brace, move back a token
            bool isForOpenCurlyBrace = (reader.Token.Id == SimpleTokenId.OpenCurlyBrace);

            if (isForOpenCurlyBrace)
            {
                reader.GoToPreviousToken();
            }

            // Loop backwards
            bool keywordFoundAfterStatement = false;
            bool statementFound             = false;

            while (true)
            {
                switch (reader.Token.Id)
                {
                case SimpleTokenId.OpenCurlyBrace: {
                    // Indent from this open curly brace
                    return(reader.SnapshotLine.IndentAmount + tabSize);
                }

                case SimpleTokenId.CloseCurlyBrace:
                    // Return the indent level of the matching {
                    reader.GoToPreviousMatchingTokenById(SimpleTokenId.CloseCurlyBrace, SimpleTokenId.OpenCurlyBrace);
                    return(reader.SnapshotLine.IndentAmount);

                case SimpleTokenId.CloseParenthesis:
                case SimpleTokenId.SemiColon:
                    if (!statementFound)
                    {
                        // Flag that a statement was found
                        statementFound = true;

                        if (!keywordFoundAfterStatement)
                        {
                            // Use this line as indentation base
                            indentationBaseLineIndex = reader.SnapshotLine.Index;
                        }
                    }
                    break;

                default:
                    if ((!keywordFoundAfterStatement) && (!statementFound) && (reader.Offset < snapshotOffset.Offset) &&
                        (reader.Token.Id >= SimpleTokenId.Function) && (reader.Token.Id <= SimpleTokenId.Var))
                    {
                        // Flag that a keyword was found
                        keywordFoundAfterStatement = true;

                        // Use this line as indentation base
                        indentationBaseLineIndex = reader.SnapshotLine.Index;
                    }
                    break;
                }

                // Go to the previous token
                if (!reader.GoToPreviousToken())
                {
                    break;
                }
            }

            // Indent a level if on the statement after the keyword
            return(reader.Snapshot.Lines[indentationBaseLineIndex].IndentAmount + (keywordFoundAfterStatement && isForOpenCurlyBrace ? tabSize : 0));
        }
        /// <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();
                        }
                    }
                }
            }
        }
예제 #21
0
        /////////////////////////////////////////////////////////////////////////////////////////////////////
        // PUBLIC PROCEDURES
        /////////////////////////////////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Translates the specified snapshot offset to the parse data's <see cref="IParseErrorProvider.Snapshot"/>, if possible, prior to containing AST node lookup.
        /// </summary>
        /// <param name="parseData">The <see cref="IDotNetParseData"/> to examine.</param>
        /// <param name="snapshotOffset">The <see cref="TextSnapshotOffset"/> to translate.</param>
        /// <returns>The translated offset.</returns>
        protected override TextSnapshotOffset TranslateToParseDataSnapshot(IDotNetParseData parseData, TextSnapshotOffset snapshotOffset)
        {
            var generatedSnapshotOffset = translateFunc(snapshotOffset);

            if (generatedSnapshotOffset.HasValue)
            {
                return(base.TranslateToParseDataSnapshot(parseData, generatedSnapshotOffset.Value));
            }
            else
            {
                return(base.TranslateToParseDataSnapshot(parseData, snapshotOffset));
            }
        }
 private void OnStartDebuggingButtonClick(object sender, RoutedEventArgs e)
 {
     foreach (var bp in document.IndicatorManager.Breakpoints.GetInstances())
     {
         var line = bp.VersionRange.Translate(document.CurrentSnapshot).StartPosition.Line;
     }
     if (currentStatementSnapshotOffset.IsDeleted)
         currentStatementSnapshotOffset = new TextSnapshotOffset(syntaxEditor.ActiveView.CurrentSnapshot, 0);
     var snapshotOffset = syntaxEditor.ActiveView.Selection.EndSnapshotOffset;
     var context = new PythonContextFactory().CreateContext(snapshotOffset);
     currentStatementSnapshotOffset = DebuggingHelper.SetCurrentStatement(syntaxEditor.Document, currentStatementSnapshotOffset);
     stopDebuggingButton.IsEnabled = !currentStatementSnapshotOffset.IsDeleted;
     syntaxEditor.Focus();
 }
 private void OnStopDebuggingButtonClick(object sender, RoutedEventArgs e)
 {
     currentStatementSnapshotOffset = DebuggingHelper.SetCurrentStatement(syntaxEditor.Document, TextSnapshotOffset.Deleted);
     stopDebuggingButton.IsEnabled = false;
     syntaxEditor.Focus();
 }