/*******************************************************************************
* Copyright (c) 2015 Bruno Medeiros and other Contributors.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Bruno Medeiros - initial API and implementation
*******************************************************************************/
package melnorme.lang.ide.ui.templates;
import static melnorme.utilbox.core.Assert.AssertNamespace.assertTrue;
import java.util.Collections;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.TextUtilities;
import org.eclipse.jface.text.templates.Template;
import org.eclipse.jface.text.templates.TemplateBuffer;
import org.eclipse.jface.text.templates.TemplateException;
import org.eclipse.jface.text.templates.TemplateTranslator;
import org.eclipse.text.edits.MalformedTreeException;
import _org.eclipse.jdt.internal.corext.template.java.JavaContext;
import _org.eclipse.jdt.internal.corext.template.java.JavaFormatter;
import melnorme.lang.ide.core.ISourceFile;
import melnorme.lang.ide.core.text.DocumentModification;
import melnorme.lang.ide.core.text.TextSourceUtils;
import melnorme.lang.utils.parse.StringCharSource;
import melnorme.utilbox.collections.ArrayList2;
public class LangContext extends JavaContext {
public LangContext(LangTemplateContextType type, IDocument document, int completionOffset,
int completionLength, ISourceFile compilationUnit) {
super(type, document, completionOffset, completionLength, compilationUnit);
}
public LangContext(LangTemplateContextType type, IDocument document, Position completionPosition,
ISourceFile compilationUnit) {
super(type, document, completionPosition, compilationUnit);
}
@Override
public TemplateBuffer evaluate(Template template) throws BadLocationException, TemplateException {
return evaluate(template, true);
}
public TemplateBuffer evaluate(Template template, boolean fixIndentation)
throws BadLocationException, TemplateException {
if (!canEvaluate(template))
return null;
TemplateTranslator translator= new TemplateTranslator();
String pattern = template.getPattern();
// if(fixIndentation) {
// pattern = fixIndentation(pattern);
// }
TemplateBuffer buffer = translator.translate(pattern);
getContextType().resolve(buffer, this);
if(fixIndentation) {
String delimiter = TextUtilities.getDefaultLineDelimiter(getDocument());
JavaFormatter formatter = new JavaFormatter(delimiter) {
@Override
protected void indent(IDocument document) throws BadLocationException, MalformedTreeException {
simpleIndent(document);
}
};
formatter.format(buffer, this);
}
return buffer;
}
// Alternative method to fix indentation, not used currently.
protected String fixIndentation(String docString) {
final String delimeter = "\n";
final String indent = TextSourceUtils.getLineIndentForOffset(docString, getStart());
StringBuilder newContents = new StringBuilder();
StringCharSource parser = new StringCharSource(docString);
String start = parser.consumeUntil(delimeter);
newContents.append(start);
while(true) {
if(!parser.tryConsume(delimeter)) {
assertTrue(parser.lookaheadIsEOS());
break;
}
newContents.append(delimeter);
newContents.append(indent);
String line = parser.consumeUntil(delimeter);
newContents.append(line);
}
return newContents.toString();
}
/**
* This method is better than {@link #fixIndentation(String)} since it updates variable positions,
* as such, it can be used after the template pattern has been evaluate.
*/
protected void simpleIndent(IDocument document) throws BadLocationException {
String docContents = getDocument().get();
final String delimeter = "\n";
final String indent = TextSourceUtils.getLineIndentForOffset(docContents, getStart());
ArrayList2<DocumentModification> changes = new ArrayList2<>();
StringCharSource parser = new StringCharSource(document.get());
parser.consumeUntil(delimeter);
while(true) {
if(!parser.tryConsume(delimeter)) {
assertTrue(parser.lookaheadIsEOS());
break;
}
changes.add(new DocumentModification(parser.getReadPosition(), 0, indent));
parser.consumeUntil(delimeter);
}
// Need to reverse so that the offset of each change remains meaningul.
Collections.reverse(changes);
for (DocumentModification docMod : changes) {
docMod.apply(document);
}
}
}