/*=============================================================================#
# Copyright (c) 2005-2016 Stephan Wahlbrink (WalWare.de) and others.
# 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:
# Stephan Wahlbrink - initial API and implementation
#=============================================================================*/
package de.walware.ecommons.ltk.ui.templates;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.jface.text.AbstractDocument;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.Region;
import org.eclipse.jface.text.templates.TemplateBuffer;
import org.eclipse.jface.text.templates.TemplateVariable;
import org.eclipse.text.edits.RangeMarker;
import org.eclipse.text.edits.TextEdit;
public class TemplatesUtil {
public static class EvaluatedTemplate {
private String fContent;
private IRegion fSelect;
private final String fLineDelimiter;
private AbstractDocument fPostEditDocument;
private Position fPostEditSelectPosition;
public EvaluatedTemplate(final TemplateBuffer buffer, final String lineDelimiter) {
setContent(buffer.getString());
final TemplateVariable selectStartVariable = findVariable(buffer, SourceEditorContextType.SELECT_START_VARIABLE);
final TemplateVariable selectEndVariable = findVariable(buffer, SourceEditorContextType.SELECT_END_VARIABLE);
if (selectStartVariable != null && selectStartVariable.getOffsets().length == 1) {
fSelect = new Region(selectStartVariable.getOffsets()[0],
(selectEndVariable != null && selectEndVariable.getOffsets().length == 1) ?
Math.max(selectEndVariable.getOffsets()[0] - selectStartVariable.getOffsets()[0], 0) : 0);
}
fLineDelimiter = lineDelimiter;
}
/**
* Sets the evaluated template text
* @param content the text
*/
public void setContent(final String content) {
fPostEditDocument = null;
fContent = content;
}
/**
* Returns the evaluated template text
* @return the text
* */
public String getContent() {
return fContent;
}
/**
* Returns the region to select, if specified
*/
public IRegion getRegionToSelect() {
return fSelect;
}
/**
* Returns a document which can be used for further edits in the text.
* After edits are done, {@link #finishPostEdit()} must be called.
*
* @return a document with the template content
* @throws BadLocationException
*/
public AbstractDocument startPostEdit() throws BadLocationException {
if (fPostEditDocument == null) {
fPostEditDocument = new Document(getContent()) {
@Override
public String getDefaultLineDelimiter() {
return fLineDelimiter;
}
};
if (fSelect != null) {
fPostEditSelectPosition = new Position(fSelect.getOffset(), fSelect.getLength());
fPostEditDocument.addPosition(fPostEditSelectPosition);
}
}
return fPostEditDocument;
}
/**
* See {@link #startPostEdit()}.
*/
public void finishPostEdit() {
setContent(fPostEditDocument.get());
if (fPostEditSelectPosition != null) {
fSelect = (fPostEditSelectPosition.isDeleted) ? null :
new Region(fPostEditSelectPosition.getOffset(), fPostEditSelectPosition.getLength());
}
}
}
public static String searchIndentation(final IDocument document, final int offset) {
try {
final IRegion region = document.getLineInformationOfOffset(offset);
final String lineContent = document.get(region.getOffset(), region.getLength());
return searchIndentation(lineContent);
}
catch (final BadLocationException e) {
return ""; //$NON-NLS-1$
}
}
private static String searchIndentation(final String text) throws BadLocationException {
int i = 0;
for (; i < text.length(); i++) {
final char c = text.charAt(i);
if (!(c == ' ' || c == '\t')) {
break;
}
}
return text.substring(0, i);
}
public static void positionsToVariables(final List<TextEdit> positions, final TemplateVariable[] variables) {
final Iterator<TextEdit> iterator = positions.iterator();
for (final TemplateVariable variable : variables) {
final int[] offsets = new int[variable.getOffsets().length];
for (int j = 0; j < offsets.length; j++) {
offsets[j] = iterator.next().getOffset();
}
variable.setOffsets(offsets);
}
}
public static List<TextEdit> variablesToPositions(final TemplateVariable[] variables) {
final List<TextEdit> positions = new ArrayList<>(5);
for (final TemplateVariable variable : variables) {
final int[] offsets = variable.getOffsets();
// trim positions off whitespace
final String value = variable.getDefaultValue();
int wsStart = 0;
while (wsStart < value.length() && Character.isWhitespace(value.charAt(wsStart)) && !isLineDelimiterChar(value.charAt(wsStart))) {
wsStart++;
}
variable.getValues()[0] = value.substring(wsStart);
for (int j = 0; j != offsets.length; j++) {
offsets[j] += wsStart;
positions.add(new RangeMarker(offsets[j], 0));
}
}
return positions;
}
public static TemplateVariable findVariable(final TemplateBuffer buffer, final String variableType) {
final TemplateVariable[] variables = buffer.getVariables();
for (final TemplateVariable cand : variables) {
if (variableType.equals(cand.getType())) {
return cand;
}
}
return null;
}
private static boolean isLineDelimiterChar(final char c) {
return (c == '\r' || c == '\n');
}
/**
* Indents each line of the template (document) using the specified indentation (string).
* An empty last line is note indented.
*
* @param doc document with the template
* @param lineIndent string to use as line indentation
* @throws BadLocationException
*/
public static void indentTemplateDocument(final AbstractDocument doc, final String lineIndent)
throws BadLocationException {
final int lastLine = doc.getNumberOfLines()-1;
for (int templateLine = 0; templateLine < lastLine; templateLine++) {
doc.replace(doc.getLineOffset(templateLine), 0, lineIndent);
}
final int lineOffset = doc.getLineOffset(lastLine);
if (lineOffset != doc.getLength()) {
doc.replace(lineOffset, 0, lineIndent);
doc.replace(doc.getLength(), 0, doc.getDefaultLineDelimiter());
}
}
}