package com.redhat.ceylon.eclipse.code.editor;
import static com.redhat.ceylon.eclipse.code.editor.CeylonEditor.getFences;
import org.eclipse.core.runtime.Assert;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextViewerExtension5;
import org.eclipse.jface.text.source.ICharacterPairMatcher;
import org.eclipse.jface.text.source.ISourceViewer;
class GotoMatchingFenceAction extends Action {
private final CeylonEditor fEditor;
public GotoMatchingFenceAction(CeylonEditor editor) {
super("Go to Matching Fence");
Assert.isNotNull(editor);
fEditor= editor;
setEnabled(true);
//PlatformUI.getWorkbench().getHelpSystem().setHelp(this, IJavaHelpContextIds.GOTO_MATCHING_BRACKET_ACTION);
}
public void run() {
gotoMatchingFence();
}
/**
* Jumps to the matching bracket.
*/
public void gotoMatchingFence() {
ISourceViewer sourceViewer = fEditor.getCeylonSourceViewer();
IDocument document= sourceViewer.getDocument();
if (document == null)
return;
IRegion selection= fEditor.getSignedSelection();
int selectionLength= Math.abs(selection.getLength());
if (selectionLength > 1) {
fEditor.setStatusLineErrorMessage("Invalid selection");
sourceViewer.getTextWidget().getDisplay().beep();
return;
}
// #26314
int sourceCaretOffset= selection.getOffset() + selection.getLength();
if (isSurroundedByBrackets(document, sourceCaretOffset))
sourceCaretOffset -= selection.getLength();
IRegion region= fEditor.getBracketMatcher().match(document, sourceCaretOffset);
if (region == null) {
fEditor.setStatusLineErrorMessage("No matching fence!");
sourceViewer.getTextWidget().getDisplay().beep();
return;
}
int offset= region.getOffset();
int length= region.getLength();
if (length < 1)
return;
int anchor= fEditor.getBracketMatcher().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) {
fEditor.setStatusLineErrorMessage("Matching fence is outside the currently selected element.");
sourceViewer.getTextWidget().getDisplay().beep();
return;
}
if (selection.getLength() < 0)
targetOffset -= selection.getLength();
sourceViewer.setSelectedRange(targetOffset, selection.getLength());
sourceViewer.revealRange(targetOffset, selection.getLength());
}
private boolean isBracket(char character) {
String[][] fences= getFences();
for(int i= 0; i != fences.length; ++i) {
if (fences[i][0].indexOf(character) >= 0)
return true;
if (fences[i][1].indexOf(character) >= 0)
return true;
}
return false;
}
private boolean isSurroundedByBrackets(IDocument document, int offset) {
if (offset == 0 || offset == document.getLength())
return false;
try {
return isBracket(document.getChar(offset - 1)) &&
isBracket(document.getChar(offset));
} catch (BadLocationException e) {
return false;
}
}
}