private void Indenting()

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();
    }