src/Tools/jEdit/src/text_structure.scala
changeset 75393 87ebf5a50283
parent 73909 1d0d9772fff0
child 75423 d164bf04d05e
equal deleted inserted replaced
75388:b3ca4a6ed74b 75393:87ebf5a50283
    15 import org.gjt.sp.jedit.textarea.{TextArea, StructureMatcher, Selection}
    15 import org.gjt.sp.jedit.textarea.{TextArea, StructureMatcher, Selection}
    16 import org.gjt.sp.jedit.buffer.JEditBuffer
    16 import org.gjt.sp.jedit.buffer.JEditBuffer
    17 import org.gjt.sp.jedit.Buffer
    17 import org.gjt.sp.jedit.Buffer
    18 
    18 
    19 
    19 
    20 object Text_Structure
    20 object Text_Structure {
    21 {
       
    22   /* token navigator */
    21   /* token navigator */
    23 
    22 
    24   class Navigator(syntax: Outer_Syntax, buffer: JEditBuffer, comments: Boolean)
    23   class Navigator(syntax: Outer_Syntax, buffer: JEditBuffer, comments: Boolean) {
    25   {
       
    26     val limit: Int = PIDE.options.value.int("jedit_structure_limit") max 0
    24     val limit: Int = PIDE.options.value.int("jedit_structure_limit") max 0
    27 
    25 
    28     def iterator(line: Int, lim: Int = limit): Iterator[Text.Info[Token]] =
    26     def iterator(line: Int, lim: Int = limit): Iterator[Text.Info[Token]] = {
    29     {
       
    30       val it = Token_Markup.line_token_iterator(syntax, buffer, line, line + lim)
    27       val it = Token_Markup.line_token_iterator(syntax, buffer, line, line + lim)
    31       if (comments) it.filterNot(_.info.is_space) else it.filter(_.info.is_proper)
    28       if (comments) it.filterNot(_.info.is_space) else it.filter(_.info.is_proper)
    32     }
    29     }
    33 
    30 
    34     def reverse_iterator(line: Int, lim: Int = limit): Iterator[Text.Info[Token]] =
    31     def reverse_iterator(line: Int, lim: Int = limit): Iterator[Text.Info[Token]] = {
    35     {
       
    36       val it = Token_Markup.line_token_reverse_iterator(syntax, buffer, line, line - lim)
    32       val it = Token_Markup.line_token_reverse_iterator(syntax, buffer, line, line - lim)
    37       if (comments) it.filterNot(_.info.is_space) else it.filter(_.info.is_proper)
    33       if (comments) it.filterNot(_.info.is_space) else it.filter(_.info.is_proper)
    38     }
    34     }
    39   }
    35   }
    40 
    36 
    41 
    37 
    42   /* indentation */
    38   /* indentation */
    43 
    39 
    44   object Indent_Rule extends IndentRule
    40   object Indent_Rule extends IndentRule {
    45   {
       
    46     private val keyword_open = Keyword.theory_goal ++ Keyword.proof_open
    41     private val keyword_open = Keyword.theory_goal ++ Keyword.proof_open
    47     private val keyword_close = Keyword.proof_close
    42     private val keyword_close = Keyword.proof_close
    48 
    43 
    49     def apply(buffer: JEditBuffer, current_line: Int, prev_line0: Int, prev_prev_line0: Int,
    44     def apply(
    50       actions: JList[IndentAction]): Unit =
    45       buffer: JEditBuffer,
    51     {
    46       current_line: Int,
       
    47       prev_line0: Int,
       
    48       prev_prev_line0: Int,
       
    49       actions: JList[IndentAction]
       
    50     ): Unit = {
    52       Isabelle.buffer_syntax(buffer) match {
    51       Isabelle.buffer_syntax(buffer) match {
    53         case Some(syntax) =>
    52         case Some(syntax) =>
    54           val keywords = syntax.keywords
    53           val keywords = syntax.keywords
    55           val nav = new Navigator(syntax, buffer, true)
    54           val nav = new Navigator(syntax, buffer, true)
    56 
    55 
    85 
    84 
    86           def prev_span: Iterator[Token] =
    85           def prev_span: Iterator[Token] =
    87             nav.reverse_iterator(prev_line).map(_.info).takeWhile(tok => !tok.is_begin_or_command)
    86             nav.reverse_iterator(prev_line).map(_.info).takeWhile(tok => !tok.is_begin_or_command)
    88 
    87 
    89 
    88 
    90           val script_indent: Text.Info[Token] => Int =
    89           val script_indent: Text.Info[Token] => Int = {
    91           {
       
    92             val opt_rendering: Option[JEdit_Rendering] =
    90             val opt_rendering: Option[JEdit_Rendering] =
    93               if (PIDE.options.value.bool("jedit_indent_script"))
    91               if (PIDE.options.value.bool("jedit_indent_script"))
    94                 GUI_Thread.now {
    92                 GUI_Thread.now {
    95                   (for {
    93                   (for {
    96                     text_area <- JEdit_Lib.jedit_text_areas(buffer)
    94                     text_area <- JEdit_Lib.jedit_text_areas(buffer)
   191         case None =>
   189         case None =>
   192       }
   190       }
   193     }
   191     }
   194   }
   192   }
   195 
   193 
   196   def line_content(buffer: JEditBuffer, keywords: Keyword.Keywords,
   194   def line_content(
   197     range: Text.Range, ctxt: Scan.Line_Context): (List[Token], Scan.Line_Context) =
   195     buffer: JEditBuffer,
   198   {
   196     keywords: Keyword.Keywords,
       
   197     range: Text.Range,
       
   198     ctxt: Scan.Line_Context
       
   199   ): (List[Token], Scan.Line_Context) = {
   199     val text = JEdit_Lib.get_text(buffer, range).getOrElse("")
   200     val text = JEdit_Lib.get_text(buffer, range).getOrElse("")
   200     val (toks, ctxt1) = Token.explode_line(keywords, text, ctxt)
   201     val (toks, ctxt1) = Token.explode_line(keywords, text, ctxt)
   201     val toks1 = toks.filterNot(_.is_space)
   202     val toks1 = toks.filterNot(_.is_space)
   202     (toks1, ctxt1)
   203     (toks1, ctxt1)
   203   }
   204   }
   204 
   205 
   205   def split_line_content(buffer: JEditBuffer, keywords: Keyword.Keywords, line: Int, caret: Int)
   206   def split_line_content(
   206     : (List[Token], List[Token]) =
   207     buffer: JEditBuffer,
   207   {
   208     keywords: Keyword.Keywords,
       
   209     line: Int,
       
   210     caret: Int
       
   211   ): (List[Token], List[Token]) = {
   208     val line_range = JEdit_Lib.line_range(buffer, line)
   212     val line_range = JEdit_Lib.line_range(buffer, line)
   209     val ctxt0 = Token_Markup.Line_Context.before(buffer, line).get_context
   213     val ctxt0 = Token_Markup.Line_Context.before(buffer, line).get_context
   210     val (toks1, ctxt1) = line_content(buffer, keywords, Text.Range(line_range.start, caret), ctxt0)
   214     val (toks1, ctxt1) = line_content(buffer, keywords, Text.Range(line_range.start, caret), ctxt0)
   211     val (toks2, _) = line_content(buffer, keywords, Text.Range(caret, line_range.stop), ctxt1)
   215     val (toks2, _) = line_content(buffer, keywords, Text.Range(caret, line_range.stop), ctxt1)
   212     (toks1, toks2)
   216     (toks1, toks2)
   213   }
   217   }
   214 
   218 
   215 
   219 
   216   /* structure matching */
   220   /* structure matching */
   217 
   221 
   218   object Matcher extends StructureMatcher
   222   object Matcher extends StructureMatcher {
   219   {
       
   220     private def find_block(
   223     private def find_block(
   221       open: Token => Boolean,
   224       open: Token => Boolean,
   222       close: Token => Boolean,
   225       close: Token => Boolean,
   223       reset: Token => Boolean,
   226       reset: Token => Boolean,
   224       restrict: Token => Boolean,
   227       restrict: Token => Boolean,
   225       it: Iterator[Text.Info[Token]]): Option[(Text.Range, Text.Range)] =
   228       it: Iterator[Text.Info[Token]]
   226     {
   229     ): Option[(Text.Range, Text.Range)] = {
   227       val range1 = it.next().range
   230       val range1 = it.next().range
   228       it.takeWhile(info => !info.info.is_command || restrict(info.info)).
   231       it.takeWhile(info => !info.info.is_command || restrict(info.info)).
   229         scanLeft((range1, 1))(
   232         scanLeft((range1, 1))(
   230           { case ((r, d), Text.Info(range, tok)) =>
   233           { case ((r, d), Text.Info(range, tok)) =>
   231               if (open(tok)) (range, d + 1)
   234               if (open(tok)) (range, d + 1)
   233               else if (reset(tok)) (range, 0)
   236               else if (reset(tok)) (range, 0)
   234               else (r, d) }
   237               else (r, d) }
   235         ).collectFirst({ case (range2, 0) => (range1, range2) })
   238         ).collectFirst({ case (range2, 0) => (range1, range2) })
   236     }
   239     }
   237 
   240 
   238     private def find_pair(text_area: TextArea): Option[(Text.Range, Text.Range)] =
   241     private def find_pair(text_area: TextArea): Option[(Text.Range, Text.Range)] = {
   239     {
       
   240       val buffer = text_area.getBuffer
   242       val buffer = text_area.getBuffer
   241       val caret_line = text_area.getCaretLine
   243       val caret_line = text_area.getCaretLine
   242       val caret = text_area.getCaretPosition
   244       val caret = text_area.getCaretPosition
   243 
   245 
   244       Isabelle.buffer_syntax(text_area.getBuffer) match {
   246       Isabelle.buffer_syntax(text_area.getBuffer) match {
   328           val line = text_area.getBuffer.getLineOfOffset(range.start)
   330           val line = text_area.getBuffer.getLineOfOffset(range.start)
   329           new StructureMatcher.Match(Matcher, line, range.start, line, range.stop)
   331           new StructureMatcher.Match(Matcher, line, range.start, line, range.stop)
   330         case None => null
   332         case None => null
   331       }
   333       }
   332 
   334 
   333     def selectMatch(text_area: TextArea): Unit =
   335     def selectMatch(text_area: TextArea): Unit = {
   334     {
       
   335       def get_span(offset: Text.Offset): Option[Text.Range] =
   336       def get_span(offset: Text.Offset): Option[Text.Range] =
   336         for {
   337         for {
   337           syntax <- Isabelle.buffer_syntax(text_area.getBuffer)
   338           syntax <- Isabelle.buffer_syntax(text_area.getBuffer)
   338           span <- Token_Markup.command_span(syntax, text_area.getBuffer, offset)
   339           span <- Token_Markup.command_span(syntax, text_area.getBuffer, offset)
   339         } yield span.range
   340         } yield span.range