Skip to content

Commit 1a358a3

Browse files
fixup! Handle CR without NL printed in EditorConsole
1 parent 77d9e0a commit 1a358a3

File tree

2 files changed

+164
-5
lines changed

2 files changed

+164
-5
lines changed

Diff for: app/src/processing/app/EditorConsole.java

+9-5
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,11 @@ public class EditorConsole extends JScrollPane {
3939

4040
private static ConsoleOutputStream out;
4141
private static ConsoleOutputStream err;
42-
private static int startOfLine = 0;
43-
private static int insertPosition = 0;
42+
private int startOfLine = 0;
43+
private int insertPosition = 0;
44+
45+
// Regex for linesplitting, see insertString for comments.
46+
private static final Pattern newLinePattern = Pattern.compile("([^\r\n]*)([\r\n]*\n)?(\r+)?");
4447

4548
public static synchronized void setCurrentEditorConsole(EditorConsole console) {
4649
if (out == null) {
@@ -186,17 +189,18 @@ public void insertString(String str, SimpleAttributeSet attributes) throws BadLo
186189
// Separate the string into content, newlines and lone carriage
187190
// returns.
188191
//
189-
// Doing so allows lone CRs to return the insertPosition to the
192+
// Doing so allows lone CRs to move the insertPosition back to the
190193
// start of the line to allow overwriting the most recent line (e.g.
191194
// for a progress bar). Any CR or NL that are immediately followed
192195
// by another NL are bunched together for efficiency, since these
193196
// can just be inserted into the document directly and still be
194197
// correct.
195198
//
196-
// This regex is written so it will necessarily match any string
199+
// The regex is written so it will necessarily match any string
197200
// completely if applied repeatedly. This is important because any
198201
// part not matched would be silently dropped.
199-
Matcher m = Pattern.compile("([^\r\n]*)([\r\n]*\n)?(\r+)?").matcher(str);
202+
Matcher m = newLinePattern.matcher(str);
203+
200204
while (m.find()) {
201205
String content = m.group(1);
202206
String newlines = m.group(2);

Diff for: app/test/processing/app/EditorConsoleTest.java

+155
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
/*
2+
* This file is part of Arduino.
3+
*
4+
* Copyright 2020 Arduino LLC (http://www.arduino.cc/)
5+
*
6+
* Arduino is free software; you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation; either version 2 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with this program; if not, write to the Free Software
18+
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19+
*
20+
* As a special exception, you may use this file as part of a free software
21+
* library without restriction. Specifically, if other files instantiate
22+
* templates or use macros or inline functions from this file, or you compile
23+
* this file and link it with other files to produce an executable, this
24+
* file does not by itself cause the resulting executable to be covered by
25+
* the GNU General Public License. This exception does not however
26+
* invalidate any other reasons why the executable file might be covered by
27+
* the GNU General Public License.
28+
*/
29+
30+
package processing.app;
31+
32+
import static org.junit.Assert.assertEquals;
33+
34+
import org.junit.Before;
35+
import org.junit.Test;
36+
37+
public class EditorConsoleTest extends AbstractWithPreferencesTest {
38+
private EditorConsole console;
39+
40+
@Before
41+
public void createConsole() {
42+
console = new EditorConsole(null);
43+
}
44+
45+
public String escapeString(String input) {
46+
// This escapes backslashes, newlines and carriage returns, to get
47+
// more readable assertion failures.
48+
return input.replace("\\", "\\\\").replace("\n", "\\n").replace("\r", "\\r");
49+
}
50+
51+
public void assertOutput(String output) {
52+
assertEquals(escapeString(output), escapeString(console.getText()));
53+
}
54+
55+
@Test
56+
public void testHelloWorld() throws Exception {
57+
console.insertString("Hello, world!", null);
58+
59+
assertOutput("Hello, world!");
60+
}
61+
62+
@Test
63+
public void testCrNlHandling() throws Exception {
64+
// Do some basic tests with \r\n
65+
console.insertString("abc\r\ndef", null);
66+
assertOutput("abc\r\ndef");
67+
68+
console.insertString("xyz", null);
69+
assertOutput("abc\r\ndefxyz");
70+
71+
console.insertString("000\r\n123", null);
72+
assertOutput("abc\r\ndefxyz000\r\n123");
73+
74+
console.insertString("\r\n", null);
75+
assertOutput("abc\r\ndefxyz000\r\n123\r\n");
76+
}
77+
78+
@Test
79+
public void testNlHandling() throws Exception {
80+
// Basic tests, but with just \n
81+
console.insertString("abc\ndef", null);
82+
assertOutput("abc\ndef");
83+
84+
console.insertString("xyz", null);
85+
assertOutput("abc\ndefxyz");
86+
87+
console.insertString("000\n123", null);
88+
assertOutput("abc\ndefxyz000\n123");
89+
90+
console.insertString("\n", null);
91+
assertOutput("abc\ndefxyz000\n123\n");
92+
}
93+
94+
@Test
95+
public void testCrHandling() throws Exception {
96+
// Then test that single \r clears the current line
97+
console.clear();
98+
console.insertString("abc\rdef", null);
99+
assertOutput("def");
100+
101+
// A single \r at the end is not added to the document
102+
console.insertString("\r", null);
103+
assertOutput("def");
104+
105+
// Nor are multiple \r at the end
106+
console.insertString("\r\r\r", null);
107+
assertOutput("def");
108+
109+
// But it does clear the line on the next write
110+
console.insertString("123", null);
111+
assertOutput("123");
112+
113+
// Same when combined with some data
114+
console.insertString("\r456\r\r", null);
115+
assertOutput("456");
116+
117+
console.insertString("000", null);
118+
assertOutput("000");
119+
120+
// Then add a newline so preceding data is kept
121+
console.insertString("\r\nxxx\r", null);
122+
assertOutput("000\r\nxxx");
123+
124+
// But data after the newline is removed
125+
console.insertString("yyy", null);
126+
assertOutput("000\r\nyyy");
127+
128+
// When a \r\n is split across inserts, it becomes a lone \n
129+
console.insertString("\r", null);
130+
assertOutput("000\r\nyyy");
131+
console.insertString("\n", null);
132+
assertOutput("000\r\nyyy\n");
133+
}
134+
135+
@Test
136+
public void testCrPartialOverwrite() throws Exception {
137+
console.insertString("abcdef\r", null);
138+
assertOutput("abcdef");
139+
140+
console.insertString("123", null);
141+
assertOutput("123def");
142+
143+
console.insertString("4", null);
144+
assertOutput("1234ef");
145+
146+
console.insertString("\r\n56", null);
147+
assertOutput("1234ef\r\n56");
148+
}
149+
150+
@Test
151+
public void testTogether() throws Exception {
152+
console.insertString("abc\n123456\rdef\rx\r\nyyy\nzzz\r999", null);
153+
assertOutput("abc\nxef456\r\nyyy\n999");
154+
}
155+
}

0 commit comments

Comments
 (0)