src/Pure/PIDE/state.scala
author wenzelm
Wed, 05 May 2010 22:23:45 +0200
changeset 36676 ac7961d42ac3
parent 36012 src/Pure/Thy/state.scala@0614676f14d4
child 36677 1225dd15827d
permissions -rw-r--r--
some rearrangement of Scala sources;

/*  Title:      Pure/PIDE/state.scala
    Author:     Fabian Immler, TU Munich
    Author:     Makarius

Accumulating results from prover.
*/

package isabelle


class State(
  val command: Command,
  val status: Command.Status.Value,
  val rev_results: List[XML.Tree],
  val markup_root: Markup_Text)
{
  def this(command: Command) =
    this(command, Command.Status.UNPROCESSED, Nil, command.empty_markup)


  /* content */

  private def set_status(st: Command.Status.Value): State =
    new State(command, st, rev_results, markup_root)

  private def add_result(res: XML.Tree): State =
    new State(command, status, res :: rev_results, markup_root)

  private def add_markup(node: Markup_Tree): State =
    new State(command, status, rev_results, markup_root + node)

  lazy val results = rev_results.reverse


  /* markup */

  lazy val highlight: Markup_Text =
  {
    markup_root.filter(_.info match {
      case Command.HighlightInfo(_) => true
      case _ => false
    })
  }

  private lazy val types: List[Markup_Node] =
    markup_root.filter(_.info match {
      case Command.TypeInfo(_) => true
      case _ => false }).flatten

  def type_at(pos: Int): Option[String] =
  {
    types.find(t => t.start <= pos && pos < t.stop) match {
      case Some(t) =>
        t.info match {
          case Command.TypeInfo(ty) => Some(command.source(t.start, t.stop) + ": " + ty)
          case _ => None
        }
      case None => None
    }
  }

  private lazy val refs: List[Markup_Node] =
    markup_root.filter(_.info match {
      case Command.RefInfo(_, _, _, _) => true
      case _ => false }).flatten

  def ref_at(pos: Int): Option[Markup_Node] =
    refs.find(t => t.start <= pos && pos < t.stop)


  /* message dispatch */

  def + (session: Session, message: XML.Tree): State =
  {
    val changed: State =
      message match {
        case XML.Elem(Markup.MESSAGE, (Markup.CLASS, Markup.STATUS) :: _, elems) =>
          (this /: elems)((state, elem) =>
            elem match {
              case XML.Elem(Markup.UNPROCESSED, _, _) => state.set_status(Command.Status.UNPROCESSED)
              case XML.Elem(Markup.FINISHED, _, _) => state.set_status(Command.Status.FINISHED)
              case XML.Elem(Markup.FAILED, _, _) => state.set_status(Command.Status.FAILED)
              case XML.Elem(kind, atts, body) =>
                val (begin, end) = Position.get_offsets(atts)
                if (begin.isEmpty || end.isEmpty) state
                else if (kind == Markup.ML_TYPING) {
                  val info = body.head.asInstanceOf[XML.Text].content   // FIXME proper match!?
                  state.add_markup(
                    command.markup_node(begin.get - 1, end.get - 1, Command.TypeInfo(info)))
                }
                else if (kind == Markup.ML_REF) {
                  body match {
                    case List(XML.Elem(Markup.ML_DEF, atts, _)) =>
                      state.add_markup(command.markup_node(
                        begin.get - 1, end.get - 1,
                        Command.RefInfo(
                          Position.get_file(atts),
                          Position.get_line(atts),
                          Position.get_id(atts),
                          Position.get_offset(atts))))
                    case _ => state
                  }
                }
                else {
                  state.add_markup(
                    command.markup_node(begin.get - 1, end.get - 1, Command.HighlightInfo(kind)))
                }
              case _ =>
                System.err.println("ignored status report: " + elem)
                state
            })
        case _ => add_result(message)
      }
    if (!(this eq changed)) session.command_change.event(command)
    changed
  }
}