mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[terminal] IJPL-191456 Fix inconsistency in blocks model
`startNewBlock` is called before shell prints the prompt. It looks like sometimes (theoretically, no actual steps to reproduce), prompt position can be before the previous block start, so our code adjusts the current block by setting endOffset < startOffset. It is a single reason that may explain the fact that "startOffset" is greater than the "endOffset" in the exception reports. Let's add protection for this case - remove blocks after the cursor offset in this case. (cherry picked from commit 3f47dc01d890f37729d2c780538f70412884f321) IJ-CR-211622 GitOrigin-RevId: 2859d1672de099c02c2628fea871d0a2c0554fea
This commit is contained in:
committed by
intellij-monorepo-bot
parent
b7074c2707
commit
cdd6ec35d9
+8
@@ -63,6 +63,14 @@ class TerminalBlocksModelImpl(
|
||||
}
|
||||
|
||||
fun startNewBlock(offset: TerminalOffset) {
|
||||
// The new prompt may start before the active block (or even before some already finished blocks)
|
||||
// if the shell moved the cursor backwards (e.g. the screen was redrawn or partially cleared via
|
||||
// cursor movement, a transient prompt was printed, or the output was reflowed on resize).
|
||||
// Remove all blocks that start after the new prompt offset, since they are being overwritten.
|
||||
// This also keeps the remaining active block's start offset <= offset, so the block below can
|
||||
// never end up with an inverted range (startOffset > endOffset).
|
||||
trimBlocksAfter(offset)
|
||||
|
||||
val active = activeBlock as TerminalCommandBlockImpl
|
||||
if (offset == active.startOffset) {
|
||||
blocks.removeLast()
|
||||
|
||||
+34
@@ -328,6 +328,40 @@ internal class TerminalBlocksModelTest : BasePlatformTestCase() {
|
||||
assertEquals("updatedPrompt: \n", outputModel.getTextAsString(secondBlock.startOffset, secondBlock.endOffset))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `new prompt started before the active block does not create an inverted block`() = runBlocking(Dispatchers.EDT) {
|
||||
val outputModel = TerminalTestUtil.createOutputModel()
|
||||
val blocksModel = createBlocksModel(outputModel)
|
||||
|
||||
// Prepare a finished block [0, 31) and an active block [31, 47).
|
||||
outputModel.update(0, "\n\n\n")
|
||||
blocksModel.startNewBlock(TerminalOffset.ZERO)
|
||||
outputModel.update(0, "myPrompt: \n\n\n")
|
||||
blocksModel.updateCommandStartOffset(TerminalOffset.of(10))
|
||||
outputModel.update(0, "myPrompt: myCommand\n\n\n")
|
||||
blocksModel.updateOutputStartOffset(TerminalOffset.of(20))
|
||||
outputModel.update(1, "someOutput\n\n")
|
||||
blocksModel.startNewBlock(TerminalOffset.of(31))
|
||||
outputModel.update(2, "updatedPrompt: \n")
|
||||
|
||||
assertEquals(2, blocksModel.blocks.size)
|
||||
|
||||
// The shell moves the cursor backwards into the first (finished) block and starts a new prompt there.
|
||||
// Previously this set the active block end offset below its start offset, producing an inverted range (startOffset > endOffset).
|
||||
blocksModel.startNewBlock(TerminalOffset.of(15))
|
||||
|
||||
assertEquals(2, blocksModel.blocks.size)
|
||||
|
||||
// The overwritten block [31, 47) is gone; the first block is trimmed to end at the new prompt offset.
|
||||
val firstBlock = blocksModel.blocks[0] as TerminalCommandBlock
|
||||
assertEquals(TerminalOffset.ZERO, firstBlock.startOffset)
|
||||
assertEquals(TerminalOffset.of(15), firstBlock.endOffset)
|
||||
|
||||
val secondBlock = blocksModel.blocks[1] as TerminalCommandBlock
|
||||
assertEquals(TerminalOffset.of(15), secondBlock.startOffset)
|
||||
assertEquals(TerminalOffset.of(47), secondBlock.endOffset)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `initial block is left if there was some text`() = runBlocking(Dispatchers.EDT) {
|
||||
val outputModel = TerminalTestUtil.createOutputModel()
|
||||
|
||||
Reference in New Issue
Block a user