/*
* Copyright (C) 2003-2007 Kepler Project.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package org.keplerproject.ldt.ui.editors;
import java.io.IOException;
import java.io.StringReader;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Stack;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITypedRegion;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.reconciler.DirtyRegion;
import org.eclipse.jface.text.reconciler.IReconcilingStrategy;
import org.eclipse.jface.text.reconciler.IReconcilingStrategyExtension;
import org.eclipse.jface.text.source.projection.ProjectionAnnotation;
import org.eclipse.swt.widgets.Display;
import org.keplerproject.ldt.ui.editors.lex.Scanner;
import org.keplerproject.ldt.ui.editors.lex.Symbol;
import org.keplerproject.ldt.ui.editors.lex.sym;
/**
* A embeded Folding Reconcilier. One day a put it out of here. for now fold
* just functions and multiline comments.
*
* @author guilherme
* @version $Id$
*/
public class LuaFoldingReconcilingStrategy implements IReconcilingStrategy,
IReconcilingStrategyExtension {
private LuaEditor reditor;
private IDocument doc;
//private ArrayList fPositions = new ArrayList();
private Map currentAnnotations = new HashMap();
private int fOffset;
private int fRangeEnd;
private int cNextPos;
public void setDocument(IDocument document) {
this.doc = document;
}
public void reconcile(DirtyRegion dirtyRegion, IRegion subRegion) {
initialReconcile();
}
public void reconcile(IRegion partition) {
initialReconcile();
}
public void setProgressMonitor(IProgressMonitor monitor) {
// TODO No progress.
}
public void initialReconcile() {
try {
fOffset = 0;
fRangeEnd = doc.getLength();
calculatePositions();
} catch (Exception e) {
// Do nothing..
return;
}
}
private Map deleteAnnotations;
private Map newAnnotations;
protected void registerFunction(String line) {
Pattern p1 = Pattern.compile("function\\s+(\\w+)\\s*?[(]([^)]*?)[)]");
Pattern p2 = Pattern.compile("(\\w+)\\s*?[=]\\s*?function\\s*?[(]([^)]*?)[)]");
Matcher m = p1.matcher(line);
Matcher n = p2.matcher(line);
boolean foundStraight=false;
boolean foundLambda=false;
foundLambda = n.find() || (foundStraight = m.find());
while(foundStraight || foundLambda) {
String functionName = foundStraight ? m.group(1) : n.group(1);
String parameters = foundStraight ? m.group(2) : n.group(2);
System.out.println("Function:"+functionName);
System.out.println("Parameters:"+parameters);
foundLambda = n.find() || (foundStraight = m.find());
}
}
protected void calculatePositions() {
// if (reditor.isDirty())
// return;
//fPositions.clear();
deleteAnnotations = currentAnnotations;
currentAnnotations = new HashMap();
newAnnotations = new HashMap();
cNextPos = fOffset;
try {
findNextFunction(cNextPos);
} catch (BadLocationException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Display.getDefault().asyncExec(new Runnable() {
public void run() {
//reditor.updateFoldingStructure(fPositions);
reditor.updateFoldingStructure(newAnnotations, deleteAnnotations);
}
});
}
private void findNextFunction(int nextPos) throws BadLocationException,
IOException {
cNextPos = nextPos;
// int funcInit = -1;
Stack stk = new Stack();
// boolean onMultStr = false;
int onMultStr = 0;
boolean elseIf = false;
while (cNextPos < fRangeEnd) {
ITypedRegion region = doc.getPartition(cNextPos);
String contType = region.getType();
if (contType.equals("__lua_multiline_comment")) {
int breakCount = 0;
if (region.getOffset() + region.getLength() + 1 < doc
.getLength()) {
char lineb1 = doc.getChar(region.getOffset()
+ region.getLength());
char lineb2 = doc.getChar(region.getOffset()
+ region.getLength() + 1);
if (lineb1 == '\r' && lineb2 == '\n')
// Windows
breakCount = 2;
else if (lineb1 == '\r' || lineb1 == '\n')
breakCount = 1;
}
emitPosition(region.getOffset(), region.getLength()
+ breakCount);
cNextPos += region.getLength() + breakCount;
} else {
cNextPos += region.getLength();
}
}
Scanner scanner = new Scanner(new StringReader(doc.get()));
Symbol symbol = scanner.yylex();
if (symbol.sym == sym.EOF) {
cNextPos += 2;
return;
}
while (symbol.sym != sym.EOF) {
//symbol.left -1 (because jflex return line starting at 1 instead of 0)
IRegion lineRegion = doc.getLineInformation(symbol.left -1);
if (symbol.sym == sym.FUNCTION) {
String functionName = doc.get(lineRegion.getOffset(), lineRegion.getLength());
registerFunction(functionName);
}
if (onMultStr == 0) {
if (symbol.sym == sym.DO || symbol.sym == sym.FUNCTION) {
stk.push(new Object[] { lineRegion, symbol });
} else if (symbol.sym == sym.THEN) {
if (elseIf)
elseIf = false;
else
stk.push(new Object[] { lineRegion, symbol });
} else if (symbol.sym == sym.ELSEIF) {
elseIf = true;
} else if (symbol.sym == sym.END) {
if (stk.empty())
return;
Object[] stkContent = (Object[]) stk.pop();
IRegion lReg = (IRegion) stkContent[0];
if (((Symbol) stkContent[1]).sym != sym.FUNCTION
|| lReg.getOffset() == lineRegion.getOffset()) {
symbol = scanner.yylex();
continue;
}
int breakCount = 0;
if (lineRegion.getOffset() + 3 + 1 < doc.getLength()) {
char lineb1 = doc
.getChar(lineRegion.getOffset() + 3);
char lineb2 = doc
.getChar(lineRegion.getOffset() + 3 + 1);
if (lineb1 == '\r' && lineb2 == '\n')
// Windows
breakCount = 2;
else if (lineb1 == '\r' || lineb1 == '\n')
breakCount = 1;
}
// Dont ask me to explain this right now..
emitPosition(lReg.getOffset(), lineRegion
.getOffset()
+ lineRegion.getLength()
- lReg.getOffset()
+ breakCount);
} else if (symbol.sym == sym.DBLBRACK) {
onMultStr++;
}
} else if (symbol.sym == sym.DBRBRACK) {
onMultStr--;
} else if (symbol.sym == sym.DBLBRACK)
onMultStr++;
symbol = scanner.yylex();
}
}
protected void emitPosition(int startOffset, int length)
{
Iterator it = deleteAnnotations.keySet().iterator();
while (it.hasNext())
{
Object key = it.next();
Position curPos = (Position) deleteAnnotations.get(key);
if (curPos.length == length && curPos.offset == startOffset)
{
currentAnnotations.put(key, deleteAnnotations.remove(key));
return;
}
}
ProjectionAnnotation newAnn = new ProjectionAnnotation();
Position pos = new Position(startOffset, length);
newAnnotations.put(newAnn, pos);
currentAnnotations.put(newAnn, pos);
//fPositions.add(new Position(startOffset, length));
}
public void setEditor(LuaEditor editor) {
this.reditor = editor;
}
}