/******************************************************************************* * Copyright (c) Gil Barash - chookapp@yahoo.com * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Gil Barash - initial API and implementation *******************************************************************************/ package com.chookapp.org.bracketeer.jdt; import org.eclipse.jdt.core.ITypeRoot; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.dom.AST; import org.eclipse.jdt.core.dom.ASTParser; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.ui.JavaUI; import org.eclipse.jdt.ui.text.IJavaPartitions; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.TextUtilities; import org.eclipse.jface.text.source.ICharacterPairMatcher; import org.eclipse.ui.IEditorPart; import com.chookapp.org.bracketeer.common.BracketsPair; import com.chookapp.org.bracketeer.common.IBracketeerProcessingContainer; import com.chookapp.org.bracketeer.common.SingleBracket; import com.chookapp.org.bracketeer.common.Utils; import com.chookapp.org.bracketeer.extensionpoint.BracketeerProcessor; import com.chookapp.org.bracketeer.jdt.core.internal.JavaPairMatcher; public class BracketeerJdtProcessor extends BracketeerProcessor { protected final static char[] BRACKETS = { '{', '}', '(', ')', '[', ']', '<', '>' }; /* Lonely brackets is different from BRACKETS because matching an * angular bracket is heuristic. So I don't want to have false positives */ protected final static String LONELY_BRACKETS = "()[]{}"; //$NON-NLS-1$ String[] ALL_JPARTITIONS = { IJavaPartitions.JAVA_CHARACTER, IJavaPartitions.JAVA_DOC, IJavaPartitions.JAVA_MULTI_LINE_COMMENT, IJavaPartitions.JAVA_SINGLE_LINE_COMMENT, IJavaPartitions.JAVA_STRING }; private JavaPairMatcher _matcher; private ITypeRoot _typeRoot; protected BracketeerJdtProcessor(IEditorPart part, IDocument doc) { super(doc); _matcher = new JavaPairMatcher(BRACKETS); _typeRoot = JavaUI.getEditorInputTypeRoot(part.getEditorInput()); } @Override protected void processDocument(IDocument doc, IBracketeerProcessingContainer container) { if(Activator.DEBUG) Activator.trace("starting process..."); //$NON-NLS-1$ try { processBrackets(doc, container); processAst(doc, container); } catch (BadLocationException e) { _cancelProcessing.set(true); } if(Activator.DEBUG) Activator.trace("process ended (" + _cancelProcessing + ")"); //$NON-NLS-1$ //$NON-NLS-2$ } private void processAst(IDocument doc, IBracketeerProcessingContainer container) { if( _typeRoot == null ) return; // can happen if this is a "classFile" without attached source... try { if(_typeRoot.getSource() == null) return; } catch (JavaModelException e) { return; } ASTParser astp = ASTParser.newParser(AST.JLS3); astp.setSource(_typeRoot); astp.setResolveBindings(false); CompilationUnit cu = (CompilationUnit) astp.createAST(null); ClosingBracketHintVisitor visitor = new ClosingBracketHintVisitor(container, doc, _cancelProcessing, _hintConf); cu.accept(visitor); } private void processBrackets(IDocument doc, IBracketeerProcessingContainer container) throws BadLocationException { for(int i = 1; i < doc.getLength(); i++) { if( _cancelProcessing.get() ) break; BracketsPair pair = getMatchingPair(doc, i); if(pair != null) { if(Activator.DEBUG) Activator.trace("matching pair added: " + pair.toString()); //$NON-NLS-1$ container.add(pair); continue; } SingleBracket single = getLonelyBracket(doc, i); if( single != null ) container.add(single); } } private SingleBracket getLonelyBracket(IDocument doc, int offset) throws BadLocationException { final int charOffset = offset - 1; char prevChar; prevChar = doc.getChar(Math.max(charOffset, 0)); if (LONELY_BRACKETS.indexOf(prevChar) == -1) return null; final String partition= TextUtilities.getContentType(doc, IJavaPartitions.JAVA_PARTITIONING, charOffset, false); for( String partName : ALL_JPARTITIONS ) { if (partName.equals( partition )) return null; } return new SingleBracket(charOffset, Utils.isOpenningBracket(prevChar), prevChar); } private BracketsPair getMatchingPair(IDocument doc, int offset) throws BadLocationException { IRegion region = _matcher.match(doc, offset); if( region == null ) return null; if( region.getLength() < 1 ) throw new RuntimeException("length is less than 1"); //$NON-NLS-1$ boolean isAnchorOpening = (ICharacterPairMatcher.LEFT == _matcher.getAnchor()); int targetOffset = isAnchorOpening ? region.getOffset() + region.getLength() : region.getOffset() + 1; offset--; targetOffset--; if( isAnchorOpening ) return new BracketsPair(offset, doc.getChar(offset), targetOffset, doc.getChar(targetOffset)); else return new BracketsPair(targetOffset, doc.getChar(targetOffset), offset, doc.getChar(offset)); } }