Skip to content

Commit 672a01f

Browse files
committed
lots of work to clean up console lockup issues (fixes #4825)
1 parent dd791b2 commit 672a01f

File tree

5 files changed

+120
-64
lines changed

5 files changed

+120
-64
lines changed

app/src/processing/app/Console.java

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030

3131

3232
/**
33-
* Message console that sits below the editing area.
33+
* Non-GUI handling of System.out and System.err redirection.
3434
* <p />
3535
* Be careful when debugging this class, because if it's throwing exceptions,
3636
* don't take over System.err, and debug while watching just System.out
@@ -43,9 +43,6 @@
4343
* get along with one another. Use 'ant run' to work on encoding-related issues.
4444
*/
4545
public class Console {
46-
// PrintStream sketchOut;
47-
// PrintStream sketchErr;
48-
4946
// Single static instance shared because there's only one real System.out.
5047
// Within the input handlers, the currentConsole variable will be used to
5148
// echo things to the correct location.
@@ -72,6 +69,13 @@ public class Console {
7269

7370

7471
static public void startup() {
72+
if (systemOut != null) {
73+
// TODO fix this dreadful style choice in how the Console is initialized
74+
// (This is not good code.. startup() should gracefully deal with this.
75+
// It's just a low priority relative to the likelihood of trouble.)
76+
new Exception("startup() called more than once").printStackTrace(systemErr);
77+
return;
78+
}
7579
systemOut = System.out;
7680
systemErr = System.err;
7781

@@ -115,8 +119,6 @@ public boolean accept(File file) {
115119
File errFile = new File(consoleDir, stamp + ".err");
116120
stderrFile = new FileOutputStream(errFile);
117121

118-
// consoleOut = new PrintStream(new EditorConsoleStream(false, null));
119-
// consoleErr = new PrintStream(new EditorConsoleStream(true, null));
120122
consoleOut = new PrintStream(new ConsoleStream(false));
121123
consoleErr = new PrintStream(new ConsoleStream(true));
122124

@@ -144,20 +146,14 @@ static public void setEditor(OutputStream out, OutputStream err) {
144146
}
145147

146148

147-
// public Console() {
148-
// sketchOut = new PrintStream(new EditorConsoleStream(false, this));
149-
// sketchErr = new PrintStream(new EditorConsoleStream(true, this));
150-
// }
151-
152-
153-
// public PrintStream getOut() {
154-
// return sketchOut;
155-
// }
149+
static public void systemOut(String what) {
150+
systemOut.println(what);
151+
}
156152

157153

158-
// public PrintStream getErr() {
159-
// return sketchErr;
160-
// }
154+
static public void systemErr(String what) {
155+
systemErr.println(what);
156+
}
161157

162158

163159
/**

app/src/processing/app/exec/StreamRedirectThread.java

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@
77
*/
88
/*
99
* Copyright (c) 1997-2001 by Sun Microsystems, Inc. All Rights Reserved.
10-
*
10+
*
1111
* Sun grants you ("Licensee") a non-exclusive, royalty free, license to use,
1212
* modify and redistribute this software in source and binary code form,
1313
* provided that i) this copyright notice and license appear on all copies of
1414
* the software; and ii) Licensee does not utilize the software in a manner
1515
* which is disparaging to Sun.
16-
*
16+
*
1717
* This software is provided "AS IS," without a warranty of any kind. ALL
1818
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
1919
* IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
@@ -25,7 +25,7 @@
2525
* CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
2626
* OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
2727
* POSSIBILITY OF SUCH DAMAGES.
28-
*
28+
*
2929
* This software is not designed or intended for use in on-line control of
3030
* aircraft, air traffic, aircraft navigation or aircraft communications; or in
3131
* the design, construction, operation or maintenance of any nuclear
@@ -50,7 +50,7 @@ public class StreamRedirectThread extends Thread {
5050

5151
private static final int BUFFER_SIZE = 2048;
5252

53-
53+
5454
/**
5555
* Set up for copy.
5656
* @param name Name of the thread
@@ -63,15 +63,15 @@ public StreamRedirectThread(String name, InputStream in, OutputStream out) {
6363
this.out = new OutputStreamWriter(out);
6464
setPriority(Thread.MAX_PRIORITY-1);
6565
}
66-
67-
66+
67+
6868
public StreamRedirectThread(String name, Reader in, Writer out) {
6969
super(name);
7070
this.in = in;
7171
this.out = out;
7272
setPriority(Thread.MAX_PRIORITY-1);
7373
}
74-
74+
7575

7676
/**
7777
* Copy.
@@ -80,16 +80,15 @@ public void run() {
8080
try {
8181
char[] cbuf = new char[BUFFER_SIZE];
8282
int count;
83-
//System.out.println("opening streamredirectthread");
8483
while ((count = in.read(cbuf, 0, BUFFER_SIZE)) >= 0) {
8584
out.write(cbuf, 0, count);
8685
// had to add the flush() here.. maybe shouldn't be using writer? [fry]
8786
out.flush();
8887
}
89-
//System.out.println("exiting streamredirectthread");
9088
out.flush();
91-
} catch(IOException exc) {
92-
System.err.println("Child I/O Transfer - " + exc);
89+
90+
} catch (IOException exc) {
91+
processing.app.Console.systemErr("Child I/O Transfer - " + exc);
9392
}
9493
}
9594
}

app/src/processing/app/ui/EditorConsole.java

Lines changed: 88 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,7 @@
3232
import java.awt.event.ActionListener;
3333
import java.io.OutputStream;
3434
import java.io.PrintStream;
35-
import java.util.ArrayList;
36-
import java.util.List;
35+
import java.util.concurrent.LinkedBlockingQueue;
3736

3837
import javax.swing.*;
3938
import javax.swing.border.MatteBorder;
@@ -46,16 +45,6 @@
4645

4746
/**
4847
* Message console that sits below the editing area.
49-
* <p />
50-
* Be careful when debugging this class, because if it's throwing exceptions,
51-
* don't take over System.err, and debug while watching just System.out
52-
* or just call println() or whatever directly to systemOut or systemErr.
53-
* <p />
54-
* Also note that encodings will not work properly when run from Eclipse. This
55-
* means that if you use non-ASCII characters in a println() or some such,
56-
* the characters won't print properly in the Processing and/or Eclipse console.
57-
* It seems that Eclipse's console-grabbing and that of Processing don't
58-
* get along with one another. Use 'ant run' to work on encoding-related issues.
5948
*/
6049
public class EditorConsole extends JScrollPane {
6150
Editor editor;
@@ -69,6 +58,7 @@ public class EditorConsole extends JScrollPane {
6958
MutableAttributeSet errStyle;
7059

7160
int maxLineCount;
61+
int maxCharCount;
7262

7363
PrintStream sketchOut;
7464
PrintStream sketchErr;
@@ -79,9 +69,10 @@ public class EditorConsole extends JScrollPane {
7969
public EditorConsole(Editor editor) {
8070
this.editor = editor;
8171

82-
maxLineCount = Preferences.getInteger("console.length");
72+
maxLineCount = Preferences.getInteger("console.lines");
73+
maxCharCount = Preferences.getInteger("console.chars");
8374

84-
consoleDoc = new BufferedStyledDocument(10000, maxLineCount);
75+
consoleDoc = new BufferedStyledDocument(10000, maxLineCount, maxCharCount);
8576
consoleTextPane = new JTextPane(consoleDoc);
8677
consoleTextPane.setEditable(false);
8778

@@ -98,7 +89,7 @@ public EditorConsole(Editor editor) {
9889

9990
protected void flush() {
10091
// only if new text has been added
101-
if (consoleDoc.hasAppendage) {
92+
if (consoleDoc.hasAppendage()) {
10293
// insert the text that's been added in the meantime
10394
consoleDoc.insertAll();
10495
// always move to the end of the text as it's added
@@ -150,8 +141,7 @@ public PrintStream getErr() {
150141
*/
151142
protected void updateAppearance() {
152143
String fontFamily = Preferences.get("editor.font.family");
153-
int fontSize =
154-
Toolkit.zoom(Preferences.getInteger("console.font.size"));
144+
int fontSize = Toolkit.zoom(Preferences.getInteger("console.font.size"));
155145
StyleConstants.setFontFamily(stdStyle, fontFamily);
156146
StyleConstants.setFontSize(stdStyle, fontSize);
157147
StyleConstants.setFontFamily(errStyle, fontFamily);
@@ -232,7 +222,7 @@ void setCurrent() {
232222
}
233223

234224

235-
synchronized public void message(String what, boolean err) {
225+
public void message(String what, boolean err) {
236226
if (err && (what.contains("invalid context 0x0") || (what.contains("invalid drawable")))) {
237227
// Respectfully declining... This is a quirk of more recent releases of
238228
// Java on Mac OS X, but is widely reported as the source of any other
@@ -302,22 +292,32 @@ public void write(int b) {
302292
* swing event thread, so they need to be synchronized
303293
*/
304294
class BufferedStyledDocument extends DefaultStyledDocument {
305-
List<ElementSpec> elements = new ArrayList<>();
306-
int maxLineLength, maxLineCount;
295+
//List<ElementSpec> elements = new ArrayList<>();
296+
LinkedBlockingQueue<ElementSpec> elements;
297+
// AtomicInteger queuedLineCount = new AtomicInteger();
298+
int maxLineLength, maxLineCount, maxCharCount;
307299
int currentLineLength = 0;
308300
boolean needLineBreak = false;
309-
boolean hasAppendage = false;
301+
// boolean hasAppendage = false;
302+
final Object insertLock = new Object();
310303

311-
public BufferedStyledDocument(int maxLineLength, int maxLineCount) {
304+
public BufferedStyledDocument(int maxLineLength, int maxLineCount,
305+
int maxCharCount) {
312306
this.maxLineLength = maxLineLength;
313307
this.maxLineCount = maxLineCount;
308+
this.maxCharCount = maxCharCount;
309+
elements = new LinkedBlockingQueue<>();
310+
}
311+
312+
// monitor this so that it's only updated when needed (otherwise console
313+
// updates every 250 ms when an app isn't even running.. see bug 180)
314+
public boolean hasAppendage() {
315+
return elements.size() > 0;
314316
}
315317

316318
/** buffer a string for insertion at the end of the DefaultStyledDocument */
317-
public synchronized void appendString(String str, AttributeSet a) {
318-
// do this so that it's only updated when needed (otherwise console
319-
// updates every 250 ms when an app isn't even running.. see bug 180)
320-
hasAppendage = true;
319+
public void appendString(String str, AttributeSet a) {
320+
// hasAppendage = true;
321321

322322
// process each line of the string
323323
while (str.length() > 0) {
@@ -326,6 +326,7 @@ public synchronized void appendString(String str, AttributeSet a) {
326326
if (needLineBreak || currentLineLength > maxLineLength) {
327327
elements.add(new ElementSpec(a, ElementSpec.EndTagType));
328328
elements.add(new ElementSpec(a, ElementSpec.StartTagType));
329+
// queuedLineCount.incrementAndGet();
329330
currentLineLength = 0;
330331
}
331332

@@ -341,15 +342,42 @@ public synchronized void appendString(String str, AttributeSet a) {
341342
needLineBreak = true;
342343
str = str.substring(str.indexOf('\n') + 1); // eat the line
343344
}
345+
/*
346+
while (queuedLineCount.get() > maxLineCount) {
347+
Console.systemOut("too many: " + queuedLineCount);
348+
ElementSpec elem = elements.remove();
349+
if (elem.getType() == ElementSpec.EndTagType) {
350+
queuedLineCount.decrementAndGet();
351+
}
352+
}
353+
*/
354+
}
355+
if (elements.size() > 1000) {
356+
insertAll();
344357
}
345358
}
346359

347360
/** insert the buffered strings */
348-
public synchronized void insertAll() {
349-
ElementSpec[] elementArray = new ElementSpec[elements.size()];
350-
elements.toArray(elementArray);
361+
public void insertAll() {
362+
/*
363+
// each line is ~3 elements
364+
int tooMany = elements.size() - maxLineCount*3;
365+
if (tooMany > 0) {
366+
try {
367+
remove(0, getLength()); // clear the document first
368+
} catch (BadLocationException ble) {
369+
ble.printStackTrace();
370+
}
371+
Console.systemOut("skipping " + elements.size());
372+
for (int i = 0; i < tooMany; i++) {
373+
elements.remove();
374+
}
375+
}
376+
*/
377+
ElementSpec[] elementArray = elements.toArray(new ElementSpec[0]);
351378

352379
try {
380+
/*
353381
// check how many lines have been used so far
354382
// if too many, shave off a few lines from the beginning
355383
Element element = super.getDefaultRootElement();
@@ -366,13 +394,42 @@ public synchronized void insertAll() {
366394
// remove to the end of the 200th line
367395
super.remove(0, endOffset);
368396
}
369-
super.insert(super.getLength(), elementArray);
397+
*/
398+
synchronized (insertLock) {
399+
checkLength();
400+
insert(getLength(), elementArray);
401+
checkLength();
402+
}
370403

371404
} catch (BadLocationException e) {
372405
// ignore the error otherwise this will cause an infinite loop
373406
// maybe not a good idea in the long run?
374407
}
375408
elements.clear();
376-
hasAppendage = false;
409+
// hasAppendage = false;
410+
}
411+
412+
private void checkLength() throws BadLocationException {
413+
// set a limit on the number of characters in the console
414+
int docLength = getLength();
415+
if (docLength > maxCharCount) {
416+
remove(0, docLength - maxCharCount);
417+
}
418+
// check how many lines have been used so far
419+
// if too many, shave off a few lines from the beginning
420+
Element element = super.getDefaultRootElement();
421+
int lineCount = element.getElementCount();
422+
int overage = lineCount - maxLineCount;
423+
if (overage > 0) {
424+
// if 1200 lines, and 1000 lines is max,
425+
// find the position of the end of the 200th line
426+
//systemOut.println("overage is " + overage);
427+
Element lineElement = element.getElement(overage);
428+
if (lineElement != null) {
429+
int endOffset = lineElement.getEndOffset();
430+
// remove to the end of the 200th line
431+
super.remove(0, endOffset);
432+
}
433+
}
377434
}
378435
}

build/shared/lib/defaults.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,8 @@ console.auto_clear = true
184184

185185
# set the maximum number of lines remembered by the console
186186
# the default is 500, lengthen at your own peril
187-
console.length = 500
187+
console.lines = 500
188+
console.chars = 40000
188189

189190
# Any additional Java options when running.
190191
# If you change this and can't run things, it's your own durn fault.

todo.txt

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
11
0261 (3.3.4 or 3.4)
2+
X redo console handling to not use Timer, fixing freeze-up problems
3+
o https://github.com/processing/processing/pull/4935
4+
X https://github.com/processing/processing/issues/4825
5+
6+
7+
_ should ant run launch the .app so that launchsvcs stuff works properly?
28

39
_ sketch.properties not being written if initial mode is p5.js?
410
_ what to double-click when opening p5 projects
@@ -39,9 +45,6 @@ _ super easy given current code implementation, might help usability
3945

4046

4147
contrib
42-
_ redo console handling to not use Timer, fixing freeze-up problems
43-
_ https://github.com/processing/processing/pull/4935
44-
_ https://github.com/processing/processing/issues/4825
4548
_ Make the change detector not reload the sketch
4649
_ https://github.com/processing/processing/pull/5021
4750
_ https://github.com/processing/processing/issues/4713

0 commit comments

Comments
 (0)