[svn] r7282: vs-plugin/trunk/Nemerle.VsIntegration:
Nemerle.VisualStudio.csproj Project/NemerleIdeBuildLog...
VladD2
svnadmin at nemerle.org
Wed Jan 17 04:56:11 CET 2007
Log:
Fix truncation of error message in Output window.
Author: VladD2
Date: Wed Jan 17 04:56:07 2007
New Revision: 7282
Added:
vs-plugin/trunk/Nemerle.VsIntegration/Project/NemerleIdeBuildLogger.cs
Modified:
vs-plugin/trunk/Nemerle.VsIntegration/Nemerle.VisualStudio.csproj
vs-plugin/trunk/Nemerle.VsIntegration/Project/NemerleProjectNode.cs
vs-plugin/trunk/Nemerle.VsIntegration/Resources.Designer.cs
vs-plugin/trunk/Nemerle.VsIntegration/Resources.resx
Modified: vs-plugin/trunk/Nemerle.VsIntegration/Nemerle.VisualStudio.csproj
==============================================================================
--- vs-plugin/trunk/Nemerle.VsIntegration/Nemerle.VisualStudio.csproj (original)
+++ vs-plugin/trunk/Nemerle.VsIntegration/Nemerle.VisualStudio.csproj Wed Jan 17 04:56:07 2007
@@ -281,6 +281,7 @@
</Compile>
<Compile Include="RegistrationAttributes\SingleFileGeneratorSupportRegistrationAttribute.cs" />
<None Include="app.config" />
+ <Compile Include="Project\NemerleIdeBuildLogger.cs" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
Added: vs-plugin/trunk/Nemerle.VsIntegration/Project/NemerleIdeBuildLogger.cs
==============================================================================
--- (empty file)
+++ vs-plugin/trunk/Nemerle.VsIntegration/Project/NemerleIdeBuildLogger.cs Wed Jan 17 04:56:07 2007
@@ -0,0 +1,503 @@
+using System;
+using System.Diagnostics;
+using System.Globalization;
+using System.CodeDom.Compiler;
+using System.Runtime.InteropServices;
+using System.Text;
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+using Microsoft.VisualStudio.Shell.Interop;
+using Microsoft.VisualStudio.Shell;
+using Microsoft.VisualStudio.TextManager.Interop;
+using Microsoft.Win32;
+using IOleServiceProvider = Microsoft.VisualStudio.OLE.Interop.IServiceProvider;
+using Microsoft.VisualStudio;
+
+namespace Nemerle.VisualStudio.Project
+{
+ /// <summary>
+ /// This class implements an MSBuild logger that output events to
+ /// VS outputwindow and tasklist.
+ /// </summary>
+ [ComVisible(true)]
+ internal class NemerleIdeBuildLogger : Logger
+ {
+ #region fields
+ // TODO: Remove these constants when we have a version that suppoerts
+ // getting the verbosity using automation.
+ private string _buildVerbosityRegistryRoot = @"Software\Microsoft\VisualStudio\8.0";
+ private const string BuildVerbosityRegistrySubKey = @"General";
+ private const string BuildVerbosityRegistryKey = "MSBuildLoggerVerbosity";
+ // TODO: Re-enable this constants when we have a version that
+ // suppoerts getting the verbosity using automation.
+ //private const string EnvironmentCategory = "Environment";
+ //private const string ProjectsAndSolutionSubCategory = "ProjectsAndSolution";
+ //private const string BuildAndRunPage = "BuildAndRun";
+
+ private int _currentIndent;
+ private IVsOutputWindowPane _outputWindowPane;
+ private string _errorString = Resources.Error;
+ private string _warningString = Resources.Warning;
+ private bool _isLogTaskDone;
+ private TaskProvider _taskProvider;
+ private IVsHierarchy _hierarchy;
+ private IServiceProvider _serviceProvider;
+
+ #endregion
+
+ #region properties
+
+ public string WarningString
+ {
+ get { return _warningString; }
+ set { _warningString = value; }
+ }
+
+ public string ErrorString
+ {
+ get { return _errorString; }
+ set { _errorString = value; }
+ }
+
+ public bool IsLogTaskDone
+ {
+ get { return _isLogTaskDone; }
+ set { _isLogTaskDone = value; }
+ }
+
+ /// <summary>
+ /// When building from within VS, setting this will
+ /// enable the logger to retrive the verbosity from
+ /// the correct registry hive.
+ /// </summary>
+ internal string BuildVerbosityRegistryRoot
+ {
+ get { return _buildVerbosityRegistryRoot; }
+ set { _buildVerbosityRegistryRoot = value; }
+ }
+
+ /// <summary>
+ /// Set to null to avoid writing to the output window
+ /// </summary>
+ internal IVsOutputWindowPane OutputWindowPane
+ {
+ get { return _outputWindowPane; }
+ set { _outputWindowPane = value; }
+ }
+
+ #endregion
+
+ #region ctors
+
+ /// <summary>
+ /// Constructor. Inititialize member data.
+ /// </summary>
+ public NemerleIdeBuildLogger(IVsOutputWindowPane output, TaskProvider taskProvider, IVsHierarchy hierarchy)
+ {
+ if (taskProvider == null)
+ throw new ArgumentNullException("taskProvider");
+ if (hierarchy == null)
+ throw new ArgumentNullException("hierarchy");
+
+ _taskProvider = taskProvider;
+ _outputWindowPane = output;
+ _hierarchy = hierarchy;
+ IOleServiceProvider site;
+ Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(hierarchy.GetSite(out site));
+ _serviceProvider = new ServiceProvider(site);
+ }
+
+ #endregion
+
+ #region overridden methods
+ /// <summary>
+ /// Overridden from the Logger class.
+ /// </summary>
+ public override void Initialize(IEventSource eventSource)
+ {
+ if (null == eventSource)
+ throw new ArgumentNullException("eventSource");
+
+ eventSource.BuildStarted += BuildStartedHandler;
+ eventSource.BuildFinished += BuildFinishedHandler;
+ eventSource.ProjectStarted += ProjectStartedHandler;
+ eventSource.ProjectFinished += ProjectFinishedHandler;
+ eventSource.TargetStarted += TargetStartedHandler;
+ eventSource.TargetFinished += TargetFinishedHandler;
+ eventSource.TaskStarted += TaskStartedHandler;
+ eventSource.TaskFinished += TaskFinishedHandler;
+ eventSource.CustomEventRaised += CustomHandler;
+ eventSource.ErrorRaised += ErrorHandler;
+ eventSource.WarningRaised += WarningHandler;
+ eventSource.MessageRaised += MessageHandler;
+ }
+
+ #endregion
+
+ #region event delegates
+
+ /// <summary>
+ /// This is the delegate for error events.
+ /// </summary>
+ private void ErrorHandler(object sender, BuildErrorEventArgs errorEvent)
+ {
+ AddToErrorList(errorEvent, errorEvent.Code, errorEvent.File,
+ errorEvent.LineNumber, errorEvent.ColumnNumber);
+ }
+
+ /// <summary>
+ /// This is the delegate for warning events.
+ /// </summary>
+ private void WarningHandler(object sender, BuildWarningEventArgs errorEvent)
+ {
+ AddToErrorList(errorEvent, errorEvent.Code, errorEvent.File,
+ errorEvent.LineNumber, errorEvent.ColumnNumber);
+ }
+
+ /// <summary>
+ /// Add the error/warning to the error list and potentially to the output window.
+ /// </summary>
+ private void AddToErrorList(
+ BuildEventArgs errorEvent,
+ string errorCode,
+ string file,
+ int line,
+ int column)
+ {
+ TaskPriority priority = (errorEvent is BuildErrorEventArgs)
+ ? TaskPriority.High : TaskPriority.Normal;
+
+ if (OutputWindowPane != null
+ && (Verbosity != LoggerVerbosity.Quiet || errorEvent is BuildErrorEventArgs))
+ {
+ // Format error and output it to the output window
+ string message = FormatMessage(errorEvent.Message);
+ CompilerError e = new CompilerError(file, line, column, errorCode, message);
+ e.IsWarning = (errorEvent is BuildWarningEventArgs);
+
+ Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(
+ OutputWindowPane.OutputStringThreadSafe(GetFormattedErrorMessage(e)));
+ }
+
+ // Add error to task list
+ ErrorTask task = new ErrorTask();
+ task.Document = file;
+ task.Line = line - 1; // The task list does +1 before showing this number.
+ task.Column = column;
+ task.Text = errorEvent.Message;
+ task.Priority = priority;
+ task.Category = TaskCategory.BuildCompile;
+ task.HierarchyItem = _hierarchy;
+ task.Navigate += new EventHandler(NavigateTo);
+ if (errorEvent is BuildWarningEventArgs)
+ task.ErrorCategory = TaskErrorCategory.Warning;
+ _taskProvider.Tasks.Add(task);
+ }
+
+
+ /// <summary>
+ /// This is the delegate for Message event types
+ /// </summary>
+ private void MessageHandler(object sender, BuildMessageEventArgs messageEvent)
+ {
+ if (LogAtImportance(messageEvent.Importance))
+ LogEvent(sender, messageEvent);
+ }
+
+ private void NavigateTo(object sender, EventArgs arguments)
+ {
+ Microsoft.VisualStudio.Shell.Task task =
+ sender as Microsoft.VisualStudio.Shell.Task;
+
+ if (task == null)
+ throw new ArgumentException("sender");
+
+ // Get the doc data for the task's document
+ if (String.IsNullOrEmpty(task.Document))
+ return;
+
+ IVsUIShellOpenDocument openDoc = _serviceProvider.GetService(
+ typeof(IVsUIShellOpenDocument)) as IVsUIShellOpenDocument;
+
+ if (openDoc == null)
+ return;
+
+ IVsWindowFrame frame;
+ IOleServiceProvider sp;
+ IVsUIHierarchy hier;
+ uint itemid;
+ Guid logicalView = VSConstants.LOGVIEWID_Code;
+
+ if (NativeMethods.Failed(openDoc.OpenDocumentViaProject(
+ task.Document, ref logicalView, out sp, out hier, out itemid, out frame))
+ || frame == null
+ )
+ return;
+
+ object docData;
+ frame.GetProperty((int)__VSFPROPID.VSFPROPID_DocData, out docData);
+
+ // Get the VsTextBuffer
+ VsTextBuffer buffer = docData as VsTextBuffer;
+ if (buffer == null)
+ {
+ IVsTextBufferProvider bufferProvider = docData as IVsTextBufferProvider;
+ if (bufferProvider != null)
+ {
+ IVsTextLines lines;
+ NativeMethods.ThrowOnFailure(bufferProvider.GetTextBuffer(out lines));
+ buffer = lines as VsTextBuffer;
+ Debug.Assert(buffer != null, "IVsTextLines does not implement IVsTextBuffer");
+
+ if (buffer == null)
+ return;
+ }
+ }
+
+ // Finally, perform the navigation.
+ IVsTextManager mgr = _serviceProvider.GetService(
+ typeof(VsTextManagerClass)) as IVsTextManager;
+
+ if (mgr == null)
+ return;
+
+ mgr.NavigateToLineAndColumn(buffer, ref logicalView,
+ task.Line, task.Column, task.Line, task.Column);
+ }
+
+ /// <summary>
+ /// This is the delegate for BuildStartedHandler events.
+ /// </summary>
+ private void BuildStartedHandler(object sender, BuildStartedEventArgs buildEvent)
+ {
+ if (LogAtImportance(MessageImportance.Low))
+ LogEvent(sender, buildEvent);
+
+ // Remove all errors and warnings since we are rebuilding
+ _taskProvider.Tasks.Clear();
+ }
+
+ /// <summary>
+ /// This is the delegate for BuildFinishedHandler events.
+ /// </summary>
+ /// <param name="sender"></param>
+ /// <param name="buildEvent"></param>
+ private void BuildFinishedHandler(object sender, BuildFinishedEventArgs buildEvent)
+ {
+ if (LogAtImportance(buildEvent.Succeeded
+ ? MessageImportance.Low : MessageImportance.High))
+ {
+ if (_outputWindowPane != null)
+ _outputWindowPane.OutputStringThreadSafe(Environment.NewLine);
+
+ LogEvent(sender, buildEvent);
+ }
+ }
+
+
+ /// <summary>
+ /// This is the delegate for ProjectStartedHandler events.
+ /// </summary>
+ private void ProjectStartedHandler(object sender, ProjectStartedEventArgs buildEvent)
+ {
+ if (LogAtImportance(MessageImportance.Low))
+ LogEvent(sender, buildEvent);
+ }
+
+ /// <summary>
+ /// This is the delegate for ProjectFinishedHandler events.
+ /// </summary>
+ private void ProjectFinishedHandler(object sender, ProjectFinishedEventArgs buildEvent)
+ {
+ if (LogAtImportance(buildEvent.Succeeded ? MessageImportance.Low : MessageImportance.High))
+ LogEvent(sender, buildEvent);
+ }
+
+ /// <summary>
+ /// This is the delegate for TargetStartedHandler events.
+ /// </summary>
+ private void TargetStartedHandler(object sender, TargetStartedEventArgs buildEvent)
+ {
+ if (LogAtImportance(MessageImportance.Normal))
+ LogEvent(sender, buildEvent);
+
+ ++_currentIndent;
+ }
+
+
+ /// <summary>
+ /// This is the delegate for TargetFinishedHandler events.
+ /// </summary>
+ private void TargetFinishedHandler(object sender, TargetFinishedEventArgs buildEvent)
+ {
+ --_currentIndent;
+ if ((_isLogTaskDone) && LogAtImportance(buildEvent.Succeeded
+ ? MessageImportance.Low : MessageImportance.High)
+ )
+ LogEvent(sender, buildEvent);
+ }
+
+
+ /// <summary>
+ /// This is the delegate for TaskStartedHandler events.
+ /// </summary>
+ private void TaskStartedHandler(object sender, TaskStartedEventArgs buildEvent)
+ {
+ if (LogAtImportance(MessageImportance.Normal))
+ LogEvent(sender, buildEvent);
+
+ ++_currentIndent;
+ }
+
+
+ /// <summary>
+ /// This is the delegate for TaskFinishedHandler events.
+ /// </summary>
+ private void TaskFinishedHandler(object sender, TaskFinishedEventArgs buildEvent)
+ {
+ --_currentIndent;
+ if (_isLogTaskDone && LogAtImportance(buildEvent.Succeeded
+ ? MessageImportance.Normal : MessageImportance.High))
+ {
+ LogEvent(sender, buildEvent);
+ }
+ }
+
+
+ /// <summary>
+ /// This is the delegate for CustomHandler events.
+ /// </summary>
+ /// <param name="sender"></param>
+ /// <param name="buildEvent"></param>
+ private void CustomHandler(object sender, CustomBuildEventArgs buildEvent)
+ {
+ LogEvent(sender, buildEvent);
+ }
+
+ #endregion
+
+ #region helpers
+ /// <summary>
+ /// This method takes a MessageImportance and returns true if messages
+ /// at importance i should be loggeed. Otherwise return false.
+ /// </summary>
+ private bool LogAtImportance(MessageImportance importance)
+ {
+ // If importance is too low for current settings, ignore the event
+ bool logIt = false;
+
+ SetVerbosity();
+
+ switch (Verbosity)
+ {
+ case LoggerVerbosity.Quiet:
+ logIt = false;
+ break;
+ case LoggerVerbosity.Minimal:
+ logIt = (importance == MessageImportance.High);
+ break;
+ case LoggerVerbosity.Normal:
+ // Falling through...
+ case LoggerVerbosity.Detailed:
+ logIt = (importance != MessageImportance.Low);
+ break;
+ case LoggerVerbosity.Diagnostic:
+ logIt = true;
+ break;
+ default:
+ Debug.Fail("Unknown Verbosity level. Ignoring will cause everything to be logged");
+ break;
+ }
+
+ return logIt;
+ }
+
+ /// <summary>
+ /// This is the method that does the main work of logging an event
+ /// when one is sent to this logger.
+ /// </summary>
+ private void LogEvent(object sender, BuildEventArgs buildEvent)
+ {
+ // Fill in the Message text
+ if (OutputWindowPane != null && !String.IsNullOrEmpty(buildEvent.Message))
+ {
+ StringBuilder msg = new StringBuilder(_currentIndent + buildEvent.Message.Length + 1);
+ if (_currentIndent > 0)
+ msg.Append('\t', _currentIndent);
+
+ msg.AppendLine(buildEvent.Message);
+ OutputWindowPane.OutputStringThreadSafe(msg.ToString());
+ }
+ }
+
+ /// <summary>
+ /// This is called when the build complete.
+ /// </summary>
+ private void ShutdownLogger()
+ {
+ }
+
+
+ /// <summary>
+ /// Format error messages for the task list
+ /// </summary>
+ /// <param name="e"></param>
+ /// <returns></returns>
+ private string GetFormattedErrorMessage(CompilerError e)
+ {
+ if (e == null) return String.Empty;
+
+ string errCode = e.IsWarning ? _warningString : _errorString;
+ StringBuilder fileRef = new StringBuilder();
+
+ if (!string.IsNullOrEmpty(e.FileName))
+ fileRef.AppendFormat("{0}({1},{2}):", e.FileName, e.Line, e.Column);
+
+ if (string.IsNullOrEmpty(e.ErrorNumber))
+ fileRef.AppendFormat("{0}: {1}", errCode, e.ErrorText);
+ else
+ fileRef.AppendFormat(CultureInfo.CurrentUICulture, "{0} {1}: {2}",
+ errCode, e.ErrorNumber, e.ErrorText);
+
+ return fileRef.ToString();
+ }
+
+ /// <summary>
+ /// Formats the message that is to be output.
+ /// </summary>
+ /// <param name="message">The message string.</param>
+ /// <returns>The new message</returns>
+ private string FormatMessage(string message)
+ {
+ return (message + Environment.NewLine).Replace('`', '\'');
+ }
+
+ /// <summary>
+ /// Sets the verbosity level.
+ /// </summary>
+ private void SetVerbosity()
+ {
+ // TODO: This should be replaced when we have a version that supports automation.
+
+ string verbosityKey = String.Format(@"{0}\{1}", BuildVerbosityRegistryRoot, BuildVerbosityRegistrySubKey);
+ using (RegistryKey subKey = Registry.CurrentUser.OpenSubKey(verbosityKey))
+ {
+ if (subKey != null)
+ {
+ object valueAsObject = subKey.GetValue(BuildVerbosityRegistryKey);
+ if (valueAsObject != null)
+ Verbosity = (LoggerVerbosity)((int)valueAsObject);
+ }
+ }
+
+ // TODO: Continue this code to get the Verbosity
+ // when we have a version that supports automation to get the Verbosity.
+ //EnvDTE.DTE dte = _serviceProvider.GetService(typeof(EnvDTE.DTE)) as EnvDTE.DTE;
+ //EnvDTE.Properties properties = dte.get_Properties(EnvironmentCategory,
+ // ProjectsAndSolutionSubCategory);
+ }
+
+ #endregion
+ }
+
+}
Modified: vs-plugin/trunk/Nemerle.VsIntegration/Project/NemerleProjectNode.cs
==============================================================================
--- vs-plugin/trunk/Nemerle.VsIntegration/Project/NemerleProjectNode.cs (original)
+++ vs-plugin/trunk/Nemerle.VsIntegration/Project/NemerleProjectNode.cs Wed Jan 17 04:56:07 2007
@@ -171,6 +171,56 @@
#region Overridden Methods
+ protected override void SetOutputLogger(IVsOutputWindowPane output)
+ {
+ //base.SetOutputLogger(output);
+ // Create our logger, if it was not specified
+ if (BuildLogger == null)
+ {
+ // Because we may be aggregated, we need to make sure to get the outer IVsHierarchy
+ IntPtr unknown = IntPtr.Zero;
+ IVsHierarchy hierarchy = null;
+ try
+ {
+ unknown = Marshal.GetIUnknownForObject(this);
+ hierarchy = Marshal.GetTypedObjectForIUnknown(unknown, typeof(IVsHierarchy)) as IVsHierarchy;
+ }
+ finally
+ {
+ if (unknown != IntPtr.Zero)
+ Marshal.Release(unknown);
+ }
+ // Create the logger
+ BuildLogger = new NemerleIdeBuildLogger(output, this.TaskProvider, hierarchy);
+
+ // To retrive the verbosity level, the build logger depends on the registry root
+ // (otherwise it will used an hardcoded default)
+ ILocalRegistry2 registry = this.GetService(typeof(SLocalRegistry)) as ILocalRegistry2;
+ if (null != registry)
+ {
+ string registryRoot;
+ registry.GetLocalRegistryRoot(out registryRoot);
+ IDEBuildLogger logger = this.BuildLogger as IDEBuildLogger;
+ if (!String.IsNullOrEmpty(registryRoot) && (null != logger))
+ {
+ logger.BuildVerbosityRegistryRoot = registryRoot;
+ logger.ErrorString = this.ErrorString;
+ logger.WarningString = this.WarningString;
+ }
+ }
+ }
+ else
+ {
+ ((NemerleIdeBuildLogger)this.BuildLogger).OutputWindowPane = output;
+ }
+
+ if (BuildEngine != null)
+ {
+ BuildEngine.UnregisterAllLoggers();
+ BuildEngine.RegisterLogger(BuildLogger);
+ }
+ }
+
public override int Close()
{
if (null != Site)
Modified: vs-plugin/trunk/Nemerle.VsIntegration/Resources.Designer.cs
==============================================================================
--- vs-plugin/trunk/Nemerle.VsIntegration/Resources.Designer.cs (original)
+++ vs-plugin/trunk/Nemerle.VsIntegration/Resources.Designer.cs Wed Jan 17 04:56:07 2007
@@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
-// Runtime Version:2.0.50727.42
+// Runtime Version:2.0.50727.308
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@@ -228,6 +228,15 @@
}
/// <summary>
+ /// Looks up a localized string similar to Error.
+ /// </summary>
+ internal static string Error {
+ get {
+ return ResourceManager.GetString("Error", resourceCulture);
+ }
+ }
+
+ /// <summary>
/// Looks up a localized string similar to General.
/// </summary>
internal static string GeneralCaption {
@@ -454,6 +463,15 @@
}
/// <summary>
+ /// Looks up a localized string similar to Warning.
+ /// </summary>
+ internal static string Warning {
+ get {
+ return ResourceManager.GetString("Warning", resourceCulture);
+ }
+ }
+
+ /// <summary>
/// Looks up a localized string similar to Working Directory.
/// </summary>
internal static string WorkingDirectory {
Modified: vs-plugin/trunk/Nemerle.VsIntegration/Resources.resx
==============================================================================
--- vs-plugin/trunk/Nemerle.VsIntegration/Resources.resx (original)
+++ vs-plugin/trunk/Nemerle.VsIntegration/Resources.resx Wed Jan 17 04:56:07 2007
@@ -257,4 +257,10 @@
<data name="105" xml:space="preserve">
<value>ZRRZZCP8HEA1C8J2QTP3IEC0P3EEHQHRQACRZDJ3EHP2RQDZI2ZKMJAEATQ3HRP0MRZHIDD2DPPRE0RQARA8C2C3C0QTQKZPR1PAHPZJI2ADACHCIEKIICHJA3QDIRA1</value>
</data>
+ <data name="Error" xml:space="preserve">
+ <value>Error</value>
+ </data>
+ <data name="Warning" xml:space="preserve">
+ <value>Warning</value>
+ </data>
</root>
\ No newline at end of file
More information about the svn
mailing list