예제 #1
0
        public NodeSnapshot(ITextSnapshot snapshot, INode node)
        {
            int offset = 0;
            if (node.Values.GetEnumerator().MoveNext())
            {
                ITextSnapshotLine line = snapshot.GetLineFromPosition(node.Position);

                // if the Value list is not empty, expand the snapshotSpan
                // to include leading whitespaces, so that when a user
                // types smth in this space he will get the dropdown
                for (; node.Position - offset > line.Extent.Start.Position; offset++)
                {
                    if (snapshot[node.Position - offset] == ' ')
                        continue;
                    if (snapshot[node.Position - offset] == '\t')
                        continue;
                    if (
                        snapshot[node.Position - offset] == '%' ||
                        snapshot[node.Position - offset] == '{' ||
                        snapshot[node.Position - offset] == '|'
                        )
                        offset++;
                    break;
                }
            }

            this.snapshotSpan = new SnapshotSpan(snapshot, node.Position - offset, node.Length + offset);
            this.node = node;
            foreach (IEnumerable<INode> list in node.Nodes.Values)
                foreach (INode child in list)
                    children.Add(new NodeSnapshot(snapshot, child));
        }
예제 #2
0
        public static bool IsFirstTokenOnLine(this SyntaxToken token, ITextSnapshot snapshot)
        {
            Contract.ThrowIfNull(snapshot);

            var baseLine = snapshot.GetLineFromPosition(token.SpanStart);
            return baseLine.GetFirstNonWhitespacePosition() == token.SpanStart;
        }
예제 #3
0
 private LinePreservingCodeReplacer(ITextView view, string newCode, Span range) {
     _view = view;
     _snapshot = view.TextBuffer.CurrentSnapshot;
     _oldCode = _snapshot.GetText(range);
     _newCode = newCode;
     _newLines = newCode.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None);
     _startingReplacementLine = _snapshot.GetLineFromPosition(range.Start).LineNumber;
 }
예제 #4
0
 public static bool IsInNamespace(ITextSnapshot snapshot, int position) {
     if (position > 0) {
         ITextSnapshotLine line = snapshot.GetLineFromPosition(position);
         if (line.Length > 2 && position - line.Start > 2) {
             return snapshot[position - 1] == ':';
         }
     }
     return false;
 }
예제 #5
0
        public ReverseExpressionParser(ITextSnapshot snapshot, ITextBuffer buffer, ITrackingSpan span)
        {
            _snapshot = snapshot;
            _buffer = buffer;
            _span = span;

            var loc = span.GetSpan(snapshot);
            var line = _curLine = snapshot.GetLineFromPosition(loc.Start);

            var targetSpan = new Span(line.Start.Position, span.GetEndPoint(snapshot).Position - line.Start.Position);
            _tokens = Classifier.GetClassificationSpans(new SnapshotSpan(snapshot, targetSpan));
        }
예제 #6
0
        public static TextSpan GetFormattingSpan(ITextSnapshot snapshot, SnapshotSpan selectedSpan)
        {
            var currentLine = snapshot.GetLineFromPosition(selectedSpan.Start);
            var endPosition = selectedSpan.IsEmpty ? currentLine.End : selectedSpan.End;
            var previousLine = GetNonEmptyPreviousLine(snapshot, currentLine);

            // first line on screen
            if (currentLine == previousLine)
            {
                return TextSpan.FromBounds(currentLine.Start, endPosition);
            }

            var lastNonNoisyCharPosition = previousLine.GetLastNonWhitespacePosition().Value;
            return TextSpan.FromBounds(lastNonNoisyCharPosition, endPosition);
        }
예제 #7
0
 private static Span? GetRoxygenBlockPosition(ITextSnapshot snapshot, int definitionStart) {
     var line = snapshot.GetLineFromPosition(definitionStart);
     for (int i = line.LineNumber - 1; i >= 0; i--) {
         var currentLine = snapshot.GetLineFromLineNumber(i);
         string lineText = currentLine.GetText().TrimStart();
         if (lineText.Length > 0) {
             if (lineText.EqualsOrdinal("##")) {
                 return new Span(currentLine.Start, currentLine.Length);
             } else if (lineText.EqualsOrdinal("#'")) {
                 return null;
             }
             break;
         }
     }
     return new Span(line.Start, 0);
 }
예제 #8
0
        public void AddError(ITextSnapshot snapshot, Diagnostic diagnostic, TextSpan span)
        {
            var line = snapshot.GetLineFromPosition(span.Start);

            var task = new ErrorTask
            {
                Text = diagnostic.Message,
                Line = line.LineNumber,
                Column = span.Start - line.Start.Position,
                Category = TaskCategory.CodeSense,
                ErrorCategory = TaskErrorCategory.Error,
                Priority = TaskPriority.Normal,
                Document = span.Filename
            };

            task.Navigate += OnTaskNavigate;

            _errorListProvider.Tasks.Add(task);
        }
예제 #9
0
        /// <summary>
        /// Creates the designer (proxy) node over the real syntax node passed in as a parameter
        /// Also recursively creates child nodes for all 'real' node children
        /// </summary>
        /// <param name="parent"></param>
        /// <param name="snapshot"></param>
        /// <param name="node"></param>
        public DesignerNode(NodeProvider provider, DesignerNode parent, ITextSnapshot snapshot, INode node)
        {
            this.provider = provider;
            Parent = parent;
            this.node = node;
            if (node.NodeType == NodeType.ParsingContext)
            {
                snapshotSpan = new SnapshotSpan(snapshot, node.Position + node.Length, 0);
                extensionSpan = new SnapshotSpan(snapshot, node.Position, node.Length);
            }
            else
            {
                snapshotSpan = new SnapshotSpan(snapshot, node.Position, node.Length);
                int offset = 0;
                if (node.Values.GetEnumerator().MoveNext())
                {
                    ITextSnapshotLine line = snapshot.GetLineFromPosition(node.Position);

                    // if the Value list is not empty, expand the snapshotSpan
                    // to include leading whitespaces, so that when a user
                    // types smth in this space he will get the dropdown
                    for (; node.Position - offset > line.Extent.Start.Position; offset++)
                    {
                        switch (snapshot[node.Position - offset - 1])
                        {
                            case ' ':
                            case '\t':
                                continue;
                            default:
                                break;
                        }
                        break;
                    }
                }
                extensionSpan = new SnapshotSpan(snapshot, node.Position - offset, offset);
            }
            foreach (IEnumerable<INode> list in node.Nodes.Values)
                foreach (INode child in list)
                    children.Add(new DesignerNode(provider, this, snapshot, child));
        }
예제 #10
0
		static bool IsWord(ITextSnapshot snapshot, int position, int length) {
			bool valid = position >= 0 && length >= 0 && (uint)(position + length) <= (uint)snapshot.Length;
			Debug.Assert(valid);
			if (!valid)
				return false;
			var line = snapshot.GetLineFromPosition(position);
			return UnicodeUtilities.IsWord(line, position - line.Start.Position, length);
		}
