blob: dae339958cec0ded090562b717b9ee3153ee91ca [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2007 IBM Corporation 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:
* IBM Corporation - initial API and implementation
* Juerg Billeter, juergbi@ethz.ch - 47136 Search view should show match objects
* Ulrich Etter, etteru@ethz.ch - 47136 Search view should show match objects
* Roman Fuchs, fuchsro@ethz.ch - 47136 Search view should show match objects
*******************************************************************************/
package org.eclipse.search.internal.ui.text;
import java.util.ArrayList;
import java.util.regex.Pattern;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.search.ui.ISearchQuery;
import org.eclipse.search.ui.ISearchResult;
import org.eclipse.search.ui.text.AbstractTextSearchResult;
import org.eclipse.search.ui.text.FileTextSearchScope;
import org.eclipse.search.ui.text.Match;
import org.eclipse.search.core.text.TextSearchEngine;
import org.eclipse.search.core.text.TextSearchMatchAccess;
import org.eclipse.search.core.text.TextSearchRequestor;
import org.eclipse.search.internal.core.text.PatternConstructor;
import org.eclipse.search.internal.ui.Messages;
import org.eclipse.search.internal.ui.SearchMessages;
public class FileSearchQuery implements ISearchQuery {
private final static class TextSearchResultCollector extends TextSearchRequestor {
private final AbstractTextSearchResult fResult;
private final boolean fIsFileSearchOnly;
private final boolean fSearchInBinaries;
private ArrayList fCachedMatches;
private static final int MAX_LINE_CONTEXT= 80;
private static final int MAX_LINE_LENGTH= 250;
private TextSearchResultCollector(AbstractTextSearchResult result, boolean isFileSearchOnly, boolean searchInBinaries) {
fResult= result;
fIsFileSearchOnly= isFileSearchOnly;
fSearchInBinaries= searchInBinaries;
}
public boolean acceptFile(IFile file) throws CoreException {
if (fIsFileSearchOnly) {
fResult.addMatch(new FileMatch(file, 0, 0, null, -1, 0));
}
flushMatches();
return true;
}
/* (non-Javadoc)
* @see org.eclipse.search.core.text.TextSearchRequestor#reportBinaryFile(org.eclipse.core.resources.IFile)
*/
public boolean reportBinaryFile(IFile file) {
return fSearchInBinaries;
}
public boolean acceptPatternMatch(TextSearchMatchAccess matchRequestor) throws CoreException {
int matchOffset= matchRequestor.getMatchOffset();
int matchEnd= matchRequestor.getMatchOffset() + matchRequestor.getMatchLength();
int lineStart= matchOffset;
int min= Math.max(0, lineStart - MAX_LINE_CONTEXT);
for (int i= lineStart; i >= min; i--) {
char ch= matchRequestor.getFileContentChar(i);
if (isLineDelimiter(ch))
break;
if (!Character.isWhitespace(ch))
lineStart= i;
}
StringBuffer buf= new StringBuffer();
if (lineStart == min && lineStart != 0) {
buf.append("..."); //$NON-NLS-1$
}
int lineEnd= matchEnd;
int max= Math.min(matchRequestor.getFileContentLength(), lineEnd + MAX_LINE_CONTEXT);
for (int i= lineEnd; i < max; i++) {
char ch= matchRequestor.getFileContentChar(i);
if (isLineDelimiter(ch))
break;
if (!Character.isWhitespace(ch))
lineEnd= i + 1;
}
appendString(matchRequestor, lineStart, matchOffset, buf);
int offsetWithinLine= buf.length();
int lineLength= lineEnd - lineStart;
if (lineLength > MAX_LINE_LENGTH) {
int numCharsToCut= lineLength - MAX_LINE_LENGTH;
int half= (matchRequestor.getMatchLength() - numCharsToCut) / 2;
appendString(matchRequestor, matchOffset, matchOffset + half, buf);
buf.append("..."); //$NON-NLS-1$
appendString(matchRequestor, matchEnd - half, matchEnd, buf);
} else {
appendString(matchRequestor, matchOffset, matchEnd, buf);
}
int lengthWithinLine= buf.length()- offsetWithinLine;
appendString(matchRequestor, matchEnd, lineEnd, buf);
fCachedMatches.add(new FileMatch(matchRequestor.getFile(), matchOffset, matchEnd - matchOffset, buf.toString(), offsetWithinLine, lengthWithinLine));
return true;
}
private static void appendString(TextSearchMatchAccess matchRequestor, int start, int end, StringBuffer buf) {
for (int i= start; i < end; i++) {
char ch= matchRequestor.getFileContentChar(i);
if (Character.isWhitespace(ch) || Character.isISOControl(ch)) {
buf.append(' ');
} else {
buf.append(ch);
}
}
}
private static boolean isLineDelimiter(char ch) {
return ch == '\n' || ch == '\r';
}
public void beginReporting() {
fCachedMatches= new ArrayList();
}
public void endReporting() {
flushMatches();
fCachedMatches= null;
}
private void flushMatches() {
if (!fCachedMatches.isEmpty()) {
fResult.addMatches((Match[]) fCachedMatches.toArray(new Match[fCachedMatches.size()]));
fCachedMatches.clear();
}
}
}
private final FileTextSearchScope fScope;
private final String fSearchText;
private final boolean fIsRegEx;
private final boolean fIsCaseSensitive;
private FileSearchResult fResult;
public FileSearchQuery(String searchText, boolean isRegEx, boolean isCaseSensitive, FileTextSearchScope scope) {
fSearchText= searchText;
fIsRegEx= isRegEx;
fIsCaseSensitive= isCaseSensitive;
fScope= scope;
}
public FileTextSearchScope getSearchScope() {
return fScope;
}
public boolean canRunInBackground() {
return true;
}
public IStatus run(final IProgressMonitor monitor) {
AbstractTextSearchResult textResult= (AbstractTextSearchResult) getSearchResult();
textResult.removeAll();
Pattern searchPattern= getSearchPattern();
boolean isFileSearchOnly= searchPattern.pattern().length() == 0;
boolean searchInBinaries= !isScopeAllFileTypes();
TextSearchResultCollector collector= new TextSearchResultCollector(textResult, isFileSearchOnly, searchInBinaries);
return TextSearchEngine.create().search(fScope, collector, searchPattern, monitor);
}
private boolean isScopeAllFileTypes() {
String[] fileNamePatterns= fScope.getFileNamePatterns();
if (fileNamePatterns == null)
return true;
for (int i= 0; i < fileNamePatterns.length; i++) {
if ("*".equals(fileNamePatterns[i])) { //$NON-NLS-1$
return true;
}
}
return false;
}
public String getLabel() {
return SearchMessages.FileSearchQuery_label;
}
public String getSearchString() {
return fSearchText;
}
public String getResultLabel(int nMatches) {
String searchString= getSearchString();
if (searchString.length() > 0) {
// text search
if (isScopeAllFileTypes()) {
// search all file extensions
if (nMatches == 1) {
Object[] args= { searchString, fScope.getDescription() };
return Messages.format(SearchMessages.FileSearchQuery_singularLabel, args);
}
Object[] args= { searchString, new Integer(nMatches), fScope.getDescription() };
return Messages.format(SearchMessages.FileSearchQuery_pluralPattern, args);
}
// search selected file extensions
if (nMatches == 1) {
Object[] args= { searchString, fScope.getDescription(), fScope.getFilterDescription() };
return Messages.format(SearchMessages.FileSearchQuery_singularPatternWithFileExt, args);
}
Object[] args= { searchString, new Integer(nMatches), fScope.getDescription(), fScope.getFilterDescription() };
return Messages.format(SearchMessages.FileSearchQuery_pluralPatternWithFileExt, args);
}
// file search
if (nMatches == 1) {
Object[] args= { fScope.getFilterDescription(), fScope.getDescription() };
return Messages.format(SearchMessages.FileSearchQuery_singularLabel_fileNameSearch, args);
}
Object[] args= { fScope.getFilterDescription(), new Integer(nMatches), fScope.getDescription() };
return Messages.format(SearchMessages.FileSearchQuery_pluralPattern_fileNameSearch, args);
}
/**
* @param result all result are added to this search result
* @param monitor the progress monitor to use
* @param file the file to search in
* @return returns the status of the operation
*/
public IStatus searchInFile(final AbstractTextSearchResult result, final IProgressMonitor monitor, IFile file) {
FileTextSearchScope scope= FileTextSearchScope.newSearchScope(new IResource[] { file }, new String[] { "*" }, true); //$NON-NLS-1$
Pattern searchPattern= getSearchPattern();
boolean isFileSearchOnly= searchPattern.pattern().length() == 0;
TextSearchResultCollector collector= new TextSearchResultCollector(result, isFileSearchOnly, true);
return TextSearchEngine.create().search(scope, collector, searchPattern, monitor);
}
protected Pattern getSearchPattern() {
return PatternConstructor.createPattern(fSearchText, fIsCaseSensitive, fIsRegEx);
}
public boolean isRegexSearch() {
return fIsRegEx;
}
public boolean isCaseSensitive() {
return fIsCaseSensitive;
}
public boolean canRerun() {
return true;
}
public ISearchResult getSearchResult() {
if (fResult == null) {
fResult= new FileSearchResult(this);
new SearchResultUpdater(fResult);
}
return fResult;
}
}