package tk.eclipse.plugin.htmleditor.editors; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.Region; import org.eclipse.jface.text.source.ICharacterPairMatcher; import tk.eclipse.plugin.htmleditor.HTMLPlugin; /** * @author Naoki Takezoe */ public abstract class AbstractCharacterPairMatcher implements ICharacterPairMatcher { private int fAnchor; private boolean enable; private Map<String, String> pairMap = new HashMap<String, String>(); private List<String> startBlock = new ArrayList<String>(); private List<String> endBlock = new ArrayList<String>(); private List<String> quote = new ArrayList<String>(); private char delimiter = '='; public void setDelimiter(char c){ this.delimiter = c; } public void addQuoteCharacter(char c){ quote.add(String.valueOf(c)); } protected String getSource(IDocument document){ return document.get(); } public void addBlockCharacter(char start, char end){ pairMap.put(String.valueOf(start), String.valueOf(end)); pairMap.put(String.valueOf(end), String.valueOf(start)); startBlock.add(String.valueOf(start)); endBlock.add(String.valueOf(end)); } public void setEnable(boolean enable){ this.enable = enable; } public void dispose() { } public void clear() { } public IRegion match(IDocument document, int offset) { if(offset < 0 || offset >= document.getLength() || !enable){ return null; } String text = getSource(document); try { // MS: Not sure who's bug this is, but if you have a document with // one character in it, text.charAt(0) throws an ArrayIndexOutOfBounds. This // seems like an Eclipse bug, actually, but we'll check it anyway just in // case. if(document.getLength() > 1 && offset < document.getLength()){ char c = text.charAt(offset); if(isEndBlock(c)){ int place = getPrevPlace(text, c, offset-1); if(place >= 0){ fAnchor = ICharacterPairMatcher.LEFT; return new Region(place, 1); } } if(isQuoteCharacter(c)){ String substr = text.substring(0, offset); int stoffset = substr.lastIndexOf(c); int eqoffset = substr.lastIndexOf(delimiter); if(stoffset > eqoffset){ int place = substr.lastIndexOf(c, offset - 1); if(place >= 0){ fAnchor = ICharacterPairMatcher.LEFT; return new Region(place, 1); } } } } if(offset > 0){ char c = text.charAt(offset - 1); if(isStartBlock(c)){ int place = getNextPlace(text, c, offset+1); if(place >= 0){ fAnchor = ICharacterPairMatcher.RIGHT; return new Region(place, 1); } } if(isQuoteCharacter(c)){ String substr = text.substring(0, offset - 1); int stoffset = substr.lastIndexOf(c); int eqoffset = substr.lastIndexOf(delimiter); if(stoffset < eqoffset){ int place = text.indexOf(c, offset); if(place >= 0){ fAnchor = ICharacterPairMatcher.RIGHT; return new Region(place, 1); } } } } } catch(Exception ex){ HTMLPlugin.logException(ex); setEnable(false); } fAnchor = -1; return null; } private int getPrevPlace(String source, char c, int offset){ char pair = getPairCharacter(c); int nest = 0; for(int i=offset;i>=0;i--){ char nc = source.charAt(i); if(nc==c){ nest++; } else if(nc==pair){ if(nest==0){ return i; } else { nest--; } } } return -1; } private int getNextPlace(String source, char c, int offset){ char pair = getPairCharacter(c); int nest = 0; for(int i=offset;i<source.length();i++){ char nc = source.charAt(i); if(nc==c){ nest++; } else if(nc==pair){ if(nest==0){ return i; } else { nest--; } } } return -1; } private boolean isStartBlock(char c){ return startBlock.contains(String.valueOf(c)); } private boolean isEndBlock(char c){ return endBlock.contains(String.valueOf(c)); } private boolean isQuoteCharacter(char c){ return quote.contains(String.valueOf(c)); } private char getPairCharacter(char c){ String pair = pairMap.get(String.valueOf(c)); if(pair==null){ return 0; } return pair.charAt(0); } public int getAnchor() { return fAnchor; } }