예제 #11
0
        /// <summary>
        /// Returns the applicable span at the provided position.
        /// </summary>
        /// <returns>A tracking span, or null if there is no token at the
        /// provided position.</returns>
        internal static ITrackingSpan GetApplicableSpan(this ITextSnapshot snapshot, int position, bool completeWord)
        {
            var classifier = snapshot.TextBuffer.GetPythonClassifier();
            var line       = snapshot.GetLineFromPosition(position);

            if (classifier == null || line == null)
            {
                return(null);
            }

            var spanLength = position - line.Start.Position;

            if (completeWord)
            {
                // Increase position by one to include 'fob' in: "abc.|fob"
                if (spanLength < line.Length)
                {
                    spanLength += 1;
                }
            }

            var classifications = classifier.GetClassificationSpans(new SnapshotSpan(line.Start, spanLength));

            // Handle "|"
            if (classifications == null || classifications.Count == 0)
            {
                return(null);
            }

            var lastToken = classifications[classifications.Count - 1];

            // Handle "fob |"
            if (lastToken == null || position > lastToken.Span.End)
            {
                return(null);
            }

            if (position > lastToken.Span.Start)
            {
                if (lastToken.ClassificationType.IsOfType(PredefinedClassificationTypeNames.String))
                {
                    // Handle "'contents of strin|g"
                    var text = lastToken.Span.GetText();
                    var span = GetStringContentSpan(text, lastToken.Span.Start) ?? lastToken.Span;

                    return(snapshot.CreateTrackingSpan(span, SpanTrackingMode.EdgeInclusive));
                }

                if (lastToken.CanComplete())
                {
                    // Handle "fo|o" : when it is 'show member' or 'complete word' use complete token.
                    // When it is autocompletion (as when typing in front of the existing contruct), take left part only.
                    var span = completeWord ? lastToken.Span : Span.FromBounds(lastToken.Span.Start, position);
                    return(snapshot.CreateTrackingSpan(span, SpanTrackingMode.EdgeInclusive));
                }

                // Handle "<|="
                return(null);
            }

            var secondLastToken = classifications.Count >= 2 ? classifications[classifications.Count - 2] : null;

            if (lastToken.Span.Start == position && lastToken.CanComplete() &&
                (secondLastToken == null ||             // Handle "|fob"
                 position > secondLastToken.Span.End || // Handle "if |fob"
                 !secondLastToken.CanComplete()))       // Handle "abc.|fob"
            {
                return(snapshot.CreateTrackingSpan(lastToken.Span, SpanTrackingMode.EdgeInclusive));
            }

            // Handle "abc|."
            // ("ab|c." would have been treated as "ab|c")
            if (secondLastToken != null && secondLastToken.Span.End == position && secondLastToken.CanComplete())
            {
                return(snapshot.CreateTrackingSpan(secondLastToken.Span, SpanTrackingMode.EdgeInclusive));
            }

            return(null);
        }
예제 #12
0
		IEnumerable<DeleteHorizontalWhitespaceInfo> GetHorizontalWhiteSpaceSpans(ITextSnapshot snapshot, Span span) {
			// Make sure no newline character is considered whitespace
			Debug.Assert(!IsWhitespace('\r'));
			Debug.Assert(!IsWhitespace('\n'));
			Debug.Assert(!IsWhitespace('\u0085'));
			Debug.Assert(!IsWhitespace('\u2028'));
			Debug.Assert(!IsWhitespace('\u2029'));

			int spanEnd = span.End;
			if (spanEnd > snapshot.Length)
				throw new ArgumentOutOfRangeException(nameof(span));
			int pos = span.Start;
			ITextSnapshotLine line = null;
			while (pos < spanEnd) {
				while (pos < spanEnd && !IsWhitespace(snapshot[pos]))
					pos++;
				int start = pos;

				while (pos < spanEnd && IsWhitespace(snapshot[pos]))
					pos++;
				int end = pos;

				if (start == end) {
					Debug.Assert(end == spanEnd);
					break;
				}

				if (line == null || start >= line.EndIncludingLineBreak.Position)
					line = snapshot.GetLineFromPosition(start);
				Debug.Assert(start >= line.Start.Position && end <= line.End);

				bool addSpace;
				if (start == line.Start.Position || end == line.End.Position)
					addSpace = false;
				else if (IsWhitespace(snapshot[start - 1]))
					addSpace = false;
				else if (IsWhitespace(snapshot[end]))
					addSpace = false;
				else {
					//TODO: sometimes all the spaces are removed "//    xxx = int i	123;"
					//		Select "xxx = int i	123;", and all spaces are removed ("xxx=inti123;")
					//		Select the full string "//    xxx = int i	123;" and whitespaces
					//		are kept ("// xxx = int i 123;"). Execute it again, and all spaces
					//		are removed ("//xxx=inti123;")
					addSpace = true;
				}
				yield return new DeleteHorizontalWhitespaceInfo(Span.FromBounds(start, end), addSpace);
			}
			Debug.Assert(pos == spanEnd);
		}
        protected virtual bool TokenEndsAtEndOfLine(ITextSnapshot snapshot, ITokenSource lexer, IToken token)
        {
            Lexer lexerLexer = lexer as Lexer;
            if (lexerLexer != null)
            {
                int c = lexerLexer.CharStream.LA(1);
                return c == '\r' || c == '\n';
            }

            ITextSnapshotLine line = snapshot.GetLineFromPosition(token.StopIndex + 1);
            return line.End <= token.StopIndex + 1 && line.EndIncludingLineBreak >= token.StopIndex + 1;
        }
