redcar-javamateview 0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. data/LICENSE +34 -0
  2. data/README +58 -0
  3. data/Rakefile +94 -0
  4. data/lib/javamateview.rb +41 -0
  5. data/lib/javamateview/example.rb +334 -0
  6. data/lib/javamateview/jar/java-mateview.jar +0 -0
  7. data/lib/javamateview/jcodings.jar +0 -0
  8. data/lib/javamateview/jdom.jar +0 -0
  9. data/lib/javamateview/joni.jar +0 -0
  10. data/spec/onig/match_spec.rb +50 -0
  11. data/spec/parsing/dynamic_parsing_spec.rb +172 -0
  12. data/spec/parsing/static_parsing_spec.rb +476 -0
  13. data/spec/spec_helper.rb +33 -0
  14. data/src/com/redcareditor/mate/Bundle.java +81 -0
  15. data/src/com/redcareditor/mate/DoublePattern.java +89 -0
  16. data/src/com/redcareditor/mate/Grammar.java +129 -0
  17. data/src/com/redcareditor/mate/IAnnotationAreaListener.java +7 -0
  18. data/src/com/redcareditor/mate/IGrammarListener.java +5 -0
  19. data/src/com/redcareditor/mate/IncludePattern.java +10 -0
  20. data/src/com/redcareditor/mate/LineNumberRulerColumn.java +922 -0
  21. data/src/com/redcareditor/mate/Marker.java +22 -0
  22. data/src/com/redcareditor/mate/MateText.java +697 -0
  23. data/src/com/redcareditor/mate/ParseThunk.java +71 -0
  24. data/src/com/redcareditor/mate/Parser.java +627 -0
  25. data/src/com/redcareditor/mate/ParserScheduler.java +237 -0
  26. data/src/com/redcareditor/mate/Pattern.java +152 -0
  27. data/src/com/redcareditor/mate/RangeSet.java +91 -0
  28. data/src/com/redcareditor/mate/Scanner.java +178 -0
  29. data/src/com/redcareditor/mate/Scope.java +534 -0
  30. data/src/com/redcareditor/mate/ScopeMatcher.java +162 -0
  31. data/src/com/redcareditor/mate/SharedTextColors.java +110 -0
  32. data/src/com/redcareditor/mate/SinglePattern.java +20 -0
  33. data/src/com/redcareditor/mate/WhitespaceCharacterPainter.java +395 -0
  34. data/src/com/redcareditor/mate/colouring/Colourer.java +16 -0
  35. data/src/com/redcareditor/mate/colouring/swt/MarginPaintListener.java +62 -0
  36. data/src/com/redcareditor/mate/colouring/swt/SwtColourer.java +501 -0
  37. data/src/com/redcareditor/mate/document/MateDocument.java +15 -0
  38. data/src/com/redcareditor/mate/document/MateTextFactory.java +9 -0
  39. data/src/com/redcareditor/mate/document/MateTextLocation.java +8 -0
  40. data/src/com/redcareditor/mate/document/MateTextLocationComparator.java +17 -0
  41. data/src/com/redcareditor/mate/document/MateTextRange.java +18 -0
  42. data/src/com/redcareditor/mate/document/swt/SwtMateDocument.java +143 -0
  43. data/src/com/redcareditor/mate/document/swt/SwtMateTextLocation.java +88 -0
  44. data/src/com/redcareditor/mate/document/swt/SwtMateTextRange.java +92 -0
  45. data/src/com/redcareditor/mate/document/swt/SwtScopePositionUpdater.java +90 -0
  46. data/src/com/redcareditor/mate/undo/MateTextUndoManager.java +11 -0
  47. data/src/com/redcareditor/mate/undo/swt/SwtMateTextUndoManager.java +166 -0
  48. data/src/com/redcareditor/onig/Match.java +212 -0
  49. data/src/com/redcareditor/onig/NullMatch.java +57 -0
  50. data/src/com/redcareditor/onig/NullRx.java +29 -0
  51. data/src/com/redcareditor/onig/Range.java +45 -0
  52. data/src/com/redcareditor/onig/Rx.java +167 -0
  53. data/src/com/redcareditor/plist/Dict.java +119 -0
  54. data/src/com/redcareditor/plist/PlistNode.java +52 -0
  55. data/src/com/redcareditor/plist/PlistPropertyLoader.java +44 -0
  56. data/src/com/redcareditor/theme/ScopeSelector.java +39 -0
  57. data/src/com/redcareditor/theme/Theme.java +122 -0
  58. data/src/com/redcareditor/theme/ThemeManager.java +41 -0
  59. data/src/com/redcareditor/theme/ThemeSetting.java +78 -0
  60. data/src/com/redcareditor/util/FileUtility.java +64 -0
  61. data/src/com/redcareditor/util/SingleLineFormatter.java +11 -0
  62. data/src/com/redcareditor/util/swt/ColourUtil.java +56 -0
  63. data/src/ruby/java-mateview.rb +68 -0
  64. data/test/com/redcareditor/mate/BundleTest.java +33 -0
  65. data/test/com/redcareditor/mate/EmptyRangeSetTest.java +27 -0
  66. data/test/com/redcareditor/mate/FilledRangeSetTest.java +82 -0
  67. data/test/com/redcareditor/mate/GrammarTest.java +158 -0
  68. data/test/com/redcareditor/mate/MateTextTest.java +35 -0
  69. data/test/com/redcareditor/mate/ScopeMatcherMatchingTest.java +55 -0
  70. data/test/com/redcareditor/mate/ScopeMatcherRankingTest.java +40 -0
  71. data/test/com/redcareditor/onig/RxTest.java +54 -0
  72. data/test/com/redcareditor/plist/DictTest.java +33 -0
  73. data/test/com/redcareditor/theme/RailsCastThemeTest.java +37 -0
  74. data/test/com/redcareditor/theme/ScopeSelectorTest.java +38 -0
  75. data/test/com/redcareditor/theme/ThemeManagerTest.java +29 -0
  76. data/test/com/redcareditor/util/swt/ColourUtilTest.java +17 -0
  77. metadata +134 -0
