redcar-javamateview 0.1-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 +142 -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
+ }