src/Tools/jEdit/src/proofdocument/ProofDocument.scala
author immler@in.tum.de
Thu Feb 19 20:44:28 2009 +0100 (2009-02-19)
changeset 34526 b504abb6eff6
parent 34516 73225f520f8c
child 34531 db1c28e326fc
permissions -rw-r--r--
tokens and commands as lists
wenzelm@34407
     1
/*
wenzelm@34485
     2
 * Document as list of commands, consisting of lists of tokens
wenzelm@34407
     3
 *
wenzelm@34407
     4
 * @author Johannes Hölzl, TU Munich
wenzelm@34485
     5
 * @author Makarius
wenzelm@34407
     6
 */
wenzelm@34407
     7
wenzelm@34318
     8
package isabelle.proofdocument
wenzelm@34318
     9
immler@34526
    10
import scala.collection.mutable.ListBuffer
wenzelm@34318
    11
import java.util.regex.Pattern
wenzelm@34485
    12
import isabelle.prover.{Prover, Command}
wenzelm@34318
    13
wenzelm@34318
    14
wenzelm@34494
    15
case class StructureChange(
immler@34526
    16
  val before_change: Option[Command],
wenzelm@34494
    17
  val added_commands: List[Command],
wenzelm@34494
    18
  val removed_commands: List[Command])
wenzelm@34485
    19
wenzelm@34483
    20
object ProofDocument
wenzelm@34483
    21
{
wenzelm@34485
    22
  // Be carefully when changing this regex. Not only must it handle the 
wenzelm@34318
    23
  // spurious end of a token but also:  
wenzelm@34318
    24
  // Bug ID: 5050507 Pattern.matches throws StackOverflow Error
wenzelm@34318
    25
  // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5050507
wenzelm@34318
    26
  
wenzelm@34483
    27
  val token_pattern = 
wenzelm@34318
    28
    Pattern.compile(
wenzelm@34318
    29
      "\\{\\*([^*]|\\*[^}]|\\*\\z)*(\\z|\\*\\})|" +
wenzelm@34318
    30
      "\\(\\*([^*]|\\*[^)]|\\*\\z)*(\\z|\\*\\))|" +
wenzelm@34318
    31
      "(\\?'?|')[A-Za-z_0-9.]*|" + 
wenzelm@34318
    32
      "[A-Za-z_0-9.]+|" + 
wenzelm@34318
    33
      "[!#$%&*+-/<=>?@^_|~]+|" +
wenzelm@34318
    34
      "\"([^\\\\\"]?(\\\\(.|\\z))?)*+(\"|\\z)|" +
wenzelm@34318
    35
      "`([^\\\\`]?(\\\\(.|\\z))?)*+(`|\\z)|" +
wenzelm@34318
    36
      "[()\\[\\]{}:;]", Pattern.MULTILINE)
wenzelm@34485
    37
wenzelm@34318
    38
}
wenzelm@34318
    39
wenzelm@34505
    40
