Browse Source

Added cut/copy/paste support.

Stan Hebben 6 years ago
parent
commit
7f9d5b3a7f

+ 33
- 0
Constructor/libraries/stdlib/src/Arrays.zs View File

19
 	
19
 	
20
 	public get first as T?;
20
 	public get first as T?;
21
 	public get last as T?;
21
 	public get last as T?;
22
+	public get reversed as T[];
22
 	
23
 	
23
 	public map<U>(projection as function(value as T) as U) as U[] {
24
 	public map<U>(projection as function(value as T) as U) as U[] {
24
 		val result as U[] = new U[](this.length);
25
 		val result as U[] = new U[](this.length);
79
 		return true;
80
 		return true;
80
 	}
81
 	}
81
 	
82
 	
83
+	public first(predicate as function(value as T) as bool) as T? {
84
+		for value in this
85
+			if predicate(value)
86
+				return value;
87
+		
88
+		return null;
89
+	}
90
+	
91
+	public first(predicate as function(i as int, value as T) as bool) as T? {
92
+		for i, value in this
93
+			if predicate(i, value)
94
+				return value;
95
+		
96
+		return null;
97
+	}
98
+	
99
+	public last(predicate as function(value as T) as bool) as T? {
100
+		for i, value in this.reversed
101
+			if predicate(value)
102
+				return value;
103
+		
104
+		return null;
105
+	}
106
+	
107
+	public last(predicate as function(value as T) as bool) as T? {
108
+		for i, value in this.reversed
109
+			if predicate(value)
110
+				return value
111
+		
112
+		return null;
113
+	}
114
+	
82
 	public count(predicate as function(value as T) as bool) as int {
115
 	public count(predicate as function(value as T) as bool) as int {
83
 		var result = 0;
116
 		var result = 0;
84
 		for value in this
117
 		for value in this

+ 16
- 0
DrawableGui/src/main/java/org/openzen/drawablegui/DClipboard.java View File

1
+/*
2
+ * To change this license header, choose License Headers in Project Properties.
3
+ * To change this template file, choose Tools | Templates
4
+ * and open the template in the editor.
5
+ */
6
+package org.openzen.drawablegui;
7
+
8
+/**
9
+ *
10
+ * @author Hoofdgebruiker
11
+ */
12
+public interface DClipboard {
13
+	void copyAsString(String value);
14
+	
15
+	String getAsString();
16
+}

+ 2
- 0
DrawableGui/src/main/java/org/openzen/drawablegui/DDrawingContext.java View File

22
 	
22
 	
23
 	DTimerHandle setTimer(int millis, Runnable target);
23
 	DTimerHandle setTimer(int millis, Runnable target);
24
 	
24
 	
25
+	DClipboard getClipboard();
26
+	
25
 	DFontMetrics getFontMetrics(DFont font);
27
 	DFontMetrics getFontMetrics(DFont font);
26
 	
28
 	
27
 	enum Cursor {
29
 	enum Cursor {

+ 6
- 0
DrawableGui/src/main/java/org/openzen/drawablegui/scroll/DScrollPane.java View File

7
 
7
 
8
 import org.openzen.drawablegui.DRectangle;
8
 import org.openzen.drawablegui.DRectangle;
9
 import org.openzen.drawablegui.DCanvas;
9
 import org.openzen.drawablegui.DCanvas;
10
+import org.openzen.drawablegui.DClipboard;
10
 import org.openzen.drawablegui.DComponent;
11
 import org.openzen.drawablegui.DComponent;
11
 import org.openzen.drawablegui.DDimensionPreferences;
12
 import org.openzen.drawablegui.DDimensionPreferences;
12
 import org.openzen.drawablegui.DDrawingContext;
13
 import org.openzen.drawablegui.DDrawingContext;
254
 		public DTimerHandle setTimer(int millis, Runnable target) {
255
 		public DTimerHandle setTimer(int millis, Runnable target) {
255
 			return context.setTimer(millis, target);
256
 			return context.setTimer(millis, target);
256
 		}
257
 		}
258
+
259
+		@Override
260
+		public DClipboard getClipboard() {
261
+			return context.getClipboard();
262
+		}
257
 	}
263
 	}
258
 	
264
 	
259
 	private class ScrollListener implements LiveInt.Listener {
265
 	private class ScrollListener implements LiveInt.Listener {

+ 46
- 0
DrawableGui/src/main/java/org/openzen/drawablegui/swing/JavaClipboard.java View File

1
+/*
2
+ * To change this license header, choose License Headers in Project Properties.
3
+ * To change this template file, choose Tools | Templates
4
+ * and open the template in the editor.
5
+ */
6
+package org.openzen.drawablegui.swing;
7
+
8
+import java.awt.Toolkit;
9
+import java.awt.datatransfer.Clipboard;
10
+import java.awt.datatransfer.DataFlavor;
11
+import java.awt.datatransfer.StringSelection;
12
+import java.awt.datatransfer.Transferable;
13
+import java.awt.datatransfer.UnsupportedFlavorException;
14
+import java.io.IOException;
15
+import org.openzen.drawablegui.DClipboard;
16
+
17
+/**
18
+ *
19
+ * @author Hoofdgebruiker
20
+ */
21
+public class JavaClipboard implements DClipboard {
22
+	private final Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
23
+
24
+	@Override
25
+	public void copyAsString(String value) {
26
+		StringSelection stringSelection = new StringSelection(value);
27
+		clipboard.setContents(stringSelection, null);
28
+	}
29
+
30
+	@Override
31
+	public String getAsString() {
32
+		Transferable contents = clipboard.getContents(null);
33
+		if (contents == null)
34
+			return null;
35
+		
36
+		if (!contents.isDataFlavorSupported(DataFlavor.stringFlavor))
37
+			return null;
38
+		
39
+		try {
40
+			return (String)contents.getTransferData(DataFlavor.stringFlavor);
41
+		} catch (UnsupportedFlavorException | IOException ex) {
42
+			ex.printStackTrace();
43
+			return null;
44
+		}
45
+	}
46
+}

+ 7
- 0
DrawableGui/src/main/java/org/openzen/drawablegui/swing/SwingGraphicsContext.java View File

10
 import java.awt.geom.GeneralPath;
10
 import java.awt.geom.GeneralPath;
11
 import java.util.WeakHashMap;
11
 import java.util.WeakHashMap;
12
 import javax.swing.Timer;
12
 import javax.swing.Timer;
13
+import org.openzen.drawablegui.DClipboard;
13
 import org.openzen.drawablegui.DComponent;
14
 import org.openzen.drawablegui.DComponent;
14
 import org.openzen.drawablegui.DPath;
15
 import org.openzen.drawablegui.DPath;
15
 import org.openzen.drawablegui.DDrawingContext;
16
 import org.openzen.drawablegui.DDrawingContext;
26
 	public final float scale;
27
 	public final float scale;
27
 	private final WeakHashMap<DPath, GeneralPath> preparedPaths = new WeakHashMap<>();
28
 	private final WeakHashMap<DPath, GeneralPath> preparedPaths = new WeakHashMap<>();
28
 	private final SwingRoot root;
29
 	private final SwingRoot root;
30
+	private final JavaClipboard clipboard = new JavaClipboard();
29
 	private Graphics graphics;
31
 	private Graphics graphics;
30
 	
32
 	
31
 	public SwingGraphicsContext(float scale, SwingRoot root) {
33
 	public SwingGraphicsContext(float scale, SwingRoot root) {
110
 		timer.start();
112
 		timer.start();
111
 		return () -> timer.stop();
113
 		return () -> timer.stop();
112
 	}
114
 	}
115
+
116
+	@Override
117
+	public DClipboard getClipboard() {
118
+		return clipboard;
119
+	}
113
 	
120
 	
114
 	private class PathTracer implements DPathTracer {
121
 	private class PathTracer implements DPathTracer {
115
 		private final GeneralPath path;
122
 		private final GeneralPath path;

+ 61
- 8
IDE/src/main/java/org/openzen/zenscript/ide/ui/view/editor/SourceEditor.java View File

314
 	
314
 	
315
 	private void handleShortcut(DKeyEvent e) {
315
 	private void handleShortcut(DKeyEvent e) {
316
 		if (e.has(DKeyEvent.CTRL)) {
316
 		if (e.has(DKeyEvent.CTRL)) {
317
-			if (e.keyCode == KeyCode.S) {
318
-				save();
317
+			switch (e.keyCode) {
318
+				case S:
319
+					save();
320
+					break;
321
+				case C:
322
+					copy();
323
+					break;
324
+				case X:
325
+					cut();
326
+					break;
327
+				case V:
328
+					paste();
329
+					break;
319
 			}
330
 			}
320
 		}
331
 		}
321
 	}
332
 	}
322
 	
333
 	
334
+	private void copy() {
335
+		String extract = tokens.extract(
336
+				SourcePosition.min(cursorStart, cursorEnd),
337
+				SourcePosition.max(cursorStart, cursorEnd));
338
+		context.getClipboard().copyAsString(extract);
339
+	}
340
+	
341
+	private void cut() {
342
+		copy();
343
+		tokens.delete(cursorStart, cursorEnd);
344
+		
345
+		SourcePosition cursor = SourcePosition.min(cursorStart, cursorEnd);
346
+		setCursor(cursor, cursor);
347
+	}
348
+	
349
+	private void paste() {
350
+		String text = context.getClipboard().getAsString();
351
+		if (text == null)
352
+			return;
353
+		
354
+		deleteSelection();
355
+		tokens.insert(cursorEnd, text);
356
+		
357
+		SourcePosition cursor = cursorEnd.advance(text.length());
358
+		setCursor(cursor, cursor);
359
+	}
360
+	
323
 	private void save() {
361
 	private void save() {
324
 		String content = tokens.toString();
362
 		String content = tokens.toString();
325
 		sourceFile.update(content);
363
 		sourceFile.update(content);
339
 		tokens.deleteCharacter(cursorEnd.line, cursorEnd.offset);
377
 		tokens.deleteCharacter(cursorEnd.line, cursorEnd.offset);
340
 	}
378
 	}
341
 	
379
 	
342
-	private void backspace() {
343
-		if (!cursorEnd.equals(cursorStart)) {
380
+	private boolean hasSelection() {
381
+		return !cursorEnd.equals(cursorStart);
382
+	}
383
+	
384
+	private boolean deleteSelection() {
385
+		if (hasSelection()) {
344
 			SourcePosition min = SourcePosition.min(cursorStart, cursorEnd);
386
 			SourcePosition min = SourcePosition.min(cursorStart, cursorEnd);
345
 			SourcePosition max = SourcePosition.max(cursorStart, cursorEnd);
387
 			SourcePosition max = SourcePosition.max(cursorStart, cursorEnd);
346
-			tokens.delete(min.line, min.offset, max.line, max.offset);
388
+			tokens.delete(min, max);
347
 			setCursor(min, min);
389
 			setCursor(min, min);
348
-			return;
390
+			return true;
349
 		}
391
 		}
350
 		
392
 		
393
+		return false;
394
+	}
395
+	
396
+	private void backspace() {
397
+		if (deleteSelection())
398
+			return;
399
+		
351
 		if (cursorEnd.offset == 0) {
400
 		if (cursorEnd.offset == 0) {
352
 			if (cursorEnd.line == 0)
401
 			if (cursorEnd.line == 0)
353
 				return;
402
 				return;
370
 	}
419
 	}
371
 	
420
 	
372
 	private void type(String value) {
421
 	private void type(String value) {
373
-		tokens.insert(cursorEnd.line, cursorEnd.offset, value);
422
+		deleteSelection();
423
+		
424
+		tokens.insert(cursorEnd, value);
374
 		SourcePosition position = new SourcePosition(tokens, cursorEnd.line, cursorEnd.offset + value.length());
425
 		SourcePosition position = new SourcePosition(tokens, cursorEnd.line, cursorEnd.offset + value.length());
375
 		setCursor(position, position);
426
 		setCursor(position, position);
376
 	}
427
 	}
377
 	
428
 	
378
 	private void newline() {
429
 	private void newline() {
430
+		deleteSelection();
431
+		
379
 		String indent = tokens.getLine(cursorEnd.line).getIndent();
432
 		String indent = tokens.getLine(cursorEnd.line).getIndent();
380
-		tokens.insert(cursorEnd.line, cursorEnd.offset, "\n" + indent);
433
+		tokens.insert(cursorEnd, "\n" + indent);
381
 		SourcePosition position = new SourcePosition(tokens, cursorEnd.line + 1, indent.length());
434
 		SourcePosition position = new SourcePosition(tokens, cursorEnd.line + 1, indent.length());
382
 		setCursor(position, position);
435
 		setCursor(position, position);
383
 	}
436
 	}

+ 20
- 0
IDE/src/main/java/org/openzen/zenscript/ide/ui/view/editor/SourcePosition.java View File

23
 		this.offset = offset;
23
 		this.offset = offset;
24
 	}
24
 	}
25
 	
25
 	
26
+	public SourcePosition advance(int characters) {
27
+		if (characters <= 0) {
28
+			throw new IllegalArgumentException("Characters must be >= 0");
29
+		} else if (characters == 0) {
30
+			return this;
31
+		} else {
32
+			int line = this.line;
33
+			int offset = this.offset;
34
+			while (offset + characters > tokens.getLineLength(line) && line < tokens.getLineCount() - 1) {
35
+				characters -= tokens.getLineLength(line) - offset + 1; // make sure to include the newline
36
+				offset = 0;
37
+				line++;
38
+			}
39
+			if (line >= tokens.getLineCount() -1)
40
+				return new SourcePosition(tokens, tokens.getLineCount() - 1, tokens.getLineLength(tokens.getLineCount() - 1));
41
+			
42
+			return new SourcePosition(tokens, line, offset + characters);
43
+		}
44
+	}
45
+	
26
 	public static SourcePosition min(SourcePosition a, SourcePosition b) {
46
 	public static SourcePosition min(SourcePosition a, SourcePosition b) {
27
 		if (a.line < b.line)
47
 		if (a.line < b.line)
28
 			return a;
48
 			return a;

+ 69
- 31
IDE/src/main/java/org/openzen/zenscript/ide/ui/view/editor/TokenModel.java View File

89
 		return new Position(line, tokenLine.getTokenCount(), 0);
89
 		return new Position(line, tokenLine.getTokenCount(), 0);
90
 	}
90
 	}
91
 	
91
 	
92
+	public String extract(SourcePosition from, SourcePosition to) {
93
+		Position fromT = from.asTokenPosition();
94
+		Position toT = to.asTokenPosition();
95
+		if (from.line == to.line) {
96
+			StringBuilder result = new StringBuilder();
97
+			ZSToken fromToken = getTokenAt(fromT);
98
+			if (fromToken != null)
99
+				result.append(fromToken.getContent().substring(fromT.offset));
100
+			
101
+			TokenLine line = getLine(from.line);
102
+			for (int i = fromT.token + 1; i < toT.token; i++)
103
+				result.append(line.getToken(i).content);
104
+			
105
+			ZSToken toToken = getTokenAt(toT);
106
+			if (toToken != null)
107
+				result.append(toToken.content.substring(0, toT.offset));
108
+			
109
+			return result.toString();
110
+		} else {
111
+			StringBuilder result = new StringBuilder();
112
+			ZSToken fromToken = getTokenAt(fromT);
113
+			if (fromToken != null)
114
+				result.append(fromToken.getContent().substring(fromT.offset));
115
+			
116
+			TokenLine fromLine = getLine(from.line);
117
+			for (int i = fromT.token + 1; i < fromLine.getTokenCount(); i++)
118
+				result.append(fromLine.getToken(i).content);
119
+			
120
+			for (int i = fromT.line + 1; i < toT.line; i++) {
121
+				result.append("\n");
122
+				for (ZSToken t : fromLine.getTokens()) {
123
+					result.append(t.content);
124
+				}
125
+			}
126
+			
127
+			result.append("\n");
128
+			
129
+			TokenLine toLine = getLine(to.line);
130
+			for (int i = 0; i < toT.token; i++)
131
+				result.append(toLine.getToken(i).content);
132
+			
133
+			ZSToken toToken = getTokenAt(toT);
134
+			if (toToken != null)
135
+				result.append(toToken.content.substring(0, toT.offset));
136
+			
137
+			return result.toString();
138
+		}
139
+	}
140
+	
92
 	public void set(Iterator<ZSToken> tokens) {
141
 	public void set(Iterator<ZSToken> tokens) {
93
 		lines.clear();
142
 		lines.clear();
94
 		lines.add(new TokenLine());
143
 		lines.add(new TokenLine());
127
 		}
176
 		}
128
 	}
177
 	}
129
 	
178
 	
130
-	public void delete(int fromLineIndex, int fromOffset, int toLineIndex, int toOffset) {
131
-		Position from = getPosition(fromLineIndex, fromOffset);
132
-		Position to = getPosition(toLineIndex, toOffset);
179
+	public void delete(SourcePosition from, SourcePosition to) {
180
+		Position fromT = from.asTokenPosition();
181
+		Position toT = to.asTokenPosition();
133
 		
182
 		
134
-		ZSToken fromToken = getTokenAt(from);
135
-		ZSToken toToken = getTokenAt(to);
183
+		ZSToken fromToken = getTokenAt(fromT);
184
+		ZSToken toToken = getTokenAt(toT);
136
 		
185
 		
137
 		String remainder = "";
186
 		String remainder = "";
138
 		if (fromToken != null)
187
 		if (fromToken != null)
139
-			remainder = fromToken.content.substring(0, from.offset);
140
-		if (toToken != null && to.offset > 0)
141
-			remainder += toToken.content.substring(to.offset);
188
+			remainder = fromToken.content.substring(0, fromT.offset);
189
+		if (toToken != null && toT.offset > 0)
190
+			remainder += toToken.content.substring(toT.offset);
142
 		
191
 		
143
-		removeTokens(from.line, from.token, to.line, to.offset > 0 ? to.token + 1 : to.token);
144
-		if (!remainder.isEmpty()) {
145
-			getLine(from.line).insert(from.token, new ZSToken(ZSTokenType.INVALID, remainder));
146
-			relex(from.line, Math.max(0, from.token - 1), from.line, from.token + 1);
147
-		}
192
+		removeTokens(fromT.line, fromT.token, toT.line, toT.offset > 0 ? toT.token + 1 : toT.token);
193
+		if (!remainder.isEmpty())
194
+			getLine(fromT.line).insert(fromT.token, new ZSToken(ZSTokenType.INVALID, remainder));
195
+		
196
+		relex(fromT.line, Math.max(0, fromT.token - 1), fromT.line, fromT.token + 1);
148
 	}
197
 	}
149
 	
198
 	
150
-	public void insert(int lineIndex, int offset, String value) {
151
-		TokenLine line = lines.get(lineIndex);
152
-		int tokenOffset = 0;
153
-		for (int i = 0; i < line.getTokenCount(); i++) {
154
-			ZSToken token = line.getToken(i);
155
-			if (tokenOffset + token.content.length() > offset) {
156
-				token = token.insert(offset - tokenOffset, value);
157
-				line.replace(i, token);
158
-				relex(lineIndex, i, lineIndex, i + 1);
159
-				return;
160
-			}
161
-			tokenOffset += token.content.length();
162
-		}
163
-
164
-		ZSToken token = line.getLastToken();
199
+	public void insert(SourcePosition position, String value) {
200
+		TokenLine line = lines.get(position.line);
201
+		Position tokenPosition = position.asTokenPosition();
202
+		ZSToken token = getTokenAt(tokenPosition);
165
 		if (token == null) {
203
 		if (token == null) {
166
 			line.add(new ZSToken(ZSTokenType.INVALID, value));
204
 			line.add(new ZSToken(ZSTokenType.INVALID, value));
167
 		} else {
205
 		} else {
168
-			token = new ZSToken(token.type, token.content + value);
169
-			line.replace(line.getTokenCount() - 1, token);
206
+			token = token.insert(tokenPosition.offset, value);
207
+			line.replace(tokenPosition.token, token);
170
 		}
208
 		}
171
-		relex(lineIndex, line.getTokenCount() - 1, lineIndex, line.getTokenCount());
209
+		relex(tokenPosition.line, Math.max(0, tokenPosition.token - 1), tokenPosition.line, tokenPosition.token + 1);
172
 	}
210
 	}
173
 	
211
 	
174
 	private void relex(int fromLine, int fromToken, int toLine, int toToken) {
212
 	private void relex(int fromLine, int fromToken, int toLine, int toToken) {

Loading…
Cancel
Save