diff --git a/ui/org.eclipse.pde.genericeditor.extension.tests/META-INF/MANIFEST.MF b/ui/org.eclipse.pde.genericeditor.extension.tests/META-INF/MANIFEST.MF index 035112ee375..e40d9d7d57a 100644 --- a/ui/org.eclipse.pde.genericeditor.extension.tests/META-INF/MANIFEST.MF +++ b/ui/org.eclipse.pde.genericeditor.extension.tests/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Tests for Generic Target Platform Editor Bundle-SymbolicName: org.eclipse.pde.genericeditor.extension.tests -Bundle-Version: 1.3.200.qualifier +Bundle-Version: 1.3.300.qualifier Bundle-Vendor: Eclipse.org Bundle-RequiredExecutionEnvironment: JavaSE-21 Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.29.0,4.0.0)", diff --git a/ui/org.eclipse.pde.genericeditor.extension.tests/pom.xml b/ui/org.eclipse.pde.genericeditor.extension.tests/pom.xml index 8b3cafceecc..4f98690f415 100644 --- a/ui/org.eclipse.pde.genericeditor.extension.tests/pom.xml +++ b/ui/org.eclipse.pde.genericeditor.extension.tests/pom.xml @@ -18,7 +18,7 @@ ../../ org.eclipse.pde.genericeditor.extension.tests - 1.3.200-SNAPSHOT + 1.3.300-SNAPSHOT eclipse-test-plugin diff --git a/ui/org.eclipse.pde.genericeditor.extension.tests/src/org/eclipse/pde/genericeditor/extension/tests/AllTargetEditorTests.java b/ui/org.eclipse.pde.genericeditor.extension.tests/src/org/eclipse/pde/genericeditor/extension/tests/AllTargetEditorTests.java index 7beaf403cd2..be0ea38fc39 100644 --- a/ui/org.eclipse.pde.genericeditor.extension.tests/src/org/eclipse/pde/genericeditor/extension/tests/AllTargetEditorTests.java +++ b/ui/org.eclipse.pde.genericeditor.extension.tests/src/org/eclipse/pde/genericeditor/extension/tests/AllTargetEditorTests.java @@ -20,7 +20,8 @@ @RunWith(Suite.class) @SuiteClasses({ AttributeNameCompletionTests.class, AttributeValueCompletionTests.class, TagNameCompletionTests.class, TagValueCompletionTests.class, Bug527084CompletionWithCommentsTest.class, - Bug528706CompletionWithMultilineTagsTest.class, UpdateUnitVersionsCommandTests.class, Bug531602FormattingTests.class }) + Bug528706CompletionWithMultilineTagsTest.class, UpdateUnitVersionsCommandTests.class, Bug531602FormattingTests.class, + TargetPlatformPresentationReconcilerTest.class }) public class AllTargetEditorTests { } diff --git a/ui/org.eclipse.pde.genericeditor.extension.tests/src/org/eclipse/pde/genericeditor/extension/tests/TargetPlatformPresentationReconcilerTest.java b/ui/org.eclipse.pde.genericeditor.extension.tests/src/org/eclipse/pde/genericeditor/extension/tests/TargetPlatformPresentationReconcilerTest.java new file mode 100644 index 00000000000..e8c65f675b0 --- /dev/null +++ b/ui/org.eclipse.pde.genericeditor.extension.tests/src/org/eclipse/pde/genericeditor/extension/tests/TargetPlatformPresentationReconcilerTest.java @@ -0,0 +1,125 @@ +/******************************************************************************* + * Copyright (c) 2026 vogella GmbH 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: + * Lars Vogel - initial implementation + *******************************************************************************/ +package org.eclipse.pde.genericeditor.extension.tests; + +import static org.junit.Assert.assertNotNull; + +import org.eclipse.jface.text.Document; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.Region; +import org.eclipse.jface.text.TextPresentation; +import org.eclipse.jface.text.presentation.IPresentationRepairer; +import org.eclipse.pde.internal.genericeditor.target.extension.reconciler.presentation.TargetPlatformPresentationReconciler; +import org.junit.Test; + +/** + * Tests for {@link TargetPlatformPresentationReconciler}. + * + *

