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 |
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 |