| /*=============================================================================# |
| # Copyright (c) 2005, 2020 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 static org.eclipse.statet.jcommons.lang.ObjectUtils.nonNullAssert; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| 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 org.eclipse.statet.jcommons.lang.NonNullByDefault; |
| import org.eclipse.statet.jcommons.lang.Nullable; |
| |
| import org.eclipse.statet.internal.ltk.ui.TemplatesMessages; |
| import org.eclipse.statet.ltk.core.ElementName; |
| import org.eclipse.statet.ltk.core.util.UserInfo; |
| import org.eclipse.statet.ltk.model.core.elements.ISourceUnit; |
| import org.eclipse.statet.ltk.model.core.elements.IWorkspaceSourceUnit; |
| |
| |
| @NonNullByDefault |
| public class SourceEditorContextType extends TemplateContextType { |
| |
| |
| public static class AuthorName extends SimpleTemplateVariableResolver { |
| |
| public AuthorName() { |
| super("author_name", TemplatesMessages.Templates_Variable_AuthorName_description); //$NON-NLS-1$ |
| } |
| |
| @Override |
| protected String resolve(final TemplateContext context) { |
| return UserInfo.getAuthorInfo().getName(); |
| } |
| } |
| |
| public static class AuthorEmail extends SimpleTemplateVariableResolver { |
| |
| public AuthorEmail() { |
| super("author_email", TemplatesMessages.Templates_Variable_AuthorEmail_description); //$NON-NLS-1$ |
| } |
| |
| @Override |
| protected String resolve(final TemplateContext context) { |
| return UserInfo.getAuthorInfo().getEmail(); |
| } |
| } |
| |
| |
| /** |
| * 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 @Nullable String resolve(final TemplateContext context) { |
| return context.getVariable(getType()); |
| } |
| |
| } |
| |
| protected static class InitialSelectionStart extends TemplateVariableResolver { |
| |
| public InitialSelectionStart() { |
| super(SELECT_START_VAR_NAME, 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_VAR_NAME, 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_VAR_NAME, TemplatesMessages.Templates_Variable_File_description); |
| } |
| |
| @Override |
| protected String resolve(final TemplateContext context) { |
| if (context instanceof IWorkbenchTemplateContext) { |
| final ISourceUnit su= ((IWorkbenchTemplateContext) context).getSourceUnit(); |
| if (su != null) { |
| final ElementName 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 @Nullable String getTag(final @Nullable 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 FILE_NAME_VAR_NAME= "file_name"; //$NON-NLS-1$ |
| public static final String SELECT_START_VAR_NAME= "selection_begin"; //$NON-NLS-1$ |
| public static final String SELECT_END_VAR_NAME= "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 AuthorName()); |
| addResolver(new AuthorEmail()); |
| 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 { |
| nonNullAssert(context); |
| final TemplateVariable[] variables= buffer.getVariables(); |
| |
| final IDocument document= new Document(buffer.getString()); |
| final List<TextEdit> positions= TemplateUtils.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= TemplateUtils.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); |
| |
| TemplateUtils.positionsToVariables(positions, variables); |
| |
| buffer.setContent(document.get(), variables); |
| } |
| |
| |
| @Override |
| public int hashCode() { |
| return getId().hashCode(); |
| } |
| |
| @Override |
| public boolean equals(final @Nullable Object obj) { |
| if (this == obj) { |
| return true; |
| } |
| if (obj instanceof SourceEditorContextType) { |
| final SourceEditorContextType other= (SourceEditorContextType) obj; |
| return getId().equals(other.getId()); |
| } |
| return false; |
| } |
| |
| } |