📄 parserservice.cs
字号:
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Mike Krüger" email="mike@icsharpcode.net"/>
// <version>$Revision: 1393 $</version>
// </file>
using System;
using System.IO;
using System.Threading;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Serialization.Formatters.Binary;
using System.Security;
using System.Security.Permissions;
using System.Security.Policy;
using System.Xml;
using System.Text;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.Project;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.SharpDevelop.Dom;
namespace ICSharpCode.Core
{
public static class ParserService
{
static ParserDescriptor[] parser;
static Dictionary<IProject, IProjectContent> projectContents = new Dictionary<IProject, IProjectContent>();
static Dictionary<string, ParseInformation> parsings = new Dictionary<string, ParseInformation>();
public static IProjectContent CurrentProjectContent {
[DebuggerStepThrough]
get {
if (forcedContent != null) return forcedContent;
if (ProjectService.CurrentProject == null || !projectContents.ContainsKey(ProjectService.CurrentProject)) {
return DefaultProjectContent;
}
return projectContents[ProjectService.CurrentProject];
}
}
static IProjectContent forcedContent;
/// <summary>
/// Used for unit tests ONLY!!
/// </summary>
public static void ForceProjectContent(IProjectContent content)
{
forcedContent = content;
}
/// <summary>
/// Gets the list of project contents of all open projects.
/// </summary>
public static IEnumerable<IProjectContent> AllProjectContents {
get {
return projectContents.Values;
}
}
/// <summary>
/// Gets the list of project contents of all open projects plus the referenced project contents.
/// </summary>
public static IEnumerable<IProjectContent> AllProjectContentsWithReferences {
get {
foreach (IProjectContent pc in AllProjectContents) {
yield return pc;
}
foreach (IProjectContent pc in ProjectContentRegistry.LoadedProjectContents) {
yield return pc;
}
}
}
static ParserService()
{
parser = (ParserDescriptor[])AddInTree.BuildItems("/Workspace/Parser", null, false).ToArray(typeof(ParserDescriptor));
ProjectService.SolutionClosed += ProjectServiceSolutionClosed;
}
static void ProjectServiceSolutionClosed(object sender, EventArgs e)
{
abortLoadSolutionProjectsThread = true;
lock (projectContents) {
foreach (IProjectContent content in projectContents.Values) {
content.Dispose();
}
projectContents.Clear();
parsings.Clear();
}
}
static Thread loadSolutionProjectsThread;
static bool abortLoadSolutionProjectsThread;
// do not use an event for this because a solution might be loaded before ParserService
// is initialized
internal static void OnSolutionLoaded()
{
if (loadSolutionProjectsThread != null) {
if (!abortLoadSolutionProjectsThread)
throw new InvalidOperationException("Cannot open new combine without closing old combine!");
if (!loadSolutionProjectsThread.Join(50)) {
// loadSolutionProjects might be waiting for main thread, so give it
// a chance to complete asynchronous calls
WorkbenchSingleton.SafeThreadAsyncCall((ThreadStart)OnSolutionLoaded);
return;
}
}
loadSolutionProjectsThread = new Thread(new ThreadStart(LoadSolutionProjects));
loadSolutionProjectsThread.Priority = ThreadPriority.BelowNormal;
loadSolutionProjectsThread.IsBackground = true;
loadSolutionProjectsThread.Start();
}
public static bool LoadSolutionProjectsThreadRunning {
get {
return loadSolutionProjectsThread != null;
}
}
static void LoadSolutionProjects()
{
try {
abortLoadSolutionProjectsThread = false;
LoggingService.Info("Start LoadSolutionProjects thread");
LoadSolutionProjectsInternal();
} finally {
LoggingService.Info("LoadSolutionProjects thread ended");
loadSolutionProjectsThread = null;
OnLoadSolutionProjectsThreadEnded(EventArgs.Empty);
}
}
static void LoadSolutionProjectsInternal()
{
List<ParseProjectContent> createdContents = new List<ParseProjectContent>();
foreach (IProject project in ProjectService.OpenSolution.Projects) {
try {
ParseProjectContent newContent = project.CreateProjectContent();
lock (projectContents) {
projectContents[project] = newContent;
}
createdContents.Add(newContent);
} catch (Exception e) {
ICSharpCode.Core.MessageService.ShowError(e, "Error while retrieving project contents from " + project);
}
}
WorkbenchSingleton.SafeThreadAsyncCall((ThreadStart)ProjectService.ParserServiceCreatedProjectContents);
int workAmount = 0;
foreach (ParseProjectContent newContent in createdContents) {
if (abortLoadSolutionProjectsThread) return;
try {
newContent.Initialize1();
workAmount += newContent.GetInitializationWorkAmount();
} catch (Exception e) {
ICSharpCode.Core.MessageService.ShowError(e, "Error while initializing project references:" + newContent);
}
}
StatusBarService.ProgressMonitor.BeginTask("Parsing...", workAmount);
foreach (ParseProjectContent newContent in createdContents) {
if (abortLoadSolutionProjectsThread) break;
try {
newContent.Initialize2();
} catch (Exception e) {
ICSharpCode.Core.MessageService.ShowError(e, "Error while initializing project contents:" + newContent);
}
}
StatusBarService.ProgressMonitor.Done();
}
static void InitAddedProject(object state)
{
ParseProjectContent newContent = (ParseProjectContent)state;
newContent.Initialize1();
StatusBarService.ProgressMonitor.BeginTask("Parsing...", newContent.GetInitializationWorkAmount());
newContent.Initialize2();
StatusBarService.ProgressMonitor.Done();
}
static void ReparseProject(object state)
{
ParseProjectContent newContent = (ParseProjectContent)state;
StatusBarService.ProgressMonitor.BeginTask("Parsing...", newContent.GetInitializationWorkAmount());
newContent.ReInitialize2();
StatusBarService.ProgressMonitor.Done();
}
public static void Reparse(IProject project)
{
ParseProjectContent pc = GetProjectContent(project) as ParseProjectContent;
if (pc != null) {
ThreadPool.QueueUserWorkItem(ReparseProject, pc);
}
}
internal static IProjectContent CreateProjectContentForAddedProject(IProject project)
{
lock (projectContents) {
ParseProjectContent newContent = project.CreateProjectContent();
projectContents[project] = newContent;
ThreadPool.QueueUserWorkItem(InitAddedProject, newContent);
return newContent;
}
}
public static IProjectContent GetProjectContent(IProject project)
{
lock (projectContents) {
if (projectContents.ContainsKey(project)) {
return projectContents[project];
}
}
return null;
}
static Queue<KeyValuePair<string, string>> parseQueue = new Queue<KeyValuePair<string, string>>();
static void ParseQueue()
{
while (true) {
KeyValuePair<string, string> entry;
lock (parseQueue) {
if (parseQueue.Count == 0)
return;
entry = parseQueue.Dequeue();
}
ParseFile(entry.Key, entry.Value);
}
}
public static void EnqueueForParsing(string fileName)
{
EnqueueForParsing(fileName, GetParseableFileContent(fileName));
}
public static void EnqueueForParsing(string fileName, string fileContent)
{
lock (parseQueue) {
parseQueue.Enqueue(new KeyValuePair<string, string>(fileName, fileContent));
}
}
public static void StartParserThread()
{
abortParserUpdateThread = false;
Thread parserThread = new Thread(new ThreadStart(ParserUpdateThread));
parserThread.Priority = ThreadPriority.BelowNormal;
parserThread.IsBackground = true;
parserThread.Start();
}
public static void StopParserThread()
{
abortParserUpdateThread = true;
}
static volatile bool abortParserUpdateThread = false;
static Dictionary<string, int> lastUpdateHash = new Dictionary<string, int>();
static void ParserUpdateThread()
{
LoggingService.Info("ParserUpdateThread started");
// preload mscorlib, we're going to need it anyway
IProjectContent dummyVar = ProjectContentRegistry.Mscorlib;
while (!abortParserUpdateThread) {
try {
ParseQueue();
ParserUpdateStep();
} catch (Exception e) {
ICSharpCode.Core.MessageService.ShowError(e);
// don't fire an exception every 2 seconds at the user, give him at least
// time to read the first :-)
Thread.Sleep(10000);
}
Thread.Sleep(2000);
}
LoggingService.Info("ParserUpdateThread stopped");
}
static object[] GetWorkbench()
{
IWorkbenchWindow activeWorkbenchWindow = WorkbenchSingleton.Workbench.ActiveWorkbenchWindow;
if (activeWorkbenchWindow == null)
return null;
IBaseViewContent activeViewContent = activeWorkbenchWindow.ActiveViewContent;
if (activeViewContent == null)
return null;
return new object[] { activeViewContent, activeWorkbenchWindow.ViewContent };
}
public static void ParseCurrentViewContent()
{
ParserUpdateStep();
}
static void ParserUpdateStep()
{
object[] workbench;
try {
workbench = (object[])WorkbenchSingleton.SafeThreadCall(typeof(ParserService), "GetWorkbench");
} catch (ObjectDisposedException) {
// maybe workbench has been disposed while waiting for the SafeThreadCall
LoggingService.Warn("ObjectDisposedException while trying to invoke GetWorkbench()");
if (abortParserUpdateThread)
return; // abort this thread
else
throw; // some other error -> re-raise
}
if (workbench != null) {
IEditable editable = workbench[0] as IEditable;
if (editable != null) {
string fileName = null;
IViewContent viewContent = (IViewContent)workbench[1];
IParseableContent parseableContent = workbench[0] as IParseableContent;
//ivoko: Pls, do not throw text = parseableContent.ParseableText away. I NEED it.
string text = null;
if (parseableContent != null) {
fileName = parseableContent.ParseableContentName;
text = parseableContent.ParseableText;
} else {
fileName = viewContent.IsUntitled ? viewContent.UntitledName : viewContent.FileName;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -