blob: 4bcf74615d580a02d7cd2dd0eb3d4fef3092126f [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2019 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
* Lars Vogel <lars.vogel@gmail.com> - [templates][content assist] Ctrl+Space without any starting letter shows to no templates - https://bugs.eclipse.org/406463
* Lukas Hanke <hanke@yatta.de> - [templates][content assist] Content assist for 'for' loop should suggest member variables - https://bugs.eclipse.org/117215
* Nicolaj Hoess <nicohoess@gmail.com> - Make some internal methods accessible to help Postfix Code Completion plug-in - https://bugs.eclipse.org/433500
* Microsoft Corporation - moved template related code to jdt.core.manipulation - https://bugs.eclipse.org/549989
*******************************************************************************/
package org.eclipse.jdt.internal.corext.template.java;
import java.lang.reflect.InvocationTargetException;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
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.TemplateContextType;
import org.eclipse.jface.text.templates.TemplateException;
import org.eclipse.jface.text.templates.TemplateVariable;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.internal.core.manipulation.util.Strings;
import org.eclipse.jdt.internal.corext.template.java.CompilationUnitCompletion.Variable;
import org.eclipse.jdt.ui.PreferenceConstants;
import org.eclipse.jdt.internal.ui.JavaPlugin;
import org.eclipse.jdt.internal.ui.text.template.contentassist.MultiVariable;
import org.eclipse.jdt.internal.ui.text.template.contentassist.MultiVariableGuess;
import org.eclipse.jdt.internal.ui.util.ExceptionHandler;
/**
* A context for Java source.
*/
public class JavaContext extends CompilationUnitContext implements IJavaContext {
private JavaContextCore fJavaContextCore;
/**
* Creates a java template context.
*
* @param type the context type.
* @param document the document.
* @param completionOffset the completion offset within the document.
* @param completionLength the completion length.
* @param compilationUnit the compilation unit (may be <code>null</code>).
*/
public JavaContext(TemplateContextType type, IDocument document, int completionOffset, int completionLength, ICompilationUnit compilationUnit) {
super(type, document, completionOffset, completionLength, compilationUnit);
this.fJavaContextCore = new JavaContextCore(this, type, document, completionOffset, completionLength, compilationUnit);
}
/**
* Creates a java template context.
*
* @param type the context type.
* @param document the document.
* @param completionPosition the position defining the completion offset and length
* @param compilationUnit the compilation unit (may be <code>null</code>).
* @since 3.2
*/
public JavaContext(TemplateContextType type, IDocument document, Position completionPosition, ICompilationUnit compilationUnit) {
super(type, document, completionPosition, compilationUnit);
this.fJavaContextCore = new JavaContextCore(this, type, document, completionPosition, compilationUnit);
}
/**
* Adds a context type that is also compatible. That means the context can also process templates of that context type.
*
* @param contextTypeId the context type to accept
*/
@Override
public void addCompatibleContextType(String contextTypeId) {
this.fJavaContextCore.addCompatibleContextType(contextTypeId);
}
/**
* Returns the indentation level at the position of code completion.
*
* @return the indentation level at the position of the code completion
*/
private int getIndentation() {
int start= getStart();
IDocument document= getDocument();
try {
IRegion region= document.getLineInformationOfOffset(start);
String lineContent= document.get(region.getOffset(), region.getLength());
IJavaProject project= getJavaProject();
return Strings.computeIndentUnits(lineContent, project);
} catch (BadLocationException e) {
return 0;
}
}
/*
* @see TemplateContext#evaluate(Template template)
*/
@Override
public TemplateBuffer evaluate(Template template) throws BadLocationException, TemplateException {
TemplateBuffer buffer= this.fJavaContextCore.evaluate(template);
IPreferenceStore prefs= JavaPlugin.getDefault().getPreferenceStore();
boolean useCodeFormatter= prefs.getBoolean(PreferenceConstants.TEMPLATES_USE_CODEFORMATTER);
IJavaProject project= getJavaProject();
JavaFormatter formatter= new JavaFormatter(TextUtilities.getDefaultLineDelimiter(getDocument()), getIndentation(), useCodeFormatter, project);
formatter.format(buffer, this);
return buffer;
}
/*
* @see TemplateContext#canEvaluate(Template templates)
*/
@Override
public boolean canEvaluate(Template template) {
return this.fJavaContextCore.canEvaluate(template);
}
/*
* @see DocumentTemplateContext#getCompletionPosition();
*/
@Override
public int getStart() {
return this.fJavaContextCore.getStart();
}
/*
* @see org.eclipse.jdt.internal.corext.template.DocumentTemplateContext#getEnd()
*/
@Override
public int getEnd() {
return this.fJavaContextCore.getEnd();
}
/*
* @see org.eclipse.jdt.internal.corext.template.DocumentTemplateContext#getKey()
*/
@Override
public String getKey() {
return this.fJavaContextCore.getKey();
}
/**
* Returns the character before the start position of the completion.
*
* @return the character before the start position of the completion
*/
public char getCharacterBeforeStart() {
return this.fJavaContextCore.getCharacterBeforeStart();
}
@Override
public void handleException(Exception e) {
String title= JavaTemplateMessages.JavaContext_error_title;
if (e instanceof CoreException)
ExceptionHandler.handle((CoreException)e, null, title, null);
else if (e instanceof InvocationTargetException)
ExceptionHandler.handle((InvocationTargetException)e, null, title, null);
else {
JavaPlugin.log(e);
String message= e.getMessage();
if (message == null) {
message= JavaTemplateMessages.JavaContext_unexpected_error_message;
}
MessageDialog.openError(null, title, message);
}
}
/**
* Returns the names of arrays available in the current {@link CompilationUnit}'s scope.
*
* @return the names of local arrays available in the current {@link CompilationUnit}'s scope
*/
@Override
public Variable[] getArrays() {
return this.fJavaContextCore.getArrays();
}
/**
* Returns the names of local variables matching <code>type</code>.
*
* @param type the type of the variables
* @return the names of local variables matching <code>type</code>
* @since 3.3
*/
@Override
public Variable[] getLocalVariables(String type) {
return this.fJavaContextCore.getLocalVariables(type);
}
/**
* Returns the names of fields matching <code>type</code>.
*
* @param type the type of the fields
* @return the names of fields matching <code>type</code>
* @since 3.3
*/
@Override
public Variable[] getFields(String type) {
return this.fJavaContextCore.getFields(type);
}
/**
* Returns the names of iterables or arrays available in the current {@link CompilationUnit}'s scope.
*
* @return the names of iterables or arrays available in the current {@link CompilationUnit}'s scope
*/
@Override
public Variable[] getIterables() {
return this.fJavaContextCore.getIterables();
}
@Override
public void markAsUsed(String name) {
this.fJavaContextCore.markAsUsed(name);
}
@Override
public String[] suggestVariableNames(String type) throws IllegalArgumentException {
return this.fJavaContextCore.suggestVariableNames(type);
}
String[] computeExcludes() {
return this.fJavaContextCore.computeExcludes();
}
/**
* Adds an import for type with type name <code>type</code> if possible.
* Returns a string which can be used to reference the type.
*
* @param type the fully qualified name of the type to import
* @return returns a type to which the type binding can be assigned to.
* The returned type contains is unqualified when an import could be added or was already known.
* It is fully qualified, if an import conflict prevented the import.
* @since 3.4
*/
@Override
public String addImport(String type) {
return this.fJavaContextCore.addImport(type);
}
/**
* Adds a static import for the member with name <code>qualifiedMemberName</code>. The member is
* either a static field or a static method or a '*' to import all static members of a type.
*
* @param qualifiedMemberName the fully qualified name of the member to import or a qualified type
* name plus a '.*' suffix.
* @return returns either the simple member name if the import was successful or else the qualified name.
* @since 3.4
*/
public String addStaticImport(String qualifiedMemberName) {
return this.fJavaContextCore.addStaticImport(qualifiedMemberName);
}
@Override
public TemplateVariable getTemplateVariable(String name) {
return this.fJavaContextCore.getTemplateVariable(name);
}
/**
* Adds a multi-variable guess dependency.
*
* @param master the master variable - <code>slave</code> needs to be updated when
* <code>master</code> changes
* @param slave the dependent variable
* @since 3.3
*/
@Override
public void addDependency(MultiVariable master, MultiVariable slave) {
MultiVariableGuess guess= getMultiVariableGuess();
if (guess == null) {
guess= new MultiVariableGuess();
setMultiVariableGuess(guess);
}
guess.addDependency(master, slave);
}
}