diff --git a/org.eclipse.jdt.ui/META-INF/MANIFEST.MF b/org.eclipse.jdt.ui/META-INF/MANIFEST.MF index d1e23212930..e305e62874b 100644 --- a/org.eclipse.jdt.ui/META-INF/MANIFEST.MF +++ b/org.eclipse.jdt.ui/META-INF/MANIFEST.MF @@ -3,7 +3,7 @@ Automatic-Module-Name: org.eclipse.jdt.ui Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.jdt.ui; singleton:=true -Bundle-Version: 3.33.300.qualifier +Bundle-Version: 3.34.0.qualifier Bundle-Activator: org.eclipse.jdt.internal.ui.JavaPlugin Bundle-ActivationPolicy: lazy Bundle-Vendor: %providerName diff --git a/org.eclipse.jdt.ui/pom.xml b/org.eclipse.jdt.ui/pom.xml index 3818bc298e7..bd14d5f10c9 100644 --- a/org.eclipse.jdt.ui/pom.xml +++ b/org.eclipse.jdt.ui/pom.xml @@ -18,7 +18,7 @@ org.eclipse.jdt org.eclipse.jdt.ui - 3.33.300-SNAPSHOT + 3.34.0-SNAPSHOT eclipse-plugin diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/folding/DefaultJavaFoldingPreferenceBlock.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/folding/DefaultJavaFoldingPreferenceBlock.java index b8f64cb15ab..af3c831f686 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/folding/DefaultJavaFoldingPreferenceBlock.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/folding/DefaultJavaFoldingPreferenceBlock.java @@ -15,10 +15,10 @@ import java.util.ArrayList; import java.util.HashMap; -import java.util.Iterator; import java.util.Map; import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.layout.GridData; @@ -26,7 +26,9 @@ import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Group; import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Text; import org.eclipse.jface.preference.IPreferenceStore; @@ -59,6 +61,12 @@ public void widgetSelected(SelectionEvent e) { fOverlayStore.setValue(fCheckBoxes.get(button), button.getSelection()); } }; + private Map fStringInputs= new HashMap<>(); + private ModifyListener fModifyListener = e -> { + Text text = (Text)e.widget; + fOverlayStore.setValue(fStringInputs.get(text), text.getText()); + }; + public DefaultJavaFoldingPreferenceBlock() { @@ -75,6 +83,9 @@ private OverlayKey[] createKeys() { overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, PreferenceConstants.EDITOR_FOLDING_METHODS)); overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, PreferenceConstants.EDITOR_FOLDING_IMPORTS)); overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, PreferenceConstants.EDITOR_FOLDING_HEADERS)); + overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, PreferenceConstants.EDITOR_FOLDING_CUSTOM_REGIONS)); + overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.STRING, PreferenceConstants.EDITOR_FOLDING_CUSTOM_REGION_START)); + overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.STRING, PreferenceConstants.EDITOR_FOLDING_CUSTOM_REGION_END)); return overlayKeys.toArray(new OverlayKey[overlayKeys.size()]); } @@ -87,22 +98,36 @@ public Control createControl(Composite composite) { fOverlayStore.load(); fOverlayStore.start(); - Composite inner= new Composite(composite, SWT.NONE); GridLayout layout= new GridLayout(1, true); layout.verticalSpacing= 3; layout.marginWidth= 0; - inner.setLayout(layout); - - Label label= new Label(inner, SWT.LEFT); - label.setText(FoldingMessages.DefaultJavaFoldingPreferenceBlock_title); - - addCheckBox(inner, FoldingMessages.DefaultJavaFoldingPreferenceBlock_comments, PreferenceConstants.EDITOR_FOLDING_JAVADOC, 0); - addCheckBox(inner, FoldingMessages.DefaultJavaFoldingPreferenceBlock_headers, PreferenceConstants.EDITOR_FOLDING_HEADERS, 0); - addCheckBox(inner, FoldingMessages.DefaultJavaFoldingPreferenceBlock_innerTypes, PreferenceConstants.EDITOR_FOLDING_INNERTYPES, 0); - addCheckBox(inner, FoldingMessages.DefaultJavaFoldingPreferenceBlock_methods, PreferenceConstants.EDITOR_FOLDING_METHODS, 0); - addCheckBox(inner, FoldingMessages.DefaultJavaFoldingPreferenceBlock_imports, PreferenceConstants.EDITOR_FOLDING_IMPORTS, 0); - - return inner; + composite.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false)); + + Composite outer= new Composite(composite, SWT.NONE); + outer.setLayout(layout); + outer.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + + Group initialFoldingGroup= new Group(outer, SWT.NONE); + initialFoldingGroup.setLayout(layout); + initialFoldingGroup.setText(FoldingMessages.DefaultJavaFoldingPreferenceBlock_title); + initialFoldingGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + + addCheckBox(initialFoldingGroup, FoldingMessages.DefaultJavaFoldingPreferenceBlock_comments, PreferenceConstants.EDITOR_FOLDING_JAVADOC, 0); + addCheckBox(initialFoldingGroup, FoldingMessages.DefaultJavaFoldingPreferenceBlock_headers, PreferenceConstants.EDITOR_FOLDING_HEADERS, 0); + addCheckBox(initialFoldingGroup, FoldingMessages.DefaultJavaFoldingPreferenceBlock_innerTypes, PreferenceConstants.EDITOR_FOLDING_INNERTYPES, 0); + addCheckBox(initialFoldingGroup, FoldingMessages.DefaultJavaFoldingPreferenceBlock_methods, PreferenceConstants.EDITOR_FOLDING_METHODS, 0); + addCheckBox(initialFoldingGroup, FoldingMessages.DefaultJavaFoldingPreferenceBlock_imports, PreferenceConstants.EDITOR_FOLDING_IMPORTS, 0); + addCheckBox(initialFoldingGroup, FoldingMessages.DefaultJavaFoldingPreferenceBlock_customRegions, PreferenceConstants.EDITOR_FOLDING_CUSTOM_REGIONS, 0); + + Group customRegionGroup= new Group(outer, SWT.NONE); + customRegionGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + + GridLayout customRegionLayout= new GridLayout(2, false); + customRegionGroup.setLayout(customRegionLayout); + customRegionGroup.setText(FoldingMessages.DefaultJavaFoldingPreferenceBlock_custom_region_title); + addStringInput(customRegionGroup, FoldingMessages.DefaultJavaFoldingPreferenceBlock_CustomRegionStart, PreferenceConstants.EDITOR_FOLDING_CUSTOM_REGION_START); + addStringInput(customRegionGroup, FoldingMessages.DefaultJavaFoldingPreferenceBlock_CustomRegionEnd, PreferenceConstants.EDITOR_FOLDING_CUSTOM_REGION_END); + return outer; } private Button addCheckBox(Composite parent, String label, String key, int indentation) { @@ -121,13 +146,29 @@ private Button addCheckBox(Composite parent, String label, String key, int inden return checkBox; } + private void addStringInput(Composite parent, String label, String key) { + Label labelElement = new Label(parent, SWT.LEFT); + labelElement.setText(label); + GridData labelGridData= new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING); + labelGridData.horizontalSpan= 1; + labelGridData.grabExcessVerticalSpace= false; + labelElement.setLayoutData(labelGridData); + + Text textInput = new Text(parent, SWT.SINGLE | SWT.BORDER); + textInput.setText(label); + textInput.addModifyListener(fModifyListener); + + GridData textGridData= new GridData(SWT.FILL, SWT.BEGINNING, true, false); + textGridData.horizontalSpan= 1; + textGridData.grabExcessVerticalSpace= true; + textInput.setLayoutData(textGridData); + + fStringInputs.put(textInput, key); + } + private void initializeFields() { - Iterator it= fCheckBoxes.keySet().iterator(); - while (it.hasNext()) { - Button b= it.next(); - String key= fCheckBoxes.get(b); - b.setSelection(fOverlayStore.getBoolean(key)); - } + fCheckBoxes.forEach((b, key) -> b.setSelection(fOverlayStore.getBoolean(key))); + fStringInputs.forEach((text, key) -> text.setText(fOverlayStore.getString(key))); } /* diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/folding/FoldingMessages.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/folding/FoldingMessages.java index 92b4ea1637c..8728dba3743 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/folding/FoldingMessages.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/folding/FoldingMessages.java @@ -32,6 +32,11 @@ private FoldingMessages() { public static String DefaultJavaFoldingPreferenceBlock_methods; public static String DefaultJavaFoldingPreferenceBlock_imports; public static String DefaultJavaFoldingPreferenceBlock_headers; + public static String DefaultJavaFoldingPreferenceBlock_customRegions; + + public static String DefaultJavaFoldingPreferenceBlock_custom_region_title; + public static String DefaultJavaFoldingPreferenceBlock_CustomRegionStart; + public static String DefaultJavaFoldingPreferenceBlock_CustomRegionEnd; public static String EmptyJavaFoldingPreferenceBlock_emptyCaption; public static String JavaFoldingStructureProviderRegistry_warning_providerNotFound_resetToDefault; diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/folding/FoldingMessages.properties b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/folding/FoldingMessages.properties index 3a91f5e6f6f..c7859302023 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/folding/FoldingMessages.properties +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/folding/FoldingMessages.properties @@ -19,6 +19,11 @@ DefaultJavaFoldingPreferenceBlock_innerTypes= Inner &types DefaultJavaFoldingPreferenceBlock_methods= &Members DefaultJavaFoldingPreferenceBlock_imports= &Imports DefaultJavaFoldingPreferenceBlock_headers= &Header Comments +DefaultJavaFoldingPreferenceBlock_customRegions= Custom folding regions + +DefaultJavaFoldingPreferenceBlock_custom_region_title= Custom folding regions: +DefaultJavaFoldingPreferenceBlock_CustomRegionStart= Text marking start of custom folding regions +DefaultJavaFoldingPreferenceBlock_CustomRegionEnd= Text marking start end of custom folding regions JavaFoldingStructureProviderRegistry_warning_providerNotFound_resetToDefault= The ''{0}'' folding provider could not be found. Resetting to the default folding provider. diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/PreferenceConstants.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/PreferenceConstants.java index 5b2fd619e15..1734a78ca50 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/PreferenceConstants.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/PreferenceConstants.java @@ -3471,6 +3471,36 @@ private PreferenceConstants() { */ public static final String EDITOR_FOLDING_HEADERS= "editor_folding_default_headers"; //$NON-NLS-1$ + /** + * A named preference that stores the value for custom region folding for the default folding provider. + * + * Value is of type Boolean. + * + * + * @since 3.34 + */ + public static final String EDITOR_FOLDING_CUSTOM_REGIONS= "editor_folding_custom_regions"; //$NON-NLS-1$ + + /** + * A named preference that stores the value for the start indicator of custom folding regions for the default folding provider. + * + * Value is of type String. + * + * + * @since 3.34 + */ + public static final String EDITOR_FOLDING_CUSTOM_REGION_START= "editor_folding_custom_region_start"; //$NON-NLS-1$ + + /** + * A named preference that stores the value for the end indicator of custom folding regions for the default folding provider. + * + * Value is of type String. + * + * + * @since 3.34 + */ + public static final String EDITOR_FOLDING_CUSTOM_REGION_END= "editor_folding_custom_region_end"; //$NON-NLS-1$ + /** * A named preference that holds the methods or types whose methods are by default expanded with * constructors in the Call Hierarchy. @@ -4288,6 +4318,9 @@ public static void initializeDefaultValues(IPreferenceStore store) { store.setDefault(PreferenceConstants.EDITOR_FOLDING_METHODS, false); store.setDefault(PreferenceConstants.EDITOR_FOLDING_IMPORTS, true); store.setDefault(PreferenceConstants.EDITOR_FOLDING_HEADERS, true); + store.setDefault(PreferenceConstants.EDITOR_FOLDING_CUSTOM_REGIONS, false); + store.setDefault(PreferenceConstants.EDITOR_FOLDING_CUSTOM_REGION_START, "#region"); //$NON-NLS-1$ + store.setDefault(PreferenceConstants.EDITOR_FOLDING_CUSTOM_REGION_END, "#endregion"); //$NON-NLS-1$ // properties file editor store.setDefault(PreferenceConstants.PROPERTIES_FILE_COLORING_KEY_BOLD, false); diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/text/folding/DefaultJavaFoldingStructureProvider.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/text/folding/DefaultJavaFoldingStructureProvider.java index e212f37c39a..4658fa02064 100755 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/text/folding/DefaultJavaFoldingStructureProvider.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/text/folding/DefaultJavaFoldingStructureProvider.java @@ -13,11 +13,13 @@ *******************************************************************************/ package org.eclipse.jdt.ui.text.folding; +import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; +import java.util.Deque; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -107,6 +109,9 @@ protected final class FoldingStructureComputationContext { private IScanner fDefaultScanner; // this one may or not be the shared DefaultJavaFoldingStructureProvider.fSharedScanner private IScanner fScannerForProject; + private Deque fOpenCustomRegionStartPositions = new ArrayDeque<>(); + private Set fCurrentCustomRegions = new HashSet<>(); + private FoldingStructureComputationContext(IDocument document, ProjectionAnnotationModel model, boolean allowCollapsing, IScanner scanner) { Assert.isNotNull(document); Assert.isNotNull(model); @@ -245,6 +250,16 @@ public boolean collapseJavadoc() { public boolean collapseMembers() { return fAllowCollapsing && fCollapseMembers; } + + /** + * Returns true if custom regions should be collapsed. + * + * @return true if custom regions should be collapsed + */ + public boolean collapseCustomRegions() { + return fAllowCollapsing && fCollapseCustomRegions; + } + } /** @@ -733,6 +748,11 @@ public void projectionDisabled() { private boolean fCollapseInnerTypes= true; private boolean fCollapseMembers= false; private boolean fCollapseHeaderComments= true; + private boolean fCollapseCustomRegions= false; + + private boolean fCustomFoldingRegionsEnabled= true; + private String fCustomFoldingRegionBegin="#region"; //$NON-NLS-1$ + private String fCustomFoldingRegionEnd="#endregion"; //$NON-NLS-1$ /* filters */ /** Member filter, matches nested members (but not top-level types). */ @@ -906,6 +926,11 @@ private void initializePreferences() { fCollapseJavadoc= store.getBoolean(PreferenceConstants.EDITOR_FOLDING_JAVADOC); fCollapseMembers= store.getBoolean(PreferenceConstants.EDITOR_FOLDING_METHODS); fCollapseHeaderComments= store.getBoolean(PreferenceConstants.EDITOR_FOLDING_HEADERS); + fCollapseCustomRegions= store.getBoolean(PreferenceConstants.EDITOR_FOLDING_CUSTOM_REGIONS); + fCustomFoldingRegionBegin=store.getString(PreferenceConstants.EDITOR_FOLDING_CUSTOM_REGION_START); + fCustomFoldingRegionEnd=store.getString(PreferenceConstants.EDITOR_FOLDING_CUSTOM_REGION_END); + fCustomFoldingRegionsEnabled = !fCustomFoldingRegionBegin.isEmpty() && !fCustomFoldingRegionEnd.isEmpty() && + !fCustomFoldingRegionBegin.contains(fCustomFoldingRegionEnd) && !fCustomFoldingRegionEnd.contains(fCustomFoldingRegionBegin); } private void update(FoldingStructureComputationContext ctx) { @@ -1060,13 +1085,16 @@ protected void computeFoldingStructure(IJavaElement element, FoldingStructureCom if (regions.length > 0) { // comments for (int i= 0; i < regions.length - 1; i++) { - IRegion normalized= alignRegion(regions[i], ctx); + IRegion region= regions[i]; + IRegion normalized= alignRegion(region, ctx); if (normalized != null) { Position position= createCommentPosition(normalized); if (position != null) { boolean commentCollapse; if (i == 0 && (regions.length > 2 || ctx.hasHeaderComment()) && element == ctx.getFirstType()) { commentCollapse= ctx.collapseHeaderComments(); + } else if(ctx.fCurrentCustomRegions.contains(region)) { + commentCollapse= ctx.collapseCustomRegions(); } else { commentCollapse= ctx.collapseJavadoc(); } @@ -1151,6 +1179,7 @@ protected final IRegion[] computeProjectionRanges(ISourceReference reference, Fo scanner.resetTo(shift, shift + range.getLength()); int start= shift; + while (true) { int token= scanner.getNextToken(); @@ -1162,10 +1191,14 @@ protected final IRegion[] computeProjectionRanges(ISourceReference reference, Fo case ITerminalSymbols.TokenNameCOMMENT_BLOCK: { int end= scanner.getCurrentTokenEndPosition() + 1; regions.add(new Region(start, end - start)); - continue; } - case ITerminalSymbols.TokenNameCOMMENT_LINE: + //$FALL-THROUGH$ + case ITerminalSymbols.TokenNameCOMMENT_LINE: { + if (fCustomFoldingRegionsEnabled) { + checkCustomFolding(ctx, regions, scanner, start, regions.size()); + } continue; + } } break; @@ -1173,6 +1206,30 @@ protected final IRegion[] computeProjectionRanges(ISourceReference reference, Fo regions.add(new Region(start, shift + range.getLength() - start)); + if (fCustomFoldingRegionsEnabled) { + if (reference instanceof IJavaElement javaElement && javaElement.getParent() != null && javaElement.getParent() instanceof IParent parent) { + IJavaElement[] siblings= parent.getChildren(); + if (javaElement == siblings[siblings.length-1] && parent instanceof ISourceReference parentSourceReference) { + int regionStart = range.getOffset() + range.getLength(); + ISourceRange parentRange= parentSourceReference.getSourceRange(); + int regionEnd = parentRange.getOffset() + parentRange.getLength(); + scanner.resetTo(regionStart, regionEnd); + for(int token = scanner.getNextToken(); token != ITerminalSymbols.TokenNameEOF; token=scanner.getNextToken()) { + if(isCommentToken(token)) { + checkCustomFolding(ctx, regions, scanner, scanner.getCurrentTokenStartPosition(), regions.size() - 1); + } + } + } + } + if (reference instanceof IParent parent && !parent.hasChildren()) { + for(int token = scanner.getNextToken(); token != ITerminalSymbols.TokenNameEOF; token=scanner.getNextToken()) { + if(isCommentToken(token)) { + checkCustomFolding(ctx, regions, scanner, scanner.getCurrentTokenStartPosition(), regions.size() - 1); + } + } + } + } + IRegion[] result= new IRegion[regions.size()]; regions.toArray(result); return result; @@ -1182,6 +1239,24 @@ protected final IRegion[] computeProjectionRanges(ISourceReference reference, Fo return new IRegion[0]; } + private boolean isCommentToken(int token) { + return token == ITerminalSymbols.TokenNameCOMMENT_BLOCK || token == ITerminalSymbols.TokenNameCOMMENT_JAVADOC || token == ITerminalSymbols.TokenNameCOMMENT_MARKDOWN || token == ITerminalSymbols.TokenNameCOMMENT_LINE; + } + + private void checkCustomFolding(FoldingStructureComputationContext ctx, List regions, IScanner scanner, int start, int regionArrayIndex) { + String currentTokenSource= new String(scanner.getCurrentTokenSource()); + if (currentTokenSource.contains(fCustomFoldingRegionBegin)) { + ctx.fOpenCustomRegionStartPositions.add(start); + } + if (currentTokenSource.contains(fCustomFoldingRegionEnd) && !ctx.fOpenCustomRegionStartPositions.isEmpty()) { + int end= scanner.getCurrentTokenEndPosition() + 1; + Integer regionStart= ctx.fOpenCustomRegionStartPositions.removeLast(); + Region region= new Region(regionStart, end - regionStart); + regions.add(regionArrayIndex, region); + ctx.fCurrentCustomRegions.add(region); + } + } + private IRegion computeHeaderComment(FoldingStructureComputationContext ctx) throws JavaModelException { // search at most up to the first type ISourceRange range= ctx.getFirstType().getSourceRange();
+ * Value is of type Boolean. + *
Boolean
+ * Value is of type String. + *
String
true