class ProofDocument(text: Text, is_command_keyword: String => Boolean)
wenzelm@34483
    41
{
immler@34526
    42
  private var active = false
wenzelm@34456
    43
  def activate() {
wenzelm@34456
    44
    if (!active) {
wenzelm@34318
    45
      active = true
immler@34526
    46
      text_changed(new Text.Change(0, content, content.length))
wenzelm@34318
    47
    }
wenzelm@34456
    48
  }
wenzelm@34485
    49
immler@34526
    50
  text.changes += (change => text_changed(change))
wenzelm@34485
    51
immler@34526
    52
  var tokens = Nil : List[Token]
immler@34526
    53
  var commands = Nil : List[Command]
immler@34526
    54
  def content = Token.string_from_tokens(tokens)
wenzelm@34485
    55
  /** token view **/
wenzelm@34485
    56
immler@34526
    57
  private def text_changed(change: Text.Change)
wenzelm@34485
    58
  {
immler@34526
    59
    val (begin, remaining) = tokens.span(_.stop < change.start)
immler@34526
    60
    val (removed, end) = remaining.span(_.start <= change.start + change.removed)
immler@34526
    61
    for (t <- end) t.start += (change.added.length - change.removed)
wenzelm@34485
    62
immler@34526
    63
    val split_begin = removed.takeWhile(_.start < change.start).
immler@34526
    64
      map (t => new Token(t.start,
immler@34526
    65
                          t.content.substring(0, change.start - t.start),
immler@34526
    66
                          t.kind))
immler@34526
    67
    val split_end = removed.dropWhile(_.stop < change.start + change.removed).
immler@34526
    68
      map (t => new Token(change.start + change.added.length,
immler@34526
    69
                          t.content.substring(change.start + change.removed - t.start),
immler@34526
    70
                          t.kind))
wenzelm@34318
    71
immler@34526
    72
    var invalid_tokens =  split_begin :::
immler@34526
    73
      new Token(change.start, change.added, Token.Kind.OTHER) :: split_end ::: end
immler@34526
    74
    var new_tokens = Nil: List[Token]
immler@34526
    75
    var old_suffix = Nil: List[Token]
wenzelm@34318
    76
immler@34526
    77
    val match_start = invalid_tokens.first.start
immler@34526
    78
    val matcher = ProofDocument.token_pattern.matcher(Token.string_from_tokens(invalid_tokens))
immler@34526
    79
immler@34526
    80
    while (matcher.find() && invalid_tokens != Nil) {
wenzelm@34485
    81
			val kind =
wenzelm@34505
    82
        if (is_command_keyword(matcher.group))
wenzelm@34485
    83
          Token.Kind.COMMAND_START
wenzelm@34494
    84
        else if (matcher.end - matcher.start > 2 && matcher.group.substring(0, 2) == "(*")
wenzelm@34485
    85
          Token.Kind.COMMENT
wenzelm@34485
    86
        else
wenzelm@34485
    87
          Token.Kind.OTHER
immler@34526
    88
      val new_token = new Token(match_start + matcher.start, matcher.group, kind)
immler@34526
    89
      new_tokens ::= new_token
wenzelm@34318
    90
immler@34526
    91
      invalid_tokens = invalid_tokens dropWhile (_.stop < new_token.stop)
immler@34526
    92
      invalid_tokens match {
immler@34526
    93
        case t::ts => if(t.start == new_token.start &&
immler@34526
    94
                         t.start > change.start + change.added.length) {
immler@34526
    95
          old_suffix = ts
immler@34526
    96
          invalid_tokens = Nil
immler@34526
    97
        }
immler@34526
    98
        case _ =>
wenzelm@34318
    99
      }
wenzelm@34318
   100
    }
immler@34526
   101
    val insert = new_tokens.reverse
immler@34526
   102
    tokens = begin ::: insert ::: old_suffix
immler@34526
   103
immler@34526
   104
    token_changed(begin.lastOption,
immler@34526
   105
                  insert,
immler@34526
   106
                  removed,
immler@34526
   107
                  old_suffix.firstOption)
wenzelm@34318
   108
  }
wenzelm@34318
   109
  
wenzelm@34485
   110
  /** command view **/
wenzelm@34485
   111
wenzelm@34485
   112
  val structural_changes = new EventBus[StructureChange]
wenzelm@34485
   113
wenzelm@34496
   114
  def find_command_at(pos: Int): Command = {
wenzelm@34485
   115
    for (cmd <- commands) { if (pos < cmd.stop) return cmd }
wenzelm@34485
   116
    return null
wenzelm@34485
   117
  }
wenzelm@34485
   118
immler@34526
   119
  private def token_changed(before_change: Option[Token],
immler@34526
   120
                            inserted_tokens: List[Token],
immler@34526
   121
                            removed_tokens: List[Token],
immler@34526
   122
                            after_change: Option[Token])
wenzelm@34485
   123
  {
immler@34526
   124
    val (begin, remaining) =
immler@34526
   125
      before_change match {
immler@34526
   126
        case None => (Nil, commands)
immler@34526
   127
        case Some(bc) => commands.break(_.tokens.contains(bc))
immler@34526
   128
      }
immler@34526
   129
    val (_removed, _end) =
immler@34526
   130
      after_change match {
immler@34526
   131
        case None => (remaining, Nil)
immler@34526
   132
        case Some(ac) => remaining.break(_.tokens.contains(ac))
immler@34526
   133
      }
immler@34526
   134
    val (removed, end) = _end match {
immler@34526
   135
      case Nil => (_removed, Nil)
immler@34526
   136
      case acc::end => if (after_change.isDefined && after_change.get.kind == Token.Kind.COMMAND_START)
immler@34526
   137
          (_removed, _end)
immler@34526
   138
        else (_removed ::: List(acc), end)
wenzelm@34485
   139
    }
immler@34526
   140
    val all_removed_tokens = for(c <- removed; t <- c.tokens) yield t
immler@34526
   141
    val (pseudo_new_pre, rest) =
immler@34526
   142
      if (! before_change.isDefined) (Nil, all_removed_tokens)
immler@34526
   143
      else {
immler@34526
   144
        val (a, b) = all_removed_tokens.span (_ != before_change.get)
immler@34526
   145
        b match {
immler@34526
   146
          case Nil => (a, Nil)
immler@34526
   147
          case bc::rest => (a ::: List(bc), b)
immler@34526
   148
        }
wenzelm@34485
   149
      }
immler@34526
   150
    val pseudo_new_post = rest.dropWhile(Some(_) != after_change)
wenzelm@34485
   151
immler@34526
   152
    def tokens_to_commands(tokens: List[Token]): List[Command]= {
immler@34526
   153
      tokens match {
immler@34526
   154
        case Nil => Nil
immler@34526
   155
        case t::ts =>
immler@34526
   156
          val (cmd,rest) = ts.span(_.kind != Token.Kind.COMMAND_START)
immler@34526
   157
          new Command(t::cmd) :: tokens_to_commands (rest)
wenzelm@34485
   158
      }
wenzelm@34485
   159
    }
wenzelm@34485
   160
immler@34526
   161
    System.err.println("ins_tokens: " + inserted_tokens)
immler@34526
   162
    val new_commands = tokens_to_commands(pseudo_new_pre ::: inserted_tokens ::: pseudo_new_post)
immler@34526
   163
    System.err.println("new_commands: " + new_commands)
wenzelm@34485
   164
immler@34526
   165
    commands = begin ::: new_commands ::: end
immler@34526
   166
    val before = begin match {case Nil => None case _ => Some (begin.last)}
immler@34526
   167
    structural_changes.event(new StructureChange(before, new_commands, removed))
immler@34526
   168
/*
immler@34526
   169
    val old = commands
immler@34526
   170
    commands = tokens_to_commands(tokens)
immler@34526
   171
    structural_changes.event(new StructureChange(None, commands, old)) */
wenzelm@34485
   172
  }
wenzelm@34318
   173
}