예제 #14
0
        ///////////////////////////////////////////////////////////////////////////////////
        //
        // Validate the mardown directive syntax according to the ruleset definitions
        //
        // Copyright (c) 2014 Microsoft Corporation.
        // Author: Junyi Yi ([email protected]) - Initial version
        //
        ///////////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// Validate the whole document according to the specified ruleset.
        /// </summary>
        /// <param name="snapshot">The whole document snapshot.</param>
        /// <param name="errorTagger">The tagger used to generate error squiggles.</param>
        /// <param name="ruleset">The specified ruleset.</param>
        public static void ValidateDirectiveSyntax(ITextSnapshot snapshot, DirectiveRuleset ruleset, SimpleTagger<ErrorTag> errorTagger)
        {
            // Remove all current error squiggles
            errorTagger.RemoveTagSpans(errorTagSpan => true);

            // Get the full document text and clear all HTML tags
            string text = snapshot.GetText();
            text = MarkdownParser.DestroyHtmlTags(text);

            // Three cases:
            // 0123456789              01234567 8              01234567  8
            // [  WA ab ]              [  WA ab \n             [  WA ab EOT
            // |        |-endIndex=9   |        |-endIndex=8   |         |-endIndex=8
            // |-startIndex=0          |-startIndex=0          |-startIndex=0

            // Greedily search for the pair of '[...]' (supports nested pair '[... [...] ...]')
            // Here 'Greedily' means if we have a string '[...[...]', it would also treat the latter '[...]' as the pair
            for (int startIndex = text.IndexOf('['); startIndex >= 0; startIndex = text.IndexOf('[', startIndex))
            {
                int endIndex = MarkdownParser.FindCorrespondingEndBracket(text, startIndex + 1);

                // Get the directive content string
                ITrackingSpan overallDirective = snapshot.CreateTrackingSpan(startIndex + 1, endIndex - startIndex - 1, SpanTrackingMode.EdgeInclusive);
                string directive = overallDirective.GetText(snapshot);
                var directiveMatches = Regex.Matches(directive, string.Concat(@"^\s*(", ValidationUtilities.DirectiveNameRegularPattern, @")(.*)$"));
                if (directiveMatches.Count != 1 || !directiveMatches[0].Success || directiveMatches[0].Groups.Count != 3 || directiveMatches[0].Value != directive)
                {
                    startIndex++;
                    continue;
                }
                string directiveName = directiveMatches[0].Groups[1].Value;
                string directiveContent = directiveMatches[0].Groups[2].Value;

                var rule = ruleset.TryGetDirectiveRule(directiveName);
                if (rule != null)
                {
                    // Get the preceding and following directive string of the same line
                    ITextSnapshotLine line = snapshot.GetLineFromPosition(startIndex);
                    string precedingText = snapshot.GetText(line.Start, startIndex - line.Start);
                    string followingText = endIndex < line.End ? snapshot.GetText(endIndex + 1, line.End - endIndex - 1) : string.Empty;

                    // If we found a exactly-matched rule, just validate it
                    string message = rule.Validate(directiveContent, precedingText, followingText);
                    if (message != null)
                    {
                        ITrackingSpan squiggleSpan = overallDirective;
                        if (rule.SquiggleWholeLine)
                        {
                            squiggleSpan = snapshot.CreateTrackingSpan(line.Start, line.Length, SpanTrackingMode.EdgeInclusive);
                        }
                        errorTagger.CreateTagSpan(squiggleSpan, new ErrorTag(PredefinedErrorTypeNames.SyntaxError, message));
                    }

                    // If we miss the closing bracket, give out the prompt message
                    if (endIndex >= text.Length || text[endIndex] != ']')
                    {
                        errorTagger.CreateTagSpan(snapshot.CreateTrackingSpan(line.End, 0, SpanTrackingMode.EdgePositive), new ErrorTag(PredefinedErrorTypeNames.CompilerError, "Missing the closing bracket"));
                    }
                }
                else
                {
                    // Otherwise we may take a look at the suspects
                    var suspects = ruleset.GetSuspects(directive);
                    if (suspects.Count() > 0)
                    {
                        StringBuilder suspectPrompt = new StringBuilder();
                        suspectPrompt.AppendLine("Are you trying to enter one of the following directives?");
                        foreach (var suspect in suspects)
                        {
                            suspectPrompt.AppendLine(string.Format("    \u2022 {0} - {1}", suspect.ParentRule.DirectiveName, suspect.SuggestionMessage));
                        }
                        errorTagger.CreateTagSpan(overallDirective, new ErrorTag(PredefinedErrorTypeNames.Warning, suspectPrompt.ToString().TrimEnd()));
                    }
                }

                startIndex = endIndex;
            }
        }
예제 #15
0
        public override async void DoCommand(object sender, EventArgs args)
        {
            var            activeView    = CommonPackage.GetActiveTextView(_serviceProvider);
            var            project       = activeView.GetProjectAtCaret(_serviceProvider);
            var            configuration = activeView.GetInterpreterConfigurationAtCaret(_serviceProvider);
            ITextSelection selection     = activeView.Selection;
            ITextSnapshot  snapshot      = activeView.TextBuffer.CurrentSnapshot;
            var            workspace     = _serviceProvider.GetWorkspace();

            IVsInteractiveWindow repl;

            try {
                repl = ExecuteInReplCommand.EnsureReplWindow(_serviceProvider, configuration, project, workspace);
            } catch (MissingInterpreterException ex) {
                MessageBox.Show(ex.Message, Strings.ProductTitle);
                return;
            }

            string input;
            bool   focusRepl = false, alwaysSubmit = false;

            if (selection.StreamSelectionSpan.Length > 0)
            {
                // Easy, just send the selection to the interactive window.
                input = activeView.Selection.StreamSelectionSpan.GetText();
                if (!input.EndsWithOrdinal("\n") && !input.EndsWithOrdinal("\r"))
                {
                    input += activeView.Options.GetNewLineCharacter();
                }
                focusRepl = true;
            }
            else if (!activeView.Properties.ContainsProperty(_executedLastLine))
            {
                // No selection, and we haven't hit the end of the file in line-by-line mode.
                // Send the current line, and then move the caret to the next non-blank line.
                ITextSnapshotLine targetLine = snapshot.GetLineFromPosition(selection.Start.Position);
                var targetSpan = targetLine.Extent;

                // If the line is inside a code cell, expand the target span to
                // contain the entire cell.
                var cellStart = CodeCellAnalysis.FindStartOfCell(targetLine);
                if (cellStart != null)
                {
                    var cellEnd = CodeCellAnalysis.FindEndOfCell(cellStart, targetLine);
                    targetSpan   = new SnapshotSpan(cellStart.Start, cellEnd.End);
                    targetLine   = CodeCellAnalysis.FindEndOfCell(cellEnd, targetLine, includeWhitespace: true);
                    alwaysSubmit = true;
                }
                input = targetSpan.GetText();

                bool moved = false;
                while (targetLine.LineNumber < snapshot.LineCount - 1)
                {
                    targetLine = snapshot.GetLineFromLineNumber(targetLine.LineNumber + 1);
                    // skip over blank lines, unless it's the last line, in which case we want to land on it no matter what
                    if (!string.IsNullOrWhiteSpace(targetLine.GetText()) ||
                        targetLine.LineNumber == snapshot.LineCount - 1)
                    {
                        activeView.Caret.MoveTo(new SnapshotPoint(snapshot, targetLine.Start));
                        activeView.Caret.EnsureVisible();
                        moved = true;
                        break;
                    }
                }

                if (!moved)
                {
                    // There's no where for the caret to go, don't execute the line if
                    // we've already executed it.
                    activeView.Caret.PositionChanged        += Caret_PositionChanged;
                    activeView.Properties[_executedLastLine] = _executedLastLine;
                }
            }
            else if ((repl.InteractiveWindow.CurrentLanguageBuffer?.CurrentSnapshot.Length ?? 0) != 0)
            {
                // We reached the end of the file but have some text buffered.  Execute it now.
                input = activeView.Options.GetNewLineCharacter();
            }
            else
            {
                // We've hit the end of the current text view and executed everything
                input = null;
            }

            if (input != null)
            {
                repl.Show(focusRepl);

                var inputs = repl.InteractiveWindow.Properties.GetOrCreateSingletonProperty(
                    () => new InteractiveInputs(repl.InteractiveWindow, _serviceProvider, alwaysSubmit)
                    );

                await inputs.EnqueueAsync(input);
            }

            // Take focus back if REPL window has stolen it and we're in line-by-line mode.
            if (!focusRepl && !activeView.HasAggregateFocus)
            {
                var adapterService = _serviceProvider.GetComponentModel().GetService <VisualStudio.Editor.IVsEditorAdaptersFactoryService>();
                var tv             = adapterService.GetViewAdapter(activeView);
                tv.SendExplicitFocus();
            }
        }
