package net.lucky_dip.hamleditor.editor;
import java.util.ArrayList;
import net.lucky_dip.hamleditor.HamlesqueBlock;
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.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.swt.widgets.Display;
public class HamlReconcilingStrategy implements IReconcilingStrategy, IReconcilingStrategyExtension {
private HamlesqueEditor editor;
private IDocument document;
private int currentLine;
private String[] lines;
protected final ArrayList positions = new ArrayList();
public HamlReconcilingStrategy(HamlesqueEditor editor) {
this.editor = editor;
}
public void initialReconcile() {
positions.clear();
currentLine = 0;
String template = document.get();
lines = template.split("\\n");
// we can't have a region starting on the last line
Position p;
while (currentLine < lines.length) {
p = getNextPosition();
if (p != null) {
positions.add(p);
}
}
Display.getDefault().asyncExec(new Runnable() {
public void run() {
editor.updateFoldingStructure(positions);
}
});
}
private Position getNextPosition() {
Position res = null;
try {
String line = lines[currentLine];
// regions can't start on an empty line
if (line.trim().length() > 0) {
int start = document.getLineOffset(currentLine);
int length = getNextPositionLength();
if (start + length >= document.getLength()) {
length = document.getLength() - start;
}
if (length > 0) {
res = new Position(start, length);
}
}
else {
currentLine++;
}
}
catch (BadLocationException e) {
res = null;
}
return res;
}
/**
* Returns the length in characters from the start of currentLine to when
* the region begun here should end.
*
* Returns 0 if no region found.
*
* @throws BadLocationException
*/
private int getNextPositionLength() throws BadLocationException {
int res = 0;
int lastLine = getLastLineInNextRegion();
if (lastLine > currentLine && lastLine < lines.length) {
for (int i = currentLine; i <= lastLine; i++) {
String trimmedLine = lines[i].trim();
if (trimmedLine.length() > 0 || i < lastLine) {
res += document.getLineLength(i);
}
}
}
currentLine = lastLine + 1;
return res;
}
/**
* Figures out which lines should be included in the next region.
*
* The index of the last line in the next region is returned.
*/
private int getLastLineInNextRegion() {
int res = currentLine;
int startOffset = HamlesqueBlock.countIndentSpaces(lines[currentLine]);
for (int i = currentLine + 1; i < lines.length; i++) {
int currentOffset = HamlesqueBlock.countIndentSpaces(lines[i]);
String trimmedLine = lines[i].trim();
if (currentOffset == startOffset && trimmedLine.length() > 0) {
// region over
break;
}
else if (currentOffset > startOffset || lines[i].trim().length() == 0) {
res++;
}
}
if (res > currentLine && res < lines.length) {
// trim all trailing whitespace
String lastLine;
while ((lastLine = lines[res]).trim().length() == 0) {
res--;
}
}
return res;
}
public void setProgressMonitor(IProgressMonitor monitor) {
}
public void reconcile(DirtyRegion dirtyRegion, IRegion subRegion) {
initialReconcile();
}
public void reconcile(IRegion partition) {
initialReconcile();
}
public void setDocument(IDocument document) {
this.document = document;
}
}