/* | |
* Licensed to the Apache Software Foundation (ASF) under one | |
* or more contributor license agreements. See the NOTICE file | |
* distributed with this work for additional information | |
* regarding copyright ownership. The ASF licenses this file | |
* to you under the Apache License, Version 2.0 (the | |
* "License"); you may not use this file except in compliance | |
* with the License. You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, | |
* software distributed under the License is distributed on an | |
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
* KIND, either express or implied. See the License for the | |
* specific language governing permissions and limitations | |
* under the License. | |
*/ | |
package org.apache.uima.ruta.ide.ui.editor; | |
import java.util.Collection; | |
import java.util.HashMap; | |
import java.util.List; | |
import java.util.Map; | |
import org.apache.uima.ruta.ide.RutaIdeUIPlugin; | |
import org.apache.uima.ruta.ide.core.RutaLanguageToolkit; | |
import org.apache.uima.ruta.ide.core.codeassist.RutaReferenceDeclarationVisitor; | |
import org.apache.uima.ruta.ide.core.codeassist.RutaReferenceVisitor; | |
import org.apache.uima.ruta.ide.core.codeassist.RutaRuleIdVisitor; | |
import org.apache.uima.ruta.ide.core.codeassist.RutaSelectionParser; | |
import org.apache.uima.ruta.ide.parser.ast.RutaAction; | |
import org.apache.uima.ruta.ide.parser.ast.RutaCondition; | |
import org.apache.uima.ruta.ide.parser.ast.RutaRule; | |
import org.apache.uima.ruta.ide.ui.RutaPartitions; | |
import org.apache.uima.ruta.ide.ui.RutaPreferenceConstants; | |
import org.apache.uima.ruta.ide.ui.text.RutaPairMatcher; | |
import org.apache.uima.ruta.ide.ui.text.folding.RutaFoldingStructureProvider; | |
import org.eclipse.core.filebuffers.IDocumentSetupParticipant; | |
import org.eclipse.dltk.ast.ASTNode; | |
import org.eclipse.dltk.ast.declarations.ModuleDeclaration; | |
import org.eclipse.dltk.compiler.env.ISourceModule; | |
import org.eclipse.dltk.core.IDLTKLanguageToolkit; | |
import org.eclipse.dltk.core.IModelElement; | |
import org.eclipse.dltk.core.ISourceRange; | |
import org.eclipse.dltk.core.ISourceReference; | |
import org.eclipse.dltk.core.ModelException; | |
import org.eclipse.dltk.internal.ui.actions.FoldingActionGroup; | |
import org.eclipse.dltk.internal.ui.editor.DLTKEditorMessages; | |
import org.eclipse.dltk.internal.ui.editor.ScriptEditor; | |
import org.eclipse.dltk.internal.ui.editor.ScriptOutlinePage; | |
import org.eclipse.dltk.internal.ui.editor.ScriptSourceViewer; | |
import org.eclipse.dltk.internal.ui.editor.ToggleCommentAction; | |
import org.eclipse.dltk.ui.actions.IScriptEditorActionDefinitionIds; | |
import org.eclipse.dltk.ui.text.ScriptTextTools; | |
import org.eclipse.dltk.ui.text.folding.IFoldingStructureProvider; | |
import org.eclipse.jface.action.Action; | |
import org.eclipse.jface.action.IAction; | |
import org.eclipse.jface.preference.IPreferenceStore; | |
import org.eclipse.jface.text.BadLocationException; | |
import org.eclipse.jface.text.IDocument; | |
import org.eclipse.jface.text.IDocumentExtension3; | |
import org.eclipse.jface.text.IRegion; | |
import org.eclipse.jface.text.ITextOperationTarget; | |
import org.eclipse.jface.text.ITextViewerExtension5; | |
import org.eclipse.jface.text.Position; | |
import org.eclipse.jface.text.TextUtilities; | |
import org.eclipse.jface.text.source.Annotation; | |
import org.eclipse.jface.text.source.IAnnotationModel; | |
import org.eclipse.jface.text.source.ICharacterPairMatcher; | |
import org.eclipse.jface.text.source.ISourceViewer; | |
import org.eclipse.jface.text.source.SourceViewerConfiguration; | |
import org.eclipse.search.internal.ui.SearchPlugin; | |
import org.eclipse.search2.internal.ui.text.Highlighter; | |
import org.eclipse.swt.custom.StyledText; | |
import org.eclipse.swt.graphics.Point; | |
import org.eclipse.ui.IEditorInput; | |
import org.eclipse.ui.texteditor.IUpdate; | |
import org.eclipse.ui.texteditor.SourceViewerDecorationSupport; | |
import org.eclipse.ui.texteditor.TextOperationAction; | |
public class RutaEditor extends ScriptEditor { | |
protected class FormatElementAction extends Action implements IUpdate { | |
/* | |
* @since 3.2 | |
*/ | |
FormatElementAction() { | |
setEnabled(isEditorInputModifiable()); | |
} | |
/* | |
* @see org.eclipse.jface.action.IAction#run() | |
*/ | |
@Override | |
public void run() { | |
final ScriptSourceViewer viewer = (ScriptSourceViewer) getSourceViewer(); | |
if (viewer.isEditable()) { | |
final Point selection = viewer.rememberSelection(); | |
try { | |
viewer.setRedraw(false); | |
final String type = TextUtilities.getContentType(viewer.getDocument(), | |
RutaPartitions.RUTA_PARTITIONING, selection.x, true); | |
if (type.equals(IDocument.DEFAULT_CONTENT_TYPE) && selection.y == 0) { | |
try { | |
final IModelElement element = getElementAt(selection.x, true); | |
if (element != null && element.exists()) { | |
final int kind = element.getElementType(); | |
if (kind == IModelElement.TYPE || kind == IModelElement.METHOD) { | |
final ISourceReference reference = (ISourceReference) element; | |
final ISourceRange range = reference.getSourceRange(); | |
if (range != null) { | |
viewer.setSelectedRange(range.getOffset(), range.getLength()); | |
viewer.doOperation(ISourceViewer.FORMAT); | |
} | |
} | |
} | |
} catch (ModelException exception) { | |
// Should not happen | |
} | |
} else { | |
viewer.setSelectedRange(selection.x, 1); | |
viewer.doOperation(ISourceViewer.FORMAT); | |
} | |
} catch (BadLocationException exception) { | |
// Can not happen | |
} finally { | |
viewer.setRedraw(true); | |
viewer.restoreSelection(); | |
} | |
} | |
} | |
/* | |
* @see org.eclipse.ui.texteditor.IUpdate#update() | |
* | |
* @since 3.2 | |
*/ | |
public void update() { | |
setEnabled(isEditorInputModifiable()); | |
} | |
} | |
public static final String EDITOR_ID = "org.apache.uima.ruta.ide.ui.editor.RutaEditor"; | |
public static final String EDITOR_CONTEXT = "#RutaEditorContext"; | |
public static final String RULER_CONTEXT = "#RutaRulerContext"; | |
private IFoldingStructureProvider foldingProvider; | |
private RutaPairMatcher bracketMatcher; | |
private void configureToggleCommentAction() { | |
IAction action = getAction("ToggleComment"); //$NON-NLS-1$ | |
if (action instanceof ToggleCommentAction) { | |
ISourceViewer sourceViewer = getSourceViewer(); | |
SourceViewerConfiguration configuration = getSourceViewerConfiguration(); | |
((ToggleCommentAction) action).configure(sourceViewer, configuration); | |
} | |
} | |
// public void dispose() { | |
// super.dispose(); | |
// highlighter.dispose(); | |
// } | |
@Override | |
protected void initializeEditor() { | |
super.initializeEditor(); | |
setEditorContextMenuId(EDITOR_CONTEXT); | |
setRulerContextMenuId(RULER_CONTEXT); | |
} | |
@Override | |
protected void createActions() { | |
super.createActions(); | |
// Comment | |
Action action = new TextOperationAction(DLTKEditorMessages.getBundleForConstructedKeys(), | |
"Comment.", this, ITextOperationTarget.PREFIX); //$NON-NLS-1$ | |
action.setActionDefinitionId(IScriptEditorActionDefinitionIds.COMMENT); | |
setAction("Comment", action); //$NON-NLS-1$ | |
markAsStateDependentAction("Comment", true); //$NON-NLS-1$ | |
// Uncomment | |
action = new TextOperationAction(DLTKEditorMessages.getBundleForConstructedKeys(), | |
"Uncomment.", this, ITextOperationTarget.STRIP_PREFIX); //$NON-NLS-1$ | |
action.setActionDefinitionId(IScriptEditorActionDefinitionIds.UNCOMMENT); | |
setAction("Uncomment", action); //$NON-NLS-1$ | |
markAsStateDependentAction("Uncomment", true); //$NON-NLS-1$ | |
// Toggle comment | |
action = new ToggleCommentAction(DLTKEditorMessages.getBundleForConstructedKeys(), | |
"ToggleComment.", this); //$NON-NLS-1$ | |
action.setActionDefinitionId(IScriptEditorActionDefinitionIds.TOGGLE_COMMENT); | |
setAction("ToggleComment", action); //$NON-NLS-1$ | |
markAsStateDependentAction("ToggleComment", true); //$NON-NLS-1$ | |
configureToggleCommentAction(); | |
action = new TextOperationAction(DLTKEditorMessages.getBundleForConstructedKeys(), | |
"Format.", this, ISourceViewer.FORMAT); //$NON-NLS-1$ | |
action.setActionDefinitionId(IScriptEditorActionDefinitionIds.FORMAT); | |
setAction("Format", action); //$NON-NLS-1$ | |
markAsStateDependentAction("Format", true); //$NON-NLS-1$ | |
markAsSelectionDependentAction("Format", true); //$NON-NLS-1$ | |
// PlatformUI.getWorkbench().getHelpSystem().setHelp(action, | |
// IJavaHelpContextIds.FORMAT_ACTION); | |
} | |
final static String[] properties = new String[] { RutaPreferenceConstants.EDITOR_FOLDING_BLOCKS, | |
RutaPreferenceConstants.EDITOR_FOLDING_EXCLUDE_LIST, | |
RutaPreferenceConstants.EDITOR_FOLDING_INCLUDE_LIST, }; | |
private Highlighter highlighter; | |
private HashMap<Annotation, Position> myAnnotations; | |
@Override | |
protected String[] getFoldingEventPreferenceKeys() { | |
return properties; | |
} | |
// protected void handlePreferenceStoreChanged(PropertyChangeEvent event) { | |
// String property = event.getProperty(); | |
// try { | |
// ISourceViewer sourceViewer = getSourceViewer(); | |
// if (sourceViewer == null) { | |
// return; | |
// } | |
// if (RutaPreferenceConstants.EDITOR_FOLDING_BLOCKS | |
// .equals(property) | |
// || RutaPreferenceConstants.EDITOR_FOLDING_COMMENTS_WITH_NEWLINES | |
// .equals(property) | |
// || RutaPreferenceConstants.EDITOR_FOLDING_EXCLUDE_LIST | |
// .equals(property) | |
// || RutaPreferenceConstants.EDITOR_FOLDING_INCLUDE_LIST | |
// .equals(property) | |
// || PreferenceConstants.EDITOR_FOLDING_LINES_LIMIT | |
// .equals(property)) { | |
// | |
// if (sourceViewer instanceof ProjectionViewer) { | |
// fProjectionModelUpdater.initialize(); | |
// } | |
// return; | |
// } | |
// } finally { | |
// super.handlePreferenceStoreChanged(event); | |
// } | |
// } | |
@Override | |
public IPreferenceStore getScriptPreferenceStore() { | |
return RutaIdeUIPlugin.getDefault().getPreferenceStore(); | |
} | |
@Override | |
public ScriptTextTools getTextTools() { | |
return RutaIdeUIPlugin.getDefault().getTextTools(); | |
} | |
@Override | |
protected ScriptOutlinePage doCreateOutlinePage() { | |
return new RutaOutlinePage(this, RutaIdeUIPlugin.getDefault().getPreferenceStore()); | |
} | |
@Override | |
protected void connectPartitioningToElement(IEditorInput input, IDocument document) { | |
if (document instanceof IDocumentExtension3) { | |
IDocumentExtension3 doc = (IDocumentExtension3) document; | |
if (doc.getDocumentPartitioner(RutaPartitions.RUTA_PARTITIONING) == null) { | |
IDocumentSetupParticipant participant = new RutaDocumentSetupParticipant(); | |
participant.setup(document); | |
} | |
} | |
} | |
@Override | |
protected IFoldingStructureProvider getFoldingStructureProvider() { | |
if (foldingProvider == null) { | |
foldingProvider = new RutaFoldingStructureProvider(); | |
} | |
return foldingProvider; | |
} | |
@Override | |
protected FoldingActionGroup createFoldingActionGroup() { | |
return new FoldingActionGroup(this, getViewer(), RutaIdeUIPlugin.getDefault() | |
.getPreferenceStore()); | |
} | |
@Override | |
public String getEditorId() { | |
return EDITOR_ID; | |
} | |
protected void selectionChanged() { | |
if (getSelectionProvider() == null) | |
return; | |
super.selectionChanged(); | |
if (myAnnotations != null && !myAnnotations.isEmpty()) { | |
removeAnnotations(myAnnotations.keySet()); | |
} | |
RutaSelectionParser parser = new RutaSelectionParser(); | |
ISourceModule unit = (ISourceModule) getInputModelElement(); | |
ModuleDeclaration parsed = parser.parse(unit); | |
ISourceViewer sourceViewer = getSourceViewer(); | |
StyledText styledText = sourceViewer.getTextWidget(); | |
int caret = 0; | |
if (sourceViewer instanceof ITextViewerExtension5) { | |
ITextViewerExtension5 extension = (ITextViewerExtension5) sourceViewer; | |
caret = extension.widgetOffset2ModelOffset(styledText.getCaretOffset()); | |
} else { | |
int offset = sourceViewer.getVisibleRegion().getOffset(); | |
caret = offset + styledText.getCaretOffset(); | |
} | |
RutaReferenceVisitor visitor1 = new RutaReferenceVisitor(caret); | |
ASTNode node = null; | |
try { | |
parsed.traverse(visitor1); | |
} catch (Exception e) { | |
} | |
node = visitor1.getResult(); | |
if (node == null) { | |
RutaReferenceDeclarationVisitor visitor2 = new RutaReferenceDeclarationVisitor(caret); | |
try { | |
parsed.traverse(visitor2); | |
} catch (Exception e) { | |
} | |
node = visitor2.getResult(); | |
} | |
if (node != null) { | |
ReferenceFinder refFinder = new ReferenceFinder(node); | |
try { | |
parsed.traverse(refFinder); | |
} catch (Exception e) { | |
} | |
List<ASTNode> result = refFinder.getResult(); | |
myAnnotations = new HashMap<Annotation, Position>(result.size()); | |
for (ASTNode each : result) { | |
Annotation annotation = new Annotation(SearchPlugin.SEARCH_ANNOTATION_TYPE, true, null); | |
Position position = null; | |
int sourceStart = each.sourceStart(); | |
int sourceEnd = each.sourceEnd(); | |
if (each instanceof RutaAction) { | |
RutaAction e = (RutaAction) each; | |
sourceStart = e.getNameStart(); | |
sourceEnd = e.getNameEnd(); | |
} else if (each instanceof RutaCondition) { | |
RutaCondition e = (RutaCondition) each; | |
sourceStart = e.getNameStart(); | |
sourceEnd = e.getNameEnd(); | |
} | |
position = new Position(sourceStart, sourceEnd - sourceStart); | |
myAnnotations.put(annotation, position); | |
} | |
addAnnotations(myAnnotations); | |
} | |
} | |
public void highlightElement(int id) { | |
if (myAnnotations != null && !myAnnotations.isEmpty()) { | |
removeAnnotations(myAnnotations.keySet()); | |
} | |
RutaSelectionParser parser = new RutaSelectionParser(); | |
ISourceModule unit = (ISourceModule) getInputModelElement(); | |
ModuleDeclaration parsed = parser.parse(unit); | |
RutaRuleIdVisitor visitor = new RutaRuleIdVisitor(id); | |
try { | |
parsed.traverse(visitor); | |
} catch (Exception e) { | |
} | |
RutaRule rule = visitor.getResult(); | |
myAnnotations = new HashMap<Annotation, Position>(); | |
if (rule != null) { | |
Annotation annotation = new Annotation(SearchPlugin.SEARCH_ANNOTATION_TYPE, true, null); | |
int sourceStart = rule.sourceStart(); | |
int sourceEnd = rule.sourceEnd(); | |
Position position = new Position(sourceStart, sourceEnd - sourceStart); | |
getSourceViewer().revealRange(sourceStart, sourceEnd - sourceStart); | |
myAnnotations.put(annotation, position); | |
} | |
addAnnotations(myAnnotations); | |
} | |
private void removeAnnotations(Collection<Annotation> annotations) { | |
IAnnotationModel model = getDocumentProvider().getAnnotationModel(getEditorInput()); | |
for (Annotation annotation : annotations) { | |
model.removeAnnotation(annotation); | |
} | |
} | |
private void addAnnotations(Map<Annotation, Position> annotationToPositionMap) { | |
IAnnotationModel model = getDocumentProvider().getAnnotationModel(getEditorInput()); | |
for (Annotation a : annotationToPositionMap.keySet()) { | |
Position p = annotationToPositionMap.get(a); | |
model.addAnnotation(a, p); | |
} | |
} | |
@Override | |
protected void initializeKeyBindingScopes() { | |
setKeyBindingScopes(new String[] { "org.apache.uima.ruta.ide.ui.rutaEditorScope" }); //$NON-NLS-1$ | |
} | |
@Override | |
public IDLTKLanguageToolkit getLanguageToolkit() { | |
return RutaLanguageToolkit.getDefault(); | |
} | |
@Override | |
public String getCallHierarchyID() { | |
return "org.eclipse.dltk.callhierarchy.view"; | |
} | |
/** | |
* Jumps to the matching bracket. | |
*/ | |
@Override | |
public void gotoMatchingBracket() { | |
ISourceViewer sourceViewer = getSourceViewer(); | |
IDocument document = sourceViewer.getDocument(); | |
if (document == null) | |
return; | |
IRegion selection = getSignedSelection(sourceViewer); | |
int selectionLength = Math.abs(selection.getLength()); | |
if (selectionLength > 1) { | |
setStatusLineErrorMessage("No bracket selected"); | |
sourceViewer.getTextWidget().getDisplay().beep(); | |
return; | |
} | |
// #26314 | |
int sourceCaretOffset = selection.getOffset() + selection.getLength(); | |
if (isSurroundedByBrackets(document, sourceCaretOffset)) | |
sourceCaretOffset -= selection.getLength(); | |
IRegion region = bracketMatcher.match(document, sourceCaretOffset); | |
if (region == null) { | |
setStatusLineErrorMessage("No matching bracket found"); | |
sourceViewer.getTextWidget().getDisplay().beep(); | |
return; | |
} | |
int offset = region.getOffset(); | |
int length = region.getLength(); | |
if (length < 1) | |
return; | |
int anchor = bracketMatcher.getAnchor(); | |
// http://dev.eclipse.org/bugs/show_bug.cgi?id=34195 | |
int targetOffset = (ICharacterPairMatcher.RIGHT == anchor) ? offset + 1 : offset + length; | |
boolean visible = false; | |
if (sourceViewer instanceof ITextViewerExtension5) { | |
ITextViewerExtension5 extension = (ITextViewerExtension5) sourceViewer; | |
visible = (extension.modelOffset2WidgetOffset(targetOffset) > -1); | |
} else { | |
IRegion visibleRegion = sourceViewer.getVisibleRegion(); | |
// http://dev.eclipse.org/bugs/show_bug.cgi?id=34195 | |
visible = (targetOffset >= visibleRegion.getOffset() && targetOffset <= visibleRegion | |
.getOffset() + visibleRegion.getLength()); | |
} | |
if (!visible) { | |
setStatusLineErrorMessage("Matching bracket is outside selected element"); | |
sourceViewer.getTextWidget().getDisplay().beep(); | |
return; | |
} | |
if (selection.getLength() < 0) | |
targetOffset -= selection.getLength(); | |
sourceViewer.setSelectedRange(targetOffset, selection.getLength()); | |
sourceViewer.revealRange(targetOffset, selection.getLength()); | |
} | |
@Override | |
protected void configureSourceViewerDecorationSupport(SourceViewerDecorationSupport support) { | |
bracketMatcher = new RutaPairMatcher(BRACKETS, this); | |
support.setCharacterPairMatcher(bracketMatcher); | |
support.setMatchingCharacterPainterPreferenceKeys(MATCHING_BRACKETS, MATCHING_BRACKETS_COLOR); | |
super.configureSourceViewerDecorationSupport(support); | |
} | |
} |