<commit_before>package com.intellij.formatting;

import com.intellij.lang.Language;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.List;

/**
 * @author yole
 */
public class SpacingBuilder {
  private static class SpacingRule {
    protected final RuleCondition myRuleCondition;
    protected final int myMinSpaces;
    protected final int myMaxSpaces;
    protected final int myMinLF;
    protected final boolean myKeepLineBreaks;
    protected final int myKeepBlankLines;

    private SpacingRule(@NotNull RuleCondition condition, int minSpaces, int maxSpaces, int minLF, boolean keepLineBreaks, int keepBlankLines) {
      myRuleCondition = condition;
      myMinSpaces = minSpaces;
      myMaxSpaces = maxSpaces;
      myMinLF = minLF;
      myKeepLineBreaks = keepLineBreaks;
      myKeepBlankLines = keepBlankLines;
    }

    public boolean matches(@NotNull ASTBlock parentBlock, @NotNull ASTBlock childBlock1, @NotNull ASTBlock childBlock2) {
      return myRuleCondition.matches(parentBlock.getNode().getElementType(),
                                     childBlock1.getNode().getElementType(),
                                     childBlock2.getNode().getElementType());
    }

    public Spacing createSpacing(@NotNull ASTBlock parentBlock, @NotNull ASTBlock childBlock1, @NotNull ASTBlock childBlock2) {
      return Spacing.createSpacing(myMinSpaces, myMaxSpaces, myMinLF, myKeepLineBreaks, myKeepBlankLines);
    }
  }

  private static class DependentLFSpacingRule extends SpacingRule {
    public DependentLFSpacingRule(@NotNull RuleCondition condition,
                                  int minSpaces,
                                  int maxSpaces,
                                  boolean keepLineBreaks,
                                  int keepBlankLines) {
      super(condition, minSpaces, maxSpaces, 1, keepLineBreaks, keepBlankLines);
    }

    @Override
    public Spacing createSpacing(@NotNull ASTBlock parentBlock, @NotNull ASTBlock childBlock1, @NotNull ASTBlock childBlock2) {
      final TextRange range = parentBlock.getNode().getTextRange();
      return Spacing.createDependentLFSpacing(myMinSpaces, myMaxSpaces, range, myKeepLineBreaks, myKeepBlankLines);
    }
  }

  private static class RuleCondition {
    private final TokenSet myParentType;
    private final TokenSet myChild1Type;
    private final TokenSet myChild2Type;

    private RuleCondition(TokenSet parentType, TokenSet child1Type, TokenSet child2Type) {
      myParentType = parentType;
      myChild1Type = child1Type;
      myChild2Type = child2Type;
    }

    private boolean matches(@NotNull IElementType parentType, @NotNull IElementType firstChildType, @NotNull IElementType secondChildType) {
      return ((myParentType == null || myParentType.contains(parentType)) &&
              (myChild1Type == null || myChild1Type.contains(firstChildType)) &&
              (myChild2Type == null || myChild2Type.contains(secondChildType)));
    }
  }

  public class RuleBuilder {
    RuleCondition[] myConditions;

    private RuleBuilder(RuleCondition... conditions) {
      myConditions = conditions;
    }

    public SpacingBuilder none() {
      return spaces(0);
    }

    public SpacingBuilder spaceIf(boolean option) {
      return spaceIf(option, false);
    }

    /**
     * If {@code useParentDependentLFSpacing} is true and parent block spans multiple lines, insert single line break.
     * Otherwise insert whitespace block with exactly one or no spaces depending on value of {@code option} parameter.
     *
     * @see Spacing#createDependentLFSpacing
     */
    public SpacingBuilder spaceIf(boolean option, boolean useParentDependentLFSpacing) {
      return spaces(option ? 1 : 0, useParentDependentLFSpacing);
    }

    public SpacingBuilder spaces(int count) {
      return spaces(count, false);
    }

    /**
     * If {@code useParentDependentLFSpacing} is true and parent block spans multiple lines, insert single line break.
     * Otherwise insert whitespace block that contains as many spaces as specified via {@code count} parameter.
     *
     * @see Spacing#createDependentLFSpacing
     */
    public SpacingBuilder spaces(int count, boolean useParentDependentLFSpacing) {
      if (useParentDependentLFSpacing) {
        return parentDependentLFSpacing(count, count, myCodeStyleSettings.KEEP_LINE_BREAKS, myCodeStyleSettings.KEEP_BLANK_LINES_IN_CODE);
      }
      else {
        return spacing(count, count, 0, myCodeStyleSettings.KEEP_LINE_BREAKS, myCodeStyleSettings.KEEP_BLANK_LINES_IN_CODE);
      }
    }

