private static Task <Document> RefactorAsync( Document document, XmlElementSyntax xmlElement, CancellationToken cancellationToken) { SyntaxList <XmlNodeSyntax> nodes = xmlElement.Content; (TextSpan span1, TextSpan span2, List <TextSpan> spans) = AddParagraphToDocumentationCommentAnalyzer.FindFixableSpan(nodes, stopOnFirstMatch: false, cancellationToken: cancellationToken); var textChanges = new List <TextChange>(); string newLine = nodes .OfType <XmlTextSyntax>() .SelectMany(f => f.TextTokens) .First(f => f.IsKind(SyntaxKind.XmlTextLiteralNewLineToken)) .ValueText; string indentation = SyntaxTriviaAnalysis.DetermineIndentation(xmlElement, cancellationToken).ToString(); string s = $"{newLine}{indentation}/// "; int prevEnd = -1; foreach (TextSpan span in spans) { cancellationToken.ThrowIfCancellationRequested(); if (prevEnd != -1) { textChanges.Add(TextSpan.FromBounds(prevEnd, span.Start), s); } SyntaxToken token = xmlElement.FindToken(span.Start); SyntaxToken endToken = xmlElement.FindToken(span.End - 1); bool isMultiline = xmlElement.SyntaxTree.IsMultiLineSpan(span, cancellationToken); var text = "<para>"; if (isMultiline) { text += s; } int start = token.SpanStart; int length = 0; if (token.IsKind(SyntaxKind.XmlTextLiteralToken) && token.ValueText[0] == ' ') { if (prevEnd == -1) { start++; } else { length++; } } textChanges.Add(new TextSpan(start, length), text); text = ""; if (isMultiline) { text += s; } text += "</para>"; textChanges.Add(new TextSpan(span.End, 0), text); prevEnd = endToken.Span.End; } cancellationToken.ThrowIfCancellationRequested(); return(document.WithTextChangesAsync(textChanges, cancellationToken)); }
internal static (Location Location, string Text)? Verify(XmlElementSyntax e, string format, string?p1, string?p2, string?p3) { var sourceText = e.SyntaxTree.GetText(); var formatPos = 0; var docPos = e.Span.Start; string?parameter = null; while (docPos < e.Span.End && formatPos < format.Length) { if (sourceText[docPos] == format[formatPos]) { formatPos++; docPos++; continue; } if (MoveToContent()) { continue; } if (format[formatPos] == '{') { parameter = NextParameter(); if (IsMatch()) { formatPos = format.IndexOf('}', formatPos) + 1; } else { var token = e.FindToken(docPos, findInsideTrivia: true); if (token.IsKind(SyntaxKind.XmlTextLiteralToken)) { return(ContentError()); } return(token.GetLocation(), parameter); } string NextParameter() { if (parameter == null) { return(p1 ?? throw new FormatException("Too few parameters provided p1 is null.")); } if (parameter == p1) { return(p2 ?? throw new FormatException("Too few parameters provided p2 is null.")); } if (parameter == p2) { return(p3 ?? throw new FormatException("Too few parameters provided p3 is null.")); } throw new FormatException("Too few parameters provided."); } bool IsMatch() { var paramPos = 0; while (paramPos < parameter !.Length && docPos < e.Span.End) { if (sourceText[docPos] == parameter[paramPos]) { paramPos++; docPos++; } else { return(false); } } return(paramPos == parameter.Length); } } else { return(ContentError()); } bool MoveToContent() { var token = e.FindToken(docPos, findInsideTrivia: true); switch (token.Kind()) { case SyntaxKind.XmlTextLiteralNewLineToken: docPos += token.ValueText.Length; return(true); case SyntaxKind.XmlTextLiteralToken when token.HasLeadingTrivia && token.LeadingTrivia.Span.Contains(docPos): docPos += token.LeadingTrivia.Span.Length; return(true); case SyntaxKind.XmlTextLiteralToken when sourceText[docPos] == ' ' &&