1 11 package org.eclipse.search.internal.core.text; 12 13 import java.io.IOException ; 14 import java.nio.charset.IllegalCharsetNameException ; 15 import java.nio.charset.UnsupportedCharsetException ; 16 import java.util.HashMap ; 17 import java.util.Map ; 18 import java.util.regex.Matcher ; 19 import java.util.regex.Pattern ; 20 21 import org.eclipse.core.filebuffers.FileBuffers; 22 import org.eclipse.core.filebuffers.ITextFileBuffer; 23 import org.eclipse.core.filebuffers.ITextFileBufferManager; 24 import org.eclipse.core.filebuffers.LocationKind; 25 26 import org.eclipse.core.runtime.CoreException; 27 import org.eclipse.core.runtime.IProgressMonitor; 28 import org.eclipse.core.runtime.IStatus; 29 import org.eclipse.core.runtime.MultiStatus; 30 import org.eclipse.core.runtime.NullProgressMonitor; 31 import org.eclipse.core.runtime.OperationCanceledException; 32 import org.eclipse.core.runtime.Platform; 33 import org.eclipse.core.runtime.Status; 34 import org.eclipse.core.runtime.content.IContentDescription; 35 import org.eclipse.core.runtime.content.IContentType; 36 import org.eclipse.core.runtime.content.IContentTypeManager; 37 import org.eclipse.core.runtime.jobs.Job; 38 39 import org.eclipse.core.resources.IFile; 40 41 import org.eclipse.jface.text.IDocument; 42 43 import org.eclipse.ui.IEditorInput; 44 import org.eclipse.ui.IEditorPart; 45 import org.eclipse.ui.IEditorReference; 46 import org.eclipse.ui.IFileEditorInput; 47 import org.eclipse.ui.IWorkbench; 48 import org.eclipse.ui.IWorkbenchPage; 49 import org.eclipse.ui.IWorkbenchWindow; 50 import org.eclipse.ui.texteditor.ITextEditor; 51 52 import org.eclipse.search.ui.NewSearchUI; 53 54 import org.eclipse.search.core.text.TextSearchMatchAccess; 55 import org.eclipse.search.core.text.TextSearchRequestor; 56 import org.eclipse.search.core.text.TextSearchScope; 57 58 import org.eclipse.search.internal.ui.Messages; 59 import org.eclipse.search.internal.ui.SearchMessages; 60 import org.eclipse.search.internal.ui.SearchPlugin; 61 62 65 public class TextSearchVisitor { 66 67 public static class ReusableMatchAccess extends TextSearchMatchAccess { 68 69 private int fOffset; 70 private int fLength; 71 private IFile fFile; 72 private CharSequence fContent; 73 74 public void initialize(IFile file, int offset, int length, CharSequence content) { 75 fFile= file; 76 fOffset= offset; 77 fLength= length; 78 fContent= content; 79 } 80 81 public IFile getFile() { 82 return fFile; 83 } 84 85 public int getMatchOffset() { 86 return fOffset; 87 } 88 89 public int getMatchLength() { 90 return fLength; 91 } 92 93 public int getFileContentLength() { 94 return fContent.length(); 95 } 96 97 public char getFileContentChar(int offset) { 98 return fContent.charAt(offset); 99 } 100 101 public String getFileContent(int offset, int length) { 102 return fContent.subSequence(offset, offset + length).toString(); } 104 } 105 106 107 private final TextSearchRequestor fCollector; 108 private final Matcher fMatcher; 109 110 private Map fDocumentsInEditors; 111 112 private IProgressMonitor fProgressMonitor; 113 114 private int fNumberOfScannedFiles; 115 private int fNumberOfFilesToScan; 116 private IFile fCurrentFile; 117 118 private final MultiStatus fStatus; 119 120 private final FileCharSequenceProvider fFileCharSequenceProvider; 121 122 private final ReusableMatchAccess fMatchAccess; 123 124 public TextSearchVisitor(TextSearchRequestor collector, Pattern searchPattern) { 125 fCollector= collector; 126 fStatus= new MultiStatus(NewSearchUI.PLUGIN_ID, IStatus.OK, SearchMessages.TextSearchEngine_statusMessage, null); 127 128 fMatcher= searchPattern.pattern().length() == 0 ? null : searchPattern.matcher(new String ()); 129 130 fFileCharSequenceProvider= new FileCharSequenceProvider(); 131 fMatchAccess= new ReusableMatchAccess(); 132 } 133 134 public IStatus search(IFile[] files, IProgressMonitor monitor) { 135 fProgressMonitor= monitor == null ? new NullProgressMonitor() : monitor; 136 fNumberOfScannedFiles= 0; 137 fNumberOfFilesToScan= files.length; 138 fCurrentFile= null; 139 140 Job monitorUpdateJob= new Job(SearchMessages.TextSearchVisitor_progress_updating_job) { 141 private int fLastNumberOfScannedFiles= 0; 142 143 public IStatus run(IProgressMonitor inner) { 144 while (!inner.isCanceled()) { 145 IFile file= fCurrentFile; 146 if (file != null) { 147 String fileName= file.getName(); 148 Object [] args= { fileName, new Integer (fNumberOfScannedFiles), new Integer (fNumberOfFilesToScan)}; 149 fProgressMonitor.subTask(Messages.format(SearchMessages.TextSearchVisitor_scanning, args)); 150 int steps= fNumberOfScannedFiles - fLastNumberOfScannedFiles; 151 fProgressMonitor.worked(steps); 152 fLastNumberOfScannedFiles += steps; 153 } 154 try { 155 Thread.sleep(100); 156 } catch (InterruptedException e) { 157 return Status.OK_STATUS; 158 } 159 } 160 return Status.OK_STATUS; 161 } 162 }; 163 164 try { 165 String taskName= fMatcher == null ? SearchMessages.TextSearchVisitor_filesearch_task_label : Messages.format(SearchMessages.TextSearchVisitor_textsearch_task_label, fMatcher.pattern().pattern()); 166 fProgressMonitor.beginTask(taskName, fNumberOfFilesToScan); 167 monitorUpdateJob.setSystem(true); 168 monitorUpdateJob.schedule(); 169 try { 170 fCollector.beginReporting(); 171 processFiles(files); 172 return fStatus; 173 } finally { 174 monitorUpdateJob.cancel(); 175 } 176 } finally { 177 fProgressMonitor.done(); 178 fCollector.endReporting(); 179 } 180 } 181 182 public IStatus search(TextSearchScope scope, IProgressMonitor monitor) { 183 return search(scope.evaluateFilesInScope(fStatus), monitor); 184 } 185 186 private void processFiles(IFile[] files) { 187 fDocumentsInEditors= evalNonFileBufferDocuments(); 188 for (int i= 0; i < files.length; i++) { 189 fCurrentFile= files[i]; 190 boolean res= processFile(fCurrentFile); 191 if (!res) 192 break; 193 } 194 fDocumentsInEditors= null; 195 } 196 197 200 private Map evalNonFileBufferDocuments() { 201 Map result= new HashMap (); 202 IWorkbench workbench= SearchPlugin.getDefault().getWorkbench(); 203 IWorkbenchWindow[] windows= workbench.getWorkbenchWindows(); 204 for (int i= 0; i < windows.length; i++) { 205 IWorkbenchPage[] pages= windows[i].getPages(); 206 for (int x= 0; x < pages.length; x++) { 207 IEditorReference[] editorRefs= pages[x].getEditorReferences(); 208 for (int z= 0; z < editorRefs.length; z++) { 209 IEditorPart ep= editorRefs[z].getEditor(false); 210 if (ep instanceof ITextEditor && ep.isDirty()) { evaluateTextEditor(result, ep); 212 } 213 } 214 } 215 } 216 return result; 217 } 218 219 private void evaluateTextEditor(Map result, IEditorPart ep) { 220 IEditorInput input= ep.getEditorInput(); 221 if (input instanceof IFileEditorInput) { 222 IFile file= ((IFileEditorInput) input).getFile(); 223 if (!result.containsKey(file)) { ITextFileBufferManager bufferManager= FileBuffers.getTextFileBufferManager(); 225 ITextFileBuffer textFileBuffer= bufferManager.getTextFileBuffer(file.getFullPath(), LocationKind.IFILE); 226 if (textFileBuffer != null) { 227 result.put(file, textFileBuffer.getDocument()); 229 } else { 230 IDocument document= ((ITextEditor) ep).getDocumentProvider().getDocument(input); 232 if (document != null) { 233 result.put(file, document); 234 } 235 } 236 } 237 } 238 } 239 240 public boolean processFile(IFile file) { 241 try { 242 if (!fCollector.acceptFile(file) || fMatcher == null) { 243 return true; 244 } 245 246 IDocument document= getOpenDocument(file); 247 248 if (document != null) { 249 DocumentCharSequence documentCharSequence= new DocumentCharSequence(document); 250 locateMatches(file, documentCharSequence); 252 } else { 253 CharSequence seq= null; 254 try { 255 seq= fFileCharSequenceProvider.newCharSequence(file); 256 if (hasBinaryContent(seq, file) && !fCollector.reportBinaryFile(file)) { 257 return true; 258 } 259 locateMatches(file, seq); 260 } catch (FileCharSequenceProvider.FileCharSequenceException e) { 261 e.throwWrappedException(); 262 } finally { 263 if (seq != null) { 264 try { 265 fFileCharSequenceProvider.releaseCharSequence(seq); 266 } catch (IOException e) { 267 SearchPlugin.log(e); 268 } 269 } 270 } 271 } 272 } catch (UnsupportedCharsetException e) { 273 String [] args= { getCharSetName(file), file.getFullPath().makeRelative().toString()}; 274 String message= Messages.format(SearchMessages.TextSearchVisitor_unsupportedcharset, args); 275 fStatus.add(new Status(IStatus.WARNING, NewSearchUI.PLUGIN_ID, IStatus.WARNING, message, e)); 276 } catch (IllegalCharsetNameException e) { 277 String [] args= { getCharSetName(file), file.getFullPath().makeRelative().toString()}; 278 String message= Messages.format(SearchMessages.TextSearchVisitor_illegalcharset, args); 279 fStatus.add(new Status(IStatus.WARNING, NewSearchUI.PLUGIN_ID, IStatus.WARNING, message, e)); 280 } catch (IOException e) { 281 String [] args= { getExceptionMessage(e), file.getFullPath().makeRelative().toString()}; 282 String message= Messages.format(SearchMessages.TextSearchVisitor_error, args); 283 fStatus.add(new Status(IStatus.WARNING, NewSearchUI.PLUGIN_ID, IStatus.WARNING, message, e)); 284 } catch (CoreException e) { 285 String [] args= { getExceptionMessage(e), file.getFullPath().makeRelative().toString()}; 286 String message= Messages.format(SearchMessages.TextSearchVisitor_error, args); 287 fStatus.add(new Status(IStatus.WARNING, NewSearchUI.PLUGIN_ID, IStatus.WARNING, message, e)); 288 } catch (StackOverflowError e) { 289 String message= SearchMessages.TextSearchVisitor_patterntoocomplex0; 290 fStatus.add(new Status(IStatus.ERROR, NewSearchUI.PLUGIN_ID, IStatus.ERROR, message, e)); 291 return false; 292 } finally { 293 fNumberOfScannedFiles++; 294 } 295 if (fProgressMonitor.isCanceled()) 296 throw new OperationCanceledException(SearchMessages.TextSearchVisitor_canceled); 297 298 return true; 299 } 300 301 private boolean hasBinaryContent(CharSequence seq, IFile file) throws CoreException { 302 IContentDescription desc= file.getContentDescription(); 303 if (desc != null) { 304 IContentType contentType= desc.getContentType(); 305 if (contentType != null && contentType.isKindOf(Platform.getContentTypeManager().getContentType(IContentTypeManager.CT_TEXT))) { 306 return false; 307 } 308 } 309 310 try { 313 int limit= FileCharSequenceProvider.BUFFER_SIZE; 314 for (int i= 0; i < limit; i++) { 315 if (seq.charAt(i) == '\0') { 316 return true; 317 } 318 } 319 } catch (IndexOutOfBoundsException e) { 320 } 321 return false; 322 } 323 324 private void locateMatches(IFile file, CharSequence searchInput) throws CoreException { 325 try { 326 fMatcher.reset(searchInput); 327 int k= 0; 328 while (fMatcher.find()) { 329 int start= fMatcher.start(); 330 int end= fMatcher.end(); 331 if (end != start) { fMatchAccess.initialize(file, start, end - start, searchInput); 333 boolean res= fCollector.acceptPatternMatch(fMatchAccess); 334 if (!res) { 335 return; } 337 } 338 if (k++ == 20) { 339 if (fProgressMonitor.isCanceled()) { 340 throw new OperationCanceledException(SearchMessages.TextSearchVisitor_canceled); 341 } 342 k= 0; 343 } 344 } 345 } finally { 346 fMatchAccess.initialize(null, 0, 0, new String ()); } 348 } 349 350 351 private String getExceptionMessage(Exception e) { 352 String message= e.getLocalizedMessage(); 353 if (message == null) { 354 return e.getClass().getName(); 355 } 356 return message; 357 } 358 359 private IDocument getOpenDocument(IFile file) { 360 IDocument document= (IDocument) fDocumentsInEditors.get(file); 361 if (document == null) { 362 ITextFileBufferManager bufferManager= FileBuffers.getTextFileBufferManager(); 363 ITextFileBuffer textFileBuffer= bufferManager.getTextFileBuffer(file.getFullPath(), LocationKind.IFILE); 364 if (textFileBuffer != null) { 365 document= textFileBuffer.getDocument(); 366 } 367 } 368 return document; 369 } 370 371 private String getCharSetName(IFile file) { 372 try { 373 return file.getCharset(); 374 } catch (CoreException e) { 375 return "unknown"; } 377 } 378 379 } 380 381 | Popular Tags |