/*=============================================================================# # 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.List; import org.eclipse.core.runtime.Assert; 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.GlobalTemplateVariables; import org.eclipse.jface.text.templates.SimpleTemplateVariableResolver; 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.TemplateVariable; import org.eclipse.jface.text.templates.TemplateVariableResolver; import org.eclipse.text.edits.MalformedTreeException; import org.eclipse.text.edits.MultiTextEdit; import org.eclipse.text.edits.ReplaceEdit; import org.eclipse.text.edits.TextEdit; import de.walware.ecommons.ltk.IElementName; import de.walware.ecommons.ltk.core.model.ISourceUnit; import de.walware.ecommons.ltk.core.model.IWorkspaceSourceUnit; import de.walware.ecommons.ltk.internal.ui.TemplatesMessages; public class SourceEditorContextType extends TemplateContextType { /** * Resolver that resolves to the variable defined in the context. */ protected static class CodeTemplatesVariableResolver extends TemplateVariableResolver { public CodeTemplatesVariableResolver(final String type, final String description) { super(type, description); } @Override protected String resolve(final TemplateContext context) { return context.getVariable(getType()); } } protected static class InitialSelectionStart extends TemplateVariableResolver { public InitialSelectionStart() { super(SELECT_START_VARIABLE, TemplatesMessages.Templates_Variable_SelectionBegin_description); } @Override public void resolve(final TemplateVariable variable, final TemplateContext context) { variable.setValue(""); //$NON-NLS-1$ variable.setUnambiguous(true); } } protected static class InitialSelectionEnd extends TemplateVariableResolver { public InitialSelectionEnd() { super(SELECT_END_VARIABLE, TemplatesMessages.Templates_Variable_SelectionEnd_description); } @Override public void resolve(final TemplateVariable variable, final TemplateContext context) { variable.setValue(""); //$NON-NLS-1$ variable.setUnambiguous(true); } } /** * Resolver for file name. */ protected static class File extends SimpleTemplateVariableResolver { public File() { super("file_name", TemplatesMessages.Templates_Variable_File_description); //$NON-NLS-1$ } @Override protected String resolve(final TemplateContext context) { if (context instanceof IWorkbenchTemplateContext) { final ISourceUnit su = ((IWorkbenchTemplateContext) context).getSourceUnit(); if (su != null) { final IElementName elementName = su.getElementName(); if (elementName != null) { return elementName.getSegmentName(); } } } return ""; //$NON-NLS-1$ } } /** * Resolver for project name. */ protected static class Project extends SimpleTemplateVariableResolver { public Project() { super("enclosing_project", TemplatesMessages.Templates_Variable_EnclosingProject_description); //$NON-NLS-1$ } @Override protected String resolve(final TemplateContext context) { if (context instanceof IWorkbenchTemplateContext) { final ISourceUnit su = ((IWorkbenchTemplateContext) context).getSourceUnit(); if (su instanceof IWorkspaceSourceUnit) { return ((IWorkspaceSourceUnit) su).getResource().getProject().getName(); } } return ""; //$NON-NLS-1$ } } /** * Resolver for ToDo-tags. Intend to extend and overwrite {@link #getTag(ISourceUnit)} */ protected static class Todo extends SimpleTemplateVariableResolver { public Todo() { super("todo", TemplatesMessages.Templates_Variable_ToDo_description); //$NON-NLS-1$ } @Override protected String resolve(final TemplateContext context) { if (context instanceof IWorkbenchTemplateContext) { final String tag = getTag(((IWorkbenchTemplateContext) context).getSourceUnit()); if (tag != null) { return tag; } } return "TODO"; //$NON-NLS-1$ } protected String getTag(final ISourceUnit su) { return null; } } private static class MyLineSelection extends GlobalTemplateVariables.LineSelection { @Override protected String resolve(final TemplateContext context) { String value = super.resolve(context); final int length = value.length(); if (length > 0 && context instanceof DocumentTemplateContext) { final char c = value.charAt(length-1); if (c != '\n' && c != '\r') { value += TextUtilities.getDefaultLineDelimiter(((DocumentTemplateContext) context).getDocument()); } } return value; } } public static final String FILENAME_VARIABLE = "file_name"; //$NON-NLS-1$ public static final String SELECT_START_VARIABLE = "selection_begin"; //$NON-NLS-1$ public static final String SELECT_END_VARIABLE = "selection_end"; ////$NON-NLS-1$ public SourceEditorContextType(final String id, final String name) { super(id, name); } public SourceEditorContextType(final String id) { super(id); } public SourceEditorContextType() { super(); } protected void addCommonVariables() { addResolver(new GlobalTemplateVariables.Dollar()); addResolver(new GlobalTemplateVariables.Date()); addResolver(new GlobalTemplateVariables.Year()); addResolver(new GlobalTemplateVariables.Time()); addResolver(new GlobalTemplateVariables.User()); addResolver(new Project()); } protected void addEditorVariables() { addResolver(new GlobalTemplateVariables.Cursor()); addResolver(new GlobalTemplateVariables.WordSelection()); addResolver(new MyLineSelection()); } protected void addSourceUnitGenerationVariables() { addResolver(new File()); addResolver(new InitialSelectionStart()); addResolver(new InitialSelectionEnd()); } @Override public void resolve(final TemplateBuffer buffer, final TemplateContext context) throws MalformedTreeException, BadLocationException { Assert.isNotNull(context); final TemplateVariable[] variables= buffer.getVariables(); final IDocument document= new Document(buffer.getString()); final List<TextEdit> positions = TemplatesUtil.variablesToPositions(variables); final List<TextEdit> edits= new ArrayList<>(5); // iterate over all variables and try to resolve them for (int i= 0; i != variables.length; i++) { final TemplateVariable variable= variables[i]; if (variable.isUnambiguous()) { continue; } // remember old values final int[] oldOffsets= variable.getOffsets(); final int oldLength= variable.getLength(); final String oldValue= variable.getDefaultValue(); final String type= variable.getType(); TemplateVariableResolver resolver = getResolver(type); if (resolver == null) { resolver = new TemplateVariableResolver(); resolver.setType(type); } resolver.resolve(variable, context); final String value= variable.getDefaultValue(); final String[] ln = document.getLegalLineDelimiters(); final boolean multiLine = (TextUtilities.indexOf(ln, value, 0)[0] != -1); if (!oldValue.equals(value)) { // update buffer to reflect new value for (int k= 0; k != oldOffsets.length; k++) { String thisValue = value; if (multiLine) { final String indent = TemplatesUtil.searchIndentation(document, oldOffsets[k]); if (indent.length() > 0) { final StringBuilder temp = new StringBuilder(thisValue); int offset = 0; while (true) { final int[] search = TextUtilities.indexOf(ln, temp.toString(), offset); if (search[0] == -1) { break; } offset = search[0]+ln[search[1]].length(); temp.insert(offset, indent); offset += indent.length(); } thisValue = temp.toString(); } } edits.add(new ReplaceEdit(oldOffsets[k], oldLength, thisValue)); } } } final MultiTextEdit edit= new MultiTextEdit(0, document.getLength()); edit.addChildren(positions.toArray(new TextEdit[positions.size()])); edit.addChildren(edits.toArray(new TextEdit[edits.size()])); edit.apply(document, TextEdit.UPDATE_REGIONS); TemplatesUtil.positionsToVariables(positions, variables); buffer.setContent(document.get(), variables); } @Override public int hashCode() { return getId().hashCode(); } @Override public boolean equals(final Object obj) { if (!(obj instanceof SourceEditorContextType)) { return false; } final SourceEditorContextType other = (SourceEditorContextType) obj; return getId().equals(other.getId()); } }