public override bool InsertIndent()
        {
            int    tabSize        = _editorOptions.GetTabSize();
            int    spacesToInsert = tabSize - (Column % tabSize);
            string indentToInsert = _editorOptions.IsConvertTabsToSpacesEnabled() ? new string(' ', spacesToInsert) : "\t";

            return(InsertText(indentToInsert));
        }
Пример #2
0
        private string GetIndentationString(IEditorOptions options, int indentationLength)
        {
            if (indentationLength <= 0)
            {
                return(string.Empty);
            }
            StringBuilder builder = new StringBuilder();
            int           num     = 0;
            int           num2    = indentationLength;

            if (!options.IsConvertTabsToSpacesEnabled())
            {
                int tabSize = options.GetTabSize();
                num   = indentationLength / tabSize;
                num2 -= num * tabSize;
            }
            for (int i = 0; i < num; i++)
            {
                builder.Append('\t');
            }
            for (int j = 0; j < num2; j++)
            {
                builder.Append(' ');
            }
            return(builder.ToString());
        }
Пример #3
0
        public void SubjectBuffersConnected(IWpfTextView textView, ConnectionReason reason, Collection <ITextBuffer> subjectBuffers)
        {
            ITextDocument textDocument;

            if (_textDocumentFactoryService.TryGetTextDocument(textView.TextBuffer, out textDocument))
            {
                textDocument.FileActionOccurred += delegate(object sender, TextDocumentFileActionEventArgs e)
                {
                    if (e.FileActionType != FileActionTypes.ContentSavedToDisk)
                    {
                        return;
                    }

                    ITextDocument document = (ITextDocument)sender;
                    ITextBuffer   buffer   = document.TextBuffer;
                    string        filePath = e.FilePath;

                    FixBufferOnSave(buffer, textView.FormattedLineSource.TabSize, filePath);
                };
            }
            foreach (var buffer in subjectBuffers)
            {
                IEditorOptions options = textView.Properties.GetProperty <IEditorOptions>(typeof(IEditorOptions));
                int            tabSize = options.GetTabSize();
                FixBufferOnLoad(buffer, tabSize);
            }

            if (textDocument != null)
            {
                textDocument.UpdateDirtyState(false, DateTime.Now);
            }
        }
        //FIXME: make this smarter, it's very simple right now
        public virtual int?GetDesiredIndentation(ITextSnapshotLine line)
        {
            if (!XmlBackgroundParser.TryGetParser(textView.TextBuffer, out var parser))
            {
                return(null);
            }

            var indentSize = options.GetIndentSize();
            var tabSize    = options.GetTabSize();

            //calculate the delta between the previous line's expected and actual indent
            int?previousIndentDelta = null;

            // find a preceding non-empty line so we don't get confused by blank lines with virtual indents
            var previousLine = GetPreviousNonEmptyLine(line);

            if (previousLine != null)
            {
                var previousExpectedIndent = GetLineExpectedIndent(previousLine, parser, indentSize);
                var previousActualIndent   = GetLineActualIndent(previousLine, tabSize);
                previousIndentDelta = previousActualIndent - previousExpectedIndent;
            }

            var indent = GetLineExpectedIndent(line, parser, indentSize);

            // if the previous non-blank line was in the same state and had a different indent than
            // expected, the user has manually corrected it, so re-apply the same delta to this line.
            if (previousIndentDelta.HasValue)
            {
                indent = Math.Max(0, indent + previousIndentDelta.Value);
            }

            return(indent);
        }
 /// <summary> Adds edits to comment out each non-blank line, at the given column. </summary>
 void ApplyCommentToNonBlankLines(IEditorOptions options, ITextEdit textEdit, Tuple <ITextSnapshotLine, ITextSnapshotLine> firstAndLastLine, int indentToColumn)
 {
     for (int lineNumber = firstAndLastLine.Item1.LineNumber; lineNumber <= firstAndLastLine.Item2.LineNumber; ++lineNumber)
     {
         var line = firstAndLastLine.Item1.Snapshot.GetLineFromLineNumber(lineNumber);
         if (!line.IsEmptyOrWhitespace())
         {
             var offset = line.GetOffsetForColumn(indentToColumn, options.GetTabSize());
             textEdit.Insert(line.Start + offset, SyntaxFacts.SingleLineComment);
         }
     }
 }
        private int GetOffsetFromIndentation(int indentation, IEditorOptions option)
        {
            int numberOfTabs   = 0;
            int numberOfSpaces = Math.Max(0, indentation);

            if (!option.IsConvertTabsToSpacesEnabled())
            {
                var tabSize = option.GetTabSize();

                numberOfTabs    = indentation / tabSize;
                numberOfSpaces -= numberOfTabs * tabSize;
            }

            return(numberOfTabs + numberOfSpaces);
        }
        /// <summary> Given a set of lines, find the minimum indent of all of the non-blank, non-whitespace lines.</summary>
        static int DetermineSmallestSignificantColumn(IEditorOptions options, SnapshotSpan span, Tuple <ITextSnapshotLine, ITextSnapshotLine> firstAndLastLine)
        {
            var tabSize           = options.GetTabSize();
            var indentToCommentAt = int.MaxValue;

            for (int lineNumber = firstAndLastLine.Item1.LineNumber; lineNumber <= firstAndLastLine.Item2.LineNumber; ++lineNumber)
            {
                var line = span.Snapshot.GetLineFromLineNumber(lineNumber);

                var significantColumn = line.GetIndentationColumn(tabSize) ?? Int32.MaxValue;
                indentToCommentAt = Math.Min(indentToCommentAt, significantColumn);
            }

            return(indentToCommentAt);
        }
Пример #8
0
        static string GetIndentString(int indent, IEditorOptions options)
        {
            if (options.IsConvertTabsToSpacesEnabled())
            {
                return(new string (' ', indent));
            }
            var tabSize   = options.GetTabSize();
            int tabs      = indent / tabSize;
            int spaces    = indent - tabs * tabSize;
            var indentStr = new string ('\t', tabs);

            if (spaces > 0)
            {
                indentStr += new string (' ', spaces);
            }
            return(indentStr);
        }