    public SpacingBuilder blankLines(int count) {
      int blankLines = count + 1;
      for (RuleCondition condition : myConditions) {
        myRules.add(new SpacingRule(condition, 0, 0, blankLines,
                                    myCodeStyleSettings.KEEP_LINE_BREAKS, myCodeStyleSettings.KEEP_BLANK_LINES_IN_DECLARATIONS));
      }
      return SpacingBuilder.this;
    }

    public SpacingBuilder lineBreakInCodeIf(boolean option) {
      return option ? lineBreakInCode() : SpacingBuilder.this;
    }

    public SpacingBuilder lineBreakInCode() {
      for (RuleCondition condition : myConditions) {
        myRules.add(new SpacingRule(condition, 0, 0, 1,
                                    myCodeStyleSettings.KEEP_LINE_BREAKS, myCodeStyleSettings.KEEP_BLANK_LINES_IN_CODE));
      }
      return SpacingBuilder.this;
    }

    public SpacingBuilder lineBreakOrForceSpace(boolean lbOption, boolean spaceOption) {
      if (lbOption) {
        return lineBreakInCode();
      }

      int count = spaceOption ? 1 : 0;
      return spacing(count, count, 0, false, 0);
    }

    public SpacingBuilder spacing(int minSpaces, int maxSpaces, int minLF, boolean keepLineBreaks, int keepBlankLines) {
      for (RuleCondition condition : myConditions) {
        myRules.add(new SpacingRule(condition, minSpaces, maxSpaces,  minLF, keepLineBreaks, keepBlankLines));
      }
      return SpacingBuilder.this;
    }

    /**<commit_msg>Set min spaces for linebreak to 1, so when spacing becomes lineFeedsReadOnly it doesn't collapse.<commit_after>package com.intellij.formatting;

import com.intellij.lang.Language;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.List;

/**
 * @author yole
 */
public class SpacingBuilder {
  private static class SpacingRule {
    protected final RuleCondition myRuleCondition;
    protected final int myMinSpaces;
    protected final int myMaxSpaces;
    protected final int myMinLF;
    protected final boolean myKeepLineBreaks;
    protected final int myKeepBlankLines;

    private SpacingRule(@NotNull RuleCondition condition, int minSpaces, int maxSpaces, int minLF, boolean keepLineBreaks, int keepBlankLines) {
      myRuleCondition = condition;
      myMinSpaces = minSpaces;
      myMaxSpaces = maxSpaces;
      myMinLF = minLF;
      myKeepLineBreaks = keepLineBreaks;
      myKeepBlankLines = keepBlankLines;
    }

    public boolean matches(@NotNull ASTBlock parentBlock, @NotNull ASTBlock childBlock1, @NotNull ASTBlock childBlock2) {
      return myRuleCondition.matches(parentBlock.getNode().getElementType(),
                                     childBlock1.getNode().getElementType(),
                                     childBlock2.getNode().getElementType());
    }

    public Spacing createSpacing(@NotNull ASTBlock parentBlock, @NotNull ASTBlock childBlock1, @NotNull ASTBlock childBlock2) {
      return Spacing.createSpacing(myMinSpaces, myMaxSpaces, myMinLF, myKeepLineBreaks, myKeepBlankLines);
    }
  }

  private static class DependentLFSpacingRule extends SpacingRule {
    public DependentLFSpacingRule(@NotNull RuleCondition condition,
                                  int minSpaces,
                                  int maxSpaces,
                                  boolean keepLineBreaks,
                                  int keepBlankLines) {
      super(condition, minSpaces, maxSpaces, 1, keepLineBreaks, keepBlankLines);
    }

    @Override
    public Spacing createSpacing(@NotNull ASTBlock parentBlock, @NotNull ASTBlock childBlock1, @NotNull ASTBlock childBlock2) {
      final TextRange range = parentBlock.getNode().getTextRange();
      return Spacing.createDependentLFSpacing(myMinSpaces, myMaxSpaces, range, myKeepLineBreaks, myKeepBlankLines);
    }
  }

