Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementing align doc type + using it for classes #279

Merged
merged 4 commits into from
Jun 10, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 31 additions & 4 deletions Src/CSharpier.Tests/DocPrinterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -616,6 +616,26 @@ public void Conditional_Group_Does_Not_Propagate_Breaks_To_Parent()
PrintedDocShouldBe(doc, "1 2", 10);
}

[Test]
public void Align_Should_Print_Basic_Case()
{
var doc = Doc.Concat("+ ", Doc.Align(2, Doc.Group("1", Doc.HardLine, "2")));
PrintedDocShouldBe(doc, $"+ 1{NewLine} 2");
}

[Test]
public void Align_Should_Convert_Non_Trailing_Spaces_To_Tabs()
{
var doc = Doc.Concat(
"+ ",
Doc.Align(
2,
Doc.Indent(Doc.Concat("+ ", Doc.Align(2, Doc.Group("1", Doc.HardLine, "2"))))
)
);
PrintedDocShouldBe(doc, $"+ + 1{NewLine}\t\t 2", useTabs: true);
}

[Test]
public void Scratch()
{
Expand All @@ -627,21 +647,28 @@ private static void PrintedDocShouldBe(
Doc doc,
string expected,
int width = PrinterOptions.WidthUsedByTests,
bool trimInitialLines = false
bool trimInitialLines = false,
bool useTabs = false
) {
var result = Print(doc, width, trimInitialLines);
var result = Print(doc, width, trimInitialLines, useTabs);

result.Should().Be(expected);
}

private static string Print(
Doc doc,
int width = PrinterOptions.WidthUsedByTests,
bool trimInitialLines = false
bool trimInitialLines = false,
bool useTabs = false
) {
return DocPrinter.DocPrinter.Print(
doc,
new PrinterOptions { Width = width, TrimInitialLines = trimInitialLines, },
new PrinterOptions
{
Width = width,
TrimInitialLines = trimInitialLines,
UseTabs = useTabs
},
Environment.NewLine
)
.TrimEnd('\r', '\n');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ class NoModifiers { }

public class WithInterface : IInterface { }

public class WithReallyLongNameInterface :
IReallyLongNameLetsMakeThisBreak___________________________ { }
public class WithReallyLongNameInterface
: IReallyLongNameLetsMakeThisBreak___________________________ { }

public class ThisIsSomeLongNameAndItShouldFormatWell1 :
AnotherLongClassName,
AndYetAnotherLongClassName,
AndStillOneMore { }
public class ThisIsSomeLongNameAndItShouldFormatWell1
: AnotherLongClassName,
AndYetAnotherLongClassName,
AndStillOneMore { }

public class SimpleGeneric<T>
where T : new() { }
Expand All @@ -36,9 +36,24 @@ public class LongerClassNameWithLotsOfGenerics<
public class SimpleGeneric<T> : BaseClass<T>
where T : new() { }

public class ThisIsSomeLongNameAndItShouldFormatWell2<T, T2, T3> :
AnotherLongClassName<T>,
AnotherClassName
public class ThisIsSomeLongNameAndItShouldFormatWell2<T, T2, T3>
: AnotherLongClassName<T>,
AnotherClassName
where T : new(), AnotherTypeConstraint
where T2 : new()
where T3 : new() { }

public class IdentityDbContext<TUser, TRole, TKey>
: IdentityDbContext<
TUser,
TRole,
TKey,
IdentityUserClaim<TKey>,
IdentityUserRole<TKey>,
IdentityUserLogin<TKey>,
IdentityRoleClaim<TKey>,
IdentityUserToken<TKey>
>
where TUser : IdentityUser<TKey>
where TRole : IdentityRole<TKey>
where TKey : IEquatable<TKey> { }
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ record PC(string x) : PrimaryConstructor(x) { }

record RecordWithoutBody(string property);

record LongerRecordNameWhatHappens_________________________________________(string x) :
R4<string>(x) { }
record LongerRecordNameWhatHappens_________________________________________(string x)
: R4<string>(x) { }

record GenericRecord<T>(T Result);
13 changes: 10 additions & 3 deletions Src/CSharpier/DocPrinter/DocFitter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ public static bool Fits(
PrintCommand nextCommand,
Stack<PrintCommand> remainingCommands,
int remainingWidth,
PrinterOptions printerOptions,
Dictionary<string, PrintMode> groupModeMap
Dictionary<string, PrintMode> groupModeMap,
Indenter indenter
) {
var returnFalseIfMoreStringsFound = false;
var newCommands = new Stack<PrintCommand>();
Expand Down Expand Up @@ -83,7 +83,7 @@ void Push(Doc doc, PrintMode printMode, Indent indent)
Push(
indent.Contents,
currentMode,
IndentBuilder.Make(currentIndent, printerOptions)
indenter.IncreaseIndent(currentIndent)
);
break;
case Trim:
Expand Down Expand Up @@ -146,6 +146,13 @@ is ConditionalGroup conditionalGroup
break;
case BreakParent:
break;
case Align align:
Push(
align.Contents,
currentMode,
indenter.AddAlign(currentIndent, align.Width)
);
break;
default:
throw new Exception("Can't handle " + currentDoc.GetType());
}
Expand Down
15 changes: 9 additions & 6 deletions Src/CSharpier/DocPrinter/DocPrinter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@ public class DocPrinter
protected bool SkipNextNewLine;
protected readonly string EndOfLine;
protected readonly PrinterOptions PrinterOptions;
protected readonly Indenter Indenter;

protected DocPrinter(Doc doc, PrinterOptions printerOptions, string endOfLine)
{
EndOfLine = endOfLine;
PrinterOptions = printerOptions;
RemainingCommands.Push(
new PrintCommand(IndentBuilder.MakeRoot(), PrintMode.Break, doc)
);
Indenter = new Indenter(printerOptions);
RemainingCommands.Push(new PrintCommand(Indenter.GenerateRoot(), PrintMode.Break, doc));
}

public static string Print(Doc document, PrinterOptions printerOptions, string endOfLine)
Expand Down Expand Up @@ -78,7 +78,7 @@ private void ProcessNextCommand()
break;
}
case IndentDoc indentDoc:
Push(indentDoc.Contents, mode, IndentBuilder.Make(indent, PrinterOptions));
Push(indentDoc.Contents, mode, Indenter.IncreaseIndent(indent));
break;
case Trim:
CurrentWidth -= Output.TrimTrailingWhitespace();
Expand Down Expand Up @@ -128,6 +128,9 @@ private void ProcessNextCommand()
case ForceFlat forceFlat:
Push(forceFlat.Contents, PrintMode.Flat, indent);
break;
case Align align:
Push(align.Contents, mode, Indenter.AddAlign(indent, align.Width));
break;
default:
throw new Exception("didn't handle " + doc);
}
Expand Down Expand Up @@ -271,8 +274,8 @@ private bool Fits(PrintCommand possibleCommand)
possibleCommand,
RemainingCommands,
PrinterOptions.Width - CurrentWidth,
PrinterOptions,
GroupModeMap
GroupModeMap,
Indenter
);
}

