blob: 597dadd04aca06fed95fb7713bf79c61c56e9bf6 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.uima.ruta.ide.ui.text;
import java.util.ArrayList;
import java.util.List;
import org.apache.uima.ruta.ide.core.RutaNature;
import org.eclipse.dltk.ast.ASTNode;
import org.eclipse.dltk.ast.ASTVisitor;
import org.eclipse.dltk.ast.declarations.ModuleDeclaration;
import org.eclipse.dltk.ast.expressions.StringLiteral;
import org.eclipse.dltk.ast.parser.ISourceParser;
import org.eclipse.dltk.ast.statements.Block;
import org.eclipse.dltk.compiler.env.ModuleSource;
import org.eclipse.dltk.core.DLTKCore;
import org.eclipse.dltk.core.DLTKLanguageManager;
import org.eclipse.dltk.core.IModelElement;
import org.eclipse.dltk.core.ISourceModule;
import org.eclipse.dltk.core.SourceParserUtil;
import org.eclipse.dltk.internal.ui.editor.ScriptEditor;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IDocumentExtension4;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.Region;
import org.eclipse.jface.text.source.ICharacterPairMatcher;
/**
* Helper class for match pairs of characters.
*/
public final class RutaPairMatcher implements ICharacterPairMatcher {
// private char[] fPairs;
private IDocument fDocument;
private int fOffset;
private int fStartPos;
private int fEndPos;
private int fAnchor;
private ScriptEditor editor;
private class PairBlock {
public PairBlock(int start, int end, char c) {
this.start = start;
this.end = end;
this.c = c;
}
int start;
int end;
char c;
}
private PairBlock[] cachedPairs;
private long cachedStamp = -1;
private long cachedHash = -1;
public RutaPairMatcher(char[] pairs, ScriptEditor editor) {
// if (pairs == null) {
// throw new IllegalArgumentException();
// }
// fPairs = pairs;
this.editor = editor;
}
private PairBlock[] computePairRanges(final int offset, String contents) {
ISourceParser pp = null;
pp = DLTKLanguageManager.getSourceParser(RutaNature.NATURE_ID);
ModuleDeclaration md = null;// pp.parse(null, contents.toCharArray(),
// null);
IModelElement el = this.editor.getInputModelElement();
if (el != null && el instanceof ISourceModule) {
md = SourceParserUtil.getModuleDeclaration((ISourceModule) el, null);
}
if (md == null) {
md = (ModuleDeclaration) pp.parse(new ModuleSource(contents), null);
}
if (md == null) {
return new PairBlock[0];
}
final List result = new ArrayList();
try {
md.traverse(new ASTVisitor() {
@Override
public boolean visitGeneral(ASTNode node) throws Exception {
if (node instanceof StringLiteral) {
StringLiteral be = (StringLiteral) node;
result.add(new PairBlock(offset + be.sourceStart(), offset + be.sourceEnd() - 1, '\"'));
// } else if (node instanceof RutaExecuteExpression) {
// RutaExecuteExpression be = (RutaExecuteExpression) node;
// result.add(new PairBlock(offset + be.sourceStart(),
// offset + be.sourceEnd() - 1, '['));
} else if (node instanceof Block) {
Block be = (Block) node;
result.add(new PairBlock(offset + be.sourceStart(), offset + be.sourceEnd() - 1, '{'));
}
return super.visitGeneral(node);
}
});
} catch (Exception e) {
if (DLTKCore.DEBUG) {
e.printStackTrace();
}
}
// Iterator i = statements.iterator();
// while (i.hasNext()) {
// Statement sst = (Statement) i.next();
// if (sst instanceof RutaStatement) {
// RutaStatement statement = (RutaStatement) sst;
// /*
// * result.add(new CodeBlock(statement, new Region(offset +
// * statement.sourceStart(), statement.sourceEnd() -
// * statement.sourceStart())));
// */
// Iterator si = statement.getExpressions().iterator();
// while (si.hasNext()) {
// Expression ex = (Expression) si.next();
// if (ex instanceof RutaBlockExpression) {
// RutaBlockExpression be = (RutaBlockExpression) ex;
// try {
// String newContents = contents.substring(be
// .sourceStart() + 1, be.sourceEnd() - 1);
// result.add(new PairBlock(offset + be.sourceStart(),
// offset + be.sourceEnd() - 1, '{'));
// PairBlock[] cb = computePairRanges(offset
// + be.sourceStart() + 1, newContents);
// for (int j = 0; j < cb.length; j++) {
// result.add(cb[j]);
// }
// } catch (StringIndexOutOfBoundsException e) {
// }
// } else if (ex instanceof StringLiteral) {
// StringLiteral be = (StringLiteral) ex;
// result.add(new PairBlock(offset + be.sourceStart(),
// offset + be.sourceEnd() - 1, '\"'));
// } else if (ex instanceof RutaExecuteExpression) {
// RutaExecuteExpression be = (RutaExecuteExpression) ex;
// result.add(new PairBlock(offset + be.sourceStart(),
// offset + be.sourceEnd() - 1, '['));
// }
// }
// }
// }
return (PairBlock[]) result.toArray(new PairBlock[result.size()]);
}
/**
* Fully recalcs pairs for document
*
* @param doc
* @throws BadLocationException
*/
private void recalc() throws BadLocationException {
String content = fDocument.get(0, fDocument.getLength());
cachedPairs = computePairRanges(0, content);
if (fDocument instanceof IDocumentExtension4) {
cachedStamp = ((IDocumentExtension4) fDocument).getModificationStamp();
} else {
cachedHash = content.hashCode();
}
}
/**
* Recalcs pairs for the document, only if it is required
*/
private void updatePairs() throws BadLocationException {
if (fDocument instanceof IDocumentExtension4) {
IDocumentExtension4 document = (IDocumentExtension4) fDocument;
if (document.getModificationStamp() == cachedStamp) {
return;
}
} else {
String content = fDocument.get(0, fDocument.getLength());
if (content.hashCode() == cachedHash) {
return;
}
}
recalc();
}
private static boolean isBrace(char c) {
return (c == '{' || c == '}' || c == '\"' || c == '[' || c == ']');
}
public IRegion match(IDocument document, int offset) {
if (document == null || offset < 0) {
throw new IllegalArgumentException();
}
try {
fOffset = offset;
fDocument = document;
if (!isBrace(fDocument.getChar(offset))
&& (offset == 0 || !isBrace(fDocument.getChar(offset - 1)))) {
return null;
}
updatePairs();
if (matchPairsAt() && fStartPos != fEndPos)
return new Region(fStartPos, fEndPos - fStartPos + 1);
} catch (BadLocationException e) {
if (DLTKCore.DEBUG_PARSER)
e.printStackTrace();
}
return null;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.text.source.ICharacterPairMatcher#getAnchor()
*/
public int getAnchor() {
return fAnchor;
}
public void dispose() {
clear();
fDocument = null;
}
public void clear() {
}
private boolean matchPairsAt() {
fStartPos = -1;
fEndPos = -1;
for (int i = 0; i < cachedPairs.length; i++) {
PairBlock block = cachedPairs[i];
if (fOffset == block.end + 1) {
fStartPos = block.start - 1;
fEndPos = block.start;
fAnchor = LEFT;
return true;
}
if (fOffset == block.start + 1) {
fStartPos = block.end - 1;
fEndPos = block.end;
fAnchor = LEFT;
return true;
}
}
return false;
}
}