summaryrefslogtreecommitdiff
path: root/main/src/main/ReplApplyHandler.scala
diff options
context:
space:
mode:
Diffstat (limited to 'main/src/main/ReplApplyHandler.scala')
-rw-r--r--main/src/main/ReplApplyHandler.scala163
1 files changed, 163 insertions, 0 deletions
diff --git a/main/src/main/ReplApplyHandler.scala b/main/src/main/ReplApplyHandler.scala
new file mode 100644
index 00000000..786a1409
--- /dev/null
+++ b/main/src/main/ReplApplyHandler.scala
@@ -0,0 +1,163 @@
+package mill.main
+
+
+import mill.define.Applicative.ApplyHandler
+import mill.define.Segment.Label
+import mill.define._
+import mill.eval.{Evaluator, Result}
+
+import mill.api.Strict.Agg
+
+import scala.collection.mutable
+object ReplApplyHandler{
+ def apply[T](home: os.Path,
+ disableTicker: Boolean,
+ colors: ammonite.util.Colors,
+ pprinter0: pprint.PPrinter,
+ rootModule: mill.define.BaseModule,
+ discover: Discover[_],
+ debugLog: Boolean) = {
+ new ReplApplyHandler(
+ pprinter0,
+ new Evaluator(
+ home,
+ ammonite.ops.pwd / 'out,
+ ammonite.ops.pwd / 'out,
+ rootModule,
+ new mill.util.PrintLogger(
+ colors != ammonite.util.Colors.BlackWhite,
+ disableTicker,
+ colors,
+ System.out,
+ System.err,
+ System.err,
+ System.in,
+ debugEnabled = debugLog
+ )
+ )
+ )
+ }
+ def pprintCross(c: mill.define.Cross[_], evaluator: Evaluator) = {
+ pprint.Tree.Lazy( ctx =>
+ Iterator(c.millOuterCtx.enclosing , ":", c.millOuterCtx.lineNum.toString, ctx.applyPrefixColor("\nChildren:").toString) ++
+ c.items.iterator.map(x =>
+ "\n (" + x._1.map(pprint.PPrinter.BlackWhite.apply(_)).mkString(", ") + ")"
+ )
+ )
+ }
+ def pprintModule(m: mill.define.Module, evaluator: Evaluator) = {
+ pprint.Tree.Lazy( ctx =>
+ Iterator(m.millInternal.millModuleEnclosing, ":", m.millInternal.millModuleLine.toString) ++
+ (if (m.millInternal.reflectAll[mill.Module].isEmpty) Nil
+ else
+ ctx.applyPrefixColor("\nChildren:").toString +:
+ m.millInternal.reflectAll[mill.Module].map("\n ." + _.millOuterCtx.segment.pathSegments.mkString("."))) ++
+ (evaluator.rootModule.millDiscover.value.get(m.getClass) match{
+ case None => Nil
+ case Some(commands) =>
+ ctx.applyPrefixColor("\nCommands:").toString +: commands.map{c =>
+ "\n ." + c._2.name + "(" +
+ c._2.argSignatures.map(s => s.name + ": " + s.typeString).mkString(", ") +
+ ")()"
+ }
+ }) ++
+ (if (m.millInternal.reflectAll[Target[_]].isEmpty) Nil
+ else {
+ Seq(ctx.applyPrefixColor("\nTargets:").toString) ++
+ m.millInternal.reflectAll[Target[_]].map(t =>
+ "\n ." + t.label + "()"
+ )
+ })
+
+ )
+ }
+
+ def resolveParents(c: Class[_]): Seq[Class[_]] = {
+ Seq(c) ++ Option(c.getSuperclass).toSeq.flatMap(resolveParents) ++ c.getInterfaces.flatMap(resolveParents)
+ }
+
+ def pprintTask(t: NamedTask[_], evaluator: Evaluator) = {
+ val seen = mutable.Set.empty[Task[_]]
+ def rec(t: Task[_]): Seq[Segments] = {
+ if (seen(t)) Nil // do nothing
+ else t match {
+ case t: Target[_] if evaluator.rootModule.millInternal.targets.contains(t) =>
+ Seq(t.ctx.segments)
+ case _ =>
+ seen.add(t)
+ t.inputs.flatMap(rec)
+ }
+ }
+
+ val annots = for {
+ c <- resolveParents(t.ctx.enclosingCls)
+ m <- c.getMethods
+ if m.getName == t.ctx.segment.pathSegments.head
+ a = m.getAnnotation(classOf[mill.moduledefs.Scaladoc])
+ if a != null
+ }yield a
+
+ val allDocs =
+ for(a <- annots.distinct)
+ yield mill.modules.Util.cleanupScaladoc(a.value).map("\n " + _).mkString
+
+ pprint.Tree.Lazy(ctx =>
+ Iterator(
+ ctx.applyPrefixColor(t.toString).toString, "(", t.ctx.fileName.split('/').last, ":", t.ctx.lineNum.toString, ")",
+ allDocs.mkString("\n"), "\n",
+ "\n", ctx.applyPrefixColor("Inputs").toString, ":"
+ ) ++ t.inputs.iterator.flatMap(rec).map("\n " + _.render)
+ )
+ }
+
+}
+class ReplApplyHandler(pprinter0: pprint.PPrinter,
+ val evaluator: Evaluator) extends ApplyHandler[Task] {
+ // Evaluate classLoaderSig only once in the REPL to avoid busting caches
+ // as the user enters more REPL commands and changes the classpath
+ val classLoaderSig = Evaluator.classLoaderSig
+ override def apply[V](t: Task[V]) = {
+ val res = evaluator.evaluate(Agg(t))
+ res.values match{
+ case Seq(head: V) => head
+ case Nil =>
+ val msg = new mutable.StringBuilder()
+ msg.append(res.failing.keyCount + " targets failed\n")
+ for((k, vs) <- res.failing.items){
+ msg.append(k match{
+ case Left(t) => "Anonymous Task\n"
+ case Right(k) => k.segments.render + "\n"
+ })
+
+ for(v <- vs){
+ v match{
+ case Result.Failure(m, _) => msg.append(m + "\n")
+ case Result.Exception(t, outerStack) =>
+ msg.append(
+ t.toString +
+ t.getStackTrace.dropRight(outerStack.value.length).map("\n " + _).mkString +
+ "\n"
+ )
+
+ }
+ }
+ }
+ throw new Exception(msg.toString)
+ }
+ }
+
+ val generatedEval = new EvalGenerated(evaluator)
+
+ val millHandlers: PartialFunction[Any, pprint.Tree] = {
+ case c: Cross[_] =>
+ ReplApplyHandler.pprintCross(c, evaluator)
+ case m: mill.Module if evaluator.rootModule.millInternal.modules.contains(m) =>
+ ReplApplyHandler.pprintModule(m, evaluator)
+ case t: mill.define.Target[_] if evaluator.rootModule.millInternal.targets.contains(t) =>
+ ReplApplyHandler.pprintTask(t, evaluator)
+
+ }
+ val pprinter = pprinter0.copy(
+ additionalHandlers = millHandlers orElse pprinter0.additionalHandlers
+ )
+}