예제 #16
0
        public SourcePos IndexToLine(int index)
        {
            var line = _ss.GetLineFromPosition(index);

            return(new SourcePos("", line.LineNumber + 1, index - line.Start.Position + 1));
        }
예제 #17
0
 public static string GetLineTextFromPosition(int position, ITextSnapshot snapshot)
 {
     return snapshot.GetLineFromPosition(position - 1).GetText();
 }
예제 #18
0
		static int GetLineNumber(ITextSnapshot snapshot, int position) {
			Debug.Assert((uint)position <= (uint)snapshot.Length);
			if ((uint)position > (uint)snapshot.Length)
				return int.MaxValue;
			return snapshot.GetLineFromPosition(position).LineNumber;
		}
예제 #19
0
        // This function could use some refinement as it will return some false positives,
        // but hopefully they are rare enough to not cause any major issues. I would much
        // rather return a couple false positives than false negatives.
        private static int GetTypeScriptFunctionLine(ITextSnapshot capture, int lineNumber, bool isAboveFunction, string lineText)
        {
            if (!isAboveFunction)
            {
                while (!lineText.Contains('(') && !typeScriptFnRegex.IsMatch(lineText))
                {
                    lineNumber--;
                    lineText = capture.GetLineFromLineNumber(lineNumber).Extent.GetText();
                    //There is no function declaration associated with the curly brace.
                    if (lineText.Contains('{')) return -1;
                }

                return lineNumber;
            }
            else
            {
                if (typeScriptFnRegex.IsMatch(lineText)) { return lineNumber; }
                if (keywordWithParen.IsMatch(lineText)) { return -1; }

                var line = capture.GetLineFromLineNumber(lineNumber);
                var parenOpen = lineText.IndexOf("(");
                var parenBlock = GetCompleteParenBlock(capture, lineNumber, line.Start + lineText.IndexOf("("));
                if (parenBlock == null) { return -1; }

                var endParamsPosition = line.Start.Position + parenOpen + parenBlock.Length;

                var lineEnd = capture.GetLineFromPosition(endParamsPosition);
                var startTextAfterParams = endParamsPosition + 1;
                var textAfterParams = capture.GetText(startTextAfterParams, lineEnd.End.Position - startTextAfterParams);
                var lineCounter = lineEnd.LineNumber;

                while (!lineText.Contains('{') && lineCounter < capture.LineCount)
                {
                    lineCounter++;
                    lineText = capture.GetLineFromLineNumber(lineCounter).Extent.GetText();
                    textAfterParams += lineText;
                }

                if (!lineText.Contains('{'))
                {
                    return -1;
                }

                textAfterParams = textAfterParams.Substring(0, textAfterParams.LastIndexOf('{'));
                // If there is no text between the ) and {, then we know it is a valid function header.
                if (String.IsNullOrWhiteSpace(textAfterParams)) { return lineNumber; }

                // If there is text between ) {, check if it is a return type declaration.
                if (textAfterParams.Trim().StartsWith(":")) { return lineNumber; }

                return -1;
            }
        }
예제 #20
0
        /// <summary>
        /// Returns the applicable span at the provided position.
        /// </summary>
        /// <returns>A tracking span, or null if there is no token at the
        /// provided position.</returns>
        public static ITrackingSpan GetApplicableSpan(this ITextSnapshot snapshot, int position)
        {
            //var classifier = snapshot.TextBuffer.GetPythonClassifier();
            IClassifier classifier = null;
            var         line       = snapshot.GetLineFromPosition(position);

            if (classifier == null || line == null)
            {
                return(null);
            }

            var spanLength = position - line.Start.Position;

            // Increase position by one to include 'fob' in: "abc.|fob"
            if (spanLength < line.Length)
            {
                spanLength += 1;
            }

            var classifications = classifier.GetClassificationSpans(new SnapshotSpan(line.Start, spanLength));

            // Handle "|"
            if (classifications == null || classifications.Count == 0)
            {
                return(null);
            }

            var lastToken = classifications[classifications.Count - 1];

            // Handle "fob |"
            if (lastToken == null || position > lastToken.Span.End)
            {
                return(null);
            }

            if (position > lastToken.Span.Start)
            {
                if (lastToken.CanComplete())
                {
                    // Handle "fo|o"
                    return(snapshot.CreateTrackingSpan(lastToken.Span, SpanTrackingMode.EdgeInclusive));
                }
                else
                {
                    // Handle "<|="
                    return(null);
                }
            }

            var secondLastToken = classifications.Count >= 2 ? classifications[classifications.Count - 2] : null;

            if (lastToken.Span.Start == position && lastToken.CanComplete() &&
                (secondLastToken == null ||             // Handle "|fob"
                 position > secondLastToken.Span.End || // Handle "if |fob"
                 !secondLastToken.CanComplete()))
            {                                           // Handle "abc.|fob"
                return(snapshot.CreateTrackingSpan(lastToken.Span, SpanTrackingMode.EdgeInclusive));
            }

            // Handle "abc|."
            // ("ab|c." would have been treated as "ab|c")
            if (secondLastToken != null && secondLastToken.Span.End == position && secondLastToken.CanComplete())
            {
                return(snapshot.CreateTrackingSpan(secondLastToken.Span, SpanTrackingMode.EdgeInclusive));
            }

            return(null);
        }
