JetBrains / JetBrains/MPS-extensions

StringIndexOutOfBoundsException in certain scenario when deleting lines in a rich text

Open
#768 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug comp.richtext
Dominant language
JetBrains MPS
Stars
88
Forks
60
Avg merge
1d 3h
Merged PRs (30d)
15

Description

Related to issue 647.

Steps to reproduce: Set the content of a Text to a number of newlines.
Empty lines are marked with "." here.
Set the cursor (here: "|") on the last line.
Example:

.
.
.
.
|

Press Shift-Upwards to select (shown by []) the empty lines except the first.
MPS will show "boxes" like this for the selection, it will not show a box for the last line (which should be also marked).

.
[]
[]
[]
.

Press Backspace/Delete once, it will delete the empty lines except one which is still selected:

.
[]

Press Backspace/Delete again, or change the selection with e.g. Rightarrow, an exception will occur:

Action dispatch failed. Thread AWT-EventQueue-0, state ACTIVE, 1 active clients.

java.lang.StringIndexOutOfBoundsException: begin 4, end 1, length 1
	at java.base/java.lang.String.checkBoundsBeginEnd(String.java:4602)
	at java.base/java.lang.String.substring(String.java:2705)
	at de.slisson.mps.richtext.runtime.selection.RichtextSelection.deleteSelected(RichtextSelection.java:510)
	at de.slisson.mps.richtext.runtime.selection.RichtextSelection.lambda$executeDeleteSelected$4(RichtextSelection.java:449)
	at jetbrains.mps.smodel.WorkbenchModelAccess$UndoContextSetup.run(WorkbenchModelAccess.java:367)
	at jetbrains.mps.smodel.ActionDispatcher.dispatch(ActionDispatcher.java:98)
	at jetbrains.mps.smodel.ActionDispatcher.lambda$wrap$0(ActionDispatcher.java:135)
	at jetbrains.mps.smodel.ActionDispatcher.dispatch(ActionDispatcher.java:98)
	at jetbrains.mps.smodel.ActionDispatcher.lambda$wrap$0(ActionDispatcher.java:135)
	at jetbrains.mps.smodel.LockRunnable.run(LockRunnable.java:60)
	at jetbrains.mps.smodel.TryRunPlatformWriteHelper.lambda$tryWrite$2(TryRunPlatformWriteHelper.java:122)
	at com.intellij.openapi.application.impl.ApplicationImpl.runWriteAction(ApplicationImpl.java:1023)
	at jetbrains.mps.smodel.TryRunPlatformWriteHelper.runWrite(TryRunPlatformWriteHelper.java:103)
	at jetbrains.mps.smodel.TryRunPlatformWriteHelper.tryWrite(TryRunPlatformWriteHelper.java:120)
	at jetbrains.mps.smodel.WorkbenchModelAccess.lambda$tryWriteInCommand$3(WorkbenchModelAccess.java:218)
	at jetbrains.mps.util.ComputeRunnable.compute(ComputeRunnable.java:32)
	at jetbrains.mps.util.AbstractComputeRunnable.run(AbstractComputeRunnable.java:27)
	at com.intellij.openapi.command.impl.CoreCommandProcessor.executeCommand(CoreCommandProcessor.java:219)
	at com.intellij.openapi.command.impl.CoreCommandProcessor.executeCommand(CoreCommandProcessor.java:174)
	at com.intellij.openapi.command.impl.CoreCommandProcessor.executeCommand(CoreCommandProcessor.java:164)
	at jetbrains.mps.smodel.WorkbenchModelAccess.tryWriteInCommand(WorkbenchModelAccess.java:235)
	at jetbrains.mps.smodel.WorkbenchModelAccess.lambda$runCommandInEDT_$2(WorkbenchModelAccess.java:151)
	at jetbrains.mps.smodel.EDTExecutor$1.tryRun(EDTExecutor.java:61)
	at jetbrains.mps.smodel.EDTExecutorInternal.tryToRunTopTask(EDTExecutorInternal.java:296)
	at jetbrains.mps.smodel.EDTExecutorInternal.flushNTasks(EDTExecutorInternal.java:251)
	at jetbrains.mps.smodel.EDTExecutorInternal.doFlush(EDTExecutorInternal.java:233)
	at jetbrains.mps.smodel.EDTExecutorInternal.flushTasksQueue(EDTExecutorInternal.java:213)
	at jetbrains.mps.smodel.EDTExecutorInternal.lambda$guaranteeWriteSafetyViaHack$2(EDTExecutorInternal.java:200)
	at com.intellij.openapi.application.TransactionGuardImpl.runWithWritingAllowed(TransactionGuardImpl.java:209)
	at com.intellij.openapi.application.TransactionGuardImpl.access$100(TransactionGuardImpl.java:21)
	at com.intellij.openapi.application.TransactionGuardImpl$1.run(TransactionGuardImpl.java:191)
	at jetbrains.mps.smodel.EDTExecutorInternal.lambda$guaranteeWriteSafetyViaHack$3(EDTExecutorInternal.java:205)
	at jetbrains.mps.smodel.EDTExecutorInternal.lambda$forceScheduleFlushEDT$1(EDTExecutorInternal.java:168)
	at com.intellij.openapi.application.TransactionGuardImpl$1.run(TransactionGuardImpl.java:194)
	at com.intellij.openapi.application.impl.ApplicationImpl.runIntendedWriteActionOnCurrentThread(ApplicationImpl.java:881)
	at com.intellij.openapi.application.impl.ApplicationImpl$3.run(ApplicationImpl.java:513)
	at com.intellij.openapi.application.impl.FlushQueue.doRun(FlushQueue.java:75)
	at com.intellij.openapi.application.impl.FlushQueue.runNextEvent(FlushQueue.java:118)
	at com.intellij.openapi.application.impl.FlushQueue.flushNow(FlushQueue.java:42)
	at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:318)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:779)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:730)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:724)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
	at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:749)
	at com.intellij.ide.IdeEventQueue.defaultDispatchEvent(IdeEventQueue.java:918)
	at com.intellij.ide.IdeEventQueue._dispatchEvent(IdeEventQueue.java:766)
	at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$6(IdeEventQueue.java:450)
	at com.intellij.openapi.progress.impl.CoreProgressManager.computePrioritized(CoreProgressManager.java:791)
	at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$7(IdeEventQueue.java:449)
	at com.intellij.openapi.application.TransactionGuardImpl.performActivity(TransactionGuardImpl.java:105)
	at com.intellij.ide.IdeEventQueue.performActivity(IdeEventQueue.java:624)
	at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$8(IdeEventQueue.java:447)
	at com.intellij.openapi.application.impl.ApplicationImpl.runIntendedWriteActionOnCurrentThread(ApplicationImpl.java:881)
	at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.java:493)
	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:207)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:128)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:117)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:113)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:105)
	at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:92)

The above stacktrace is in MPS Extensions 2022.2, but probably looks similar with newer versions.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at de.slisson.mps.richtext.runtime.selection.RichtextSelection, especially deleteSelected at line 510 and executeDeleteSelected near line 449. Reproduce the newline-selection sequence in the issue, then trace the selection bounds during the second deletion or selection change. Done means the sequence no longer throws StringIndexOutOfBoundsException and preserves the expected selection behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
desktop-dev
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.