Skip to content

Commit

Permalink
add custom folding regions
Browse files Browse the repository at this point in the history
  • Loading branch information
danthe1st committed Dec 7, 2024
1 parent 77f5098 commit a8a21b5
Show file tree
Hide file tree
Showing 7 changed files with 186 additions and 26 deletions.
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

0 comments on commit a8a21b5

Please sign in to comment.