Пример #9
0
        public bool TryGetDocumentOption(Document document, OptionKey option, OptionSet underlyingOptions, out object value)
        {
            // From the document, look up the ITextBuffer, and find its IEditorOptions.
            // Note that IEditorOptions are also available from an ITextView. Not sure if those options can differ from the ones on the buffer.
            var            workspace     = PrimaryWorkspace.Workspace as VisualStudioWorkspace;
            var            textBuffer    = workspace?.GetTextBufferForDocument(document.Id);
            IEditorOptions editorOptions = textBuffer?.Properties[typeof(IEditorOptions)] as IEditorOptions;

            if (editorOptions == null)
            {
                value = null;
                return(false);
            }

            // Check if the OptionKey is one of the ones we want to override with values from the IEditorOptions
            if (option.Option == FormattingOptions.UseTabs)
            {
                value = !editorOptions.IsConvertTabsToSpacesEnabled();
                return(true);
            }
            else if (option.Option == FormattingOptions.TabSize)
            {
                value = editorOptions.GetTabSize();
                return(true);
            }
            else if (option.Option == FormattingOptions.IndentationSize)
            {
                value = editorOptions.GetIndentSize();
                return(true);
            }
            else if (option.Option == FormattingOptions.NewLine)
            {
                value = editorOptions.GetNewLineCharacter();
                return(true);
            }
            else
            {
                value = null;
                return(false);
            }
        }
        public CSharpOutliningTagger(ITextBuffer buffer, IClassifier classifier, IEditorOptions editorOptions)
        {
            this.Buffer          = buffer;
            this.Snapshot        = buffer.CurrentSnapshot;
            this.Classifier      = classifier;
            this.Buffer.Changed += BufferChanged;
            this.EditorOptions   = editorOptions;
            // need Microsoft.VisualStudio.Text.Editor.OptionsExtensionMethods namespace to work
            this.TabSize = editorOptions.GetTabSize();
            //this.Classifier.ClassificationChanged += BufferChanged;

            //timer that will trigger outlining update after some period of no buffer changes
            UpdateTimer          = new DispatcherTimer(DispatcherPriority.ApplicationIdle);
            UpdateTimer.Interval = TimeSpan.FromMilliseconds(2500);
            UpdateTimer.Tick    += (sender, args) =>
            {
                UpdateTimer.Stop();
                this.Outline();
            };
            this.Outline(); // Force an initial full parse
        }
Пример #11
0
        private static int DetermineIndentationColumn(
            IEditorOptions editorOptions,
            IEnumerable <SnapshotSpan> spans)
        {
            int?indentationColumn = null;

            foreach (SnapshotSpan span in spans)
            {
                ITextSnapshot snapshot        = span.Snapshot;
                int           startLineNumber = snapshot.GetLineNumberFromPosition(span.Start);
                int           endLineNumber   = snapshot.GetLineNumberFromPosition(span.End);

                // If the span starts after the first non-whitespace of the first line, we'll
                // exclude that line to avoid throwing off the calculation. Otherwise, the
                // incorrect indentation will be returned for lambda cases like so:
                //
                // void M()
                // {
                //     Func<int> f = () =>
                //         {
                //             return 1;
                //         };
                // }
                //
                // Without throwing out the first line in the example above, the indentation column
                // used will be 4, rather than 8.
                int?startLineFirstNonWhitespace = snapshot.GetLineFromLineNumber(startLineNumber).GetFirstNonWhitespacePosition();
                if (startLineFirstNonWhitespace.HasValue && startLineFirstNonWhitespace.Value < span.Start)
                {
                    startLineNumber++;
                }

                for (int lineNumber = startLineNumber; lineNumber <= endLineNumber; lineNumber++)
                {
                    ITextSnapshotLine line = snapshot.GetLineFromLineNumber(lineNumber);
                    if (string.IsNullOrWhiteSpace(line.GetText()))
                    {
                        continue;
                    }

                    indentationColumn = indentationColumn.HasValue
                        ? Math.Min(indentationColumn.Value, line.GetText().GetColumnOfFirstNonWhitespaceCharacterOrEndOfLine(editorOptions.GetTabSize()))
                        : line.GetText().GetColumnOfFirstNonWhitespaceCharacterOrEndOfLine(editorOptions.GetTabSize());
                }
            }

            return(indentationColumn ?? 0);
        }
Пример #12
0
 public static int GetLineOffsetFromColumn(this ITextSnapshotLine line, int column, IEditorOptions editorOptions)
 {
     return(line.GetText().GetLineOffsetFromColumn(column, editorOptions.GetTabSize()));
 }
Пример #13
0
 public static int GetColumnFromLineOffset(this ITextSnapshotLine line, int lineOffset, IEditorOptions editorOptions)
 {
     return(line.GetText().GetColumnFromLineOffset(lineOffset, editorOptions.GetTabSize()));
 }
Пример #14
0
 public static int GetColumnOfFirstNonWhitespaceCharacterOrEndOfLine(this ITextSnapshotLine line, IEditorOptions editorOptions)
 {
     return(line.GetColumnOfFirstNonWhitespaceCharacterOrEndOfLine(editorOptions.GetTabSize()));
 }
