in ReSharper.FSharp/src/FSharp/FSharp.Psi/src/CodeFormatter/FSharpCodeFormatterInfoProvider.cs [252:508]
private void Indenting()
{
// continuous indent is wrapping in the middle of a line
// todo: use continuous indent
Describe<IndentingRule>()
.Name("ModuleLikeHeaderIndent")
.Where(
Parent().In(ElementBitsets.TOP_LEVEL_MODULE_LIKE_DECLARATION_BIT_SET),
Node().In(
AccessModifiers.Union(
FSharpTokenType.REC, FSharpTokenType.DOT,
FSharpTokenType.IDENTIFIER, FSharpTokenType.GLOBAL,
ElementType.TYPE_REFERENCE_NAME, ElementType.EXPRESSION_REFERENCE_NAME)))
.Return(IndentType.External)
.Build();
Describe<IndentingRule>()
.Name("Object type repr indenting ")
.Where(Left().In(FSharpTokenType.CLASS, FSharpTokenType.INTERFACE, FSharpTokenType.STRUCT),
Right().In(FSharpTokenType.END), Parent().In(ElementBitsets.OBJECT_MODEL_TYPE_REPRESENTATION_BIT_SET))
.Return(IndentType.Internal)
.Build();
// var pattern = Node().In(ElementType.PAREN_PAT)
// .Satisfies((node, context) => ((IParenPat)node.Node).Pattern is ITuplePat).Or().In(ElementType.PAREN_EXPR)
// .Satisfies((node, context) => ((IParenExpr)node.Node).InnerExpression is ITupleExpr);
//
// var blank = pattern.BuildBlank();
// Describe<IndentingRule>()
// .Name("Yo")
// .Where(
// Parent().Is(blank),
// Left().In(FSharpTokenType.LPAREN),
// Right().In(FSharpTokenType.RPAREN))
// .Return(IndentType.Internal | IndentType.NonSticky)
// .Build();
var simpleIndentingNodes = new[]
{
("ForExpr", ElementType.FOR_EXPR, ForExpr.DO_EXPR),
("ForEachExpr", ElementType.FOR_EACH_EXPR, ForEachExpr.DO_EXPR),
("WhileExpr", ElementType.WHILE_EXPR, WhileExpr.DO_EXPR),
("DoExpr", ElementType.DO_EXPR, DoExpr.EXPR),
("AssertExpr", ElementType.ASSERT_EXPR, AssertExpr.EXPR),
("LazyExpr", ElementType.LAZY_EXPR, LazyExpr.EXPR),
("ComputationExpr", ElementType.COMPUTATION_EXPR, ComputationExpr.EXPR),
("SetExpr", ElementType.SET_EXPR, SetExpr.RIGHT_EXPR),
("TryFinally_TryExpr", ElementType.TRY_FINALLY_EXPR, TryFinallyExpr.TRY_EXPR),
("TryFinally_FinallyExpr", ElementType.TRY_FINALLY_EXPR, TryFinallyExpr.FINALLY_EXPR),
("TryWith_TryExpr", ElementType.TRY_WITH_EXPR, TryWithExpr.TRY_EXPR),
("IfThenExpr", ElementType.IF_THEN_ELSE_EXPR, IfThenElseExpr.THEN_EXPR),
("ElifThenExpr", ElementType.ELIF_EXPR, ElifExpr.THEN_EXPR),
("MatchExpr_Expr", ElementType.MATCH_EXPR, MatchExpr.EXPR),
("MatchExpr_With", ElementType.MATCH_EXPR, MatchExpr.WITH),
};
simpleIndentingNodes
.ToList()
.ForEach(DescribeSimpleIndentingRule);
Describe<IndentingRule>()
.Name("LambdaExprBodyIndent")
.Where(
Node().HasRole(LambdaExpr.EXPR).Or().In(FSharpTokenType.LINE_COMMENT, FSharpTokenType.BLOCK_COMMENT).Before(Node().HasRole(LambdaExpr.EXPR))) // todo: add set
.StartAlternating()
.Where(
Parent().HasType(ElementType.LAMBDA_EXPR).Satisfies((node, _) => node.HasNewLineBefore()))
.Return(IndentType.External | IndentType.NonSticky)
.Build()
.Where(
Parent().HasType(ElementType.LAMBDA_EXPR).Satisfies((node, _) => !node.HasNewLineBefore()))
.Return(IndentType.External)
.Build();
DescribeHeaderRule("LambdaExpr", ElementType.LAMBDA_EXPR, FSharpTokenType.FUN, FSharpTokenType.RARROW);
DescribeHeaderRule("ObjExpr", ElementType.OBJ_EXPR, FSharpTokenType.NEW, FSharpTokenType.WITH);
var continuousIndentNodes =
new NodeTypeSet(
ElementType.UNIT_EXPR,
ElementType.REFERENCE_EXPR,
ElementType.PREFIX_APP_EXPR,
ElementType.ARRAY_PAT,
ElementType.CHAR_RANGE_PAT,
ElementType.IS_INST_PAT,
ElementType.LIST_PAT,
ElementType.TYPED_PAT,
ElementType.UNIT_PAT,
ElementType.PARAMETERS_OWNER_PAT,
ElementType.ARRAY_TYPE_USAGE,
ElementType.FUNCTION_TYPE_USAGE,
ElementType.NAMED_TYPE_USAGE,
ElementType.LOCAL_BINDING,
ElementType.TOP_BINDING,
ElementType.EXPRESSION_REFERENCE_NAME,
ElementType.TYPE_REFERENCE_NAME,
ElementType.UNION_CASE_FIELD_DECLARATION,
ElementType.NESTED_MODULE_DECLARATION,
ElementType.F_SHARP_TYPE_DECLARATION,
ElementType.TYPE_EXTENSION_DECLARATION,
ElementType.OPEN_STATEMENT,
ElementType.EXCEPTION_DECLARATION,
ElementType.UNION_CASE_DECLARATION,
ElementType.ENUM_CASE_DECLARATION,
ElementType.INTERFACE_IMPLEMENTATION,
ElementType.MODULE_ABBREVIATION_DECLARATION)
.Union(ElementBitsets.TYPE_BODY_MEMBER_DECLARATION_BIT_SET)
.Except(ElementType.LET_BINDINGS_DECLARATION);
Describe<ContinuousIndentRule>()
.Name("ContinuousIndent")
.Where(Node().In(continuousIndentNodes.Except(ElementType.MEMBER_DECLARATION)).Satisfies((node, _) => !(IsNestedRefOrAppExpr(node.NodeOrNull))))
.AddException(Node().In(ElementType.ATTRIBUTE_LIST, ElementType.DOC_COMMENT_BLOCK))
.AddException(Node().In(ElementType.COMPUTATION_EXPR).Satisfies((node, _) =>
!node.HasNewLineBefore()))
.Build();
Describe<ContinuousIndentRule>()
.Name("ContinuousIndentDouble").DefaultMultiplier(1) // use 2 // use multiplier setting instead of default multiplier
.Where(Node().In(ElementType.MEMBER_DECLARATION))
.AddException(Node().In(ElementType.ATTRIBUTE_LIST, ElementType.DOC_COMMENT_BLOCK))
.AddException(Node().In(ElementType.CHAMELEON_EXPRESSION))
.Build();
Describe<IndentingRule>()
.Name("MemberDeclBody")
.Where(
Node().In(ElementType.CHAMELEON_EXPRESSION),
Parent().In(ElementType.MEMBER_DECLARATION))
.Return(IndentType.External)
.Build();
Describe<IndentingRule>()
.Name("ObjExprIndent")
.Where(
Parent().In(ElementType.OBJ_EXPR),
Left().In(FSharpTokenType.LBRACE),
Right().In(FSharpTokenType.RBRACE))
.Return(IndentType.Internal)
.Build();
Describe<FSharpContinuousIndentRule>()
.Name("FSharpContinuousIndentRule")
.Where(Node().In(ElementType.MATCH_CLAUSE))
.AddException(
Parent().In(ElementType.MATCH_CLAUSE).Satisfies(IsLastNodeOfItsType),
Node().In(ElementBitsets.F_SHARP_EXPRESSION_BIT_SET).Satisfies((node, context) =>
AreAligned(node, node.Parent, context.CodeFormatter)))
.AddException(
Parent().In(ElementType.MATCH_CLAUSE),
Node().In(ElementType.OR_PAT))
.Build();
// External: starts/ends at first/last node in interval
// Internal: skips first/last node in interval
var memberOrRepr =
ElementBitsets.TYPE_BODY_MEMBER_DECLARATION_BIT_SET.Union(ElementBitsets.TYPE_REPRESENTATION_BIT_SET);
FixPartialSelectionMemberIndentingRule(ElementType.NESTED_MODULE_DECLARATION, ElementBitsets.MODULE_MEMBER_BIT_SET);
FixPartialSelectionMemberIndentingRule(ElementType.F_SHARP_TYPE_DECLARATION, memberOrRepr);
FixPartialSelectionMemberIndentingRule(ElementType.TYPE_EXTENSION_DECLARATION, memberOrRepr);
FixPartialSelectionMemberIndentingRule(ElementType.OBJ_EXPR, ElementBitsets.TYPE_BODY_MEMBER_DECLARATION_BIT_SET);
FixPartialSelectionMemberIndentingRule(ElementType.INTERFACE_IMPLEMENTATION, memberOrRepr);
FixPartialSelectionMemberIndentingRule(ElementType.CLASS_REPRESENTATION, memberOrRepr);
FixPartialSelectionMemberIndentingRule(ElementType.INTERFACE_REPRESENTATION, memberOrRepr);
FixPartialSelectionMemberIndentingRule(ElementType.STRUCT_REPRESENTATION, memberOrRepr);
FixPartialSelectionMemberIndentingRule(ElementType.ENUM_REPRESENTATION, new NodeTypeSet(ElementType.ENUM_CASE_DECLARATION));
FixPartialSelectionMemberIndentingRule(ElementType.UNION_REPRESENTATION, new NodeTypeSet(ElementType.UNION_CASE_DECLARATION));
Describe<IndentingRule>()
.Name("ObjExprInterfaceImpl")
.Where(
Parent().In(ElementType.OBJ_EXPR),
Node().In(ElementType.INTERFACE_IMPLEMENTATION))
.Calculate((node, context) =>
{
if (node == null || context == null)
return new ConstantOptionNode(new IndentOptionValue(IndentType.StartAtExternal | IndentType.EndAtExternal));
var treeNode = (VirtNode)node;
var objExpr = ObjExprNavigator.GetByInterfaceImplementation((IInterfaceImplementation)treeNode.Node);
var newKeyword = objExpr?.NewKeyword;
if (newKeyword == null) // todo: formatter: check this
return new ConstantOptionNode(new IndentOptionValue(IndentType.StartAtExternal | IndentType.EndAtExternal));
var newKeywordVirtNode = new VirtNode(context, newKeyword);
var newKeywordIndent = newKeywordVirtNode.CalcNodeIndent(context.TabWidth);
return
new ConstantOptionNode(
new IndentOptionValue(
IndentType.AbsoluteIndent | IndentType.StartAtExternal | IndentType.EndAtExternal |
IndentType.NonSticky | IndentType.NonAdjustable, 0, newKeywordIndent));
})
.Build();
Describe<IndentingRule>()
.Name("SimpleTypeRepr_Accessibility")
.Where(
Parent().In(ElementBitsets.ENUM_LIKE_TYPE_REPRESENTATION_BIT_SET),
Left().In(ElementBitsets.ENUM_CASE_LIKE_DECLARATION_BIT_SET).Satisfies((node, _) =>
AccessModifiers[node.GetPreviousMeaningfulSibling().GetTokenType()]))
.CloseNodeGetter((node, _) => node.Parent.LastChild)
.Return(IndentType.External)
.Build();
Describe<IndentingRule>()
.Name("TryWith_WithClauseIndent")
.Where(
Parent().HasType(ElementType.TRY_WITH_EXPR),
Node().HasRole(TryWithExpr.MATCH_CLAUSE))
.Switch(
settings => settings.IndentOnTryWith,
When(true).Return(IndentType.External),
When(false).Return(IndentType.None))
.Build();
Describe<IndentingRule>()
.Name("ElseExprIndent")
.Where(
Parent().In(ElementType.IF_THEN_ELSE_EXPR, ElementType.ELIF_EXPR),
Node()
.HasRole(IfThenElseExpr.ELSE_CLAUSE)
.Satisfies(IndentElseExpr)
.Or()
.HasRole(ElifExpr.ELSE_CLAUSE)
.Satisfies(IndentElseExpr))
.Return(IndentType.External)
.Build();
Describe<IndentingRule>()
.Name("MatchClauseWhenExprIndent")
.Where(
Parent().HasType(ElementType.MATCH_CLAUSE),
Node().HasRole(MatchClause.WHEN_CLAUSE))
.Return(IndentType.External)
.Build();
Describe<IndentingRule>()
.Name("DoDeclIndent")
.Where(
Parent()
.HasType(ElementType.DO_STATEMENT),
Node().HasRole(DoStatement.CHAMELEON_EXPR))
.Return(IndentType.External)
.Build();
}