redcar-javamateview 0.1-java
Sign up to get free protection for your applications and to get access to all the features.
- 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,237 @@
|
|
1
|
+
package com.redcareditor.mate;
|
2
|
+
|
3
|
+
import org.eclipse.swt.events.ModifyEvent;
|
4
|
+
import org.eclipse.swt.events.ModifyListener;
|
5
|
+
import org.eclipse.swt.events.SelectionEvent;
|
6
|
+
import org.eclipse.swt.events.SelectionListener;
|
7
|
+
import org.eclipse.swt.events.VerifyEvent;
|
8
|
+
import org.eclipse.swt.events.VerifyListener;
|
9
|
+
|
10
|
+
import org.eclipse.jface.text.IDocumentListener;
|
11
|
+
import org.eclipse.jface.text.IViewportListener;
|
12
|
+
import org.eclipse.jface.text.JFaceTextUtil;
|
13
|
+
import org.eclipse.jface.text.DocumentEvent;
|
14
|
+
|
15
|
+
import com.redcareditor.mate.document.swt.SwtMateTextLocation;
|
16
|
+
import com.redcareditor.onig.Range;
|
17
|
+
|
18
|
+
public class ParserScheduler {
|
19
|
+
public static int LOOK_AHEAD = 300;
|
20
|
+
public static boolean synchronousParsing = false;
|
21
|
+
public int lookAhead;
|
22
|
+
public int lastVisibleLine;
|
23
|
+
public boolean alwaysParseAll;
|
24
|
+
public boolean enabled;
|
25
|
+
public RangeSet changes;
|
26
|
+
public int deactivationLevel;
|
27
|
+
|
28
|
+
public int modifyStart, modifyEnd;
|
29
|
+
public String modifyText;
|
30
|
+
public ParseThunk thunk;
|
31
|
+
public Parser parser;
|
32
|
+
|
33
|
+
public int parsed_upto;
|
34
|
+
public SwtMateTextLocation parsedUpto;
|
35
|
+
|
36
|
+
public ParserScheduler(Parser parser) {
|
37
|
+
this.parser = parser;
|
38
|
+
lookAhead = LOOK_AHEAD;
|
39
|
+
lastVisibleLine = 0;
|
40
|
+
changes = new RangeSet();
|
41
|
+
deactivationLevel = 0;
|
42
|
+
alwaysParseAll = false;
|
43
|
+
modifyStart = -1;
|
44
|
+
enabled = true;
|
45
|
+
setParsedUpto(0);
|
46
|
+
attachListeners();
|
47
|
+
}
|
48
|
+
|
49
|
+
public void close() {
|
50
|
+
if (thunk != null) {
|
51
|
+
thunk.stop();
|
52
|
+
thunk = null;
|
53
|
+
}
|
54
|
+
removeListeners();
|
55
|
+
}
|
56
|
+
|
57
|
+
private VerifyListener verifyListener;
|
58
|
+
private ModifyListener modifyListener;
|
59
|
+
private IViewportListener viewportListener;
|
60
|
+
private IDocumentListener documentListener;
|
61
|
+
|
62
|
+
public void attachListeners() {
|
63
|
+
viewportListener = new IViewportListener() {
|
64
|
+
public void viewportChanged(int verticalOffset) {
|
65
|
+
viewportScrolledCallback();
|
66
|
+
}
|
67
|
+
};
|
68
|
+
|
69
|
+
parser.mateText.viewer.addViewportListener(viewportListener);
|
70
|
+
|
71
|
+
documentListener = new IDocumentListener() {
|
72
|
+
public void documentAboutToBeChanged(DocumentEvent e) {
|
73
|
+
verifyEventCallback(e.fOffset, e.fOffset + e.fLength, e.fText);
|
74
|
+
}
|
75
|
+
|
76
|
+
public void documentChanged(DocumentEvent e) {
|
77
|
+
modifyEventCallback();
|
78
|
+
}
|
79
|
+
};
|
80
|
+
parser.mateText.getDocument().addDocumentListener(documentListener);
|
81
|
+
}
|
82
|
+
|
83
|
+
public void removeListeners() {
|
84
|
+
parser.mateText.viewer.removeViewportListener(viewportListener);
|
85
|
+
parser.mateText.getDocument().removeDocumentListener(documentListener);
|
86
|
+
}
|
87
|
+
|
88
|
+
public void verifyEventCallback(int start, int end, String text) {
|
89
|
+
if (enabled) {
|
90
|
+
modifyStart = start;
|
91
|
+
modifyEnd = end;
|
92
|
+
modifyText = text;
|
93
|
+
}
|
94
|
+
}
|
95
|
+
|
96
|
+
public void modifyEventCallback() {
|
97
|
+
if (enabled) {
|
98
|
+
changes.add(
|
99
|
+
parser.getLineAtOffset(modifyStart),
|
100
|
+
parser.getLineAtOffset(modifyStart + modifyText.length())
|
101
|
+
);
|
102
|
+
modifyStart = -1;
|
103
|
+
modifyEnd = -1;
|
104
|
+
modifyText = null;
|
105
|
+
if (deactivationLevel == 0)
|
106
|
+
processChanges();
|
107
|
+
}
|
108
|
+
}
|
109
|
+
|
110
|
+
public void viewportScrolledCallback() {
|
111
|
+
if (enabled) {
|
112
|
+
lastVisibleLineChanged(JFaceTextUtil.getBottomIndex(parser.mateText.getTextWidget()));
|
113
|
+
}
|
114
|
+
}
|
115
|
+
|
116
|
+
public void deactivate() {
|
117
|
+
deactivationLevel++;
|
118
|
+
}
|
119
|
+
|
120
|
+
public void reactivate() {
|
121
|
+
deactivationLevel--;
|
122
|
+
if (deactivationLevel < 0)
|
123
|
+
deactivationLevel = 0;
|
124
|
+
if (deactivationLevel == 0)
|
125
|
+
processChanges();
|
126
|
+
}
|
127
|
+
|
128
|
+
// Process all change ranges.
|
129
|
+
public void processChanges() {
|
130
|
+
int thisParsedUpto = -1;
|
131
|
+
// System.out.printf("process_changes (lastVisibleLine: %d) (charCount = %d)\n", lastVisibleLine, document.getLength());
|
132
|
+
for (Range range : changes) {
|
133
|
+
if (range.end > thisParsedUpto && range.start <= lastVisibleLine + lookAhead) {
|
134
|
+
int rangeEnd;
|
135
|
+
if (alwaysParseAll) {
|
136
|
+
rangeEnd = parser.getLineCount() - 1;
|
137
|
+
} else {
|
138
|
+
rangeEnd = Math.min(lastVisibleLine + lookAhead, range.end);
|
139
|
+
}
|
140
|
+
//System.out.printf("parseRange from processChanges\n");
|
141
|
+
thisParsedUpto = parseRange(range.start, rangeEnd);
|
142
|
+
}
|
143
|
+
int startOffset = parser.getOffsetAtLine(range.start);
|
144
|
+
int endOffset = parser.getOffsetAtLine(range.end);
|
145
|
+
parser.styledText.redrawRange(startOffset, endOffset - startOffset, false);
|
146
|
+
}
|
147
|
+
// System.out.printf("%s\n", root.pretty(0));
|
148
|
+
changes.ranges.clear();
|
149
|
+
}
|
150
|
+
|
151
|
+
public void thunkFrom(int lineIx) {
|
152
|
+
if (thunk != null) {
|
153
|
+
thunk.delayAndUpdate(lineIx);
|
154
|
+
}
|
155
|
+
else {
|
156
|
+
if (lineIx <= parser.getLineCount() - 1) {
|
157
|
+
thunk = new ParseThunk(parser, lineIx);
|
158
|
+
if (ParserScheduler.synchronousParsing) {
|
159
|
+
thunk.execute();
|
160
|
+
}
|
161
|
+
}
|
162
|
+
}
|
163
|
+
}
|
164
|
+
|
165
|
+
// Parse from from_line to *at least* to_line. Will parse
|
166
|
+
// more if necessary. Returns the index of the last line
|
167
|
+
// parsed.
|
168
|
+
public int parseRange(int fromLine, int toLine) {
|
169
|
+
//System.out.printf("parse_range(%d, %d)\n", fromLine, toLine);
|
170
|
+
|
171
|
+
int lineIx = fromLine;
|
172
|
+
boolean scopeChanged = false;
|
173
|
+
boolean scopeEverChanged = false;
|
174
|
+
while (lineIx <= toLine) {
|
175
|
+
scopeChanged = parser.parseLine(lineIx);
|
176
|
+
if (scopeChanged) {
|
177
|
+
if (scopeEverChanged == false && getParsedUpto() > lineIx) {
|
178
|
+
//System.out.printf(parser.root.pretty(4));
|
179
|
+
//System.out.printf("-- clearFrom(%d) --\n", lineIx);
|
180
|
+
parser.clearFrom(parser.getOffsetAtLine(lineIx + 1));
|
181
|
+
//System.out.printf(parser.root.pretty(4));
|
182
|
+
}
|
183
|
+
setParsedUpto(lineIx);
|
184
|
+
scopeEverChanged = true;
|
185
|
+
}
|
186
|
+
lineIx++;
|
187
|
+
}
|
188
|
+
if (scopeEverChanged) {
|
189
|
+
thunkFrom(lineIx);
|
190
|
+
}
|
191
|
+
|
192
|
+
return toLine;
|
193
|
+
}
|
194
|
+
|
195
|
+
public int parseOnwards(int fromLine) {
|
196
|
+
// The widget can be disposed between the Thunk being created and being executed.
|
197
|
+
if (parser.styledText.isDisposed())
|
198
|
+
return -1;
|
199
|
+
int lineIx = fromLine;
|
200
|
+
int lineCount = parser.getLineCount();
|
201
|
+
int lastLine = Math.min(lastVisibleLine + LOOK_AHEAD, lineCount - 1);
|
202
|
+
int toLine = Math.min(fromLine + LOOK_AHEAD, lastLine);
|
203
|
+
while (lineIx <= toLine) {
|
204
|
+
parser.parseLine(lineIx);
|
205
|
+
setParsedUpto(lineIx);
|
206
|
+
parser.redrawLine(lineIx);
|
207
|
+
lineIx++;
|
208
|
+
}
|
209
|
+
|
210
|
+
return lineIx;
|
211
|
+
}
|
212
|
+
|
213
|
+
public void lastVisibleLineChanged(int newLastVisibleLine) {
|
214
|
+
int oldLastVisibleLine = lastVisibleLine;
|
215
|
+
//System.out.printf("lastVisibleLineChanged(%d)\n", newLastVisibleLine);
|
216
|
+
this.lastVisibleLine = newLastVisibleLine;
|
217
|
+
//System.out.printf("lastVisibleLine: %d, lookAhead: %d, getParsedUpto: %d\n", lastVisibleLine, lookAhead, getParsedUpto());
|
218
|
+
if (lastVisibleLine + lookAhead >= getParsedUpto() && getParsedUpto() < parser.getLineCount() - 1) {
|
219
|
+
int endRange = Math.min(parser.getLineCount() - 1, lastVisibleLine + lookAhead);
|
220
|
+
thunkFrom(getParsedUpto());
|
221
|
+
}
|
222
|
+
}
|
223
|
+
|
224
|
+
public void setParsedUpto(int line_ix) {
|
225
|
+
if (parsedUpto == null) {
|
226
|
+
parsedUpto = (SwtMateTextLocation) parser.mateDocument.getTextLocation(0, 0);
|
227
|
+
parser.mateDocument.addTextLocation("lefts", parsedUpto);
|
228
|
+
}
|
229
|
+
parsedUpto.offset = parser.getOffsetAtLine(line_ix);
|
230
|
+
}
|
231
|
+
|
232
|
+
public int getParsedUpto() {
|
233
|
+
// System.out.printf("parsedUpto %d,%d (/%d)\n", parsedUpto.getOffset(), parsedUpto.getLength(), parser.getCharCount());
|
234
|
+
return parser.getLineAtOffset(parsedUpto.getOffset());
|
235
|
+
}
|
236
|
+
|
237
|
+
}
|
@@ -0,0 +1,152 @@
|
|
1
|
+
package com.redcareditor.mate;
|
2
|
+
|
3
|
+
import java.util.ArrayList;
|
4
|
+
import java.util.HashMap;
|
5
|
+
import java.util.List;
|
6
|
+
import java.util.Map;
|
7
|
+
|
8
|
+
import com.redcareditor.plist.Dict;
|
9
|
+
import com.redcareditor.plist.PlistNode;
|
10
|
+
|
11
|
+
public class Pattern {
|
12
|
+
public Grammar grammar;
|
13
|
+
public String name;
|
14
|
+
public boolean disabled;
|
15
|
+
|
16
|
+
public static Pattern createPattern(List<Pattern> allPatterns, Dict dict) {
|
17
|
+
if (dict.containsElement("match")) {
|
18
|
+
return new SinglePattern(allPatterns, dict);
|
19
|
+
}
|
20
|
+
|
21
|
+
if (dict.containsElement("include")) {
|
22
|
+
return new IncludePattern(dict);
|
23
|
+
}
|
24
|
+
|
25
|
+
if (dict.containsElement("begin")) {
|
26
|
+
return new DoublePattern(allPatterns, dict);
|
27
|
+
}
|
28
|
+
|
29
|
+
return null;
|
30
|
+
}
|
31
|
+
|
32
|
+
public static Map<Integer, String> makeCapturesFromPlist(Dict pd) {
|
33
|
+
if (pd == null)
|
34
|
+
return new HashMap<Integer, String>();
|
35
|
+
Dict pcd;
|
36
|
+
String ns;
|
37
|
+
Map<Integer, String> captures = new HashMap<Integer, String>();
|
38
|
+
for (String sCapnum : pd.value.keySet()) {
|
39
|
+
int capnum = Integer.parseInt(sCapnum);
|
40
|
+
pcd = pd.getDictionary(sCapnum);
|
41
|
+
ns = pcd.getString("name");
|
42
|
+
// System.out.printf("capture: %d, %s\n", capnum, ns);
|
43
|
+
captures.put((Integer) capnum, ns);
|
44
|
+
}
|
45
|
+
return captures;
|
46
|
+
}
|
47
|
+
|
48
|
+
public static void replaceIncludePatterns(List<Pattern> patterns, Grammar grammar) {
|
49
|
+
replaceRepositoryIncludes(patterns, grammar);
|
50
|
+
replaceBaseAndSelfIncludes(patterns, grammar);
|
51
|
+
}
|
52
|
+
|
53
|
+
public static void replaceRepositoryIncludes(List<Pattern> patterns, Grammar grammar) {
|
54
|
+
int i = 0;
|
55
|
+
while (i < patterns.size()) {
|
56
|
+
Pattern p = patterns.get(i);
|
57
|
+
if (p instanceof IncludePattern && p.name.startsWith("#")) {
|
58
|
+
// System.out.printf("repo include: %s\n", p.name);
|
59
|
+
String reponame = p.name.substring(1, p.name.length());
|
60
|
+
List<Pattern> repositoryEntryPatterns = grammar.repository.get(reponame);
|
61
|
+
if (repositoryEntryPatterns != null) {
|
62
|
+
// System.out.printf(" got %d patterns\n", repositoryEntryPatterns.size());
|
63
|
+
patterns.remove(i);
|
64
|
+
patterns.addAll(i, repositoryEntryPatterns);
|
65
|
+
i--;
|
66
|
+
} else {
|
67
|
+
System.out.printf("warning: couldn't find repository key '%s' in grammar '%s'\n", reponame,
|
68
|
+
grammar.name);
|
69
|
+
}
|
70
|
+
}
|
71
|
+
i++;
|
72
|
+
}
|
73
|
+
}
|
74
|
+
|
75
|
+
public static void replaceBaseAndSelfIncludes(List<Pattern> patterns, Grammar grammar) {
|
76
|
+
boolean alreadySelf = false; // some patterns have $self twice
|
77
|
+
Grammar ng;
|
78
|
+
int i = 0;
|
79
|
+
while (i < patterns.size()) {
|
80
|
+
Pattern p = patterns.get(i);
|
81
|
+
if (p instanceof IncludePattern) {
|
82
|
+
if (p.name.startsWith("$")) {
|
83
|
+
if ((p.name.equals("$self") || p.name.equals("$base")) && !alreadySelf) {
|
84
|
+
alreadySelf = true;
|
85
|
+
patterns.remove(i);
|
86
|
+
patterns.addAll(i, grammar.patterns);
|
87
|
+
i--;
|
88
|
+
}
|
89
|
+
//} else if ((ng = Grammar.findByScopeName(p.name)) != null) {
|
90
|
+
// ng.initForUse();
|
91
|
+
// patterns.remove(i);
|
92
|
+
// patterns.addAll(i, ng.patterns);
|
93
|
+
// i--;
|
94
|
+
}
|
95
|
+
}
|
96
|
+
i++;
|
97
|
+
}
|
98
|
+
}
|
99
|
+
|
100
|
+
private static void removePatterns(List<Pattern> patlist, List<Pattern> ps) {
|
101
|
+
for (Pattern p : ps) {
|
102
|
+
patlist.remove(p);
|
103
|
+
}
|
104
|
+
}
|
105
|
+
|
106
|
+
private static void addPatterns(List<Pattern> patlist, List<Pattern> ps) {
|
107
|
+
for (Pattern p : ps) {
|
108
|
+
patlist.add(p);
|
109
|
+
}
|
110
|
+
}
|
111
|
+
|
112
|
+
public void setDisabled(Dict dict) {
|
113
|
+
PlistNode<?> plistNode = dict.value.get("disabled");
|
114
|
+
int intn;
|
115
|
+
if (plistNode != null) {
|
116
|
+
if (plistNode.value instanceof String) {
|
117
|
+
String strn = dict.getString("disabled");
|
118
|
+
intn = Integer.parseInt(strn);
|
119
|
+
}
|
120
|
+
else {
|
121
|
+
intn = dict.getInt("disabled");
|
122
|
+
}
|
123
|
+
switch (intn) {
|
124
|
+
case 1:
|
125
|
+
disabled = true;
|
126
|
+
break;
|
127
|
+
default:
|
128
|
+
disabled = false;
|
129
|
+
break;
|
130
|
+
}
|
131
|
+
} else {
|
132
|
+
disabled = false;
|
133
|
+
}
|
134
|
+
}
|
135
|
+
|
136
|
+
public String prettyName() {
|
137
|
+
if (name == null) {
|
138
|
+
if (this instanceof SinglePattern) {
|
139
|
+
return ((SinglePattern) this).match.pattern;
|
140
|
+
}
|
141
|
+
else if (this instanceof DoublePattern) {
|
142
|
+
return ((DoublePattern) this).begin.pattern;
|
143
|
+
}
|
144
|
+
else {
|
145
|
+
return "unknown";
|
146
|
+
}
|
147
|
+
}
|
148
|
+
else {
|
149
|
+
return name;
|
150
|
+
}
|
151
|
+
}
|
152
|
+
}
|
@@ -0,0 +1,91 @@
|
|
1
|
+
package com.redcareditor.mate;
|
2
|
+
|
3
|
+
import java.util.ArrayList;
|
4
|
+
import java.util.Iterator;
|
5
|
+
import java.util.List;
|
6
|
+
|
7
|
+
import com.redcareditor.onig.Range;
|
8
|
+
|
9
|
+
public class RangeSet implements Iterable<Range> {
|
10
|
+
List<Range> ranges = new ArrayList<Range>();
|
11
|
+
|
12
|
+
public void add(int a, int b) {
|
13
|
+
int insertAt = 0;
|
14
|
+
Range range = new Range(a, b);
|
15
|
+
|
16
|
+
while (insertAt < length() && ranges.get(insertAt).start < range.start) {
|
17
|
+
insertAt++;
|
18
|
+
}
|
19
|
+
|
20
|
+
merge(insertAt, range);
|
21
|
+
}
|
22
|
+
|
23
|
+
public Range get(int i) {
|
24
|
+
return ranges.get(i);
|
25
|
+
}
|
26
|
+
|
27
|
+
public int length() {
|
28
|
+
return size();
|
29
|
+
}
|
30
|
+
|
31
|
+
public int size() {
|
32
|
+
return ranges.size();
|
33
|
+
}
|
34
|
+
|
35
|
+
public int rangeSize() {
|
36
|
+
int sizec = 0;
|
37
|
+
for (int i = 0; i < length(); i++) {
|
38
|
+
sizec += ranges.get(i).end - ranges.get(i).start + 1;
|
39
|
+
}
|
40
|
+
return sizec;
|
41
|
+
}
|
42
|
+
|
43
|
+
public String present() {
|
44
|
+
return toString();
|
45
|
+
}
|
46
|
+
|
47
|
+
public String toString() {
|
48
|
+
StringBuilder sb = new StringBuilder("");
|
49
|
+
for (int i = 0; i < length(); i++) {
|
50
|
+
sb.append(get(i).toString());
|
51
|
+
if (i != length() - 1) {
|
52
|
+
sb.append(", ");
|
53
|
+
}
|
54
|
+
}
|
55
|
+
return sb.toString();
|
56
|
+
}
|
57
|
+
|
58
|
+
public boolean isEmpty() {
|
59
|
+
return ranges.isEmpty();
|
60
|
+
}
|
61
|
+
|
62
|
+
public Iterator<Range> iterator() {
|
63
|
+
return ranges.iterator();
|
64
|
+
}
|
65
|
+
|
66
|
+
private void merge(int mergeAt, Range range) {
|
67
|
+
ranges.add(mergeAt, range);
|
68
|
+
|
69
|
+
if (mergeAt > 0) {
|
70
|
+
Range beforeMerge = ranges.get(mergeAt - 1);
|
71
|
+
if (range.isTouching(beforeMerge)) {
|
72
|
+
ranges.remove(mergeAt);
|
73
|
+
beforeMerge.end = Math.max(beforeMerge.end, range.end);
|
74
|
+
mergeAt--;
|
75
|
+
range = ranges.get(mergeAt);
|
76
|
+
}
|
77
|
+
}
|
78
|
+
|
79
|
+
if (mergeAt + 1 < length()) {
|
80
|
+
Range afterMerge = ranges.get(mergeAt + 1);
|
81
|
+
while (mergeAt < length() - 1 && range.isTouching(afterMerge)) {
|
82
|
+
range.start = Math.min(range.start, afterMerge.start);
|
83
|
+
range.end = Math.max(range.end, afterMerge.end);
|
84
|
+
ranges.remove(mergeAt + 1);
|
85
|
+
if (mergeAt + 1 < length())
|
86
|
+
afterMerge = ranges.get(mergeAt + 1);
|
87
|
+
}
|
88
|
+
}
|
89
|
+
}
|
90
|
+
|
91
|
+
}
|