Пример #15
0
        private static int CalculateIndentation(string baseline, ITextSnapshotLine line, IEditorOptions options, IClassifier classifier, ITextView textView)
        {
            int indentation = GetIndentation(baseline, options.GetTabSize());
            int tabSize     = options.GetIndentSize();
            var tokens      = classifier.GetClassificationSpans(line.Extent);

            if (tokens.Count > 0 && !IsUnterminatedStringToken(tokens[tokens.Count - 1]))
            {
                int tokenIndex = tokens.Count - 1;

                while (tokenIndex >= 0 &&
                       (tokens[tokenIndex].ClassificationType.IsOfType(PredefinedClassificationTypeNames.Comment) ||
                        tokens[tokenIndex].ClassificationType.IsOfType(PredefinedClassificationTypeNames.WhiteSpace)))
                {
                    tokenIndex--;
                }

                if (tokenIndex < 0)
                {
                    return(indentation);
                }

                if (Genero4glReverseParser.IsExplicitLineJoin(tokens[tokenIndex]))
                {
                    // explicit line continuation, we indent 1 level for the continued line unless
                    // we're already indented because of multiple line continuation characters.

                    indentation = GetIndentation(line.GetText(), options.GetTabSize());
                    var joinedLine = tokens[tokenIndex].Span.Start.GetContainingLine();
                    if (joinedLine.LineNumber > 0)
                    {
                        var prevLineSpans = classifier.GetClassificationSpans(tokens[tokenIndex].Span.Snapshot.GetLineFromLineNumber(joinedLine.LineNumber - 1).Extent);
                        if (prevLineSpans.Count == 0 || !Genero4glReverseParser.IsExplicitLineJoin(prevLineSpans[prevLineSpans.Count - 1]))
                        {
                            indentation += tabSize;
                        }
                    }
                    else
                    {
                        indentation += tabSize;
                    }

                    return(indentation);
                }

                string sline    = tokens[tokenIndex].Span.GetText();
                var    lastChar = sline.Length == 0 ? '\0' : sline[sline.Length - 1];

                // use the expression parser to figure out if we're in a grouping...
                var spans = textView.BufferGraph.MapDownToFirstMatch(
                    tokens[tokenIndex].Span,
                    SpanTrackingMode.EdgePositive,
                    PythonContentTypePrediciate
                    );
                if (spans.Count == 0)
                {
                    return(indentation);
                }

                var revParser = new Genero4glReverseParser(
                    spans[0].Snapshot,
                    spans[0].Snapshot.TextBuffer,
                    spans[0].Snapshot.CreateTrackingSpan(
                        spans[0].Span,
                        SpanTrackingMode.EdgePositive
                        )
                    );

                var tokenStack = new List <ClassificationSpan>();
                tokenStack.Insert(0, null);
                bool endAtNextNull = false;

                foreach (var token in revParser)
                {
                    tokenStack.Insert(0, token);
                    if (token == null && endAtNextNull)
                    {
                        break;
                    }
                    else if (token != null &&
                             token.ClassificationType == Genero4glClassifierProvider.Keyword)
                    {
                        var tok = Tokens.GetToken(token.Span.GetText());
                        if (tok != null && Genero4glAst.ValidStatementKeywords.Contains(tok.Kind))
                        {
                            switch (tok.Kind)
                            {
                            // Handle any tokens that are valid statement keywords in the autocomplete context but not in the "statement start" context
                            case TokenKind.EndKeyword:
                                continue;

                            default:
                                endAtNextNull = true;
                                break;
                            }
                        }
                    }
                }

                var indentStack = new System.Collections.Generic.Stack <LineInfo>();
                var current     = LineInfo.Empty;
                List <CancelIndent> cancelIndent           = null;
                int                cancelIndentStartingAt  = -1;
                TokenKind          firstStatement          = TokenKind.EndOfFile;
                TokenKind          latestIndentChangeToken = TokenKind.EndOfFile;
                ClassificationSpan firstToken = null;

                for (int i = 0; i < tokenStack.Count; i++)
                {
                    var token = tokenStack[i];
                    if (token != null && firstToken == null)
                    {
                        firstToken = token;
                    }

                    if (token == null)
                    {
                        current.NeedsUpdate = true;
                    }
                    else if (token.IsOpenGrouping())
                    {
                        indentStack.Push(current);
                        var start = token.Span.Start;
                        var line2 = start.GetContainingLine();
                        current = new LineInfo
                        {
                            Indentation = start.Position - line2.Start.Position + 1
                        };
                    }
                    else if (token.IsCloseGrouping())
                    {
                        if (indentStack.Count > 0)
                        {
                            current = indentStack.Pop();
                        }
                        else
                        {
                            current.NeedsUpdate = true;
                        }
                    }
                    else if (Genero4glReverseParser.IsExplicitLineJoin(token))
                    {
                        while (token != null && i + 1 < tokenStack.Count)
                        {
                            i++;
                            token = tokenStack[i];
                        }
                    }
                    else if (current.NeedsUpdate == true)
                    {
                        var tok = Tokens.GetToken(token.Span.GetText());
                        if (tok == null || !Genero4glAst.ValidStatementKeywords.Contains(tok.Kind))
                        {
                            current.NeedsUpdate = false;
                        }
                        else
                        {
                            switch (tok.Kind)
                            {
                            // Handle any tokens that are valid statement keywords in the autocomplete context but not in the "statement start" context
                            case TokenKind.EndKeyword:
                                if (firstStatement != TokenKind.EndOfFile)
                                {
                                    current.NeedsUpdate = false;
                                }
                                else
                                {
                                    latestIndentChangeToken = tok.Kind;
                                }
                                break;

                            default:
                            {
                                if (firstStatement == TokenKind.EndOfFile)
                                {
                                    firstStatement = tok.Kind;
                                }
                                var line2 = token.Span.Start.GetContainingLine();
                                current = new LineInfo
                                {
                                    Indentation = GetIndentation(line2.GetText(), tabSize)
                                };
                                break;
                            }
                            }
                        }
                    }

                    if (token != null && current.ShouldIndentAfter && cancelIndent != null)
                    {
                        // Check to see if we have following tokens that would cancel the current indent.

                        var  tok           = Tokens.GetToken(token.Span.GetText());
                        var  tokenCategory = token.ClassificationType;
                        bool allPast       = true;
                        bool cancel        = false;
                        foreach (var ci in cancelIndent)
                        {
                            if (ci.TokensAhead < (i - cancelIndentStartingAt))
                            {
                                continue;
                            }
                            else
                            {
                                allPast = false;
                                if (ci.TokensAhead == (i - cancelIndentStartingAt))
                                {
                                    if (ci.UseCategory && ci.CancelCategory != null)
                                    {
                                        cancel = tokenCategory == ci.CancelCategory;
                                    }
                                    else if (tok != null)
                                    {
                                        cancel = tok.Kind == ci.CancelToken;
                                    }
                                    if (cancel)
                                    {
                                        break;
                                    }
                                }
                            }
                        }
                        if (cancel)
                        {
                            current.ShouldIndentAfter = false;
                        }
                        if (cancel || allPast)
                        {
                            cancelIndent            = null;
                            cancelIndentStartingAt  = -1;
                            latestIndentChangeToken = TokenKind.EndOfFile;
                        }
                    }

                    if (token != null && ShouldDedentAfterKeyword(token))
                    {     // dedent after some statements
                        current.ShouldDedentAfter = true;
                    }

                    TokenKind tempChangeToken;
                    if (token != null &&
                        indentStack.Count == 0 &&
                        firstToken == token &&
                        ShouldIndentAfterKeyword(token, out tempChangeToken, out cancelIndent))
                    {                               // except in a grouping
                        if (latestIndentChangeToken != TokenKind.EndKeyword)
                        {
                            current.ShouldIndentAfter = true;
                        }
                        latestIndentChangeToken = tempChangeToken;
                        if (cancelIndent != null)
                        {
                            cancelIndentStartingAt = i;
                        }
                    }
                }

                if (tokenStack.Count > 2 &&
                    tokenStack[tokenStack.Count - 2] != null)
                {
                    if (latestIndentChangeToken != TokenKind.EndOfFile &&
                        _customIndentingRules.ContainsKey(latestIndentChangeToken))
                    {
                        var potentialIndent = _customIndentingRules[latestIndentChangeToken](tokenStack, tabSize);
                        if (potentialIndent != 0)
                        {
                            return(potentialIndent);
                        }
                    }

                    // see if we have specific alignment rules
                    if (firstStatement != TokenKind.EndOfFile &&
                        _customIndentingRules.ContainsKey(firstStatement))
                    {
                        var potentialIndent = _customIndentingRules[firstStatement](tokenStack, tabSize);
                        if (potentialIndent != 0)
                        {
                            return(potentialIndent);
                        }
                    }
                }

                indentation = current.Indentation +
                              (current.ShouldIndentAfter ? tabSize : 0) -
                              (current.ShouldDedentAfter ? tabSize : 0);
            }

            return(indentation);
        }
 public static int GetLineOffsetFromColumn(this ITextSnapshotLine line, int column, IEditorOptions editorOptions)
 {
     return line.GetText().GetLineOffsetFromColumn(column, editorOptions.GetTabSize());
 }
 public static int GetColumnOfFirstNonWhitespaceCharacterOrEndOfLine(this ITextSnapshotLine line, IEditorOptions editorOptions)
 {
     return line.GetColumnOfFirstNonWhitespaceCharacterOrEndOfLine(editorOptions.GetTabSize());
 }
