Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Search while you type... #78 #81

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion org.eclipse.search/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %pluginName
Bundle-SymbolicName: org.eclipse.search; singleton:=true
Bundle-Version: 3.14.300.qualifier
Bundle-Version: 3.15.0.qualifier
Bundle-Activator: org.eclipse.search.internal.ui.SearchPlugin
Bundle-ActivationPolicy: lazy
Bundle-Vendor: %providerName
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*******************************************************************************
* Copyright (c) 2022 Joerg Kubitz 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:
* Joerg Kubitz - initial API and implementation
*******************************************************************************/
package org.eclipse.search.ui;

import org.eclipse.core.runtime.IProgressMonitor;

/**
* Represents a particular search query that can be rerun in background with an
* updated search text
* <p>
* Clients may implement this interface.
* </p>
*
* @since 3.15
*/
public interface IResearchQuery extends ISearchQuery {
/**
* @return the text the user was searching for
*/
String getSearchString();

/**
* Sets the search text for the next run
*
* @param s
* the text the user is searching for
* @see org.eclipse.search.ui.ISearchQuery#run(IProgressMonitor)
*/
void setSearchString(String s);

@Override
public default boolean canRerun() {
return true;
}

@Override
public default boolean canRunInBackground() {
return true;
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2000, 2008 IBM Corporation and others.
* Copyright (c) 2000, 2022 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
Expand All @@ -13,6 +13,8 @@
*******************************************************************************/
package org.eclipse.search.ui;

import java.util.Objects;

import org.eclipse.core.runtime.IStatus;

import org.eclipse.jface.dialogs.ErrorDialog;
Expand Down Expand Up @@ -243,9 +245,12 @@ public static boolean isQueryRunning(ISearchQuery query) {
/**
* Sends a 'cancel' command to the given query running in background.
* The call has no effect if the query is not running, not in background or is not cancelable.
*
* The query may still running.
*
* @param query
* the query
* @see #waitFinished
* @since 3.1
*/
public static void cancelQuery(ISearchQuery query) {
Expand All @@ -255,6 +260,19 @@ public static void cancelQuery(ISearchQuery query) {
InternalSearchUI.getInstance().cancelSearch(query);
}

/**
* waits till the query is finished
*
* @param query
* the query
* @see #cancelQuery
* @since 3.15
*/
public static void waitFinished(ISearchQuery query) {
Objects.requireNonNull(query, "query must not be null"); //$NON-NLS-1$
InternalSearchUI.getInstance().waitFinished(query);
}

/**
* Removes the given search query.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2000, 2015 IBM Corporation and others.
* Copyright (c) 2000, 2022 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
Expand All @@ -15,8 +15,9 @@
package org.eclipse.search2.internal.ui;

import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
Expand All @@ -39,6 +40,7 @@
import org.eclipse.search.ui.ISearchQuery;
import org.eclipse.search.ui.ISearchResult;
import org.eclipse.search.ui.ISearchResultViewPart;
import org.eclipse.search.ui.NewSearchUI;

import org.eclipse.search2.internal.ui.text.PositionTracker;

Expand All @@ -48,31 +50,28 @@ public class InternalSearchUI {
private static InternalSearchUI fgInstance;

// contains all running jobs
private HashMap<ISearchQuery, SearchJobRecord> fSearchJobs;
private final Map<ISearchQuery, SearchJobRecord> fSearchJobs;

private QueryManager fSearchResultsManager;
private PositionTracker fPositionTracker;
private final QueryManager fSearchResultsManager;
private final PositionTracker fPositionTracker;

private SearchViewManager fSearchViewManager;
private final SearchViewManager fSearchViewManager;

public static final Object FAMILY_SEARCH = new Object();

private static class SearchJobRecord {
public ISearchQuery query;
public Job job;
public boolean isRunning;
public final ISearchQuery query;
public volatile Job job;

public SearchJobRecord(ISearchQuery job) {
this.query= job;
this.isRunning= false;
this.job= null;
}
}


private class InternalSearchJob extends Job {

private SearchJobRecord fSearchJobRecord;
private final SearchJobRecord fSearchJobRecord;

public InternalSearchJob(SearchJobRecord sjr) {
super(sjr.query.getLabel());
Expand Down Expand Up @@ -102,6 +101,7 @@ protected IStatus run(IProgressMonitor monitor) {
fSearchJobRecord.job= null;
return status;
}

@Override
public boolean belongsTo(Object family) {
return family == InternalSearchUI.FAMILY_SEARCH;
Expand All @@ -110,12 +110,10 @@ public boolean belongsTo(Object family) {
}

private void searchJobStarted(SearchJobRecord record) {
record.isRunning= true;
getSearchManager().queryStarting(record.query);
}

private void searchJobFinished(SearchJobRecord record) {
record.isRunning= false;
fSearchJobs.remove(record.query);
getSearchManager().queryFinished(record.query);
}
Expand All @@ -125,7 +123,7 @@ private void searchJobFinished(SearchJobRecord record) {
*/
public InternalSearchUI() {
fgInstance= this;
fSearchJobs= new HashMap<>();
fSearchJobs= new ConcurrentHashMap<>();
fSearchResultsManager= new QueryManager();
fPositionTracker= new PositionTracker();

Expand All @@ -137,7 +135,7 @@ public InternalSearchUI() {
/**
* @return returns the shared instance.
*/
public static InternalSearchUI getInstance() {
public static synchronized InternalSearchUI getInstance() {
if (fgInstance ==null)
fgInstance= new InternalSearchUI();
return fgInstance;
Expand All @@ -158,8 +156,13 @@ private IWorkbenchSiteProgressService getProgressService() {
}

public boolean runSearchInBackground(ISearchQuery query, ISearchResultViewPart view) {
if (isQueryRunning(query))
SearchJobRecord sjr = new SearchJobRecord(query);
// do not rerun same query in parallel (avoid MT issues):
NewSearchUI.waitFinished(query); // blocks UI :-(
SearchJobRecord queryRunning = fSearchJobs.putIfAbsent(query, sjr);
if (queryRunning != null) {
return false;
}

// prepare view
if (view == null) {
Expand All @@ -170,8 +173,6 @@ public boolean runSearchInBackground(ISearchQuery query, ISearchResultViewPart v

addQuery(query);

SearchJobRecord sjr= new SearchJobRecord(query);
fSearchJobs.put(query, sjr);

Job job= new InternalSearchJob(sjr);
job.setPriority(Job.BUILD);
Expand All @@ -188,12 +189,13 @@ public boolean runSearchInBackground(ISearchQuery query, ISearchResultViewPart v
}

public boolean isQueryRunning(ISearchQuery query) {
SearchJobRecord sjr= fSearchJobs.get(query);
return sjr != null && sjr.isRunning;
return fSearchJobs.containsKey(query);
}

public IStatus runSearchInForeground(IRunnableContext context, final ISearchQuery query, ISearchResultViewPart view) {
if (isQueryRunning(query)) {
SearchJobRecord sjr = new SearchJobRecord(query);
SearchJobRecord queryRunning = fSearchJobs.putIfAbsent(query, sjr);
if (queryRunning != null) {
return Status.CANCEL_STATUS;
}

Expand All @@ -206,9 +208,6 @@ public IStatus runSearchInForeground(IRunnableContext context, final ISearchQuer

addQuery(query);

SearchJobRecord sjr= new SearchJobRecord(query);
fSearchJobs.put(query, sjr);

if (context == null)
context= new ProgressMonitorDialog(null);

Expand Down Expand Up @@ -264,13 +263,30 @@ private void doShutdown() {

}

public void cancelSearch(ISearchQuery job) {
SearchJobRecord rec= fSearchJobs.get(job);
if (rec != null && rec.job != null)
rec.job.cancel();
public void cancelSearch(ISearchQuery query) {
SearchJobRecord rec = fSearchJobs.get(query);
Job job = rec == null ? null : rec.job;
if (job != null) {
job.cancel();
// note that the job may still be running for some time
// which can cause multithreading issues.
}
}


public boolean waitFinished(ISearchQuery query) {
SearchJobRecord rec = fSearchJobs.get(query);
Job job = rec == null ? null : rec.job;
if (job != null) {
try {
job.cancel();
job.join();
return true;
} catch (InterruptedException e) {
// ignore
}
}
return false;
}

public QueryManager getSearchManager() {
return fSearchResultsManager;
Expand Down Expand Up @@ -348,5 +364,4 @@ private void showSearchResult(SearchView searchView, ISearchResult result) {
searchView.showSearchResult(result);
}


}
Loading