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..e933fe66c2a 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; @@ -27,6 +27,7 @@ import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Text; import org.eclipse.jface.preference.IPreferenceStore; @@ -59,6 +60,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 +82,8 @@ 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.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 +96,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 outer= new Composite(composite, SWT.NONE); + outer.setLayout(layout); + + Composite initialFoldingComposite= new Composite(outer, SWT.NONE); + initialFoldingComposite.setLayout(layout); + + Label initialFoldLabel= new Label(initialFoldingComposite, SWT.LEFT); + initialFoldLabel.setText(FoldingMessages.DefaultJavaFoldingPreferenceBlock_title); + + addCheckBox(initialFoldingComposite, FoldingMessages.DefaultJavaFoldingPreferenceBlock_comments, PreferenceConstants.EDITOR_FOLDING_JAVADOC, 0); + addCheckBox(initialFoldingComposite, FoldingMessages.DefaultJavaFoldingPreferenceBlock_headers, PreferenceConstants.EDITOR_FOLDING_HEADERS, 0); + addCheckBox(initialFoldingComposite, FoldingMessages.DefaultJavaFoldingPreferenceBlock_innerTypes, PreferenceConstants.EDITOR_FOLDING_INNERTYPES, 0); + addCheckBox(initialFoldingComposite, FoldingMessages.DefaultJavaFoldingPreferenceBlock_methods, PreferenceConstants.EDITOR_FOLDING_METHODS, 0); + addCheckBox(initialFoldingComposite, FoldingMessages.DefaultJavaFoldingPreferenceBlock_imports, PreferenceConstants.EDITOR_FOLDING_IMPORTS, 0); + + Composite customRegionComposite= new Composite(outer, SWT.NONE); + GridLayout customRegionLayout= new GridLayout(2, false); + customRegionLayout.verticalSpacing= 3; + customRegionLayout.marginWidth= 0; + customRegionComposite.setLayout(customRegionLayout); + Label customRegionLabel= new Label(customRegionComposite, SWT.LEFT); + customRegionLabel.setLayoutData(new GridData(SWT.BEGINNING, SWT.BEGINNING, false, false, 2, 1)); + customRegionLabel.setText(FoldingMessages.DefaultJavaFoldingPreferenceBlock_custom_region_title); + addStringInput(customRegionComposite, FoldingMessages.DefaultJavaFoldingPreferenceBlock_CustomRegionStart, PreferenceConstants.EDITOR_FOLDING_CUSTOM_REGION_START); + addStringInput(customRegionComposite, FoldingMessages.DefaultJavaFoldingPreferenceBlock_CustomRegionEnd, PreferenceConstants.EDITOR_FOLDING_CUSTOM_REGION_END); + return outer; } private Button addCheckBox(Composite parent, String label, String key, int indentation) { @@ -121,13 +144,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..13cd8ffda1c 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,10 @@ private FoldingMessages() { public static String DefaultJavaFoldingPreferenceBlock_methods; public static String DefaultJavaFoldingPreferenceBlock_imports; public static String DefaultJavaFoldingPreferenceBlock_headers; + + 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..b08f1882155 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 @@ -20,6 +20,10 @@ DefaultJavaFoldingPreferenceBlock_methods= &Members DefaultJavaFoldingPreferenceBlock_imports= &Imports DefaultJavaFoldingPreferenceBlock_headers= &Header Comments +DefaultJavaFoldingPreferenceBlock_custom_region_title=Custom regions: +DefaultJavaFoldingPreferenceBlock_CustomRegionStart= Start of custom folding regions +DefaultJavaFoldingPreferenceBlock_CustomRegionEnd= End of custom folding region + JavaFoldingStructureProviderRegistry_warning_providerNotFound_resetToDefault= The ''{0}'' folding provider could not be found. Resetting to the default folding provider. EmptyJavaFoldingPreferenceBlock_emptyCaption= 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..061ef4507db 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,26 @@ private PreferenceConstants() { */ public static final String EDITOR_FOLDING_HEADERS= "editor_folding_default_headers"; //$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 +4308,8 @@ 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_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..40413bafae5 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,8 @@ protected final class FoldingStructureComputationContext { private IScanner fDefaultScanner; // this one may or not be the shared DefaultJavaFoldingStructureProvider.fSharedScanner private IScanner fScannerForProject; + private Deque customRegions = new ArrayDeque<>(); + private FoldingStructureComputationContext(IDocument document, ProjectionAnnotationModel model, boolean allowCollapsing, IScanner scanner) { Assert.isNotNull(document); Assert.isNotNull(model); @@ -734,6 +738,10 @@ public void projectionDisabled() { private boolean fCollapseMembers= false; private boolean fCollapseHeaderComments= true; + 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). */ private final Filter fMemberFilter = new MemberFilter(); @@ -906,6 +914,10 @@ private void initializePreferences() { fCollapseJavadoc= store.getBoolean(PreferenceConstants.EDITOR_FOLDING_JAVADOC); fCollapseMembers= store.getBoolean(PreferenceConstants.EDITOR_FOLDING_METHODS); fCollapseHeaderComments= store.getBoolean(PreferenceConstants.EDITOR_FOLDING_HEADERS); + 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) { @@ -1151,6 +1163,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 +1175,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 +1190,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 +1223,22 @@ 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.customRegions.add(start); + } + if (currentTokenSource.contains(fCustomFoldingRegionEnd) && !ctx.customRegions.isEmpty()) { + int end= scanner.getCurrentTokenEndPosition() + 1; + Integer regionStart= ctx.customRegions.removeLast(); + regions.add(regionArrayIndex, new Region(regionStart, end - regionStart)); + } + } + private IRegion computeHeaderComment(FoldingStructureComputationContext ctx) throws JavaModelException { // search at most up to the first type ISourceRange range= ctx.getFirstType().getSourceRange();
+ * Value is of type String. + *
String