Пример #18
0
        // Code taken from https://github.com/dotnet/roslyn/blob/master/src/EditorFeatures/Core/Shared/Extensions/IProjectionBufferFactoryServiceExtensions.cs
        public static IProjectionBuffer CreateProjectionBufferWithoutIndentation(
            this IProjectionBufferFactoryService projectionBufferFactoryService,
            IEditorOptions editorOptions,
            ITextSnapshot textSnapshot,
            string separator,
            params LineSpan[] exposedLineSpans)
        {
            var spans = new List <object>();

            if (exposedLineSpans.Length > 0)
            {
                if (exposedLineSpans[0].Start > 0 && !string.IsNullOrEmpty(separator))
                {
                    spans.Add(separator);
                    spans.Add(editorOptions.GetNewLineCharacter());
                }

                IList <IList <SnapshotSpan> > snapshotSpanRanges = CreateSnapshotSpanRanges(textSnapshot, exposedLineSpans);
                int indentColumn = DetermineIndentationColumn(editorOptions, snapshotSpanRanges.SelectMany(s => s));

                foreach (IList <SnapshotSpan> snapshotSpanRange in snapshotSpanRanges)
                {
                    foreach (SnapshotSpan snapshotSpan in snapshotSpanRange)
                    {
                        ITextSnapshotLine line = snapshotSpan.Snapshot.GetLineFromPosition(snapshotSpan.Start);
                        int indentPosition     = line.GetText().GetLineOffsetFromColumn(indentColumn, editorOptions.GetTabSize()) + line.Start;
                        var mappedSpan         = new SnapshotSpan(snapshotSpan.Snapshot, Span.FromBounds(indentPosition, snapshotSpan.End));

                        ITrackingSpan trackingSpan = mappedSpan.Snapshot.CreateTrackingSpan(mappedSpan, SpanTrackingMode.EdgeExclusive);

                        spans.Add(trackingSpan);

                        // Add a newline between every line.
                        if (snapshotSpan != snapshotSpanRange.Last())
                        {
                            spans.Add(editorOptions.GetNewLineCharacter());
                        }
                    }

                    // Add a separator between every set of lines.
                    if (snapshotSpanRange != snapshotSpanRanges.Last())
                    {
                        spans.Add(editorOptions.GetNewLineCharacter());
                        spans.Add(separator);
                        spans.Add(editorOptions.GetNewLineCharacter());
                    }
                }

                if (textSnapshot.GetLineNumberFromPosition(snapshotSpanRanges.Last().Last().End) < textSnapshot.LineCount - 1)
                {
                    spans.Add(editorOptions.GetNewLineCharacter());
                    spans.Add(separator);
                }
            }

            return(projectionBufferFactoryService.CreateProjectionBuffer(
                       projectionEditResolver: null,
                       sourceSpans: spans,
                       options: ProjectionBufferOptions.None,
                       contentType: textSnapshot.ContentType));
        }
Пример #19
0
 public SmartIndent(ITextView textView, IEditorOptions options) : this(textView)
 {
     _options = options;
     _tabSize = _options.GetTabSize();
 }
        public override bool Indent()
        {
            bool singleLineSelection = (GetStartPoint().LineNumber == GetEndPoint().LineNumber);
            bool entireLastLineSelected
                = (GetStartPoint().CurrentPosition != GetEndPoint().CurrentPosition&&
                   GetStartPoint().CurrentPosition == TextBuffer.GetEndPoint().StartOfLine&&
                   GetEndPoint().CurrentPosition == TextBuffer.GetEndPoint().EndOfLine);

            if (singleLineSelection && !entireLastLineSelected)
            {
                TextPoint endPoint = GetEndPoint();
                if (!Delete())
                {
                    return(false);
                }
                if (!endPoint.InsertIndent())
                {
                    return(false);
                }
                TextView.AdvancedTextView.Caret.MoveTo(endPoint.AdvancedTextPoint);
            }
            else // indent the selected lines
            {
                VirtualSnapshotPoint oldStartPoint = TextSelection.Start;
                VirtualSnapshotPoint oldEndPoint   = TextSelection.End;
                bool isReversed = TextSelection.IsReversed;

                ITextSnapshotLine startLine = AdvancedTextRange.Snapshot.GetLineFromPosition(oldStartPoint.Position);
                ITextSnapshotLine endLine   = AdvancedTextRange.Snapshot.GetLineFromPosition(oldEndPoint.Position);

                // If the selection span initially starts at the whitespace at the beginning of the line in the startLine or
                // ends at the whitespace at the beginning of the line in the endLine, restore selection and caret position,
                // *unless* the selection was in box mode.
                bool startAtStartLineWhitespace = oldStartPoint.Position <= _textView.GetTextPoint(startLine.Start).GetFirstNonWhiteSpaceCharacterOnLine().CurrentPosition;
                bool endAtEndLineWhitespace     = oldEndPoint.Position < _textView.GetTextPoint(endLine.Start).GetFirstNonWhiteSpaceCharacterOnLine().CurrentPosition;
                bool isBoxSelection             = AdvancedSelection.Mode == TextSelectionMode.Box;

                if (isBoxSelection)
                {
                    if (!this.BoxIndent())
                    {
                        return(false);
                    }
                }
                else
                {
                    if (!TextRange.Indent())
                    {
                        return(false);
                    }
                }

                // Computing the new selection and caret position
                VirtualSnapshotPoint newStartPoint = TextSelection.Start;
                VirtualSnapshotPoint newEndPoint   = TextSelection.End;

                if (!isBoxSelection && (startAtStartLineWhitespace || endAtEndLineWhitespace))
                {
                    // After indent selection span should start at the start of startLine and end at the start of endLine
                    if (startAtStartLineWhitespace)
                    {
                        newStartPoint = new VirtualSnapshotPoint(AdvancedTextRange.Snapshot, oldStartPoint.Position.Position);
                    }

                    if (endAtEndLineWhitespace && oldEndPoint.Position.Position != endLine.Start && endLine.Length != 0)
                    {
                        int insertedTextSize = _editorOptions.IsConvertTabsToSpacesEnabled() ? _editorOptions.GetTabSize() : 1;
                        newEndPoint = new VirtualSnapshotPoint(AdvancedTextRange.Snapshot, newEndPoint.Position.Position - insertedTextSize);
                    }

                    if (!isReversed)
                    {
                        TextSelection.Select(newStartPoint, newEndPoint);
                    }
                    else
                    {
                        TextSelection.Select(newEndPoint, newStartPoint);
                    }

                    TextView.AdvancedTextView.Caret.MoveTo(TextSelection.ActivePoint, PositionAffinity.Successor);
                }
            }
            TextView.AdvancedTextView.Caret.EnsureVisible();
            return(true);
        }
