diff --git a/src/Main/Base/Project/Src/Project/Items/ItemType.cs b/src/Main/Base/Project/Src/Project/Items/ItemType.cs index d55a31f781..1a7f658d52 100644 --- a/src/Main/Base/Project/Src/Project/Items/ItemType.cs +++ b/src/Main/Base/Project/Src/Project/Items/ItemType.cs @@ -56,6 +56,11 @@ namespace ICSharpCode.SharpDevelop.Project public static readonly ItemType Folder = new ItemType("Folder"); public static readonly ItemType WebReferences = new ItemType("WebReferences"); + /// + /// Gets a collection of item types that are known not to be used for files. + /// + public static readonly ReadOnlyCollectionWrapper NonFileItemTypes + = new ReadOnlyCollectionWrapper(new List(ReferenceItemTypes) { Folder, WebReferences, Import }); readonly string itemName; diff --git a/src/Main/Base/Project/Src/Services/File/FileService.cs b/src/Main/Base/Project/Src/Services/File/FileService.cs index b427276267..8a55dc6ddd 100644 --- a/src/Main/Base/Project/Src/Services/File/FileService.cs +++ b/src/Main/Base/Project/Src/Services/File/FileService.cs @@ -81,6 +81,8 @@ namespace ICSharpCode.SharpDevelop if (fileName == null) throw new ArgumentNullException("fileName"); + WorkbenchSingleton.AssertMainThread(); + fileName = FileUtility.NormalizePath(fileName); OpenedFile file; openedFileDict.TryGetValue(fileName, out file); diff --git a/src/Main/Base/Project/Src/Services/ParserService/ParseProjectContent.cs b/src/Main/Base/Project/Src/Services/ParserService/ParseProjectContent.cs index 615ee237ed..952d398417 100644 --- a/src/Main/Base/Project/Src/Services/ParserService/ParseProjectContent.cs +++ b/src/Main/Base/Project/Src/Services/ParserService/ParseProjectContent.cs @@ -8,6 +8,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using ICSharpCode.Core; using ICSharpCode.SharpDevelop.Dom; @@ -246,7 +247,6 @@ namespace ICSharpCode.SharpDevelop { if (!initializing) return; //int progressStart = progressMonitor.WorkDone; - ParseableFileContentEnumerator enumerator = new ParseableFileContentEnumerator(project); try { IProjectContent[] referencedContents; lock (this.ReferencedContents) { @@ -260,21 +260,21 @@ namespace ICSharpCode.SharpDevelop } } - while (enumerator.MoveNext()) { - int i = enumerator.Index; - if ((i % 4) == 2) { - //progressMonitor.WorkDone = progressStart + i; - token.ThrowIfCancellationRequested(); + ParseableFileContentFinder finder = new ParseableFileContentFinder(); + var fileContents = + from p in project.Items.AsParallel().WithCancellation(token) + where !ItemType.NonFileItemTypes.Contains(p.ItemType) + select finder.Create(p); + fileContents.ForAll( + entry => { + ITextBuffer content = entry.GetContent(); + if (content != null) + ParserService.ParseFile(this, entry.FileName, content); } - - ParserService.ParseFile(this, enumerator.CurrentFileName, new StringTextBuffer(enumerator.CurrentFileContent)); - - if (!initializing) return; - } + ); } finally { initializing = false; //progressMonitor.WorkDone = progressStart + enumerator.ItemCount; - enumerator.Dispose(); } } diff --git a/src/Main/Base/Project/Src/Services/ParserService/ParserService.cs b/src/Main/Base/Project/Src/Services/ParserService/ParserService.cs index 8694142246..0ebfd830c4 100644 --- a/src/Main/Base/Project/Src/Services/ParserService/ParserService.cs +++ b/src/Main/Base/Project/Src/Services/ParserService/ParserService.cs @@ -275,11 +275,6 @@ namespace ICSharpCode.SharpDevelop static ITextBuffer GetParseableFileContentInternal(string fileName) { - IViewContent viewContent = FileService.GetOpenFile(fileName); - IEditable editable = viewContent as IEditable; - if (editable != null) { - return editable.CreateSnapshot(); - } //ITextBuffer res = project.GetParseableFileContent(fileName); //if (res != null) // return res; diff --git a/src/Main/Base/Project/Src/Services/ProjectService/ParseableFileContentEnumerator.cs b/src/Main/Base/Project/Src/Services/ProjectService/ParseableFileContentEnumerator.cs index 4ce8347dde..ebefb6ac92 100644 --- a/src/Main/Base/Project/Src/Services/ProjectService/ParseableFileContentEnumerator.cs +++ b/src/Main/Base/Project/Src/Services/ProjectService/ParseableFileContentEnumerator.cs @@ -5,201 +5,65 @@ // $Revision$ // -using ICSharpCode.SharpDevelop.Editor; using System; using System.Collections; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Text; + using ICSharpCode.Core; using ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor; using ICSharpCode.SharpDevelop.Dom.Refactoring; +using ICSharpCode.SharpDevelop.Editor; using ICSharpCode.SharpDevelop.Gui; namespace ICSharpCode.SharpDevelop.Project { - /// - /// An enumerator which enumerates through a list of project items, returning the - /// parseable file content of each item. - /// - /// - /// This class is thread-safe in a very limited way: - /// It can be created from every thread, but may be only used by the thread that created it. - /// It automatically uses WorkbenchSingleton.SafeThreadCall for reading currently open - /// files when it is created/accessed from a thread. - /// - public class ParseableFileContentEnumerator : IEnumerator> + public class ParseableFileContentEntry { - void IEnumerator.Reset() { - throw new NotSupportedException(); - } + public string FileName { get; private set; } + ITextBuffer openContent; - KeyValuePair current; - - object IEnumerator.Current { - get { - return current; - } - } - - public KeyValuePair Current { - get { - return current; - } - } - - public string CurrentFileName { - get { - return current.Key; - } - } - - public string CurrentFileContent { - get { - return current.Value; - } - } - - public void Dispose() - { - } - - IList projectItems; - bool isOnMainThread; - Encoding defaultEncoding; - - public ParseableFileContentEnumerator(IProject project) : this(project.Items) { } - - public ParseableFileContentEnumerator(IList projectItems) + public ITextBuffer GetContent() { - isOnMainThread = !WorkbenchSingleton.InvokeRequired; - this.projectItems = projectItems; - if (projectItems.Count > 0) { - nextItem = projectItems[0]; - } - defaultEncoding = ParserService.DefaultFileEncoding; - } - - string GetParseableFileContent(IProject project, string fileName) - { - // Loading the source files is done asynchronously: - // While one file is parsed, the next is already loaded from disk. - - // Load file from memory if it is open - OpenedFile file = FileService.GetOpenedFile(fileName); - if (file != null) { - string content; - if (isOnMainThread) { - content = GetFileContentFromFileDocumentProvider(file); - } else { - content = WorkbenchSingleton.SafeThreadFunction(GetFileContentFromFileDocumentProvider, file); - } - if (content != null) { - return content; - } - - using(Stream s = file.OpenRead()) { - Encoding encoding = defaultEncoding; - return ICSharpCode.TextEditor.Util.FileReader.ReadFileContent(s, ref encoding); - } - } - - // load file - return ICSharpCode.TextEditor.Util.FileReader.ReadFileContent(fileName, defaultEncoding); - } - - ProjectItem nextItem; - int index = 0; - - public int ItemCount { - get { - return projectItems.Count; - } - } - - public int Index { - get { - return index; - } - } - - public bool MoveNext() - { - ProjectItem item = nextItem; - nextItem = (++index < projectItems.Count) ? projectItems[index] : null; - if (item == null) return false; - - if (ParserService.CreateParser(item.FileName) == null) - return MoveNext(); - - string fileContent; + if (openContent != null) + return openContent; try { - fileContent = GetFileContent(item); - } catch (FileNotFoundException ex) { - LoggingService.Warn("ParseableFileContentEnumerator: " + ex.Message); - return MoveNext(); // skip files that were not found - } catch (IOException ex) { - LoggingService.Warn("ParseableFileContentEnumerator: " + ex.Message); - return MoveNext(); // skip invalid files - } - current = new KeyValuePair(item.FileName, fileContent); - return true; - } - - string GetFileContent(ProjectItem item) - { - string fileName = item.FileName; - if (IsFileOpen(fileName)) { - string content; - if (isOnMainThread) - content = GetFileContentFromOpenFile(fileName); - else - content = WorkbenchSingleton.SafeThreadFunction(GetFileContentFromOpenFile, fileName); - if (content != null) - return content; + return new StringTextBuffer(ICSharpCode.AvalonEdit.Utils.FileReader.ReadFileContent(FileName, ParserService.DefaultFileEncoding)); + } catch (IOException) { + return null; + } catch (UnauthorizedAccessException) { + return null; } - return GetParseableFileContent(item.Project, fileName); } - IList viewContentFileNamesCollection; - - bool IsFileOpen(string fileName) + internal ParseableFileContentEntry(ProjectItem item, IList viewContentFileNamesCollection) { - if (viewContentFileNamesCollection == null) { - try { - viewContentFileNamesCollection = WorkbenchSingleton.SafeThreadFunction>(FileService.GetOpenFiles); - } catch (InvalidOperationException ex) { - // can happen if the user closes SharpDevelop while the parser thread is running - LoggingService.Warn(ex); - viewContentFileNamesCollection = new string[0]; + this.FileName = item.FileName; + foreach (string name in viewContentFileNamesCollection) { + if (FileUtility.IsEqualFileName(name, this.FileName)) { + openContent = WorkbenchSingleton.SafeThreadFunction(ParserService.GetParseableFileContent, this.FileName); + break; } } - foreach (string contentName in viewContentFileNamesCollection) { - if (contentName != null) { - if (FileUtility.IsEqualFileName(fileName, contentName)) - return true; - } - } - return false; - } - - string GetFileContentFromOpenFile(string fileName) - { - IViewContent viewContent = FileService.GetOpenFile(fileName); - IEditable editable = viewContent as IEditable; - if (editable != null) { - return editable.Text; - } - return null; } + } + + /// + /// Can be used to create ParseableFileContentEntry for ProjectItems. + /// This class is thread-safe. + /// + public class ParseableFileContentFinder + { + IList viewContentFileNamesCollection = WorkbenchSingleton.SafeThreadFunction(FileService.GetOpenFiles); - static string GetFileContentFromFileDocumentProvider(OpenedFile file) + /// + /// Retrieves the file contents for the specified project items. + /// + public ParseableFileContentEntry Create(ProjectItem p) { - IFileDocumentProvider p = file.CurrentView as IFileDocumentProvider; - if (p == null) return null; - IDocument document = p.GetDocumentForFile(file); - if (document == null) return null; - return document.Text; + return new ParseableFileContentEntry(p, viewContentFileNamesCollection); } } } diff --git a/src/Main/Base/Project/Src/Services/RefactoringService/RefactoringService.cs b/src/Main/Base/Project/Src/Services/RefactoringService/RefactoringService.cs index 01ea976992..b1391a5d29 100644 --- a/src/Main/Base/Project/Src/Services/RefactoringService/RefactoringService.cs +++ b/src/Main/Base/Project/Src/Services/RefactoringService/RefactoringService.cs @@ -152,7 +152,7 @@ namespace ICSharpCode.SharpDevelop.Refactoring ownerClass = ownerClass.GetCompoundClass(); files = GetPossibleFiles(ownerClass, member); } - ParseableFileContentEnumerator enumerator = new ParseableFileContentEnumerator(files.ToArray()); + ParseableFileContentFinder finder = new ParseableFileContentFinder(); List references = new List(); try { if (progressMonitor != null) { @@ -163,21 +163,27 @@ namespace ICSharpCode.SharpDevelop.Refactoring System.Diagnostics.Debugger.Break(); } #endif - while (enumerator.MoveNext()) { + int index = 0; + foreach (ProjectItem item in files) { + var entry = finder.Create(item); + if (progressMonitor != null) { - progressMonitor.WorkDone = enumerator.Index; + progressMonitor.WorkDone = index; if (progressMonitor.IsCancelled) { return null; } } - AddReferences(references, ownerClass, member, isLocal, enumerator.CurrentFileName, enumerator.CurrentFileContent); + ITextBuffer content = entry.GetContent(); + if (content != null) { + AddReferences(references, ownerClass, member, isLocal, entry.FileName, content.Text); + } + index++; } } finally { if (progressMonitor != null) { progressMonitor.Done(); } - enumerator.Dispose(); } return references; } diff --git a/src/Main/Base/Project/Src/TextEditor/Gui/Dialogs/GotoDialog.cs b/src/Main/Base/Project/Src/TextEditor/Gui/Dialogs/GotoDialog.cs index 7cb7656125..496e5d5050 100644 --- a/src/Main/Base/Project/Src/TextEditor/Gui/Dialogs/GotoDialog.cs +++ b/src/Main/Base/Project/Src/TextEditor/Gui/Dialogs/GotoDialog.cs @@ -113,19 +113,6 @@ namespace ICSharpCode.SharpDevelop.Gui listBox.ScrollIntoView(listBox.Items[index]); } - static readonly IList emptyList = new ICompletionItem[0]; - - IList Resolve(string expression) - { - ITextEditor editor = GetEditor(); - if (editor != null) { - CodeCompletionItemProvider cdp = new DotCodeCompletionItemProvider(); - var list = cdp.GenerateCompletionListForExpression(editor, new ExpressionResult(expression)); - return list != null ? list.Items.ToList() : emptyList; - } - return emptyList; - } - Dictionary visibleEntries = new Dictionary(); int bestMatchType; double bestPriority; @@ -164,29 +151,6 @@ namespace ICSharpCode.SharpDevelop.Gui if (!int.TryParse(line, out lineNr)) lineNr = 0; AddSourceFiles(file, lineNr); - } else if (dotPos > 0) { - AddSourceFiles(text, 0); - string expression = text.Substring(0, dotPos).Trim(); - text = text.Substring(dotPos + 1).Trim(); - ShowCompletionData(Resolve(expression), text); - foreach (IClass c in SearchClasses(expression)) { - if (c.Name.Equals(expression, StringComparison.InvariantCultureIgnoreCase)) { - foreach (IMethod m in c.DefaultReturnType.GetMethods()) { - if (!m.IsConstructor) { - AddItemIfMatchText(text, m, ClassBrowserIconService.GetIcon(m)); - } - } - foreach (IField f in c.DefaultReturnType.GetFields()) { - AddItemIfMatchText(text, f, ClassBrowserIconService.GetIcon(f)); - } - foreach (IProperty p in c.DefaultReturnType.GetProperties()) { - AddItemIfMatchText(text, p, ClassBrowserIconService.GetIcon(p)); - } - foreach (IEvent evt in c.DefaultReturnType.GetEvents()) { - AddItemIfMatchText(text, evt, ClassBrowserIconService.GetIcon(evt)); - } - } - } } else { AddSourceFiles(text, 0); foreach (IClass c in SearchClasses(text)) {