예제 #21
0
 public IEditorLine GetLineFromPosition(int position) => new EditorLine(_snapshot.GetLineFromPosition(position));
        internal void OnVisualBufferChanged(object sender, TextContentChangedEventArgs e)
        {
            if (textSnapshot != null)
            {
                foreach (ITextChange textChange in e.Changes)
                {
                    Span textChangeCurrentSpan;
                    if (e.Before == textSnapshot)
                    {
                        textChangeCurrentSpan = textChange.OldSpan;
                    }
                    else if (e.After == textSnapshot)
                    {
                        textChangeCurrentSpan = textChange.NewSpan;
                    }
                    else
                    {
                        ITrackingSpan textChangeOldSpan = e.Before.CreateTrackingSpan(textChange.OldSpan, SpanTrackingMode.EdgeInclusive);
                        textChangeCurrentSpan = textChangeOldSpan.GetSpan(textSnapshot);
                    }

                    var startLine = textSnapshot.GetLineFromPosition(textChangeCurrentSpan.Start);
                    var endLine   = startLine;
                    if (startLine.EndIncludingLineBreak.Position < textChangeCurrentSpan.End)
                    {
                        endLine = textSnapshot.GetLineFromPosition(textChangeCurrentSpan.End);
                    }

                    for (int i = startLine.LineNumber; i <= endLine.LineNumber; i++)
                    {
                        modifiedLinesCache.Add(i);
                    }
                }
            }

            // Recreate MdTextViewLine for the current snapshot for all lines except those
            // modified as those will get recreated during render
            foreach (MdTextViewLine line in this)
            {
                int lineNumber = line.LineNumber;
                if (!modifiedLinesCache.Contains(lineNumber - 1))
                {
                    reusedLinesCache.Add(line);
                }
            }

            this.Clear();

            var newSnapshot = e.After;

            foreach (MdTextViewLine line in reusedLinesCache)
            {
                var snapshotLine    = textSnapshot.GetLineFromLineNumber(line.LineNumber - 1);
                var lineStart       = textSnapshot.CreateTrackingPoint(snapshotLine.Start, PointTrackingMode.Negative);
                var newLineStart    = lineStart.GetPosition(newSnapshot);
                var newSnapshotLine = newSnapshot.GetLineFromPosition(newLineStart);
                int lineNumber      = newSnapshotLine.LineNumber + 1;
                var documentLine    = textEditor.Document.GetLine(lineNumber);

                var newLine = new MdTextViewLine(this, textEditor, documentLine, lineNumber, textEditor.TextViewMargin.GetLayout(documentLine));
                Add(newLine);
            }

            modifiedLinesCache.Clear();
            reusedLinesCache.Clear();

            textSnapshot = newSnapshot;

            // we need this to synchronize MultiSelectionBroker to the new snapshot
            this.textEditor.TextArea.RaiseLayoutChanged();
        }