Пример #21
0
        private int?DoSmartIndent(ITextSnapshotLine line)
        {
            if (line.LineNumber == 0)
            {
                return(null);
            }
            int?indentation     = GetLeadingWhiteSpace(line.GetText());
            var classifications = EnumerateClassificationsInReverse(
                _classifier,
                line.Snapshot.GetLineFromLineNumber(line.LineNumber - 1).End
                );

            if (classifications.MoveNext())
            {
                var starting = classifications.Current;

                // first check to see if we're in an unterminated multiline token
                if (starting != null)
                {
                    if (starting.Tag.ClassificationType.Classification == "comment" &&
                        starting.Span.GetText().StartsWith("/*") &&
                        (!starting.Span.GetText().EndsWith("*/") || starting.Span.End.GetContainingLine() == line))
                    {
                        // smart indent in comment, dont indent
                        return(null);
                    }
                    else if (starting.Tag.ClassificationType.Classification == "string")
                    {
                        var text = starting.Span.GetText();
                        if (!text.EndsWith("\"") && !text.EndsWith("'"))
                        {
                            // smart indent in multiline string, no indent
                            return(null);
                        }
                    }
                }

                // walk backwards and collect all of the possible tokens that could
                // be useful here...
                var tokenStack = new System.Collections.Generic.Stack <ITagSpan <ClassificationTag> >();
                tokenStack.Push(null);  // end with an implicit newline
                bool endAtNextNull = false;

                do
                {
                    var token = classifications.Current;
                    tokenStack.Push(token);
                    if (token == null && endAtNextNull)
                    {
                        break;
                    }
                    else if (token != null &&
                             token.Span.GetText() == "{")
                    {
                        endAtNextNull = true;
                    }
                } while (classifications.MoveNext());

                var indentStack = new System.Collections.Generic.Stack <LineInfo>();
                var current     = LineInfo.Empty;

                while (tokenStack.Count > 0)
                {
                    var  token     = tokenStack.Pop();
                    bool didDedent = false;
                    if (token == null)
                    {
                        current.NeedsUpdate = true;
                    }
                    else if (IsOpenGrouping(token))
                    {
                        if (current.WasIndentKeyword && token.Span.GetText() == "{")
                        {
                            // the indentation statement is followed by braces, go ahead
                            // and remove the level of indentation now
                            current.WasIndentKeyword = false;
                            current.Indentation     -= _editorOptions.GetTabSize();
                        }
                        indentStack.Push(current);
                        var start = token.Span.Start;
                        current = new LineInfo {
                            Indentation = GetLeadingWhiteSpace(start.GetContainingLine().GetText()) + _editorOptions.GetTabSize()
                        };
                    }
                    else if (_indentKeywords.Contains(token.Span.GetText()) && !current.WasDoKeyword)
                    {
                        // if (foo)
                        //      console.log('hi')
                        // We should indent here
                        var start    = token.Span.Start;
                        int dedentTo = GetLeadingWhiteSpace(start.GetContainingLine().GetText());
                        if (current.DedentTo != null && token.Span.GetText() != "if")
                        {
                            // https://nodejstools.codeplex.com/workitem/1176
                            // if (true)
                            //     while (true)
                            //         ;
                            //
                            // We should dedent to the if (true)
                            // But for:
                            // if (true)
                            //     if (true)
                            //          ;
                            // We still want to dedent to our current level for the else
                            dedentTo = current.DedentTo.Value;
                        }
                        current = new LineInfo {
                            Indentation      = GetLeadingWhiteSpace(start.GetContainingLine().GetText()) + _editorOptions.GetTabSize(),
                            DedentTo         = dedentTo,
                            WasIndentKeyword = true,
                            WasDoKeyword     = token.Span.GetText() == "do"
                        };
                    }
                    else if (IsCloseGrouping(token))
                    {
                        if (indentStack.Count > 0)
                        {
                            current = indentStack.Pop();
                        }
                        else
                        {
                            current = new LineInfo {
                                Indentation = GetLeadingWhiteSpace(token.Span.Start.GetContainingLine().GetText())
                            };
                        }
                    }
                    else if (IsMultilineStringOrComment(token))
                    {
                        while (token != null && tokenStack.Count > 0)
                        {
                            token = tokenStack.Pop();
                        }
                    }
                    else if (current.WasIndentKeyword)
                    {
                        // we've encountered a token after the opening of the indented
                        // statement, go ahead and decrement our indentation level now.
                        current = new LineInfo {
                            Indentation  = current.DedentTo,
                            DedentTo     = current.DedentTo - _editorOptions.GetTabSize(),
                            WasDoKeyword = current.WasDoKeyword
                        };
                        didDedent = true;
                    }
                    else if (current.NeedsUpdate)
                    {
                        var line2 = token.Span.Start.GetContainingLine();
                        current = new LineInfo {
                            Indentation = GetLeadingWhiteSpace(line2.GetText())
                        };
                    }

                    if (!didDedent && token != null && _dedentKeywords.Contains(token.Span.GetText()))       // dedent after some statements
                    {
                        current.ShouldDedentAfter = true;
                    }
                }

                return(current.Indentation -
                       (current.ShouldDedentAfter ? _editorOptions.GetTabSize() : 0));
            }

            return(null);
        }
