Skip to content

Commit

Permalink
Add runner.optimizer.forceConfig... flag.
Browse files Browse the repository at this point in the history
Towards #140.
  • Loading branch information
olafurpg committed Dec 19, 2016
1 parent 4de2681 commit 4e6a43a
Show file tree
Hide file tree
Showing 7 changed files with 516 additions and 210 deletions.
11 changes: 10 additions & 1 deletion core/src/main/scala/org/scalafmt/config/ScalafmtOptimizer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,13 @@ import metaconfig.ConfigReader
*
* By starting a new search queue, we can perform
* aggressive optimizations inside optimizations zones.
* @param forceConfigStyleOnOffset
* If negative number, does nothing. If n >= 0, then scalafmt will force
* "config style" on Term.Apply nodes IF it has more than [[forceConfigStyleOnArgCount]]
* arguments AND the non-whitespace byte offset between the opening
* parens and closing parens is greater than [[forceConfigStyleOnOffset]].
* By forcing config style on such applications, the search space is greatly
* reduced.
*/
@ConfigReader
case class ScalafmtOptimizer(
Expand All @@ -63,7 +70,9 @@ case class ScalafmtOptimizer(
acceptOptimalAtHints: Boolean = true,
disableOptimizationsInsideSensitiveAreas: Boolean = true,
pruneSlowStates: Boolean = true,
recurseOnBlocks: Boolean = true
recurseOnBlocks: Boolean = true,
forceConfigStyleOnOffset: Int = 500,
forceConfigStyleOnArgCount: Int = 5
)

object ScalafmtOptimizer {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,8 @@ class BestFirstSearch(val formatOps: FormatOps,
if (!isInsideNoOptZone(splitToken) && lastDequeue.policy.isSafe) {
lastDequeue = curr
}
} else if (emptyQueueSpots(hash(splitToken.left))) {
Q.dequeueAll
}

if (shouldRecurseOnBlock(curr, stop)) {
Expand Down
63 changes: 47 additions & 16 deletions core/src/main/scala/org/scalafmt/internal/FormatOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import scala.meta.Pat
import scala.meta.Pkg
import scala.meta.Template
import scala.meta.Term
import scala.meta.Term.Apply
import scala.meta.Tree
import scala.meta.Type
import scala.meta.dialects.Scala211
Expand All @@ -19,7 +20,6 @@ import scala.meta.tokens.Token._
import scala.meta.tokens.Tokens

import org.scalafmt.Error.CaseMissingArrow
import org.scalafmt.config.ScalafmtRunner
import org.scalafmt.config.ScalafmtConfig
import org.scalafmt.internal.ExpiresOn.Left
import org.scalafmt.internal.Length.Num
Expand All @@ -45,6 +45,24 @@ class FormatOps(val tree: Tree, val initStyle: ScalafmtConfig) {
val matchingParentheses = getMatchingParentheses(tree.tokens)
val styleMap = new StyleMap(tokens, initStyle)
private val vAlignDepthCache = mutable.Map.empty[Tree, Int]
// Maps token to number of non-whitespace bytes before the token's position.
private final val nonWhitespaceOffset: Map[Token, Int] = {
val resultB = Map.newBuilder[Token, Int]
var curr = 0
tree.tokens.foreach {
case t =>
resultB += (t -> curr)
if (!t.is[Whitespace]) {
curr += (t.end - t.start)
}

}
resultB.result()
}

val (forceConfigStyle, emptyQueueSpots) = getForceConfigStyle

@inline def matching(token: Token): Token = matchingParentheses(hash(token))

@inline
def owners(token: Token): Tree = ownersMap(hash(token))
Expand Down Expand Up @@ -82,6 +100,11 @@ class FormatOps(val tree: Tree, val initStyle: ScalafmtConfig) {
(packages.result(), imports.result(), b.toMap)
}

object `:owner:` {
def unapply(tok: Token): Option[(Token, Tree)] =
ownersMap.get(hash(tok)).map(tree => tok -> tree)
}

lazy val leftTok2tok: Map[Token, FormatToken] = {
val result = Map.newBuilder[Token, FormatToken]
result.sizeHint(tokens.length)
Expand Down Expand Up @@ -504,21 +527,6 @@ class FormatOps(val tree: Tree, val initStyle: ScalafmtConfig) {
}
}

// Maps token to number of non-whitespace bytes before the token's position.
private final val nonWhitespaceOffset: Map[Token, Int] = {
val resultB = Map.newBuilder[Token, Int]
var curr = 0
tree.tokens.foreach {
case t =>
resultB += (t -> curr)
if (!t.is[Whitespace]) {
curr += (t.end - t.start)
}

}
resultB.result()
}

def distance(left: Token, right: Token): Int = {
nonWhitespaceOffset(right) - nonWhitespaceOffset(left)
}
Expand Down Expand Up @@ -570,4 +578,27 @@ class FormatOps(val tree: Tree, val initStyle: ScalafmtConfig) {
case None => count
}
}

def getForceConfigStyle: (Set[Tree], Set[TokenHash]) = {
val maxDistance = runner.optimizer.forceConfigStyleOnOffset
if (maxDistance < 0 ||
initStyle.bestEffortInDeeplyNestedCode) // breaks test
(Set.empty, Set.empty)
else {
val clearQueues = Set.newBuilder[TokenHash]
val forces = Set.newBuilder[Tree]
tree.tokens.foreach {
case left @ LeftParen() `:owner:` (app: Term.Apply)
if app.args.length > runner.optimizer.forceConfigStyleOnArgCount &&
distance(left, matching(left)) > maxDistance =>
forces += app
app.args.foreach { arg =>
clearQueues += hash(arg.tokens.head)
}
case _ =>
}
(forces.result(), clearQueues.result())
}
}

}
2 changes: 1 addition & 1 deletion core/src/main/scala/org/scalafmt/internal/Router.scala
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ class Router(formatOps: FormatOps) {
case FormatToken(LeftParen() | LeftBracket(), right, between)
if style.configStyleArguments &&
(isDefnSite(leftOwner) || isCallSite(leftOwner)) &&
opensConfigStyle(formatToken) =>
(opensConfigStyle(formatToken) || forceConfigStyle(leftOwner)) =>
val open = formatToken.left
val indent = getApplyIndent(leftOwner, isConfigStyle = true)
val close = matchingParentheses(hash(open))
Expand Down
Loading

0 comments on commit 4e6a43a

Please sign in to comment.