Skip to content

Commit 061a1a5

Browse files
committed
Vphases uses Highlight, option formatting
1 parent 893bf57 commit 061a1a5

File tree

3 files changed

+60
-37
lines changed

3 files changed

+60
-37
lines changed

compiler/src/dotty/tools/dotc/config/CliCommand.scala

Lines changed: 58 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ package config
33

44
import Settings._
55
import core.Contexts._
6+
import printing.Highlighting
67

8+
import scala.util.chaining.given
79
import scala.PartialFunction.cond
810

911
trait CliCommand:
@@ -52,7 +54,7 @@ trait CliCommand:
5254
protected def availableOptionsMsg(cond: Setting[?] => Boolean)(using settings: ConcreteSettings)(using SettingsState): String =
5355
val ss = (settings.allSettings filter cond).toList sortBy (_.name)
5456
val maxNameWidth = 30
55-
val nameWidths = ss.map(_.name.length).partition(_ < maxNameWidth)._1
57+
val nameWidths = ss.map(_.name.length).filter(_ < maxNameWidth)
5658
val width = if nameWidths.nonEmpty then nameWidths.max else maxNameWidth
5759
val terminalWidth = settings.pageWidth.value
5860
val (nameWidth, descriptionWidth) = {
@@ -136,39 +138,10 @@ trait CliCommand:
136138
createUsageMsg("Possible private", shouldExplain = true, isPrivate)
137139

138140
/** Used for the formatted output of -Xshow-phases */
139-
protected def phasesMessage(using ctx: Context): String =
140-
141-
import scala.io.AnsiColor.*
142-
val colors = Array(GREEN, YELLOW, /*BLUE,*/ MAGENTA, CYAN, RED)
141+
protected def phasesMessage(using Context): String =
143142
val phases = new Compiler().phases
144-
val nameLimit = 25
145-
val maxCol = ctx.settings.pageWidth.value
146-
val maxName = phases.flatten.map(_.phaseName.length).max
147-
val width = maxName.min(nameLimit)
148-
val maxDesc = maxCol - (width + 6)
149-
val colorSlot = if ctx.useColors then GREEN.length.toString else "0"
150-
val fmt = s"%.${colorSlot}s%${width}.${width}s%.${colorSlot}s %.${maxDesc}s%n"
151-
def plain(name: String, description: String) = fmt.format("", name, "", description)
152-
153-
val sb = new StringBuilder
154-
sb ++= plain("phase name", "description")
155-
sb ++= plain("----------", "-----------")
156-
157-
def color(index: Int): String = colors(index % colors.length)
158-
def emit(index: Int)(phase: core.Phases.Phase): Unit = sb ++= fmt.format(color(index), phase.phaseName, RESET, phase.description)
159-
def group(index: Int)(body: Int => Unit): Unit =
160-
if !ctx.useColors then sb ++= plain(s"{", "")
161-
body(index)
162-
if !ctx.useColors then sb ++= plain(s"}", "")
163-
164-
phases.zipWithIndex.foreach { (phase, index) =>
165-
phase match
166-
case List(single) => emit(index)(single)
167-
case Nil =>
168-
case mega => group(index)(i => mega.foreach(emit(i)))
169-
}
170-
sb.mkString
171-
143+
val formatter = Columnator("phase name", "description", maxField = 25, separation = 2)
144+
formatter(phases.map(mega => mega.map(p => (p.phaseName, p.description))))
172145

173146
/** Provide usage feedback on argument summary, assuming that all settings
174147
* are already applied in context.
@@ -196,3 +169,55 @@ trait CliCommand:
196169

197170
extension [T](setting: Setting[T])
198171
protected def value(using ss: SettingsState): T = setting.valueIn(ss)
172+
173+
extension (s: String)
174+
def padLeft(width: Int): String = StringBuilder().tap(_.append(" " * (width - s.length)).append(s)).toString
175+
176+
// Formatting for -help and -Vphases in two columns, handling long field1 and wrapping long field2
177+
class Columnator(heading1: String, heading2: String, maxField: Int, separation: Int = 1):
178+
def apply(texts: List[List[(String, String)]])(using Context): String = StringBuilder().tap(columnate(_, texts)).toString
179+
180+
private def columnate(sb: StringBuilder, texts: List[List[(String, String)]])(using Context): Unit =
181+
import scala.util.Properties.{lineSeparator => EOL}
182+
import Highlighting.*
183+
val colors = Seq(Green(_), Yellow(_), Magenta(_), Cyan(_), Red(_))
184+
val nocolor = texts.length == 1
185+
def color(index: Int): String => Highlight = if nocolor then NoColor(_) else colors(index % colors.length)
186+
val maxCol = ctx.settings.pageWidth.value
187+
val field1 = maxField.min(texts.flatten.map(_._1.length).filter(_ < maxField).max) // widest field under maxField
188+
val field2 = if field1 + separation + maxField < maxCol then maxCol - field1 - separation else 0 // skinny window -> terminal wrap
189+
val separator = " " * separation
190+
def formatField1(text: String): String = if text.length <= field1 then text.padLeft(field1) else EOL + "".padLeft(field1)
191+
def formatField2(text: String): String =
192+
if field2 == 0 || text.length <= field2 then text
193+
else
194+
text.lastIndexOf(" ", field2) match
195+
case -1 => text
196+
case i =>
197+
val (prefix, rest) = text.splitAt(i)
198+
s"${prefix}${EOL}${formatField1("")}${separator}${formatField2(rest.trim)}"
199+
def format(first: String, second: String, index: Int, colorPicker: Int => String => Highlight) =
200+
sb.append(colorPicker(index)(formatField1(first)).show)
201+
.append(separator)
202+
.append(formatField2(second))
203+
.append(EOL): Unit
204+
def fancy(first: String, second: String, index: Int) = format(first, second, index, color)
205+
def plain(first: String, second: String) = format(first, second, 0, _ => NoColor(_))
206+
207+
if heading1.nonEmpty then
208+
plain(heading1, heading2)
209+
plain("-" * heading1.length, "-" * heading2.length)
210+
211+
def emit(index: Int)(textPair: (String, String)): Unit = fancy(textPair._1, textPair._2, index)
212+
def group(index: Int)(body: Int => Unit): Unit =
213+
if !ctx.useColors then plain(s"{", "")
214+
body(index)
215+
if !ctx.useColors then plain(s"}", "")
216+
217+
texts.zipWithIndex.foreach { (text, index) =>
218+
text match
219+
case List(single) => emit(index)(single)
220+
case Nil =>
221+
case mega => group(index)(i => mega.foreach(emit(i)))
222+
}
223+
end Columnator

compiler/src/dotty/tools/dotc/config/ScalaSettings.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ private sealed trait VerboseSettings:
134134
self: SettingGroup =>
135135
val Vhelp: Setting[Boolean] = BooleanSetting("-V", "Print a synopsis of verbose options.")
136136
val Xprint: Setting[List[String]] = PhasesSetting("-Vprint", "Print out program after", aliases = List("-Xprint"))
137+
val XshowPhases: Setting[Boolean] = BooleanSetting("-Vphases", "List compiler phases.", aliases = List("-Xshow-phases"))
137138

138139
/** -W "Warnings" settings
139140
*/
@@ -215,7 +216,6 @@ private sealed trait XSettings:
215216
val XprintInline: Setting[Boolean] = BooleanSetting("-Xprint-inline", "Show where inlined code comes from.")
216217
val XprintSuspension: Setting[Boolean] = BooleanSetting("-Xprint-suspension", "Show when code is suspended until macros are compiled.")
217218
val Xprompt: Setting[Boolean] = BooleanSetting("-Xprompt", "Display a prompt after each error (debugging option).")
218-
val XshowPhases: Setting[Boolean] = BooleanSetting("-Xshow-phases", "Print all compiler phases.")
219219
val XreplDisableDisplay: Setting[Boolean] = BooleanSetting("-Xrepl-disable-display", "Do not display definitions in REPL.")
220220
val XverifySignatures: Setting[Boolean] = BooleanSetting("-Xverify-signatures", "Verify generic signatures in generated bytecode.")
221221
val XignoreScala2Macros: Setting[Boolean] = BooleanSetting("-Xignore-scala2-macros", "Ignore errors when compiling code that calls Scala2 macros, these will fail at runtime.")

compiler/src/dotty/tools/dotc/printing/Highlighting.scala

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,7 @@ object Highlighting {
1010
abstract class Highlight(private val highlight: String) {
1111
def text: String
1212

13-
def show(using Context): String =
14-
if (ctx.settings.color.value == "never") text
15-
else highlight + text + Console.RESET
13+
def show(using Context): String = if ctx.useColors then highlight + text + Console.RESET else text
1614

1715
override def toString: String =
1816
highlight + text + Console.RESET

0 commit comments

Comments
 (0)