Пример #22
0
        private static int CalculateIndentation(string baseline, ITextSnapshotLine line, IEditorOptions options, IClassifier classifier, ITextView textView) {
            int indentation = GetIndentation(baseline, options.GetTabSize());
            int tabSize = options.GetIndentSize();
            var tokens = classifier.GetClassificationSpans(line.Extent);
            if (tokens.Count > 0 && !IsUnterminatedStringToken(tokens[tokens.Count - 1])) {
                int tokenIndex = tokens.Count - 1;

                while (tokenIndex >= 0 &&
                    (tokens[tokenIndex].ClassificationType.IsOfType(PredefinedClassificationTypeNames.Comment) ||
                    tokens[tokenIndex].ClassificationType.IsOfType(PredefinedClassificationTypeNames.WhiteSpace))) {
                    tokenIndex--;
                }

                if (tokenIndex < 0) {
                    return indentation;
                }

                if (ReverseExpressionParser.IsExplicitLineJoin(tokens[tokenIndex])) {
                    // explicit line continuation, we indent 1 level for the continued line unless
                    // we're already indented because of multiple line continuation characters.

                    indentation = GetIndentation(line.GetText(), options.GetTabSize());
                    var joinedLine = tokens[tokenIndex].Span.Start.GetContainingLine();
                    if (joinedLine.LineNumber > 0) {
                        var prevLineSpans = classifier.GetClassificationSpans(tokens[tokenIndex].Span.Snapshot.GetLineFromLineNumber(joinedLine.LineNumber - 1).Extent);
                        if (prevLineSpans.Count == 0 || !ReverseExpressionParser.IsExplicitLineJoin(prevLineSpans[prevLineSpans.Count - 1])) {
                            indentation += tabSize;
                        }
                    } else {
                        indentation += tabSize;
                    }

                    return indentation;
                }

                string sline = tokens[tokenIndex].Span.GetText();
                var lastChar = sline.Length == 0 ? '\0' : sline[sline.Length - 1];

                // use the expression parser to figure out if we're in a grouping...
                var spans = textView.BufferGraph.MapDownToFirstMatch(
                    tokens[tokenIndex].Span,
                    SpanTrackingMode.EdgePositive,
                    PythonContentTypePrediciate
                );
                if (spans.Count == 0) {
                    return indentation;
                }
                
                var revParser = new ReverseExpressionParser(
                        spans[0].Snapshot,
                        spans[0].Snapshot.TextBuffer,
                        spans[0].Snapshot.CreateTrackingSpan(
                            spans[0].Span,
                            SpanTrackingMode.EdgePositive
                        )
                    );

                var tokenStack = new System.Collections.Generic.Stack<ClassificationSpan>();
                tokenStack.Push(null);  // end with an implicit newline
                bool endAtNextNull = false;

                foreach (var token in revParser) {
                    tokenStack.Push(token);
                    if (token == null && endAtNextNull) {
                        break;
                    } else if (token != null &&
                       token.ClassificationType == revParser.Classifier.Provider.Keyword &&
                       PythonKeywords.IsOnlyStatementKeyword(token.Span.GetText())) {
                        endAtNextNull = true;
                    }
                }

                var indentStack = new System.Collections.Generic.Stack<LineInfo>();
                var current = LineInfo.Empty;

                while (tokenStack.Count > 0) {
                    var token = tokenStack.Pop();
                    if (token == null) {
                        current.NeedsUpdate = true;
                    } else if (token.IsOpenGrouping()) {
                        indentStack.Push(current);
                        var start = token.Span.Start;
                        var line2 = start.GetContainingLine();
                        var next = tokenStack.Count > 0 ? tokenStack.Peek() : null;
                        if (next != null && next.Span.End <= line2.End) {
                            current = new LineInfo {
                                Indentation = start.Position - line2.Start.Position + 1
                            };
                        } else {
                            current = new LineInfo {
                                Indentation = GetIndentation(line2.GetText(), tabSize) + tabSize
                            };
                        }
                    } else if (token.IsCloseGrouping()) {
                        if (indentStack.Count > 0) {
                            current = indentStack.Pop();
                        } else {
                            current.NeedsUpdate = true;
                        }
                    } else if (ReverseExpressionParser.IsExplicitLineJoin(token)) {
                        while (token != null && tokenStack.Count > 0) {
                            token = tokenStack.Pop();
                        }
                    } else if (current.NeedsUpdate == true) {
                        var line2 = token.Span.Start.GetContainingLine();
                        current = new LineInfo {
                            Indentation = GetIndentation(line2.GetText(), tabSize)
                        };
                    }

                    if (token != null && ShouldDedentAfterKeyword(token)) {     // dedent after some statements
                        current.ShouldDedentAfter = true;
                    }

                    if (token != null && token.Span.GetText() == ":" &&         // indent after a colon
                        indentStack.Count == 0) {                               // except in a grouping
                        current.ShouldIndentAfter = true;
                        // If the colon isn't at the end of the line, cancel it out.
                        // If the following is a ShouldDedentAfterKeyword, only one dedent will occur.
                        current.ShouldDedentAfter = (tokenStack.Count != 0 && tokenStack.Peek() != null);
                    }
                }

                indentation = current.Indentation +
                    (current.ShouldIndentAfter ? tabSize : 0) -
                    (current.ShouldDedentAfter ? tabSize : 0);
            }

            // Map indentation back to the view's text buffer.
            int offset = 0;
            var viewLineStart = textView.BufferGraph.MapUpToSnapshot(line.Start, PointTrackingMode.Positive, PositionAffinity.Successor, textView.TextSnapshot);
            if (viewLineStart.HasValue) {
                offset = viewLineStart.Value.Position - viewLineStart.Value.GetContainingLine().Start.Position;
            }

            return offset + indentation;
        }
Пример #23
0
        private static int CalculateIndentation(
            string baseline,
            ITextSnapshotLine line,
            IEditorOptions options,
            PythonTextBufferInfo buffer
            )
        {
            var snapshot = line.Snapshot;

            if (snapshot.TextBuffer != buffer.Buffer)
            {
                throw new ArgumentException("buffer mismatch");
            }

            int indentation = GetIndentation(baseline, options.GetTabSize());
            int tabSize     = options.GetIndentSize();
            var tokens      = buffer.GetTokens(line).ToList();

            while (tokens.Count > 0 && IsWhitespace(tokens[tokens.Count - 1].Category))
            {
                tokens.RemoveAt(tokens.Count - 1);
            }

            if (tokens.Count == 0 || IsUnterminatedStringToken(tokens[tokens.Count - 1], snapshot))
            {
                return(indentation);
            }

            if (HasExplicitLineJoin(tokens, snapshot))
            {
                // explicit line continuation, we indent 1 level for the continued line unless
                // we're already indented because of multiple line continuation characters.
                indentation = GetIndentation(line.GetText(), options.GetTabSize());
                var joinedLine = line.LineNumber - 1;
                if (joinedLine >= 0)
                {
                    var prevLineTokens = buffer.GetTokens(snapshot.GetLineFromLineNumber(joinedLine)).ToList();
                    if (prevLineTokens.Count == 0 || !HasExplicitLineJoin(prevLineTokens, snapshot))
                    {
                        indentation += tabSize;
                    }
                }
                else
                {
                    indentation += tabSize;
                }

                return(indentation);
            }

            var tokenStack = new Stack <TrackingTokenInfo?>();

            tokenStack.Push(null);  // end with an implicit newline
            int endAtLine = -1, currentLine = tokens.Last().LineNumber;

            foreach (var t in buffer.GetTokensInReverseFromPoint(tokens.Last().ToSnapshotSpan(snapshot).Start))
            {
                if (t.LineNumber == currentLine)
                {
                    tokenStack.Push(t);
                }
                else
                {
                    tokenStack.Push(null);
                }

                if (t.LineNumber == endAtLine)
                {
                    break;
                }
                else if (t.Category == TokenCategory.Keyword && PythonKeywords.IsOnlyStatementKeyword(t.GetText(snapshot), buffer.LanguageVersion))
                {
                    endAtLine = t.LineNumber - 1;
                }

                if (t.LineNumber != currentLine)
                {
                    currentLine = t.LineNumber;
                    if (t.Category != TokenCategory.WhiteSpace && t.Category != TokenCategory.Comment && t.Category != TokenCategory.LineComment)
                    {
                        tokenStack.Push(t);
                    }
                }
            }

            var indentStack = new Stack <LineInfo>();
            var current     = LineInfo.Empty;

            while (tokenStack.Count > 0)
            {
                var t = tokenStack.Pop();
                if (t == null)
                {
                    current.NeedsUpdate = true;
                    continue;
                }

                var tline = new Lazy <string>(() => snapshot.GetLineFromLineNumber(t.Value.LineNumber).GetText());

                if (IsOpenGrouping(t.Value, snapshot))
                {
                    indentStack.Push(current);
                    var next = tokenStack.Count > 0 ? tokenStack.Peek() : null;
                    if (next != null && next.Value.LineNumber == t.Value.LineNumber)
                    {
                        // Put indent at same depth as grouping
                        current = new LineInfo {
                            Indentation = t.Value.ToSourceSpan().End.Column - 1
                        };
                    }
                    else
                    {
                        // Put indent at one indent deeper than this line
                        current = new LineInfo {
                            Indentation = GetIndentation(tline.Value, tabSize) + tabSize
                        };
                    }
                }
                else if (IsCloseGrouping(t.Value, snapshot))
                {
                    if (indentStack.Count > 0)
                    {
                        current = indentStack.Pop();
                    }
                    else
                    {
                        current.NeedsUpdate = true;
                    }
                }
                else if (IsExplicitLineJoin(t.Value, snapshot))
                {
                    while (t != null && tokenStack.Count > 0)
                    {
                        t = tokenStack.Pop();
                    }
                    if (!t.HasValue)
                    {
                        continue;
                    }
                }
                else if (current.NeedsUpdate == true)
                {
                    current = new LineInfo {
                        Indentation = GetIndentation(tline.Value, tabSize)
                    };
                }

                if (ShouldDedentAfterKeyword(t.Value, snapshot))      // dedent after some statements
                {
                    current.ShouldDedentAfter = true;
                }

                if (IsColon(t.Value, snapshot) &&       // indent after a colon
                    indentStack.Count == 0)             // except in a grouping
                {
                    current.ShouldIndentAfter = true;
                    // If the colon isn't at the end of the line, cancel it out.
                    // If the following is a ShouldDedentAfterKeyword, only one dedent will occur.
                    current.ShouldDedentAfter = (tokenStack.Count != 0 && tokenStack.Peek() != null);
                }
            }

            indentation = current.Indentation +
                          (current.ShouldIndentAfter ? tabSize : 0) -
                          (current.ShouldDedentAfter ? tabSize : 0);

            return(indentation);
        }
 public static int GetColumnFromLineOffset(this ITextSnapshotLine line, int lineOffset, IEditorOptions editorOptions)
 {
     return line.GetText().GetColumnFromLineOffset(lineOffset, editorOptions.GetTabSize());
 }
