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; } } }