@@ -0,0 +1,71 @@
1
+ package com.redcareditor.mate;
2
+
3
+ import org.eclipse.swt.widgets.Display;
4
+
5
+ public class ParseThunk implements Runnable {
6
+ int WAIT = 500;
7
+ int DELAY_IF_MODIFIED_WITHIN = 400;
8
+ int DELAY_FOR_USER_INPUT = 10;
9
+
10
+ public long timeCreated;
11
+ public long lastModificationTime;
12
+ public int parseFrom;
13
+ public boolean closed;
14
+ public int wait = WAIT;
15
+
16
+ private Parser parser;
17
+
18
+ public ParseThunk(Parser parser, int parseFrom) {
19
+ this.parser = parser;
20
+ this.timeCreated = System.currentTimeMillis();
21
+ this.lastModificationTime = System.currentTimeMillis();
22
+ this.parseFrom = parseFrom;
23
+ // System.out.printf("New thunk. parseFrom:%d time: %d\n", parseFrom, timeCreated);
24
+ enqueue();
25
+ }
26
+
27
+ public void enqueue() {
28
+ Display.getCurrent().timerExec(wait, this);
29
+ }
30
+
31
+ public void stop() {
32
+ closed = true;
33
+ }
34
+
35
+ public void run() {
36
+ if (closed)
37
+ return;
38
+ // System.out.printf("Run thunk. time: %s\n", System.currentTimeMillis());
39
+ if (lastModificationTime > System.currentTimeMillis() - DELAY_IF_MODIFIED_WITHIN) {
40
+ // System.out.printf(" Postponing thunk.\n", parseFrom);
41
+ Display.getCurrent().timerExec(wait, this);
42
+ }
43
+ else {
44
+ // System.out.printf(" Once, after 0.5 seconds, parse from %d.\n", parseFrom);
45
+ execute();
46
+ }
47
+ }
48
+
49
+ public void delayAndUpdate(int lineIx) {
50
+ // System.out.printf("Delay thunk time: %s\n", System.currentTimeMillis());
51
+ this.lastModificationTime = System.currentTimeMillis();
52
+ this.parseFrom = Math.min(parseFrom, lineIx);
53
+ }
54
+
55
+ public void execute() {
56
+ parser.parserScheduler.thunk = null;
57
+ //System.out.printf("Thunk: parseOnwards(%d)\n", parseFrom);
58
+ parseFrom = parser.parserScheduler.parseOnwards(parseFrom);
59
+ if (parseFrom == -1)
60
+ return;
61
+ if (parseFrom >= parser.getLineCount() - 1)
62
+ return;
63
+ if (parseFrom >= parser.parserScheduler.lastVisibleLine + ParserScheduler.LOOK_AHEAD - 5)
64
+ return;
65
+ if (parseFrom <= parser.getLineCount() - 1) {
66
+ wait = DELAY_FOR_USER_INPUT;
67
+ enqueue();
68
+ }
69
+ }
70
+ }
71
+
@@ -0,0 +1,627 @@
1
+ package com.redcareditor.mate;
2
+
3
+ import java.util.ArrayList;
4
+ import java.util.List;
5
+ import java.util.Map;
6
+ import java.util.logging.Logger;
7
+ import java.util.logging.Handler;
8
+ import java.util.logging.ConsoleHandler;
9
+ import java.util.logging.Level;
10
+
11
+ import org.eclipse.swt.custom.StyledText;
12
+ import org.eclipse.swt.widgets.Display;
13
+ import org.eclipse.swt.widgets.ScrollBar;
14
+
15
+ import org.eclipse.jface.text.BadLocationException;
16
+ import org.eclipse.jface.text.Document;
17
+ import org.eclipse.jface.text.IRegion;
18
+
19
+ import com.redcareditor.mate.ParserScheduler;
20
+ import com.redcareditor.mate.document.MateDocument;
21
+ import com.redcareditor.mate.document.MateTextLocation;
22
+ import com.redcareditor.mate.document.swt.SwtMateDocument;
23
+ import com.redcareditor.onig.Match;
24
+ import com.redcareditor.onig.Rx;
25
+
26
+ public class Parser {
27
+ public static int linesParsed = 0;
28
+ public Logger logger;
29
+
30
+ public Grammar grammar;
31
+ public MateText mateText;
32
+ public Document document;
33
+ public StyledText styledText;
34
+ public MateDocument mateDocument;
35
+
36
+ public Scope root;
37
+ public ParserScheduler parserScheduler;
38
+
39
+ public Parser(Grammar g, MateText m) {
40
+ g.initForUse();
41
+ grammar = g;
42
+ mateText = m;
43
+ styledText = m.getTextWidget();
44
+ makeRoot();
45
+ mateDocument = m.getMateDocument();
46
+ document = (Document) m.getDocument();
47
+ parserScheduler = new ParserScheduler(this);
48
+ logger = Logger.getLogger("JMV.Parser ");
49
+ logger.setUseParentHandlers(false);
50
+ for (Handler h : logger.getHandlers()) {
51
+ logger.removeHandler(h);
52
+ }
53
+ logger.addHandler(MateText.consoleHandler());
54
+ logger.setLevel(Level.INFO);
55
+ }
56
+
57
+ public void close() {
58
+ parserScheduler.close();
59
+ }
60
+
61
+ public void setRoot(Scope root) {
62
+ this.root = root;
63
+ root.setMateText(mateText);
64
+ }
65
+
66
+ public void makeRoot() {
67
+ this.root = new Scope(mateText, this.grammar.scopeName);
68
+ this.root.isOpen = true;
69
+ DoublePattern dp = new DoublePattern();
70
+ dp.name = this.grammar.name;
71
+ dp.patterns = this.grammar.patterns;
72
+ dp.grammar = this.grammar;
73
+ this.root.pattern = dp;
74
+ }
75
+
76
+ public int getLineAtOffset(int offset) {
77
+ try {
78
+ return document.getLineOfOffset(offset);
79
+ } catch (BadLocationException e) {
80
+ System.out.printf("*** Warning BadLocationException offset:%d\n", offset);
81
+ e.printStackTrace();
82
+ return -1;
83
+ }
84
+ }
85
+
86
+ public int getOffsetAtLine(int line) {
87
+ try {
88
+ return document.getLineOffset(line);
89
+ } catch (BadLocationException e) {
90
+ System.out.printf("*** Warning BadLocationException");
91
+ e.printStackTrace();
92
+ return -1;
93
+ }
94
+ }
95
+
96
+ public int getLineCount() {
97
+ return document.getNumberOfLines();
98
+ }
99
+
100
+ public int getCharCount() {
101
+ return document.getLength();
102
+ }
103
+
104
+ public String getLine(int line) {
105
+ try {
106
+ IRegion region = document.getLineInformation(line);
107
+ return document.get(region.getOffset(), region.getLength());
108
+ } catch (BadLocationException e) {
109
+ System.out.printf("*** Warning BadLocationException");
110
+ e.printStackTrace();
111
+ return "";
112
+ }
113
+ }
114
+
115
+
116
+ public boolean shouldColour() {
117
+ return (parserScheduler.modifyStart == -1);
118
+ }
119
+
120
+ public void redrawLine(int lineIx) {
121
+ // System.out.printf("redrawLine(%d)\n", lineIx);
122
+ int startOffset = getOffsetAtLine(lineIx);
123
+ int endOffset;
124
+ int lineCount = getLineCount();
125
+ if (lineIx + 1 < lineCount) {
126
+ endOffset = getOffsetAtLine(lineIx + 1) - 1;
127
+ }
128
+ else {
129
+ endOffset = getCharCount();
130
+ }
131
+ styledText.redrawRange(startOffset, endOffset - startOffset, false);
132
+ }
133
+
134
+ private Scope scopeBeforeStartOfLine(int lineIx) {
135
+ Scope startScope = this.root.scopeAt(lineIx, 0);
136
+ // System.out.printf("scopeBeforeStartOfLine: %s\n", startScope.pattern.name);
137
+ if (startScope.getStart().getLine() == lineIx) { // || startScope.pattern instanceof SinglePattern) {
138
+ startScope = startScope.containingDoubleScope(lineIx);
139
+ // System.out.printf("scopeBeforeStartOfLine: up %s\n", startScope.pattern.name);
140
+ }
141
+
142
+ return startScope;
143
+ }
144
+
145
+ private Scope scopeAfterEndOfLine(int lineIx, int lineLength) {
146
+ Scope endScope = this.root.scopeAt(lineIx, lineLength - 1);
147
+ if (endScope.getStart().getLine() == lineIx ) {
148
+ endScope = endScope.containingDoubleScope(lineIx);
149
+ }
150
+
151
+ return endScope;
152
+ }
153
+
154
+ public void clearFrom(int offset) {
155
+ root.clearFrom(offset);
156
+ }
157
+
158
+ public boolean parseLine(int lineIx) {
159
+ Parser.linesParsed++;
160
+ String line = getLine(lineIx) + "\n";
161
+ int length = line.length();
162
+ //if (length > 1)
163
+ // logger.info(String.format("parseLine(%d) \"%s\"", lineIx, line.substring(0, line.length() - 1)));
164
+ //else
165
+ // logger.info(String.format("parseLine(%d)", lineIx));
166
+ if (lineIx > parserScheduler.getParsedUpto())
167
+ parserScheduler.setParsedUpto(lineIx);
168
+ //System.out.printf("getParsedUpto: %d\n", getParsedUpto());
169
+ Scope startScope = scopeBeforeStartOfLine(lineIx);
170
+ Scope endScope1 = scopeAfterEndOfLine(lineIx, length);
171
+ //logger.info(String.format(" startScope is: %s", startScope.name));
172
+ //logger.info(String.format(" endScope1: %s", endScope1.name));
173
+ Scanner scanner = new Scanner(startScope, line, lineIx);
174
+ ArrayList<Scope> allScopes = new ArrayList<Scope>();
175
+ allScopes.add(startScope);
176
+ ArrayList<Scope> closedScopes = new ArrayList<Scope>();
177
+ ArrayList<Scope> removedScopes = new ArrayList<Scope>();
178
+ allScopes.add(startScope);
179
+ //logger.info(String.format("start pretty:\n%s", root.pretty(4)));
180
+ for (Marker m : scanner) {
181
+ Scope expectedScope = getExpectedScope(scanner.getCurrentScope(), lineIx, length, scanner.position);
182
+ // if (expectedScope != null)
183
+ // logger.info(String.format("expectedScope: %s (%d, %d)", expectedScope.name, expectedScope.getStart().getLine(),
184
+ // expectedScope.getStart().getLineOffset()));
185
+ // else
186
+ // logger.info("no expected scope");
187
+ // logger.info(String.format(" scope: %s %d-%d (line length: %d)",
188
+ // m.pattern.name, m.from, m.match.getCapture(0).end, length));
189
+ if (m.isCloseScope) {
190
+ //logger.info(" (closing)");
191
+ closeScope(scanner, expectedScope, lineIx, line, length, m,
192
+ allScopes, closedScopes, removedScopes);
193
+ }
194
+ else if (m.pattern instanceof DoublePattern) {
195
+ //logger.info(" (opening)");
196
+ openScope(scanner, expectedScope, lineIx, line, length, m,
197
+ allScopes, closedScopes, removedScopes);
198
+ }
199
+ else {
200
+ //logger.info(" (single)");
201
+ singleScope(scanner, expectedScope, lineIx, line, length, m,
202
+ allScopes, closedScopes, removedScopes);
203
+ }
204
+ //System.out.printf("pretty:\n%s\n", root.pretty(2));
205
+ scanner.position = m.match.getByteCapture(0).end;
206
+ }
207
+ clearLine(lineIx, startScope, allScopes, closedScopes, removedScopes);
208
+ Scope endScope2 = scopeAfterEndOfLine(lineIx, length);
209
+ //logger.info(String.format(" end_scope2: %s\n", endScope2.name));
210
+ //System.out.printf("end pretty: %s\n", this.root.pretty(4));
211
+ // if (colourer != null) {
212
+ // // System.out.printf("before_uncolour_scopes\n");
213
+ // colourer.uncolourScopes(removedScopes);
214
+ // // System.out.printf("before_colour_line_with_scopes\n");
215
+ // colourer.colourLineWithScopes(allScopes);
216
+ // // System.out.printf("after_colour_line_with_scopes\n");
217
+ // ]
218
+ // else {
219
+ // // stdout.printf("no colourer");
220
+ // ]
221
+ return (endScope1 != endScope2);
222
+ }
223
+
224
+ public Scope getExpectedScope(Scope currentScope, int line, int lineLength, int lineOffset) {
225
+ // System.out.printf("get_expected_scope(%s, %d, %d)\n", currentScope.name, line, lineOffset);
226
+ if (lineOffset == lineLength)
227
+ return null;
228
+ Scope expectedScope = currentScope.firstChildAfter(mateDocument.getTextLocation(line, lineOffset));
229
+ // System.out.printf("first_child_after: %s\n", expectedScope.name);
230
+ assert(expectedScope != currentScope);
231
+ if (expectedScope != null) {
232
+ if (expectedScope.getStart().getLine() != line)
233
+ expectedScope = null;
234
+ while (expectedScope != null && expectedScope.isCapture) {
235
+ expectedScope = expectedScope.parent;
236
+ }
237
+ }
238
+ return expectedScope;
239
+ }
240
+
241
+ public void closeScope(Scanner scanner, Scope expectedScope, int lineIx, String line,
242
+ int length, Marker m, ArrayList<Scope> allScopes,
243
+ ArrayList<Scope> closedScopes, ArrayList<Scope> removedScopes) {
244
+ String endMatchString = line.substring(m.from, m.match.getCapture(0).end);
245
+
246
+ boolean is_ended = !scanner.getCurrentScope().isOpen; //(scanner.getCurrentScope().getEnd() != null);
247
+ boolean equal_ends = false;
248
+ boolean equal_inner_ends = false;
249
+ boolean equal_match_strings = false;
250
+
251
+ if (is_ended) {
252
+ equal_ends = (scanner.getCurrentScope().getEnd().equals(mateDocument.getTextLocation(lineIx, m.match.getCapture(0).end)));
253
+ equal_inner_ends = (scanner.getCurrentScope().getInnerEnd().equals(mateDocument.getTextLocation(lineIx, m.from)));
254
+ equal_match_strings = (scanner.getCurrentScope().endMatchString.equals(endMatchString));
255
+ }
256
+
257
+ if (is_ended && equal_ends && equal_inner_ends && equal_match_strings) {
258
+ // System.out.printf("closing scope matches expected\n");
259
+ // we have already parsed this line and this scope ends here
260
+
261
+ // Re-add the captures from the end of the current scope to the
262
+ // tracking arrays
263
+ for (Scope child : scanner.getCurrentScope().children) {
264
+ if (child.isCapture &&
265
+ child.getStart().getLine() == lineIx) {
266
+ if (!closedScopes.contains(child))
267
+ closedScopes.add(child);
268
+ if (!allScopes.contains(child))
269
+ allScopes.add(child);
270
+ }
271
+ }
272
+ }
273
+ else {
274
+ // System.out.printf("closing scope does not match expected\n");
275
+ // stdout.printf("closing scope at %d\n", m.from);
276
+ // if (colourer != null) {
277
+ // colourer.uncolourScope(scanner.getCurrentScope(), false);
278
+ // ]
279
+ setInnerEndPosSafely(scanner.getCurrentScope(), m, lineIx, length, 0);
280
+ setEndPosSafely(scanner.getCurrentScope(), m, lineIx, length, 0);
281
+ scanner.getCurrentScope().isOpen = false;
282
+ scanner.getCurrentScope().endMatchString = endMatchString;
283
+ //stdout.printf("end_match_string: '%s'\n", scanner.current_scope.end_match_string);
284
+ if (expectedScope != null) {
285
+ scanner.getCurrentScope().removeChild(expectedScope);
286
+ removedScopes.add(expectedScope);
287
+ // @removed_scopes << expected_scope
288
+ }
289
+ }
290
+ removeCloseCaptures(scanner.getCurrentScope());
291
+ handleCaptures(lineIx, length, line, scanner.getCurrentScope(), m, allScopes, closedScopes);
292
+ removedScopes.add(scanner.getCurrentScope()); // so it gets uncoloured
293
+ closedScopes.add(scanner.getCurrentScope());
294
+ scanner.setCurrentScope(scanner.getCurrentScope().parent);
295
+ allScopes.add(scanner.getCurrentScope());
296
+ }
297
+
298
+
299
+ public void openScope(Scanner scanner, Scope expectedScope, int lineIx,
300
+ String line, int length, Marker m,
301
+ ArrayList<Scope> allScopes, ArrayList<Scope> closedScopes, ArrayList<Scope> removedScopes ) {
302
+ // System.out.printf("[opening with %d patterns], \n", ((DoublePattern) m.pattern).patterns.size());
303
+ Scope s = new Scope(mateText, m.pattern.name);
304
+ s.pattern = m.pattern;
305
+ s.openMatch = m.match;
306
+ setStartPosSafely(s, m, lineIx, length, 0);
307
+ setInnerStartPosSafely(s, m, lineIx, length, 0);
308
+ s.beginMatchString = line.substring(m.from, m.match.getCapture(0).end);
309
+
310
+ s.isOpen = true;
311
+ s.isCapture = false;
312
+ s.parent = scanner.getCurrentScope();
313
+ Scope newScope = s;
314
+ // is this a bug? captures aren't necessarily to be put into all_scopes yet surely?
315
+ if (expectedScope != null) {
316
+ // check mod ending scopes as the new one will not have a closing marker
317
+ // but the expected one will:
318
+ // stdout.printf("%s == %s and %s == %s and %s == %s and %s == %s and %s == %s",
319
+ // name, other.name, pattern.name, other.pattern.name, start_loc().to_s(),
320
+ // other.start_loc().to_s(), inner_start_loc().to_s(), other.inner_start_loc().to_s(),
321
+ // begin_match_string, other.begin_match_string);
322
+ // if (!s.name.equals(expectedScope.name)) System.out.printf("different names\n");
323
+ // if (!s.pattern.name.equals(expectedScope.pattern.name)) System.out.printf("different patterns\n");
324
+ // if (!s.getStart().equals(expectedScope.getStart())) System.out.printf("different starts\n");
325
+ // if (!s.getInnerStart().equals(expectedScope.getInnerStart())) System.out.printf("different inner starts\n");
326
+ // if (!s.beginMatchString.equals(expectedScope.beginMatchString)) {
327
+ // System.out.printf("different beginMatchStrings '%s'/'%s'\n", s.beginMatchString, expectedScope.beginMatchString);
328
+ // }
329
+ if (s.surfaceIdenticalToModuloEnding(expectedScope)) {
330
+ // System.out.printf("surface_identical_mod_ending: keep expected\n");
331
+ // don't need to do anything as we have already found this,
332
+ // but let's keep the old scope since it will have children and what not.
333
+ newScope = expectedScope;
334
+ for (Scope child : expectedScope.children) {
335
+ // if (!child.isCapture) {
336
+ closedScopes.add(child);
337
+ allScopes.add(child);
338
+ // }
339
+ }
340
+ // handleCaptures(lineIx, length, line, s, m, allScopes, closedScopes);
341
+ scanner.setCurrentScope(expectedScope);
342
+ }
343
+ else {
344
+ // System.out.printf("surface_NOT_identical_mod_ending: replace expected\n");
345
+ if (s.overlapsWith(expectedScope)) {
346
+ scanner.getCurrentScope().removeChild(expectedScope);
347
+ // removed_scopes << expected_scope
348
+ removedScopes.add(expectedScope);
349
+ }
350
+ handleCaptures(lineIx, length, line, s, m, allScopes, closedScopes);
351
+ scanner.getCurrentScope().addChild(s);
352
+ scanner.setCurrentScope(s);
353
+ }
354
+ }
355
+ else {
356
+ handleCaptures(lineIx, length, line, s, m, allScopes, closedScopes);
357
+ scanner.getCurrentScope().addChild(s);
358
+ scanner.setCurrentScope(s);
359
+ }
360
+ allScopes.add(newScope);
361
+ }
362
+
363
+ private void singleScope(Scanner scanner, Scope expectedScope, int lineIx,
364
+ String line, int length, Marker m,
365
+ ArrayList<Scope> allScopes, ArrayList<Scope> closedScopes,
366
+ ArrayList<Scope> removedScopes) {
367
+ Scope s = new Scope(this.mateText, m.pattern.name);
368
+ s.pattern = m.pattern;
369
+ s.openMatch = m.match;
370
+ setStartPosSafely(s, m, lineIx, length, 0);
371
+ setEndPosSafely(s, m, lineIx, length, 0);
372
+ s.isOpen = false;
373
+ s.isCapture = false;
374
+ // System.out.printf("beginMatchString '%s' %d - %d\n", new String(line.getBytes(), m.from, m.match.getCapture(0).end - m.from), m.from, m.match.getCapture(0).end);
375
+ // s.beginMatchString = new String(line.getBytes(), m.from, m.match.getCapture(0).end - m.from);
376
+ s.beginMatchString = line.substring(m.match.getCapture(0).start, m.match.getCapture(0).end);
377
+ s.parent = scanner.getCurrentScope();
378
+ Scope newScope = s;
379
+ if (expectedScope != null) {
380
+ if (s.surfaceIdenticalTo(expectedScope)) {
381
+ newScope = expectedScope;
382
+ for (Scope child : expectedScope.children) {
383
+ closedScopes.add(child);
384
+ }
385
+ }
386
+ else {
387
+ handleCaptures(lineIx, length, line, s, m, allScopes, closedScopes);
388
+ if (s.overlapsWith(expectedScope)) {
389
+ if (expectedScope == scanner.getCurrentScope()) {
390
+ // we expected this scope to close, but it doesn't
391
+ }
392
+ else {
393
+ scanner.getCurrentScope().removeChild(expectedScope);
394
+ // removed_scopes << expectedScope
395
+ removedScopes.add(expectedScope);
396
+ }
397
+ }
398
+ scanner.getCurrentScope().addChild(s);
399
+ }
400
+ }
401
+ else {
402
+ handleCaptures(lineIx, length, line, s, m, allScopes, closedScopes);
403
+ scanner.getCurrentScope().addChild(s);
404
+ }
405
+ allScopes.add(newScope);
406
+ closedScopes.add(newScope);
407
+ }
408
+
409
+ private boolean atEndOfNonFinalLine(int lineIx, int length, int to) {
410
+ return to == length && getLineCount() > lineIx+1;
411
+ }
412
+
413
+ public void setStartPosSafely(Scope scope, Marker m, int lineIx, int length, int cap) {
414
+ int to = m.match.getCapture(cap).start;
415
+ // if (atEndOfNonFinalLine(lineIx, length, to))
416
+ // scope.setStartPos(lineIx+1, 0, false);
417
+ // else
418
+ scope.setStartPos(lineIx, Math.min(to, length), false);
419
+ }
420
+
421
+ public void setInnerStartPosSafely(Scope scope, Marker m, int lineIx, int length, int cap) {
422
+ int to = m.match.getCapture(cap).start;
423
+ // if (atEndOfNonFinalLine(lineIx, length, to))
424
+ // scope.setInnerStartPos(lineIx+1, 0, false);
425
+ // else
426
+ scope.setInnerStartPos(lineIx, Math.min(to, length), false);
427
+ }
428
+
429
+ public void setInnerEndPosSafely(Scope scope, Marker m, int lineIx, int length, int cap) {
430
+ int from = m.match.getCapture(cap).start;
431
+ // if (atEndOfNonFinalLine(lineIx, length, from)) {
432
+ // scope.setInnerEndPos(lineIx, length, true);
433
+ // }
434
+ // else {
435
+ scope.setInnerEndPos(lineIx, Math.min(from, length-1), true);
436
+ // }
437
+ }
438
+
439
+ public void setEndPosSafely(Scope scope, Marker m, int lineIx, int length, int cap) {
440
+ int to = m.match.getCapture(cap).end;
441
+ // if (atEndOfNonFinalLine(lineIx, length, to)) {
442
+ // scope.setEndPos(lineIx, length, true);
443
+ // }
444
+ // else {
445
+ scope.setEndPos(lineIx, Math.min(to, length-1), true);
446
+ // }
447
+ }
448
+
449
+ // Opens scopes for captures AND creates closing regexp from
450
+ // captures if necessary.
451
+ public void handleCaptures(int lineIx, int length, String line,
452
+ Scope scope, Marker m, ArrayList<Scope> allScopes, ArrayList<Scope> closedScopes) {
453
+ makeClosingRegex(line, scope, m);
454
+ collectChildCaptures(lineIx, length, scope, m, allScopes, closedScopes);
455
+ }
456
+
457
+ public Rx makeClosingRegex(String line, Scope scope, Marker m) {
458
+ if (m.pattern instanceof DoublePattern && !m.isCloseScope) {
459
+ DoublePattern dp = (DoublePattern) m.pattern;
460
+ // System.out.printf("making closing regex: %s\n", dp.endString);
461
+ Rx rx = Rx.createRx("\\\\(\\d+)");
462
+ Match match;
463
+ int pos = 0;
464
+ StringBuilder src = new StringBuilder("");
465
+ boolean found = false;
466
+ while ((match = rx.search(dp.endString, pos, (int) dp.endString.length())) != null) {
467
+ found = true;
468
+ src.append(dp.endString.substring(pos, match.getCapture(0).start));
469
+ String numstr = dp.endString.substring(match.getCapture(1).start, match.getCapture(1).end);
470
+ int num = Integer.parseInt(numstr);
471
+ // System.out.printf("capture found: %d\n", num);
472
+ String capstr = line.substring(m.match.getCapture(num).start, m.match.getCapture(num).end);
473
+ src.append(Rx.escape(capstr));
474
+ pos = match.getCapture(1).end;
475
+ }
476
+ if (found)
477
+ src.append(dp.endString.substring(pos, dp.endString.length()));
478
+ else
479
+ src.append(dp.endString);
480
+ // System.out.printf("close re: '%s'\n", src.toString());
481
+ scope.closingRegex = Rx.createRx(src.toString());
482
+ }
483
+ return null;
484
+ }
485
+
486
+ public void removeCloseCaptures(Scope scope) {
487
+ int i = 0;
488
+ ArrayList<Scope> children = scope.children;
489
+ while (i < children.size()) {
490
+ Scope childScope = children.get(i);
491
+ if (childScope.isCloseCapture) {
492
+ children.remove(i);
493
+ i--;
494
+ }
495
+ i++;
496
+ }
497
+ }
498
+
499
+ public void collectChildCaptures(int lineIx, int length, Scope scope,
500
+ Marker m, ArrayList<Scope> allScopes, ArrayList<Scope> closedScopes) {
501
+ Scope s;
502
+ Map<Integer, String> captures;
503
+ boolean isCloseCaptures = false;
504
+ if (m.pattern instanceof SinglePattern) {
505
+ captures = ((SinglePattern) m.pattern).captures;
506
+ }
507
+ else {
508
+ if (m.isCloseScope) {
509
+ isCloseCaptures = true;
510
+ captures = ((DoublePattern) m.pattern).endCaptures;
511
+ }
512
+ else {
513
+ captures = ((DoublePattern) m.pattern).beginCaptures;
514
+ }
515
+ if (((DoublePattern) m.pattern).bothCaptures != null) {
516
+ captures = ((DoublePattern) m.pattern).bothCaptures;
517
+ }
518
+ }
519
+ List<Scope> captureScopes = new ArrayList<Scope>();
520
+ // create capture scopes
521
+ if (captures != null) {
522
+ for (Integer cap : captures.keySet()) {
523
+ if (m.match.numCaptures() - 1 >= cap && m.match.getCapture(cap).start != -1) {
524
+ s = new Scope(mateText, captures.get(cap));
525
+ s.pattern = scope.pattern;
526
+ s.setStartPos(lineIx, Math.min(m.match.getCapture(cap).start, length-1), false);
527
+ setInnerEndPosSafely(s, m, lineIx, length, cap);
528
+ setEndPosSafely(s, m, lineIx, length, cap);
529
+ s.isOpen = false;
530
+ s.isCapture = true;
531
+ s.isCloseCapture = isCloseCaptures;
532
+ s.parent = scope;
533
+ captureScopes.add(s);
534
+ allScopes.add(s);
535
+ closedScopes.add(s);
536
+ }
537
+ }
538
+ }
539
+ // Now we arrange the capture scopes into a tree under the matched
540
+ // scope. We do this by processing the captures in order of offset and
541
+ // length. For each capture, we check to see if it is a child of an already
542
+ // placed capture, and if so we add it as a child (we know that the latest
543
+ // such capture is the one to add it to by the ordering). If not we
544
+ // add it as a child of the matched scope.
545
+
546
+ List<Scope> placedScopes = new ArrayList<Scope>();
547
+ Scope parentScope;
548
+ while (captureScopes.size() > 0) {
549
+ s = null;
550
+ // find first and longest remaining scope (put it in 's')
551
+ for (Scope cs : captureScopes) {
552
+ if (s == null ||
553
+ cs.getStart().compareTo(s.getStart()) < 0 ||
554
+ (cs.getStart().compareTo(s.getStart()) == 0 && cs.getLength() > s.getLength())) {
555
+ s = cs;
556
+ }
557
+ }
558
+ //System.out.printf("arrange: %s, start: %d, length: %d\n", s.name, s.startOffset(), s.endOffset() - s.startOffset());
559
+ // look for somewhere to put it from placed_scopes
560
+ parentScope = null;
561
+ for (Scope ps : placedScopes) {
562
+ if (s.getStart().compareTo(ps.getStart()) >= 0 && s.getEnd().compareTo(ps.getEnd()) <= 0) {
563
+ parentScope = ps;
564
+ }
565
+ }
566
+ if (parentScope != null) {
567
+ parentScope.addChild(s);
568
+ s.parent = parentScope;
569
+ }
570
+ else {
571
+ scope.addChild(s);
572
+ }
573
+ // logger.info(String.format(" capture %s", s.name));
574
+ placedScopes.add(s);
575
+ captureScopes.remove(s);
576
+ }
577
+ }
578
+
579
+ private ArrayList<Scope> deleteAnyOnLineNotIn(Scope cs, int lineIx, ArrayList<Scope> allScopes) {
580
+ int startOffset = getOffsetAtLine(lineIx);
581
+ int endOffset;
582
+ if (lineIx == getLineCount() - 1)
583
+ endOffset = getCharCount();
584
+ else
585
+ endOffset = getOffsetAtLine(lineIx + 1);
586
+ return cs.deleteAnyBetweenNotIn(startOffset, endOffset, allScopes);
587
+ }
588
+
589
+ private void clearLine(int lineIx, Scope startScope, ArrayList<Scope> allScopes,
590
+ ArrayList<Scope> closedScopes, ArrayList<Scope> removedScopes) {
591
+ // If we are reparsing, we might find that some scopes have disappeared,
592
+ // delete them:
593
+ Scope cs = startScope;
594
+ while (cs != null) {
595
+ // stdout.printf(" removing_scopes from: %s\n", cs.name);
596
+ ArrayList<Scope> newRemovedScopes = deleteAnyOnLineNotIn(cs, lineIx, allScopes);
597
+ removedScopes.addAll(newRemovedScopes);
598
+ cs = cs.parent;
599
+ }
600
+
601
+ // any that we expected to close on this line that now don't?
602
+ // first build list of scopes that close on this line (including ones
603
+ // that did but haven't been removed yet).
604
+ ArrayList<Scope> scopesThatClosedOnLine = new ArrayList<Scope>();
605
+ Scope ts = startScope;
606
+ while (ts.parent != null) {
607
+ if (ts.getInnerEnd().getLine() == lineIx) {
608
+ scopesThatClosedOnLine.add(ts);
609
+ }
610
+ ts = ts.parent;
611
+ }
612
+ for (Scope s : scopesThatClosedOnLine) {
613
+ if (!closedScopes.contains(s)) {
614
+ if (s.isCapture) {
615
+ s.parent.removeChild(s);
616
+ removedScopes.add(s);
617
+ }
618
+ else {
619
+ int line = getLineCount() - 1;
620
+ int lineOffset = getCharCount() - getOffsetAtLine(line);
621
+ s.removeEnd();
622
+ s.isOpen = true;
623
+ }
624
+ }
625
+ }
626
+ }
627
+ }