예제 #23
0
        private static SnapshotPoint Scan(string txt, SnapshotPoint start, List <TokenRegion> newRegions, ITextSnapshot newSnapshot)
        {
            int           longCommentDepth     = 0;
            SnapshotPoint commentStart         = new SnapshotPoint();
            SnapshotPoint commentEndAsWeKnowIt = new SnapshotPoint(); // used only when longCommentDepth != 0
            int           N    = txt.Length;
            bool          done = false;

            while (!done)
            {
                N = txt.Length; // length of the current buffer
                int cur = 0;    // offset into the current buffer
                if (longCommentDepth != 0)
                {
                    ScanForEndOfComment(txt, ref longCommentDepth, ref cur);
                    if (longCommentDepth == 0)
                    {
                        // we just finished parsing a long comment
                        newRegions.Add(new TokenRegion(commentStart, new SnapshotPoint(newSnapshot, start + cur), DafnyTokenKind.Comment));
                    }
                    else
                    {
                        // we're still parsing the long comment
                        Contract.Assert(cur == txt.Length);
                        commentEndAsWeKnowIt = new SnapshotPoint(newSnapshot, start + cur);
                        goto OUTER_CONTINUE;
                    }
                }
                // repeatedly get the remaining tokens from this buffer
                int end; // offset into the current buffer
                for (; ; cur = end)
                {
                    // advance to the first character of a keyword or token
                    DafnyTokenKind ty = DafnyTokenKind.Keyword;
                    for (; ; cur++)
                    {
                        if (N <= cur)
                        {
                            // we've looked at everything in this buffer
                            goto OUTER_CONTINUE;
                        }
                        char ch = txt[cur];
                        if ('a' <= ch && ch <= 'z')
                        {
                            break;
                        }
                        if ('A' <= ch && ch <= 'Z')
                        {
                            break;
                        }
                        if ('0' <= ch && ch <= '9')
                        {
                            ty = DafnyTokenKind.Number; break;
                        }
                        if (ch == '_' || ch == '?' || ch == '\\')
                        {
                            break;                            // parts of identifiers
                        }
                        if (ch == '\'')
                        {
                            ty = DafnyTokenKind.Char; break;
                        }                                         // part character literal or identifier
                        if (ch == '"')
                        {
                            ty = DafnyTokenKind.String; break;
                        }
                        if (ch == '/')
                        {
                            ty = DafnyTokenKind.Comment; break;
                        }
                    }

                    // advance to the end of the token
                    end = cur + 1; // offset into the current buffer
                    // first investigate if this is really a character literal
                    if (ty == DafnyTokenKind.Char)
                    {
                        ty = DafnyTokenKind.Keyword;
                        // we've seen a starting single-quote already
                        if (cur + 3 <= N && txt[cur + 2] == '\'')
                        {
                            // Look for a simple character literal, like 'a'
                            char cx = txt[cur + 1];
                            if (cx != '\'' && cx != '\\' && cx != '\n' && cx != '\r')
                            {
                                if (cur + 3 == N)
                                {
                                    ty  = DafnyTokenKind.Char;
                                    end = cur + 3;
                                }
                                else
                                {
                                    // check if the next character is an identifier character, because then what we've seen was
                                    // really just part of that identifier
                                    cx = txt[cur + 3];
                                    if ('a' <= cx && cx <= 'z')
                                    {
                                    }
                                    else if ('A' <= cx && cx <= 'Z')
                                    {
                                    }
                                    else if ('0' <= cx && cx <= '9')
                                    {
                                    }
                                    else if (cx == '\'' || cx == '_' || cx == '?' || cx == '\\')
                                    {
                                    }
                                    else
                                    {
                                        ty  = DafnyTokenKind.Char;
                                        end = cur + 3;
                                    }
                                }
                            }
                        }
                        else if (cur + 4 <= N && txt[cur + 1] == '\\' && txt[cur + 3] == '\'')
                        {
                            // Look for an escaped character literal, like '\n' (note, a \ cannot be part of an identifier)
                            char cx = txt[cur + 2];
                            if (cx == '\'' || cx == '\"' || cx == '\\' || cx == '0' || cx == 'n' || cx == 'r' || cx == 't')
                            {
                                ty  = DafnyTokenKind.Char;
                                end = cur + 4;
                            }
                        }
                        else if (cur + 8 <= N && txt[cur + 1] == '\\' && txt[cur + 2] == 'u' && txt[cur + 7] == '\'')
                        {
                            // Look for a unicode character literal, like '\u40fE' (note, a \ cannot be part of an identifier)
                            var numberOfHexDigits = 0;
                            for (int i = 3; i < 7; i++)
                            {
                                char cx = txt[cur + i];
                                if (('0' <= cx && cx <= '9') || ('a' <= cx && cx <= 'f') || ('A' <= cx && cx <= 'F'))
                                {
                                    numberOfHexDigits++;
                                }
                            }
                            if (numberOfHexDigits == 4)
                            {
                                ty  = DafnyTokenKind.Char;
                                end = cur + 8;
                            }
                        }
                    }

                    if (ty == DafnyTokenKind.Number)
                    {
                        // scan the rest of this number
                        for (; end < N; end++)
                        {
                            char ch = txt[end];
                            if ('0' <= ch && ch <= '9')
                            {
                            }
                            else
                            {
                                break;
                            }
                        }
                    }
                    else if (ty == DafnyTokenKind.Char)
                    {
                        // we already did the work above
                    }
                    else if (ty == DafnyTokenKind.String)
                    {
                        // scan the rest of this string, but not past the end-of-buffer
                        for (; end < N; end++)
                        {
                            char ch = txt[end];
                            if (ch == '"')
                            {
                                end++; break;
                            }
                            else if (ch == '\\')
                            {
                                // escape sequence
                                end++;
                                if (end == N)
                                {
                                    break;
                                }
                                ch = txt[end];
                                if (ch == 'u')
                                {
                                    end += 4;
                                    if (N <= end)
                                    {
                                        end = N; break;
                                    }
                                }
                            }
                        }
                    }
                    else if (ty == DafnyTokenKind.Comment)
                    {
                        if (end == N)
                        {
                            continue; // this was not the start of a comment; it was just a single "/" and we don't care to color it
                        }
                        char ch = txt[end];
                        if (ch == '/')
                        {
                            // a short comment, to the end of the line.
                            end = newSnapshot.GetLineFromPosition(start + end).End.Position - start;
                        }
                        else if (ch == '*')
                        {
                            // a long comment; find the matching "*/"
                            end++;
                            commentStart = new SnapshotPoint(newSnapshot, start + cur);
                            Contract.Assert(longCommentDepth == 0);
                            longCommentDepth = 1;
                            ScanForEndOfComment(txt, ref longCommentDepth, ref end);
                            if (longCommentDepth == 0)
                            {
                                // we finished scanning a long comment, and "end" is set to right after it
                                newRegions.Add(new TokenRegion(commentStart, new SnapshotPoint(newSnapshot, start + end), DafnyTokenKind.Comment));
                            }
                            else
                            {
                                commentEndAsWeKnowIt = new SnapshotPoint(newSnapshot, start + end);
                            }
                            continue;
                        }
                        else
                        {
                            // not a comment; it was just a single "/" and we don't care to color it
                            continue;
                        }
                    }
                    else
                    {
                        int trailingDigits = 0;
                        for (; end < N; end++)
                        {
                            char ch = txt[end];
                            if ('a' <= ch && ch <= 'z')
                            {
                                trailingDigits = 0;
                            }
                            else if ('A' <= ch && ch <= 'Z')
                            {
                                trailingDigits = 0;
                            }
                            else if ('0' <= ch && ch <= '9')
                            {
                                trailingDigits++;
                            }
                            else if (ch == '\'' || ch == '_' || ch == '?' || ch == '\\')
                            {
                                trailingDigits = 0;
                            }
                            else
                            {
                                break;
                            }
                        }
                        // we have a keyword or an identifier
                        string s = txt.Substring(cur, end - cur);
                        if (0 < trailingDigits && s.Length == 5 + trailingDigits && s.StartsWith("array") && s[5] != '0' && (trailingDigits != 1 || s[5] != '1'))
                        {
                            // this is a keyword for a built-in type (array2, array3, ...)
                            ty = DafnyTokenKind.BuiltInType;
                        }
                        else if (0 < trailingDigits && s.Length == 2 + trailingDigits && s.StartsWith("bv") && (s[2] != '0' || trailingDigits == 1))
                        {
                            // this is a keyword for a built-in type (bv0, bv1, ...)
                            ty = DafnyTokenKind.BuiltInType;
                        }
                        else
                        {
                            switch (s)
                            {
                                #region keywords
                            case "abstract":
                            case "allocated":
                            case "as":
                            case "assert":
                            case "assume":
                            case "break":
                            case "by":
                            case "calc":
                            case "case":
                            case "class":
                            case "const":
                            case "trait":
                            case "extends":
                            case "codatatype":
                            case "colemma":
                            case "constructor":
                            case "copredicate":
                            case "datatype":
                            case "else":
                            case "exists":
                            case "export":
                            case "false":
                            case "forall":
                            case "fresh":
                            case "function":
                            case "ghost":
                            case "if":
                            case "import":
                            case "in":
                            case "include":
                            case "inductive":
                            case "iterator":
                            case "label":
                            case "lemma":
                            case "match":
                            case "method":
                            case "modify":
                            case "module":
                            case "new":
                            case "newtype":
                            case "null":
                            case "old":
                            case "opened":
                            case "predicate":
                            case "print":
                            case "protected":
                            case "refines":
                            case "return":
                            case "returns":
                            case "static":
                            case "then":
                            case "this":
                            case "true":
                            case "twostate":
                            case "type":
                            case "unchanged":
                            case "var":
                            case "where":
                            case "while":
                            case "yield":
                            case "yields":
                                #endregion
                                break;

                                #region keywords in specification clauses
                            case "decreases":
                            case "ensures":
                            case "invariant":
                            case "modifies":
                            case "provides":
                            case "reads":
                            case "requires":
                            case "reveals":
                            case "witness":
                                // "yields" plays a dual role
                                #endregion
                                ty = DafnyTokenKind.SpecificationClause;
                                break;

                                #region keywords for built-in types
                            case "array":
                            case "bool":
                            case "char":
                            case "imap":
                            case "int":
                            case "iset":
                            case "map":
                            case "multiset":
                            case "nat":
                            case "object":
                            case "real":
                            case "seq":
                            case "set":
                            case "string":
                                #endregion
                                ty = DafnyTokenKind.BuiltInType;
                                break;

                            default:
                                continue; // it was an identifier, so we don't color it
                            }
                        }
                    }
                    newRegions.Add(new TokenRegion(new SnapshotPoint(newSnapshot, start + cur), new SnapshotPoint(newSnapshot, start + end), ty));
                }
OUTER_CONTINUE:
                done = true;
                if (longCommentDepth != 0)
                {
                    // we need to look into the next line
                    ITextSnapshotLine currLine = newSnapshot.GetLineFromPosition(start + N);
                    if ((currLine.LineNumber + 1) < newSnapshot.LineCount)
                    {
                        ITextSnapshotLine nextLine = newSnapshot.GetLineFromLineNumber(currLine.LineNumber + 1);
                        txt   = nextLine.GetText();
                        start = nextLine.Start;
                        // we are done scanning the current buffer, but not the whole file yet.
                        // we need to continue to find the enclosing "*/", or until the end of the file.
                        done = false;
                    }
                    else
                    {
                        // This was a malformed comment, running to the end of the buffer.  Above, we let "commentEndAsWeKnowIt" be the end of the
                        // last line, so we can use it here.
                        newRegions.Add(new TokenRegion(commentStart, commentEndAsWeKnowIt, DafnyTokenKind.Comment));
                    }
                }
            }
            return(new SnapshotPoint(newSnapshot, start + N));
        }
