blob: 50578d8152df09679457758ef39064b6c0caa4bf [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2005, 2019 Stephan Wahlbrink and others.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
# which is available at https://www.apache.org/licenses/LICENSE-2.0.
#
# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
#
# Contributors:
# Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
#=============================================================================*/
package org.eclipse.statet.ltk.ui.templates;
import java.util.List;
import java.util.regex.Matcher;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.TextUtilities;
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.TemplateContextType;
import org.eclipse.jface.text.templates.TemplateException;
import org.eclipse.jface.text.templates.TemplateTranslator;
import org.eclipse.jface.text.templates.TemplateVariable;
import org.eclipse.text.edits.InsertEdit;
import org.eclipse.text.edits.MultiTextEdit;
import org.eclipse.text.edits.TextEdit;
import org.eclipse.statet.jcommons.lang.NonNullByDefault;
import org.eclipse.statet.jcommons.lang.Nullable;
import org.eclipse.statet.jcommons.text.core.TextRegion;
import org.eclipse.statet.ecommons.text.TextUtil;
import org.eclipse.statet.ltk.model.core.elements.ISourceUnit;
import org.eclipse.statet.ltk.ui.sourceediting.ISourceEditor;
@NonNullByDefault
public class SourceEditorTemplateContext extends DocumentTemplateContext implements IWorkbenchTemplateContext {
public static final int FORMAT= 1 << 4;
public static final int FORMAT_START= 1 << 5;
protected static final String SELECTION_VAR_NAME= "selection"; //$NON-NLS-1$
protected static final String INDENTATION_VAR_NAME= "indentation"; //$NON-NLS-1$
private final ISourceEditor editor;
private final int flags;
public SourceEditorTemplateContext(final TemplateContextType type, final IDocument document,
final TextRegion region,
final ISourceEditor editor, final int flags) {
super(type, document, region.getStartOffset(), region.getLength());
this.editor= editor;
this.flags= flags;
}
@Override
public ISourceEditor getEditor() {
return this.editor;
}
@Override
public @Nullable ISourceUnit getSourceUnit() {
return this.editor.getSourceUnit();
}
public int getFlags() {
return this.flags;
}
@Override
public @Nullable String evaluateInfo(final Template template) throws BadLocationException, TemplateException {
final TemplateBuffer buffer= super.evaluate(template);
if (buffer != null) {
return buffer.getString();
}
return null;
}
@Override
public @Nullable TemplateBuffer evaluate(final Template template) throws BadLocationException, TemplateException {
if (!canEvaluate(template)) {
return null;
}
final String ln= TextUtilities.getDefaultLineDelimiter(getDocument());
final TemplateTranslator translator= new TemplateTranslator();
String pattern= template.getPattern();
// correct line delimiter
final Matcher matcher= TextUtil.LINE_DELIMITER_PATTERN.matcher(pattern);
if (matcher.find()) {
pattern= matcher.replaceAll(ln);
}
// default, see super
final TemplateBuffer buffer= translator.translate(pattern);
getContextType().resolve(buffer, this);
format(buffer);
final String selection= getVariable(SELECTION_VAR_NAME);
if (selection != null && TextUtilities.indexOf(getDocument().getLegalLineDelimiters(), selection, 0)[0] != -1) {
buffer.setContent(buffer.getString() + ln, buffer.getVariables());
}
return buffer;
}
private void format(final TemplateBuffer buffer) throws BadLocationException {
final TemplateVariable[] variables= buffer.getVariables();
final List<TextEdit> positions= TemplateUtils.variablesToPositions(variables);
final IDocument baseDoc= getDocument();
final IDocument templateDoc= new Document(buffer.getString());
final MultiTextEdit root= new MultiTextEdit(0, templateDoc.getLength());
root.addChildren(positions.toArray(new TextEdit[positions.size()]));
format(root, templateDoc, variables, baseDoc);
root.apply(templateDoc, TextEdit.UPDATE_REGIONS);
TemplateUtils.positionsToVariables(positions, variables);
buffer.setContent(templateDoc.get(), variables);
}
protected void format(final MultiTextEdit root, final IDocument templateDoc,
final TemplateVariable[] variables, final IDocument baseDoc)
throws BadLocationException {
indent(root, templateDoc, variables, baseDoc);
if ((getFlags() & FORMAT_START) != 0 && getVariable(INDENTATION_VAR_NAME) == null
&& getStart() > 0 && !Character.isWhitespace(baseDoc.getChar(getStart() - 1))
&& templateDoc.getLength() > 0 && !Character.isWhitespace(templateDoc.getChar(0)) ) {
root.addChild(new InsertEdit(0, " ")); //$NON-NLS-1$
}
}
protected void indent(final MultiTextEdit root, final IDocument templateDoc,
final TemplateVariable[] variables, final IDocument baseDoc)
throws BadLocationException {
String indentation= getVariable(INDENTATION_VAR_NAME);
// first line
{ int line= 0;
int offset= templateDoc.getLineOffset(line);
if (indentation != null) {
final TextEdit edit= new InsertEdit(offset, indentation);
root.addChild(edit);
}
else {
indentation= TemplateUtils.searchIndentation(baseDoc, getStart());
}
// following lines
while (++line < templateDoc.getNumberOfLines()) {
offset= templateDoc.getLineOffset(line);
final TextEdit edit= new InsertEdit(offset, indentation);
root.addChild(edit);
}
}
}
}