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.
- data/LICENSE +34 -0
- data/README +58 -0
- data/Rakefile +94 -0
- data/lib/javamateview.rb +41 -0
- data/lib/javamateview/example.rb +334 -0
- data/lib/javamateview/jar/java-mateview.jar +0 -0
- data/lib/javamateview/jcodings.jar +0 -0
- data/lib/javamateview/jdom.jar +0 -0
- data/lib/javamateview/joni.jar +0 -0
- data/spec/onig/match_spec.rb +50 -0
- data/spec/parsing/dynamic_parsing_spec.rb +172 -0
- data/spec/parsing/static_parsing_spec.rb +476 -0
- data/spec/spec_helper.rb +33 -0
- data/src/com/redcareditor/mate/Bundle.java +81 -0
- data/src/com/redcareditor/mate/DoublePattern.java +89 -0
- data/src/com/redcareditor/mate/Grammar.java +129 -0
- data/src/com/redcareditor/mate/IAnnotationAreaListener.java +7 -0
- data/src/com/redcareditor/mate/IGrammarListener.java +5 -0
- data/src/com/redcareditor/mate/IncludePattern.java +10 -0
- data/src/com/redcareditor/mate/LineNumberRulerColumn.java +922 -0
- data/src/com/redcareditor/mate/Marker.java +22 -0
- data/src/com/redcareditor/mate/MateText.java +697 -0
- data/src/com/redcareditor/mate/ParseThunk.java +71 -0
- data/src/com/redcareditor/mate/Parser.java +627 -0
- data/src/com/redcareditor/mate/ParserScheduler.java +237 -0
- data/src/com/redcareditor/mate/Pattern.java +152 -0
- data/src/com/redcareditor/mate/RangeSet.java +91 -0
- data/src/com/redcareditor/mate/Scanner.java +178 -0
- data/src/com/redcareditor/mate/Scope.java +534 -0
- data/src/com/redcareditor/mate/ScopeMatcher.java +162 -0
- data/src/com/redcareditor/mate/SharedTextColors.java +110 -0
- data/src/com/redcareditor/mate/SinglePattern.java +20 -0
- data/src/com/redcareditor/mate/WhitespaceCharacterPainter.java +395 -0
- data/src/com/redcareditor/mate/colouring/Colourer.java +16 -0
- data/src/com/redcareditor/mate/colouring/swt/MarginPaintListener.java +62 -0
- data/src/com/redcareditor/mate/colouring/swt/SwtColourer.java +501 -0
- data/src/com/redcareditor/mate/document/MateDocument.java +15 -0
- data/src/com/redcareditor/mate/document/MateTextFactory.java +9 -0
- data/src/com/redcareditor/mate/document/MateTextLocation.java +8 -0
- data/src/com/redcareditor/mate/document/MateTextLocationComparator.java +17 -0
- data/src/com/redcareditor/mate/document/MateTextRange.java +18 -0
- data/src/com/redcareditor/mate/document/swt/SwtMateDocument.java +143 -0
- data/src/com/redcareditor/mate/document/swt/SwtMateTextLocation.java +88 -0
- data/src/com/redcareditor/mate/document/swt/SwtMateTextRange.java +92 -0
- data/src/com/redcareditor/mate/document/swt/SwtScopePositionUpdater.java +90 -0
- data/src/com/redcareditor/mate/undo/MateTextUndoManager.java +11 -0
- data/src/com/redcareditor/mate/undo/swt/SwtMateTextUndoManager.java +166 -0
- data/src/com/redcareditor/onig/Match.java +212 -0
- data/src/com/redcareditor/onig/NullMatch.java +57 -0
- data/src/com/redcareditor/onig/NullRx.java +29 -0
- data/src/com/redcareditor/onig/Range.java +45 -0
- data/src/com/redcareditor/onig/Rx.java +167 -0
- data/src/com/redcareditor/plist/Dict.java +119 -0
- data/src/com/redcareditor/plist/PlistNode.java +52 -0
- data/src/com/redcareditor/plist/PlistPropertyLoader.java +44 -0
- data/src/com/redcareditor/theme/ScopeSelector.java +39 -0
- data/src/com/redcareditor/theme/Theme.java +122 -0
- data/src/com/redcareditor/theme/ThemeManager.java +41 -0
- data/src/com/redcareditor/theme/ThemeSetting.java +78 -0
- data/src/com/redcareditor/util/FileUtility.java +64 -0
- data/src/com/redcareditor/util/SingleLineFormatter.java +11 -0
- data/src/com/redcareditor/util/swt/ColourUtil.java +56 -0
- data/src/ruby/java-mateview.rb +68 -0
- data/test/com/redcareditor/mate/BundleTest.java +33 -0
- data/test/com/redcareditor/mate/EmptyRangeSetTest.java +27 -0
- data/test/com/redcareditor/mate/FilledRangeSetTest.java +82 -0
- data/test/com/redcareditor/mate/GrammarTest.java +158 -0
- data/test/com/redcareditor/mate/MateTextTest.java +35 -0
- data/test/com/redcareditor/mate/ScopeMatcherMatchingTest.java +55 -0
- data/test/com/redcareditor/mate/ScopeMatcherRankingTest.java +40 -0
- data/test/com/redcareditor/onig/RxTest.java +54 -0
- data/test/com/redcareditor/plist/DictTest.java +33 -0
- data/test/com/redcareditor/theme/RailsCastThemeTest.java +37 -0
- data/test/com/redcareditor/theme/ScopeSelectorTest.java +38 -0
- data/test/com/redcareditor/theme/ThemeManagerTest.java +29 -0
- data/test/com/redcareditor/util/swt/ColourUtilTest.java +17 -0
- 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
|
+
}
|