Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add custom folding regions #1825

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion org.eclipse.jdt.ui/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion org.eclipse.jdt.ui/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
</parent>
<groupId>org.eclipse.jdt</groupId>
<artifactId>org.eclipse.jdt.ui</artifactId>
<version>3.33.300-SNAPSHOT</version>
<version>3.34.0-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>

<build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,20 @@

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;
import org.eclipse.swt.layout.GridLayout;
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;

Expand Down Expand Up @@ -59,6 +61,12 @@ public void widgetSelected(SelectionEvent e) {
fOverlayStore.setValue(fCheckBoxes.get(button), button.getSelection());
}
};
private Map<Text, String> fStringInputs= new HashMap<>();
private ModifyListener fModifyListener = e -> {
Text text = (Text)e.widget;
fOverlayStore.setValue(fStringInputs.get(text), text.getText());
};



public DefaultJavaFoldingPreferenceBlock() {
Expand All @@ -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()]);
}
Expand All @@ -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) {
Expand All @@ -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<Button> 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)));
}

/*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,17 @@
###############################################################################


DefaultJavaFoldingPreferenceBlock_title= Initially fold these elements:
DefaultJavaFoldingPreferenceBlock_title= Initially fold these elements
DefaultJavaFoldingPreferenceBlock_comments= &Comments
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 end of custom folding regions

JavaFoldingStructureProviderRegistry_warning_providerNotFound_resetToDefault= The ''{0}'' folding provider could not be found. Resetting to the default folding provider.

Expand Down
33 changes: 33 additions & 0 deletions org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/PreferenceConstants.java
Original file line number Diff line number Diff line change
Expand Up @@ -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.
* <p>
* Value is of type <code>Boolean</code>.
* </p>
*
* @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.
* <p>
* Value is of type <code>String</code>.
* </p>
*
* @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.
* <p>
* Value is of type <code>String</code>.
* </p>
*
* @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.
Expand Down Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<Integer> fOpenCustomRegionStartPositions = new ArrayDeque<>();
private Set<Region> fCurrentCustomRegions = new HashSet<>();

private FoldingStructureComputationContext(IDocument document, ProjectionAnnotationModel model, boolean allowCollapsing, IScanner scanner) {
Assert.isNotNull(document);
Assert.isNotNull(model);
Expand Down Expand Up @@ -245,6 +250,17 @@ public boolean collapseJavadoc() {
public boolean collapseMembers() {
return fAllowCollapsing && fCollapseMembers;
}

/**
* Returns <code>true</code> if custom regions should be collapsed.
*
* @return <code>true</code> if custom regions should be collapsed
* @since 3.34
*/
public boolean collapseCustomRegions() {
return fAllowCollapsing && fCollapseCustomRegions;
}

}

/**
Expand Down Expand Up @@ -733,6 +749,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). */
Expand Down Expand Up @@ -906,6 +927,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) {
Expand Down Expand Up @@ -1060,13 +1086,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();
}
Expand Down Expand Up @@ -1151,6 +1180,7 @@ protected final IRegion[] computeProjectionRanges(ISourceReference reference, Fo
scanner.resetTo(shift, shift + range.getLength());

int start= shift;

while (true) {

int token= scanner.getNextToken();
Expand All @@ -1162,17 +1192,45 @@ 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;
}

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;
Expand All @@ -1182,6 +1240,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<IRegion> 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();
Expand Down