The reconciler overrides {@code createPresentation} to scan from offset 0 + * so that multi-line rules (XML comments) are correctly recognised even when + * the damaged region is deep inside the document. These tests verify that the + * presentation is computed correctly for several representative document shapes + * and damage positions. + */ +public class TargetPlatformPresentationReconcilerTest { + + /** Subclass that exposes the protected {@code createPresentation} for testing. */ + private static class TestableReconciler extends TargetPlatformPresentationReconciler { + TextPresentation createPresentation(IDocument document, IRegion damage) { + IPresentationRepairer repairer = getRepairer(IDocument.DEFAULT_CONTENT_TYPE); + if (repairer != null) { + repairer.setDocument(document); + } + return createPresentation(damage, document); + } + } + + @Test + public void testCreatePresentationReturnsNonNullForSimpleDocument() { + TestableReconciler reconciler = new TestableReconciler(); + String content = "\n" //$NON-NLS-1$ + + "\n" //$NON-NLS-1$ + + " \n" //$NON-NLS-1$ + + "\n"; //$NON-NLS-1$ + IDocument document = new Document(content); + IRegion damage = new Region(0, content.length()); + + TextPresentation presentation = reconciler.createPresentation(document, damage); + + assertNotNull("Expected a non-null TextPresentation for a simple document", presentation); //$NON-NLS-1$ + } + + @Test + public void testCreatePresentationWithDamageSubsetOfDocument() { + TestableReconciler reconciler = new TestableReconciler(); + String content = "\n" //$NON-NLS-1$ + + "\n" //$NON-NLS-1$ + + " \n" //$NON-NLS-1$ + + " \n" //$NON-NLS-1$ + + "\n"; //$NON-NLS-1$ + IDocument document = new Document(content); + // Damage is only the last few characters, not the full document. + int damageOffset = content.indexOf(""); //$NON-NLS-1$ + IRegion damage = new Region(damageOffset, content.length() - damageOffset); + + TextPresentation presentation = reconciler.createPresentation(document, damage); + + assertNotNull("Expected a non-null TextPresentation when damage covers only end of document", presentation); //$NON-NLS-1$ + } + + @Test + public void testCreatePresentationWithMultilineCommentBeforeDamage() { + TestableReconciler reconciler = new TestableReconciler(); + // Multi-line comment appears before the damage region. The reconciler must + // scan from offset 0 so it can correctly determine the scanner state + // (comment vs normal) at the start of the damage. + String content = "\n" //$NON-NLS-1$ + + "\n" //$NON-NLS-1$ + + "\n" //$NON-NLS-1$ + + " \n" //$NON-NLS-1$ + + "\n"; //$NON-NLS-1$ + IDocument document = new Document(content); + // Damage is after the comment closes. + int damageOffset = content.indexOf(""); //$NON-NLS-1$ + IRegion damage = new Region(damageOffset, content.length() - damageOffset); + + TextPresentation presentation = reconciler.createPresentation(document, damage); + + assertNotNull("Expected a non-null TextPresentation when a multi-line comment precedes the damage", //$NON-NLS-1$ + presentation); + } + + @Test + public void testCreatePresentationWithDamageInsideMultilineComment() { + TestableReconciler reconciler = new TestableReconciler(); + String content = "\n" //$NON-NLS-1$ + + "\n" //$NON-NLS-1$ + + "\n" //$NON-NLS-1$ + + "\n"; //$NON-NLS-1$ + IDocument document = new Document(content); + // Damage is inside the comment body. + int damageOffset = content.indexOf(" line two"); //$NON-NLS-1$ + IRegion damage = new Region(damageOffset, " line two\n".length()); //$NON-NLS-1$ + + TextPresentation presentation = reconciler.createPresentation(document, damage); + + assertNotNull("Expected a non-null TextPresentation when damage is inside a multi-line comment", presentation); //$NON-NLS-1$ + } +} diff --git a/ui/org.eclipse.pde.genericeditor.extension/META-INF/MANIFEST.MF b/ui/org.eclipse.pde.genericeditor.extension/META-INF/MANIFEST.MF index 0ee79b46b8d..845bd9df355 100644 --- a/ui/org.eclipse.pde.genericeditor.extension/META-INF/MANIFEST.MF +++ b/ui/org.eclipse.pde.genericeditor.extension/META-INF/MANIFEST.MF @@ -28,6 +28,6 @@ Export-Package: org.eclipse.pde.internal.genericeditor.target.extension.autocomp org.eclipse.pde.internal.genericeditor.target.extension.model.xml;x-internal:=true, org.eclipse.pde.internal.genericeditor.target.extension.p2;x-internal:=true, org.eclipse.pde.internal.genericeditor.target.extension.reconciler.folding;x-internal:=true, - org.eclipse.pde.internal.genericeditor.target.extension.reconciler.presentation;x-internal:=true, + org.eclipse.pde.internal.genericeditor.target.extension.reconciler.presentation;x-friends:="org.eclipse.pde.genericeditor.extension.tests", org.eclipse.pde.internal.genericeditor.target.extension.validator;x-internal:=true Automatic-Module-Name: org.eclipse.pde.genericeditor.extension diff --git a/ui/org.eclipse.pde.genericeditor.extension/src/org/eclipse/pde/internal/genericeditor/target/extension/reconciler/presentation/TargetPlatformPresentationReconciler.java b/ui/org.eclipse.pde.genericeditor.extension/src/org/eclipse/pde/internal/genericeditor/target/extension/reconciler/presentation/TargetPlatformPresentationReconciler.java index 1efa13de4af..2522208bd11 100644 --- a/ui/org.eclipse.pde.genericeditor.extension/src/org/eclipse/pde/internal/genericeditor/target/extension/reconciler/presentation/TargetPlatformPresentationReconciler.java +++ b/ui/org.eclipse.pde.genericeditor.extension/src/org/eclipse/pde/internal/genericeditor/target/extension/reconciler/presentation/TargetPlatformPresentationReconciler.java @@ -109,8 +109,11 @@ private void setDamageRepairerScanner() { } /** - * Performs the repair on the full document to ensure MultiLineRules are - * enforced + * Performs the repair from the start of the document up to and including the + * damaged region to ensure MultiLineRules (e.g. XML comments) are correctly + * recognised. Scanning stops at the damage end rather than the document end + * because the returned {@link TextPresentation} is bounded by {@code damage} + * anyway, so any style ranges beyond that point would be discarded. */ @Override protected TextPresentation createPresentation(IRegion damage, IDocument document) { @@ -118,8 +121,9 @@ protected TextPresentation createPresentation(IRegion damage, IDocument document IPresentationRepairer repairer = this.getRepairer(IDocument.DEFAULT_CONTENT_TYPE); if (repairer != null) { try { + int scanEnd = Math.min(damage.getOffset() + damage.getLength(), document.getLength()); ITypedRegion[] regions = TextUtilities.computePartitioning(document, getDocumentPartitioning(), 0, - document.getLength(), false); + scanEnd, false); if (regions.length > 0) { repairer.createPresentation(presentation, regions[0]); return presentation;