diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/buildconsole/BuildConsolePartitionerEditDataTest.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/buildconsole/BuildConsolePartitionerEditDataTest.java index c3c5c2f7fb9..d342e16eb04 100644 --- a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/buildconsole/BuildConsolePartitionerEditDataTest.java +++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/buildconsole/BuildConsolePartitionerEditDataTest.java @@ -53,24 +53,30 @@ public class BuildConsolePartitionerEditDataTest { assertThat(update0.getNewContents(), is("")); assertThat(update0.getStreamsNeedingNotifcation(), is(empty())); assertThat(update0.needsClearDocumentMarkerManager(), is(true)); + assertThat(update0.getOffset(), is(0L)); data.append("Line of text\n", stream1, null); UpdateUIData update1 = data.getUpdate(); assertThat(update1.getNewContents(), is("Line of text\n")); assertThat(update1.getStreamsNeedingNotifcation(), is(Arrays.asList(stream1))); assertThat(update1.needsClearDocumentMarkerManager(), is(false)); + assertThat(update1.getOffset(), is(0L)); data.append("Another line of text\n", stream2, null); UpdateUIData update2 = data.getUpdate(); assertThat(update2.getNewContents(), is("Line of text\nAnother line of text\n")); assertThat(update2.getStreamsNeedingNotifcation(), is(Arrays.asList(stream2))); assertThat(update2.needsClearDocumentMarkerManager(), is(false)); + assertThat(update2.getOffset(), is(0L)); } @Test public void testOverflow() { + StringBuilder all = new StringBuilder(); for (int i = 0; i < DEFAULT_MAX_LINES * 4; i++) { - data.append("Line " + i + "\n", stream1, null); + String text = "Line " + i + "\n"; + data.append(text, stream1, null); + all.append(text); } UpdateUIData update = data.getUpdate(); @@ -86,6 +92,9 @@ public class BuildConsolePartitionerEditDataTest { assertThat(contents, endsWith("Line " + lastLine + "\n")); int firstLine = lastLine - newlines + 1; assertThat(contents, startsWith("Line " + firstLine + "\n")); + + long expectedOffset = all.indexOf(contents); + assertThat(update.getOffset(), is(expectedOffset)); } @Test diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsolePartitioner.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsolePartitioner.java index 741c95395af..a0bc8421da1 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsolePartitioner.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsolePartitioner.java @@ -26,6 +26,7 @@ import org.eclipse.core.filesystem.EFS; import org.eclipse.core.filesystem.IFileStore; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; +import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.DocumentEvent; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IDocumentPartitioner; @@ -104,6 +105,8 @@ public class BuildConsolePartitioner private int fUpdateDelay = BuildConsolePreferencePage.DEFAULT_BUILDCONSOLE_UPDATE_DELAY_MS; + private long fOffset; + /** * Construct a partitioner that is not associated with a specific project */ @@ -251,19 +254,23 @@ public class BuildConsolePartitioner fDocumentMarkerManager.clear(); } - /* - * This call is slow, it updates the UI as a side effect. - * - * XXX: Doing a set on the whole document means that all the line - * numbers need to be recalculated. This can be optimized further by - * keeping track of what needs to be edited. However, for now this - * optimization has not been done because although this leads to - * increased CPU usage, it does not lead to a delay in total processing - * time, but rather to a decrease in frame rate. Furthermore, if the - * document overflows, the document's line numbers need to be - * recalculated anyway, so little benefit. - */ - fDocument.set(update.getNewContents()); + try { + long offsetChangeSinceLastUpdate = update.getOffset() - fOffset; + int toTrim = (int) Math.min(offsetChangeSinceLastUpdate, fDocument.getLength()); + + int length = fDocument.getLength(); + String newContents = update.getNewContents(); + String appendContents = newContents.substring(length - toTrim); + // The append has to be done before the delete from head + // to avoid document becoming 0 length and therefore the + // listeners assume the document has been cleared + fDocument.replace(length + toTrim, 0, appendContents); + fDocument.replace(0, toTrim, ""); //$NON-NLS-1$ + } catch (BadLocationException e) { + fDocument.set(update.getNewContents()); + } + + fOffset = update.getOffset(); } /** diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsolePartitionerEditData.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsolePartitionerEditData.java index d3af3f96e0b..d28550bcf5c 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsolePartitionerEditData.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsolePartitionerEditData.java @@ -36,6 +36,11 @@ public class BuildConsolePartitionerEditData { */ boolean needsClearDocumentMarkerManager(); + /** + * The content's offset since beginning of time. + */ + long getOffset(); + /** * New contents for the build console. */ @@ -70,6 +75,11 @@ public class BuildConsolePartitionerEditData { */ private boolean fClearDocumentMarkerManager = false; + /** + * Offset of the start of the document since the beginning of time. + */ + private long fOffset = 0; + /** * Editable document, all modifications are made to this copy of the * document, then the UI thread occasionally gets these updates @@ -86,6 +96,7 @@ public class BuildConsolePartitionerEditData { */ private Set fEditStreams = new HashSet<>(); + public BuildConsolePartitionerEditData(int maxLines) { fMaxLines = maxLines; } @@ -105,6 +116,7 @@ public class BuildConsolePartitionerEditData { synchronized (this) { fEditPartitions.clear(); fClearDocumentMarkerManager = true; + fOffset += fEditStringBuilder.length(); fEditStringBuilder.setLength(0); fEditLineCount = 0; } @@ -239,6 +251,7 @@ public class BuildConsolePartitionerEditData { fEditPartitions = newParitions; fClearDocumentMarkerManager = true; + fOffset += offsetToOffset; fEditStringBuilder.delete(0, offsetToOffset); fEditLineCount = newNewlineCount; @@ -287,11 +300,13 @@ public class BuildConsolePartitionerEditData { */ public UpdateUIData getUpdate() { boolean clearDocumentMarkerManager; + long newOffset; String newConents; List newPartitions; List streamsNeedingNotifcation; synchronized (this) { + newOffset = fOffset; newConents = fEditStringBuilder.toString(); newPartitions = new ArrayList<>(fEditPartitions); clearDocumentMarkerManager = fClearDocumentMarkerManager; @@ -321,6 +336,11 @@ public class BuildConsolePartitionerEditData { public String getNewContents() { return newConents; } + + @Override + public long getOffset() { + return newOffset; + } }; }