4 using System.CodeDom.Compiler;
5 using System.Diagnostics;
6 using System.Globalization;
7 using System.Runtime.InteropServices;
9 using Microsoft.Build.Framework;
11 using Microsoft.VisualStudio;
12 using Microsoft.VisualStudio.Shell;
13 using Microsoft.VisualStudio.Shell.Interop;
14 using Microsoft.VisualStudio.TextManager.Interop;
15 using Microsoft.Win32;
18 namespace SiliconStudio.Paradox.VisualStudio.BuildEngine
24 [System.Diagnostics.CodeAnalysis.SuppressMessage(
"Microsoft.Design",
"CA1001:TypesThatOwnDisposableFieldsShouldBeDisposable"), ComVisible(
true)]
25 internal sealed
class IDEBuildLogger :
Logger
29 private static RegistryKey userRegistryRoot;
30 private const string buildVerbosityRegistrySubKey =
@"General";
31 private const string buildVerbosityRegistryKey =
"MSBuildLoggerVerbosity";
37 private int currentIndent;
38 private IVsOutputWindowPane outputWindowPane;
39 private string errorString =
"error";
40 private string warningString =
"warning";
41 private bool isLogTaskDone;
42 private TaskProvider taskProvider;
43 private IVsHierarchy hierarchy;
44 private IServiceProvider serviceProvider;
49 public string WarningString
51 get {
return this.warningString; }
52 set { this.warningString = value; }
54 public string ErrorString
56 get {
return this.errorString; }
57 set { this.errorString = value; }
59 [System.Diagnostics.CodeAnalysis.SuppressMessage(
"Microsoft.Performance",
"CA1811:AvoidUncalledPrivateCode")]
60 public bool IsLogTaskDone
62 get {
return this.isLogTaskDone; }
63 set { this.isLogTaskDone = value; }
70 internal static RegistryKey UserRegistryRoot
72 get {
return userRegistryRoot; }
73 set { userRegistryRoot = value; }
78 internal IVsOutputWindowPane OutputWindowPane
80 get {
return outputWindowPane; }
81 set { outputWindowPane = value; }
89 public IDEBuildLogger(IVsOutputWindowPane output, TaskProvider taskProvider, IVsHierarchy hierarchy)
91 if (taskProvider == null)
92 throw new ArgumentNullException(
"taskProvider");
93 if (hierarchy == null)
94 throw new ArgumentNullException(
"hierarchy");
96 this.taskProvider = taskProvider;
97 this.outputWindowPane = output;
98 this.hierarchy = hierarchy;
100 Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(hierarchy.GetSite(out site));
101 this.serviceProvider =
new ServiceProvider(site);
105 #region overridden methods
109 public override void Initialize(IEventSource eventSource)
111 if (null == eventSource)
113 throw new ArgumentNullException(
"eventSource");
115 eventSource.BuildStarted +=
new BuildStartedEventHandler(BuildStartedHandler);
116 eventSource.BuildFinished +=
new BuildFinishedEventHandler(BuildFinishedHandler);
117 eventSource.ProjectStarted +=
new ProjectStartedEventHandler(ProjectStartedHandler);
118 eventSource.ProjectFinished +=
new ProjectFinishedEventHandler(ProjectFinishedHandler);
119 eventSource.TargetStarted +=
new TargetStartedEventHandler(TargetStartedHandler);
120 eventSource.TargetFinished +=
new TargetFinishedEventHandler(TargetFinishedHandler);
121 eventSource.TaskStarted +=
new TaskStartedEventHandler(TaskStartedHandler);
122 eventSource.TaskFinished +=
new TaskFinishedEventHandler(TaskFinishedHandler);
123 eventSource.CustomEventRaised +=
new CustomBuildEventHandler(CustomHandler);
124 eventSource.ErrorRaised +=
new BuildErrorEventHandler(ErrorHandler);
125 eventSource.WarningRaised +=
new BuildWarningEventHandler(WarningHandler);
126 eventSource.MessageRaised +=
new BuildMessageEventHandler(MessageHandler);
130 #region event delegates
134 private void ErrorHandler(
object sender, BuildErrorEventArgs errorEvent)
140 errorEvent.LineNumber,
141 errorEvent.ColumnNumber);
147 private void WarningHandler(
object sender, BuildWarningEventArgs errorEvent)
153 errorEvent.LineNumber,
154 errorEvent.ColumnNumber);
160 [System.Diagnostics.CodeAnalysis.SuppressMessage(
"Microsoft.Performance",
"CA1800:DoNotCastUnnecessarily")]
161 private void AddToErrorList(
162 BuildEventArgs errorEvent,
168 TaskPriority priority = (errorEvent is BuildErrorEventArgs) ? TaskPriority.High : TaskPriority.Normal;
169 if (OutputWindowPane != null
170 && (this.Verbosity != LoggerVerbosity.Quiet || errorEvent is BuildErrorEventArgs))
173 string message = FormatMessage(errorEvent.Message);
174 CompilerError e =
new CompilerError(file,
179 e.IsWarning = (errorEvent is BuildWarningEventArgs);
181 Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(OutputWindowPane.OutputStringThreadSafe(GetFormattedErrorMessage(e)));
185 ErrorTask task =
new ErrorTask();
186 task.Document = file;
187 task.Line = line - 1;
188 task.Column = column;
189 task.Text = errorEvent.Message;
190 task.Priority = priority;
191 task.Category = TaskCategory.BuildCompile;
192 task.HierarchyItem = hierarchy;
193 task.Navigate +=
new EventHandler(NavigateTo);
194 if (errorEvent is BuildWarningEventArgs)
195 task.ErrorCategory = TaskErrorCategory.Warning;
196 this.taskProvider.Tasks.Add(task);
203 private void MessageHandler(
object sender, BuildMessageEventArgs messageEvent)
205 if (LogAtImportance(messageEvent.Importance))
207 LogEvent(sender, messageEvent);
211 private void NavigateTo(
object sender,
EventArgs arguments)
215 throw new ArgumentException(
"Sender is not a Microsoft.VisualStudio.Shell.Task",
"sender");
218 if (String.IsNullOrEmpty(task.Document))
221 IVsUIShellOpenDocument openDoc = serviceProvider.GetService(typeof(IVsUIShellOpenDocument)) as IVsUIShellOpenDocument;
225 IVsWindowFrame frame;
229 Guid logicalView = VSConstants.LOGVIEWID_Code;
231 if (Microsoft.VisualStudio.ErrorHandler.Failed(openDoc.OpenDocumentViaProject(task.Document, ref logicalView, out sp, out hier, out itemid, out frame)) || frame == null)
235 Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(frame.GetProperty((int)__VSFPROPID.VSFPROPID_DocData, out docData));
238 VsTextBuffer buffer = docData as VsTextBuffer;
241 IVsTextBufferProvider bufferProvider = docData as IVsTextBufferProvider;
242 if (bufferProvider != null)
245 Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(bufferProvider.GetTextBuffer(out lines));
246 buffer = lines as VsTextBuffer;
247 Debug.Assert(buffer != null,
"IVsTextLines does not implement IVsTextBuffer");
254 IVsTextManager mgr = serviceProvider.GetService(typeof(VsTextManagerClass)) as IVsTextManager;
258 Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(mgr.NavigateToLineAndColumn(buffer, ref logicalView, task.Line, task.Column, task.Line, task.Column));
264 private void BuildStartedHandler(
object sender, BuildStartedEventArgs buildEvent)
266 if (LogAtImportance(MessageImportance.Low))
268 LogEvent(sender, buildEvent);
271 taskProvider.Tasks.Clear();
279 private void BuildFinishedHandler(
object sender, BuildFinishedEventArgs buildEvent)
281 if (LogAtImportance(buildEvent.Succeeded ? MessageImportance.Low :
282 MessageImportance.High))
284 if (this.outputWindowPane != null)
285 Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(this.outputWindowPane.OutputStringThreadSafe(Environment.NewLine));
286 LogEvent(sender, buildEvent);
294 private void ProjectStartedHandler(
object sender, ProjectStartedEventArgs buildEvent)
296 if (LogAtImportance(MessageImportance.Low))
298 LogEvent(sender, buildEvent);
305 private void ProjectFinishedHandler(
object sender, ProjectFinishedEventArgs buildEvent)
307 if (LogAtImportance(buildEvent.Succeeded ? MessageImportance.Low
308 : MessageImportance.High))
310 LogEvent(sender, buildEvent);
317 private void TargetStartedHandler(
object sender, TargetStartedEventArgs buildEvent)
319 if (LogAtImportance(MessageImportance.Normal))
321 LogEvent(sender, buildEvent);
323 ++this.currentIndent;
330 private void TargetFinishedHandler(
object sender, TargetFinishedEventArgs buildEvent)
332 --this.currentIndent;
333 if ((IsLogTaskDone) &&
334 LogAtImportance(buildEvent.Succeeded ? MessageImportance.Low
335 : MessageImportance.High))
337 LogEvent(sender, buildEvent);
345 private void TaskStartedHandler(
object sender, TaskStartedEventArgs buildEvent)
347 if (LogAtImportance(MessageImportance.Normal))
349 LogEvent(sender, buildEvent);
351 ++this.currentIndent;
358 private void TaskFinishedHandler(
object sender, TaskFinishedEventArgs buildEvent)
360 --this.currentIndent;
361 if ((IsLogTaskDone) &&
362 LogAtImportance(buildEvent.Succeeded ? MessageImportance.Normal
363 : MessageImportance.High))
365 LogEvent(sender, buildEvent);
375 private void CustomHandler(
object sender, CustomBuildEventArgs buildEvent)
377 LogEvent(sender, buildEvent);
387 private bool LogAtImportance(MessageImportance importance)
394 switch (this.Verbosity)
396 case LoggerVerbosity.Quiet:
399 case LoggerVerbosity.Minimal:
400 logIt = (importance == MessageImportance.High);
402 case LoggerVerbosity.Normal:
404 case LoggerVerbosity.Detailed:
405 logIt = (importance != MessageImportance.Low);
407 case LoggerVerbosity.Diagnostic:
411 Debug.Fail(
"Unknown Verbosity level. Ignoring will cause everything to be logged");
422 private void LogEvent(
object sender, BuildEventArgs buildEvent)
425 if (OutputWindowPane != null && !String.IsNullOrEmpty(buildEvent.Message))
427 StringBuilder msg =
new StringBuilder(this.currentIndent + buildEvent.Message.Length + 1);
428 if (this.currentIndent > 0)
430 msg.Append(
'\t', this.currentIndent);
432 msg.AppendLine(buildEvent.Message);
433 Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(this.OutputWindowPane.OutputStringThreadSafe(msg.ToString()));
442 private string GetFormattedErrorMessage(CompilerError e)
444 if (e == null)
return String.Empty;
446 string errCode = (e.IsWarning) ? this.WarningString : this.ErrorString;
447 StringBuilder fileRef =
new StringBuilder();
449 if (!
string.IsNullOrEmpty(e.FileName))
451 fileRef.AppendFormat(CultureInfo.CurrentUICulture,
"{0}({1},{2}):",
452 e.FileName, e.Line, e.Column);
454 fileRef.AppendFormat(CultureInfo.CurrentUICulture,
" {0} {1}: {2}", errCode, e.ErrorNumber, e.ErrorText);
456 return fileRef.ToString();
464 private static string FormatMessage(
string message)
466 if (
string.IsNullOrEmpty(message))
468 return Environment.NewLine;
471 StringBuilder sb =
new StringBuilder(message.Length + Environment.NewLine.Length);
473 sb.AppendLine(message);
474 return sb.ToString();
480 private void SetVerbosity()
484 if (userRegistryRoot != null)
486 using (RegistryKey subKey = userRegistryRoot.OpenSubKey(buildVerbosityRegistrySubKey))
490 object valueAsObject = subKey.GetValue(buildVerbosityRegistryKey);
491 if (valueAsObject != null)
493 this.Verbosity = (LoggerVerbosity)((
int)valueAsObject);
Microsoft.VisualStudio.OLE.Interop.IServiceProvider IOleServiceProvider
System.Threading.Tasks.Task Task
SiliconStudio.Core.Utilities Utilities