package org.rubypeople.rdt.internal.ui.rubyeditor;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.DocumentCommand;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.Region;
import org.eclipse.jface.text.link.LinkedPosition;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.text.templates.DocumentTemplateContext;
import org.eclipse.jface.text.templates.Template;
import org.eclipse.jface.text.templates.TemplateBuffer;
import org.eclipse.jface.text.templates.TemplateContext;
import org.eclipse.jface.text.templates.TemplateContextType;
import org.eclipse.jface.text.templates.TemplateException;
import org.eclipse.jface.text.templates.TemplateVariable;
import org.rubypeople.rdt.internal.ui.text.ruby.LegacyRubyCompletionProcessor;
public class RubyAutoEditStrategy implements ILinkedModeEditStrategy {
private LegacyRubyCompletionProcessor fRubyCp;
private ISourceViewer fViewer;
/** The linked position list */
protected final List fPositionList = new ArrayList();
public RubyAutoEditStrategy(String partition, ISourceViewer viewer,
LegacyRubyCompletionProcessor rhtmlCp) {
fViewer = viewer;
fRubyCp = rhtmlCp;
}
public void customizeDocumentCommand(IDocument document,
DocumentCommand command) {
fPositionList.clear();
if (command.text.length() == 1) {
if (command.text.charAt(0) == '\t') {
try {
int length = 0;
while ((command.offset - length > 0)
&& Pattern.matches("\\w", document.get(
command.offset - length - 1, 1))) {
length++;
}
String prefix = document.get(command.offset - length,
length);
Region region = new Region(
command.offset - prefix.length(), prefix.length());
if (prefix.length() > 0) {
Template[] templates = fRubyCp
.getTemplates("ruby");
for (int i = 0; i < templates.length; i++) {
Template template = templates[i];
if (template.getName().equals(prefix)) {
final int offset = command.offset
- prefix.length();
TemplateContextType contextType = fRubyCp
.getContextType(fViewer, region);
TemplateContext context = new DocumentTemplateContext(
contextType, document, region
.getOffset(), region
.getLength());
context.setReadOnly(false);
TemplateBuffer templateBuffer;
try {
templateBuffer = context.evaluate(template);
} catch (TemplateException e1) {
return;
}
int start = getReplaceOffset(context, region);
int end = Math.max(getReplaceEndOffset(context,
region), offset);
// insert template string
String templateString = templateBuffer
.getString();
command.text = templateString;
command.offset = start;
command.length = end - start;
fPositionList.add(new LinkedPosition(document,
offset + templateString.length(), 0));
// translate positions
TemplateVariable[] variables = templateBuffer
.getVariables();
for (int z = 0; z != variables.length; z++) {
TemplateVariable variable = variables[z];
if (variable.isUnambiguous())
continue;
int[] offsets = variable.getOffsets();
int variablelength = variable.getLength();
for (int j = 0; j != offsets.length; j++)
fPositionList.add(new LinkedPosition(
document, offsets[j] + start,
variablelength));
}
break;
}
}
}
} catch (BadLocationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public LinkedPosition[] getLinkedPositions() {
final int size = fPositionList.size();
if (size > 0) {
final LinkedPosition[] positions = new LinkedPosition[size];
fPositionList.toArray(positions);
return positions;
}
return null;
}
/**
* Returns the offset of the range in the document that will be replaced by
* applying this template.
*
* @return the offset of the range in the document that will be replaced by
* applying this template
* @since 3.1
*/
protected final int getReplaceOffset(TemplateContext context, Region region) {
int start;
if (context instanceof DocumentTemplateContext) {
DocumentTemplateContext docContext = (DocumentTemplateContext) context;
start = docContext.getStart();
} else {
start = region.getOffset();
}
return start;
}
/**
* Returns the end offset of the range in the document that will be replaced
* by applying this template.
*
* @return the end offset of the range in the document that will be replaced
* by applying this template
* @since 3.1
*/
protected final int getReplaceEndOffset(TemplateContext context,
Region region) {
int end;
if (context instanceof DocumentTemplateContext) {
DocumentTemplateContext docContext = (DocumentTemplateContext) context;
end = docContext.getEnd();
} else {
end = region.getOffset() + region.getLength();
}
return end;
}
}