Added support for toggling comments with ctrl|cmd+/ in Epsilon editors
diff --git a/plugins/org.eclipse.epsilon.common.dt/plugin.xml b/plugins/org.eclipse.epsilon.common.dt/plugin.xml
index 8be7a30..d76e5f5 100644
--- a/plugins/org.eclipse.epsilon.common.dt/plugin.xml
+++ b/plugins/org.eclipse.epsilon.common.dt/plugin.xml
@@ -77,5 +77,22 @@
class="org.eclipse.epsilon.common.dt.launching.extensions.ModelTypeExtension"
defaultName="modelTypeExtension">
</tool>
+ </extension>
+ <extension
+ point="org.eclipse.ui.bindings">
+ <key
+ commandId="org.eclipse.epsilon.common.dt.editor.AbsractModuleEditor.ToggleComment"
+ contextId="org.eclipse.ui.textEditorScope"
+ schemeId="org.eclipse.ui.defaultAcceleratorConfiguration"
+ sequence="M1+/">
+ </key>
+ </extension>
+ <extension
+ point="org.eclipse.ui.commands">
+ <command
+ categoryId="org.eclipse.ui.category.textEditor"
+ id="org.eclipse.epsilon.common.dt.editor.AbsractModuleEditor.ToggleComment"
+ name="Toggle Comment">
+ </command>
</extension>
</plugin>
diff --git a/plugins/org.eclipse.epsilon.common.dt/src/org/eclipse/epsilon/common/dt/editor/AbstractModuleEditor.java b/plugins/org.eclipse.epsilon.common.dt/src/org/eclipse/epsilon/common/dt/editor/AbstractModuleEditor.java
index 92b7fe0..3572f05 100644
--- a/plugins/org.eclipse.epsilon.common.dt/src/org/eclipse/epsilon/common/dt/editor/AbstractModuleEditor.java
+++ b/plugins/org.eclipse.epsilon.common.dt/src/org/eclipse/epsilon/common/dt/editor/AbstractModuleEditor.java
@@ -10,7 +10,15 @@
package org.eclipse.epsilon.common.dt.editor;
import java.io.File;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
@@ -67,7 +75,7 @@
import org.eclipse.ui.texteditor.TextOperationAction;
public abstract class AbstractModuleEditor extends AbstractDecoratedTextEditor {
-
+
protected Color backgroundColor = null;
protected Job parseModuleJob = null;
protected ArrayList<IModuleParseListener> moduleParsedListeners = new ArrayList<>();
@@ -75,54 +83,53 @@
protected EpsilonHighlightingManager highlightingManager;
public static final String PROBLEM_MARKER = "org.eclipse.epsilon.common.dt.problemmarker";
-
+
private ModuleContentOutlinePage outlinePage;
public AbstractModuleEditor() {
super();
setDocumentProvider(new AbstractModuleEditorDocumentProvider());
setEditorContextMenuId("#TextEditorContext");
- setRulerContextMenuId("editor.rulerMenu");
+ setRulerContextMenuId("editor.rulerMenu");
highlightingManager = new EpsilonHighlightingManager();
highlightingManager.initialiseDefaultColors();
}
-
+
public void addModuleParsedListener(IModuleParseListener listener) {
this.moduleParsedListeners.add(listener);
}
-
+
public ArrayList<IModuleParseListener> getModuleParsedListeners() {
return moduleParsedListeners;
}
-
+
public boolean removeModuleParsedListener(IModuleParseListener listener) {
return moduleParsedListeners.remove(listener);
}
-
+
public void addTemplateContributor(IAbstractModuleEditorTemplateContributor templateContributor) {
this.templateContributors.add(templateContributor);
}
-
+
public boolean removeTemplateContributor(IAbstractModuleEditorTemplateContributor templateContributor) {
return this.templateContributors.remove(templateContributor);
}
-
+
protected void notifyModuleParsedListeners(IModule module) {
for (IModuleParseListener listener : moduleParsedListeners) {
listener.moduleParsed(this, module);
}
}
-
+
public ModuleElement adaptToAST(Object o) {
if (o instanceof ModuleElement) {
return (ModuleElement) o;
- }
- else return null;
+ } else
+ return null;
}
-
+
public void insertText(String text) {
- IDocument doc = this.getDocumentProvider().getDocument(
- this.getEditorInput());
+ IDocument doc = this.getDocumentProvider().getDocument(this.getEditorInput());
TextSelection selection = (TextSelection) getSelectionProvider().getSelection();
try {
doc.replace(selection.getOffset(), 0, text);
@@ -130,26 +137,25 @@
e.printStackTrace();
}
}
-
+
public final static String EDITOR_MATCHING_BRACKETS = "matchingBrackets";
- public final static String EDITOR_MATCHING_BRACKETS_COLOR= "matchingBracketsColor";
-
+ public final static String EDITOR_MATCHING_BRACKETS_COLOR = "matchingBracketsColor";
+
@Override
- protected void configureSourceViewerDecorationSupport(
- SourceViewerDecorationSupport support) {
+ protected void configureSourceViewerDecorationSupport(SourceViewerDecorationSupport support) {
super.configureSourceViewerDecorationSupport(support);
- char[] matchChars = {'(', ')', '[', ']', '{', '}'};
- ICharacterPairMatcher matcher = new DefaultCharacterPairMatcher(matchChars ,
+ char[] matchChars = { '(', ')', '[', ']', '{', '}' };
+ ICharacterPairMatcher matcher = new DefaultCharacterPairMatcher(matchChars,
IDocumentExtension3.DEFAULT_PARTITIONING);
support.setCharacterPairMatcher(matcher);
- support.setMatchingCharacterPainterPreferenceKeys(EDITOR_MATCHING_BRACKETS,EDITOR_MATCHING_BRACKETS_COLOR);
-
+ support.setMatchingCharacterPainterPreferenceKeys(EDITOR_MATCHING_BRACKETS, EDITOR_MATCHING_BRACKETS_COLOR);
+
IPreferenceStore store = getPreferenceStore();
store.setDefault(EDITOR_MATCHING_BRACKETS, true);
store.setDefault(EDITOR_MATCHING_BRACKETS_COLOR, "128,128,128");
}
-
+
@SuppressWarnings("unchecked")
@Override
public <T> T getAdapter(Class<T> required) {
@@ -158,48 +164,41 @@
}
return super.getAdapter(required);
}
-
- //TODO: (fonso) this list seems incomplete with respect to the book list
+
+ // TODO: (fonso) this list seems incomplete with respect to the book list
public List<String> getAssertions() {
return Arrays.asList("assert", "assertError");
}
-
+
public Collection<String> getTypes() {
// The list returned by Arrays.asList cannot be changed in size,
// as it is just a wrapper over the Java array. Therefore, any
// calls to add/remove will return an UnsupportedOperationException.
- return new ArrayList<>(Arrays.asList(
- "String", "Boolean", "Integer", "Real",
- "Any", "Map", "Collection", "Bag", "Sequence",
- "Set", "OrderedSet", "Native", "List", "Tuple",
- "ConcurrentSet", "ConcurrentBag", "ConcurrentMap")
- );
+ return new ArrayList<>(Arrays.asList("String", "Boolean", "Integer", "Real", "Any", "Map", "Collection", "Bag",
+ "Sequence", "Set", "OrderedSet", "Native", "List", "Tuple", "ConcurrentSet", "ConcurrentBag",
+ "ConcurrentMap"));
}
-
+
public abstract List<String> getKeywords();
public abstract List<String> getBuiltinVariables();
public ModuleContentOutlinePage createOutlinePage() {
-
- ModuleContentOutlinePage outline =
- new ModuleContentOutlinePage(
- this.getDocumentProvider(),
- this,
- createModuleElementLabelProvider(),
- createModuleContentProvider());
-
+
+ ModuleContentOutlinePage outline = new ModuleContentOutlinePage(this.getDocumentProvider(), this,
+ createModuleElementLabelProvider(), createModuleContentProvider());
+
addModuleParsedListener(outline);
-
+
return outline;
}
-
+
public abstract IModule createModule();
-
+
public abstract ModuleElementLabelProvider createModuleElementLabelProvider();
-
+
protected abstract ModuleContentProvider createModuleContentProvider();
-
+
ProjectionSupport projectionSupport;
AnnotationModel annotationModel;
@@ -208,33 +207,32 @@
public void createPartControl(Composite parent) {
super.createPartControl(parent);
ProjectionViewer viewer = (ProjectionViewer) getSourceViewer();
- projectionSupport = new ProjectionSupport(viewer,
- getAnnotationAccess(), getSharedColors());
+ projectionSupport = new ProjectionSupport(viewer, getAnnotationAccess(), getSharedColors());
projectionSupport.install();
// turn projection mode on
viewer.doOperation(ProjectionViewer.TOGGLE);
annotationModel = viewer.getProjectionAnnotationModel();
- //updateFoldingStructure();
+ // updateFoldingStructure();
}
@Override
- protected ISourceViewer createSourceViewer(Composite parent,
- IVerticalRuler ruler, int styles) {
+ protected ISourceViewer createSourceViewer(Composite parent, IVerticalRuler ruler, int styles) {
- ISourceViewer viewer = new ProjectionViewer(parent, ruler,
- getOverviewRuler(), isOverviewRulerVisible(), styles);
-
- //IDocument doc = this.getDocumentProvider().getDocument(
- // this.getEditorInput());
- //autoclosingPairManager = new AutoclosingPairManager(doc, getSourceViewerConfiguration().getUndoManager(viewer));
- //viewer.getTextWidget().addVerifyKeyListener(autoclosingPairManager);
+ ISourceViewer viewer = new ProjectionViewer(parent, ruler, getOverviewRuler(), isOverviewRulerVisible(),
+ styles);
+
+ // IDocument doc = this.getDocumentProvider().getDocument(
+ // this.getEditorInput());
+ // autoclosingPairManager = new AutoclosingPairManager(doc,
+ // getSourceViewerConfiguration().getUndoManager(viewer));
+ // viewer.getTextWidget().addVerifyKeyListener(autoclosingPairManager);
getSourceViewerDecorationSupport(viewer);
-
+
return viewer;
}
-
- //TODO : Improve the folding functionality
+
+ // TODO : Improve the folding functionality
// boolean useCodeFolding = false;
//
@@ -276,33 +274,32 @@
// } catch (Exception e) {
// e.printStackTrace();
// }
-
- // annotationModel.modifyAnnotationPosition(annotation,new
- // Position(0,10));
- /*
- * Annotation[] annotations = new Annotation[positions.size()];
- *
- * //this will hold the new annotations along //with their corresponding
- * positions HashMap newAnnotations = new HashMap();
- *
- * for(int i = 0; i < positions.size();i++) { ProjectionAnnotation
- * annotation = new ProjectionAnnotation();
- *
- * newAnnotations.put(annotation, positions.get(i));
- *
- * annotations[i] = annotation; }
- *
- * annotationModel.mmodifyAnnotation(oldAnnotations,
- * newAnnotations,null);
- *
- * oldAnnotations = annotations;
- */
- //}
-
+
+ // annotationModel.modifyAnnotationPosition(annotation,new
+ // Position(0,10));
+ /*
+ * Annotation[] annotations = new Annotation[positions.size()];
+ *
+ * //this will hold the new annotations along //with their corresponding
+ * positions HashMap newAnnotations = new HashMap();
+ *
+ * for(int i = 0; i < positions.size();i++) { ProjectionAnnotation annotation =
+ * new ProjectionAnnotation();
+ *
+ * newAnnotations.put(annotation, positions.get(i));
+ *
+ * annotations[i] = annotation; }
+ *
+ * annotationModel.mmodifyAnnotation(oldAnnotations, newAnnotations,null);
+ *
+ * oldAnnotations = annotations;
+ */
+ // }
+
public SourceViewerConfiguration createSourceViewerConfiguration() {
return new AbstractModuleEditorSourceViewerConfiguration(this);
}
-
+
@Override
public void init(IEditorSite site, IEditorInput input) {
try {
@@ -310,87 +307,86 @@
} catch (PartInitException e) {
e.printStackTrace();
}
-
+
setSourceViewerConfiguration(createSourceViewerConfiguration());
-
+
PlatformUI.getWorkbench().getThemeManager().addPropertyChangeListener(new ThemeChangeListener() {
@Override
public void themeChange() {
highlightingManager.initialiseDefaultColors();
refreshText();
}
-
+
});
-
+
highlightingManager.getPreferenceStore().addPropertyChangeListener(event -> {
if (highlightingManager.isColorPreference(event.getProperty())) {
refreshText();
}
});
-
+
outlinePage = createOutlinePage();
-
-
+
final long delay = 1000;
-
+
parseModuleJob = new Job("Parsing module") {
-
+
protected int status = -1;
-
+
@Override
protected IStatus run(IProgressMonitor monitor) {
-
+
if (!isClosed()) {
int textHashCode = getText().hashCode();
if (status != textHashCode) {
parseModule();
status = textHashCode;
}
-
+
this.schedule(delay);
}
-
+
return Status.OK_STATUS;
}
};
-
+
parseModuleJob.setSystem(true);
parseModuleJob.schedule(delay);
-
+
}
-
+
public boolean isClosed() {
return this.getDocumentProvider() == null;
}
-
+
public String getText() {
- return this.getDocumentProvider().getDocument(
- this.getEditorInput()).get();
+ return this.getDocumentProvider().getDocument(this.getEditorInput()).get();
}
-
+
public void parseModule() {
-
- // Return early if the file is opened in an unexpected editor (e.g. in a Subclipse RemoteFileEditor)
- if (!(getEditorInput() instanceof FileEditorInput)) return;
-
+
+ // Return early if the file is opened in an unexpected editor (e.g. in a
+ // Subclipse RemoteFileEditor)
+ if (!(getEditorInput() instanceof FileEditorInput))
+ return;
+
FileEditorInput fileInputEditor = (FileEditorInput) getEditorInput();
IFile file = fileInputEditor.getFile();
-
+
final IModule module = createModule();
- final IDocument doc = this.getDocumentProvider().getDocument(
- this.getEditorInput());
-
+ final IDocument doc = this.getDocumentProvider().getDocument(this.getEditorInput());
+
// Replace tabs with spaces to match
// column numbers produced by the parser
String code = doc.get();
code = code.replaceAll("\t", " ");
-
+
try {
module.parse(code, new File(file.getLocation().toOSString()));
} catch (Exception e) {
-
+
}
-
+
// Update problem markers
// TODO: Update problem markers in all referenced files
try {
@@ -398,98 +394,104 @@
for (String markerType : getMarkerTypes()) {
file.deleteMarkers(markerType, true, IResource.DEPTH_INFINITE);
}
-
+
// Create markers for parse problems
for (ParseProblem problem : module.getParseProblems()) {
Map<String, Object> attr = new HashMap<>();
attr.put(IMarker.LINE_NUMBER, problem.getLine());
- attr.put(IMarker.MESSAGE, problem.getReason());
+ attr.put(IMarker.MESSAGE, problem.getReason());
int markerSeverity;
if (problem.getSeverity() == ParseProblem.ERROR) {
markerSeverity = IMarker.SEVERITY_ERROR;
- }
- else {
+ } else {
markerSeverity = IMarker.SEVERITY_WARNING;
}
attr.put(IMarker.SEVERITY, markerSeverity);
MarkerUtilities.createMarker(file, attr, AbstractModuleEditor.PROBLEM_MARKER);
}
-
+
// If the module has no parse problems, pass it on to the validators
// Use try/catch to protect against unexpected exceptions in the validators
if (module.getParseProblems().isEmpty()) {
-
+
try {
- if (EpsilonCommonsPlugin.getDefault().getPreferenceStore().getBoolean(EpsilonPreferencePage.ENABLE_STATIC_ANALYSIS)) {
+ if (EpsilonCommonsPlugin.getDefault().getPreferenceStore()
+ .getBoolean(EpsilonPreferencePage.ENABLE_STATIC_ANALYSIS)) {
if (module instanceof IEolModule) {
IEolCompilationContext compilationContext = ((IEolModule) module).getCompilationContext();
- if (compilationContext != null) compilationContext.setModelFactory(new ModelTypeExtensionFactory());
+ if (compilationContext != null)
+ compilationContext.setModelFactory(new ModelTypeExtensionFactory());
}
createMarkers(module.compile(), doc, file, AbstractModuleEditor.PROBLEM_MARKER);
}
-
- for (IModuleValidator validator : ModuleValidatorExtensionPointManager.getDefault().getExtensions()) {
- String markerType = (validator.getMarkerType() == null ? AbstractModuleEditor.PROBLEM_MARKER : validator.getMarkerType());
+
+ for (IModuleValidator validator : ModuleValidatorExtensionPointManager.getDefault()
+ .getExtensions()) {
+ String markerType = (validator.getMarkerType() == null ? AbstractModuleEditor.PROBLEM_MARKER
+ : validator.getMarkerType());
createMarkers(validator.validate(module), doc, file, markerType);
}
+ } catch (Exception ex) {
+ LogUtil.log(ex);
}
- catch (Exception ex) { LogUtil.log(ex); }
-
+
}
-
- } catch (CoreException e1) {}
-
+
+ } catch (CoreException e1) {
+ }
+
if (module != null && module.getParseProblems().size() == 0) {
notifyModuleParsedListeners(module);
}
-
+
}
-
- private void createMarkers(List<ModuleMarker> moduleMarkers, IDocument doc, IFile file, String markerType) throws BadLocationException, CoreException {
- if (moduleMarkers == null) return;
-
+
+ private void createMarkers(List<ModuleMarker> moduleMarkers, IDocument doc, IFile file, String markerType)
+ throws BadLocationException, CoreException {
+ if (moduleMarkers == null)
+ return;
+
for (ModuleMarker moduleMarker : moduleMarkers) {
Map<String, Object> attr = new HashMap<>();
Region region = moduleMarker.getRegion();
- int startOffset = doc.getLineOffset(region.getStart().getLine()-1) + region.getStart().getColumn();
- int endOffset = doc.getLineOffset(region.getEnd().getLine()-1) + region.getEnd().getColumn();
+ int startOffset = doc.getLineOffset(region.getStart().getLine() - 1) + region.getStart().getColumn();
+ int endOffset = doc.getLineOffset(region.getEnd().getLine() - 1) + region.getEnd().getColumn();
attr.put(IMarker.CHAR_START, startOffset);
attr.put(IMarker.CHAR_END, endOffset);
attr.put(IMarker.MESSAGE, moduleMarker.getMessage());
if (moduleMarker.getSeverity() == Severity.Error) {
attr.put(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
- }
- else if (moduleMarker.getSeverity() == Severity.Warning) {
+ } else if (moduleMarker.getSeverity() == Severity.Warning) {
attr.put(IMarker.SEVERITY, IMarker.SEVERITY_WARNING);
- }
- else {
+ } else {
attr.put(IMarker.SEVERITY, IMarker.SEVERITY_INFO);
}
-
+
MarkerUtilities.createMarker(file, attr, markerType);
}
}
-
+
private Collection<String> getMarkerTypes() {
final Set<String> markerTypes = new HashSet<>();
markerTypes.add(AbstractModuleEditor.PROBLEM_MARKER);
-
+
for (IModuleValidator validator : ModuleValidatorExtensionPointManager.getDefault().getExtensions()) {
markerTypes.add(validator.getMarkerType());
}
return markerTypes;
}
-
+
@Override
public void doSave(IProgressMonitor progressMonitor) {
super.doSave(progressMonitor);
- if (!supportsDirtyTextParsing()) parseModule();
+ if (!supportsDirtyTextParsing())
+ parseModule();
}
-
+
protected abstract boolean supportsHyperlinks();
-
+
protected abstract boolean supportsDirtyTextParsing();
-
+
public Color getBackgroundColor() {
return backgroundColor;
}
@@ -497,71 +499,64 @@
public void setBackgroundColor(Color backgroundColor) {
this.backgroundColor = backgroundColor;
}
-
+
@Override
public void close(boolean save) {
parseModuleJob.cancel();
super.close(save);
}
-
+
public final List<Template> getTemplates() {
-
+
List<Template> templates = new ArrayList<>();
-
+
for (IAbstractModuleEditorTemplateContributor contributor : templateContributors) {
templates.addAll(contributor.getTemplates());
}
-
+
return templates;
}
-
- private static final String CONTENTASSIST_PROPOSAL_ID = "org.eclipse.common.dt.editor.AbsractModuleEditor.ContentAssistProposal";
-
+
+ private static final String CONTENTASSIST_PROPOSAL_ID = "org.eclipse.common.dt.editor.AbsractModuleEditor.ContentAssistProposal";
+ private static final String TOGGLE_COMMENT_ID = "org.eclipse.epsilon.common.dt.editor.AbsractModuleEditor.ToggleComment";
+
@Override
protected void createActions() {
- super.createActions();
+ super.createActions();
- // This action will fire a CONTENTASSIST_PROPOSALS operation
- // when executed
- IAction action =
- new TextOperationAction(new ResourceBundle(){
+ // This action will fire a CONTENTASSIST_PROPOSALS operation
+ // when executed
+ IAction action = new TextOperationAction(new EmptyResourceBundle(), "ContentAssistProposal", this,
+ ISourceViewer.CONTENTASSIST_PROPOSALS);
+ action.setActionDefinitionId(CONTENTASSIST_PROPOSAL_ID);
+ setAction(CONTENTASSIST_PROPOSAL_ID, action);
- @Override
- public Enumeration<String> getKeys() {
- // TODO Auto-generated method stub
- return null;
- }
+ // Tell the editor to execute this action
+ // when Ctrl+Spacebar is pressed
+ setActionActivationCode(CONTENTASSIST_PROPOSAL_ID, ' ', -1, SWT.CTRL);
- @Override
- protected Object handleGetObject(String key) {
- // TODO Auto-generated method stub
- return null;
- }},
- "ContentAssistProposal", this, ISourceViewer.CONTENTASSIST_PROPOSALS);
- action.setActionDefinitionId(CONTENTASSIST_PROPOSAL_ID);
-
- // Tell the editor about this new action
- setAction(CONTENTASSIST_PROPOSAL_ID, action);
-
- // Tell the editor to execute this action
- // when Ctrl+Spacebar is pressed
- setActionActivationCode(CONTENTASSIST_PROPOSAL_ID,' ', -1, SWT.CTRL);
+ // Set up the toggle comment action
+ ToggleCommentAction toggleCommentAction = new ToggleCommentAction(new EmptyResourceBundle(), "ToggleComment",
+ this);
+ toggleCommentAction.setActionDefinitionId(TOGGLE_COMMENT_ID);
+ toggleCommentAction.configure(getSourceViewer(), getSourceViewerConfiguration());
+ setAction(TOGGLE_COMMENT_ID, toggleCommentAction);
}
public EpsilonHighlightingManager getHighlightingManager() {
return highlightingManager;
}
-
+
private void refreshText() {
ISourceViewer viewer = getSourceViewer();
if (!(viewer instanceof ISourceViewerExtension2))
return;
- ((ISourceViewerExtension2)viewer).unconfigure();
+ ((ISourceViewerExtension2) viewer).unconfigure();
setSourceViewerConfiguration(createSourceViewerConfiguration());
viewer.configure(getSourceViewerConfiguration());
}
-
+
@Override
public boolean isDirty() {
// TODO add logic to fix bug 376294
diff --git a/plugins/org.eclipse.epsilon.common.dt/src/org/eclipse/epsilon/common/dt/editor/AbstractModuleEditorSourceViewerConfiguration.java b/plugins/org.eclipse.epsilon.common.dt/src/org/eclipse/epsilon/common/dt/editor/AbstractModuleEditorSourceViewerConfiguration.java
index e964de1..8f5f44f 100644
--- a/plugins/org.eclipse.epsilon.common.dt/src/org/eclipse/epsilon/common/dt/editor/AbstractModuleEditorSourceViewerConfiguration.java
+++ b/plugins/org.eclipse.epsilon.common.dt/src/org/eclipse/epsilon/common/dt/editor/AbstractModuleEditorSourceViewerConfiguration.java
@@ -33,10 +33,9 @@
public class AbstractModuleEditorSourceViewerConfiguration extends SourceViewerConfiguration {
protected AbstractModuleEditor editor = null;
-
protected AbstractModuleEditorScanner scanner;
protected AbstractModuleEditorNormalFontScanner commentScanner;
- //protected AbstractModuleEditorNormalFontScanner stringScanner;
+ protected String[] defaultPrefixes = new String[] {"//"};
public AbstractModuleEditorSourceViewerConfiguration(AbstractModuleEditor editor) {
this.editor = editor;
@@ -140,4 +139,9 @@
public AbstractModuleEditorNormalFontScanner getCommentScanner() {
return commentScanner;
}
+
+ @Override
+ public String[] getDefaultPrefixes(ISourceViewer sourceViewer, String contentType) {
+ return defaultPrefixes;
+ }
}
diff --git a/plugins/org.eclipse.epsilon.common.dt/src/org/eclipse/epsilon/common/dt/editor/EmptyResourceBundle.java b/plugins/org.eclipse.epsilon.common.dt/src/org/eclipse/epsilon/common/dt/editor/EmptyResourceBundle.java
new file mode 100644
index 0000000..5725856
--- /dev/null
+++ b/plugins/org.eclipse.epsilon.common.dt/src/org/eclipse/epsilon/common/dt/editor/EmptyResourceBundle.java
@@ -0,0 +1,18 @@
+package org.eclipse.epsilon.common.dt.editor;
+
+import java.util.Enumeration;
+import java.util.ResourceBundle;
+
+public class EmptyResourceBundle extends ResourceBundle {
+
+ @Override
+ protected Object handleGetObject(String key) {
+ return null;
+ }
+
+ @Override
+ public Enumeration<String> getKeys() {
+ return null;
+ }
+
+}
diff --git a/plugins/org.eclipse.epsilon.common.dt/src/org/eclipse/epsilon/common/dt/editor/ToggleCommentAction.java b/plugins/org.eclipse.epsilon.common.dt/src/org/eclipse/epsilon/common/dt/editor/ToggleCommentAction.java
new file mode 100644
index 0000000..3916124
--- /dev/null
+++ b/plugins/org.eclipse.epsilon.common.dt/src/org/eclipse/epsilon/common/dt/editor/ToggleCommentAction.java
@@ -0,0 +1,311 @@
+package org.eclipse.epsilon.common.dt.editor;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.ResourceBundle;
+
+import org.eclipse.epsilon.common.dt.util.LogUtil;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.ITextOperationTarget;
+import org.eclipse.jface.text.ITextSelection;
+import org.eclipse.jface.text.ITypedRegion;
+import org.eclipse.jface.text.Region;
+import org.eclipse.jface.text.TextUtilities;
+import org.eclipse.jface.text.source.ISourceViewer;
+import org.eclipse.jface.text.source.SourceViewerConfiguration;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.swt.custom.BusyIndicator;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.texteditor.ITextEditor;
+import org.eclipse.ui.texteditor.ResourceAction;
+import org.eclipse.ui.texteditor.TextEditorAction;
+
+
+/**
+ * An action which toggles comment prefixes on the selected lines.
+ * Copied/adapted from org.eclipse.jdt.internal.ui.javaeditor.ToggleCommentAction
+ *
+ * @since 2.3
+ */
+public final class ToggleCommentAction extends TextEditorAction {
+
+ /** The text operation target */
+ private ITextOperationTarget fOperationTarget;
+ /** The document partitioning */
+ private String fDocumentPartitioning;
+ /** The comment prefixes */
+ private Map<String, String[]> fPrefixesMap;
+
+ /**
+ * Creates and initializes the action for the given text editor. The action
+ * configures its visual representation from the given resource bundle.
+ *
+ * @param bundle the resource bundle
+ * @param prefix a prefix to be prepended to the various resource keys
+ * (described in <code>ResourceAction</code> constructor), or
+ * <code>null</code> if none
+ * @param editor the text editor
+ * @see ResourceAction#ResourceAction(ResourceBundle, String, int)
+ */
+ public ToggleCommentAction(ResourceBundle bundle, String prefix, ITextEditor editor) {
+ super(bundle, prefix, editor);
+ }
+
+ /**
+ * Implementation of the <code>IAction</code> prototype. Checks if the selected
+ * lines are all commented or not and uncomments/comments them respectively.
+ */
+ @Override
+ public void run() {
+
+ if (fOperationTarget == null || fDocumentPartitioning == null || fPrefixesMap == null)
+ return;
+
+ ITextEditor editor= getTextEditor();
+ if (editor == null)
+ return;
+
+ if (!validateEditorInputState())
+ return;
+
+ final int operationCode;
+ if (isSelectionCommented(editor.getSelectionProvider().getSelection()))
+ operationCode= ITextOperationTarget.STRIP_PREFIX;
+ else
+ operationCode= ITextOperationTarget.PREFIX;
+
+ Shell shell= editor.getSite().getShell();
+ if (!fOperationTarget.canDoOperation(operationCode)) {
+ return;
+ }
+
+ Display display= null;
+ if (shell != null && !shell.isDisposed())
+ display= shell.getDisplay();
+
+ BusyIndicator.showWhile(display, new Runnable() {
+ @Override
+ public void run() {
+ fOperationTarget.doOperation(operationCode);
+ }
+ });
+ }
+
+ /**
+ * Is the given selection single-line commented?
+ *
+ * @param selection Selection to check
+ * @return <code>true</code> iff all selected lines are commented
+ */
+ private boolean isSelectionCommented(ISelection selection) {
+ if (!(selection instanceof ITextSelection))
+ return false;
+
+ ITextSelection textSelection= (ITextSelection) selection;
+ if (textSelection.getStartLine() < 0 || textSelection.getEndLine() < 0)
+ return false;
+
+ IDocument document= getTextEditor().getDocumentProvider().getDocument(getTextEditor().getEditorInput());
+
+ try {
+
+ IRegion block= getTextBlockFromSelection(textSelection, document);
+ ITypedRegion[] regions= TextUtilities.computePartitioning(document, fDocumentPartitioning, block.getOffset(), block.getLength(), false);
+
+ int[] lines= new int[regions.length * 2]; // [startline, endline, startline, endline, ...]
+ for (int i= 0, j= 0; i < regions.length; i++, j+= 2) {
+ // start line of region
+ lines[j]= getFirstCompleteLineOfRegion(regions[i], document);
+ // end line of region
+ int length= regions[i].getLength();
+ int offset= regions[i].getOffset() + length;
+ if (length > 0)
+ offset--;
+ lines[j + 1]= (lines[j] == -1 ? -1 : document.getLineOfOffset(offset));
+ }
+
+ // Perform the check
+ for (int i= 0, j= 0; i < regions.length; i++, j += 2) {
+ String[] prefixes= fPrefixesMap.get(regions[i].getType());
+ if (prefixes != null && prefixes.length > 0 && lines[j] >= 0 && lines[j + 1] >= 0)
+ if (!isBlockCommented(lines[j], lines[j + 1], prefixes, document))
+ return false;
+ }
+
+ return true;
+
+ } catch (BadLocationException x) {
+ // should not happen
+ LogUtil.log(x);
+ }
+
+ return false;
+ }
+
+ /**
+ * Creates a region describing the text block (something that starts at
+ * the beginning of a line) completely containing the current selection.
+ *
+ * @param selection The selection to use
+ * @param document The document
+ * @return the region describing the text block comprising the given selection
+ */
+ private IRegion getTextBlockFromSelection(ITextSelection selection, IDocument document) {
+
+ try {
+ IRegion line= document.getLineInformationOfOffset(selection.getOffset());
+ int length= selection.getLength() == 0 ? line.getLength() : selection.getLength() + (selection.getOffset() - line.getOffset());
+ return new Region(line.getOffset(), length);
+
+ } catch (BadLocationException x) {
+ // should not happen
+ LogUtil.log(x);
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns the index of the first line whose start offset is in the given text range.
+ *
+ * @param region the text range in characters where to find the line
+ * @param document The document
+ * @return the first line whose start index is in the given range, -1 if there is no such line
+ */
+ private int getFirstCompleteLineOfRegion(IRegion region, IDocument document) {
+
+ try {
+
+ final int startLine= document.getLineOfOffset(region.getOffset());
+
+ int offset= document.getLineOffset(startLine);
+ if (offset >= region.getOffset())
+ return startLine;
+
+ final int nextLine= startLine + 1;
+ if (nextLine == document.getNumberOfLines())
+ return -1;
+
+ offset= document.getLineOffset(nextLine);
+ return (offset > region.getOffset() + region.getLength() ? -1 : nextLine);
+
+ } catch (BadLocationException x) {
+ // should not happen
+ LogUtil.log(x);
+ }
+
+ return -1;
+ }
+
+ /**
+ * Determines whether each line is prefixed by one of the prefixes.
+ *
+ * @param startLine Start line in document
+ * @param endLine End line in document
+ * @param prefixes Possible comment prefixes
+ * @param document The document
+ * @return <code>true</code> iff each line from <code>startLine</code>
+ * to and including <code>endLine</code> is prepended by one
+ * of the <code>prefixes</code>, ignoring whitespace at the
+ * begin of line
+ */
+ private boolean isBlockCommented(int startLine, int endLine, String[] prefixes, IDocument document) {
+
+ try {
+
+ // check for occurrences of prefixes in the given lines
+ for (int i= startLine; i <= endLine; i++) {
+
+ IRegion line= document.getLineInformation(i);
+ String text= document.get(line.getOffset(), line.getLength());
+
+ int[] found= TextUtilities.indexOf(prefixes, text, 0);
+
+ if (found[0] == -1)
+ // found a line which is not commented
+ return false;
+
+ String s= document.get(line.getOffset(), found[0]);
+ s= s.trim();
+ if (s.length() != 0)
+ // found a line which is not commented
+ return false;
+
+ }
+
+ return true;
+
+ } catch (BadLocationException x) {
+ // should not happen
+ LogUtil.log(x);
+ }
+
+ return false;
+ }
+
+ /**
+ * Implementation of the <code>IUpdate</code> prototype method discovers
+ * the operation through the current editor's
+ * <code>ITextOperationTarget</code> adapter, and sets the enabled state
+ * accordingly.
+ */
+ @Override
+ public void update() {
+ super.update();
+
+ if (!canModifyEditor()) {
+ setEnabled(false);
+ return;
+ }
+
+ ITextEditor editor= getTextEditor();
+ if (fOperationTarget == null && editor != null)
+ fOperationTarget= editor.getAdapter(ITextOperationTarget.class);
+
+ boolean isEnabled= (fOperationTarget != null && fOperationTarget.canDoOperation(ITextOperationTarget.PREFIX) && fOperationTarget.canDoOperation(ITextOperationTarget.STRIP_PREFIX));
+ setEnabled(isEnabled);
+ }
+
+ /*
+ * @see TextEditorAction#setEditor(ITextEditor)
+ */
+ @Override
+ public void setEditor(ITextEditor editor) {
+ super.setEditor(editor);
+ fOperationTarget= null;
+ }
+
+ public void configure(ISourceViewer sourceViewer, SourceViewerConfiguration configuration) {
+ fPrefixesMap= null;
+
+ String[] types= configuration.getConfiguredContentTypes(sourceViewer);
+ Map<String, String[]> prefixesMap= new HashMap<>(types.length);
+ for (String type : types) {
+ String[] prefixes= configuration.getDefaultPrefixes(sourceViewer, type);
+ if (prefixes != null && prefixes.length > 0) {
+ int emptyPrefixes= 0;
+ for (String prefix : prefixes) {
+ if (prefix.length() == 0) {
+ emptyPrefixes++;
+ }
+ }
+ if (emptyPrefixes > 0) {
+ String[] nonemptyPrefixes= new String[prefixes.length - emptyPrefixes];
+ for (int j= 0, k= 0; j < prefixes.length; j++) {
+ String prefix= prefixes[j];
+ if (prefix.length() != 0) {
+ nonemptyPrefixes[k]= prefix;
+ k++;
+ }
+ }
+ prefixes= nonemptyPrefixes;
+ }
+ prefixesMap.put(type, prefixes);
+ }
+ }
+ fDocumentPartitioning= configuration.getConfiguredDocumentPartitioning(sourceViewer);
+ fPrefixesMap= prefixesMap;
+ }
+}