Bug 575275 - faster console * better mutlithreading, * bigger buffer, * faster single byte charset decoding, * trim console before drawing (faster and looks nicer) * removed unused Class and members => debugged application runs faster if it outputs a lot Change-Id: Id3fbcbdd2c261271efa90dd81a1dc1b333459dcb Signed-off-by: Joerg Kubitz <jkubitz-eclipse@gmx.de> Reviewed-on: https://git.eclipse.org/r/c/platform/eclipse.platform.debug/+/190929 Tested-by: Platform Bot <platform-bot@eclipse.org>
diff --git a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/OutputStreamMonitor.java b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/OutputStreamMonitor.java index fb09bc6..218d870 100644 --- a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/OutputStreamMonitor.java +++ b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/OutputStreamMonitor.java
@@ -98,7 +98,8 @@ * unused if only the binary interface is used */ public OutputStreamMonitor(InputStream stream, Charset charset) { - fStream = new BufferedInputStream(stream, 8192); + // java.lang.ProcessImpl returns a buffered stream anyway + fStream = stream instanceof BufferedInputStream ? stream : new BufferedInputStream(stream); fCharset = charset; fDecoder = new StreamDecoder(charset == null ? Charset.defaultCharset() : charset); fDone = new AtomicBoolean(false); @@ -162,9 +163,7 @@ */ private void fireStreamAppended(final byte[] data, int offset, int length) { if (!fListeners.isEmpty()) { - StringBuilder sb = new StringBuilder(); - fDecoder.decode(sb, data, offset, length); - final String text = sb.toString(); + String text = fDecoder.decode(data, offset, length); for (final IStreamListener listener : fListeners) { SafeRunner.run(new ISafeRunnable() { @Override @@ -211,10 +210,8 @@ if (fCachedDecodedContents != null) { return fCachedDecodedContents; } - StringBuilder sb = new StringBuilder(); byte[] data = getData(); - fBufferedDecoder.decode(sb, data, 0, data.length); - fCachedDecodedContents = sb.toString(); + fCachedDecodedContents = fBufferedDecoder.decode(data, 0, data.length); return fCachedDecodedContents; } @@ -276,11 +273,8 @@ currentTime = System.currentTimeMillis(); if (currentTime - lastSleep > 1000) { lastSleep = currentTime; - try { - // just give up CPU to maintain UI responsiveness. - Thread.sleep(1); - } catch (InterruptedException e) { - } + Thread.yield();// just give up CPU to maintain UI + // responsiveness. } } } finally {
diff --git a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/StreamDecoder.java b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/StreamDecoder.java index 7cb15a7..f64d3d4 100644 --- a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/StreamDecoder.java +++ b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/StreamDecoder.java
@@ -20,6 +20,7 @@ import java.nio.charset.CharsetDecoder; import java.nio.charset.CoderResult; import java.nio.charset.CodingErrorAction; +import java.util.Set; /** * Wraps CharsetDecoder to decode a byte stream statefully to characters. @@ -29,20 +30,30 @@ public class StreamDecoder { // For more context see https://bugs.eclipse.org/bugs/show_bug.cgi?id=507664 - static private final int BUFFER_SIZE = 4096; + /** size of java.io.BufferedInputStream.DEFAULT_BUFFER_SIZE **/ + private static final int INPUT_BUFFER_SIZE = 8192; + private final Charset charset; private final CharsetDecoder decoder; private final ByteBuffer inputBuffer; private final CharBuffer outputBuffer; - private boolean finished; + private volatile boolean finished; + + /** + * Incomplete list of known Single Byte Character Sets (see + * sun.nio.cs.SingleByte) which do not need a buffer + **/ + Set<String> singlebyteCharsetNames = Set.of("ISO_8859_1", "US_ASCII", "windows-1250", "windows-1251", "windows-1252", "windows-1253", "windows-1254", "windows-1255", "windows-1256", "windows-1257", "windows-1258"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ //$NON-NLS-11$ public StreamDecoder(Charset charset) { - this.decoder = charset.newDecoder(); - this.decoder.onMalformedInput(CodingErrorAction.REPLACE); - this.decoder.onUnmappableCharacter(CodingErrorAction.REPLACE); - this.inputBuffer = ByteBuffer.allocate(StreamDecoder.BUFFER_SIZE); - this.inputBuffer.flip(); - this.outputBuffer = CharBuffer.allocate(StreamDecoder.BUFFER_SIZE); + this.charset = charset; + CharsetDecoder d = charset.newDecoder(); + d.onMalformedInput(CodingErrorAction.REPLACE); + d.onUnmappableCharacter(CodingErrorAction.REPLACE); + boolean unbuffered = singlebyteCharsetNames.contains(charset.name()); + this.decoder = unbuffered ? null : d; + this.inputBuffer = unbuffered ? null : ByteBuffer.allocate(StreamDecoder.INPUT_BUFFER_SIZE).flip(); + this.outputBuffer = unbuffered ? null : CharBuffer.allocate((int) (StreamDecoder.INPUT_BUFFER_SIZE * d.maxCharsPerByte())); this.finished = false; } @@ -81,12 +92,31 @@ } while (!finishedReading); } - public void decode(StringBuilder consumer, byte[] buffer, int offset, int length) { + public String decode(byte[] buffer, int offset, int length) { + if (this.decoder == null) { + // fast path for single byte encodings + return new String(buffer, offset, length, charset); + } + StringBuilder builder = new StringBuilder(); + decode(builder, buffer, offset, length); + return builder.toString(); + } + + private void decode(StringBuilder consumer, byte[] buffer, int offset, int length) { this.internalDecode(consumer, buffer, offset, length); this.consume(consumer); } - public void finish(StringBuilder consumer) { + public String finish() { + if (this.decoder == null) { + return ""; //$NON-NLS-1$ + } + StringBuilder builder = new StringBuilder(); + finish(builder); + return builder.toString(); + } + + private void finish(StringBuilder consumer) { if (this.finished) { return; }
diff --git a/org.eclipse.debug.tests/src/org/eclipse/debug/tests/console/IOConsoleTests.java b/org.eclipse.debug.tests/src/org/eclipse/debug/tests/console/IOConsoleTests.java index ae51f9f..bc1157c 100644 --- a/org.eclipse.debug.tests/src/org/eclipse/debug/tests/console/IOConsoleTests.java +++ b/org.eclipse.debug.tests/src/org/eclipse/debug/tests/console/IOConsoleTests.java
@@ -28,10 +28,10 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Queue; import java.util.Random; +import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; - import org.eclipse.core.runtime.ILogListener; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; @@ -78,12 +78,12 @@ * Number of received log messages with severity error while running a * single test method. */ - private final AtomicInteger loggedErrors = new AtomicInteger(); + private final Queue<IStatus> loggedErrors = new ConcurrentLinkedQueue<>(); /** Listener to count error messages while testing. */ private final ILogListener errorLogListener = (IStatus status, String plugin) -> { if (status.matches(IStatus.ERROR)) { - loggedErrors.incrementAndGet(); + loggedErrors.add(status); } }; @@ -107,7 +107,7 @@ activePage.activate(consoleView); // add error listener - loggedErrors.set(0); + loggedErrors.clear(); Platform.addLogListener(errorLogListener); } @@ -117,7 +117,16 @@ Platform.removeLogListener(errorLogListener); super.tearDown(); - assertEquals("Test triggered errors in IOConsole.", 0, loggedErrors.get()); + assertNoError(); + } + + private void assertNoError() { + loggedErrors.forEach(status -> { + if (status.getException() != null) { + throw new AssertionError("Test triggered errors in IOConsole", status.getException()); + } + }); + assertTrue("Test triggered errors in IOConsole: " + loggedErrors.stream().toString(), loggedErrors.isEmpty()); } /** @@ -309,7 +318,7 @@ } closeConsole(c); } - assertEquals("Test triggered errors in IOConsole.", 0, loggedErrors.get()); + assertNoError(); } /** @@ -436,7 +445,7 @@ assertEquals("Wrong number of lines.", 4, c.getDocument().getNumberOfLines()); closeConsole(c); - assertEquals("Test triggered errors in IOConsole.", 0, loggedErrors.get()); + assertNoError(); } /** @@ -518,7 +527,7 @@ c.verifyContentByLine("1.", 0).verifyContentByLine("2.", 1).verifyPartitions(); } closeConsole(c); - assertEquals("Test triggered errors in IOConsole.", 0, loggedErrors.get()); + assertNoError(); } /** @@ -564,7 +573,7 @@ assertTrue("Line breaks did not overwrite text.", !c.getDocument().get().contains("err")); } closeConsole(c); - assertEquals("Test triggered errors in IOConsole.", 0, loggedErrors.get()); + assertNoError(); } /** @@ -722,7 +731,7 @@ c.verifyContent("()").verifyPartitions(); closeConsole(c); - assertEquals("Test triggered errors in IOConsole.", 0, loggedErrors.get()); + assertNoError(); } /** @@ -844,7 +853,7 @@ } c.verifyPartitions(); closeConsole(c, "#"); - assertEquals("Test triggered errors in IOConsole.", 0, loggedErrors.get()); + assertNoError(); } /**
diff --git a/org.eclipse.ui.console/META-INF/MANIFEST.MF b/org.eclipse.ui.console/META-INF/MANIFEST.MF index a278788..d3fbb40 100644 --- a/org.eclipse.ui.console/META-INF/MANIFEST.MF +++ b/org.eclipse.ui.console/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.ui.console; singleton:=true -Bundle-Version: 3.11.100.qualifier +Bundle-Version: 3.11.200.qualifier Bundle-Activator: org.eclipse.ui.console.ConsolePlugin Bundle-Vendor: %providerName Bundle-Localization: plugin
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 bbe638b..38cd40b 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
@@ -43,7 +43,7 @@ /** * Flag indicating whether this stream has been closed. */ - private boolean closed = false; + private volatile boolean closed; /** * The console's document partitioner. @@ -53,26 +53,28 @@ /** * The console this stream is attached to. */ - private IOConsole console; + private final IOConsole console; /** * Flag indicating that the console should be activated when data * is written to this stream. */ - private boolean activateOnWrite = false; + private volatile boolean activateOnWrite; /** * The color used to decorate data written to this stream. */ - private Color color; + private volatile Color color; /** * The font style used to decorate data written to this stream. */ - private int fontStyle; + private volatile int fontStyle; + /** synchronized access for atomic update **/ private StreamDecoder decoder; + /** synchronized access for atomic update **/ private boolean prependCR; /** @@ -159,7 +161,7 @@ * Returns true if the stream has been closed * @return true is the stream has been closed, false otherwise. */ - public synchronized boolean isClosed() { + public boolean isClosed() { return closed; } @@ -169,14 +171,13 @@ // Closeable#close() has no effect if already closed return; } - StringBuilder builder = new StringBuilder(); if (prependCR) { // force writing of last /r prependCR = false; - builder.append('\r'); + notifyParitioner("\r"); //$NON-NLS-1$ } - this.decoder.finish(builder); - if (builder.length() > 0) { - notifyParitioner(builder.toString()); + String s = this.decoder.finish(); + if (s.length() > 0) { + notifyParitioner(s); } console.streamClosed(this); closed = true; @@ -196,9 +197,8 @@ if (closed) { throw new IOException("Output Stream is closed"); //$NON-NLS-1$ } - StringBuilder builder = new StringBuilder(); - this.decoder.decode(builder, b, off, len); - encodedWrite(builder.toString()); + String s = this.decoder.decode(b, off, len); + encodedWrite(s); } @Override @@ -271,7 +271,7 @@ } if (newencoding.endsWith("\r")) { //$NON-NLS-1$ prependCR = true; - newencoding = new String(newencoding.substring(0, newencoding.length() - 1)); + newencoding = newencoding.substring(0, newencoding.length() - 1); } notifyParitioner(newencoding); } @@ -323,10 +323,9 @@ if (closed) { throw new IOException("Output Stream is closed"); //$NON-NLS-1$ } - StringBuilder builder = new StringBuilder(); - this.decoder.finish(builder); - if (builder.length() > 0) { - this.encodedWrite(builder.toString()); + String s = this.decoder.finish(); + if (s.length() > 0) { + this.encodedWrite(s); } this.decoder = new StreamDecoder(charset); }
diff --git a/org.eclipse.ui.console/src/org/eclipse/ui/internal/console/ConsoleDocument.java b/org.eclipse.ui.console/src/org/eclipse/ui/internal/console/ConsoleDocument.java index 2d6aef4..f5c4427 100644 --- a/org.eclipse.ui.console/src/org/eclipse/ui/internal/console/ConsoleDocument.java +++ b/org.eclipse.ui.console/src/org/eclipse/ui/internal/console/ConsoleDocument.java
@@ -99,4 +99,10 @@ public synchronized Position[] getPositions(String category) throws BadPositionCategoryException { return super.getPositions(category); } + + /** for debug only **/ + @Override + public synchronized String toString() { + return get(); + } }
diff --git a/org.eclipse.ui.console/src/org/eclipse/ui/internal/console/IOConsolePartitioner.java b/org.eclipse.ui.console/src/org/eclipse/ui/internal/console/IOConsolePartitioner.java index 0e448a6..3158162 100644 --- a/org.eclipse.ui.console/src/org/eclipse/ui/internal/console/IOConsolePartitioner.java +++ b/org.eclipse.ui.console/src/org/eclipse/ui/internal/console/IOConsolePartitioner.java
@@ -28,6 +28,9 @@ import java.util.Iterator; import java.util.List; import java.util.Objects; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -113,10 +116,19 @@ * elements. (see also {@link #checkPartitions()}) */ private final ArrayList<IOConsolePartition> partitions = new ArrayList<>(); - /** Blocks of data that have not yet been appended to the document. */ - private final ArrayList<PendingPartition> pendingPartitions = new ArrayList<>(); - /** Total length of pending partitions content. */ - private int pendingSize; + /** + * max ~ 16MB when debugged application outputs faster then we can handle. Seems + * to be a could compromise between memory and speed we can handle. Eclipse IDE + * may use that memory size ~3 times during processing (buffer+document+parser) + */ + private static final int MAX_BUFFER_BYTES = 16_000_000; + /** + * Queue of buffers that have not yet been appended to the document. Every + * buffer will hold up to 8192 byte - but typically a single line output if + * handled fast. The debugged application will block if the limit is exceeded. + */ + private final BlockingQueue<PendingPartition> pendingPartitions = new LinkedBlockingQueue<>( + MAX_BUFFER_BYTES / 8192); /** Job that appends pending partitions to the document. */ private final QueueProcessingJob queueJob = new QueueProcessingJob(); /** Job that trims console content if it exceeds {@link #highWaterMark}. */ @@ -130,7 +142,6 @@ * </p> */ private DocUpdateType updateType = DocUpdateType.INPUT; - private IRegion changedRegion; /** * A list of partitions containing input from the console, that have not been * appended to the input stream yet. No guarantees on element order. @@ -214,11 +225,7 @@ @Override public void disconnect() { - synchronized (pendingPartitions) { - pendingPartitions.clear(); - pendingSize = 0; - pendingPartitions.notifyAll(); - } + pendingPartitions.clear(); synchronized (partitions) { trimJob.cancel(); queueJob.cancel(); @@ -283,10 +290,7 @@ if (streamsClosed) { // do not expect new data since all streams are closed // check if pending data is queued - final boolean morePending; - synchronized (pendingPartitions) { - morePending = !pendingPartitions.isEmpty(); - } + final boolean morePending = !pendingPartitions.isEmpty(); if (morePending) { queueJob.schedule(); } else { @@ -430,10 +434,8 @@ if (document != null && highWaterMark > 0) { int length = document.getLength(); if (length > highWaterMark) { - if (trimJob.getState() == Job.NONE) { // if the job isn't already running - trimJob.setTrimLineOffset(length - lowWaterMark); - trimJob.schedule(); - } + // do trim synchronous to prevent drawing trimmed text - we are already in UI and have the lock + trim(length - lowWaterMark, true); } } } @@ -442,10 +444,7 @@ * Clears the console content. */ public void clearBuffer() { - synchronized (pendingPartitions) { - pendingPartitions.clear(); - pendingSize = 0; - } + pendingPartitions.clear(); synchronized (partitions) { if (document != null) { trimJob.setTrimOffset(document.getLength()); @@ -484,7 +483,7 @@ // update and trim jobs are triggered by this partitioner and all partitioning // changes are applied separately case OUTPUT: - return changedRegion; + return null; // changedRegion was never assigned case TRIM: return null; // trim does not change partition types @@ -692,37 +691,27 @@ if (s == null) { return; } - synchronized (pendingPartitions) { - final PendingPartition lastPending = pendingPartitions.size() > 0 - ? pendingPartitions.get(pendingPartitions.size() - 1) - : null; - if (lastPending != null && lastPending.stream == stream) { - lastPending.append(s); - } else { - pendingPartitions.add(new PendingPartition(stream, s)); - } + PendingPartition partition = new PendingPartition(stream, s); + while (!offer(partition)) { + helpProgress(); + } + queueJob.schedule(); + } - if (pendingSize > 1000) { - queueJob.schedule(); - } else { - queueJob.schedule(50); - } + private void helpProgress() { + if (Display.getCurrent() != null) { + // make sure pendingPartitions can take + queueJob.processPendingPartitions(); + } else { + Thread.yield(); // give UI thread chance to proceed + } + } - if (pendingSize > 160000) { - if (Display.getCurrent() == null) { - try { - // Block thread to give UI time to process pending output. - // Do not wait forever. Current thread and UI thread might share locks. An - // example is bug 421303 where current thread and UI thread both write to - // console and therefore both need the write lock for IOConsoleOutputStream. - pendingPartitions.wait(1000); - } catch (InterruptedException e) { - } - } else { - // If we are in UI thread we cannot lock it, so process queued output. - queueJob.processPendingPartitions(); - } - } + private boolean offer(PendingPartition p) { + try { + return pendingPartitions.offer(p, 10, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + return false; } } @@ -730,17 +719,17 @@ * Holds data until updateJob can be run and the document can be updated. */ private class PendingPartition { - StringBuilder text = new StringBuilder(8192); - IOConsoleOutputStream stream; + private final CharSequence text; + private final IOConsoleOutputStream stream; - PendingPartition(IOConsoleOutputStream stream, String text) { + PendingPartition(IOConsoleOutputStream stream, CharSequence text) { this.stream = stream; - append(text); + this.text = text; } - void append(String moreText) { - text.append(moreText); - pendingSize += moreText.length(); + @Override + public String toString() { + return text.toString(); } } @@ -755,8 +744,6 @@ private int atOutputPartitionIndex = -1; /** The pending number of characters to replace in document. */ private int replaceLength; - /** The pending content to be inserted in document. */ - private StringBuilder content; /** The offset in document where to apply the next replace. */ private int nextWriteOffset; @@ -784,10 +771,7 @@ */ @Override public boolean shouldRun() { - synchronized (pendingPartitions) { - final boolean shouldRun = pendingPartitions.size() > 0; - return shouldRun; - } + return !pendingPartitions.isEmpty(); } /** @@ -795,22 +779,29 @@ * update partitioning. */ private void processPendingPartitions() { - final List<PendingPartition> pendingCopy; - final int size; - synchronized (pendingPartitions) { - pendingCopy = new ArrayList<>(pendingPartitions); - size = pendingSize; - pendingPartitions.clear(); - pendingSize = 0; - pendingPartitions.notifyAll(); + final List<PendingPartition> pendingCopy = new ArrayList<>(); + // draining the whole buffer here is important - this way we get as much data as + // available and may skip to draw text that exceeds the Console buffer size + // anyway (see checkBufferSize()). + pendingPartitions.drainTo(pendingCopy); + int sizeHint = 0; + if (pendingCopy.isEmpty()) { + return; + } + IOConsoleOutputStream stream = pendingCopy.get(0).stream; + for (PendingPartition p : pendingCopy) { + if (p.stream != stream) { + break; + } + sizeHint += p.text.length(); } synchronized (partitions) { if (document != null) { - applyStreamOutput(pendingCopy, size); + applyStreamOutput(pendingCopy, sizeHint); } + checkFinished(); + checkBufferSize(); // needs partitions synchronized } - checkFinished(); - checkBufferSize(); } /** @@ -835,17 +826,19 @@ // resulting in multiple partitions but if all the content is appended to the // document there is only one update required to add the actual content. nextWriteOffset = outputOffset; - content = new StringBuilder(sizeHint); + StringBuilder content = new StringBuilder(sizeHint); replaceLength = 0; atOutputPartition = null; atOutputPartitionIndex = -1; for (PendingPartition pending : pendingCopy) { // create matcher to find control characters in pending content (if enabled) - final Matcher controlCharacterMatcher = controlPattern != null ? controlPattern.matcher(pending.text) + CharSequence text = pending.text; + IOConsoleOutputStream stream = pending.stream; + final Matcher controlCharacterMatcher = controlPattern != null ? controlPattern.matcher(text) : null; - for (int textOffset = 0; textOffset < pending.text.length();) { + for (int textOffset = 0; textOffset < text.length();) { // Process pending content in chunks. // Processing is primary split on control characters since there interpretation // is easier if all content changes before are already applied. @@ -866,11 +859,11 @@ partEnd = controlCharacterMatcher.start(); foundControlCharacter = true; } else { - partEnd = pending.text.length(); + partEnd = text.length(); foundControlCharacter = false; } - partititonContent(pending.stream, pending.text, textOffset, partEnd); + partititonContent(stream, text, textOffset, partEnd, content); textOffset = partEnd; // finished processing of regular content before control characters @@ -891,7 +884,7 @@ // move virtual output cursor one step back for each \b // but stop at current line start and skip any input partitions int backStepCount = controlCharacterMatch.length(); - if (partitions.size() == 0) { + if (partitions.isEmpty()) { outputOffset = 0; break; } @@ -947,7 +940,7 @@ } outputOffset = document.getLength(); nextWriteOffset = outputOffset; - partititonContent(pending.stream, vtab, 0, vtab.length()); + partititonContent(stream, vtab, 0, vtab.length(), content); break; case 0: @@ -968,7 +961,6 @@ } } applyOutputToDocument(content.toString(), nextWriteOffset, replaceLength); - content = null; } /** @@ -988,7 +980,8 @@ * @param offset the start offset (inclusive) within text to partition * @param endOffset the end offset (exclusive) within text to partition */ - private void partititonContent(IOConsoleOutputStream stream, CharSequence text, int offset, int endOffset) { + private void partititonContent(IOConsoleOutputStream stream, CharSequence text, int offset, int endOffset, + StringBuilder content) { int textOffset = offset; while (textOffset < endOffset) { // Process content part. This part never contains control characters. @@ -1180,27 +1173,25 @@ * @param offset trims console content up to this offset */ public void setTrimOffset(int offset) { + // XXX an arbitrary offset would cause follow up errors if we trim a delim + // exactly between \r and \n truncateOffset = offset; truncateToOffsetLineStart = false; } - /** - * Sets the trim offset. - * - * @param offset trims output up to the line containing this offset - */ - public void setTrimLineOffset(int offset) { - truncateOffset = offset; - truncateToOffsetLineStart = true; - } - @Override public IStatus runInUIThread(IProgressMonitor monitor) { synchronized (partitions) { - if (document == null) { - return Status.OK_STATUS; - } + trim(truncateOffset, truncateToOffsetLineStart); + } + return Status.OK_STATUS; + } + } + + private void trim(int truncateOffset, boolean truncateToOffsetLineStart) { + if (document != null) { + { try { int length = document.getLength(); int cutOffset = truncateOffset; @@ -1242,7 +1233,6 @@ log(e); } } - return Status.OK_STATUS; } }
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 deleted file mode 100644 index e334aa2..0000000 --- a/org.eclipse.ui.console/src/org/eclipse/ui/internal/console/StreamDecoder.java +++ /dev/null
@@ -1,30 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2017 Andreas Loth and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Andreas Loth - initial API and implementation - *******************************************************************************/ - -package org.eclipse.ui.internal.console; - -import java.nio.charset.Charset; - - -/** - * @deprecated class was moved to - * {@link org.eclipse.debug.internal.core.StreamDecoder} - */ -@Deprecated -public class StreamDecoder extends org.eclipse.debug.internal.core.StreamDecoder { - - public StreamDecoder(Charset charset) { - super(charset); - } -}