diff options
3 files changed, 50 insertions, 11 deletions
diff --git a/org.eclipse.debug.tests/src/org/eclipse/debug/tests/console/ConsoleTests.java b/org.eclipse.debug.tests/src/org/eclipse/debug/tests/console/ConsoleTests.java index 3939c4d3a..b683fe22e 100644 --- a/org.eclipse.debug.tests/src/org/eclipse/debug/tests/console/ConsoleTests.java +++ b/org.eclipse.debug.tests/src/org/eclipse/debug/tests/console/ConsoleTests.java @@ -55,6 +55,31 @@ public class ConsoleTests extends TestCase { TestHelper.waitForJobs(); TestCase.assertEquals("whole test string should be written", testString, document.get()); //$NON-NLS-1$ } + TestHelper.waitForJobs(); + // after closing the stream, the document content should still be the + // same + TestCase.assertEquals("closing the stream should not alter the document", testString, document.get()); //$NON-NLS-1$ + } + + public void testConsoleOutputStreamLastR() throws IOException, InterruptedException { + String testString = "a\r"; //$NON-NLS-1$ + byte[] testStringBuffer = testString.getBytes(StandardCharsets.UTF_8); + TestCase.assertEquals("Test string \"" + testString + "\" should consist of 2 UTF-8 bytes", 2, testStringBuffer.length); //$NON-NLS-1$ //$NON-NLS-2$ + MessageConsole console = new MessageConsole("Test Console", //$NON-NLS-1$ + IConsoleConstants.MESSAGE_CONSOLE_TYPE, null, StandardCharsets.UTF_8.name(), true); + IDocument document = console.getDocument(); + TestHelper.waitForJobs(); + TestCase.assertEquals("Document should be empty", "", document.get()); //$NON-NLS-1$ //$NON-NLS-2$ + try (IOConsoleOutputStream outStream = console.newOutputStream()) { + outStream.write(testStringBuffer); + // everything but pending \r should be written + TestHelper.waitForJobs(); + TestCase.assertEquals("First char should be written", testString.substring(0, 1), document.get()); //$NON-NLS-1$ + } + TestHelper.waitForJobs(); + // after closing the stream, the document content should still be the + // same + TestCase.assertEquals("closing the stream should write the pending \\r", testString, document.get()); //$NON-NLS-1$ } } diff --git a/org.eclipse.ui.console/src/org/eclipse/ui/console/IOConsoleOutputStream.java b/org.eclipse.ui.console/src/org/eclipse/ui/console/IOConsoleOutputStream.java index 7e78ddf6a..8ee47071f 100644 --- a/org.eclipse.ui.console/src/org/eclipse/ui/console/IOConsoleOutputStream.java +++ b/org.eclipse.ui.console/src/org/eclipse/ui/console/IOConsoleOutputStream.java @@ -168,10 +168,15 @@ public class IOConsoleOutputStream extends OutputStream { // Closeable#close() has no effect if already closed return; } + StringBuilder builder = new StringBuilder(); if (prependCR) { // force writing of last /r prependCR = false; - notifyParitioner("\r"); //$NON-NLS-1$ + builder.append('\r'); } + this.decoder.finish(builder); + if (builder.length() > 0) { + notifyParitioner(builder.toString()); + } console.streamClosed(this); closed = true; partitioner = null; @@ -193,7 +198,7 @@ public class IOConsoleOutputStream extends OutputStream { * @see java.io.OutputStream#write(byte[], int, int) */ @Override - public void write(byte[] b, int off, int len) throws IOException { + public synchronized void write(byte[] b, int off, int len) throws IOException { StringBuilder builder = new StringBuilder(); this.decoder.decode(builder, b, off, len); encodedWrite(builder.toString()); @@ -317,10 +322,12 @@ public class IOConsoleOutputStream extends OutputStream { * @throws IOException if the stream is closed * @since 3.7 */ - public void setCharset(Charset charset) throws IOException { + public synchronized void setCharset(Charset charset) throws IOException { StringBuilder builder = new StringBuilder(); this.decoder.finish(builder); - this.encodedWrite(builder.toString()); + if (builder.length() > 0) { + this.encodedWrite(builder.toString()); + } this.decoder = new StreamDecoder(charset); } diff --git a/org.eclipse.ui.console/src/org/eclipse/ui/internal/console/StreamDecoder.java b/org.eclipse.ui.console/src/org/eclipse/ui/internal/console/StreamDecoder.java index dde14fdcd..aeb0179f1 100644 --- a/org.eclipse.ui.console/src/org/eclipse/ui/internal/console/StreamDecoder.java +++ b/org.eclipse.ui.console/src/org/eclipse/ui/internal/console/StreamDecoder.java @@ -29,6 +29,7 @@ public class StreamDecoder { private final CharsetDecoder decoder; private final ByteBuffer inputBuffer; private final CharBuffer outputBuffer; + private boolean finished; public StreamDecoder(Charset charset) { this.decoder = charset.newDecoder(); @@ -37,6 +38,7 @@ public class StreamDecoder { this.inputBuffer = ByteBuffer.allocate(StreamDecoder.BUFFER_SIZE); this.inputBuffer.flip(); this.outputBuffer = CharBuffer.allocate(StreamDecoder.BUFFER_SIZE); + this.finished = false; } private void consume(StringBuilder consumer) { @@ -45,15 +47,15 @@ public class StreamDecoder { this.outputBuffer.clear(); } - private void internalDecode(StringBuilder consumer, byte[] buffer, int offset, int length, boolean last) { + private void internalDecode(StringBuilder consumer, byte[] buffer, int offset, int length) { assert (offset >= 0); assert (length >= 0); int position = offset; int end = offset + length; assert (end <= buffer.length); - boolean finished = false; + boolean finishedReading = false; do { - CoderResult result = this.decoder.decode(this.inputBuffer, this.outputBuffer, last); + CoderResult result = this.decoder.decode(this.inputBuffer, this.outputBuffer, false); if (result.isOverflow()) { this.consume(consumer); } else if (result.isUnderflow()) { @@ -65,23 +67,28 @@ public class StreamDecoder { this.inputBuffer.put(buffer, position, read); position += read; } else { - finished = true; + finishedReading = true; } this.inputBuffer.flip(); } else { assert false; } - } while (!finished); + } while (!finishedReading); } public void decode(StringBuilder consumer, byte[] buffer, int offset, int length) { - this.internalDecode(consumer, buffer, offset, length, false); + this.internalDecode(consumer, buffer, offset, length); this.consume(consumer); } public void finish(StringBuilder consumer) { - this.internalDecode(consumer, new byte[0], 0, 0, true); + if (this.finished) { + return; + } + this.finished = true; CoderResult result; + result = this.decoder.decode(this.inputBuffer, this.outputBuffer, true); + assert (result.isOverflow() || result.isUnderflow()); do { result = this.decoder.flush(this.outputBuffer); if (result.isOverflow()) { |