From 3bcbbf5c7e27f10c0ef63fbfdf07de157fb8af8c Mon Sep 17 00:00:00 2001 From: cschar Date: Sun, 10 Aug 2025 13:31:42 -0400 Subject: [PATCH 1/2] Specify Read/Write Action types for EDT tasks to prevent threading issues and improve stability. --- CHANGELOG.md | 2 + .../pmode3/ParticleContainerManager.java | 5 +- .../pmode3/actionHandlers/MyPasteHandler.java | 223 +++++++++--------- .../pmode3/listeners/MyCaretListener.java | 56 ++--- 4 files changed, 143 insertions(+), 143 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d4f00be..695cf3d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ # power-mode-zeranthium Changelog ## [Unreleased] +- bug fix: Specify Read/Write Action types on some EDT Thread tasks + ## [3.4.1-stable.243] - 2025-02-17 diff --git a/src/main/java/com/cschar/pmode3/ParticleContainerManager.java b/src/main/java/com/cschar/pmode3/ParticleContainerManager.java index f9c1811..95e714c 100644 --- a/src/main/java/com/cschar/pmode3/ParticleContainerManager.java +++ b/src/main/java/com/cschar/pmode3/ParticleContainerManager.java @@ -14,6 +14,7 @@ package com.cschar.pmode3; import com.intellij.openapi.Disposable; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.ScrollingModel; import com.intellij.openapi.editor.VisualPosition; @@ -154,7 +155,9 @@ public void update(final Editor editor) { @Override public void run() { - updateInUI(editor); + ApplicationManager.getApplication().runReadAction(() -> { + updateInUI(editor); + }); } }); } diff --git a/src/main/java/com/cschar/pmode3/actionHandlers/MyPasteHandler.java b/src/main/java/com/cschar/pmode3/actionHandlers/MyPasteHandler.java index f38667e..43cec36 100644 --- a/src/main/java/com/cschar/pmode3/actionHandlers/MyPasteHandler.java +++ b/src/main/java/com/cschar/pmode3/actionHandlers/MyPasteHandler.java @@ -69,127 +69,120 @@ protected void doExecute(@NotNull Editor editor, @Nullable Caret caret, DataCon @Override public void run() { - ScrollingModel scrollingModel = editor.getScrollingModel(); - - //disable so sprites render at correct spot and arent slowed down by visual scroll - scrollingModel.disableAnimation(); - try { - int beforePasteOffset = scrollingModel.getVerticalScrollOffset(); - }catch(UnsupportedOperationException e){ - LOGGER.debug("paste unsupported, exiting early"); - //if we are pasting into a search box via ctrl+f, etc.. (not a real editor), - // e.g. com.intellij.openapi.editor.textarea.TextComponentScrollingModel - // don't draw to GUI, just paste and exit - EditorCopyPasteHelper.getInstance().pasteFromClipboard(editor); - return; - } - - TextRange[] pasted = EditorCopyPasteHelper.getInstance().pasteFromClipboard(editor); - if(pasted.length != 1) return; //ensure we have a single TextRange to work with - TextRange t = pasted[0]; - - - //TODO: figure out how to calculate each pasted character x,y coord without incrementing caret - //Disable CaretListener for the following... - MyCaretListener.enabled = false; - - // |hey| | | - // |ya| ----> | | - // |hello there hi| | | - - //Begin moving caret along all of selected text to build an outline of - //the 'selected' blob. When outline built, add effect to it. - int afterPasteOffset = scrollingModel.getVerticalScrollOffset(); - scrollingModel.enableAnimation(); -// -// int charWidth = EditorUtil.getPlainSpaceWidth(editor); - int lineHeight = editor.getLineHeight(); - int start = t.getStartOffset(); - int offset = t.getLength(); //offset is # of characters typed - - //paste outline points, - //to show where each line starts and ends with 2 points - // max size possible for line numbers is offset - // ex: paste offset 5, but contents is 5 characters w/ newlines - Point[][] poPoints = new Point[offset][2]; - - Caret curCaret = editor.getCaretModel().getCurrentCaret(); - Point prevPoint = null; - Point point = null; - int curLine = 0; - - for(int i = start; i <= start + offset; i++){ - curCaret.moveToOffset(i); - VisualPosition visualPosition = curCaret.getVisualPosition(); - point = editor.visualPositionToXY(visualPosition); - point.x = point.x - scrollingModel.getHorizontalScrollOffset(); - point.y = point.y - afterPasteOffset; - - if(prevPoint == null){ //only happens once - poPoints[0][0] = point; - }else{ - if(prevPoint.y == point.y){ //on same line, dont add anything - //continue - }else {//we've moved to a new line, - // so add prevPoint as END of last line, - poPoints[curLine][1] = prevPoint; - curLine += 1; - //add new line boundary - poPoints[curLine][0] = point; - } + // All editor operations should be in write action since we're modifying content + WriteCommandAction.runWriteCommandAction(editor.getProject(), () -> { + + ScrollingModel scrollingModel = editor.getScrollingModel(); + + //disable so sprites render at correct spot and arent slowed down by visual scroll + scrollingModel.disableAnimation(); + + int beforePasteOffset; + try { + beforePasteOffset = scrollingModel.getVerticalScrollOffset(); + } catch(UnsupportedOperationException e){ + LOGGER.debug("paste unsupported, exiting early"); + //if we are pasting into a search box via ctrl+f, etc.. (not a real editor), + // e.g. com.intellij.openapi.editor.textarea.TextComponentScrollingModel + // don't draw to GUI, just paste and exit + EditorCopyPasteHelper.getInstance().pasteFromClipboard(editor); + return; } - prevPoint = point; - - } - - poPoints[curLine][1] = point; + TextRange[] pasted = EditorCopyPasteHelper.getInstance().pasteFromClipboard(editor); + if(pasted.length != 1) return; //ensure we have a single TextRange to work with + TextRange t = pasted[0]; + + //TODO: figure out how to calculate each pasted character x,y coord without incrementing caret + //Disable CaretListener for the following... + MyCaretListener.enabled = false; + + int afterPasteOffset = scrollingModel.getVerticalScrollOffset(); + scrollingModel.enableAnimation(); + + int lineHeight = editor.getLineHeight(); + int start = t.getStartOffset(); + int offset = t.getLength(); //offset is # of characters typed + + //paste outline points, + //to show where each line starts and ends with 2 points + // max size possible for line numbers is offset + // ex: paste offset 5, but contents is 5 characters w/ newlines + Point[][] poPoints = new Point[offset][2]; + + Caret curCaret = editor.getCaretModel().getCurrentCaret(); + Point prevPoint = null; + Point point = null; + int curLine = 0; + + for(int i = start; i <= start + offset; i++){ + curCaret.moveToOffset(i); + VisualPosition visualPosition = curCaret.getVisualPosition(); + point = editor.visualPositionToXY(visualPosition); + point.x = point.x - scrollingModel.getHorizontalScrollOffset(); + point.y = point.y - afterPasteOffset; + + if(prevPoint == null){ //only happens once + poPoints[0][0] = point; + }else{ + if(prevPoint.y == point.y){ //on same line, dont add anything + //continue + }else {//we've moved to a new line, + // so add prevPoint as END of last line, + poPoints[curLine][1] = prevPoint; + curLine += 1; + //add new line boundary + poPoints[curLine][0] = point; + } + } + prevPoint = point; + } - //Now, with poPoints containing outline for every caret spot in blob - //flesh out the pasteShape - Path2D pasteShape = new Path2D.Double(); + poPoints[curLine][1] = point; + + //Now, with poPoints containing outline for every caret spot in blob + //flesh out the pasteShape + Path2D pasteShape = new Path2D.Double(); + + for(int i = 0; i <= curLine; i++) { + if (i == 0) { //immediately go to right side + pasteShape.moveTo(poPoints[i][0].x, poPoints[i][0].y); + pasteShape.lineTo(poPoints[i][1].x, poPoints[i][1].y); + } else { //work way down to bottom + //move down + pasteShape.lineTo(poPoints[i-1][1].x, poPoints[i-1][1].y+lineHeight); + //move either left/right to meet next line point + pasteShape.lineTo(poPoints[i][1].x, poPoints[i][1].y); + } + } + //wrap around + pasteShape.lineTo(poPoints[curLine][1].x, poPoints[curLine][1].y + lineHeight); + pasteShape.lineTo(poPoints[curLine][0].x, poPoints[curLine][0].y + lineHeight); - for(int i = 0; i <= curLine; i++) { - if (i == 0) { //immediately go to right side - pasteShape.moveTo(poPoints[i][0].x, poPoints[i][0].y); - pasteShape.lineTo(poPoints[i][1].x, poPoints[i][1].y); - } else { //work way down to bottom - //move down - pasteShape.lineTo(poPoints[i-1][1].x, poPoints[i-1][1].y+lineHeight); - //move either left/right to meet next line point - pasteShape.lineTo(poPoints[i][1].x, poPoints[i][1].y); + //work way back up + for(int i = curLine; i > 0; i--) { + pasteShape.lineTo(poPoints[i][0].x, poPoints[i][0].y); + } + pasteShape.lineTo(poPoints[0][0].x, poPoints[0][0].y+lineHeight); + pasteShape.lineTo(poPoints[0][0].x, poPoints[0][0].y); + + int winningIndex = SpriteDataAnimated.getWeightedAmountWinningIndex(ParticleSpritePasteShape.spriteDataAnimated); + if(winningIndex == -1 && !CopyPasteVoidConfig.FADE_ENABLED(settings)){ + //do nothing + }else { + ParticleSpritePasteShape pFontShape = new ParticleSpritePasteShape(pasteShape, 100, + CopyPasteVoidConfig.FADE_COLOR(settings), + CopyPasteVoidConfig.FADE_AMOUNT(settings), + CopyPasteVoidConfig.FADE_ENABLED(settings), + winningIndex, + editor); + ParticleContainerManager.particleContainers.get(editor).addExternalParticle(pFontShape); } - } - //wrap around - pasteShape.lineTo(poPoints[curLine][1].x, poPoints[curLine][1].y + lineHeight); - pasteShape.lineTo(poPoints[curLine][0].x, poPoints[curLine][0].y + lineHeight); - - //work way back up - for(int i = curLine; i > 0; i--) { - pasteShape.lineTo(poPoints[i][0].x, poPoints[i][0].y); - } - pasteShape.lineTo(poPoints[0][0].x, poPoints[0][0].y+lineHeight); - pasteShape.lineTo(poPoints[0][0].x, poPoints[0][0].y); - - - int winningIndex = SpriteDataAnimated.getWeightedAmountWinningIndex(ParticleSpritePasteShape.spriteDataAnimated); - if(winningIndex == -1 && !CopyPasteVoidConfig.FADE_ENABLED(settings)){ - //do nothing - }else { - ParticleSpritePasteShape pFontShape = new ParticleSpritePasteShape(pasteShape, 100, - CopyPasteVoidConfig.FADE_COLOR(settings), - CopyPasteVoidConfig.FADE_AMOUNT(settings), - CopyPasteVoidConfig.FADE_ENABLED(settings), - winningIndex, - editor); - ParticleContainerManager.particleContainers.get(editor).addExternalParticle(pFontShape); - } - - - MyCaretListener.enabled = true; - curCaret.moveToOffset(start+offset); - scrollingModel.scrollToCaret(ScrollType.MAKE_VISIBLE); + MyCaretListener.enabled = true; + curCaret.moveToOffset(start+offset); + scrollingModel.scrollToCaret(ScrollType.MAKE_VISIBLE); + }); } }; diff --git a/src/main/java/com/cschar/pmode3/listeners/MyCaretListener.java b/src/main/java/com/cschar/pmode3/listeners/MyCaretListener.java index 43481e4..5b2b523 100644 --- a/src/main/java/com/cschar/pmode3/listeners/MyCaretListener.java +++ b/src/main/java/com/cschar/pmode3/listeners/MyCaretListener.java @@ -4,6 +4,7 @@ import com.cschar.pmode3.config.LanternConfig; import com.cschar.pmode3.config.LinkerConfig; import com.cschar.pmode3.config.MultiLayerConfig; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.ScrollingModel; @@ -29,47 +30,48 @@ public void caretPositionChanged(@NotNull CaretEvent event) { if(enabled && pluginInitialized) { - Editor editor = event.getEditor(); - VisualPosition visualPosition = event.getCaret().getVisualPosition(); - Point point = editor.visualPositionToXY(visualPosition); - ScrollingModel scrollingModel = editor.getScrollingModel(); - point.x = point.x - scrollingModel.getHorizontalScrollOffset(); - point.y = point.y - scrollingModel.getVerticalScrollOffset(); + ApplicationManager.getApplication().runReadAction(() -> { + Editor editor = event.getEditor(); + VisualPosition visualPosition = event.getCaret().getVisualPosition(); + Point point = editor.visualPositionToXY(visualPosition); + ScrollingModel scrollingModel = editor.getScrollingModel(); + point.x = point.x - scrollingModel.getHorizontalScrollOffset(); + point.y = point.y - scrollingModel.getVerticalScrollOffset(); + ParticleSpriteDroste.cursorX = point.x; + ParticleSpriteDroste.cursorY = point.y; - ParticleSpriteDroste.cursorX = point.x; - ParticleSpriteDroste.cursorY = point.y; + PowerMode3 settings = PowerMode3.getInstance(); + if (settings.getSpriteTypeEnabled(PowerMode3.ConfigType.MULTI_LAYER) && + MultiLayerConfig.MOVE_WITH_CARET(settings)) { - PowerMode3 settings = PowerMode3.getInstance(); - if(settings.getSpriteTypeEnabled(PowerMode3.ConfigType.MULTI_LAYER) && - MultiLayerConfig.MOVE_WITH_CARET(settings)){ + ParticleSpriteMultiLayer.targetX = point.x; + ParticleSpriteMultiLayer.targetY = point.y; + ParticleSpriteMultiLayer.moveSpeed = MultiLayerConfig.CARET_MOVE_SPEED(settings); - ParticleSpriteMultiLayer.targetX = point.x; - ParticleSpriteMultiLayer.targetY = point.y; - ParticleSpriteMultiLayer.moveSpeed = MultiLayerConfig.CARET_MOVE_SPEED(settings); + } - } - - if(settings.getSpriteTypeEnabled(PowerMode3.ConfigType.LINKER) && - LinkerConfig.MOVE_WITH_CARET(settings)){ + if (settings.getSpriteTypeEnabled(PowerMode3.ConfigType.LINKER) && + LinkerConfig.MOVE_WITH_CARET(settings)) { // ParticleSpriteLinkerAnchor.cursorX = point.x; // ParticleSpriteLinkerAnchor.cursorY = point.y; - ParticleSpriteLinkerAnchor.targetX = point.x; - ParticleSpriteLinkerAnchor.targetY = point.y; - ParticleSpriteLinkerAnchor.moveSpeed = LinkerConfig.CARET_MOVE_SPEED(settings); + ParticleSpriteLinkerAnchor.targetX = point.x; + ParticleSpriteLinkerAnchor.targetY = point.y; + ParticleSpriteLinkerAnchor.moveSpeed = LinkerConfig.CARET_MOVE_SPEED(settings); - } + } - if(settings.getSpriteTypeEnabled(PowerMode3.ConfigType.LANTERN) && - LanternConfig.MOVE_WITH_CARET(settings)){ + if (settings.getSpriteTypeEnabled(PowerMode3.ConfigType.LANTERN) && + LanternConfig.MOVE_WITH_CARET(settings)) { - ParticleSpriteLantern.targetX = point.x; - ParticleSpriteLantern.targetY = point.y; + ParticleSpriteLantern.targetX = point.x; + ParticleSpriteLantern.targetY = point.y; // ParticleSpriteLantern.typeX = point.x; // ParticleSpriteLantern.typeY = point.y; - } + } + }); } } From 0b6b99c157672acaad1c8af09e836a1adfb53c78 Mon Sep 17 00:00:00 2001 From: cschar Date: Sun, 10 Aug 2025 14:41:51 -0400 Subject: [PATCH 2/2] update to new 3.4.2 version in properties file --- gradle.properties | 3 ++- justfile | 9 ++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/gradle.properties b/gradle.properties index fd34603..5c90c5d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -12,7 +12,8 @@ pluginRepositoryUrl = https://github.com/cschar/power-mode-zeranthium #pluginVersion = 1.14.0 #pluginVersion = 3.4.0-eap.242 #pluginVersion = 3.4.1-stable.251 -pluginVersion = 3.4.1-stable.243 +#pluginVersion = 3.4.1-stable.243 +pluginVersion = 3.4.2-stable.243 # Supported build number ranges and IntelliJ Platform versions -> https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html # when running ./gradlew :verifyPlugin, will start at below VERSION_NUM and check all going forward diff --git a/justfile b/justfile index 5750484..bd18fc9 100644 --- a/justfile +++ b/justfile @@ -10,4 +10,11 @@ test_ui_launch_ide: ./gradlew :testIdeUi test_ui_run_tests: - TEST_TYPE=UI ./gradlew :test --tests com.cschar.pmode3.uitest.OpenSettingsJavaTest \ No newline at end of file + TEST_TYPE=UI ./gradlew :test --tests com.cschar.pmode3.uitest.OpenSettingsJavaTest + +gradle_check_cache: + dust ~/.gradle + +gradle_clean_cache: + rm -rf ~/.gradle/caches/transforms/ + # rm -rf ~/.gradle/caches