private string CountAndReplaceIndentSpaces(string line, out int count) { StringBuilder sb = new StringBuilder(); count = 0; for (int i = 0; i < line.Length; i++) { char c = line[i]; if (c == ' ') { sb.Append(' '); count++; } else if (c == '\t') { int newCount = CharHelper.AddTab(count); sb.Append(' ', newCount - count); count = newCount; } else { sb.Append(line, i, line.Length - i); break; } } return(sb.ToString()); }
/// <summary> /// Parses the indentation from the current position in the line, updating <see cref="StartBeforeIndent"/>, /// <see cref="ColumnBeforeIndent"/>, <see cref="Start"/> and <see cref="Column"/> accordingly /// taking into account space taken by tabs. /// </summary> public void ParseIndent() { var c = CurrentChar; var previousStartBeforeIndent = StartBeforeIndent; var startBeforeIndent = Start; var previousColumnBeforeIndent = ColumnBeforeIndent; var columnBeforeIndent = Column; while (c != '\0') { if (c == '\t') { Column = CharHelper.AddTab(Column); } else if (c == ' ') { Column++; } else { break; } c = Line.NextChar(); } if (columnBeforeIndent == Column) { StartBeforeIndent = previousStartBeforeIndent; ColumnBeforeIndent = previousColumnBeforeIndent; } else { StartBeforeIndent = startBeforeIndent; ColumnBeforeIndent = columnBeforeIndent; } }
/// <summary> /// Appends the specified line to this instance. /// </summary> /// <param name="slice">The slice.</param> /// <param name="column">The column.</param> /// <param name="line">The line.</param> /// <param name="sourceLinePosition"></param> public void AppendLine(ref StringSlice slice, int column, int line, int sourceLinePosition) { if (Lines.Lines == null) { Lines = new StringLineGroup(4); } var stringLine = new StringLine(ref slice, line, column, sourceLinePosition); // Regular case, we are not in the middle of a tab if (slice.CurrentChar != '\t' || !CharHelper.IsAcrossTab(column)) { Lines.Add(ref stringLine); } else { // We need to expand tabs to spaces var builder = StringBuilderCache.Local(); for (int i = column; i < CharHelper.AddTab(column); i++) { builder.Append(' '); } builder.Append(slice.Text, slice.Start + 1, slice.Length - 1); stringLine.Slice = new StringSlice(builder.ToString()); Lines.Add(ref stringLine); } }
/// <summary> /// Unwind any previous indent from the current character back to the first space. /// </summary> public void UnwindAllIndents() { // Find the previous first space on the current line var previousStart = Line.Start; for (; Line.Start > originalLineStart; Line.Start--) { var c = Line.PeekCharAbsolute(Line.Start - 1); if (c == 0) { break; } if (!c.IsSpaceOrTab()) { break; } } var targetStart = Line.Start; // Nothing changed? Early exit if (previousStart == targetStart) { return; } // TODO: factorize the following code with what is done with GoToColumn // If we have found the first space, we need to recalculate the correct column Line.Start = originalLineStart; Column = 0; ColumnBeforeIndent = 0; StartBeforeIndent = originalLineStart; for (; Line.Start < targetStart; Line.Start++) { var c = Line.Text[Line.Start]; if (c == '\t') { Column = CharHelper.AddTab(Column); } else { if (!c.IsSpaceOrTab()) { ColumnBeforeIndent = Column + 1; StartBeforeIndent = Line.Start + 1; } Column++; } } // Reset the indent ColumnBeforeIndent = Column; StartBeforeIndent = Start; }
/// <summary> /// Returns the next character in the line being processed. Update <see cref="Start"/> and <see cref="Column"/>. /// </summary> /// <returns>The next character or `\0` if end of line is reached</returns> public char NextChar() { var c = Line.CurrentChar; if (c == '\t') { Column = CharHelper.AddTab(Column); } else { Column++; } return(Line.NextChar()); }
/// <summary> /// Moves to the position to the specified column position, taking into account spaces in tabs. /// </summary> /// <param name="newColumn">The new column position to move the cursor to.</param> public void GoToColumn(int newColumn) { // Optimized path when we are moving above the previous start of indent if (newColumn >= ColumnBeforeIndent) { Line.Start = StartBeforeIndent; Column = ColumnBeforeIndent; } else { Line.Start = originalLineStart; Column = 0; ColumnBeforeIndent = 0; StartBeforeIndent = originalLineStart; } for (; Line.Start <= Line.End && Column < newColumn; Line.Start++) { var c = Line.Text[Line.Start]; if (c == '\t') { Column = CharHelper.AddTab(Column); } else { if (!c.IsSpaceOrTab()) { ColumnBeforeIndent = Column + 1; StartBeforeIndent = Line.Start + 1; } Column++; } } if (Column > newColumn) { Column = newColumn; if (Line.Start > 0) { Line.Start--; } } }