Beispiel #1
0
        protected override StatementSyntax CreateParameterCheckIfStatement(
            DocumentOptionSet options,
            ExpressionSyntax condition,
            StatementSyntax ifTrueStatement
            )
        {
            var withBlock =
                options.GetOption(CSharpCodeStyleOptions.PreferBraces).Value
                == CodeAnalysis.CodeStyle.PreferBracesPreference.Always;
            var singleLine =
                options.GetOption(CSharpCodeStyleOptions.AllowEmbeddedStatementsOnSameLine).Value;
            var closeParenToken = Token(SyntaxKind.CloseParenToken);

            if (withBlock)
            {
                ifTrueStatement = Block(ifTrueStatement);
            }
            else if (singleLine)
            {
                // Any elastic trivia between the closing parenthesis of if and the statement must be removed
                // to convince the formatter to keep everything on a single line.
                // Note: ifTrueStatement and closeParenToken are generated, so there is no need to deal with any existing trivia.
                closeParenToken = closeParenToken.WithTrailingTrivia(Space);
                ifTrueStatement = ifTrueStatement.WithoutLeadingTrivia();
            }

            return(IfStatement(
                       attributeLists: default,
Beispiel #2
0
        private static string GetReplacementText(
            ITextView textView,
            DocumentOptionSet options,
            ITextSnapshotLine triviaLine,
            SyntaxTrivia trivia,
            int position
            )
        {
            // We're inside a comment.  Instead of inserting just a newline here, insert
            // 1. a newline
            // 2. spaces up to the indentation of the current comment
            // 3. the comment prefix (extended out for repeated chars).

            // Then, depending on if the current comment starts with whitespace or not, we will insert those same spaces
            // to match.

            var commentStartColumn = triviaLine.GetColumnFromLineOffset(
                trivia.SpanStart - triviaLine.Start,
                textView.Options
                );

            var useTabs = options.GetOption(FormattingOptions.UseTabs);
            var tabSize = options.GetOption(FormattingOptions.TabSize);

            var prefix          = GetCommentPrefix(triviaLine.Snapshot, trivia, position);
            var replacementText =
                options.GetOption(FormattingOptions.NewLine)
                + commentStartColumn.CreateIndentationString(useTabs, tabSize)
                + prefix
                + GetWhitespaceAfterCommentPrefix(trivia, triviaLine, prefix, position);

            return(replacementText);
        }
 private bool OnlySmartIndentCloseBrace(DocumentOptionSet options)
 {
     // User does not want auto-formatting (either in general, or for close braces in
     // specific).  So we only smart indent close braces when typed.
     return(!options.GetOption(FeatureOnOffOptions.AutoFormattingOnCloseBrace) ||
            !options.GetOption(FeatureOnOffOptions.AutoFormattingOnTyping));
 }
        private static int?SplitStringLiteral(
            Document document,
            DocumentOptionSet options,
            int position,
            CancellationToken cancellationToken
            )
        {
            var useTabs     = options.GetOption(FormattingOptions.UseTabs);
            var tabSize     = options.GetOption(FormattingOptions.TabSize);
            var indentStyle = options.GetOption(
                FormattingOptions.SmartIndent,
                LanguageNames.CSharp
                );

            var root       = document.GetSyntaxRootSynchronously(cancellationToken);
            var sourceText = root.SyntaxTree.GetText(cancellationToken);

            var splitter = StringSplitter.Create(
                document,
                position,
                root,
                sourceText,
                useTabs,
                tabSize,
                indentStyle,
                cancellationToken
                );

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

            return(splitter.TrySplit());
        }
        public DocumentationCommentSnippet?GetDocumentationCommentSnippetOnCharacterTyped(
            SyntaxTree syntaxTree,
            SourceText text,
            int position,
            DocumentOptionSet options,
            CancellationToken cancellationToken)
        {
            if (!options.GetOption(FeatureOnOffOptions.AutoXmlDocCommentGeneration))
            {
                return(null);
            }

            // Only generate if the position is immediately after '///',
            // and that is the only documentation comment on the target member.

            var token = syntaxTree.GetRoot(cancellationToken).FindToken(position, findInsideTrivia: true);

            if (position != token.SpanStart)
            {
                return(null);
            }

            var lines = GetDocumentationCommentLines(token, text, options, out var indentText);

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

            var newLine = options.GetOption(FormattingOptions.NewLine);

            var lastLine = lines[^ 1];
        private bool InsertOnCommandInvoke(
            SyntaxTree syntaxTree,
            SourceText text,
            int position,
            int originalPosition,
            ITextBuffer subjectBuffer,
            ITextView textView,
            DocumentOptionSet options,
            CancellationToken cancellationToken)
        {
            var targetMember = GetTargetMember(syntaxTree, text, position, cancellationToken);

            if (targetMember == null)
            {
                return(false);
            }

            var startPosition = targetMember.GetFirstToken().SpanStart;
            var line          = text.Lines.GetLineFromPosition(startPosition);

            Debug.Assert(!line.IsEmptyOrWhitespace());

            var lines = GetDocumentationCommentStubLines(targetMember);

            Debug.Assert(lines.Count > 2);

            var newLine = options.GetOption(FormattingOptions.NewLine);

            AddLineBreaks(text, lines, newLine);

            // Add indents
            var lineOffset = line.GetColumnOfFirstNonWhitespaceCharacterOrEndOfLine(options.GetOption(FormattingOptions.TabSize));

            Debug.Assert(line.Start + lineOffset == startPosition);

            var indentText = lineOffset.CreateIndentationString(options.GetOption(FormattingOptions.UseTabs), options.GetOption(FormattingOptions.TabSize));

            for (var i = 1; i < lines.Count; i++)
            {
                lines[i] = indentText + lines[i];
            }

            lines[lines.Count - 1] = lines[lines.Count - 1] + indentText;

            var newText = string.Join(string.Empty, lines);
            var offset  = lines[0].Length + lines[1].Length - newLine.Length;

            subjectBuffer.Insert(startPosition, newText);

            textView.TryMoveCaretToAndEnsureVisible(subjectBuffer.CurrentSnapshot.GetPoint(startPosition + offset));

            return(true);
        }
            public BinaryExpressionCodeActionComputer(
                AbstractBinaryExpressionWrapper <TBinaryExpressionSyntax> service,
                Document document,
                SourceText originalSourceText,
                DocumentOptionSet options,
                TBinaryExpressionSyntax binaryExpression,
                ImmutableArray <SyntaxNodeOrToken> exprsAndOperators,
                CancellationToken cancellationToken
                ) : base(service, document, originalSourceText, options, cancellationToken)
            {
                _exprsAndOperators = exprsAndOperators;
                _preference        = options.GetOption(CodeStyleOptions2.OperatorPlacementWhenWrapping);

                var generator = SyntaxGenerator.GetGenerator(document);

                _newlineBeforeOperatorTrivia = service.GetNewLineBeforeOperatorTrivia(
                    NewLineTrivia
                    );

                _indentAndAlignTrivia = new SyntaxTriviaList(
                    generator.Whitespace(
                        OriginalSourceText
                        .GetOffset(binaryExpression.Span.Start)
                        .CreateIndentationString(UseTabs, TabSize)
                        )
                    );

                _smartIndentTrivia = new SyntaxTriviaList(
                    generator.Whitespace(GetSmartIndentationAfter(_exprsAndOperators[1]))
                    );
            }
 private bool OnlySmartIndentOpenBrace(DocumentOptionSet options)
 {
     // User does not want auto-formatting .  So we only smart indent open braces when typed.
     // Note: there is no specific option for controlling formatting on open brace.  So we
     // don't have the symmetry with OnlySmartIndentCloseBrace.
     return(!options.GetOption(FeatureOnOffOptions.AutoFormattingOnTyping));
 }
Beispiel #9
0
        private static SyntaxNode UseExpressionOrBlockBodyIfDesired(
            DocumentOptionSet documentOptions, ParseOptions parseOptions,
            MethodDeclarationSyntax methodDeclaration, bool createReturnStatementForExpression)
        {
            var expressionBodyPreference = documentOptions.GetOption(CSharpCodeStyleOptions.PreferExpressionBodiedMethods).Value;

            if (methodDeclaration.Body != null && expressionBodyPreference != ExpressionBodyPreference.Never)
            {
                if (methodDeclaration.Body.TryConvertToArrowExpressionBody(
                        methodDeclaration.Kind(), parseOptions, expressionBodyPreference,
                        out var arrowExpression, out var semicolonToken))
                {
                    return(methodDeclaration.WithBody(null)
                           .WithExpressionBody(arrowExpression)
                           .WithSemicolonToken(semicolonToken)
                           .WithAdditionalAnnotations(Formatter.Annotation));
                }
            }
            else if (methodDeclaration.ExpressionBody != null && expressionBodyPreference == ExpressionBodyPreference.Never)
            {
                if (methodDeclaration.ExpressionBody.TryConvertToBlock(
                        methodDeclaration.SemicolonToken, createReturnStatementForExpression, out var block))
                {
                    return(methodDeclaration.WithExpressionBody(null)
                           .WithSemicolonToken(default)
Beispiel #10
0
        private static AccessorDeclarationSyntax UseExpressionOrBlockBodyIfDesired(
            DocumentOptionSet documentOptions, ParseOptions parseOptions,
            AccessorDeclarationSyntax accessorDeclaration)
        {
            var preferExpressionBody = documentOptions.GetOption(CSharpCodeStyleOptions.PreferExpressionBodiedAccessors).Value;

            if (accessorDeclaration?.Body != null && preferExpressionBody)
            {
                if (accessorDeclaration.Body.TryConvertToExpressionBody(
                        parseOptions, out var arrowExpression, out var semicolonToken))
                {
                    return(accessorDeclaration.WithBody(null)
                           .WithExpressionBody(arrowExpression)
                           .WithSemicolonToken(semicolonToken)
                           .WithAdditionalAnnotations(Formatter.Annotation));
                }
            }
            else if (accessorDeclaration?.ExpressionBody != null && !preferExpressionBody)
            {
                var block = accessorDeclaration.ExpressionBody.ConvertToBlock(
                    accessorDeclaration.SemicolonToken,
                    createReturnStatementForExpression: accessorDeclaration.Kind() == SyntaxKind.GetAccessorDeclaration);
                return(accessorDeclaration.WithExpressionBody(null)
                       .WithSemicolonToken(default(SyntaxToken))
                       .WithBody(block)
                       .WithAdditionalAnnotations(Formatter.Annotation));
            }

            return(accessorDeclaration);
        }
Beispiel #11
0
        private int?SplitStringLiteral(
            ITextBuffer subjectBuffer, Document document, DocumentOptionSet options, int position, CancellationToken cancellationToken)
        {
            var useTabs = options.GetOption(FormattingOptions.UseTabs);
            var tabSize = options.GetOption(FormattingOptions.TabSize);

            var root       = document.GetSyntaxRootSynchronously(cancellationToken);
            var sourceText = root.SyntaxTree.GetText(cancellationToken);

            var splitter = StringSplitter.Create(document, position, root, sourceText, useTabs, tabSize, cancellationToken);

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

            return(splitter.TrySplit());
        }
 public static KeyValueLogMessage Create(DocumentOptionSet docOptions)
 {
     return(KeyValueLogMessage.Create(LogType.UserAction, m =>
     {
         foreach (var option in CodeCleanupOptionsProvider.SingletonOptions)
         {
             m[option.Name] = docOptions.GetOption((PerLanguageOption <bool>)option, LanguageNames.CSharp);
         }
     }));
 }
        public SyntaxNode ConvertMethodsToProperty(
            DocumentOptionSet documentOptions, ParseOptions parseOptions,
            SemanticModel semanticModel, SyntaxGenerator generator, GetAndSetMethods getAndSetMethods,
            string propertyName, bool nameChanged)
        {
            var propertyDeclaration = ConvertMethodsToPropertyWorker(
                documentOptions, parseOptions, semanticModel,
                generator, getAndSetMethods, propertyName, nameChanged);

            var expressionBodyPreference = documentOptions.GetOption(CSharpCodeStyleOptions.PreferExpressionBodiedProperties).Value;

            if (expressionBodyPreference != ExpressionBodyPreference.Never)
            {
                if (propertyDeclaration.AccessorList?.Accessors.Count == 1 &&
                    propertyDeclaration.AccessorList?.Accessors[0].Kind() == SyntaxKind.GetAccessorDeclaration)
                {
                    var getAccessor = propertyDeclaration.AccessorList.Accessors[0];
                    if (getAccessor.ExpressionBody != null)
                    {
                        return(propertyDeclaration.WithExpressionBody(getAccessor.ExpressionBody)
                               .WithSemicolonToken(getAccessor.SemicolonToken)
                               .WithAccessorList(null));
                    }
                    else if (getAccessor.Body != null &&
                             getAccessor.Body.TryConvertToExpressionBody(
                                 parseOptions, expressionBodyPreference,
                                 out var arrowExpression, out var semicolonToken))
                    {
                        return(propertyDeclaration.WithExpressionBody(arrowExpression)
                               .WithSemicolonToken(semicolonToken)
                               .WithAccessorList(null));
                    }
                }
            }
            else
            {
                if (propertyDeclaration.ExpressionBody != null &&
                    propertyDeclaration.ExpressionBody.TryConvertToBlock(
                        propertyDeclaration.SemicolonToken,
                        createReturnStatementForExpression: true,
                        block: out var block))
                {
                    var accessor =
                        SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
                        .WithBody(block);

                    var accessorList = SyntaxFactory.AccessorList(SyntaxFactory.SingletonList(accessor));
                    return(propertyDeclaration.WithAccessorList(accessorList)
                           .WithExpressionBody(null)
                           .WithSemicolonToken(default(SyntaxToken)));
                }
            }

            return(propertyDeclaration);
        }
Beispiel #14
0
        private async Task <Document> RemoveSortUsingsAsync(Document document, DocumentOptionSet docOptions, CancellationToken cancellationToken)
        {
            // remove usings
            if (docOptions.GetOption(CodeCleanupOptions.RemoveUnusedImports))
            {
                var removeUsingsService = document.GetLanguageService <IRemoveUnnecessaryImportsService>();
                if (removeUsingsService != null)
                {
                    document = await removeUsingsService.RemoveUnnecessaryImportsAsync(document, cancellationToken).ConfigureAwait(false);
                }
            }

            // sort usings
            if (docOptions.GetOption(CodeCleanupOptions.SortImports))
            {
                document = await OrganizeImportsService.OrganizeImportsAsync(document, cancellationToken).ConfigureAwait(false);
            }

            return(document);
        }
Beispiel #15
0
            static SourceText GetIndentedText(
                SourceText textToIndent,
                TextLine lineToIndent,
                LinePosition desiredCaretLinePosition,
                DocumentOptionSet documentOptions
                )
            {
                // Indent by the amount needed to make the caret line contain the desired indentation column.
                var amountToIndent = desiredCaretLinePosition.Character - lineToIndent.Span.Length;

                // Create and apply a text change with whitespace for the indentation amount.
                var indentText = amountToIndent.CreateIndentationString(
                    documentOptions.GetOption(FormattingOptions.UseTabs),
                    documentOptions.GetOption(FormattingOptions.TabSize)
                    );
                var indentedText = textToIndent.WithChanges(
                    new TextChange(new TextSpan(lineToIndent.End, 0), indentText)
                    );

                return(indentedText);
            }
Beispiel #16
0
            public AbstractCodeActionComputer(
                TWrapper service,
                Document document,
                SourceText originalSourceText,
                DocumentOptionSet options,
                CancellationToken cancellationToken)
            {
                Wrapper            = service;
                OriginalDocument   = document;
                OriginalSourceText = originalSourceText;
                CancellationToken  = cancellationToken;

                UseTabs        = options.GetOption(FormattingOptions.UseTabs);
                TabSize        = options.GetOption(FormattingOptions.TabSize);
                NewLine        = options.GetOption(FormattingOptions.NewLine);
                WrappingColumn = options.GetOption(FormattingOptions.PreferredWrappingColumn);

                var generator = SyntaxGenerator.GetGenerator(document);

                NewLineTrivia          = new SyntaxTriviaList(generator.EndOfLine(NewLine));
                SingleWhitespaceTrivia = new SyntaxTriviaList(generator.Whitespace(" "));
            }
Beispiel #17
0
        private string CreateInsertionTextFromPreviousLine(TextLine previousLine, DocumentOptionSet options)
        {
            var useTabs = options.GetOption(FormattingOptions.UseTabs);
            var tabSize = options.GetOption(FormattingOptions.TabSize);

            var previousLineText         = previousLine.ToString();
            var firstNonWhitespaceColumn = previousLineText.GetColumnOfFirstNonWhitespaceCharacterOrEndOfLine(tabSize);

            var trimmedPreviousLine = previousLineText.Trim();

            Debug.Assert(trimmedPreviousLine.StartsWith(ExteriorTriviaText), "Unexpected: previous line does not begin with doc comment exterior trivia.");

            // skip exterior trivia.
            trimmedPreviousLine = trimmedPreviousLine.Substring(3);

            var firstNonWhitespaceOffsetInPreviousXmlText = trimmedPreviousLine.GetFirstNonWhitespaceOffset();

            var extraIndent = firstNonWhitespaceOffsetInPreviousXmlText != null
                ? trimmedPreviousLine.Substring(0, firstNonWhitespaceOffsetInPreviousXmlText.Value)
                : " ";

            return(firstNonWhitespaceColumn.CreateIndentationString(useTabs, tabSize) + ExteriorTriviaText + extraIndent);
        }
Beispiel #18
0
        private IEnumerable <string> GetEnabledDiagnosticIds(DocumentOptionSet docOptions)
        {
            var diagnosticIds = new List <string>();

            foreach (var tuple in _optionDiagnosticsMappings)
            {
                if (docOptions.GetOption(tuple.Item1))
                {
                    diagnosticIds.AddRange(tuple.Item2);
                }
            }

            return(diagnosticIds);
        }
Beispiel #19
0
        private int?DoSmartIndent(ITextSnapshotLine line, Document document, DocumentOptionSet optionSet, CancellationToken cancellationToken)
        {
            var indentationService = document.GetLanguageService <IIndentationService>();
            var syntaxFactsService = document.GetLanguageService <ISyntaxFactsService>();

            var syntaxTree = document.GetSyntaxTreeSynchronously(cancellationToken);

            var indent = FindTotalParentChainIndent(
                syntaxTree.Root,
                line.Start.Position,
                0,
                optionSet.GetOption(FormattingOptions.IndentationSize),
                indentationService,
                syntaxFactsService);

            return(indent);
        }
        private static IEnumerable <XmlNodeSyntax> ExceptionDocumentation(DocumentOptionSet options, ImmutableArray <String> exceptions)
        {
            ImmutableArrayIterator <String> iterator = new ImmutableArrayIterator <String>(exceptions);

            if (iterator.TryGetNext(out String exception, out iterator))
            {
                String newLine = options.GetOption(FormattingOptions.NewLine);

                yield return(XmlExceptionElement(TypeCref(TypeName(exception)))
                             .WithLeadingTrivia(DocumentationCommentExterior("/// ")));

                while (iterator.TryGetNext(out exception, out iterator))
                {
                    yield return(XmlNewLine(newLine, continueXmlDocumentationComment: true));

                    yield return(XmlExceptionElement(TypeCref(TypeName(exception))));
                }

                yield return(XmlNewLine(newLine, continueXmlDocumentationComment: false));
            }
        }
Beispiel #21
0
        private int GetLeadingWhiteSpace(string text, DocumentOptionSet optionSet)
        {
            var size = 0;

            foreach (var ch in text)
            {
                if (ch == '\t')
                {
                    size += optionSet.GetOption(FormattingOptions.TabSize);
                }
                else if (ch == ' ')
                {
                    size++;
                }
                else
                {
                    break;
                }
            }

            return(size);
        }
        /// <summary>
        /// re-adjust caret position to be the beginning of first text on the line. and make sure the text start at the given indentation
        /// </summary>
        private static void ReadjustIndentation(ITextView view, ITextBuffer subjectBuffer, int firstNonWhitespaceIndex, int indentation, DocumentOptionSet options)
        {
            var lineInSubjectBuffer = view.GetCaretPoint(subjectBuffer).Value.GetContainingLine();

            // first set the caret at the beginning of the text on the line
            view.TryMoveCaretToAndEnsureVisible(new SnapshotPoint(lineInSubjectBuffer.Snapshot, lineInSubjectBuffer.Start + firstNonWhitespaceIndex));

            var document = lineInSubjectBuffer.Snapshot.GetOpenDocumentInCurrentContextWithChanges();

            if (document == null)
            {
                return;
            }

            // and then, insert the text
            document.Project.Solution.Workspace.ApplyTextChanges(document.Id,
                                                                 new TextChange(
                                                                     new TextSpan(
                                                                         lineInSubjectBuffer.Start.Position, firstNonWhitespaceIndex),
                                                                     indentation.CreateIndentationString(options.GetOption(FormattingOptions.UseTabs), options.GetOption(FormattingOptions.TabSize))),
                                                                 CancellationToken.None);
        }
Beispiel #23
0
        private bool TryGenerateDocumentationCommentAfterEnter(
            SyntaxTree syntaxTree,
            SourceText text,
            int position,
            int originalPosition,
            ITextBuffer subjectBuffer,
            ITextView textView,
            DocumentOptionSet options,
            CancellationToken cancellationToken)
        {
            // Find the documentation comment before the new line that was just pressed
            var token = GetTokenToLeft(syntaxTree, position, cancellationToken);

            if (!IsDocCommentNewLine(token))
            {
                return(false);
            }

            var documentationComment = token.GetAncestor <TDocumentationComment>();

            if (!IsSingleExteriorTrivia(documentationComment))
            {
                return(false);
            }

            var targetMember = GetTargetMember(documentationComment);

            if (targetMember == null)
            {
                return(false);
            }

            // Ensure that the target member is only preceded by a single documentation comment (our ///).
            if (GetPrecedingDocumentationCommentCount(targetMember) != 1)
            {
                return(false);
            }

            var line = text.Lines.GetLineFromPosition(documentationComment.FullSpan.Start);

            if (line.IsEmptyOrWhitespace())
            {
                return(false);
            }

            var lines = GetDocumentationCommentStubLines(targetMember);

            Contract.Assume(lines.Count > 2);

            AddLineBreaks(text, lines);

            // Shave off initial exterior trivia
            lines[0] = lines[0].Substring(3);

            // Add indents
            var lineOffset = line.GetColumnOfFirstNonWhitespaceCharacterOrEndOfLine(options.GetOption(FormattingOptions.TabSize));
            var indentText = lineOffset.CreateIndentationString(options.GetOption(FormattingOptions.UseTabs), options.GetOption(FormattingOptions.TabSize));

            for (int i = 1; i < lines.Count; i++)
            {
                lines[i] = indentText + lines[i];
            }

            var newText = string.Join(string.Empty, lines);
            var offset  = lines[0].Length + lines[1].Length - GetNewLine(text).Length;

            // Shave off final line break or add trailing indent if necessary
            var trivia = syntaxTree.GetRoot(cancellationToken).FindTrivia(position, findInsideTrivia: false);

            if (IsEndOfLineTrivia(trivia))
            {
                newText = newText.Substring(0, newText.Length - GetNewLine(text).Length);
            }
            else
            {
                newText += indentText;
            }

            var replaceSpan         = token.Span.ToSpan();
            var currentLine         = text.Lines.GetLineFromPosition(position);
            var currentLinePosition = currentLine.GetFirstNonWhitespacePosition();

            if (currentLinePosition.HasValue)
            {
                replaceSpan = Span.FromBounds(replaceSpan.Start, currentLinePosition.Value);
            }

            subjectBuffer.Replace(replaceSpan, newText);
            textView.TryMoveCaretToAndEnsureVisible(subjectBuffer.CurrentSnapshot.GetPoint(replaceSpan.Start + offset));

            return(true);
        }
 protected override bool PrefersThrowExpression(DocumentOptionSet options)
 => options.GetOption(CSharpCodeStyleOptions.PreferThrowExpression).Value;
Beispiel #25
0
        private bool InsertOnCharacterTyped(
            SyntaxTree syntaxTree,
            SourceText text,
            int position,
            int originalPosition,
            ITextBuffer subjectBuffer,
            ITextView textView,
            DocumentOptionSet options,
            CancellationToken cancellationToken)
        {
            if (!subjectBuffer.GetFeatureOnOffOption(FeatureOnOffOptions.AutoXmlDocCommentGeneration))
            {
                return(false);
            }

            // Only generate if the position is immediately after '///',
            // and that is the only documentation comment on the target member.

            var token = syntaxTree.GetRoot(cancellationToken).FindToken(position, findInsideTrivia: true);

            if (position != token.SpanStart)
            {
                return(false);
            }

            var documentationComment = token.GetAncestor <TDocumentationComment>();

            if (!IsSingleExteriorTrivia(documentationComment))
            {
                return(false);
            }

            var targetMember = GetTargetMember(documentationComment);

            if (targetMember == null)
            {
                return(false);
            }

            // Ensure that the target member is only preceded by a single documentation comment (i.e. our ///).
            if (GetPrecedingDocumentationCommentCount(targetMember) != 1)
            {
                return(false);
            }

            var line = text.Lines.GetLineFromPosition(documentationComment.FullSpan.Start);

            if (line.IsEmptyOrWhitespace())
            {
                return(false);
            }

            var lines = GetDocumentationCommentStubLines(targetMember);

            Contract.Assume(lines.Count > 2);

            AddLineBreaks(text, lines);

            // Shave off initial three slashes
            lines[0] = lines[0].Substring(3);

            // Add indents
            var lineOffset = line.GetColumnOfFirstNonWhitespaceCharacterOrEndOfLine(options.GetOption(FormattingOptions.TabSize));
            var indentText = lineOffset.CreateIndentationString(options.GetOption(FormattingOptions.UseTabs), options.GetOption(FormattingOptions.TabSize));

            for (int i = 1; i < lines.Count - 1; i++)
            {
                lines[i] = indentText + lines[i];
            }

            var lastLine = lines[lines.Count - 1];

            lastLine = indentText + lastLine.Substring(0, lastLine.Length - GetNewLine(text).Length);
            lines[lines.Count - 1] = lastLine;

            var newText = string.Join(string.Empty, lines);
            var offset  = lines[0].Length + lines[1].Length - GetNewLine(text).Length;

            subjectBuffer.Insert(position, newText);
            textView.TryMoveCaretToAndEnsureVisible(subjectBuffer.CurrentSnapshot.GetPoint(position + offset));

            return(true);
        }