Пример #25
0
        private static int CalculateIndentation(string baseline, ITextSnapshotLine line, IEditorOptions options, IClassifier classifier, ITextView textView)
        {
            int indentation = GetIndentation(baseline, options.GetTabSize());
            int tabSize     = options.GetIndentSize();
            var tokens      = classifier.GetClassificationSpans(line.Extent);

            if (tokens.Count > 0 && !IsUnterminatedStringToken(tokens[tokens.Count - 1]))
            {
                int tokenIndex = tokens.Count - 1;

                while (tokenIndex >= 0 &&
                       (tokens[tokenIndex].ClassificationType.IsOfType(PredefinedClassificationTypeNames.Comment) ||
                        tokens[tokenIndex].ClassificationType.IsOfType(PredefinedClassificationTypeNames.WhiteSpace)))
                {
                    tokenIndex--;
                }

                if (tokenIndex < 0)
                {
                    return(indentation);
                }

                if (ReverseExpressionParser.IsExplicitLineJoin(tokens[tokenIndex]))
                {
                    // explicit line continuation, we indent 1 level for the continued line unless
                    // we're already indented because of multiple line continuation characters.

                    indentation = GetIndentation(line.GetText(), options.GetTabSize());
                    var joinedLine = tokens[tokenIndex].Span.Start.GetContainingLine();
                    if (joinedLine.LineNumber > 0)
                    {
                        var prevLineSpans = classifier.GetClassificationSpans(tokens[tokenIndex].Span.Snapshot.GetLineFromLineNumber(joinedLine.LineNumber - 1).Extent);
                        if (prevLineSpans.Count == 0 || !ReverseExpressionParser.IsExplicitLineJoin(prevLineSpans[prevLineSpans.Count - 1]))
                        {
                            indentation += tabSize;
                        }
                    }
                    else
                    {
                        indentation += tabSize;
                    }

                    return(indentation);
                }

                string sline    = tokens[tokenIndex].Span.GetText();
                var    lastChar = sline.Length == 0 ? '\0' : sline[sline.Length - 1];

                // use the expression parser to figure out if we're in a grouping...
                var spans = textView.BufferGraph.MapDownToFirstMatch(
                    tokens[tokenIndex].Span,
                    SpanTrackingMode.EdgePositive,
                    PythonContentTypePrediciate
                    );
                if (spans.Count == 0)
                {
                    return(indentation);
                }

                var revParser = new ReverseExpressionParser(
                    spans[0].Snapshot,
                    spans[0].Snapshot.TextBuffer,
                    spans[0].Snapshot.CreateTrackingSpan(
                        spans[0].Span,
                        SpanTrackingMode.EdgePositive
                        )
                    );

                var tokenStack = new System.Collections.Generic.Stack <ClassificationSpan>();
                tokenStack.Push(null);  // end with an implicit newline
                bool endAtNextNull = false;

                foreach (var token in revParser)
                {
                    tokenStack.Push(token);
                    if (token == null && endAtNextNull)
                    {
                        break;
                    }
                    else if (token != null &&
                             token.ClassificationType == revParser.Classifier.Provider.Keyword &&
                             PythonKeywords.IsOnlyStatementKeyword(token.Span.GetText()))
                    {
                        endAtNextNull = true;
                    }
                }

                var indentStack = new System.Collections.Generic.Stack <LineInfo>();
                var current     = LineInfo.Empty;

                while (tokenStack.Count > 0)
                {
                    var token = tokenStack.Pop();
                    if (token == null)
                    {
                        current.NeedsUpdate = true;
                    }
                    else if (token.IsOpenGrouping())
                    {
                        indentStack.Push(current);
                        var start = token.Span.Start;
                        var line2 = start.GetContainingLine();
                        var next  = tokenStack.Count > 0 ? tokenStack.Peek() : null;
                        if (next != null && next.Span.End <= line2.End)
                        {
                            current = new LineInfo {
                                Indentation = start.Position - line2.Start.Position + 1
                            };
                        }
                        else
                        {
                            current = new LineInfo {
                                Indentation = GetIndentation(line2.GetText(), tabSize) + tabSize
                            };
                        }
                    }
                    else if (token.IsCloseGrouping())
                    {
                        if (indentStack.Count > 0)
                        {
                            current = indentStack.Pop();
                        }
                        else
                        {
                            current.NeedsUpdate = true;
                        }
                    }
                    else if (ReverseExpressionParser.IsExplicitLineJoin(token))
                    {
                        while (token != null && tokenStack.Count > 0)
                        {
                            token = tokenStack.Pop();
                        }
                    }
                    else if (current.NeedsUpdate == true)
                    {
                        var line2 = token.Span.Start.GetContainingLine();
                        current = new LineInfo {
                            Indentation = GetIndentation(line2.GetText(), tabSize)
                        };
                    }

                    if (token != null && ShouldDedentAfterKeyword(token))       // dedent after some statements
                    {
                        current.ShouldDedentAfter = true;
                    }

                    if (token != null && token.Span.GetText() == ":" &&         // indent after a colon
                        indentStack.Count == 0)                                 // except in a grouping
                    {
                        current.ShouldIndentAfter = true;
                        // If the colon isn't at the end of the line, cancel it out.
                        // If the following is a ShouldDedentAfterKeyword, only one dedent will occur.
                        current.ShouldDedentAfter = (tokenStack.Count != 0 && tokenStack.Peek() != null);
                    }
                }

                indentation = current.Indentation +
                              (current.ShouldIndentAfter ? tabSize : 0) -
                              (current.ShouldDedentAfter ? tabSize : 0);
            }

            // Map indentation back to the view's text buffer.
            int offset        = 0;
            var viewLineStart = textView.BufferGraph.MapUpToSnapshot(line.Start, PointTrackingMode.Positive, PositionAffinity.Successor, textView.TextSnapshot);

            if (viewLineStart.HasValue)
            {
                offset = viewLineStart.Value.Position - viewLineStart.Value.GetContainingLine().Start.Position;
            }

            return(offset + indentation);
        }
