diff options
author | Mickael Istria | 2021-09-27 13:38:03 +0000 |
---|---|---|
committer | Mickael Istria | 2021-09-27 14:06:55 +0000 |
commit | 667a1fdf000996bc6367a72756d16e737b9f1b20 (patch) | |
tree | dcfb3f8ecc637580201cec0ab0bd03ca7a2880c2 | |
parent | e3d11f1798296654051627f25b5f0410e99c17ea (diff) | |
download | eclipse.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>
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(); } } |