diff --git a/debug/org.eclipse.debug.tests/src/org/eclipse/debug/tests/console/IOConsoleTests.java b/debug/org.eclipse.debug.tests/src/org/eclipse/debug/tests/console/IOConsoleTests.java index 86623850a1d..cd8fd8f6de6 100644 --- a/debug/org.eclipse.debug.tests/src/org/eclipse/debug/tests/console/IOConsoleTests.java +++ b/debug/org.eclipse.debug.tests/src/org/eclipse/debug/tests/console/IOConsoleTests.java @@ -1139,4 +1139,30 @@ public void testIsAnsiEscapeEnabled() throws ExecutionException, NotDefinedExcep final boolean changedBack = IOConsole.isAnsiConsoleEnabled(); assertEquals(initial, changedBack); } + + + @Test + public void testBug2127_CaretRepositionedAfterOutput() throws Exception { + IOConsoleTestUtil c = getTestUtil("Test caret reposition after output"); + try { + c.writeAndVerify("Please type something: "); + c.insertTypingAndVerify("42"); + c.enter(); + TestUtil.waitWhile(() -> c.getCaretOffset() != c.getContentLength(), TestUtil.DEFAULT_TIMEOUT, () -> "Caret never reached end of document after submitting input."); + + int caretBeforeOutput = c.getCaretOffset(); + c.writeAndVerify("You typed: 42"); + TestUtil.waitWhile(() -> c.getCaretOffset() != c.getContentLength(), TestUtil.DEFAULT_TIMEOUT, () -> "Caret was not repositioned to end of document after output arrived at the old (now read-only) caret position."); + + assertTrue(c.getPartitioner().isReadOnly(caretBeforeOutput), "Precondition: old caret position must now be read-only."); + + c.insertTypingAndVerify("7"); + c.enter().clear(); + c.verifyPartitions(); + closeConsole(c, "42", "7"); + } finally { + ConsolePlugin.getDefault().getConsoleManager().removeConsoles(new IConsole[] { + c.getConsole() }); + } + } } diff --git a/debug/org.eclipse.ui.console/src/org/eclipse/ui/internal/console/IOConsoleViewer.java b/debug/org.eclipse.ui.console/src/org/eclipse/ui/internal/console/IOConsoleViewer.java index 7d977066ab9..8d8237f726b 100644 --- a/debug/org.eclipse.ui.console/src/org/eclipse/ui/internal/console/IOConsoleViewer.java +++ b/debug/org.eclipse.ui.console/src/org/eclipse/ui/internal/console/IOConsoleViewer.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2019 IBM Corporation and others. + * Copyright (c) 2000, 2026 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -225,10 +225,43 @@ public void documentAboutToBeChanged(DocumentEvent event) { public void documentChanged(DocumentEvent event) { if (fAutoScroll) { revealEndOfDocument(); + repositionCaretAfterOutput(); } } }; } return fAutoScrollListener; } + + /** + * Moves caret to the beginning of next valid input section + */ + private void repositionCaretAfterOutput() { + final IDocument doc = getDocument(); + if (doc == null) { + return; + } + if (doc.getDocumentPartitioner() instanceof IConsoleDocumentPartitioner consolePart + && consolePart instanceof IConsoleDocumentPartitionerExtension consolePartExt) { + StyledText widget = getTextWidget(); + if (widget == null || widget.isDisposed()) { + return; + } + ConsolePlugin.getStandardDisplay().asyncExec(() -> { + StyledText styleText = getTextWidget(); + if (styleText == null || styleText.isDisposed()) { + return; + } + int caretOffset = widget.getCaretOffset(); + if (consolePart.isReadOnly(caretOffset) && consolePart.isReadOnly(Math.max(caretOffset - 1, 0))) { + int nextWritable = consolePartExt.getNextOffsetByState(caretOffset, true); + if (nextWritable != caretOffset) { + styleText.setCaretOffset(nextWritable); + styleText.showSelection(); + } + } + }); + } + + } }