|
@@ -6,8 +6,6 @@
|
6
|
6
|
package org.openzen.zenscript.ide.ui.view.editor;
|
7
|
7
|
|
8
|
8
|
import java.io.IOException;
|
9
|
|
-import java.util.Timer;
|
10
|
|
-import java.util.TimerTask;
|
11
|
9
|
import org.openzen.drawablegui.DCanvas;
|
12
|
10
|
import org.openzen.drawablegui.DComponent;
|
13
|
11
|
import org.openzen.drawablegui.DDimensionPreferences;
|
|
@@ -52,10 +50,9 @@ public class SourceEditor implements DComponent {
|
52
|
50
|
private int selectionLineHeight;
|
53
|
51
|
|
54
|
52
|
private int lineBarWidth;
|
55
|
|
- private CursorPosition cursorStart = null;
|
56
|
|
- private CursorPosition cursorEnd = null;
|
|
53
|
+ private SourcePosition cursorStart = null;
|
|
54
|
+ private SourcePosition cursorEnd = null;
|
57
|
55
|
|
58
|
|
- private Timer blink = new Timer();
|
59
|
56
|
private boolean cursorBlink = true;
|
60
|
57
|
|
61
|
58
|
private int mouseDownX = -1;
|
|
@@ -67,13 +64,6 @@ public class SourceEditor implements DComponent {
|
67
|
64
|
tokens = new TokenModel(sourceFile.getName(), tab.length());
|
68
|
65
|
tokenListener = tokens.addListener(new TokenListener());
|
69
|
66
|
|
70
|
|
- blink.scheduleAtFixedRate(new TimerTask() {
|
71
|
|
- @Override
|
72
|
|
- public void run() {
|
73
|
|
- blink();
|
74
|
|
- }
|
75
|
|
- }, 300, 300);
|
76
|
|
-
|
77
|
67
|
try {
|
78
|
68
|
TokenParser<ZSToken, ZSTokenType> parser = ZSTokenParser.createRaw(sourceFile.getName(), new ReaderCharReader(sourceFile.read()), tab.length());
|
79
|
69
|
tokens.set(parser);
|
|
@@ -91,6 +81,7 @@ public class SourceEditor implements DComponent {
|
91
|
81
|
selectionLineHeight = textLineHeight + style.selectionPaddingTop + style.selectionPaddingBottom;
|
92
|
82
|
|
93
|
83
|
dimensionPreferences.setValue(new DDimensionPreferences(0, fullLineHeight * tokens.getLineCount()));
|
|
84
|
+ context.setTimer(300, this::blink);
|
94
|
85
|
}
|
95
|
86
|
|
96
|
87
|
@Override
|
|
@@ -126,25 +117,25 @@ public class SourceEditor implements DComponent {
|
126
|
117
|
|
127
|
118
|
if (cursorStart != null && !cursorStart.equals(cursorEnd)) {
|
128
|
119
|
if (cursorStart.line == cursorEnd.line) {
|
129
|
|
- int y = cursorStart.getY();
|
130
|
|
- int x1 = cursorStart.getX();
|
131
|
|
- int x2 = cursorEnd.getX();
|
|
120
|
+ int y = getY(cursorStart);
|
|
121
|
+ int x1 = getX(cursorStart);
|
|
122
|
+ int x2 = getX(cursorEnd);
|
132
|
123
|
int fromX = Math.min(x1, x2);
|
133
|
124
|
int toX = Math.max(x1, x2);
|
134
|
125
|
canvas.fillRectangle(fromX, y, toX - fromX, selectionLineHeight, style.selectionColor);
|
135
|
126
|
} else {
|
136
|
|
- CursorPosition from = cursorStart.line < cursorEnd.line ? cursorStart : cursorEnd;
|
137
|
|
- CursorPosition to = cursorStart.line < cursorEnd.line ? cursorEnd : cursorStart;
|
|
127
|
+ SourcePosition from = SourcePosition.min(cursorStart, cursorEnd);
|
|
128
|
+ SourcePosition to = SourcePosition.max(cursorStart, cursorEnd);
|
138
|
129
|
|
139
|
|
- int fromX = from.getX();
|
140
|
|
- canvas.fillRectangle(fromX, from.getY(), bounds.width - fromX, selectionLineHeight, style.selectionColor);
|
|
130
|
+ int fromX = getX(from);
|
|
131
|
+ canvas.fillRectangle(fromX, getY(from), bounds.width - fromX, selectionLineHeight, style.selectionColor);
|
141
|
132
|
|
142
|
133
|
for (int i = from.line + 1; i < to.line; i++) {
|
143
|
134
|
canvas.fillRectangle(x, lineToY(i), bounds.width - x, selectionLineHeight, style.selectionColor);
|
144
|
135
|
}
|
145
|
136
|
|
146
|
|
- int toX = to.getX();
|
147
|
|
- canvas.fillRectangle(x, to.getY(), toX - x, selectionLineHeight, style.selectionColor);
|
|
137
|
+ int toX = getX(to);
|
|
138
|
+ canvas.fillRectangle(x, getY(to), toX - x, selectionLineHeight, style.selectionColor);
|
148
|
139
|
}
|
149
|
140
|
}
|
150
|
141
|
|
|
@@ -169,8 +160,8 @@ public class SourceEditor implements DComponent {
|
169
|
160
|
}
|
170
|
161
|
|
171
|
162
|
if (cursorEnd != null && cursorBlink) {
|
172
|
|
- int cursorX = cursorEnd.getX();
|
173
|
|
- int cursorY = cursorEnd.getY();
|
|
163
|
+ int cursorX = getX(cursorEnd);
|
|
164
|
+ int cursorY = getY(cursorEnd);
|
174
|
165
|
canvas.fillRectangle(cursorX, cursorY, 2, selectionLineHeight, 0xFF000000);
|
175
|
166
|
}
|
176
|
167
|
}
|
|
@@ -189,23 +180,23 @@ public class SourceEditor implements DComponent {
|
189
|
180
|
public void onMouseClick(DMouseEvent e) {
|
190
|
181
|
context.focus(this);
|
191
|
182
|
|
192
|
|
- CursorPosition position = getPositionAt(e.x, e.y);
|
|
183
|
+ SourcePosition position = getPositionAt(e.x, e.y);
|
193
|
184
|
if (e.isDoubleClick()) {
|
194
|
185
|
// select entire word
|
195
|
|
- TokenPosition token = getTokenAt(position);
|
|
186
|
+ TokenModel.Position tokenPosition = tokens.getPosition(position.line, position.offset);
|
196
|
187
|
setCursor(
|
197
|
|
- new CursorPosition(position.line, position.offset - token.offset),
|
198
|
|
- new CursorPosition(position.line, position.offset + token.token.content.length() - token.offset));
|
|
188
|
+ new SourcePosition(tokens, position.line, position.offset - tokenPosition.offset),
|
|
189
|
+ new SourcePosition(tokens, position.line, position.offset - tokenPosition.offset + tokens.getTokenAt(tokenPosition).content.length()));
|
199
|
190
|
} else if (e.isTripleClick()) {
|
200
|
191
|
setCursor(
|
201
|
|
- new CursorPosition(position.line, 0),
|
202
|
|
- new CursorPosition(position.line + 1, 0));
|
|
192
|
+ new SourcePosition(tokens, position.line, 0),
|
|
193
|
+ new SourcePosition(tokens, position.line + 1, 0));
|
203
|
194
|
} else {
|
204
|
195
|
setCursor(position, position);
|
205
|
196
|
}
|
206
|
197
|
}
|
207
|
198
|
|
208
|
|
- private void setCursor(CursorPosition start, CursorPosition end) {
|
|
199
|
+ private void setCursor(SourcePosition start, SourcePosition end) {
|
209
|
200
|
if (cursorStart != null)
|
210
|
201
|
repaint(cursorStart, cursorEnd);
|
211
|
202
|
|
|
@@ -231,7 +222,7 @@ public class SourceEditor implements DComponent {
|
231
|
222
|
|
232
|
223
|
@Override
|
233
|
224
|
public void onMouseDrag(DMouseEvent e) {
|
234
|
|
- CursorPosition start = cursorStart;
|
|
225
|
+ SourcePosition start = cursorStart;
|
235
|
226
|
if (!dragging)
|
236
|
227
|
start = getPositionAt(mouseDownX, mouseDownY);
|
237
|
228
|
|
|
@@ -248,7 +239,8 @@ public class SourceEditor implements DComponent {
|
248
|
239
|
|
249
|
240
|
{
|
250
|
241
|
int line = cursorEnd.line - 1;
|
251
|
|
- CursorPosition position = new CursorPosition(
|
|
242
|
+ SourcePosition position = new SourcePosition(
|
|
243
|
+ tokens,
|
252
|
244
|
line,
|
253
|
245
|
Math.min(tokens.getLineLength(line), cursorEnd.offset));
|
254
|
246
|
setCursor(shift ? cursorStart : position, position);
|
|
@@ -260,7 +252,8 @@ public class SourceEditor implements DComponent {
|
260
|
252
|
|
261
|
253
|
{
|
262
|
254
|
int line = cursorEnd.line + 1;
|
263
|
|
- CursorPosition position = new CursorPosition(
|
|
255
|
+ SourcePosition position = new SourcePosition(
|
|
256
|
+ tokens,
|
264
|
257
|
line,
|
265
|
258
|
Math.min(tokens.getLineLength(line), cursorEnd.offset));
|
266
|
259
|
setCursor(shift ? cursorStart : position, position);
|
|
@@ -271,12 +264,12 @@ public class SourceEditor implements DComponent {
|
271
|
264
|
return;
|
272
|
265
|
|
273
|
266
|
{
|
274
|
|
- CursorPosition position;
|
|
267
|
+ SourcePosition position;
|
275
|
268
|
if (cursorEnd.offset == 0) {
|
276
|
269
|
int line = cursorEnd.line - 1;
|
277
|
|
- position = new CursorPosition(line, tokens.getLineLength(line));
|
|
270
|
+ position = new SourcePosition(tokens, line, tokens.getLineLength(line));
|
278
|
271
|
} else {
|
279
|
|
- position = new CursorPosition(cursorEnd.line, cursorEnd.offset - 1);
|
|
272
|
+ position = new SourcePosition(tokens, cursorEnd.line, cursorEnd.offset - 1);
|
280
|
273
|
}
|
281
|
274
|
setCursor(shift ? cursorStart : position, position);
|
282
|
275
|
}
|
|
@@ -286,11 +279,11 @@ public class SourceEditor implements DComponent {
|
286
|
279
|
return;
|
287
|
280
|
|
288
|
281
|
{
|
289
|
|
- CursorPosition position;
|
|
282
|
+ SourcePosition position;
|
290
|
283
|
if (cursorEnd.offset == tokens.getLineLength(cursorEnd.line)) {
|
291
|
|
- position = new CursorPosition(cursorEnd.line + 1, 0);
|
|
284
|
+ position = new SourcePosition(tokens, cursorEnd.line + 1, 0);
|
292
|
285
|
} else {
|
293
|
|
- position = new CursorPosition(cursorEnd.line, cursorEnd.offset + 1);
|
|
286
|
+ position = new SourcePosition(tokens, cursorEnd.line, cursorEnd.offset + 1);
|
294
|
287
|
}
|
295
|
288
|
setCursor(shift ? cursorStart : position, position);
|
296
|
289
|
}
|
|
@@ -344,10 +337,17 @@ public class SourceEditor implements DComponent {
|
344
|
337
|
}
|
345
|
338
|
|
346
|
339
|
tokens.deleteCharacter(cursorEnd.line, cursorEnd.offset);
|
347
|
|
- repaintLine(cursorEnd.line);
|
348
|
340
|
}
|
349
|
341
|
|
350
|
342
|
private void backspace() {
|
|
343
|
+ if (!cursorEnd.equals(cursorStart)) {
|
|
344
|
+ SourcePosition min = SourcePosition.min(cursorStart, cursorEnd);
|
|
345
|
+ SourcePosition max = SourcePosition.max(cursorStart, cursorEnd);
|
|
346
|
+ tokens.delete(min.line, min.offset, max.line, max.offset);
|
|
347
|
+ setCursor(min, min);
|
|
348
|
+ return;
|
|
349
|
+ }
|
|
350
|
+
|
351
|
351
|
if (cursorEnd.offset == 0) {
|
352
|
352
|
if (cursorEnd.line == 0)
|
353
|
353
|
return;
|
|
@@ -355,56 +355,40 @@ public class SourceEditor implements DComponent {
|
355
|
355
|
int length = tokens.getLineLength(cursorEnd.line - 1);
|
356
|
356
|
tokens.deleteNewline(cursorEnd.line - 1);
|
357
|
357
|
|
358
|
|
- CursorPosition position = new CursorPosition(cursorEnd.line - 1, length);
|
|
358
|
+ SourcePosition position = new SourcePosition(tokens, cursorEnd.line - 1, length);
|
359
|
359
|
setCursor(position, position);
|
360
|
360
|
return;
|
361
|
361
|
}
|
362
|
362
|
|
363
|
|
- tokens.deleteCharacter(cursorEnd.line, cursorEnd.offset - 1);
|
364
|
|
- CursorPosition position = new CursorPosition(cursorEnd.line, cursorEnd.offset - 1);
|
365
|
|
- setCursor(position, position);
|
|
363
|
+ try {
|
|
364
|
+ tokens.deleteCharacter(cursorEnd.line, cursorEnd.offset - 1);
|
|
365
|
+ SourcePosition position = new SourcePosition(tokens, cursorEnd.line, cursorEnd.offset - 1);
|
|
366
|
+ setCursor(position, position);
|
|
367
|
+ } catch (Exception ex) {
|
|
368
|
+ ex.printStackTrace();
|
|
369
|
+ }
|
366
|
370
|
}
|
367
|
371
|
|
368
|
372
|
private void type(String value) {
|
369
|
373
|
tokens.insert(cursorEnd.line, cursorEnd.offset, value);
|
370
|
|
- CursorPosition position = new CursorPosition(cursorEnd.line, cursorEnd.offset + value.length());
|
|
374
|
+ SourcePosition position = new SourcePosition(tokens, cursorEnd.line, cursorEnd.offset + value.length());
|
371
|
375
|
setCursor(position, position);
|
372
|
376
|
}
|
373
|
377
|
|
374
|
378
|
private void newline() {
|
375
|
379
|
String indent = tokens.getLine(cursorEnd.line).getIndent();
|
376
|
380
|
tokens.insert(cursorEnd.line, cursorEnd.offset, "\n" + indent);
|
377
|
|
- CursorPosition position = new CursorPosition(cursorEnd.line + 1, indent.length());
|
|
381
|
+ SourcePosition position = new SourcePosition(tokens, cursorEnd.line + 1, indent.length());
|
378
|
382
|
setCursor(position, position);
|
379
|
383
|
}
|
380
|
384
|
|
381
|
|
- private TokenPosition getTokenAt(CursorPosition position) {
|
382
|
|
- TokenLine line = tokens.getLine(position.line);
|
383
|
|
- int offset = 0;
|
384
|
|
- for (ZSToken token : line.getTokens()) {
|
385
|
|
- if (offset + token.content.length() > position.offset)
|
386
|
|
- return new TokenPosition(token, position.offset - offset);
|
387
|
|
- offset += token.content.length();
|
388
|
|
- }
|
389
|
|
-
|
390
|
|
- return new TokenPosition(line.getLastToken(), position.offset - offset);
|
391
|
|
- }
|
392
|
|
-
|
393
|
|
- private class TokenPosition {
|
394
|
|
- public final ZSToken token;
|
395
|
|
- public final int offset;
|
396
|
|
-
|
397
|
|
- public TokenPosition(ZSToken token, int offset) {
|
398
|
|
- this.token = token;
|
399
|
|
- this.offset = offset;
|
400
|
|
- }
|
401
|
|
- }
|
402
|
|
-
|
403
|
|
- private void repaint(CursorPosition from, CursorPosition to) {
|
|
385
|
+ private void repaint(SourcePosition from, SourcePosition to) {
|
404
|
386
|
if (from.line == to.line) {
|
405
|
387
|
int y = lineToY(from.line);
|
406
|
|
- int fromX = offsetToX(from.line, Math.min(from.offset, to.offset));
|
407
|
|
- int toX = offsetToX(from.line, Math.max(from.offset, to.offset)) + 2;
|
|
388
|
+ int x1 = getX(from);
|
|
389
|
+ int x2 = getX(to);
|
|
390
|
+ int fromX = Math.min(x1, x2);
|
|
391
|
+ int toX = Math.max(x1, x2) + 2;
|
408
|
392
|
context.repaint(fromX, y, toX - fromX, selectionLineHeight);
|
409
|
393
|
} else {
|
410
|
394
|
int fromY = lineToY(Math.min(from.line, to.line));
|
|
@@ -420,10 +404,8 @@ public class SourceEditor implements DComponent {
|
420
|
404
|
context.repaint(bounds.x, lineToY(line), bounds.width, selectionLineHeight);
|
421
|
405
|
}
|
422
|
406
|
|
423
|
|
- private void scrollTo(CursorPosition position) {
|
424
|
|
- int y = lineToY(position.line);
|
425
|
|
- int x = offsetToX(position.line, position.offset);
|
426
|
|
- context.scrollInView(x, y, 2, selectionLineHeight);
|
|
407
|
+ public void scrollTo(SourcePosition position) {
|
|
408
|
+ context.scrollInView(getX(position), getY(position), 2, selectionLineHeight);
|
427
|
409
|
}
|
428
|
410
|
|
429
|
411
|
private void blink() {
|
|
@@ -433,7 +415,7 @@ public class SourceEditor implements DComponent {
|
433
|
415
|
}
|
434
|
416
|
}
|
435
|
417
|
|
436
|
|
- private CursorPosition getPositionAt(int x, int y) {
|
|
418
|
+ public SourcePosition getPositionAt(int x, int y) {
|
437
|
419
|
int line = yToLine(y);
|
438
|
420
|
int offset = xToOffset(line, x);
|
439
|
421
|
|
|
@@ -442,7 +424,7 @@ public class SourceEditor implements DComponent {
|
442
|
424
|
if (line >= tokens.getLineCount())
|
443
|
425
|
line = tokens.getLineCount() - 1;
|
444
|
426
|
|
445
|
|
- return new CursorPosition(line, offset);
|
|
427
|
+ return new SourcePosition(tokens, line, offset);
|
446
|
428
|
}
|
447
|
429
|
|
448
|
430
|
private int xToOffset(int lineIndex, int x) {
|
|
@@ -493,28 +475,23 @@ public class SourceEditor implements DComponent {
|
493
|
475
|
return startY + line * fullLineHeight;
|
494
|
476
|
}
|
495
|
477
|
|
496
|
|
- private int offsetToX(int line, int offset) {
|
497
|
|
- if (line >= tokens.getLineCount())
|
498
|
|
- return 0;
|
499
|
|
-
|
500
|
|
- int tokensOffset = 0;
|
|
478
|
+ public int getX(SourcePosition position) {
|
501
|
479
|
int x = bounds.x + lineBarWidth + 10;
|
502
|
|
- TokenLine lineData = tokens.getLine(line);
|
503
|
|
- for (ZSToken token : lineData.getTokens()) {
|
504
|
|
- String content = getDisplayContent(token);
|
505
|
|
- if (tokensOffset + token.content.length() >= offset) {
|
506
|
|
- if (token.type == ZSTokenType.T_WHITESPACE_TAB)
|
507
|
|
- return offset == tokensOffset ? x : x + fontMetrics.getWidth(tab);
|
508
|
|
-
|
509
|
|
- return x + fontMetrics.getWidth(token.content, 0, offset - tokensOffset);
|
510
|
|
- }
|
511
|
|
-
|
512
|
|
- x += fontMetrics.getWidth(content);
|
513
|
|
- tokensOffset += token.content.length();
|
514
|
|
- }
|
|
480
|
+ TokenLine lineData = tokens.getLine(position.line);
|
|
481
|
+
|
|
482
|
+ TokenModel.Position tokenPosition = position.asTokenPosition();
|
|
483
|
+ for (int i = 0; i < tokenPosition.token; i++)
|
|
484
|
+ x += fontMetrics.getWidth(getDisplayContent(lineData.getToken(i)));
|
|
485
|
+ if (tokenPosition.offset > 0)
|
|
486
|
+ x += fontMetrics.getWidth(getDisplayContent(lineData.getToken(tokenPosition.token)), 0, tokenPosition.offset);
|
|
487
|
+
|
515
|
488
|
return x;
|
516
|
489
|
}
|
517
|
490
|
|
|
491
|
+ public int getY(SourcePosition position) {
|
|
492
|
+ return lineToY(position.line);
|
|
493
|
+ }
|
|
494
|
+
|
518
|
495
|
private String getDisplayContent(ZSToken token) {
|
519
|
496
|
return token.type == ZSTokenType.T_WHITESPACE_TAB ? tab : token.content;
|
520
|
497
|
}
|
|
@@ -658,26 +635,4 @@ public class SourceEditor implements DComponent {
|
658
|
635
|
}
|
659
|
636
|
}
|
660
|
637
|
}
|
661
|
|
-
|
662
|
|
- public class CursorPosition {
|
663
|
|
- public final int line;
|
664
|
|
- public final int offset;
|
665
|
|
-
|
666
|
|
- public CursorPosition(int line, int offset) {
|
667
|
|
- this.line = line;
|
668
|
|
- this.offset = offset;
|
669
|
|
- }
|
670
|
|
-
|
671
|
|
- public int getX() {
|
672
|
|
- return offsetToX(line, offset);
|
673
|
|
- }
|
674
|
|
-
|
675
|
|
- public int getY() {
|
676
|
|
- return lineToY(line);
|
677
|
|
- }
|
678
|
|
-
|
679
|
|
- public boolean equals(CursorPosition other) {
|
680
|
|
- return line == other.line && offset == other.offset;
|
681
|
|
- }
|
682
|
|
- }
|
683
|
638
|
}
|