Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMickael Istria2021-09-27 13:38:03 +0000
committerMickael Istria2021-09-27 14:06:55 +0000
commit667a1fdf000996bc6367a72756d16e737b9f1b20 (patch)
treedcfb3f8ecc637580201cec0ab0bd03ca7a2880c2
parente3d11f1798296654051627f25b5f0410e99c17ea (diff)
downloadeclipse.platform.text-667a1fdf000996bc6367a72756d16e737b9f1b20.tar.gz
eclipse.platform.text-667a1fdf000996bc6367a72756d16e737b9f1b20.tar.xz
eclipse.platform.text-667a1fdf000996bc6367a72756d16e737b9f1b20.zip
Bug 576281 - To Upper/Lower case commands can lead to bad selectionI20210928-1800I20210928-0600I20210927-1800
Change-Id: I00cb4e113a495903198c96920a6e952342f44264 Reviewed-on: https://git.eclipse.org/r/c/platform/eclipse.platform.text/+/185854 Tested-by: Mickael Istria <mistria@redhat.com> Reviewed-by: Mickael Istria <mistria@redhat.com>
-rw-r--r--org.eclipse.ui.editors.tests/src/org/eclipse/ui/editors/tests/CaseActionTest.java119
-rw-r--r--org.eclipse.ui.editors.tests/src/org/eclipse/ui/editors/tests/EditorsTestSuite.java2
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/CaseAction.java46
3 files changed, 151 insertions, 16 deletions
diff --git a/org.eclipse.ui.editors.tests/src/org/eclipse/ui/editors/tests/CaseActionTest.java b/org.eclipse.ui.editors.tests/src/org/eclipse/ui/editors/tests/CaseActionTest.java
new file mode 100644
index 00000000000..27be393f8f7
--- /dev/null
+++ b/org.eclipse.ui.editors.tests/src/org/eclipse/ui/editors/tests/CaseActionTest.java
@@ -0,0 +1,119 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Red Hat Inc. and others
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Mickael Istria (Red Hat Inc.)
+ *******************************************************************************/
+package org.eclipse.ui.editors.tests;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+
+import java.io.ByteArrayInputStream;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import org.eclipse.swt.custom.StyledText;
+import org.eclipse.swt.widgets.Control;
+
+import org.eclipse.core.runtime.NullProgressMonitor;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.ResourcesPlugin;
+
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IMultiTextSelection;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.MultiTextSelection;
+import org.eclipse.jface.text.Region;
+
+import org.eclipse.ui.IEditorDescriptor;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.intro.IIntroPart;
+import org.eclipse.ui.part.FileEditorInput;
+
+import org.eclipse.ui.texteditor.AbstractTextEditor;
+import org.eclipse.ui.texteditor.ITextEditorActionConstants;
+
+public class CaseActionTest {
+
+ private static IProject project;
+ private static IFile file;
+ private StyledText text;
+ private AbstractTextEditor editor;
+
+ @BeforeClass
+ public static void setUpBeforeClass() throws Exception {
+ project = ResourcesPlugin.getWorkspace().getRoot().getProject("test");
+ project.create(new NullProgressMonitor());
+ project.open(new NullProgressMonitor());
+ file = project.getFile("foo.txt");
+ file.create(new ByteArrayInputStream("bar".getBytes()), true, new NullProgressMonitor());
+ }
+
+ @AfterClass
+ public static void tearDownAfterClass() throws Exception {
+ file.delete(true, new NullProgressMonitor());
+ project.delete(true, new NullProgressMonitor());
+ TestUtil.cleanUp();
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ IIntroPart intro = PlatformUI.getWorkbench().getIntroManager().getIntro();
+ if (intro != null) {
+ PlatformUI.getWorkbench().getIntroManager().closeIntro(intro);
+ }
+
+ IEditorDescriptor desc = PlatformUI.getWorkbench().getEditorRegistry().getDefaultEditor(file.getName());
+ editor = (AbstractTextEditor) PlatformUI.getWorkbench().getActiveWorkbenchWindow()
+ .getActivePage().openEditor(new FileEditorInput(file), desc.getId());
+ editor.setFocus();
+ text = (StyledText) editor.getAdapter(Control.class);
+ // make sure we start from a clean state
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ editor.close(false);
+ editor= null;
+ }
+
+ @Test
+ public void testMultiSelectionCase() {
+ IDocument doc = editor.getDocumentProvider().getDocument(editor.getEditorInput());
+ doc.set("foo bar foo");
+ IRegion[] initialSelection = { new Region(0,3), new Region(8, 3) };
+ editor.getSelectionProvider().setSelection(new MultiTextSelection(doc, initialSelection));
+ editor.getAction(ITextEditorActionConstants.UPPER_CASE).run();
+ assertEquals("FOO bar FOO", doc.get());
+ assertArrayEquals(initialSelection,
+ ((IMultiTextSelection) editor.getSelectionProvider().getSelection()).getRegions());
+ //
+ doc.set("foß bar fßo bar ßoo");
+ editor.getSelectionProvider().setSelection(new MultiTextSelection(doc, new IRegion[] { //
+ new Region(0, 3), //
+ new Region(8, 3), //
+ new Region(16, 3) }));
+ editor.getAction(ITextEditorActionConstants.UPPER_CASE).run();
+ assertEquals("FOSS bar FSSO bar SSOO", doc.get());
+ assertArrayEquals(new IRegion[] { //
+ new Region(0, 4), //
+ new Region(9, 4), //
+ new Region(18, 4) //
+ }, ((IMultiTextSelection) editor.getSelectionProvider().getSelection()).getRegions());
+ }
+
+}
diff --git a/org.eclipse.ui.editors.tests/src/org/eclipse/ui/editors/tests/EditorsTestSuite.java b/org.eclipse.ui.editors.tests/src/org/eclipse/ui/editors/tests/EditorsTestSuite.java
index 66b41fbff3a..74c52d215c7 100644
--- a/org.eclipse.ui.editors.tests/src/org/eclipse/ui/editors/tests/EditorsTestSuite.java
+++ b/org.eclipse.ui.editors.tests/src/org/eclipse/ui/editors/tests/EditorsTestSuite.java
@@ -36,7 +36,7 @@ import org.junit.runners.Suite.SuiteClasses;
TextFileDocumentProviderTest.class,
StatusEditorTest.class,
TextNavigationTest.class,
- LargeFileTest.class
+ LargeFileTest.class, CaseActionTest.class
})
public class EditorsTestSuite {
// see @SuiteClasses
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/CaseAction.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/CaseAction.java
index 9d91c18bd6d..9f376e144b4 100644
--- a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/CaseAction.java
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/CaseAction.java
@@ -15,10 +15,15 @@
*******************************************************************************/
package org.eclipse.ui.texteditor;
+import java.util.ArrayList;
+import java.util.List;
import java.util.ResourceBundle;
import org.eclipse.swt.custom.StyledText;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IBlockTextSelection;
import org.eclipse.jface.text.IDocument;
@@ -26,8 +31,12 @@ import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.text.ITextViewerExtension;
import org.eclipse.jface.text.JFaceTextUtil;
+import org.eclipse.jface.text.MultiTextSelection;
+import org.eclipse.jface.text.Region;
import org.eclipse.jface.text.source.ISourceViewer;
+import org.eclipse.ui.internal.texteditor.TextEditorPlugin;
+
/**
* Action that converts the current selection to lower case or upper case.
* @since 3.0
@@ -79,37 +88,44 @@ public class CaseAction extends TextEditorAction {
ITextSelection selection= (ITextSelection) viewer.getSelectionProvider().getSelection();
- int adjustment= 0;
try {
if (JFaceTextUtil.isEmpty(viewer, selection))
return;
IRegion[] ranges= JFaceTextUtil.getCoveredRanges(viewer, selection);
+ List<IRegion> newRanges = new ArrayList<>(ranges.length);
if (ranges.length > 1 && viewer instanceof ITextViewerExtension)
((ITextViewerExtension) viewer).getRewriteTarget().beginCompoundChange();
+ int offsetShift = 0;
for (IRegion region : ranges) {
- String target= document.get(region.getOffset(), region.getLength());
+ int newOffset = region.getOffset() + offsetShift;
+ String target = document.get(newOffset, region.getLength());
String replacement= (fToUpper ? target.toUpperCase() : target.toLowerCase());
if (!target.equals(replacement)) {
- document.replace(region.getOffset(), region.getLength(), replacement);
- // https://bugs.eclipse.org/bugs/show_bug.cgi?id=145326: replacement might be larger than the original
- adjustment= replacement.length() - target.length();
+ document.replace(newOffset, region.getLength(), replacement);
}
+ // https://bugs.eclipse.org/bugs/show_bug.cgi?id=145326: replacement might be
+ // larger than the original
+ int currentAdjustment = replacement.length() - target.length();
+ offsetShift += currentAdjustment;
+ newRanges.add(new Region(newOffset, region.getLength() + currentAdjustment));
}
if (ranges.length > 1 && viewer instanceof ITextViewerExtension)
((ITextViewerExtension) viewer).getRewriteTarget().endCompoundChange();
+
+ // reinstall selection and move it into view
+ if (!(selection instanceof IBlockTextSelection)) {
+ viewer.getSelectionProvider()
+ .setSelection(new MultiTextSelection(viewer.getDocument(), newRanges.toArray(IRegion[]::new)));
+ } else {
+ viewer.getSelectionProvider().setSelection(selection);
+ }
+ // don't use the viewer's reveal feature in order to avoid jumping around
+ st.showSelection();
} catch (BadLocationException x) {
- // ignore and return
- return;
+ TextEditorPlugin.getDefault().getLog()
+ .log(new Status(IStatus.ERROR, TextEditorPlugin.PLUGIN_ID, x.getMessage(), x));
}
-
- // reinstall selection and move it into view
- if (!(selection instanceof IBlockTextSelection))
- viewer.setSelectedRange(selection.getOffset(), selection.getLength() + adjustment);
- else
- viewer.getSelectionProvider().setSelection(selection);
- // don't use the viewer's reveal feature in order to avoid jumping around
- st.showSelection();
}
}

Back to the top