in ReSharper.FSharp/src/FSharp/FSharp.Psi/src/CodeFormatter/FSharpCodeFormatterInfoProvider.cs [720:1100]
private void DescribeNestedAlignment(string title, NodeType nodeType) =>
Describe<IndentingRule>()
.Name(title)
.Where(Node().In(nodeType).Satisfies((node, _) => !IsNestedRefOrAppExpr(node.NodeOrNull)))
.Return(IndentType.AlignThrough)
.Build();
private void DescribeChildrenAlignment<TParent>(IBuilderAction<IBlankWithSinglePattern> parentPattern,
IBuilderAction<IBlankWithSinglePattern> nodeParent, Func<TParent, IEnumerable<ITreeNode>> childrenGetter) =>
Describe<IndentingRule>()
.Name("ListLikePatLikeAlignment")
.Where(parentPattern, nodeParent)
.CloseNodeGetter((node, context) => new VirtNode(context, childrenGetter((TParent) node.Parent.NodeOrNull).LastOrDefault()))
.Return(IndentType.AlignThrough)
.Build();
private void DescribeChildrenAlignment<TParent>(NodeTypeSet parent, NodeTypeSet children,
Func<TParent, IEnumerable<ITreeNode>> childrenGetter) =>
DescribeChildrenAlignment(
Parent().In(parent), Node().In(children).Satisfies(IsFirstNodeOfTypeSet(children, false)), childrenGetter);
private void DescribeChildrenAlignment<TParent>(NodeType parent, NodeType children,
Func<TParent, IEnumerable<ITreeNode>> childrenGetter) =>
DescribeChildrenAlignment(
Parent().In(parent), Node().In(children).Satisfies(IsFirstNodeOfItsType), childrenGetter);
private void Formatting()
{
var nodesWithSpaces =
new NodeTypeSet(
ElementType.MATCH_EXPR,
ElementType.CHAR_RANGE_PAT,
ElementType.IS_INST_PAT,
ElementType.LIST_CONS_PAT,
ElementType.TYPED_PAT,
ElementType.MATCH_CLAUSE,
ElementType.F_SHARP_TYPE_DECLARATION,
ElementType.PRIMARY_CONSTRUCTOR_DECLARATION,
ElementType.SECONDARY_CONSTRUCTOR_DECLARATION,
ElementType.ENUM_CASE_DECLARATION,
ElementType.UNION_CASE_DECLARATION,
ElementType.UNION_CASE_FIELD_DECLARATION_LIST,
ElementType.FUNCTION_TYPE_USAGE,
ElementType.TUPLE_TYPE_USAGE,
ElementType.LOCAL_BINDING,
ElementType.TOP_BINDING,
ElementType.INTERFACE_IMPLEMENTATION);
Describe<FormattingRule>()
.Name("DeclarationsSpaces")
.Group(SpaceRuleGroup)
.Where(Parent().In(nodesWithSpaces))
.Return(IntervalFormatType.Space)
.Build();
Describe<FormattingRule>()
.Name("MultilineMatchExpr")
.Group(SpaceRuleGroup)
.Priority(100)
.Where(
Parent().In(ElementType.MATCH_EXPR, ElementType.MATCH_LAMBDA_EXPR),
Right().In(ElementType.MATCH_CLAUSE)
)
.Return(IntervalFormatType.InsertSpace)
.Build();
Describe<FormattingRule>()
.Name("GoodPlacesToWrap")
.Group(WrapRuleGroup | LineBreaksRuleGroup)
.Where(Parent().In(ElementType.PREFIX_APP_EXPR))
.Return(IntervalFormatType.GoodPlaceToWrap)
.Build();
var membersBitset =
ElementBitsets.MODULE_MEMBER_BIT_SET.Union(ElementBitsets.TYPE_BODY_MEMBER_DECLARATION_BIT_SET);
Describe<FormattingRule>()
.Name("LineBreaksBetweenMembers")
.Group(LineBreaksRuleGroup)
.Where(Right().In(membersBitset))
.Return(IntervalFormatType.NewLine)
.Build();
// Describe<FormattingRule>()
// .Name("PipeNewLine")
// .Group(LineBreaksRuleGroup)
// .Where(
// Left().In(ElementBitsets.F_SHARP_EXPRESSION_BIT_SET),
// Right().In(FSharpTokenType.SYMBOLIC_OP), // todo: check pipe op
// If((context, formattingContext) => )
// )
// .Return(IntervalFormatType.NewLine)
// .Build();
Describe<FormattingRule>()
.Name("LineBreakBeforeBindingInExpr")
.Group(LineBreaksRuleGroup)
.Where(
Parent().In(ElementType.LET_OR_USE_EXPR).Satisfies((node, _) => ((ILetOrUseExpr)node.Node).InKeyword == null),
Right().In(ElementBitsets.F_SHARP_EXPRESSION_BIT_SET)
)
.Return(IntervalFormatType.NewLine)
.Build();
// todo: members
Describe<FormattingRule>()
.Name("GoodPlacesToWrap")
.Group(WrapRuleGroup | LineBreaksRuleGroup)
.Where(Parent().In(ElementBitsets.BINDING_BIT_SET), Left().In(FSharpTokenType.EQUALS))
.Return(IntervalFormatType.GoodPlaceToWrap)
.Build();
Describe<FormattingRule>()
.Name("ProhibitWrappingBeforeSemicolon")
.Group(WrapRuleGroup | LineBreaksRuleGroup)
.Where(Right().In(FSharpTokenType.SEMICOLON, FSharpTokenType.COMMA, FSharpTokenType.THEN))
.Return(IntervalFormatType.NoWrap)
.Build();
Describe<FormattingRule>()
.Name("PreferWrappingAfterSemicolon")
.Group(WrapRuleGroup | LineBreaksRuleGroup)
.Where(Left().In(FSharpTokenType.SEMICOLON, FSharpTokenType.COMMA))
.Return(IntervalFormatType.ExcellentPlaceToWrap)
.Build();
Describe<FormattingRule>()
.Name("SpaceAfterPunctuation")
.Group(SpaceRuleGroup)
.Where(Left().In(FSharpTokenType.COLON, FSharpTokenType.RARROW, ElementType.RETURN_TYPE_INFO))
.Return(IntervalFormatType.Space)
.Build();
Describe<FormattingRule>()
.Name("SpaceBeforeColon")
.Group(SpaceRuleGroup)
.Where(Right().In(ElementType.RETURN_TYPE_INFO, FSharpTokenType.COLON))
.Switch(it => it.SpaceBeforeColon, SpaceOptionsBuilders)
.Build();
Describe<FormattingRule>()
.Name("SpaceBeforeColon")
.Group(SpaceRuleGroup)
.Priority(100)
.Where(
Parent().In(ElementBitsets.BINDING_BIT_SET),
Right().In(ElementType.RETURN_TYPE_INFO).Satisfies((node, _) => (node.Node.Parent as IBinding)?.HasParameters ?? false)
)
.Return(IntervalFormatType.Space)
.Build();
Describe<FormattingRule>()
.Name("SpaceAfterComma")
.Group(SpaceRuleGroup)
.Where(Left().In(FSharpTokenType.COMMA))
.Switch(it => it.SpaceAfterComma, SpaceOptionsBuilders)
.Build();
Describe<FormattingRule>()
.Name("NoSpaceBeforeSeparators")
.Group(SpaceRuleGroup)
.Where(Right().In(FSharpTokenType.COMMA, FSharpTokenType.SEMICOLON, FSharpTokenType.SEMICOLON_SEMICOLON, FSharpTokenType.RPAREN))
.Return(IntervalFormatType.Empty)
.Build();
Describe<FormattingRule>()
.Name("NoSpaceBeforeSeparators")
.Group(SpaceRuleGroup)
.Where(Left().In(FSharpTokenType.LPAREN))
.Return(IntervalFormatType.Empty)
.Build();
Describe<FormattingRule>()
.Name("NoSpaceBeforePrimaryCtor")
.Group(SpaceRuleGroup)
.Where(
Parent().In(ElementType.F_SHARP_TYPE_DECLARATION),
Left().In(FSharpTokenType.IDENTIFIER, ElementType.POSTFIX_TYPE_PARAMETER_DECLARATION_LIST),
Right().In(ElementType.PRIMARY_CONSTRUCTOR_DECLARATION, ElementType.POSTFIX_TYPE_PARAMETER_DECLARATION_LIST))
.Return(IntervalFormatType.Empty)
.Build();
Describe<FormattingRule>()
.Name("NoSpaceInsideIndexerLikeList")
.Group(SpaceRuleGroup)
.Priority(1000)
.Where(
Parent().In(ElementType.LIST_EXPR).Satisfies((node, _) =>
node.NodeOrNull is IListExpr listExpr &&
(DotLambdaExprNavigator.GetByExpression(listExpr) != null ||
PrefixAppExprNavigator.GetByArgumentExpression(listExpr) is { IsIndexerLike: true })))
.Return(IntervalFormatType.Empty)
.StartAlternating()
.Where(Left().In(FSharpTokenType.LBRACK))
.Build()
.Where(Right().In(FSharpTokenType.RBRACK))
.Build();
Describe<FormattingRule>()
.Name("NoSpaceBeforeTypeParams")
.Group(SpaceRuleGroup)
.Where(
Parent().In(ElementBitsets.BINDING_BIT_SET),
Left().In(ElementBitsets.F_SHARP_PATTERN_BIT_SET),
Right().In(ElementType.POSTFIX_TYPE_PARAMETER_DECLARATION_LIST)
)
.Return(IntervalFormatType.Empty)
.Build();
DescribeEmptyOnlyFormatting(ElementType.UNIT_EXPR, FSharpTokenType.LPAREN, FSharpTokenType.RPAREN);
DescribeEmptyOnlyFormatting(ElementType.ARRAY_PAT, FSharpTokenType.LBRACK_BAR, FSharpTokenType.BAR_RBRACK);
DescribeEmptyOnlyFormatting(ElementType.LIST_PAT, FSharpTokenType.LBRACK, FSharpTokenType.RBRACK);
DescribeEmptyOnlyFormatting(ElementType.UNIT_PAT, FSharpTokenType.LPAREN, FSharpTokenType.RPAREN);
Describe<FormattingRule>()
.Name("SpaceInLists")
.Group(SpaceRuleGroup)
.Where(
Parent().In(ElementBitsets.ARRAY_OR_LIST_PAT_BIT_SET).Satisfies((node, _) =>
!(node.NodeOrNull is IArrayOrListPat arrayOrListPat && arrayOrListPat.PatternsEnumerable.IsEmpty())))
.Return(IntervalFormatType.Space)
.Build();
Describe<FormattingRule>()
.Name("NoSpaceInArrayTypeUsage")
.Group(SpaceRuleGroup)
.Where(
Parent().In(ElementType.ARRAY_TYPE_USAGE),
Left().In(ElementBitsets.TYPE_USAGE_BIT_SET),
Right().In(FSharpTokenType.LBRACK))
.Return(IntervalFormatType.Empty)
.Build();
Describe<FormattingRule>()
.Name("NoSpaceInListPat")
.Group(SpaceRuleGroup)
.Where(
Parent().In(ElementType.LIST_PAT, ElementType.ARRAY_PAT),
Left().In(FSharpTokenType.LBRACK, FSharpTokenType.LBRACE_BAR),
Right().In(ElementBitsets.F_SHARP_PATTERN_BIT_SET))
.Switch(it => it.SpaceAroundDelimiter, SpaceOptionsBuilders)
.Build();
Describe<FormattingRule>()
.Name("NoSpaceInListPat")
.Group(SpaceRuleGroup)
.Where(
Parent().In(ElementType.LIST_PAT, ElementType.ARRAY_PAT),
Left().In(ElementBitsets.F_SHARP_PATTERN_BIT_SET),
Right().In(FSharpTokenType.RBRACK, FSharpTokenType.BAR_RBRACK))
.Switch(it => it.SpaceAroundDelimiter, SpaceOptionsBuilders)
.Build();
Describe<FormattingRule>()
.Name("AttributeBrackets")
.Group(SpaceRuleGroup | LineBreaksRuleGroup)
.Where(
Parent().In(ElementType.ATTRIBUTE_LIST))
.Return(IntervalFormatType.OnlyEmpty)
.StartAlternating()
.Where(
Left().In(FSharpTokenType.LBRACK_LESS),
Right().In(ElementType.ATTRIBUTE))
.Build()
.Where(
Left().In(ElementType.ATTRIBUTE),
Right().In(FSharpTokenType.GREATER_RBRACK))
.Build();
Describe<FormattingRule>()
.Name("ErrorNodes")
.Group(AllRuleGroup)
.Priority(1000)
.Where(
Right()
.In(ElementType.FROM_ERROR_EXPR, ElementType.FROM_ERROR_PAT)
.Or().In(ElementType.CHAMELEON_EXPRESSION).Satisfies((node, _) => node.IsZeroLength)
)
.Return(IntervalFormatType.ReallyDoNotChangeAnything)
.Build()
.AndViceVersa()
.Build();
Describe<FormattingRule>()
.Group(LineBreaksRuleGroup)
.Name("LineBreakAfterTypeReprAccessModifier")
.Where(
Parent()
.In(ElementBitsets.SIMPLE_TYPE_REPRESENTATION_BIT_SET)
.Satisfies((node, _) => ((ISimpleTypeRepresentation) node.Node).AccessModifier != null),
Right().In(ElementBitsets.ENUM_CASE_LIKE_DECLARATION_BIT_SET).Satisfies(IsFirstNodeOfItsType))
.Switch(settings => settings.LineBreakAfterTypeReprAccessModifier,
When(true).Return(IntervalFormatType.NewLine))
.Build();
Describe<FormattingRule>()
.Group(LineBreaksRuleGroup)
.Name("NewLineBetweenMembers")
.Return(IntervalFormatType.NewLine)
.StartAlternating()
.Where(
Right().In(ElementBitsets.MODULE_MEMBER_BIT_SET.Union(ElementBitsets.TYPE_BODY_MEMBER_DECLARATION_BIT_SET)))
.Build()
.Where(
Left().In(ElementBitsets.MODULE_MEMBER_BIT_SET.Union(ElementBitsets.TYPE_BODY_MEMBER_DECLARATION_BIT_SET)),
Right().Not().In(FSharpTokenType.SEMICOLON))
.Build();
DescribeLineBreakInDeclarationWithEquals("TypeDeclaration",
Node().In(ElementType.F_SHARP_TYPE_DECLARATION),
Node().In(ElementBitsets.TYPE_REPRESENTATION_BIT_SET));
DescribeLineBreakInDeclarationWithEquals("ModuleAbbreviation",
Node().In(ElementType.MODULE_ABBREVIATION_DECLARATION),
Node().In(ElementType.TYPE_REFERENCE_NAME));
Describe<FormattingRule>()
.Group(SpaceRuleGroup)
.Name("SpaceAfterImplicitConstructorDecl")
.Where(Left().HasType(ElementType.PRIMARY_CONSTRUCTOR_DECLARATION))
.Return(IntervalFormatType.Space)
.Build();
Describe<FormattingRule>()
.Group(SpaceRuleGroup)
.Name("SpacesInMemberConstructorDecl")
.Where(Parent().HasType(ElementType.SECONDARY_CONSTRUCTOR_DECLARATION))
.Return(IntervalFormatType.Space)
.Build();
Describe<FormattingRule>()
.Name("SpaceBetweenRecordBindings")
.Where(
Left()
.HasType(ElementType.RECORD_FIELD_BINDING)
.Satisfies((node, _) => ((IRecordFieldBinding) node.Node).Semicolon != null),
Right().HasType(ElementType.RECORD_FIELD_BINDING))
.Return(IntervalFormatType.Space)
.Build();
Describe<FormattingRule>()
.Group(LineBreaksRuleGroup)
.Name("LineBreaksBetweenRecordBindings")
.Where(
Left()
.HasType(ElementType.RECORD_FIELD_BINDING)
.Satisfies((node, _) => ((IRecordFieldBinding) node.Node).Semicolon == null),
Right().HasType(ElementType.RECORD_FIELD_BINDING))
.Return(IntervalFormatType.NewLine)
.Build();
Describe<FormattingRule>()
.Group(LineBreaksRuleGroup)
.Name("NewLineAfterPrecedingAttrList")
.Where(
Parent().In(ElementBitsets.MODULE_DECLARATION_BIT_SET.Union(ElementBitsets.F_SHARP_TYPE_OR_EXTENSION_DECLARATION_BIT_SET).Union(ElementBitsets.TYPE_BODY_MEMBER_DECLARATION_BIT_SET)),
Left().In(ElementType.ATTRIBUTE_LIST),
Right().In(ElementType.ATTRIBUTE_LIST, FSharpTokenType.MODULE, FSharpTokenType.TYPE, FSharpTokenType.AND, FSharpTokenType.OVERRIDE, FSharpTokenType.MEMBER))
.Return(IntervalFormatType.NewLine)
.Build();
Describe<FormattingRule>()
.Group(SpaceRuleGroup)
.Name("SpacesAroundAttrList")
.Where(Left().In(ElementType.ATTRIBUTE_LIST))
.Return(IntervalFormatType.Space)
.Build()
.AndViceVersa()
.Build();
}