79873
|
1 |
/* Title: Pure/System/program_progress.scala
|
|
2 |
Author: Makarius
|
|
3 |
|
|
4 |
Structured program progress.
|
|
5 |
*/
|
|
6 |
|
|
7 |
package isabelle
|
|
8 |
|
|
9 |
|
|
10 |
object Program_Progress {
|
|
11 |
class Program private[Program_Progress](heading: String, title: String) {
|
|
12 |
private val output_buffer = new StringBuffer(256) // synchronized
|
|
13 |
|
|
14 |
def output(message: Progress.Message): Unit = synchronized {
|
|
15 |
if (output_buffer.length() > 0) output_buffer.append('\n')
|
|
16 |
output_buffer.append(message.output_text)
|
|
17 |
}
|
|
18 |
|
|
19 |
val start_time: Time = Time.now()
|
|
20 |
private var stop_time: Option[Time] = None
|
|
21 |
def stop_now(): Unit = synchronized { stop_time = Some(Time.now()) }
|
|
22 |
|
|
23 |
def output(): (Command.Results, XML.Body) = synchronized {
|
|
24 |
val output_text = output_buffer.toString
|
|
25 |
val elapsed_time = stop_time.map(t => t - start_time)
|
|
26 |
|
|
27 |
val message_prefix = heading + " "
|
|
28 |
val message_suffix =
|
|
29 |
elapsed_time match {
|
|
30 |
case None => " ..."
|
|
31 |
case Some(t) => " ... (" + t.message + " elapsed time)"
|
|
32 |
}
|
|
33 |
|
|
34 |
val (results, message) =
|
|
35 |
if (output_text.isEmpty) {
|
|
36 |
(Command.Results.empty, XML.string(message_prefix + title + message_suffix))
|
|
37 |
}
|
|
38 |
else {
|
|
39 |
val i = Document_ID.make()
|
|
40 |
val results = Command.Results.make(List(i -> Protocol.writeln_message(output_text)))
|
|
41 |
val message =
|
|
42 |
XML.string(message_prefix) :::
|
|
43 |
List(XML.Elem(Markup(Markup.WRITELN, Markup.Serial(i)), XML.string(title))) :::
|
|
44 |
XML.string(message_suffix)
|
|
45 |
(results, message)
|
|
46 |
}
|
|
47 |
|
|
48 |
(results, List(XML.elem(Markup.TRACING_MESSAGE, message)))
|
|
49 |
}
|
|
50 |
}
|
|
51 |
}
|
|
52 |
|
|
53 |
abstract class Program_Progress(
|
|
54 |
default_heading: String = "Running",
|
|
55 |
default_title: String = "program",
|
|
56 |
override val verbose: Boolean = false
|
|
57 |
) extends Progress {
|
|
58 |
private var _finished_programs: List[Program_Progress.Program] = Nil
|
|
59 |
private var _running_program: Option[Program_Progress.Program] = None
|
|
60 |
|
|
61 |
def output(): (Command.Results, XML.Body) = synchronized {
|
|
62 |
val programs = (_running_program.toList ::: _finished_programs).reverse
|
|
63 |
val programs_output = programs.map(_.output())
|
|
64 |
val results = Command.Results.merge(programs_output.map(_._1))
|
|
65 |
val body = Library.separate(Pretty.Separator, programs_output.map(_._2)).flatten
|
|
66 |
(results, body)
|
|
67 |
}
|
|
68 |
|
|
69 |
private def start_program(heading: String, title: String): Unit = synchronized {
|
|
70 |
_running_program = Some(new Program_Progress.Program(heading, title))
|
|
71 |
}
|
|
72 |
|
|
73 |
def stop_program(): Unit = synchronized {
|
|
74 |
_running_program match {
|
|
75 |
case Some(program) =>
|
|
76 |
program.stop_now()
|
|
77 |
_finished_programs ::= program
|
|
78 |
_running_program = None
|
|
79 |
case None =>
|
|
80 |
}
|
|
81 |
}
|
|
82 |
|
|
83 |
def detect_program(s: String): Option[String]
|
|
84 |
|
|
85 |
override def output(message: Progress.Message): Unit = synchronized {
|
|
86 |
val writeln_msg = if (message.kind == Progress.Kind.writeln) message.text else ""
|
|
87 |
detect_program(writeln_msg).map(Word.explode) match {
|
|
88 |
case Some(a :: bs) =>
|
|
89 |
stop_program()
|
|
90 |
start_program(a, Word.implode(bs))
|
|
91 |
case _ =>
|
|
92 |
if (_running_program.isEmpty) start_program(default_heading, default_title)
|
|
93 |
if (do_output(message)) _running_program.get.output(message)
|
|
94 |
}
|
|
95 |
}
|
|
96 |
}
|