Пример #26
0
        private LineCommentInfo(ITextSnapshotLine line, IList<ClassificationSpan> spans, SnapshotSpan commentSpan, IEditorOptions options)
        {
            this.Line = line;
            this.CommentSpan = commentSpan;
            this.CommentOnly = spans.Count == 1;    // what about leading whitespace?

            var commentStart = this.CommentSpan.Start;

            // Is there a reliable way to detect we're inside a multi-line comment?
            // for now, we assume single-line...
            var text = this.CommentSpan.GetText();

            if (text.StartsWith("////") || text.StartsWith("''''"))
            {
                // A code-comment, probably *shouldn't* be wrapped!
                this.Style = CommentStyle.CodeComment;
                this.MarkerSpan = new SnapshotSpan(commentStart, 4);
            }
            else if (text.StartsWith("///") || text.StartsWith("'''"))
            {
                this.Style = CommentStyle.DocComment;
                this.MarkerSpan = new SnapshotSpan(commentStart, 3);
            }
            else if (text.StartsWith("//") || text.StartsWith("''"))
            {
                this.Style = CommentStyle.SingleLine;

                // Look for special leading characters (+, -, !, ?) commonly
                // used in other comment-formatters, and consider them a part
                // of the marker...
                var extra = text.Skip(2).TakeWhile(c => FormatMarkers.Contains(c)).Count();

                this.MarkerSpan = new SnapshotSpan(commentStart, 2 + extra);
            }
            else if (text.StartsWith("/*"))
            {
                this.Style = CommentStyle.MultiLineStart;

                // Look for special leading characters (+, -, !, ?) commonly
                // used in other comment-formatters, and consider them a part
                // of the marker...
                var extra = text.Skip(2).TakeWhile(c => FormatMarkers.Contains(c)).Count();

                this.MarkerSpan = new SnapshotSpan(commentStart, 2 + extra);
            }
            else if ((text.StartsWith("/") || text.StartsWith("'")) &&
                    (commentStart > line.Start) &&
                    ((commentStart - 1).GetChar() == commentStart.GetChar()))
            {
                // Weird case where the classifier gives a bogus result when typing
                // the "//" at the beginning of the line... perhaps we should *not*
                // wrap in this case?

                // Treat like "//" or "''" comment... but fix the span up!
                this.CommentSpan = new SnapshotSpan(commentStart - 1, this.CommentSpan.End);
                commentSpan = this.CommentSpan;
                commentStart = this.CommentSpan.Start;
                text = this.CommentSpan.GetText();

                this.Style = CommentStyle.SingleLine;

                // Look for special leading characters (+, -, !, ?) commonly
                // used in other comment-formatters, and consider them a part
                // of the marker...
                var extra = text.Skip(2).TakeWhile(c => FormatMarkers.Contains(c)).Count();

                this.MarkerSpan = new SnapshotSpan(commentStart, 2 + extra);
            }
            else
            {
                // We must be a continuation?
                this.Style = CommentStyle.MultiLineContinuation;
                this.MarkerSpan = new SnapshotSpan(commentStart, 0);
            }

            // Determine the post-marker whitespace (if any).
            var space = text.Skip(this.MarkerSpan.Length).TakeWhile(c => Whitespace.Contains(c)).Count();
            this.ContentSpan = new SnapshotSpan(commentStart + this.MarkerSpan.Length + space, this.CommentSpan.End);

            // Determine the effective column of the comment, taking into
            // account that tabs may be more than one space.  Sadly, there
            // doesn't seem to be a way to handle this other than counting every
            // character in the line!
            var lineText = this.Line.Extent.GetText();
            var currentColumn = 0;
            var currentPos = this.Line.Start.Position;
            this.ContentColumnStart = this.ContentSpan.Start.Position - currentPos;

            int tabSize = options.GetTabSize();

            foreach (var c in lineText)
            {
                if (currentPos == this.MarkerSpan.Start.Position)
                {
                    this.MarkerColumnStart = currentColumn;
                }

                if (currentPos == this.ContentSpan.Start.Position)
                {
                    this.ContentColumnStart = currentColumn;
                    break;
                }

                // TODO: track effective comment start/end/length?
                if (c == '\t')
                {
                    // round up to the next multiple of the tab-stop size!
                    currentColumn += tabSize - (currentColumn % tabSize);
                }
                else
                {
                    currentColumn++;
                }

                currentPos++;
            }
        }
Пример #27
0
        public override bool Indent()
        {
            string textToInsert = _editorOptions.IsConvertTabsToSpacesEnabled() ? new string(' ', _editorOptions.GetTabSize()) : "\t";

            if (_startPoint.LineNumber == _endPoint.LineNumber)
            {
                return(_startPoint.InsertIndent());
            }

            using (ITextEdit edit = TextBuffer.AdvancedTextBuffer.CreateEdit())
            {
                ITextSnapshot snapshot = TextBuffer.AdvancedTextBuffer.CurrentSnapshot;
                for (int i = _startPoint.LineNumber; i <= _endPoint.LineNumber; i++)
                {
                    ITextSnapshotLine line = snapshot.GetLineFromLineNumber(i);
                    if ((line.Length > 0) &&
                        (line.Start != _endPoint.CurrentPosition))
                    {
                        if (!edit.Insert(line.Start, textToInsert))
                        {
                            return(false);
                        }
                    }
                }

                edit.Apply();

                if (edit.Canceled)
                {
                    return(false);
                }
            }

            return(true);
        }