public static FormattingContext Create( DocumentUri uri, DocumentSnapshot originalSnapshot, RazorCodeDocument codeDocument, FormattingOptions options, AdhocWorkspaceFactory workspaceFactory, bool isFormatOnType = false) { if (uri is null) { throw new ArgumentNullException(nameof(uri)); } if (originalSnapshot is null) { throw new ArgumentNullException(nameof(originalSnapshot)); } if (codeDocument is null) { throw new ArgumentNullException(nameof(codeDocument)); } if (options is null) { throw new ArgumentNullException(nameof(options)); } if (workspaceFactory is null) { throw new ArgumentNullException(nameof(workspaceFactory)); } var syntaxTree = codeDocument.GetSyntaxTree(); var formattingSpans = syntaxTree.GetFormattingSpans(); var result = new FormattingContext(workspaceFactory) { Uri = uri, OriginalSnapshot = originalSnapshot, CodeDocument = codeDocument, Options = options, IsFormatOnType = isFormatOnType, FormattingSpans = formattingSpans }; var sourceText = codeDocument.GetSourceText(); var indentations = new Dictionary <int, IndentationContext>(); var previousIndentationLevel = 0; for (var i = 0; i < sourceText.Lines.Count; i++) { // Get first non-whitespace character position var nonWsPos = sourceText.Lines[i].GetFirstNonWhitespacePosition(); var existingIndentation = (nonWsPos ?? sourceText.Lines[i].End) - sourceText.Lines[i].Start; // The existingIndentation above is measured in characters, and is used to create text edits // The below is measured in columns, so takes into account tab size. This is useful for creating // new indentation strings var existingIndentationSize = sourceText.Lines[i].GetIndentationSize(options.TabSize); var emptyOrWhitespaceLine = false; if (nonWsPos == null) { emptyOrWhitespaceLine = true; nonWsPos = sourceText.Lines[i].Start; } // position now contains the first non-whitespace character or 0. Get the corresponding FormattingSpan. if (result.TryGetFormattingSpan(nonWsPos.Value, out var span)) { indentations[i] = new IndentationContext(firstSpan: span) { Line = i, RazorIndentationLevel = span.RazorIndentationLevel, HtmlIndentationLevel = span.HtmlIndentationLevel, RelativeIndentationLevel = span.IndentationLevel - previousIndentationLevel, ExistingIndentation = existingIndentation, ExistingIndentationSize = existingIndentationSize, EmptyOrWhitespaceLine = emptyOrWhitespaceLine, }; previousIndentationLevel = span.IndentationLevel; } else { // Couldn't find a corresponding FormattingSpan. Happens if it is a 0 length line. // Let's create a 0 length span to represent this and default it to HTML. var placeholderSpan = new FormattingSpan( new Language.Syntax.TextSpan(nonWsPos.Value, 0), new Language.Syntax.TextSpan(nonWsPos.Value, 0), FormattingSpanKind.Markup, FormattingBlockKind.Markup, razorIndentationLevel: 0, htmlIndentationLevel: 0, isInClassBody: false, componentLambdaNestingLevel: 0); indentations[i] = new IndentationContext(firstSpan: placeholderSpan) { Line = i, RazorIndentationLevel = 0, HtmlIndentationLevel = 0, RelativeIndentationLevel = previousIndentationLevel, ExistingIndentation = existingIndentation, ExistingIndentationSize = existingIndentation, EmptyOrWhitespaceLine = emptyOrWhitespaceLine, }; } } result.Indentations = indentations; return(result); }
public static FormattingContext Create( DocumentUri uri, DocumentSnapshot originalSnapshot, RazorCodeDocument codeDocument, FormattingOptions options, Range range = null, bool isFormatOnType = false) { if (uri is null) { throw new ArgumentNullException(nameof(uri)); } if (originalSnapshot is null) { throw new ArgumentNullException(nameof(originalSnapshot)); } if (codeDocument is null) { throw new ArgumentNullException(nameof(codeDocument)); } if (options is null) { throw new ArgumentNullException(nameof(options)); } var text = codeDocument.GetSourceText(); range ??= TextSpan.FromBounds(0, text.Length).AsRange(text); var result = new FormattingContext() { Uri = uri, OriginalSnapshot = originalSnapshot, CodeDocument = codeDocument, Range = range, Options = options, IsFormatOnType = isFormatOnType }; var source = codeDocument.Source; var syntaxTree = codeDocument.GetSyntaxTree(); var formattingSpans = syntaxTree.GetFormattingSpans(); var indentations = new Dictionary <int, IndentationContext>(); var total = 0; var previousIndentationLevel = 0; for (var i = 0; i < source.Lines.Count; i++) { // Get first non-whitespace character position var lineLength = source.Lines.GetLineLength(i); var nonWsChar = 0; for (var j = 0; j < lineLength; j++) { var ch = source[total + j]; if (!char.IsWhiteSpace(ch) && !ParserHelpers.IsNewLine(ch)) { nonWsChar = j; break; } } // position now contains the first non-whitespace character or 0. Get the corresponding FormattingSpan. if (TryGetFormattingSpan(total + nonWsChar, formattingSpans, out var span)) { indentations[i] = new IndentationContext { Line = i, IndentationLevel = span.IndentationLevel, RelativeIndentationLevel = span.IndentationLevel - previousIndentationLevel, ExistingIndentation = nonWsChar, FirstSpan = span, }; previousIndentationLevel = span.IndentationLevel; } else { // Couldn't find a corresponding FormattingSpan. Happens if it is a 0 length line. // Let's create a 0 length span to represent this and default it to HTML. var placeholderSpan = new FormattingSpan( new Language.Syntax.TextSpan(total + nonWsChar, 0), new Language.Syntax.TextSpan(total + nonWsChar, 0), FormattingSpanKind.Markup, FormattingBlockKind.Markup, indentationLevel: 0, isInClassBody: false); indentations[i] = new IndentationContext { Line = i, IndentationLevel = 0, RelativeIndentationLevel = previousIndentationLevel, ExistingIndentation = nonWsChar, FirstSpan = placeholderSpan, }; } total += lineLength; } result.Indentations = indentations; return(result); }
public static FormattingContext Create( DocumentUri uri, DocumentSnapshot originalSnapshot, RazorCodeDocument codeDocument, FormattingOptions options, Range range = null, bool isFormatOnType = false) { if (uri is null) { throw new ArgumentNullException(nameof(uri)); } if (originalSnapshot is null) { throw new ArgumentNullException(nameof(originalSnapshot)); } if (codeDocument is null) { throw new ArgumentNullException(nameof(codeDocument)); } if (options is null) { throw new ArgumentNullException(nameof(options)); } var text = codeDocument.GetSourceText(); range ??= TextSpan.FromBounds(0, text.Length).AsRange(text); var result = new FormattingContext() { Uri = uri, OriginalSnapshot = originalSnapshot, CodeDocument = codeDocument, Range = range, Options = options, IsFormatOnType = isFormatOnType }; var sourceText = codeDocument.GetSourceText(); var syntaxTree = codeDocument.GetSyntaxTree(); var formattingSpans = syntaxTree.GetFormattingSpans(); var indentations = new Dictionary <int, IndentationContext>(); var previousIndentationLevel = 0; for (var i = 0; i < sourceText.Lines.Count; i++) { // Get first non-whitespace character position var nonWsPos = sourceText.Lines[i].GetFirstNonWhitespacePosition(); var existingIndentation = (nonWsPos ?? sourceText.Lines[i].End) - sourceText.Lines[i].Start; var emptyOrWhitespaceLine = false; if (nonWsPos == null) { emptyOrWhitespaceLine = true; nonWsPos = sourceText.Lines[i].Start; } // position now contains the first non-whitespace character or 0. Get the corresponding FormattingSpan. if (TryGetFormattingSpan(nonWsPos.Value, formattingSpans, out var span)) { indentations[i] = new IndentationContext { Line = i, RazorIndentationLevel = span.RazorIndentationLevel, HtmlIndentationLevel = span.HtmlIndentationLevel, RelativeIndentationLevel = span.IndentationLevel - previousIndentationLevel, ExistingIndentation = existingIndentation, FirstSpan = span, EmptyOrWhitespaceLine = emptyOrWhitespaceLine, }; previousIndentationLevel = span.IndentationLevel; } else { // Couldn't find a corresponding FormattingSpan. Happens if it is a 0 length line. // Let's create a 0 length span to represent this and default it to HTML. var placeholderSpan = new FormattingSpan( new Language.Syntax.TextSpan(nonWsPos.Value, 0), new Language.Syntax.TextSpan(nonWsPos.Value, 0), FormattingSpanKind.Markup, FormattingBlockKind.Markup, razorIndentationLevel: 0, htmlIndentationLevel: 0, isInClassBody: false); indentations[i] = new IndentationContext { Line = i, RazorIndentationLevel = 0, HtmlIndentationLevel = 0, RelativeIndentationLevel = previousIndentationLevel, ExistingIndentation = existingIndentation, FirstSpan = placeholderSpan, EmptyOrWhitespaceLine = emptyOrWhitespaceLine, }; } } result.Indentations = indentations; return(result); }
/// <summary>A Dictionary of int (line number) to IndentationContext.</summary> /// <remarks> /// Don't use this to discover the indentation level you should have, use /// <see cref="TryGetIndentationLevel(int, out int)"/> which operates on the position rather than just the line. /// </remarks> public IReadOnlyDictionary <int, IndentationContext> GetIndentations() { if (_indentations is null) { var sourceText = this.SourceText; var indentations = new Dictionary <int, IndentationContext>(); var previousIndentationLevel = 0; for (var i = 0; i < sourceText.Lines.Count; i++) { var line = sourceText.Lines[i]; // Get first non-whitespace character position var nonWsPos = line.GetFirstNonWhitespacePosition(); var existingIndentation = (nonWsPos ?? line.End) - line.Start; // The existingIndentation above is measured in characters, and is used to create text edits // The below is measured in columns, so takes into account tab size. This is useful for creating // new indentation strings var existingIndentationSize = line.GetIndentationSize(this.Options.TabSize); var emptyOrWhitespaceLine = false; if (nonWsPos is null) { emptyOrWhitespaceLine = true; nonWsPos = line.Start; } // position now contains the first non-whitespace character or 0. Get the corresponding FormattingSpan. if (TryGetFormattingSpan(nonWsPos.Value, out var span)) { indentations[i] = new IndentationContext(firstSpan: span) { Line = i, #if DEBUG DebugOnly_LineText = line.ToString(), #endif RazorIndentationLevel = span.RazorIndentationLevel, HtmlIndentationLevel = span.HtmlIndentationLevel, RelativeIndentationLevel = span.IndentationLevel - previousIndentationLevel, ExistingIndentation = existingIndentation, ExistingIndentationSize = existingIndentationSize, EmptyOrWhitespaceLine = emptyOrWhitespaceLine, }; previousIndentationLevel = span.IndentationLevel; } else { // Couldn't find a corresponding FormattingSpan. Happens if it is a 0 length line. // Let's create a 0 length span to represent this and default it to HTML. var placeholderSpan = new FormattingSpan( new Language.Syntax.TextSpan(nonWsPos.Value, 0), new Language.Syntax.TextSpan(nonWsPos.Value, 0), FormattingSpanKind.Markup, FormattingBlockKind.Markup, razorIndentationLevel: 0, htmlIndentationLevel: 0, isInClassBody: false, componentLambdaNestingLevel: 0); indentations[i] = new IndentationContext(firstSpan: placeholderSpan) { Line = i, #if DEBUG DebugOnly_LineText = line.ToString(), #endif RazorIndentationLevel = 0, HtmlIndentationLevel = 0, RelativeIndentationLevel = previousIndentationLevel, ExistingIndentation = existingIndentation, ExistingIndentationSize = existingIndentation, EmptyOrWhitespaceLine = emptyOrWhitespaceLine, }; } } _indentations = indentations; } return(_indentations); }