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