use ansi colored diffs;
authorFabian Huch <huch@in.tum.de>
Fri, 05 Jul 2024 09:52:56 +0200
changeset 80501 83c212f7cf97
parent 80500 12dc23fc3135
child 80502 db89ef6a8a42
use ansi colored diffs;
src/Pure/Build/build_manager.scala
--- a/src/Pure/Build/build_manager.scala	Fri Jul 05 09:47:21 2024 +0200
+++ b/src/Pure/Build/build_manager.scala	Fri Jul 05 09:52:56 2024 +0200
@@ -792,8 +792,9 @@
     private def diff(repository: Mercurial.Repository, rev0: String, rev: String): String =
       if (rev0.isEmpty || rev.isEmpty) ""
       else {
-        val diff_opts = "--noprefix --nodates --ignore-all-space"
-        repository.diff(rev0 + ":" + rev, diff_opts)
+        val diff_opts = "--noprefix --nodates --ignore-all-space --color always"
+        val cmd = repository.command_line("diff", Mercurial.opt_rev(rev0 + ":" + rev), diff_opts)
+        Isabelle_System.bash("export HGPLAINEXCEPT=color\n" + cmd).check.out
       }
 
     private def start_next(): Option[Context] =
@@ -1193,7 +1194,22 @@
               submit_form("", List(hidden(ID, uuid.toString),
                 api_button(paths.api_route(API.BUILD_CANCEL), "cancel build")))))
 
-          def render_diff(diff: String): XML.Body = List(source(text(diff)))
+          def render_diff(diff: String): XML.Body = {
+            val Colored = "\u001b\\[([0-9;]+)m(.*)\u001b\\[0m".r
+            val colors = List("black", "red", "green", "yellow", "blue", "magenta", "cyan", "white")
+
+            val lines = split_lines(diff).map {
+              case Colored(code, s) =>
+                val codes = space_explode(';', code.stripSuffix(";1")).map(Value.Int.parse)
+                val fg = codes match { case 0 :: i :: Nil => colors.unapply(i - 30) case _ => None }
+
+                val sp = span(if (code.endsWith(";1")) List(bold(text(s))) else text(s))
+                List(fg.map(color => sp + ("style" -> ("color:" + color))).getOrElse(sp))
+              case line => text(Library.strip_ansi_color(line))
+            }
+
+            List(source(Library.separate(nl, lines).flatten))
+          }
 
           def render_rev(components: List[Component], diffs: Map[String, String]): XML.Body =
             for (component <- components if !component.is_local)