  private static class RuleCondition {
    private final TokenSet myParentType;
    private final TokenSet myChild1Type;
    private final TokenSet myChild2Type;

    private RuleCondition(TokenSet parentType, TokenSet child1Type, TokenSet child2Type) {
      myParentType = parentType;
      myChild1Type = child1Type;
      myChild2Type = child2Type;
    }

    private boolean matches(@NotNull IElementType parentType, @NotNull IElementType firstChildType, @NotNull IElementType secondChildType) {
      return ((myParentType == null || myParentType.contains(parentType)) &&
              (myChild1Type == null || myChild1Type.contains(firstChildType)) &&
              (myChild2Type == null || myChild2Type.contains(secondChildType)));
    }
  }

  public class RuleBuilder {
    RuleCondition[] myConditions;

    private RuleBuilder(RuleCondition... conditions) {
      myConditions = conditions;
    }

    public SpacingBuilder none() {
      return spaces(0);
    }

    public SpacingBuilder spaceIf(boolean option) {
      return spaceIf(option, false);
    }

    /**
     * If {@code useParentDependentLFSpacing} is true and parent block spans multiple lines, insert single line break.
     * Otherwise insert whitespace block with exactly one or no spaces depending on value of {@code option} parameter.
     *
     * @see Spacing#createDependentLFSpacing
     */
    public SpacingBuilder spaceIf(boolean option, boolean useParentDependentLFSpacing) {
      return spaces(option ? 1 : 0, useParentDependentLFSpacing);
    }

    public SpacingBuilder spaces(int count) {
      return spaces(count, false);
    }

    /**
     * If {@code useParentDependentLFSpacing} is true and parent block spans multiple lines, insert single line break.
     * Otherwise insert whitespace block that contains as many spaces as specified via {@code count} parameter.
     *
     * @see Spacing#createDependentLFSpacing
     */
    public SpacingBuilder spaces(int count, boolean useParentDependentLFSpacing) {
      if (useParentDependentLFSpacing) {
        return parentDependentLFSpacing(count, count, myCodeStyleSettings.KEEP_LINE_BREAKS, myCodeStyleSettings.KEEP_BLANK_LINES_IN_CODE);
      }
      else {
        return spacing(count, count, 0, myCodeStyleSettings.KEEP_LINE_BREAKS, myCodeStyleSettings.KEEP_BLANK_LINES_IN_CODE);
      }
    }

    public SpacingBuilder blankLines(int count) {
      int blankLines = count + 1;
      for (RuleCondition condition : myConditions) {
        myRules.add(new SpacingRule(condition, 0, 0, blankLines,
                                    myCodeStyleSettings.KEEP_LINE_BREAKS, myCodeStyleSettings.KEEP_BLANK_LINES_IN_DECLARATIONS));
      }
      return SpacingBuilder.this;
    }

    public SpacingBuilder lineBreakInCodeIf(boolean option) {
      return option ? lineBreakInCode() : SpacingBuilder.this;
    }

    public SpacingBuilder lineBreakInCode() {
      for (RuleCondition condition : myConditions) {
        myRules.add(new SpacingRule(condition, 1, 0, 1,
                                    myCodeStyleSettings.KEEP_LINE_BREAKS, myCodeStyleSettings.KEEP_BLANK_LINES_IN_CODE));
      }
      return SpacingBuilder.this;
    }

    public SpacingBuilder lineBreakOrForceSpace(boolean lbOption, boolean spaceOption) {
      if (lbOption) {
        return lineBreakInCode();
      }

      int count = spaceOption ? 1 : 0;
      return spacing(count, count, 0, false, 0);
    }

    public SpacingBuilder spacing(int minSpaces, int maxSpaces, int minLF, boolean keepLineBreaks, int keepBlankLines) {
      for (RuleCondition condition : myConditions) {
        myRules.add(new SpacingRule(condition, minSpaces, maxSpaces,  minLF, keepLineBreaks, keepBlankLines));
      }
      return SpacingBuilder.this;
    }

    /**
{'fraction_non_alphanumeric': 0.07406534715677034, 'fraction_numerical': 0.005576500157084511, 'mean_word_length': 3.25, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 16, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4939843', 'n_tokens_mistral': 3652, 'n_tokens_neox': 3489, 'n_words': 866}