Expand Down
129 changes: 115 additions & 14 deletions Src/CSharpier/DocPrinter/Indent.cs
Original file line number Diff line number Diff line change
@@ -1,36 +1,137 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace CSharpier.DocPrinter
{
public record Indent(string Value, int Length);
public class Indent
{
public string Value = string.Empty;
public int Length;
public IList<IIndentType>? TypesForTabs;
}

public interface IIndentType { }

public class IndentType : IIndentType
{
protected IndentType() { }

public static IndentType Instance = new();
}

public class AlignType : IIndentType
{
public int Width { get; init; }
}

public static class IndentBuilder
public class Indenter
{
public static Indent MakeRoot()
protected readonly PrinterOptions PrinterOptions;

public Indenter(PrinterOptions printerOptions)
{
return new Indent(string.Empty, 0);
PrinterOptions = printerOptions;
}

public static Indent Make(Indent indent, PrinterOptions printerOptions)
public Indent GenerateRoot()
{
return GenerateIndent(indent, printerOptions);
return new();
}

private static Indent GenerateIndent(Indent indent, PrinterOptions printerOptions)
public Indent IncreaseIndent(Indent indent)
{
if (printerOptions.UseTabs)
if (PrinterOptions.UseTabs)
{
return new Indent(indent.Value + "\t", indent.Length + printerOptions.TabWidth);
if (indent.TypesForTabs != null)
{
return MakeIndentWithTypesForTabs(indent, IndentType.Instance);
}

return new Indent
{
Value = indent.Value + "\t",
Length = indent.Length + PrinterOptions.TabWidth
};
}
else
{
return new Indent(
indent.Value + new string(' ', printerOptions.TabWidth),
indent.Length + printerOptions.TabWidth
);
return new Indent
{
Value = indent.Value + new string(' ', PrinterOptions.TabWidth),
Length = indent.Length + PrinterOptions.TabWidth
};
}
}

public Indent AddAlign(Indent indent, int alignment)
{
if (PrinterOptions.UseTabs)
{
return MakeIndentWithTypesForTabs(indent, new AlignType { Width = alignment });
}
else
{
return new Indent
{
Value = indent.Value + new string(' ', alignment),
Length = indent.Length + alignment
};
}
}

// when using tabs we need to sometimes replace the spaces from align with tabs
// trailing aligns stay as spaces, but any aligns before a tab get converted to a single tab
// see https://github.com/prettier/prettier/blob/main/commands.md#align
private Indent MakeIndentWithTypesForTabs(Indent indent, IIndentType nextIndentType)
{
List<IIndentType> types;

// if it doesn't exist yet, then all values on it are regular indents, not aligns
if (indent.TypesForTabs == null)
{
types = new List<IIndentType>();
for (var x = 0; x < indent.Value.Length; x++)
{
types.Add(IndentType.Instance);
}
}
else
{
var placeTab = false;
types = new List<IIndentType>(indent.TypesForTabs);
for (var x = types.Count - 1; x >= 0; x--)
{
if (types[x] == IndentType.Instance)
{
placeTab = true;
}

if (placeTab)
{
types[x] = IndentType.Instance;
}
}
}

types.Add(nextIndentType);

var length = 0;
var value = new StringBuilder();
foreach (var indentType in types)
{
if (indentType is AlignType alignType)
{
value.Append(' ', alignType.Width);
length += alignType.Width;
}
else
{
value.Append('\t');
length += PrinterOptions.TabWidth;
}
}

return new Indent { Length = length, Value = value.ToString(), TypesForTabs = types };
}
}
}
1 change: 1 addition & 0 deletions Src/CSharpier/DocSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ string PrintConcat(Concat concatToPrint)
LineDoc lineDoc => indent
+ (lineDoc.Type == LineDoc.LineType.Normal ? "Doc.Line" : "Doc.SoftLine"),
BreakParent => "",
Align align => $"{indent}Doc.Align({align.Width}, {PrintIndentedDocTree(align.Contents)})",
Trim => $"{indent}Doc.Trim",
ForceFlat forceFlat => $"{indent}Doc.ForceFlat({newLine}{PrintIndentedDocTree(forceFlat.Contents)})",
IndentDoc indentDoc => $"{indent}Doc.Indent({newLine}{PrintIndentedDocTree(indentDoc.Contents)}{newLine}{indent})",
Expand Down
21 changes: 21 additions & 0 deletions Src/CSharpier/DocTypes/Align.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using System;

namespace CSharpier.DocTypes
{
public class Align : Doc, IHasContents
{
public int Width { get; }
public Doc Contents { get; }

public Align(int width, Doc contents)
{
if (width < 1)
{
throw new Exception($"{nameof(width)} must be >= 1");
}

this.Width = width;
this.Contents = contents;
}
}
}
4 changes: 3 additions & 1 deletion Src/CSharpier/DocTypes/Doc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ public static IndentIfBreak IndentIfBreak(Doc contents, string groupId) =>
public static Doc Directive(string value) => new StringDoc(value, true);

public static ConditionalGroup ConditionalGroup(params Doc[] options) => new(options);

public static Align Align(int alignment, Doc contents) => new(alignment, contents);
}

public enum CommentType
Expand All @@ -117,6 +119,6 @@ public enum CommentType

interface IHasContents
{
Doc Contents { get; set; }
Doc Contents { get; }
}
}
Loading