blob: c6fe60fd7124516d15881ae5654e3278fdff59c5 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2015 Ecliptical Software Inc. 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:
* Ecliptical Software Inc. - initial API and implementation
* IBM Canada - review initial contribution and commit
*******************************************************************************/
package org.eclipse.jdt.internal.debug.ui.search;
import java.util.Iterator;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.regex.Pattern;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.core.variables.VariablesPlugin;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.internal.ui.DebugUIPlugin;
import org.eclipse.debug.ui.DebugUITools;
import org.eclipse.debug.ui.ILaunchGroup;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IMember;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.search.IJavaSearchConstants;
import org.eclipse.jdt.core.search.IJavaSearchScope;
import org.eclipse.jdt.internal.debug.ui.JDIDebugUIPlugin;
import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants;
import org.eclipse.jdt.ui.search.ElementQuerySpecification;
import org.eclipse.jdt.ui.search.IMatchPresentation;
import org.eclipse.jdt.ui.search.IQueryParticipant;
import org.eclipse.jdt.ui.search.ISearchRequestor;
import org.eclipse.jdt.ui.search.PatternQuerySpecification;
import org.eclipse.jdt.ui.search.QuerySpecification;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.search.ui.text.Match;
import org.eclipse.ui.PartInitException;
/**
* This class provides a search participant to find class references in the
* {@linkplain IJavaLaunchConfigurationConstants#ATTR_MAIN_TYPE_NAME} attribute
* of Java launch configurations
*
* @since 3.4.0
*/
public class LaunchConfigurationQueryParticipant implements IQueryParticipant {
/**
* Singleton instance of the UI participant for the configuration
* search matches
*/
private UIParticipant uiParticipant;
/* (non-Javadoc)
* @see org.eclipse.jdt.ui.search.IQueryParticipant#estimateTicks(org.eclipse.jdt.ui.search.QuerySpecification)
*/
@Override
public int estimateTicks(QuerySpecification query) {
if (isValid(query)) {
return 50;
}
return 0;
}
/* (non-Javadoc)
* @see org.eclipse.jdt.ui.search.IQueryParticipant#getUIParticipant()
*/
@Override
public synchronized IMatchPresentation getUIParticipant() {
if (uiParticipant == null) {
uiParticipant = new UIParticipant();
}
return uiParticipant;
}
/* (non-Javadoc)
* @see org.eclipse.jdt.ui.search.IQueryParticipant#search(org.eclipse.jdt.ui.search.ISearchRequestor, org.eclipse.jdt.ui.search.QuerySpecification, org.eclipse.core.runtime.IProgressMonitor)
*/
@Override
public void search(ISearchRequestor requestor, QuerySpecification query, IProgressMonitor monitor) throws CoreException {
if (!isValid(query)) {
return;
}
if(monitor == null) {
monitor = new NullProgressMonitor();
}
monitor.beginTask("", 11); //$NON-NLS-1$
try {
Pattern pattern = null;
if (query instanceof ElementQuerySpecification) {
ElementQuerySpecification elementQuery = (ElementQuerySpecification) query;
IJavaElement element = elementQuery.getElement();
if(element instanceof IMember) {
IMember member = (IMember) element;
IType type = null;
if(member.getElementType() == IJavaElement.TYPE) {
type = (IType) member;
}
else if(member.getElementType() == IJavaElement.METHOD) {
if(((IMethod)member).isMainMethod()) {
type = member.getDeclaringType();
}
}
if(type != null) {
pattern = Pattern.compile(quotePattern(type.getFullyQualifiedName('$')));
}
else {
return;
}
}
else {
return;
}
}
if (query instanceof PatternQuerySpecification) {
PatternQuerySpecification patternQuery = (PatternQuerySpecification) query;
int flags = patternQuery.isCaseSensitive() ? 0
: Pattern.CASE_INSENSITIVE;
String quotedPattern = quotePattern(patternQuery.getPattern());
pattern = Pattern.compile(quotedPattern, flags);
}
if(monitor.isCanceled()) {
return;
}
monitor.worked(1);
searchLaunchConfigurations(query.getScope(), requestor, pattern, new SubProgressMonitor(monitor, 7));
} finally {
monitor.done();
}
}
/**
* Creates an adjusted pattern from the specified quote pattern
* @param pattern the search pattern to manipulate
* @return the original pattern adjusted to escape special chars in Java,and change Eclipse
* search chars to Java RegEx chars
*/
private String quotePattern(String pattern) {
StringTokenizer t = new StringTokenizer(pattern, ".?*$()", true); //$NON-NLS-1$
StringBuilder buf = new StringBuilder();
String token = null;
while (t.hasMoreTokens()) {
token = t.nextToken();
switch (token.charAt(0)) {
case '.': {
buf.append('\\');
break;
}
case '?':
case '*': {
buf.append('.');
break;
}
case '$': {
buf.append('\\');
break;
}
case '(': {
buf.append('\\');
break;
}
case ')': {
buf.append('\\');
break;
}
}
buf.append(token);
}
return buf.toString();
}
/**
* Determines if the current query should be considered or not
* @param query the current query
* @return true if the query should be considered, false otherwise
*/
private boolean isValid(QuerySpecification query) {
switch(query.getLimitTo()) {
case IJavaSearchConstants.REFERENCES:
case IJavaSearchConstants.ALL_OCCURRENCES: {
break;
}
default: {
return false;
}
}
if (query instanceof ElementQuerySpecification) {
IJavaElement element = ((ElementQuerySpecification) query).getElement();
return element.getElementType() == IJavaElement.TYPE || element.getElementType() == IJavaElement.METHOD;
}
if (query instanceof PatternQuerySpecification) {
PatternQuerySpecification patternQuery = (PatternQuerySpecification) query;
switch (patternQuery.getSearchFor()) {
case IJavaSearchConstants.UNKNOWN:
case IJavaSearchConstants.TYPE:
case IJavaSearchConstants.CLASS:
case IJavaSearchConstants.CLASS_AND_INTERFACE:
case IJavaSearchConstants.CLASS_AND_ENUM: {
return true;
}
}
}
return false;
}
/**
* Returns the success of the the pattern matching
* @param scope the search scope
* @param config the backing {@link ILaunchConfiguration}
* @param pattern the search pattern
* @return true if there were matching elements for the pattern, false otherwise
* @throws CoreException if an exception occurs
*/
private boolean matches(IJavaSearchScope scope, ILaunchConfiguration config, Pattern pattern) throws CoreException {
if(!config.exists() || !config.getType().isPublic() || !DebugUIPlugin.doLaunchConfigurationFiltering(config)) {
return false;
}
String mainTypeName = config.getAttribute(IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME, (String) null);
if (mainTypeName == null) {
return false;
}
try {
mainTypeName = VariablesPlugin.getDefault().getStringVariableManager().performStringSubstitution(mainTypeName);
}
catch(CoreException ce) {
return false;
}
if (! pattern.matcher(mainTypeName).matches()) {
return false;
}
IResource[] resources = config.getMappedResources();
if (resources != null) {
for (IResource resource : resources) {
if (scope.encloses(resource.getFullPath().toString())) {
return true;
}
}
}
return false;
}
/**
* Searches for configurations matching the specified pattern
* @param scope the search scope
* @param requestor the requester
* @param pattern the search pattern
* @param monitor for progress monitoring
* @throws CoreException if an exception occurs
*/
private void searchLaunchConfigurations(IJavaSearchScope scope, ISearchRequestor requestor, Pattern pattern, IProgressMonitor monitor) throws CoreException {
ILaunchConfiguration[] configs = DebugPlugin.getDefault().getLaunchManager().getLaunchConfigurations();
monitor.beginTask("Searching for launch configurations", configs.length); //$NON-NLS-1$
try {
for (ILaunchConfiguration config : configs) {
if (monitor.isCanceled()) {
return;
}
monitor.worked(1);
if (matches(scope, config, pattern)) {
requestor.reportMatch(new Match(config, 0, 0));
}
}
} finally {
monitor.done();
}
}
/**
* The UI participant for showing configuration matches in the search view
*
* @since 3.4.0
*/
private static class UIParticipant implements IMatchPresentation {
/* (non-Javadoc)
* @see org.eclipse.jdt.ui.search.IMatchPresentation#createLabelProvider()
*/
@Override
public ILabelProvider createLabelProvider() {
return DebugUITools.newDebugModelPresentation();
}
/* (non-Javadoc)
* @see org.eclipse.jdt.ui.search.IMatchPresentation#showMatch(org.eclipse.search.ui.text.Match, int, int, boolean)
*/
@Override
public void showMatch(Match match, int currentOffset, int currentLength, boolean activate) throws PartInitException {
Object o = match.getElement();
if (o instanceof ILaunchConfiguration) {
if (activate) {
try {
ILaunchConfiguration config = (ILaunchConfiguration) o;
Set<Set<String>> modes = config.getType().getSupportedModeCombinations();
ILaunchGroup group = null;
Set<String> mode = null;
for (Iterator<Set<String>> iter = modes.iterator(); iter.hasNext();) {
mode = iter.next();
if(mode.size() == 1) {
group = DebugUITools.getLaunchGroup(config, mode.iterator().next());
if (group != null) {
break;
}
}
}
if (group == null || !config.exists()) {
return;
}
DebugUITools.openLaunchConfigurationDialog(JDIDebugUIPlugin.getActiveWorkbenchShell(), config, group.getIdentifier(), Status.OK_STATUS);
}
catch(CoreException ce) {
JDIDebugUIPlugin.log(ce);
}
}
}
}
}
}