예제 #24
0
        /// <summary>
        /// Find all of the tag regions in the document (snapshot) and notify
        /// listeners of any that changed
        /// </summary>
        void ReparseFile(object sender, TextContentChangedEventArgs args)
        {
            ITextSnapshot snapshot = _buffer.CurrentSnapshot;

            if (snapshot == _snapshot)
            {
                return; // we've already computed the regions for this snapshot
            }
            NormalizedSnapshotSpanCollection difference = new NormalizedSnapshotSpanCollection();
            ScanResult result;

            if (_buffer.Properties.TryGetProperty(bufferTokenTaggerKey, out result) &&
                (result._oldSnapshot == _snapshot) &&
                (result._newSnapshot == snapshot))
            {
                difference = result._difference;
                // save the new baseline
                _regions  = result._regions;
                _snapshot = snapshot;
            }
            else
            {
                List <TokenRegion>  regions          = new List <TokenRegion>();
                List <SnapshotSpan> rescannedRegions = new List <SnapshotSpan>();

                // loop through the changes and check for changes in comments first. If
                // the change is in a comments, we need to rescan starting from the
                // beginning of the comments (which in multi-lined comments, it can
                // be a line that the changes are not on), otherwise, we can just rescan the lines
                // that the changes are on.
                bool          done;
                SnapshotPoint start, end;
                for (int i = 0; i < args.Changes.Count; i++)
                {
                    done = false;
                    // get the span of the lines that the change is on.
                    int cStart = args.Changes[i].NewSpan.Start;
                    int cEnd   = args.Changes[i].NewSpan.End;
                    start = snapshot.GetLineFromPosition(cStart).Start;
                    end   = snapshot.GetLineFromPosition(cEnd).End;
                    SnapshotSpan newSpan = new SnapshotSpan(start, end);
                    foreach (TokenRegion r in _regions)
                    {
                        if (r.Kind == DafnyTokenKind.Comment)
                        {
                            // if the change is in the comments, we want to start scanning from the
                            // the beginning of the comments instead.
                            SnapshotSpan span = r.Span.TranslateTo(snapshot, SpanTrackingMode.EdgeExclusive);
                            if (span.IntersectsWith(newSpan))
                            {
                                start = span.Start.Position < newSpan.Start.Position ? span.Start : newSpan.Start;
                                end   = span.End.Position > newSpan.End.Position ? span.End : newSpan.End;
                                end   = Scan(snapshot.GetText(new SnapshotSpan(start, end)), start, regions, snapshot);
                                // record the regions that we rescanned.
                                rescannedRegions.Add(new SnapshotSpan(start, end));
                                done = true;
                                break;
                            }
                        }
                    }
                    if (!done)
                    {
                        // scan the lines that the change is on to generate the new regions.
                        end = Scan(snapshot.GetText(new SnapshotSpan(start, end)), start, regions, snapshot);
                        // record the span that we rescanned.
                        rescannedRegions.Add(new SnapshotSpan(start, end));
                    }
                }

                List <SnapshotSpan> oldSpans = new List <SnapshotSpan>();
                List <SnapshotSpan> newSpans = new List <SnapshotSpan>();
                // record the newly created spans.
                foreach (TokenRegion r in regions)
                {
                    newSpans.Add(r.Span);
                }
                // loop through the old scan results and remove the ones that
                // are in the regions that are rescanned.
                foreach (TokenRegion r in _regions)
                {
                    SnapshotSpan origSpan = r.Span.TranslateTo(snapshot, SpanTrackingMode.EdgeExclusive);
                    bool         obsolete = false;
                    foreach (SnapshotSpan span in rescannedRegions)
                    {
                        if (origSpan.IntersectsWith(span))
                        {
                            oldSpans.Add(span);
                            obsolete = true;
                            break;
                        }
                    }
                    if (!obsolete)
                    {
                        TokenRegion region = new TokenRegion(origSpan.Start, origSpan.End, r.Kind);
                        regions.Add(region);
                    }
                }

                NormalizedSnapshotSpanCollection oldSpanCollection = new NormalizedSnapshotSpanCollection(oldSpans);
                NormalizedSnapshotSpanCollection newSpanCollection = new NormalizedSnapshotSpanCollection(newSpans);
                difference = SymmetricDifference(oldSpanCollection, newSpanCollection);

                // save the scan result
                _buffer.Properties[bufferTokenTaggerKey] = new ScanResult(_snapshot, snapshot, regions, difference);
                // save the new baseline
                _snapshot = snapshot;
                _regions  = regions;
            }

            var chng = TagsChanged;

            if (chng != null)
            {
                foreach (var span in difference)
                {
                    chng(this, new SnapshotSpanEventArgs(span));
                }
            }
        }
예제 #25
0
 public static string GetLineTextFromPosition(int position, ITextSnapshot snapshot)
 {
     return(snapshot.GetLineFromPosition(position - 1).GetText());
 }
예제 #26
0
        private static int GetFirstArgumentIndent(ITextSnapshot snapshot, IFunction fc)
        {
            var line = snapshot.GetLineFromPosition(fc.OpenBrace.End);

            return(fc.OpenBrace.End - line.Start);
        }
예제 #27
0
        public static int GetLineColumnFromPosition(this ITextSnapshot snapshot, int caretPosition)
        {
            var snapshotLine = snapshot.GetLineFromPosition(caretPosition);

            return(caretPosition - snapshotLine.Start.Position);
        }
        /// <summary>
        /// Returns the applicable span at the provided position.
        /// </summary>
        /// <returns>A tracking span, or null if there is no token at the
        /// provided position.</returns>
        internal static ITrackingSpan GetApplicableSpan(ITextSnapshot snapshot, int position) {
            var classifier = snapshot.TextBuffer.GetNodejsClassifier();
            var line = snapshot.GetLineFromPosition(position);
            if (classifier == null || line == null) {
                return null;
            }

            var spanLength = position - line.Start.Position;
            // Increase position by one to include 'fob' in: "abc.|fob"
            if (spanLength < line.Length) {
                spanLength += 1;
            }

            var classifications = classifier.GetClassificationSpans(new SnapshotSpan(line.Start, spanLength));
            // Handle "|"
            if (classifications == null || classifications.Count == 0) {
                return null;
            }

            var lastToken = classifications[classifications.Count - 1];
            // Handle "fob |"
            if (lastToken == null || position > lastToken.Span.End) {
                return null;
            }

            if (position > lastToken.Span.Start) {
                if (lastToken.CanComplete()) {
                    // Handle "fo|o"
                    return snapshot.CreateTrackingSpan(lastToken.Span, SpanTrackingMode.EdgeInclusive);
                } else {
                    // Handle "<|="
                    return null;
                }
            }

            var secondLastToken = classifications.Count >= 2 ? classifications[classifications.Count - 2] : null;
            if (lastToken.Span.Start == position && lastToken.CanComplete() &&
                (secondLastToken == null ||             // Handle "|fob"
                 position > secondLastToken.Span.End || // Handle "if |fob"
                 !secondLastToken.CanComplete())) {     // Handle "abc.|fob"
                return snapshot.CreateTrackingSpan(lastToken.Span, SpanTrackingMode.EdgeInclusive);
            }

            // Handle "abc|."
            // ("ab|c." would have been treated as "ab|c")
            if (secondLastToken != null && secondLastToken.Span.End == position && secondLastToken.CanComplete()) {
                return snapshot.CreateTrackingSpan(secondLastToken.Span, SpanTrackingMode.EdgeInclusive);
            }

            return null;
        }
