diff --git a/java/testFramework/src/com/intellij/codeInsight/JavaCodeInsightTestCase.java b/java/testFramework/src/com/intellij/codeInsight/JavaCodeInsightTestCase.java index ff20947bf228..1e429bfc326f 100644 --- a/java/testFramework/src/com/intellij/codeInsight/JavaCodeInsightTestCase.java +++ b/java/testFramework/src/com/intellij/codeInsight/JavaCodeInsightTestCase.java @@ -38,6 +38,7 @@ import com.intellij.psi.impl.source.PostprocessReformattingAspect; import com.intellij.psi.impl.source.tree.injected.InjectedLanguageEditorUtil; import com.intellij.psi.search.ProjectScope; import com.intellij.testFramework.*; +import com.intellij.testFramework.common.EditorCaretTestUtil; import com.intellij.testFramework.fixtures.impl.CodeInsightTestFixtureImpl; import com.intellij.util.ArrayUtil; import com.intellij.util.containers.ContainerUtil; @@ -387,7 +388,7 @@ public abstract class JavaCodeInsightTestCase extends JavaPsiTestCase { expectedText = StringUtil.convertLineSeparators(expectedText); Document document = EditorFactory.getInstance().createDocument(expectedText); - EditorTestUtil.CaretAndSelectionState caretState = EditorTestUtil.extractCaretAndSelectionMarkers(document); + EditorCaretTestUtil.CaretAndSelectionState caretState = EditorTestUtil.extractCaretAndSelectionMarkers(document); expectedText = document.getText(); if (stripTrailingSpaces) { diff --git a/platform/lang-impl/testSources/com/intellij/execution/console/ConsoleHistoryControllerTest.java b/platform/lang-impl/testSources/com/intellij/execution/console/ConsoleHistoryControllerTest.java index 5b85fa5aee9c..d093291db7f4 100644 --- a/platform/lang-impl/testSources/com/intellij/execution/console/ConsoleHistoryControllerTest.java +++ b/platform/lang-impl/testSources/com/intellij/execution/console/ConsoleHistoryControllerTest.java @@ -24,6 +24,7 @@ import com.intellij.psi.PsiDocumentManager; import com.intellij.testFramework.EditorTestUtil; import com.intellij.testFramework.LightPlatformCodeInsightTestCase; import com.intellij.testFramework.TestActionEvent; +import com.intellij.testFramework.common.EditorCaretTestUtil; /** @@ -54,7 +55,7 @@ public class ConsoleHistoryControllerTest extends LightPlatformCodeInsightTestCa private void setCaretWithText(String markedText) { myConsole.setInputText(markedText); - EditorTestUtil.CaretAndSelectionState state = EditorTestUtil.extractCaretAndSelectionMarkers(myConsole.getEditorDocument()); + EditorCaretTestUtil.CaretAndSelectionState state = EditorTestUtil.extractCaretAndSelectionMarkers(myConsole.getEditorDocument()); EditorTestUtil.setCaretsAndSelection(myConsole.getConsoleEditor(), state); PsiDocumentManager.getInstance(getProject()).commitAllDocuments(); } diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/editor/EditorMultiCaretStateRestoreTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/editor/EditorMultiCaretStateRestoreTest.java index d54a7960a2ab..1a48ba4c402e 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/editor/EditorMultiCaretStateRestoreTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/editor/EditorMultiCaretStateRestoreTest.java @@ -10,6 +10,7 @@ import com.intellij.openapi.fileTypes.PlainTextFileType; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiFile; import com.intellij.testFramework.EditorTestUtil; +import com.intellij.testFramework.common.EditorCaretTestUtil; public class EditorMultiCaretStateRestoreTest extends HeavyFileEditorManagerTestCase { public void testRestoreState() { @@ -38,7 +39,7 @@ public class EditorMultiCaretStateRestoreTest extends HeavyFileEditorManagerTest private static void verifyEditorState(Editor editor, String textWithMarkup) { final Document document = new DocumentImpl(textWithMarkup); - EditorTestUtil.CaretAndSelectionState caretAndSelectionState = EditorTestUtil.extractCaretAndSelectionMarkers(document); + EditorCaretTestUtil.CaretAndSelectionState caretAndSelectionState = EditorTestUtil.extractCaretAndSelectionMarkers(document); assertEquals(document.getCharsSequence().toString(), editor.getDocument().getText()); EditorTestUtil.verifyCaretAndSelectionState(editor, caretAndSelectionState); } diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/TrailingSpacesStripperTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/TrailingSpacesStripperTest.java index a29b229edb01..6f4a2063fe30 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/TrailingSpacesStripperTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/TrailingSpacesStripperTest.java @@ -12,6 +12,7 @@ import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.testFramework.EditorTestUtil; import com.intellij.testFramework.LightPlatformCodeInsightTestCase; +import com.intellij.testFramework.common.EditorCaretTestUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -242,7 +243,7 @@ public class TrailingSpacesStripperTest extends LightPlatformCodeInsightTestCase final Document document = manager.getDocument(myVFile); manager.reloadFromDisk(document); Editor editor = createEditor(myVFile); - EditorTestUtil.CaretAndSelectionState caretsState = EditorTestUtil.extractCaretAndSelectionMarkers(document); + EditorCaretTestUtil.CaretAndSelectionState caretsState = EditorTestUtil.extractCaretAndSelectionMarkers(document); EditorTestUtil.setCaretsAndSelection(editor, caretsState); return editor; } diff --git a/platform/testFramework/common/src/common/EditorCaretTestUtil.java b/platform/testFramework/common/src/common/EditorCaretTestUtil.java new file mode 100644 index 000000000000..3a5e28a644d3 --- /dev/null +++ b/platform/testFramework/common/src/common/EditorCaretTestUtil.java @@ -0,0 +1,170 @@ +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.intellij.testFramework.common; + +import com.intellij.openapi.command.WriteCommandAction; +import com.intellij.openapi.editor.*; +import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.util.text.StringUtil; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.TestOnly; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +@TestOnly +@ApiStatus.Internal +public final class EditorCaretTestUtil { + public static final String CARET_TAG = ""; + public static final String CARET_TAG_PREFIX = CARET_TAG.substring(0, CARET_TAG.length() - 1); + + public static final String SELECTION_START_TAG = ""; + public static final String SELECTION_END_TAG = ""; + public static final String BLOCK_SELECTION_START_TAG = ""; + public static final String BLOCK_SELECTION_END_TAG = ""; + + public static class CaretInfo { + public final @Nullable LogicalPosition position; // column number in this position is calculated in terms of characters, + // not in terms of visual position + // so Tab character always increases the column number by 1 + public final @Nullable TextRange selection; + + public CaretInfo(@Nullable LogicalPosition position, @Nullable TextRange selection) { + this.position = position; + this.selection = selection; + } + + public int getCaretOffset(Document document) { + return position == null ? -1 : document.getLineStartOffset(position.line) + position.column; + } + } + + public record CaretAndSelectionState(List carets, @Nullable TextRange blockSelection) { + + /** + * Returns true if current CaretAndSelectionState contains at least one caret or selection explicitly specified + */ + public boolean hasExplicitCaret() { + if(carets.isEmpty()) return false; + if(blockSelection == null && carets.size() == 1) { + CaretInfo caret = carets.get(0); + return caret.position != null || caret.selection != null; + } + return true; + } + } + + + public static @NotNull CaretAndSelectionState extractCaretAndSelectionMarkers(@NotNull Document document) { + return extractCaretAndSelectionMarkers(document, true); + } + + public static @NotNull CaretAndSelectionState extractCaretAndSelectionMarkers(@NotNull Document document, final boolean processBlockSelection) { + return WriteCommandAction.writeCommandAction(null).compute(() -> extractCaretAndSelectionMarkersImpl(document, processBlockSelection)); + } + public static @NotNull CaretAndSelectionState extractCaretAndSelectionMarkersImpl(@NotNull Document document, boolean processBlockSelection) { + List carets = new ArrayList<>(); + String fileText = document.getText(); + + RangeMarker blockSelectionStartMarker = null; + RangeMarker blockSelectionEndMarker = null; + if (processBlockSelection) { + int blockSelectionStart = fileText.indexOf(BLOCK_SELECTION_START_TAG); + int blockSelectionEnd = fileText.indexOf(BLOCK_SELECTION_END_TAG); + if ((blockSelectionStart ^ blockSelectionEnd) < 0) { + throw new IllegalArgumentException("Both block selection opening and closing tag must be present"); + } + if (blockSelectionStart >= 0) { + blockSelectionStartMarker = document.createRangeMarker(blockSelectionStart, blockSelectionStart); + blockSelectionEndMarker = document.createRangeMarker(blockSelectionEnd, blockSelectionEnd); + document.deleteString(blockSelectionStartMarker.getStartOffset(), blockSelectionStartMarker.getStartOffset() + BLOCK_SELECTION_START_TAG.length()); + document.deleteString(blockSelectionEndMarker.getStartOffset(), blockSelectionEndMarker.getStartOffset() + BLOCK_SELECTION_END_TAG.length()); + } + } + + boolean multiCaret = StringUtil.getOccurrenceCount(document.getText(), CARET_TAG) > 1 + || StringUtil.getOccurrenceCount(document.getText(), SELECTION_START_TAG) > 1; + int pos = 0; + while (pos < document.getTextLength()) { + fileText = document.getText(); + int caretIndex = fileText.indexOf(CARET_TAG, pos); + int selStartIndex = fileText.indexOf(SELECTION_START_TAG, pos); + int selEndIndex = fileText.indexOf(SELECTION_END_TAG, pos); + + if ((selStartIndex ^ selEndIndex) < 0) { + selStartIndex = -1; + selEndIndex = -1; + } + if (0 <= selEndIndex && selEndIndex < selStartIndex) { + throw new IllegalArgumentException("Wrong order of selection opening and closing tags"); + } + if (caretIndex < 0 && selStartIndex < 0 && selEndIndex < 0) { + break; + } + if (multiCaret && 0 <= caretIndex && caretIndex < selStartIndex) { + selStartIndex = -1; + selEndIndex = -1; + } + if (multiCaret && caretIndex > selEndIndex && selEndIndex >= 0) { + caretIndex = -1; + } + + final RangeMarker caretMarker = caretIndex >= 0 ? document.createRangeMarker(caretIndex, caretIndex) : null; + final RangeMarker selStartMarker = selStartIndex >= 0 + ? document.createRangeMarker(selStartIndex, selStartIndex) + : null; + final RangeMarker selEndMarker = selEndIndex >= 0 + ? document.createRangeMarker(selEndIndex, selEndIndex) + : null; + + if (caretMarker != null) { + document.deleteString(caretMarker.getStartOffset(), caretMarker.getStartOffset() + CARET_TAG.length()); + } + if (selStartMarker != null) { + document.deleteString(selStartMarker.getStartOffset(), + selStartMarker.getStartOffset() + SELECTION_START_TAG.length()); + } + if (selEndMarker != null) { + document.deleteString(selEndMarker.getStartOffset(), + selEndMarker.getStartOffset() + SELECTION_END_TAG.length()); + } + LogicalPosition caretPosition = null; + if (caretMarker != null) { + int line = document.getLineNumber(caretMarker.getStartOffset()); + int column = caretMarker.getStartOffset() - document.getLineStartOffset(line); + caretPosition = new LogicalPosition(line, column); + } + carets.add(new CaretInfo(caretPosition, + selStartMarker == null || selEndMarker == null + ? null + : new TextRange(selStartMarker.getStartOffset(), selEndMarker.getEndOffset()))); + + pos = Math.max(caretMarker == null ? -1 : caretMarker.getStartOffset(), selEndMarker == null ? -1 : selEndMarker.getEndOffset()); + } + if (carets.isEmpty()) { + carets.add(new CaretInfo(null, null)); + } + TextRange blockSelection = null; + if (blockSelectionStartMarker != null) { + blockSelection = new TextRange(blockSelectionStartMarker.getStartOffset(), blockSelectionEndMarker.getStartOffset()); + } + return new CaretAndSelectionState(Arrays.asList(carets.toArray(new CaretInfo[0])), blockSelection); + } + + public static void setCaretsAndSelection(Editor editor, CaretAndSelectionState caretsState) { + CaretModel caretModel = editor.getCaretModel(); + List states = new ArrayList<>(caretsState.carets().size()); + for (CaretInfo caret : caretsState.carets()) { + states.add(new CaretState(caret.position == null ? null : editor.offsetToLogicalPosition(caret.getCaretOffset(editor.getDocument())), + caret.selection == null ? null : editor.offsetToLogicalPosition(caret.selection.getStartOffset()), + caret.selection == null ? null : editor.offsetToLogicalPosition(caret.selection.getEndOffset()))); + } + caretModel.setCaretsAndSelections(states); + if (caretsState.blockSelection() != null) { + editor.getSelectionModel().setBlockSelection(editor.offsetToLogicalPosition(caretsState.blockSelection().getStartOffset()), + editor.offsetToLogicalPosition(caretsState.blockSelection().getEndOffset())); + } + } +} diff --git a/platform/testFramework/src/com/intellij/codeInsight/EditorInfo.java b/platform/testFramework/src/com/intellij/codeInsight/EditorInfo.java index 0dda30f00a33..8826dd62b1e6 100644 --- a/platform/testFramework/src/com/intellij/codeInsight/EditorInfo.java +++ b/platform/testFramework/src/com/intellij/codeInsight/EditorInfo.java @@ -19,10 +19,11 @@ import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.EditorFactory; import com.intellij.testFramework.EditorTestUtil; +import com.intellij.testFramework.common.EditorCaretTestUtil; public class EditorInfo { private final String newFileText; - public EditorTestUtil.CaretAndSelectionState caretState; + public EditorCaretTestUtil.CaretAndSelectionState caretState; public EditorInfo(final String fileText) { Document document = EditorFactory.getInstance().createDocument(fileText); diff --git a/platform/testFramework/src/com/intellij/testFramework/EditorTestUtil.java b/platform/testFramework/src/com/intellij/testFramework/EditorTestUtil.java index 7c614bfa602b..680a72cb23ed 100644 --- a/platform/testFramework/src/com/intellij/testFramework/EditorTestUtil.java +++ b/platform/testFramework/src/com/intellij/testFramework/EditorTestUtil.java @@ -5,7 +5,6 @@ import com.intellij.codeInsight.daemon.impl.HighlightInfo; import com.intellij.codeInsight.daemon.impl.IdentifierHighlighterPassFactory; import com.intellij.codeInsight.folding.CodeFoldingManager; import com.intellij.ide.DataManager; -import com.intellij.injected.editor.EditorWindow; import com.intellij.lang.Language; import com.intellij.lang.folding.FoldingBuilder; import com.intellij.lang.folding.LanguageFolding; @@ -46,6 +45,9 @@ import com.intellij.openapi.util.*; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.encoding.EncodingManager; import com.intellij.openapi.vfs.encoding.EncodingProjectManager; +import com.intellij.testFramework.common.EditorCaretTestUtil; +import com.intellij.testFramework.common.EditorCaretTestUtil.CaretInfo; +import com.intellij.testFramework.common.EditorCaretTestUtil.CaretAndSelectionState; import com.intellij.platform.testFramework.core.FileComparisonFailedError; import com.intellij.psi.FileViewProvider; import com.intellij.psi.PsiDocumentManager; @@ -80,13 +82,13 @@ import static org.junit.Assert.*; * @author Maxim.Mossienko */ public final class EditorTestUtil { - public static final String CARET_TAG = ""; - public static final String CARET_TAG_PREFIX = CARET_TAG.substring(0, CARET_TAG.length() - 1); + public static final String CARET_TAG = EditorCaretTestUtil.CARET_TAG; + public static final String CARET_TAG_PREFIX = EditorCaretTestUtil.CARET_TAG_PREFIX; - public static final String SELECTION_START_TAG = ""; - public static final String SELECTION_END_TAG = ""; - public static final String BLOCK_SELECTION_START_TAG = ""; - public static final String BLOCK_SELECTION_END_TAG = ""; + public static final String SELECTION_START_TAG = EditorCaretTestUtil.SELECTION_START_TAG; + public static final String SELECTION_END_TAG = EditorCaretTestUtil.SELECTION_END_TAG; + public static final String BLOCK_SELECTION_START_TAG = EditorCaretTestUtil.BLOCK_SELECTION_START_TAG; + public static final String BLOCK_SELECTION_END_TAG = EditorCaretTestUtil.BLOCK_SELECTION_END_TAG; public static final char BACKSPACE_FAKE_CHAR = '\uFFFF'; public static final char SMART_ENTER_FAKE_CHAR = '\uFFFE'; @@ -361,7 +363,7 @@ public final class EditorTestUtil { * @see #extractCaretAndSelectionMarkers(Document, boolean) */ public static @NotNull CaretAndSelectionState extractCaretAndSelectionMarkers(@NotNull Document document) { - return extractCaretAndSelectionMarkers(document, true); + return EditorCaretTestUtil.extractCaretAndSelectionMarkers(document, true); } /** @@ -371,114 +373,18 @@ public final class EditorTestUtil { * @param processBlockSelection if {@code true}, <block> and </block> tags describing a block selection state will also be extracted. */ public static @NotNull CaretAndSelectionState extractCaretAndSelectionMarkers(@NotNull Document document, final boolean processBlockSelection) { - return WriteCommandAction.writeCommandAction(null).compute(() -> extractCaretAndSelectionMarkersImpl(document, processBlockSelection)); + return EditorCaretTestUtil.extractCaretAndSelectionMarkers(document, processBlockSelection); } public static @NotNull CaretAndSelectionState extractCaretAndSelectionMarkersImpl(@NotNull Document document, boolean processBlockSelection) { - List carets = new ArrayList<>(); - String fileText = document.getText(); - - RangeMarker blockSelectionStartMarker = null; - RangeMarker blockSelectionEndMarker = null; - if (processBlockSelection) { - int blockSelectionStart = fileText.indexOf(BLOCK_SELECTION_START_TAG); - int blockSelectionEnd = fileText.indexOf(BLOCK_SELECTION_END_TAG); - if ((blockSelectionStart ^ blockSelectionEnd) < 0) { - throw new IllegalArgumentException("Both block selection opening and closing tag must be present"); - } - if (blockSelectionStart >= 0) { - blockSelectionStartMarker = document.createRangeMarker(blockSelectionStart, blockSelectionStart); - blockSelectionEndMarker = document.createRangeMarker(blockSelectionEnd, blockSelectionEnd); - document.deleteString(blockSelectionStartMarker.getStartOffset(), blockSelectionStartMarker.getStartOffset() + BLOCK_SELECTION_START_TAG.length()); - document.deleteString(blockSelectionEndMarker.getStartOffset(), blockSelectionEndMarker.getStartOffset() + BLOCK_SELECTION_END_TAG.length()); - } - } - - boolean multiCaret = StringUtil.getOccurrenceCount(document.getText(), CARET_TAG) > 1 - || StringUtil.getOccurrenceCount(document.getText(), SELECTION_START_TAG) > 1; - int pos = 0; - while (pos < document.getTextLength()) { - fileText = document.getText(); - int caretIndex = fileText.indexOf(CARET_TAG, pos); - int selStartIndex = fileText.indexOf(SELECTION_START_TAG, pos); - int selEndIndex = fileText.indexOf(SELECTION_END_TAG, pos); - - if ((selStartIndex ^ selEndIndex) < 0) { - selStartIndex = -1; - selEndIndex = -1; - } - if (0 <= selEndIndex && selEndIndex < selStartIndex) { - throw new IllegalArgumentException("Wrong order of selection opening and closing tags"); - } - if (caretIndex < 0 && selStartIndex < 0 && selEndIndex < 0) { - break; - } - if (multiCaret && 0 <= caretIndex && caretIndex < selStartIndex) { - selStartIndex = -1; - selEndIndex = -1; - } - if (multiCaret && caretIndex > selEndIndex && selEndIndex >= 0) { - caretIndex = -1; - } - - final RangeMarker caretMarker = caretIndex >= 0 ? document.createRangeMarker(caretIndex, caretIndex) : null; - final RangeMarker selStartMarker = selStartIndex >= 0 - ? document.createRangeMarker(selStartIndex, selStartIndex) - : null; - final RangeMarker selEndMarker = selEndIndex >= 0 - ? document.createRangeMarker(selEndIndex, selEndIndex) - : null; - - if (caretMarker != null) { - document.deleteString(caretMarker.getStartOffset(), caretMarker.getStartOffset() + CARET_TAG.length()); - } - if (selStartMarker != null) { - document.deleteString(selStartMarker.getStartOffset(), - selStartMarker.getStartOffset() + SELECTION_START_TAG.length()); - } - if (selEndMarker != null) { - document.deleteString(selEndMarker.getStartOffset(), - selEndMarker.getStartOffset() + SELECTION_END_TAG.length()); - } - LogicalPosition caretPosition = null; - if (caretMarker != null) { - int line = document.getLineNumber(caretMarker.getStartOffset()); - int column = caretMarker.getStartOffset() - document.getLineStartOffset(line); - caretPosition = new LogicalPosition(line, column); - } - carets.add(new CaretInfo(caretPosition, - selStartMarker == null || selEndMarker == null - ? null - : new TextRange(selStartMarker.getStartOffset(), selEndMarker.getEndOffset()))); - - pos = Math.max(caretMarker == null ? -1 : caretMarker.getStartOffset(), selEndMarker == null ? -1 : selEndMarker.getEndOffset()); - } - if (carets.isEmpty()) { - carets.add(new CaretInfo(null, null)); - } - TextRange blockSelection = null; - if (blockSelectionStartMarker != null) { - blockSelection = new TextRange(blockSelectionStartMarker.getStartOffset(), blockSelectionEndMarker.getStartOffset()); - } - return new CaretAndSelectionState(Arrays.asList(carets.toArray(new CaretInfo[0])), blockSelection); + return EditorCaretTestUtil.extractCaretAndSelectionMarkersImpl(document, processBlockSelection); } /** * Applies given caret/selection state to the editor. Editor text must have been set up previously. */ public static void setCaretsAndSelection(Editor editor, CaretAndSelectionState caretsState) { - CaretModel caretModel = editor.getCaretModel(); - List states = new ArrayList<>(caretsState.carets.size()); - for (CaretInfo caret : caretsState.carets) { - states.add(new CaretState(caret.position == null ? null : editor.offsetToLogicalPosition(caret.getCaretOffset(editor.getDocument())), - caret.selection == null ? null : editor.offsetToLogicalPosition(caret.selection.getStartOffset()), - caret.selection == null ? null : editor.offsetToLogicalPosition(caret.selection.getEndOffset()))); - } - caretModel.setCaretsAndSelections(states); - if (caretsState.blockSelection != null) { - editor.getSelectionModel().setBlockSelection(editor.offsetToLogicalPosition(caretsState.blockSelection.getStartOffset()), - editor.offsetToLogicalPosition(caretsState.blockSelection.getEndOffset())); - } + EditorCaretTestUtil.setCaretsAndSelection(editor, caretsState); } public static void verifyCaretAndSelectionState(Editor editor, CaretAndSelectionState caretState) { @@ -491,8 +397,8 @@ public final class EditorTestUtil { public static void verifyCaretAndSelectionState(Editor editor, CaretAndSelectionState caretState, String message, String expectedFilePath) { boolean hasChecks = false; - for (int i = 0; i < caretState.carets.size(); i++) { - EditorTestUtil.CaretInfo expected = caretState.carets.get(i); + for (int i = 0; i < caretState.carets().size(); i++) { + CaretInfo expected = caretState.carets().get(i); if (expected.position != null || expected.selection != null) { hasChecks = true; break; @@ -507,7 +413,7 @@ public final class EditorTestUtil { } catch (AssertionError e) { try { - String expected = CaretAndSelectionMarkup.renderExpectedState(editor, caretState.carets); + String expected = CaretAndSelectionMarkup.renderExpectedState(editor, caretState.carets()); String actual = CaretAndSelectionMarkup.renderActualState(editor); if (expectedFilePath != null) { if (!expected.equals(actual)) { @@ -529,9 +435,9 @@ public final class EditorTestUtil { String messageSuffix = message == null ? "" : (message + ": "); CaretModel caretModel = editor.getCaretModel(); List allCarets = new ArrayList<>(caretModel.getAllCarets()); - assertEquals(messageSuffix + " Unexpected number of carets", caretState.carets.size(), allCarets.size()); - for (int i = 0; i < caretState.carets.size(); i++) { - String caretDescription = caretState.carets.size() == 1 ? "" : "caret " + (i + 1) + "/" + caretState.carets.size() + " "; + assertEquals(messageSuffix + " Unexpected number of carets", caretState.carets().size(), allCarets.size()); + for (int i = 0; i < caretState.carets().size(); i++) { + String caretDescription = caretState.carets().size() == 1 ? "" : "caret " + (i + 1) + "/" + caretState.carets().size() + " "; Caret currentCaret = allCarets.get(i); int actualCaretLine = editor.getDocument().getLineNumber(currentCaret.getOffset()); int actualCaretColumn = currentCaret.getOffset() - editor.getDocument().getLineStartOffset(actualCaretLine); @@ -540,7 +446,7 @@ public final class EditorTestUtil { int selectionEnd = currentCaret.getSelectionEnd(); LogicalPosition actualSelectionStart = editor.offsetToLogicalPosition(selectionStart); LogicalPosition actualSelectionEnd = editor.offsetToLogicalPosition(selectionEnd); - CaretInfo expected = caretState.carets.get(i); + CaretInfo expected = caretState.carets().get(i); if (expected.position != null) { assertEquals(messageSuffix + caretDescription + "unexpected caret position", expected.position, actualCaretPosition); } @@ -887,38 +793,6 @@ public final class EditorTestUtil { return sb.append(documentSequence.subSequence(lastEnd, documentSequence.length())).toString(); } - - public record CaretAndSelectionState(List carets, @Nullable TextRange blockSelection) { - - /** - * Returns true if current CaretAndSelectionState contains at least one caret or selection explicitly specified - */ - public boolean hasExplicitCaret() { - if(carets.isEmpty()) return false; - if(blockSelection == null && carets.size() == 1) { - CaretInfo caret = carets.get(0); - return caret.position != null || caret.selection != null; - } - return true; - } - } - - public static class CaretInfo { - public final @Nullable LogicalPosition position; // column number in this position is calculated in terms of characters, - // not in terms of visual position - // so Tab character always increases the column number by 1 - public final @Nullable TextRange selection; - - public CaretInfo(@Nullable LogicalPosition position, @Nullable TextRange selection) { - this.position = position; - this.selection = selection; - } - - public int getCaretOffset(Document document) { - return position == null ? -1 : document.getLineStartOffset(position.line) + position.column; - } - } - private static final class EmptyInlayRenderer implements EditorCustomElementRenderer { private final int width; private final Integer height; diff --git a/platform/testFramework/src/com/intellij/testFramework/LightPlatformCodeInsightTestCase.java b/platform/testFramework/src/com/intellij/testFramework/LightPlatformCodeInsightTestCase.java index 0d496c7a796e..a529769e9353 100644 --- a/platform/testFramework/src/com/intellij/testFramework/LightPlatformCodeInsightTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/LightPlatformCodeInsightTestCase.java @@ -43,6 +43,7 @@ import com.intellij.psi.PsiFile; import com.intellij.psi.impl.source.PostprocessReformattingAspect; import com.intellij.psi.impl.source.tree.injected.InjectedLanguageEditorUtil; import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil; +import com.intellij.testFramework.common.EditorCaretTestUtil; import com.intellij.util.ThrowableRunnable; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -162,7 +163,8 @@ public abstract class LightPlatformCodeInsightTestCase extends LightPlatformTest return WriteCommandAction.writeCommandAction(null).compute(() -> { Document fakeDocument = new DocumentImpl(fileText); - EditorTestUtil.CaretAndSelectionState caretsState = EditorTestUtil.extractCaretAndSelectionMarkers(fakeDocument); + EditorCaretTestUtil.CaretAndSelectionState + caretsState = EditorTestUtil.extractCaretAndSelectionMarkers(fakeDocument); if (checkCaret) { assertTrue("No caret specified in " + fileName, caretsState.hasExplicitCaret()); } @@ -185,7 +187,7 @@ public abstract class LightPlatformCodeInsightTestCase extends LightPlatformTest protected @NotNull Editor configureFromFileTextWithoutPSI(@NonNls @NotNull String fileText) { return WriteCommandAction.writeCommandAction(getProject()).compute(() -> { Document fakeDocument = EditorFactory.getInstance().createDocument(fileText); - EditorTestUtil.CaretAndSelectionState caretsState = EditorTestUtil.extractCaretAndSelectionMarkers(fakeDocument); + EditorCaretTestUtil.CaretAndSelectionState caretsState = EditorTestUtil.extractCaretAndSelectionMarkers(fakeDocument); String newFileText = fakeDocument.getText(); Document document = EditorFactory.getInstance().createDocument(newFileText); @@ -424,7 +426,7 @@ public abstract class LightPlatformCodeInsightTestCase extends LightPlatformTest ((DocumentImpl)document).stripTrailingSpaces(getProject()); } - EditorTestUtil.CaretAndSelectionState carets = EditorTestUtil.extractCaretAndSelectionMarkers(document); + EditorCaretTestUtil.CaretAndSelectionState carets = EditorTestUtil.extractCaretAndSelectionMarkers(document); PostprocessReformattingAspect.getInstance(getProject()).doPostponedFormatting(); String newFileText = document.getText(); @@ -453,7 +455,7 @@ public abstract class LightPlatformCodeInsightTestCase extends LightPlatformTest ((DocumentImpl)fakeDocument).stripTrailingSpaces(getProject()); } - EditorTestUtil.CaretAndSelectionState carets = EditorTestUtil.extractCaretAndSelectionMarkers(fakeDocument); + EditorCaretTestUtil.CaretAndSelectionState carets = EditorTestUtil.extractCaretAndSelectionMarkers(fakeDocument); String newFileText = fakeDocument.getText(); String fileText1 = editor.getDocument().getText(); diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java index 10f0e35adeb6..81b1707bbecc 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java @@ -129,6 +129,7 @@ import com.intellij.refactoring.rename.*; import com.intellij.refactoring.rename.api.RenameTarget; import com.intellij.refactoring.rename.impl.RenameKt; import com.intellij.testFramework.*; +import com.intellij.testFramework.common.EditorCaretTestUtil; import com.intellij.testFramework.fixtures.*; import com.intellij.testFramework.utils.inlays.CaretAndInlaysInfo; import com.intellij.testFramework.utils.inlays.InlayHintsChecker; @@ -153,7 +154,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; import org.jetbrains.annotations.Unmodifiable; -import org.junit.Assert; import java.io.File; import java.io.IOException; @@ -2365,7 +2365,7 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig private final String filePath; private final String newFileText; private final String newDocumentText; - private final EditorTestUtil.CaretAndSelectionState caretState; + private final EditorCaretTestUtil.CaretAndSelectionState caretState; private SelectionAndCaretMarkupLoader(@NotNull String fileText, @NotNull String documentText, String filePath) { this.filePath = filePath; diff --git a/python/testSrc/com/jetbrains/env/debug/tests/PyDynamicTypesTest.java b/python/testSrc/com/jetbrains/env/debug/tests/PyDynamicTypesTest.java index 75a8fa1b6caf..f7afb0551d88 100644 --- a/python/testSrc/com/jetbrains/env/debug/tests/PyDynamicTypesTest.java +++ b/python/testSrc/com/jetbrains/env/debug/tests/PyDynamicTypesTest.java @@ -8,6 +8,7 @@ import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.testFramework.EditorTestUtil; import com.intellij.testFramework.EdtTestUtil; +import com.intellij.testFramework.common.EditorCaretTestUtil; import com.jetbrains.env.EnvTestTagsRequired; import com.jetbrains.env.PyEnvTestCase; import com.jetbrains.env.debug.tasks.PyDebuggerTask; @@ -62,8 +63,8 @@ public class PyDynamicTypesTest extends PyEnvTestCase { EdtTestUtil.runInEdtAndWait(() -> { myFixture.configureByFile(scriptName); - EditorTestUtil.setCaretsAndSelection(myFixture.getEditor(), new EditorTestUtil.CaretAndSelectionState( - Lists.newArrayList(new EditorTestUtil.CaretInfo(new LogicalPosition(0, 6), null)), null)); + EditorTestUtil.setCaretsAndSelection(myFixture.getEditor(), new EditorCaretTestUtil.CaretAndSelectionState( + Lists.newArrayList(new EditorCaretTestUtil.CaretInfo(new LogicalPosition(0, 6), null)), null)); final IntentionAction action = myFixture.findSingleIntention(PyPsiBundle.message("INTN.insert.docstring.stub")); boolean saved = PyCodeInsightSettings.getInstance().INSERT_TYPE_DOCSTUB; try { diff --git a/python/testSrc/com/jetbrains/env/debug/tests/PythonConsoleTest.java b/python/testSrc/com/jetbrains/env/debug/tests/PythonConsoleTest.java index 7fcf0a747f53..2c694965f603 100644 --- a/python/testSrc/com/jetbrains/env/debug/tests/PythonConsoleTest.java +++ b/python/testSrc/com/jetbrains/env/debug/tests/PythonConsoleTest.java @@ -12,6 +12,7 @@ import com.intellij.openapi.editor.ex.EditorEx; import com.intellij.testFramework.EditorTestUtil; import com.intellij.testFramework.EdtTestUtil; import com.intellij.testFramework.TestActionEvent; +import com.intellij.testFramework.common.EditorCaretTestUtil; import com.intellij.testFramework.fixtures.CodeInsightTestFixture; import com.intellij.util.concurrency.annotations.RequiresEdt; import com.intellij.xdebugger.impl.ui.tree.nodes.XDebuggerTreeNode; @@ -60,7 +61,7 @@ public class PythonConsoleTest extends PyEnvTestCase { var model = consoleEditor.getCaretModel(); List oldCarets = List.copyOf(model.getAllCarets()); - for (EditorTestUtil.CaretInfo caret : state.carets()) { + for (EditorCaretTestUtil.CaretInfo caret : state.carets()) { if (caret.position != null) { model.addCaret(caret.position, primary.get()); primary.set(false);