diff --git a/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/model/tests/CModelElementsTests.java b/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/model/tests/CModelElementsTests.java index 00920e6bb1a..5c648109821 100644 --- a/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/model/tests/CModelElementsTests.java +++ b/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/model/tests/CModelElementsTests.java @@ -35,6 +35,7 @@ import org.eclipse.cdt.core.model.IMethodDeclaration; import org.eclipse.cdt.core.model.IMethodTemplateDeclaration; import org.eclipse.cdt.core.model.INamespace; import org.eclipse.cdt.core.model.IParent; +import org.eclipse.cdt.core.model.IPragma; import org.eclipse.cdt.core.model.ISourceRange; import org.eclipse.cdt.core.model.ISourceReference; import org.eclipse.cdt.core.model.IStructure; @@ -137,6 +138,69 @@ public class CModelElementsTests extends BaseTestCase { checkBug180815(tu); checkBug352350(tu); + + checkPragmas(tu); + } + + private void checkPragmas(ITranslationUnit tu) throws CModelException { + List pragmas = tu.getChildrenOfType(ICElement.C_PRAGMA); + + int line = 0; + { + IPragma pragma = (IPragma) pragmas.get(line++); + assertEquals("mark - before and after -", pragma.getElementName()); + assertEquals(true, pragma.getPragmaMarkInfo().get().isDividerBeforeMark()); + assertEquals(true, pragma.getPragmaMarkInfo().get().isDividerAfterMark()); + assertEquals("before and after", pragma.getPragmaMarkInfo().get().getMarkName()); + } + { + IPragma pragma = (IPragma) pragmas.get(line++); + assertEquals("mark - before", pragma.getElementName()); + assertEquals(true, pragma.getPragmaMarkInfo().get().isDividerBeforeMark()); + assertEquals(false, pragma.getPragmaMarkInfo().get().isDividerAfterMark()); + assertEquals("before", pragma.getPragmaMarkInfo().get().getMarkName()); + } + { + IPragma pragma = (IPragma) pragmas.get(line++); + assertEquals("mark after -", pragma.getElementName()); + assertEquals(false, pragma.getPragmaMarkInfo().get().isDividerBeforeMark()); + assertEquals(true, pragma.getPragmaMarkInfo().get().isDividerAfterMark()); + assertEquals("after", pragma.getPragmaMarkInfo().get().getMarkName()); + } + { + IPragma pragma = (IPragma) pragmas.get(line++); + assertEquals("mark neither", pragma.getElementName()); + assertEquals(false, pragma.getPragmaMarkInfo().get().isDividerBeforeMark()); + assertEquals(false, pragma.getPragmaMarkInfo().get().isDividerAfterMark()); + assertEquals("neither", pragma.getPragmaMarkInfo().get().getMarkName()); + } + { + IPragma pragma = (IPragma) pragmas.get(line++); + assertEquals("mark -", pragma.getElementName()); + assertEquals(true, pragma.getPragmaMarkInfo().get().isDividerBeforeMark()); + assertEquals(false, pragma.getPragmaMarkInfo().get().isDividerAfterMark()); + assertEquals("", pragma.getPragmaMarkInfo().get().getMarkName()); + } + { + IPragma pragma = (IPragma) pragmas.get(line++); + assertEquals("mark", pragma.getElementName()); + assertEquals(false, pragma.getPragmaMarkInfo().get().isDividerBeforeMark()); + assertEquals(false, pragma.getPragmaMarkInfo().get().isDividerAfterMark()); + assertEquals("", pragma.getPragmaMarkInfo().get().getMarkName()); + } + { + IPragma pragma = (IPragma) pragmas.get(line++); + assertEquals("ms_struct on", pragma.getElementName()); + assertEquals(true, pragma.getPragmaMarkInfo().isEmpty()); + assertEquals(false, pragma.isPragmaOperator()); + } + { + IPragma pragma = (IPragma) pragmas.get(line++); + assertEquals("_Pragma(\"once\")", pragma.getElementName()); + assertEquals(true, pragma.getPragmaMarkInfo().isEmpty()); + assertEquals(true, pragma.isPragmaOperator()); + } + assertEquals(line, pragmas.size()); } // https://bugs.eclipse.org/bugs/show_bug.cgi?id=180815 diff --git a/core/org.eclipse.cdt.core.tests/resources/cfiles/CModelElementsTestStart.h b/core/org.eclipse.cdt.core.tests/resources/cfiles/CModelElementsTestStart.h index d9736eff1d3..18ca36e0829 100644 --- a/core/org.eclipse.cdt.core.tests/resources/cfiles/CModelElementsTestStart.h +++ b/core/org.eclipse.cdt.core.tests/resources/cfiles/CModelElementsTestStart.h @@ -143,4 +143,15 @@ struct bug180815 { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=352350 namespace { int bug352350; -} \ No newline at end of file +} + +// https://bugs.eclipse.org/bugs/show_bug.cgi?id=574271 +#pragma mark - before and after - +#pragma mark - before +#pragma mark after - +#pragma mark neither +#pragma mark -// blank1 +#pragma mark // blank2 +#pragma ms_struct on +_Pragma("once") + diff --git a/core/org.eclipse.cdt.core/META-INF/MANIFEST.MF b/core/org.eclipse.cdt.core/META-INF/MANIFEST.MF index d692c5c25be..8a329b9f158 100644 --- a/core/org.eclipse.cdt.core/META-INF/MANIFEST.MF +++ b/core/org.eclipse.cdt.core/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.cdt.core; singleton:=true -Bundle-Version: 7.2.200.qualifier +Bundle-Version: 7.3.0.qualifier Bundle-Activator: org.eclipse.cdt.core.CCorePlugin Bundle-Vendor: %providerName Bundle-Localization: plugin diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/model/ICElement.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/model/ICElement.java index 28034b42238..c4e069976ec 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/model/ICElement.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/model/ICElement.java @@ -243,6 +243,12 @@ public interface ICElement extends IAdaptable { */ static final int ASM_LABEL = 94; + /** + * A pragma statement. + * @since 7.3 + */ + static final int C_PRAGMA = 95; + /** * @deprecated use {@link IMethodDeclaration#isConstructor()} * @noreference This field is not intended to be referenced by clients. diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/model/IPragma.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/model/IPragma.java new file mode 100644 index 00000000000..334f9ed971e --- /dev/null +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/model/IPragma.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * Copyright (c) 2021 Kichwa Coders Canada 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 + *******************************************************************************/ + +package org.eclipse.cdt.core.model; + +import java.util.Optional; + +/** + * Represents a pragma statement. + * + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. + * @since 7.3 + */ +public interface IPragma extends ICElement, ISourceManipulation, ISourceReference { + + public interface PragmaMarkInfo { + /** + * Whether the pragma indicates a divider before it. + */ + public boolean isDividerBeforeMark(); + + /** + * Whether the pragma indicates a divider after it. + */ + public boolean isDividerAfterMark(); + + /** + * The display string of the mark. + */ + public String getMarkName(); + } + + /** + * Returns whether this uses the pragma operator syntax, e.g: _Pragma("once") + * @since 5.2 + */ + public boolean isPragmaOperator(); + + /** + * Returns the PragmaMarkInfo if the pragma represents a #pragma mark or similar pragma + * that should be interpreted as such. + * @return {@link Optional} of the {@link PragmaMarkInfo} + */ + Optional getPragmaMarkInfo(); +} diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/CModelBuilder2.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/CModelBuilder2.java index 51253f7bc59..97c13fac1f5 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/CModelBuilder2.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/CModelBuilder2.java @@ -43,6 +43,7 @@ import org.eclipse.cdt.core.dom.ast.IASTNodeLocation; import org.eclipse.cdt.core.dom.ast.IASTPreprocessorFunctionStyleMacroDefinition; import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIncludeStatement; import org.eclipse.cdt.core.dom.ast.IASTPreprocessorMacroDefinition; +import org.eclipse.cdt.core.dom.ast.IASTPreprocessorPragmaStatement; import org.eclipse.cdt.core.dom.ast.IASTPreprocessorStatement; import org.eclipse.cdt.core.dom.ast.IASTProblem; import org.eclipse.cdt.core.dom.ast.IASTProblemDeclaration; @@ -109,6 +110,14 @@ public class CModelBuilder2 implements IContributedModelBuilder { private Stack fVisibilityStack; private HashMap fEqualElements; + /** + * To support the new feature "#pragma mark to Outline view" (Bug 546981) the model was updated + * to include pragmas. Because the model is widely used, this feature flag allows turning off + * including pragmas in the model. + */ + private static final boolean INCLUDE_PRAGMAS_IN_MODEL = Boolean + .parseBoolean(System.getProperty("org.eclipse.cdt.core.model_include_pragmas", "true")); //$NON-NLS-1$ //$NON-NLS-2$ + /** * Create a model builder for the given translation unit. * @@ -220,6 +229,12 @@ public class CModelBuilder2 implements IContributedModelBuilder { if (isLocalToFile(statement)) { createMacro(fTranslationUnit, (IASTPreprocessorMacroDefinition) statement); } + } else if (statement instanceof IASTPreprocessorPragmaStatement) { + if (INCLUDE_PRAGMAS_IN_MODEL) { + if (isLocalToFile(statement)) { + createPragma(fTranslationUnit, (IASTPreprocessorPragmaStatement) statement); + } + } } } @@ -320,6 +335,27 @@ public class CModelBuilder2 implements IContributedModelBuilder { return element; } + private Pragma createPragma(Parent parent, IASTPreprocessorPragmaStatement pragma) throws CModelException { + // Create element + String name; + if (pragma.isPragmaOperator()) { + name = pragma.getRawSignature(); + } else { + char[] message = pragma.getMessage(); + name = new String(message); + } + Pragma element = new Pragma(parent, name); + setIndex(element); + element.setActive(pragma.isActive()); + // Add to parent + parent.addChild(element); + // Set positions + setIdentifierPosition(element, pragma); + setBodyPosition(element, pragma); + element.setPragmaOperator(pragma.isPragmaOperator()); + return element; + } + private void createDeclaration(Parent parent, IASTDeclaration declaration) throws CModelException, DOMException { if (declaration instanceof IASTFunctionDefinition) { createFunctionDefinition(parent, (IASTFunctionDefinition) declaration, false); @@ -1219,6 +1255,16 @@ public class CModelBuilder2 implements IContributedModelBuilder { } } + /** + * Utility method to set the identifier position of an element from an AST node. + * + * @param element + * @param astNode + */ + private void setIdentifierPosition(SourceManipulation element, IASTNode astNode) { + setIdentifierPosition(getSourceManipulationInfo(element), astNode); + } + /** * Utility method to set the identifier position of an element from an AST name. * diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/Pragma.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/Pragma.java new file mode 100644 index 00000000000..b6ccc4570f0 --- /dev/null +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/Pragma.java @@ -0,0 +1,109 @@ +/******************************************************************************* + * Copyright (c) 2021 Kichwa Coders Canada 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 + *******************************************************************************/ + +package org.eclipse.cdt.internal.core.model; + +import java.util.Optional; +import java.util.StringTokenizer; + +import org.eclipse.cdt.core.model.ICElement; +import org.eclipse.cdt.core.model.IPragma; + +public class Pragma extends SourceManipulation implements IPragma { + + private boolean isPragmaOperator = false; + private Optional pragmaMarkInfo = null; + + public Pragma(ICElement parent, String name) { + super(parent, name, ICElement.C_PRAGMA); + } + + private PragmaMarkInfo calculateMarkInfo(String name) { + String nameTrimmed = name.trim(); + + StringTokenizer tokenizer = new StringTokenizer(nameTrimmed); + if (tokenizer.hasMoreTokens()) { + + boolean dividerBeforeMark = false; + boolean dividerAfterMark = false; + String markName = ""; //$NON-NLS-1$ + + String pragmaName = tokenizer.nextToken(); + String restOfLine; + if (tokenizer.hasMoreTokens()) { + restOfLine = tokenizer.nextToken("").trim(); //$NON-NLS-1$ + } else { + restOfLine = ""; //$NON-NLS-1$ + } + switch (pragmaName) { + case "mark": { //$NON-NLS-1$ + if (restOfLine.startsWith("-")) { //$NON-NLS-1$ + dividerBeforeMark = true; + restOfLine = restOfLine.substring(1); + } + if (restOfLine.endsWith("-")) { //$NON-NLS-1$ + dividerAfterMark = true; + restOfLine = restOfLine.substring(0, restOfLine.length() - 1); + } + markName = restOfLine.trim(); + } + break; + default: + return null; + } + + boolean finalDividerBeforeMark = dividerBeforeMark; + boolean finalDividerAfterMark = dividerAfterMark; + String finalMarkName = markName; + return new PragmaMarkInfo() { + + @Override + public boolean isDividerBeforeMark() { + return finalDividerBeforeMark; + } + + @Override + public boolean isDividerAfterMark() { + return finalDividerAfterMark; + } + + @Override + public String getMarkName() { + return finalMarkName; + } + }; + } else { + return null; + } + } + + @Override + protected CElementInfo createElementInfo() { + return new SourceManipulationInfo(this); + } + + public void setPragmaOperator(boolean isPragmaOperator) { + this.isPragmaOperator = isPragmaOperator; + } + + @Override + public boolean isPragmaOperator() { + return isPragmaOperator; + } + + @Override + public Optional getPragmaMarkInfo() { + if (pragmaMarkInfo == null) { + pragmaMarkInfo = Optional.ofNullable(calculateMarkInfo(getElementName())); + } + return pragmaMarkInfo; + } +} diff --git a/core/org.eclipse.cdt.ui/META-INF/MANIFEST.MF b/core/org.eclipse.cdt.ui/META-INF/MANIFEST.MF index 334f57a3475..f29e47c1eea 100644 --- a/core/org.eclipse.cdt.ui/META-INF/MANIFEST.MF +++ b/core/org.eclipse.cdt.ui/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.cdt.ui; singleton:=true -Bundle-Version: 7.2.100.qualifier +Bundle-Version: 7.3.0.qualifier Bundle-Activator: org.eclipse.cdt.ui.CUIPlugin Bundle-Vendor: %providerName Bundle-Localization: plugin @@ -102,7 +102,7 @@ Export-Package: org.eclipse.cdt.internal.corext;x-internal:=true, org.eclipse.cdt.ui.wizards, org.eclipse.cdt.ui.wizards.conversion, org.eclipse.cdt.utils.ui.controls -Require-Bundle: org.eclipse.cdt.core;bundle-version="[7.0.0,8.0.0)", +Require-Bundle: org.eclipse.cdt.core;bundle-version="[7.3.0,8.0.0)", org.eclipse.compare;bundle-version="[3.7.700,4.0.0)", org.eclipse.core.expressions;bundle-version="[3.6.500,4.0.0)", org.eclipse.core.filesystem;bundle-version="[1.7.500,2.0.0)", diff --git a/core/org.eclipse.cdt.ui/css/e4-dark_cdt.css b/core/org.eclipse.cdt.ui/css/e4-dark_cdt.css index 9de73825e4e..ef225ddadf5 100644 --- a/core/org.eclipse.cdt.ui/css/e4-dark_cdt.css +++ b/core/org.eclipse.cdt.ui/css/e4-dark_cdt.css @@ -82,4 +82,6 @@ IEclipsePreferences#org-eclipse-cdt-ui:org-eclipse-cdt-ui { IEclipsePreferences#org-eclipse-ui-workbench:org-eclipse-cdt-ui { /* pseudo attribute added to allow contributions without replacing this node, see Bug 466075 */ preferences: "org.eclipse.cdt.ui.ColoredLabels.writeaccess_highlight=255,128,128" + "org.eclipse.cdt.ui.outline.mark.textcolor=115,129,133" + "org.eclipse.cdt.ui.outline.mark.dividercolor=80,80,80" } diff --git a/core/org.eclipse.cdt.ui/icons/dlcl16/outline_mark.png b/core/org.eclipse.cdt.ui/icons/dlcl16/outline_mark.png new file mode 100644 index 00000000000..14a9e25681f Binary files /dev/null and b/core/org.eclipse.cdt.ui/icons/dlcl16/outline_mark.png differ diff --git a/core/org.eclipse.cdt.ui/icons/dlcl16/outline_mark@2x.png b/core/org.eclipse.cdt.ui/icons/dlcl16/outline_mark@2x.png new file mode 100644 index 00000000000..3d4065a94a9 Binary files /dev/null and b/core/org.eclipse.cdt.ui/icons/dlcl16/outline_mark@2x.png differ diff --git a/core/org.eclipse.cdt.ui/icons/elcl16/outline_mark.png b/core/org.eclipse.cdt.ui/icons/elcl16/outline_mark.png new file mode 100644 index 00000000000..14a9e25681f Binary files /dev/null and b/core/org.eclipse.cdt.ui/icons/elcl16/outline_mark.png differ diff --git a/core/org.eclipse.cdt.ui/icons/elcl16/outline_mark@2x.png b/core/org.eclipse.cdt.ui/icons/elcl16/outline_mark@2x.png new file mode 100644 index 00000000000..3d4065a94a9 Binary files /dev/null and b/core/org.eclipse.cdt.ui/icons/elcl16/outline_mark@2x.png differ diff --git a/core/org.eclipse.cdt.ui/icons/obj16/outline_mark.png b/core/org.eclipse.cdt.ui/icons/obj16/outline_mark.png new file mode 100644 index 00000000000..14a9e25681f Binary files /dev/null and b/core/org.eclipse.cdt.ui/icons/obj16/outline_mark.png differ diff --git a/core/org.eclipse.cdt.ui/icons/obj16/outline_mark@2x.png b/core/org.eclipse.cdt.ui/icons/obj16/outline_mark@2x.png new file mode 100644 index 00000000000..3d4065a94a9 Binary files /dev/null and b/core/org.eclipse.cdt.ui/icons/obj16/outline_mark@2x.png differ diff --git a/core/org.eclipse.cdt.ui/plugin.properties b/core/org.eclipse.cdt.ui/plugin.properties index 178d9267284..e2d94044163 100644 --- a/core/org.eclipse.cdt.ui/plugin.properties +++ b/core/org.eclipse.cdt.ui/plugin.properties @@ -396,6 +396,15 @@ CEditorFontDefinition.description = The C/C++ editor text font is used by C/C++ CPresentation.label= C/C++ CEditorPresentation.label= Editor +## C Outline Fonts +COutlinePresentation.label= Outline +COutline.mark.font.label= C/C++ Outline Mark/Region Text Font +COutline.mark.font.description= The C/C++ Outline Mark/Region Text font is used by C/C++ outlines for highlighted elements by #pragma mark or #pragma region +COutline.mark.textcolor.label=C/C++ Outline Mark/Region Text Color +COutline.mark.textcolor.description=The C/C++ Outline Mark/Region Text color is used by C/C++ outlines for highlighted elements by #pragma mark or #pragma region +COutline.mark.dividercolor.label=C/C++ Outline Mark/Region Divider Color +COutline.mark.dividercolor.description=The C/C++ Outline Mark/Region Divider color is used by C/C++ outlines for dividing lines around elements highlighted by #pragma mark or #pragma region + CDTIndexerMarker.label= C/C++ Indexer Markers diff --git a/core/org.eclipse.cdt.ui/plugin.xml b/core/org.eclipse.cdt.ui/plugin.xml index a764afa8d11..bf3837a4f81 100644 --- a/core/org.eclipse.cdt.ui/plugin.xml +++ b/core/org.eclipse.cdt.ui/plugin.xml @@ -574,6 +574,40 @@ %CEditorFontDefinition.description + + + + + %COutline.mark.font.description + + + + + %COutline.mark.textcolor.description + + + + + %COutline.mark.dividercolor.description + + false); } - public BaseCElementContentProvider(boolean provideMembers, boolean provideWorkingCopy) { + /** + * + * @param provideMembers + * @param provideWorkingCopy + * @param providePragmaMarks Include {@link PragmaMark} and its {@link DividerLine}s + * @param isSorted is a non-null supplier that returns true if the content is sorted, this is used + * to remove {@link DividerLine}s when sorted + */ + public BaseCElementContentProvider(boolean provideMembers, boolean provideWorkingCopy, boolean providePragmaMarks, + BooleanSupplier isSorted) { + Assert.isNotNull(isSorted); fProvideMembers = provideMembers; fProvideWorkingCopy = provideWorkingCopy; + fProvidePragmaMarks = providePragmaMarks; + fIsSorted = isSorted; } /** @@ -187,6 +209,21 @@ public class BaseCElementContentProvider implements ITreeContentProvider { fMacroGrouping = enable; } + /** + * @return whether hiding pragma mark is enabled + */ + public boolean isHidePragmaMarkEnabled() { + return !fProvidePragmaMarks; + } + + /** + * Enable/disable hiding pragma mark + * @param enable + */ + public void setHidePragmaMark(boolean enable) { + fProvidePragmaMarks = !enable; + } + /* (non-Cdoc) * Method declared on IContentProvider. */ @@ -452,6 +489,7 @@ public class BaseCElementContentProvider implements ITreeContentProvider { protected Object[] getTranslationUnitChildren(ITranslationUnit unit) throws CModelException { Object[] children = unit.getChildren(); + children = filterAndTransformPragmas(children); if (fIncludesGrouping) { boolean hasInclude = false; ArrayList list = new ArrayList<>(children.length); @@ -538,6 +576,42 @@ public class BaseCElementContentProvider implements ITreeContentProvider { return children; } + /** + * Filter and transform pragma elements in the list + * @param children the list of objects + * @return a new list of objects + */ + private Object[] filterAndTransformPragmas(Object[] children) { + List list = new LinkedList<>(Arrays.asList(children)); + boolean isSorted = fIsSorted.getAsBoolean(); + for (ListIterator iterator = list.listIterator(); iterator.hasNext();) { + Object object = iterator.next(); + if (object instanceof IPragma) { + IPragma pragma = (IPragma) object; + // remove the pragma + iterator.remove(); + if (!fProvidePragmaMarks) { + continue; + } + + pragma.getPragmaMarkInfo().ifPresent(info -> { + if (!isSorted && info.isDividerBeforeMark()) { + iterator.add(new DividerLine(pragma)); + } + if (!info.getMarkName().isEmpty()) { + // Add the pragma back in if the mark has something to display + iterator.add(pragma); + } + if (!isSorted && info.isDividerAfterMark()) { + iterator.add(new DividerLine(pragma)); + } + }); + } + } + + return list.toArray(); + } + protected Object[] getNamespaceChildren(IParent element) throws CModelException { Object[] children = element.getChildren(); if (fMemberGrouping) { diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/CPluginImages.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/CPluginImages.java index a69660fcbd9..85e1a497857 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/CPluginImages.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/CPluginImages.java @@ -378,6 +378,7 @@ public class CPluginImages { public static final String IMG_MENU_SHIFT_LEFT = NAME_PREFIX + "shift_l_edit.gif"; //$NON-NLS-1$ public static final String IMG_MENU_OPEN_INCLUDE = NAME_PREFIX + "open_include.gif"; //$NON-NLS-1$ public static final String IMG_MENU_GROUP_INCLUDE = NAME_PREFIX + "group_include.gif"; //$NON-NLS-1$ + public static final String IMG_MENU_HIDE_PRAGMA_MARKS = NAME_PREFIX + "outline_mark.png"; //$NON-NLS-1$ public static final String IMG_MENU_SEGMENT_EDIT = NAME_PREFIX + "segment_edit.gif"; //$NON-NLS-1$ public static final String IMG_MENU_CODE_ASSIST = NAME_PREFIX + "metharg_obj.gif"; //$NON-NLS-1$ public static final String IMG_MENU_COLLAPSE_ALL = NAME_PREFIX + "collapseall.png"; //$NON-NLS-1$ diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/actions/ActionMessages.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/actions/ActionMessages.java index 862faf82193..8617f1b40cd 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/actions/ActionMessages.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/actions/ActionMessages.java @@ -111,6 +111,9 @@ public class ActionMessages extends NLS { public static String CopyQualifiedNameAction_ActionName; public static String CopyQualifiedNameAction_ErrorTitle; public static String CopyQualifiedNameAction_NoElementToQualify; + public static String HidePragmaMarks_label; + public static String HidePragmaMarks_tooltip; + public static String HidePragmaMarks_description; static { // Initialize resource bundle. diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/actions/ActionMessages.properties b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/actions/ActionMessages.properties index baeddfc01b3..626b2de4d34 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/actions/ActionMessages.properties +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/actions/ActionMessages.properties @@ -77,6 +77,10 @@ MacroGroupingAction_label= Group Macros MacroGroupingAction_tooltip= Group macro definitions MacroGroupingAction_description= Group macro definitions +HidePragmaMarks_label=Hide Dividers +HidePragmaMarks_tooltip=Hide Dividers (#pragma mark) +HidePragmaMarks_description=Hide Dividers (#pragma mark) + COutlineInformationControl_viewMenu_sort_label=Sort ChangeBuildConfigMenuAction_title=Sorry diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/cview/DividerLine.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/cview/DividerLine.java new file mode 100644 index 00000000000..5352dbac6d8 --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/cview/DividerLine.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2021 Kichwa Coders Canada 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 + *******************************************************************************/ +package org.eclipse.cdt.internal.ui.cview; + +import org.eclipse.cdt.core.model.ISourceReference; +import org.eclipse.cdt.internal.ui.viewsupport.DecoratingCOutlineLabelProvider; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.ui.model.IWorkbenchAdapter; +import org.eclipse.ui.model.WorkbenchAdapter; + +public class DividerLine extends WorkbenchAdapter implements IAdaptable { + + private ISourceReference element; + + public DividerLine(ISourceReference element) { + this.element = element; + } + + @Override + public T getAdapter(Class adapter) { + if (adapter == IWorkbenchAdapter.class) { + return adapter.cast(this); + } + if (adapter == ISourceReference.class) { + return adapter.cast(element); + } + return null; + } + + /** + * When owner draw is not enabled ( General > Appearance > Use mixed fonts and colors for labels.) + * the custom draw in {@link DecoratingCOutlineLabelProvider} is not used and therefore the + * entry uses the getLabel value to fill the entry. + * @see DecoratingCOutlineLabelProvider + */ + @Override + public String getLabel(Object object) { + return "-".repeat(20); //$NON-NLS-1$ + } +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/AbstractCModelOutlinePage.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/AbstractCModelOutlinePage.java index 93d0ffcca12..10f31d86dd8 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/AbstractCModelOutlinePage.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/AbstractCModelOutlinePage.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2015 IBM Corporation and others. + * Copyright (c) 2005, 2021 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -37,7 +37,7 @@ import org.eclipse.cdt.internal.ui.util.ProblemTreeViewer; import org.eclipse.cdt.internal.ui.viewsupport.AppearanceAwareLabelProvider; import org.eclipse.cdt.internal.ui.viewsupport.CElementLabels; import org.eclipse.cdt.internal.ui.viewsupport.CUILabelProvider; -import org.eclipse.cdt.internal.ui.viewsupport.DecoratingCLabelProvider; +import org.eclipse.cdt.internal.ui.viewsupport.DecoratingCOutlineLabelProvider; import org.eclipse.cdt.ui.CDTSharedImages; import org.eclipse.cdt.ui.CUIPlugin; import org.eclipse.cdt.ui.IncludesGrouping; @@ -52,6 +52,7 @@ import org.eclipse.jface.action.IToolBarManager; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.commands.ActionHandler; +import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.text.ITextSelection; import org.eclipse.jface.util.LocalSelectionTransfer; import org.eclipse.jface.util.PropertyChangeEvent; @@ -60,6 +61,7 @@ import org.eclipse.jface.viewers.IDoubleClickListener; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.LabelProviderChangedEvent; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.TreeViewer; @@ -108,14 +110,18 @@ public abstract class AbstractCModelOutlinePage extends Page public COutlineLabelProvider(long textFlags, int imageFlags) { super(textFlags, imageFlags); + JFaceResources.getFontRegistry().addListener(this); PreferenceConstants.getPreferenceStore().addPropertyChangeListener(this); + PlatformUI.getWorkbench().getThemeManager().getCurrentTheme().getColorRegistry().addListener(this); fSimpleName = PreferenceConstants.getPreferenceStore() .getBoolean(PreferenceConstants.OUTLINE_GROUP_MEMBERS); } @Override public void dispose() { + JFaceResources.getFontRegistry().removeListener(this); PreferenceConstants.getPreferenceStore().removePropertyChangeListener(this); + PlatformUI.getWorkbench().getThemeManager().getCurrentTheme().getColorRegistry().removeListener(this); super.dispose(); } @@ -138,6 +144,15 @@ public abstract class AbstractCModelOutlinePage extends Page .getBoolean(PreferenceConstants.OUTLINE_GROUP_MEMBERS); } } + if (PreferenceConstants.OUTLINE_MARK_TEXT_FONT.equals(event.getProperty())) { + fireLabelProviderChanged(new LabelProviderChangedEvent(this)); + } + if (PreferenceConstants.OUTLINE_MARK_TEXT_COLOR.equals(event.getProperty())) { + fireLabelProviderChanged(new LabelProviderChangedEvent(this)); + } + if (PreferenceConstants.OUTLINE_MARK_DIVIDER_COLOR.equals(event.getProperty())) { + fireLabelProviderChanged(new LabelProviderChangedEvent(this)); + } } } @@ -240,6 +255,29 @@ public abstract class AbstractCModelOutlinePage extends Page } } + protected static class HidePragmaMarkAction extends Action { + + public HidePragmaMarkAction(AbstractCModelOutlinePage outlinePage) { + super(ActionMessages.HidePragmaMarks_label); + setDescription(ActionMessages.HidePragmaMarks_description); + setToolTipText(ActionMessages.HidePragmaMarks_tooltip); + CPluginImages.setImageDescriptors(this, CPluginImages.T_LCL, CPluginImages.IMG_MENU_HIDE_PRAGMA_MARKS); + + boolean enabled = isHidePragmaMarkEnabled(); + setChecked(enabled); + } + + @Override + public void run() { + PreferenceConstants.getPreferenceStore().setValue(PreferenceConstants.OUTLINE_HIDE_PRAGMA_MARK, + isChecked()); + } + + public boolean isHidePragmaMarkEnabled() { + return PreferenceConstants.getPreferenceStore().getBoolean(PreferenceConstants.OUTLINE_HIDE_PRAGMA_MARK); + } + } + /** * This action toggles whether this C Outline page links * its selection to the active editor. @@ -454,7 +492,7 @@ public abstract class AbstractCModelOutlinePage extends Page protected ProblemTreeViewer createTreeViewer(Composite parent) { ProblemTreeViewer treeViewer = new OutlineTreeViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL); treeViewer.setContentProvider(createContentProvider(treeViewer)); - treeViewer.setLabelProvider(new DecoratingCLabelProvider(createLabelProvider(), true)); + treeViewer.setLabelProvider(new DecoratingCOutlineLabelProvider(createLabelProvider())); treeViewer.setAutoExpandLevel(3); treeViewer.setUseHashlookup(true); treeViewer.addSelectionChangedListener(this); @@ -604,6 +642,8 @@ public abstract class AbstractCModelOutlinePage extends Page fToggleLinkingAction = new ToggleLinkingAction(); menu.add(fToggleLinkingAction); + menu.add(new Separator("dividers.layout")); //$NON-NLS-1$ + menu.add(new HidePragmaMarkAction(this)); menu.add(new Separator("group.layout")); //$NON-NLS-1$ menu.add(new IncludeGroupingAction(this)); menu.add(new MacroGroupingAction(this)); diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CContentOutlinerProvider.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CContentOutlinerProvider.java index 9da4664ef72..8bf77fb379b 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CContentOutlinerProvider.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CContentOutlinerProvider.java @@ -71,13 +71,18 @@ public class CContentOutlinerProvider extends BaseCElementContentProvider { * Tree viewer. */ public CContentOutlinerProvider(TreeViewer viewer, IWorkbenchPartSite site) { - super(true, true); + super(true, true, true, () -> isSorted(viewer)); treeViewer = viewer; final IPreferenceStore store = PreferenceConstants.getPreferenceStore(); setIncludesGrouping(store.getBoolean(PreferenceConstants.OUTLINE_GROUP_INCLUDES)); setNamespacesGrouping(store.getBoolean(PreferenceConstants.OUTLINE_GROUP_NAMESPACES)); setMemberGrouping(store.getBoolean(PreferenceConstants.OUTLINE_GROUP_MEMBERS)); setMacroGrouping(store.getBoolean(PreferenceConstants.OUTLINE_GROUP_MACROS)); + setHidePragmaMark(store.getBoolean(PreferenceConstants.OUTLINE_HIDE_PRAGMA_MARK)); + } + + private static boolean isSorted(TreeViewer viewer) { + return viewer != null && viewer.getComparator() != null; } /** @@ -376,6 +381,15 @@ public class CContentOutlinerProvider extends BaseCElementContentProvider { contentUpdated(); } } + } else if (prop.equals(PreferenceConstants.OUTLINE_HIDE_PRAGMA_MARK)) { + Object newValue = event.getNewValue(); + if (newValue instanceof Boolean) { + boolean value = ((Boolean) newValue).booleanValue(); + if (isHidePragmaMarkEnabled() != value) { + setHidePragmaMark(value); + contentUpdated(); + } + } } } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/AppearancePreferencePage.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/AppearancePreferencePage.java index 23a90c5f6bf..56bc31a791a 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/AppearancePreferencePage.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/AppearancePreferencePage.java @@ -56,6 +56,7 @@ public class AppearancePreferencePage extends PreferencePage implements IWorkben private SelectionButtonDialogField fOutlineGroupMacros; private SelectionButtonDialogField fShowSourceRootsAtTopOfProject; private SelectionButtonDialogField fCViewSortOrderOfExcludedFiles; + private SelectionButtonDialogField fOutlineHidePragmaMarks; public AppearancePreferencePage() { setPreferenceStore(PreferenceConstants.getPreferenceStore()); @@ -102,6 +103,10 @@ public class AppearancePreferencePage extends PreferencePage implements IWorkben fOutlineGroupMacros.setDialogFieldListener(listener); fOutlineGroupMacros.setLabelText(PreferencesMessages.AppearancePreferencePage_outlineGroupMacros_label); + fOutlineHidePragmaMarks = new SelectionButtonDialogField(SWT.CHECK); + fOutlineHidePragmaMarks.setDialogFieldListener(listener); + fOutlineHidePragmaMarks.setLabelText(PreferencesMessages.AppearancePreferencePage_HidePragmaMarks_label); + fCViewGroupMacros = new SelectionButtonDialogField(SWT.CHECK); fCViewGroupMacros.setDialogFieldListener(listener); fCViewGroupMacros.setLabelText(PreferencesMessages.AppearancePreferencePage_cviewGroupMacros_label); @@ -123,6 +128,7 @@ public class AppearancePreferencePage extends PreferencePage implements IWorkben fOutlineGroupNamespaces.setSelection(prefs.getBoolean(PreferenceConstants.OUTLINE_GROUP_NAMESPACES)); fOutlineGroupMembers.setSelection(prefs.getBoolean(PreferenceConstants.OUTLINE_GROUP_MEMBERS)); fOutlineGroupMacros.setSelection(prefs.getBoolean(PreferenceConstants.OUTLINE_GROUP_MACROS)); + fOutlineHidePragmaMarks.setSelection(prefs.getBoolean(PreferenceConstants.OUTLINE_HIDE_PRAGMA_MARK)); boolean showSourceRootsAtTopOfProject = CCorePlugin.showSourceRootsAtTopOfProject(); fShowSourceRootsAtTopOfProject.setSelection(showSourceRootsAtTopOfProject); fCViewSortOrderOfExcludedFiles.setSelection(prefs.getBoolean(PreferenceConstants.SORT_ORDER_OF_EXCLUDED_FILES)); @@ -159,6 +165,7 @@ public class AppearancePreferencePage extends PreferencePage implements IWorkben fOutlineGroupMembers.doFillIntoGrid(result, nColumns); fCViewGroupMacros.doFillIntoGrid(result, nColumns); fOutlineGroupMacros.doFillIntoGrid(result, nColumns); + fOutlineHidePragmaMarks.doFillIntoGrid(result, nColumns); new Separator().doFillIntoGrid(result, nColumns); @@ -216,6 +223,7 @@ public class AppearancePreferencePage extends PreferencePage implements IWorkben prefs.setValue(PreferenceConstants.OUTLINE_GROUP_NAMESPACES, fOutlineGroupNamespaces.isSelected()); prefs.setValue(PreferenceConstants.OUTLINE_GROUP_MEMBERS, fOutlineGroupMembers.isSelected()); prefs.setValue(PreferenceConstants.OUTLINE_GROUP_MACROS, fOutlineGroupMacros.isSelected()); + prefs.setValue(PreferenceConstants.OUTLINE_HIDE_PRAGMA_MARK, fOutlineHidePragmaMarks.isSelected()); prefs.setValue(PreferenceConstants.SORT_ORDER_OF_EXCLUDED_FILES, fCViewSortOrderOfExcludedFiles.isSelected()); try { InstanceScope.INSTANCE.getNode(CUIPlugin.PLUGIN_ID).flush(); @@ -244,6 +252,7 @@ public class AppearancePreferencePage extends PreferencePage implements IWorkben fOutlineGroupNamespaces.setSelection(prefs.getDefaultBoolean(PreferenceConstants.OUTLINE_GROUP_NAMESPACES)); fOutlineGroupMembers.setSelection(prefs.getDefaultBoolean(PreferenceConstants.OUTLINE_GROUP_MEMBERS)); fOutlineGroupMacros.setSelection(prefs.getDefaultBoolean(PreferenceConstants.OUTLINE_GROUP_MACROS)); + fOutlineHidePragmaMarks.setSelection(prefs.getDefaultBoolean(PreferenceConstants.OUTLINE_HIDE_PRAGMA_MARK)); boolean showSourceRootsPref = DefaultScope.INSTANCE.getNode(CCorePlugin.PLUGIN_ID) .getBoolean(CCorePreferenceConstants.SHOW_SOURCE_ROOTS_AT_TOP_LEVEL_OF_PROJECT, true); fShowSourceRootsAtTopOfProject.setSelection(showSourceRootsPref); diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/PreferencesMessages.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/PreferencesMessages.java index 4298052a36c..a0e29530635 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/PreferencesMessages.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/PreferencesMessages.java @@ -155,6 +155,7 @@ public final class PreferencesMessages extends NLS { public static String AppearancePreferencePage_outlineGroupMethods_label; public static String AppearancePreferencePage_outlineGroupNamespaces_label; public static String AppearancePreferencePage_outlineGroupMacros_label; + public static String AppearancePreferencePage_HidePragmaMarks_label; public static String AppearancePreferencePage_note; public static String AppearancePreferencePage_preferenceOnlyForNewViews; public static String AppearancePreferencePage_showSourceRootsAtTopOfProject_label; diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/PreferencesMessages.properties b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/PreferencesMessages.properties index 7a42b567672..43f7929aea8 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/PreferencesMessages.properties +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/PreferencesMessages.properties @@ -188,6 +188,7 @@ AppearancePreferencePage_outlineGroupNamespaces_label= Group namespaces in the O AppearancePreferencePage_note=Note: AppearancePreferencePage_preferenceOnlyForNewViews=These two preferences do not affect open views AppearancePreferencePage_outlineGroupMacros_label=Group macro definitions in the Outline view +AppearancePreferencePage_HidePragmaMarks_label=Hide Dividers (#pragma mark) in the Outline view AppearancePreferencePage_showSourceRootsAtTopOfProject_label=Show source roots at top of project #Build Logging diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/COutlineInformationControl.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/COutlineInformationControl.java index 464924753d1..23e9404c5a0 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/COutlineInformationControl.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/COutlineInformationControl.java @@ -23,7 +23,7 @@ import org.eclipse.cdt.internal.ui.editor.LexicalSortingAction; import org.eclipse.cdt.internal.ui.util.ProblemTreeViewer; import org.eclipse.cdt.internal.ui.viewsupport.AppearanceAwareLabelProvider; import org.eclipse.cdt.internal.ui.viewsupport.CElementLabels; -import org.eclipse.cdt.internal.ui.viewsupport.DecoratingCLabelProvider; +import org.eclipse.cdt.internal.ui.viewsupport.DecoratingCOutlineLabelProvider; import org.eclipse.cdt.ui.PreferenceConstants; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.Separator; @@ -84,7 +84,7 @@ public class COutlineInformationControl extends AbstractInformationControl { if (PreferenceConstants.getPreferenceStore().getBoolean(PreferenceConstants.OUTLINE_GROUP_MEMBERS)) textFlags = textFlags | CElementLabels.M_SIMPLE_NAME | CElementLabels.F_SIMPLE_NAME; treeViewer.setLabelProvider( - new DecoratingCLabelProvider(new AppearanceAwareLabelProvider(textFlags, IMAGE_FLAGS), true)); + new DecoratingCOutlineLabelProvider(new AppearanceAwareLabelProvider(textFlags, IMAGE_FLAGS))); treeViewer.setAutoExpandLevel(AbstractTreeViewer.ALL_LEVELS); return treeViewer; } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/viewsupport/CElementImageProvider.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/viewsupport/CElementImageProvider.java index bc4bbcabd1e..50b5a652a75 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/viewsupport/CElementImageProvider.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/viewsupport/CElementImageProvider.java @@ -18,6 +18,7 @@ package org.eclipse.cdt.internal.ui.viewsupport; import java.util.HashMap; import java.util.Map; +import java.util.Optional; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.model.CModelException; @@ -36,6 +37,8 @@ import org.eclipse.cdt.core.model.IInclude; import org.eclipse.cdt.core.model.IIncludeReference; import org.eclipse.cdt.core.model.ILibraryReference; import org.eclipse.cdt.core.model.IMethodDeclaration; +import org.eclipse.cdt.core.model.IPragma; +import org.eclipse.cdt.core.model.IPragma.PragmaMarkInfo; import org.eclipse.cdt.core.model.ISourceReference; import org.eclipse.cdt.core.model.ISourceRoot; import org.eclipse.cdt.core.model.ITemplate; @@ -484,6 +487,15 @@ public class CElementImageProvider { case ICElement.C_USING: return getUsingImageDescriptor(); + case ICElement.C_PRAGMA: + IPragma pragma = (IPragma) celement; + Optional pragmaMarkInfo = pragma.getPragmaMarkInfo(); + if (pragmaMarkInfo.isPresent()) { + return CDTSharedImages.getImageDescriptor(CDTSharedImages.IMG_OUTLINE_MARK); + } else { + return null; + } + default: return getImageDescriptor(type); } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/viewsupport/CElementLabelComposer.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/viewsupport/CElementLabelComposer.java index 27a5712453b..555d85ab0f5 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/viewsupport/CElementLabelComposer.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/viewsupport/CElementLabelComposer.java @@ -16,6 +16,8 @@ *******************************************************************************/ package org.eclipse.cdt.internal.ui.viewsupport; +import java.util.Optional; + import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.model.CModelException; import org.eclipse.cdt.core.model.IBinary; @@ -27,6 +29,8 @@ import org.eclipse.cdt.core.model.IFunctionDeclaration; import org.eclipse.cdt.core.model.IInheritance; import org.eclipse.cdt.core.model.IMacro; import org.eclipse.cdt.core.model.IMethodDeclaration; +import org.eclipse.cdt.core.model.IPragma; +import org.eclipse.cdt.core.model.IPragma.PragmaMarkInfo; import org.eclipse.cdt.core.model.ISourceRoot; import org.eclipse.cdt.core.model.ITemplate; import org.eclipse.cdt.core.model.ITranslationUnit; @@ -35,12 +39,18 @@ import org.eclipse.cdt.core.model.IVariableDeclaration; import org.eclipse.cdt.core.parser.ast.ASTAccessVisibility; import org.eclipse.cdt.internal.core.model.CoreModelMessages; import org.eclipse.cdt.ui.CUIPlugin; +import org.eclipse.cdt.ui.PreferenceConstants; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; +import org.eclipse.jface.resource.ColorRegistry; +import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.viewers.StyledString; import org.eclipse.jface.viewers.StyledString.Styler; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.TextStyle; +import org.eclipse.ui.PlatformUI; // Most parts of this file were previously located in CElementLabels. // FlexibleBuffer and sub-types are taken from JDTs JavaElementLabelComposer. @@ -214,6 +224,9 @@ public class CElementLabelComposer { case ICElement.C_MACRO: appendMacroLabel((IMacro) element, flags); break; + case ICElement.C_PRAGMA: + appendPragmaLabel((IPragma) element, flags); + break; case ICElement.C_METHOD: case ICElement.C_METHOD_DECLARATION: case ICElement.C_TEMPLATE_METHOD: @@ -312,6 +325,45 @@ public class CElementLabelComposer { } } + /** + * Appends the label for a pragma definition to a StringBuilder. + * @param pragma a pragma + * @param flags {@link CElementLabels#MF_POST_FILE_QUALIFIED}, or 0. + */ + public void appendPragmaLabel(IPragma pragma, long flags) { + Optional pragmaMarkInfo = pragma.getPragmaMarkInfo(); + String display = pragmaMarkInfo.map(PragmaMarkInfo::getMarkName).orElseGet(() -> pragma.getElementName()); + int displayOffset = fBuffer.length(); + fBuffer.append(display); + if (pragmaMarkInfo.isPresent()) { + if (getFlag(flags, CElementLabels.COLORIZE)) { + Styler styler = new Styler() { + @Override + public void applyStyles(TextStyle textStyle) { + textStyle.font = JFaceResources.getFont(PreferenceConstants.OUTLINE_MARK_TEXT_FONT); + ColorRegistry colorRegistry = PlatformUI.getWorkbench().getThemeManager().getCurrentTheme() + .getColorRegistry(); + textStyle.foreground = new Color( + colorRegistry.getRGB(PreferenceConstants.OUTLINE_MARK_TEXT_COLOR)); + } + }; + fBuffer.setStyle(displayOffset, fBuffer.length() - displayOffset, styler); + } + } + + if (getFlag(flags, CElementLabels.MF_POST_FILE_QUALIFIED)) { + IPath path = pragma.getPath(); + if (path != null) { + int offset = fBuffer.length(); + fBuffer.append(CElementLabels.CONCAT_STRING); + fBuffer.append(path.toString()); + if (getFlag(flags, CElementLabels.COLORIZE)) { + fBuffer.setStyle(offset, fBuffer.length() - offset, QUALIFIER_STYLE); + } + } + } + } + /** * Appends the label for a method declaration to a StringBuilder. * @param method a method declaration diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/viewsupport/DecoratingCOutlineLabelProvider.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/viewsupport/DecoratingCOutlineLabelProvider.java new file mode 100644 index 00000000000..95825d28109 --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/viewsupport/DecoratingCOutlineLabelProvider.java @@ -0,0 +1,77 @@ +/******************************************************************************* + * Copyright (c) 2021 Kichwa Coders Canada 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 + *******************************************************************************/ +package org.eclipse.cdt.internal.ui.viewsupport; + +import org.eclipse.cdt.internal.ui.cview.DividerLine; +import org.eclipse.cdt.ui.PreferenceConstants; +import org.eclipse.jface.resource.ColorRegistry; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Event; +import org.eclipse.ui.PlatformUI; + +/** + * Specialization of the C label provider that allows drawing divider lines used + * in Outline view and information control + */ +public class DecoratingCOutlineLabelProvider extends DecoratingCLabelProvider { + + private static final int MAXIMUM_REASONABLE_WIDTH = 4000; + + public DecoratingCOutlineLabelProvider(CUILabelProvider labelProvider) { + super(labelProvider, true); + } + + @Override + protected void measure(Event event, Object element) { + if (!isOwnerDrawEnabled()) + return; + if (element instanceof DividerLine) { + GC gc = event.gc; + if (gc == null) { + // If there is no gc (can this happen?) default to a reasonably wide measurement + event.width = MAXIMUM_REASONABLE_WIDTH; + } else { + // Use the clipping area of the event to know how wide the tree control + // is so that we can make a line exactly the right size. + // This has the side effect the tree can never become narrower than this + // width as the width of the tree is in part based on the width of its + // widest item. Therefore if the view becomes smaller, a horizontal + // scroll bar is created + // We use a max of MAXIMUM_REASONABLE_WIDTH here to ensure that we don't + // end up in a loop that the item asks for a wider width, so the tree gets wider, etc. + Rectangle clipping = gc.getClipping(); + event.width = Math.min(clipping.width - event.x, MAXIMUM_REASONABLE_WIDTH); + } + } else { + super.measure(event, element); + } + } + + @Override + protected void paint(Event event, Object element) { + if (!isOwnerDrawEnabled()) + return; + if (element instanceof DividerLine) { + int y = event.y + event.height / 2; + ColorRegistry colorRegistry = PlatformUI.getWorkbench().getThemeManager().getCurrentTheme() + .getColorRegistry(); + event.gc.setForeground(new Color(colorRegistry.getRGB(PreferenceConstants.OUTLINE_MARK_DIVIDER_COLOR))); + // draw a line as wide as possible, we can't use event.width here as that doesn't take into account + // our declared width in measure. On Windows this is clipped to the size we measured above, but + // on GTK and macOS this is clipped to the containing tree control. + event.gc.drawLine(0, y, event.x + MAXIMUM_REASONABLE_WIDTH, y); + } else { + super.paint(event, element); + } + } +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/CDTSharedImages.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/CDTSharedImages.java index d309556f2db..08180632a8c 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/CDTSharedImages.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/CDTSharedImages.java @@ -214,6 +214,9 @@ public class CDTSharedImages { public static final String IMG_VIEW_PIN_ACTION_B = "icons/obj16/toolbar_pinned_b.gif"; //$NON-NLS-1$ public static final String IMG_VIEW_PIN_ACTION_MULTI = "icons/obj16/toolbar_pinned_multi.gif"; //$NON-NLS-1$ + /** @since 7.3*/ + public static final String IMG_OUTLINE_MARK = "icons/obj16/outline_mark.png"; //$NON-NLS-1$ + private static SharedImagesFactory imagesFactory = new SharedImagesFactory(CUIPlugin.getDefault()); /** diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/CElementContentProvider.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/CElementContentProvider.java index 979f4f92984..6e567e6df84 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/CElementContentProvider.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/CElementContentProvider.java @@ -97,7 +97,7 @@ public class CElementContentProvider extends BaseCElementContentProvider * Creates a new content provider for C elements. */ public CElementContentProvider(boolean provideMembers, boolean provideWorkingCopy) { - super(provideMembers, provideWorkingCopy); + super(provideMembers, provideWorkingCopy, false, () -> false); } @Override diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/PreferenceConstants.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/PreferenceConstants.java index 42d615b7390..25ad5dd52e0 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/PreferenceConstants.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/PreferenceConstants.java @@ -560,6 +560,24 @@ public class PreferenceConstants { */ public final static String EDITOR_TEXT_FONT = "org.eclipse.cdt.ui.editors.textfont"; //$NON-NLS-1$ + /** + * The symbolic font name for the C/C++ outline pragma mark or pragma region text font. + * @since 7.3 + */ + public final static String OUTLINE_MARK_TEXT_FONT = "org.eclipse.cdt.ui.outline.mark.textfont"; //$NON-NLS-1$ + + /** + * The color preference for the C/C++ outline pragma mark or pragma region text font color. + * @since 7.3 + */ + public final static String OUTLINE_MARK_TEXT_COLOR = "org.eclipse.cdt.ui.outline.mark.textcolor"; //$NON-NLS-1$ + + /** + * The color preference for the C/C++ outline pragma mark or pragma region divider color. + * @since 7.3 + */ + public final static String OUTLINE_MARK_DIVIDER_COLOR = "org.eclipse.cdt.ui.outline.mark.dividercolor"; //$NON-NLS-1$ + /** * A named preference that controls whether the cview's selection is linked to the active * editor. @@ -766,6 +784,14 @@ public class PreferenceConstants { */ public static final String OUTLINE_LINK_TO_EDITOR = "org.eclipse.cdt.ui.outline.linktoeditor"; //$NON-NLS-1$ + /** + * A named preference that controls whether the Outline view should hide pragma mark directives. + *

+ * Value is of type {@code Boolean}. + * @since 7.3 + */ + public static final String OUTLINE_HIDE_PRAGMA_MARK = "org.eclipse.cdt.ui.outline.hidePragmaMark"; //$NON-NLS-1$ + /** * A named preference that controls whether include directives should be grouped in * the C/C++ Projects view and the Project Explorer view.