예제 #29
0
 private void GetTrackingSpan(ITextSnapshot snapshot, int triggerPoint)
 {
     ITextSnapshotLine line = snapshot.GetLineFromPosition(triggerPoint);
     string lineString = line.GetText();
     var stopChars = new char[] {' ', '\t', '{', '}', '.', '"', ':'};
     int start = lineString.Substring(0, triggerPoint - line.Start.Position).LastIndexOfAny(stopChars) + line.Start.Position + 1;
     int length = lineString.Substring(triggerPoint - line.Start.Position).IndexOfAny(stopChars) + triggerPoint - start;
     _trackingSpan = snapshot.CreateTrackingSpan(start, length < 0 ? 0 : length, SpanTrackingMode.EdgeInclusive);
 }
예제 #30
0
        private bool TryAsSwitchSection(SyntaxNode childnode, ITextSnapshot snapshot, ref BlockType type, ref int startPosition, ref int endPosition)
        {
            var child = childnode as SwitchSectionSyntax;
            if (child != null)
            {
                type = BlockType.Conditional;

                startPosition = child.Labels.FullSpan.End;
                ITextSnapshotLine line = snapshot.GetLineFromPosition(startPosition);
                if ((startPosition == line.Start.Position) && (line.LineNumber > 0))
                {
                    startPosition = snapshot.GetLineFromLineNumber(line.LineNumber - 1).End;
                }

                endPosition = child.Span.End;

                return true;
            }

            return false;
        }
예제 #31
0
 private static int GetFirstArgumentIndent(ITextSnapshot snapshot, IFunction fc) {
     var line = snapshot.GetLineFromPosition(fc.OpenBrace.End);
     return fc.OpenBrace.End - line.Start;
 }
        private void AddAllGuids(ITextSnapshot snapshot, List<Intel.Completion> list)
        {
            var guidSpans = _classifier.GetClassificationSpans(new SnapshotSpan(snapshot, 0, snapshot.Length)).Where(g => g.ClassificationType.IsOfType(PkgdefClassificationTypes.Guid));
            Dictionary<string, Tuple<string, ImageSource>> dic = new Dictionary<string, Tuple<string, ImageSource>>();
            var unknown = _glyphService.GetGlyph(StandardGlyphGroup.GlyphGroupModule, StandardGlyphItem.TotalGlyphItems);

            foreach (var cspan in guidSpans)
            {
                string guid = cspan.Span.GetText();
                ITextSnapshotLine line = snapshot.GetLineFromPosition(cspan.Span.Start.Position);
                string lineText = line.GetText();
                Guid check = Guid.Empty;

                if (!dic.ContainsKey(guid) && Guid.TryParse(guid, out check))
                {
                    dic[guid] = null;
                }

                if (check != Guid.Empty && (!dic.ContainsKey(guid) || dic[guid] == null || !dic[guid].Item1.Contains("\\")))
                {
                    string before = lineText.Substring(0, lineText.IndexOf(guid)).Trim();
                    string text = before;
                    var glyph = unknown;

                    Match entryKey = Regex.Match(text, "\"(?<key>[^\"]+)\"");
                    if (entryKey.Success)
                    {
                        text = entryKey.Value + "=";
                    }

                    string name;
                    glyph = GetGlyph(lineText, glyph, out name);

                    if (glyph == null || text == "\"")
                        continue;

                    if (!string.IsNullOrEmpty(name))
                        name += Environment.NewLine;

                    dic[guid] = Tuple.Create(name + text + Environment.NewLine + "Line: " + line.LineNumber, glyph);
                }
            }

            List<Completion> entries = new List<Completion>();

            foreach (string guid in dic.Keys)
            {
                if (dic[guid] != null)
                    entries.Add(CreateCompletion(guid, guid, dic[guid].Item2, dic[guid].Item1));
            }

            list.AddRange(entries.OrderByDescending(e => e.Description));
        }
예제 #33
0
        // This function could use some refinement as it will return some false positives,
        // but hopefully they are rare enough to not cause any major issues. I would much
        // rather return a couple false positives than false negatives.
        private static int GetTypeScriptFunctionLine(ITextSnapshot capture, int lineNumber, bool isAboveFunction, string lineText)
        {
            if (!isAboveFunction)
            {
                while (!lineText.Contains('(') && !typeScriptFnRegex.IsMatch(lineText))
                {
                    lineNumber--;
                    lineText = capture.GetLineFromLineNumber(lineNumber).Extent.GetText();
                    //There is no function declaration associated with the curly brace.
                    if (lineText.Contains('{'))
                    {
                        return(-1);
                    }
                }

                return(lineNumber);
            }
            else
            {
                if (typeScriptFnRegex.IsMatch(lineText))
                {
                    return(lineNumber);
                }
                if (keywordWithParen.IsMatch(lineText))
                {
                    return(-1);
                }

                var line       = capture.GetLineFromLineNumber(lineNumber);
                var parenOpen  = lineText.IndexOf("(");
                var parenBlock = GetCompleteParenBlock(capture, lineNumber, line.Start + lineText.IndexOf("("));
                if (parenBlock == null)
                {
                    return(-1);
                }

                var endParamsPosition = line.Start.Position + parenOpen + parenBlock.Length;

                var lineEnd = capture.GetLineFromPosition(endParamsPosition);
                var startTextAfterParams = endParamsPosition + 1;
                var textAfterParams      = capture.GetText(startTextAfterParams, lineEnd.End.Position - startTextAfterParams);
                var lineCounter          = lineEnd.LineNumber;

                while (!lineText.Contains('{') && lineCounter < capture.LineCount)
                {
                    lineCounter++;
                    lineText         = capture.GetLineFromLineNumber(lineCounter).Extent.GetText();
                    textAfterParams += lineText;
                }

                if (!lineText.Contains('{'))
                {
                    return(-1);
                }

                textAfterParams = textAfterParams.Substring(0, textAfterParams.LastIndexOf('{'));
                // If there is no text between the ) and {, then we know it is a valid function header.
                if (String.IsNullOrWhiteSpace(textAfterParams))
                {
                    return(lineNumber);
                }

                // If there is text between ) {, check if it is a return type declaration.
                if (textAfterParams.Trim().StartsWith(":"))
                {
                    return(lineNumber);
                }

                return(-1);
            }
        }