Skip to content

Commit

Permalink
ModExt: move alt centrally from NewlineT
Browse files Browse the repository at this point in the history
  • Loading branch information
kitbellew committed Nov 23, 2024
1 parent 2056384 commit 9d48629
Show file tree
Hide file tree
Showing 8 changed files with 72 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -932,7 +932,7 @@ class FormatOps(
indentLen: Int,
extendsThenWith: => Boolean = false,
)(implicit fileLine: FileLine, ft: FT, style: ScalafmtConfig): Seq[Split] = {
val nlMod = NewlineT(alt = Some(Space))
val nlMod = Newline.withAlt(Space)
def nlPolicy(ignore: Boolean) = Policy ? (ignore || owners.isEmpty) ||
Policy.onRight(lastFt, prefix = "WITH") {
case d @ Decision(FT(_, _: T.KwWith, m), _) if owners(m.rightOwner) =>
Expand Down Expand Up @@ -1161,7 +1161,7 @@ class FormatOps(
style.newlines.forceAfterImplicitParamListModifier
val nlNoAlt = implicitNL ||
!rightIsImplicit && style.verticalMultiline.newlineAfterOpenParen
val nlMod = NewlineT(alt = if (nlNoAlt) None else Some(slbSplit.modExt))
val nlMod = Newline.withAltIf(!nlNoAlt)(slbSplit.modExt)
val spaceImplicit = !implicitNL && implicitParams.lengthCompare(1) > 0 &&
style.newlines.notBeforeImplicitParamListModifier
Seq(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,46 @@ package org.scalafmt.internal

import scala.meta.tokens.{Token => T}

import scala.language.implicitConversions
import scala.annotation.tailrec

/** @param mod
* Is this a space, no space, newline or 2 newlines?
* @param indents
* Does this add indentation?
*/
case class ModExt(mod: Modification, indents: Seq[Indent] = Seq.empty) {
lazy val indentation = indents.mkString("[", ", ", "]")

case class ModExt(
mod: Modification,
indents: Seq[Indent] = Nil,
altOpt: Option[ModExt] = None,
) {
@inline
def isNL: Boolean = mod.isNL

@tailrec
private def toString(prefix: String, indentPrefix: String): String = {
@inline
def res(suffix: String) = {
val ind = if (indents.isEmpty) "" else indents.mkString("[", ", ", "]")
s"$prefix$mod($indentPrefix$ind)$suffix"
}

altOpt match {
case None => res("")
case Some(x) => x.toString(res("|"), "+")
}
}

override def toString: String = toString("", "")

def withAlt(alt: ModExt): ModExt =
if (altOpt.contains(alt)) this else copy(altOpt = Some(alt))

@inline
def withAltIf(ok: Boolean)(alt: => ModExt): ModExt =
if (ok) withAlt(alt) else this

def orMod(flag: Boolean, mod: => ModExt): ModExt = if (flag) this else mod

def withIndent(length: => Length, expire: => FT, when: ExpiresOn): ModExt =
length match {
case Length.Num(0, _) => this
Expand Down Expand Up @@ -75,9 +102,3 @@ case class ModExt(mod: Modification, indents: Seq[Indent] = Seq.empty) {
.flatMap(_.withStateOffset(offset + mod.length))

}

object ModExt {

implicit def implicitModToModExt(mod: Modification): ModExt = ModExt(mod)

}
Original file line number Diff line number Diff line change
Expand Up @@ -34,25 +34,18 @@ case object NoSplit extends Modification {
* optional additional set of indents) if the newline will indent beyond the
* current column? For example, used by select chains in [[Router]].
*/
case class NewlineT(
isDouble: Boolean = false,
noIndent: Boolean = false,
alt: Option[ModExt] = None,
) extends Modification {
case class NewlineT(isDouble: Boolean = false, noIndent: Boolean = false)
extends Modification {
override def toString = {
val double = if (isDouble) "x2" else ""
val indent = if (noIndent) "[NoIndent]" else ""
val altStr = alt.fold("")(x => "|" + x.mod.toString)
"NL" + double + indent + altStr
"NL" + double + indent
}
override val newlines: Int = if (isDouble) 2 else 1
override val length: Int = 0
}

object Newline extends NewlineT {
def orMod(flag: Boolean, mod: => Modification): Modification =
if (flag) this else mod
}
object Newline extends NewlineT

object Newline2x extends NewlineT(isDouble = true) {
def apply(isDouble: Boolean): NewlineT = if (isDouble) this else Newline
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1474,11 +1474,11 @@ class Router(formatOps: FormatOps) {
val nlIndentLen =
if (nlClosedOnOpenEffective eq NlClosedOnOpen.Cfg) indentLen
else bpIndentLen
val nlMod =
if (nlOnly && noBreak() && right.is[T.Comment]) Space
else NewlineT(alt = if (singleLineOnly) Some(NoSplit) else None)
val nlMod = {
if (nlOnly && noBreak() && right.is[T.Comment]) Space.toExt
else Newline.withAltIf(singleLineOnly)(NoSplit)
}.withIndent(nlIndentLen, close, Before)
val nlSplit = Split(nlMod, bracketPenalty * (if (oneline) 4 else 2))
.withIndent(nlIndentLen, close, Before)
.withSingleLineNoOptimal(close, ignore = !singleLineOnly).andPolicy(
Policy ? singleLineOnly || nlPolicy & penalizeNewlinesPolicy,
).andPolicy(singleArgAsInfix.map(InfixSplits(_, ft).nlPolicy))
Expand Down Expand Up @@ -1850,7 +1850,7 @@ class Router(formatOps: FormatOps) {
if (ok) Some(nd) else None
}
val altIndent = endSelect.map(Indent(-indentLen, _, After))
NewlineT(alt = Some(ModExt(modSpace).withIndentOpt(altIndent)))
Newline.withAlt(modSpace.withIndentOpt(altIndent))
}

val prevChain = inSelectChain(prevSelect, thisSelect, expireTree)
Expand Down Expand Up @@ -1889,9 +1889,8 @@ class Router(formatOps: FormatOps) {
val nlCost = nlBaseCost + nestedPenalty + chainLengthPenalty
val nlMod = getNlMod
val legacySplit = Split(!prevChain, 1) { // must come first, for backwards compat
if (style.optIn.breaksInsideChains) Newline
.orMod(hasBreak(), modSpace)
else nlMod
if (!style.optIn.breaksInsideChains) nlMod
else Newline.orMod(hasBreak(), modSpace)
}.withPolicy(newlinePolicy).onlyFor(SplitTag.SelectChainSecondNL)
val slbSplit =
if (ignoreNoSplit) Split.ignored
Expand All @@ -1907,7 +1906,7 @@ class Router(formatOps: FormatOps) {
.withSingleLineNoOptimal(chainExpire, noSyntaxNL = true)
}
}.andPolicy(penalizeBreaks)
val nlSplit = Split(if (ignoreNoSplit) Newline else nlMod, nlCost)
val nlSplit = Split(Newline.orMod(ignoreNoSplit, nlMod), nlCost)
.withPolicy(newlinePolicy)
Seq(legacySplit, slbSplit, nlSplit)
} else {
Expand Down Expand Up @@ -1945,14 +1944,14 @@ class Router(formatOps: FormatOps) {
else Seq(
Split(nlOnly, 0)(modSpace)
.withSingleLine(expire, noSyntaxNL = true),
Split(NewlineT(alt = Some(modSpace)), nlCost)
Split(Newline.withAlt(modSpace), nlCost)
.withPolicy(forcedBreakOnNextDotPolicy),
)

case Newlines.fold =>
def nlSplitBase(cost: Int, policy: Policy = NoPolicy)(implicit
fileLine: FileLine,
) = Split(NewlineT(alt = Some(modSpace)), cost, policy = policy)
) = Split(Newline.withAlt(modSpace), cost, policy = policy)
if (nextDotIfSig.isEmpty)
if (nlOnly) Seq(nlSplitBase(0))
else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ case class Split(
import PolicyOps._

def withNoIndent: Split = mod match {
case x @ NewlineT(_, false, _) =>
case x: NewlineT if !x.noIndent =>
copy(modExt = modExt.copy(mod = x.copy(noIndent = true)))
case _ => this
}
Expand All @@ -70,9 +70,6 @@ case class Split(
@inline
def fileLine: FileLine = fileLineStack.fileLineLast

@inline
def indentation: String = modExt.indentation

@inline
def isNL: Boolean = modExt.isNL

Expand Down Expand Up @@ -318,7 +315,7 @@ case class Split(
else ""
}
val opt = optimalAt.fold("")(", opt=" + _)
s"""${prefix}c=$cost[$penalty] $mod:[$fileLineStack](indents=$indentation, $policy$opt)"""
s"""${prefix}c=$cost[$penalty] $modExt:[$fileLineStack]($policy$opt)"""
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ final class State(
if (right.is[T.EOF]) (initialNextSplit, 0, Seq.empty)
else {
val offset = column - indentation
def getUnexpired(modExt: ModExt, indents: Seq[ActualIndent] = Nil) = {
def getUnexpired(modExt: ModExt, indents: Seq[ActualIndent]) = {
val extendedEnd = getRelativeToLhsLastLineEnd(modExt.isNL)
(modExt.getActualIndents(offset) ++ indents).flatMap { x =>
if (x.notExpiredBy(tok)) Some(x)
Expand All @@ -80,19 +80,17 @@ final class State(
}

val initialModExt = initialNextSplit.modExt
val indents = initialModExt.indents
val nextPushes = getUnexpired(initialModExt, pushes)
val nextIndent = Indent.getIndent(nextPushes)
initialNextSplit.mod match {
case m: NewlineT
if !tok.left.is[T.Comment] && m.alt.isDefined &&
nextIndent >= m.alt.get.mod.length + column =>
val alt = m.alt.get
val altPushes = getUnexpired(alt)
val altIndent = Indent.getIndent(altPushes)
val split = initialNextSplit.withMod(alt.withIndents(indents))
(split, nextIndent + altIndent, nextPushes ++ altPushes)
case _ => (initialNextSplit, nextIndent, nextPushes)
initialModExt.altOpt.flatMap { alt =>
if (tok.left.is[T.Comment]) None
else if (nextIndent < alt.mod.length + column) None
else Some(alt.withIndents(initialModExt.indents))
}.fold((initialNextSplit, nextIndent, nextPushes)) { alt =>
val altPushes = getUnexpired(alt, pushes)
val altIndent = Indent.getIndent(altPushes)
val split = initialNextSplit.withMod(alt)
(split, altIndent, altPushes)
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,20 @@
package org.scalafmt

import scala.language.implicitConversions

package object internal {

private[scalafmt] type FT = FormatToken
private[scalafmt] val FT = FormatToken

private[scalafmt] implicit def implicitModToModExt(
mod: Modification,
): ModExt = ModExt(mod)

private[scalafmt] implicit class ImplicitModification(
private val mod: Modification,
) extends AnyVal {
def toExt: ModExt = mod
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ object LoggerOps {
s"d=${s.depth} w=${s.cost}[${s.appliedPenalty}] i=${s.indentation} col=${s
.column} #nl=${s.lineId}$policies;${delim}s=${log(s.split)}$nls"
}
def log(split: Split): String = s"$split"
def log(split: Split): String = split.toString

def log(formatToken: FT): String =
s"""|${log(formatToken.left)}
Expand Down

0 comments on commit 9d48629

Please sign in to comment.