src/Pure/PIDE/state.scala
author wenzelm
Fri, 07 May 2010 22:00:23 +0200
changeset 36735 42b7f881f5fc
parent 36677 1225dd15827d
child 37044 d93b849cbecd
permissions -rw-r--r--
output symbolic pretty printing markup and format in the front end;

/*  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) =>
                atts match {
                  case Position.Range(begin, end) =>
                    if (kind == Markup.ML_TYPING) {
                      val info = Pretty.string_of(body, margin = 40)
                      state.add_markup(
                        command.markup_node(begin - 1, end - 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 - 1, end - 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 - 1, end - 1, Command.HighlightInfo(kind)))
                    }
                  case _ => state
                }
              case _ =>
                System.err.println("ignored status report: " + elem)
                state
            })
        case _ => add_result(message)
      }
    if (!(this eq changed)) session.command_change.event(command)
    changed
  }
}