790 } |
790 } |
791 |
791 |
792 private def diff(repository: Mercurial.Repository, rev0: String, rev: String): String = |
792 private def diff(repository: Mercurial.Repository, rev0: String, rev: String): String = |
793 if (rev0.isEmpty || rev.isEmpty) "" |
793 if (rev0.isEmpty || rev.isEmpty) "" |
794 else { |
794 else { |
795 val diff_opts = "--noprefix --nodates --ignore-all-space" |
795 val diff_opts = "--noprefix --nodates --ignore-all-space --color always" |
796 repository.diff(rev0 + ":" + rev, diff_opts) |
796 val cmd = repository.command_line("diff", Mercurial.opt_rev(rev0 + ":" + rev), diff_opts) |
|
797 Isabelle_System.bash("export HGPLAINEXCEPT=color\n" + cmd).check.out |
797 } |
798 } |
798 |
799 |
799 private def start_next(): Option[Context] = |
800 private def start_next(): Option[Context] = |
800 synchronized_database("start_next") { |
801 synchronized_database("start_next") { |
801 for ((name, task) <- _state.pending if Exn.is_exn(Exn.capture(task.build_hosts))) { |
802 for ((name, task) <- _state.pending if Exn.is_exn(Exn.capture(task.build_hosts))) { |
1191 def render_cancel(uuid: UUID.T): XML.Body = |
1192 def render_cancel(uuid: UUID.T): XML.Body = |
1192 render_if(!public, List( |
1193 render_if(!public, List( |
1193 submit_form("", List(hidden(ID, uuid.toString), |
1194 submit_form("", List(hidden(ID, uuid.toString), |
1194 api_button(paths.api_route(API.BUILD_CANCEL), "cancel build"))))) |
1195 api_button(paths.api_route(API.BUILD_CANCEL), "cancel build"))))) |
1195 |
1196 |
1196 def render_diff(diff: String): XML.Body = List(source(text(diff))) |
1197 def render_diff(diff: String): XML.Body = { |
|
1198 val Colored = "\u001b\\[([0-9;]+)m(.*)\u001b\\[0m".r |
|
1199 val colors = List("black", "red", "green", "yellow", "blue", "magenta", "cyan", "white") |
|
1200 |
|
1201 val lines = split_lines(diff).map { |
|
1202 case Colored(code, s) => |
|
1203 val codes = space_explode(';', code.stripSuffix(";1")).map(Value.Int.parse) |
|
1204 val fg = codes match { case 0 :: i :: Nil => colors.unapply(i - 30) case _ => None } |
|
1205 |
|
1206 val sp = span(if (code.endsWith(";1")) List(bold(text(s))) else text(s)) |
|
1207 List(fg.map(color => sp + ("style" -> ("color:" + color))).getOrElse(sp)) |
|
1208 case line => text(Library.strip_ansi_color(line)) |
|
1209 } |
|
1210 |
|
1211 List(source(Library.separate(nl, lines).flatten)) |
|
1212 } |
1197 |
1213 |
1198 def render_rev(components: List[Component], diffs: Map[String, String]): XML.Body = |
1214 def render_rev(components: List[Component], diffs: Map[String, String]): XML.Body = |
1199 for (component <- components if !component.is_local) |
1215 for (component <- components if !component.is_local) |
1200 yield par(text(component.toString) ++ diffs.get(component.name).flatMap(render_diff)) |
1216 yield par(text(component.toString) ++ diffs.get(component.name).flatMap(render_diff)) |
1201 |
1217 |