diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..5aff5e16 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,7 @@ +; Top-most EditorConfig file +root = true + +; 4-column space indentation +[*.cs] +indent_style = space +indent_size = 4 \ No newline at end of file diff --git a/.gitignore b/.gitignore index 7d392e4a..e7e1f8f3 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ *.suo *.user *.sln.docstates +.vs # Build results @@ -98,6 +99,9 @@ publish/ # NuGet Packages Directory packages/ +# NuGet lock files +project.lock.json + # Windows Azure Build Output csx *.build.csdef diff --git a/Microsoft.Common.Core/Collections/DictionaryExtension.cs b/Microsoft.Common.Core/Collections/DictionaryExtension.cs new file mode 100644 index 00000000..b1e4b2e6 --- /dev/null +++ b/Microsoft.Common.Core/Collections/DictionaryExtension.cs @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace Microsoft.Common.Core { + public static class DictionaryExtension { + public static IDictionary FromAnonymousObject(object data) { + IDictionary dict; + if (data != null) { + dict = data as IDictionary; + if (dict == null) { + var attr = BindingFlags.Public | BindingFlags.Instance; + dict = new Dictionary(); + foreach (var property in data.GetType().GetProperties(attr)) { + if (property.CanRead) { + dict.Add(property.Name, property.GetValue(data, null)); + } + } + } + } + else { + dict = new Dictionary(); + } + return dict; + } + + public static void RemoveWhere(this IDictionary dictionary, Func, bool> predicate) { + var toRemove = dictionary.Where(predicate).ToList(); + foreach (var item in toRemove) { + dictionary.Remove(item.Key); + } + } + } +} diff --git a/Microsoft.Common.Core/Collections/EnumerableExtensions.cs b/Microsoft.Common.Core/Collections/EnumerableExtensions.cs new file mode 100644 index 00000000..21cc5322 --- /dev/null +++ b/Microsoft.Common.Core/Collections/EnumerableExtensions.cs @@ -0,0 +1,113 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Microsoft.Common.Core { + public static class EnumerableExtensions { + public static List AsList(this IEnumerable source) { + return source as List ?? source.ToList(); + } + + public static T[] AsArray(this IEnumerable source) { + return source as T[] ?? source.ToArray(); + } + + public static IEnumerable Append(this IEnumerable source, T item) { + foreach (T sourceItem in source) { + yield return sourceItem; + } + + yield return item; + } + + public static void Split(this IEnumerable source, Func predicate, out IList first, out IList second) { + first = new List(); + second = new List(); + foreach (var item in source) { + if (predicate(item)) { + first.Add(item); + } else { + second.Add(item); + } + } + } + + public static void Split(this IEnumerable source, Func predicate, Func converter, out IList first, out IList second) { + first = new List(); + second = new List(); + foreach (var item in source) { + if (predicate(item)) { + first.Add(converter(item)); + } else { + second.Add(converter(item)); + } + } + } + + public static IEnumerable> Split(this IEnumerable source, int chunkSize) { + var index = 0; + var items = new T[chunkSize]; + foreach (var item in source) { + items[index] = item; + index++; + + if (index == chunkSize) { + index = 0; + yield return items; + items = new T[chunkSize]; + } + } + + if (index > 0) { + T[] lastItems = new T[index]; + Array.Copy(items, 0, lastItems, 0, lastItems.Length); + yield return lastItems; + } + } + + public static IEnumerable IndexWhere(this IEnumerable source, Func predicate) { + var i = 0; + foreach (var item in source) { + if (predicate(item)) { + yield return i; + } + + i++; + } + } + + public static IEnumerable TraverseBreadthFirst(this T root, Func> selectChildren) { + Queue items = new Queue(); + items.Enqueue(root); + while (items.Count > 0) { + var item = items.Dequeue(); + yield return item; + + IEnumerable childen = selectChildren(item); + if (childen == null) { + continue; + } + + foreach (var child in childen) { + items.Enqueue(child); + } + } + } + + public static IEnumerable TraverseDepthFirst(this T root, Func> selectChildren) { + yield return root; + + var children = selectChildren(root); + if (children != null) { + foreach (T child in children) { + foreach (T t in TraverseDepthFirst(child, selectChildren)) { + yield return t; + } + } + } + } + } +} diff --git a/Microsoft.Common.Core/Collections/ListExtensions.cs b/Microsoft.Common.Core/Collections/ListExtensions.cs new file mode 100644 index 00000000..4ffb7ec2 --- /dev/null +++ b/Microsoft.Common.Core/Collections/ListExtensions.cs @@ -0,0 +1,76 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Microsoft.Common.Core.Collections { + public static class ListExtensions { + public static IList AddIf(this IList list, bool condition, T value) { + if (condition) { + list.Add(value); + } + + return list; + } + + public static void RemoveWhere(this IList list, Func predicate) { + for (var i = list.Count - 1; i >= 0; i--) { + if (predicate(list[i])) { + list.RemoveAt(i); + } + } + } + + public static bool AddSorted(this IList list, T value, IComparer comparer = null) { + var index = list.BinarySearch(value, comparer); + if (index >= 0) { + return false; + } + + list.Insert(~index, value); + return true; + } + + public static bool RemoveSorted(this IList list, T value, IComparer comparer = null) { + var index = list.BinarySearch(value, comparer); + if (index < 0) { + return false; + } + + list.RemoveAt(index); + return true; + } + + public static int BinarySearch(this IList list, T value, IComparer comparer = null) { + if (list == null) { + throw new ArgumentNullException(nameof(list)); + } + + comparer = comparer ?? Comparer.Default; + + int low = 0; + int high = list.Count - 1; + + while (low <= high) { + int mid = low + (high - low) / 2; + int comparisonResult = comparer.Compare(list[mid], value); + + if (comparisonResult < 0) { + low = mid + 1; + } else if (comparisonResult > 0) { + high = mid - 1; + } else { + return mid; + } + } + + return ~low; + } + + public static bool Equals(this IList source, IList other, Func predicate) { + return source.Count == other.Count && !source.Where((t, i) => !predicate(t, other[i])).Any(); + } + } +} \ No newline at end of file diff --git a/Microsoft.Common.Core/Composition/INamedExport.cs b/Microsoft.Common.Core/Composition/INamedExport.cs new file mode 100644 index 00000000..06e20653 --- /dev/null +++ b/Microsoft.Common.Core/Composition/INamedExport.cs @@ -0,0 +1,8 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +namespace Microsoft.Common.Core.Composition { + public interface INamedExport { + string Name { get; } + } +} diff --git a/Microsoft.Common.Core/Composition/NamedExportLocator.cs b/Microsoft.Common.Core/Composition/NamedExportLocator.cs new file mode 100644 index 00000000..084c7b5a --- /dev/null +++ b/Microsoft.Common.Core/Composition/NamedExportLocator.cs @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.Linq; + +namespace Microsoft.Common.Core.Composition { + public sealed class NamedExportLocator { + [ImportMany] + private IEnumerable> Exports { get; set; } + + public NamedExportLocator(ICompositionService cs) { + cs.SatisfyImportsOnce(this); + } + + public TExport GetExport(string name) { + return Exports.FirstOrDefault(e => e.Metadata.Name.EqualsOrdinal(name)).Value; + } + } +} diff --git a/Microsoft.Common.Core/Diagnostics/Check.cs b/Microsoft.Common.Core/Diagnostics/Check.cs new file mode 100644 index 00000000..c1d30e91 --- /dev/null +++ b/Microsoft.Common.Core/Diagnostics/Check.cs @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; + +namespace Microsoft.Common.Core.Diagnostics { + public static class Check { + public static void ArgumentNull(string argumentName, object argument) { + if (argument == null) { + throw new ArgumentNullException(argumentName); + } + } + + public static void ArgumentStringNullOrEmpty(string argumentName, string argument) { + Check.ArgumentNull(argumentName, argument); + + if (string.IsNullOrEmpty(argument)) { + throw new ArgumentException(argumentName); + } + } + + public static void ArgumentOutOfRange(string argumentName, Func predicate) { + if (predicate()) { + throw new ArgumentOutOfRangeException(argumentName); + } + } + + public static void InvalidOperation(Func predicate) { + if (predicate()) { + throw new InvalidOperationException(); + } + } + } +} \ No newline at end of file diff --git a/Microsoft.Common.Core/Diagnostics/RestartManager.cs b/Microsoft.Common.Core/Diagnostics/RestartManager.cs new file mode 100644 index 00000000..c341be32 --- /dev/null +++ b/Microsoft.Common.Core/Diagnostics/RestartManager.cs @@ -0,0 +1,137 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Security; + +namespace Microsoft.Common.Core.Diagnostics { + public static class RestartManager { + /// + /// Given a list of filenames with absolute path, returns enumerable of process currently locking those files. + /// + /// Filenames with absolute path. + /// Enumerable of processes locking the files. Empty if it encounters any error. + public static IEnumerable GetProcessesUsingFiles(string[] filePaths) { + uint sessionHandle; + int error = NativeMethods.RmStartSession(out sessionHandle, 0, Guid.NewGuid().ToString("N")); + if (error == 0) { + try { + error = NativeMethods.RmRegisterResources(sessionHandle, (uint)filePaths.Length, filePaths, 0, null, 0, null); + if (error == 0) { + RM_PROCESS_INFO[] processInfo = null; + uint pnProcInfoNeeded = 0, pnProcInfo = 0, lpdwRebootReasons = RmRebootReasonNone; + error = NativeMethods.RmGetList(sessionHandle, out pnProcInfoNeeded, ref pnProcInfo, null, ref lpdwRebootReasons); + while (error == ERROR_MORE_DATA) { + processInfo = new RM_PROCESS_INFO[pnProcInfoNeeded]; + pnProcInfo = (uint)processInfo.Length; + error = NativeMethods.RmGetList(sessionHandle, out pnProcInfoNeeded, ref pnProcInfo, processInfo, ref lpdwRebootReasons); + } + + if (error == 0 && processInfo != null) { + for (var i = 0; i < pnProcInfo; i++) { + RM_PROCESS_INFO procInfo = processInfo[i]; + Process proc = null; + try { + proc = Process.GetProcessById(procInfo.Process.dwProcessId); + } catch (ArgumentException) { + // Eat exceptions for processes which are no longer running. + } + + if (proc != null) { + yield return proc; + } + } + } + } + } finally { + NativeMethods.RmEndSession(sessionHandle); + } + } + } + + private const int RmRebootReasonNone = 0; + private const int CCH_RM_MAX_APP_NAME = 255; + private const int CCH_RM_MAX_SVC_NAME = 63; + private const int ERROR_MORE_DATA = 234; + + [StructLayout(LayoutKind.Sequential)] + private struct RM_UNIQUE_PROCESS { + public int dwProcessId; + public System.Runtime.InteropServices.ComTypes.FILETIME ProcessStartTime; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + private struct RM_PROCESS_INFO { + public RM_UNIQUE_PROCESS Process; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCH_RM_MAX_APP_NAME + 1)] + public string strAppName; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCH_RM_MAX_SVC_NAME + 1)] + public string strServiceShortName; + public RM_APP_TYPE ApplicationType; + public uint AppStatus; + public uint TSSessionId; + [MarshalAs(UnmanagedType.Bool)] + public bool bRestartable; + } + + private enum RM_APP_TYPE { + RmUnknownApp = 0, + RmMainWindow = 1, + RmOtherWindow = 2, + RmService = 3, + RmExplorer = 4, + RmConsole = 5, + RmCritical = 1000 + } + + [SuppressUnmanagedCodeSecurity] + private static class NativeMethods { + /// + /// Starts a new Restart Manager session. + /// + /// A pointer to the handle of a Restart Manager session. The session handle can be passed in subsequent calls to the Restart Manager API. + /// Reserved must be 0. + /// A null-terminated string that contains the session key to the new session. A GUID will work nicely. + /// Error code. 0 is successful. + [DllImport("RSTRTMGR.DLL", CharSet = CharSet.Unicode)] + public static extern int RmStartSession(out uint pSessionHandle, int dwSessionFlags, string strSessionKey); + + /// + /// Ends the Restart Manager session. + /// + /// A handle to an existing Restart Manager session. + /// Error code. 0 is successful. + [DllImport("RSTRTMGR.DLL")] + public static extern int RmEndSession(uint pSessionHandle); + + /// + /// Registers resources to a Restart Manager session. + /// + /// A handle to an existing Restart Manager session. + /// The number of files being registered. + /// An array of strings of full filename paths. + /// The number of processes being registered. + /// An array of RM_UNIQUE_PROCESS structures. + /// The number of services to be registered. + /// An array of null-terminated strings of service short names. + /// Error code. 0 is successful. + [DllImport("RSTRTMGR.DLL", CharSet = CharSet.Unicode)] + public static extern int RmRegisterResources(uint pSessionHandle, uint nFiles, string[] rgsFilenames, uint nApplications, [In] RM_UNIQUE_PROCESS[] rgApplications, uint nServices, string[] rgsServiceNames); + + /// + /// Gets a list of all applications and services that are currently using resources that have been registered with the Restart Manager session. + /// + /// A handle to an existing Restart Manager session. + /// A pointer to an array size necessary to receive RM_PROCESS_INFO structures + /// A pointer to the total number of RM_PROCESS_INFO structures in an array and number of structures filled. + /// An array of RM_PROCESS_INFO structures that list the applications and services using resources that have been registered with the session. + /// Pointer to location that receives a value of the RM_REBOOT_REASON enumeration that describes the reason a system restart is needed. + /// Error code. 0 is successful. + [DllImport("RSTRTMGR.DLL")] + public static extern int RmGetList(uint dwSessionHandle, out uint pnProcInfoNeeded, ref uint pnProcInfo, [In, Out] RM_PROCESS_INFO[] rgAffectedApps, ref uint lpdwRebootReasons); + } + } +} diff --git a/Microsoft.Common.Core/Disposables/CountdownDisposable.cs b/Microsoft.Common.Core/Disposables/CountdownDisposable.cs new file mode 100644 index 00000000..e5dd874f --- /dev/null +++ b/Microsoft.Common.Core/Disposables/CountdownDisposable.cs @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.Threading; + +namespace Microsoft.Common.Core.Disposables { + public sealed class CountdownDisposable { + private readonly Action _disposeAction; + private int _count; + + public int Count => _count; + + public CountdownDisposable(Action disposeAction = null) { + this._disposeAction = disposeAction ?? (() => { }); + } + + public IDisposable Increment() { + Interlocked.Increment(ref _count); + return Disposable.Create(Decrement); + } + + public void Decrement() { + if (Interlocked.Decrement(ref _count) == 0) { + this._disposeAction(); + } + } + } +} diff --git a/Microsoft.Common.Core/Disposables/DefaultDisposable.cs b/Microsoft.Common.Core/Disposables/DefaultDisposable.cs new file mode 100644 index 00000000..561fbab4 --- /dev/null +++ b/Microsoft.Common.Core/Disposables/DefaultDisposable.cs @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; + +namespace Microsoft.Common.Core.Disposables { + /// + /// Represents a disposable that does nothing on disposal. + /// Implementation is copied from System.Reactive.Core.dll + /// + internal sealed class DefaultDisposable : IDisposable { + /// + /// Singleton default disposable. + /// + public static readonly DefaultDisposable Instance = new DefaultDisposable(); + + private DefaultDisposable() { } + + /// + /// Does nothing. + /// + public void Dispose() { } + } +} \ No newline at end of file diff --git a/Microsoft.Common.Core/Disposables/Disposable.cs b/Microsoft.Common.Core/Disposables/Disposable.cs new file mode 100644 index 00000000..3e46c7ea --- /dev/null +++ b/Microsoft.Common.Core/Disposables/Disposable.cs @@ -0,0 +1,57 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.Common.Core.Disposables { + /// + /// Provides a set of static methods for creating Disposables. + /// + public static class Disposable { + /// + /// Creates a disposable object that invokes the specified action when disposed. + /// + /// Action to run during the first call to . The action is guaranteed to be run at most once. + /// The disposable object that runs the given action upon disposal. + /// is null. + public static IDisposable Create(Action dispose) { + if (dispose == null) { + throw new ArgumentNullException(nameof(dispose)); + } + + return new AnonymousDisposable(dispose); + } + + /// + /// Gets the disposable that does nothing when disposed. + /// + public static IDisposable Empty => DefaultDisposable.Instance; + + public static Task EmptyTask { get; } = Task.FromResult(DefaultDisposable.Instance); + + /// + /// Represents an Action-based disposable. + /// + private sealed class AnonymousDisposable : IDisposable { + private Action _dispose; + + /// + /// Constructs a new disposable with the given action used for disposal. + /// + /// Disposal action which will be run upon calling Dispose. + public AnonymousDisposable(Action dispose) { + _dispose = dispose; + } + + /// + /// Calls the disposal action if and only if the current instance hasn't been disposed yet. + /// + public void Dispose() { + Action action = Interlocked.Exchange(ref _dispose, null); + action?.Invoke(); + } + } + } +} diff --git a/Microsoft.Common.Core/Disposables/DisposableBag.cs b/Microsoft.Common.Core/Disposables/DisposableBag.cs new file mode 100644 index 00000000..65d060c0 --- /dev/null +++ b/Microsoft.Common.Core/Disposables/DisposableBag.cs @@ -0,0 +1,62 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.Collections.Concurrent; +using System.Threading; + +namespace Microsoft.Common.Core.Disposables { + public sealed class DisposableBag { + private readonly string _message; + private ConcurrentStack _disposables; + + public static DisposableBag Create(IDisposable disposable) where T : IDisposable => Create().Add(disposable); + public static DisposableBag Create(Action action) where T : IDisposable => Create().Add(action); + public static DisposableBag Create() where T : IDisposable => new DisposableBag(FormattableString.Invariant($"{typeof(T).Name} instance is disposed")); + + public DisposableBag(string message = null) { + _message = message; + _disposables = new ConcurrentStack(); + } + + public DisposableBag Add(IDisposable disposable) => Add(disposable.Dispose); + + public DisposableBag Add(Action action) { + _disposables?.Push(action); + ThrowIfDisposed(); + return this; + } + + public bool TryAdd(IDisposable disposable) => TryAdd(disposable.Dispose); + + public bool TryAdd(Action action) { + _disposables?.Push(action); + return _disposables != null; + } + + public void ThrowIfDisposed() { + if (_disposables != null) { + return; + } + + if (_message == null) { + throw new InvalidOperationException(); + } + + throw new InvalidOperationException(_message); + } + + public bool TryDispose() { + var disposables = Interlocked.Exchange(ref _disposables, null); + if (disposables == null) { + return false; + } + + foreach (var disposable in disposables) { + disposable(); + } + + return true; + } + } +} \ No newline at end of file diff --git a/Microsoft.Common.Core/Disposables/DisposeToken.cs b/Microsoft.Common.Core/Disposables/DisposeToken.cs new file mode 100644 index 00000000..d78b1a0c --- /dev/null +++ b/Microsoft.Common.Core/Disposables/DisposeToken.cs @@ -0,0 +1,39 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.Threading; +using static System.FormattableString; + +namespace Microsoft.Common.Core.Disposables { + public sealed class DisposeToken { + private readonly string _message; + private int _disposed; + + public static DisposeToken Create() where T : IDisposable { + return new DisposeToken(Invariant($"{typeof(T).Name} instance is disposed")); + } + + public bool IsDisposed => _disposed == 1; + + public DisposeToken(string message = null) { + _message = message; + } + + public void ThrowIfDisposed() { + if (_disposed == 0) { + return; + } + + if (_message == null) { + throw new InvalidOperationException(); + } + + throw new InvalidOperationException(_message); + } + + public bool TryMarkDisposed() { + return Interlocked.Exchange(ref _disposed, 1) == 0; + } + } +} \ No newline at end of file diff --git a/Microsoft.Common.Core/Enums/YesNoAsk.cs b/Microsoft.Common.Core/Enums/YesNoAsk.cs new file mode 100644 index 00000000..7e786197 --- /dev/null +++ b/Microsoft.Common.Core/Enums/YesNoAsk.cs @@ -0,0 +1,10 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +namespace Microsoft.Common.Core.Enums { + public enum YesNoAsk { + Yes, + No, + Ask + } +} diff --git a/Microsoft.Common.Core/Extensions/ArraySegmentExtensions.cs b/Microsoft.Common.Core/Extensions/ArraySegmentExtensions.cs new file mode 100644 index 00000000..546c499b --- /dev/null +++ b/Microsoft.Common.Core/Extensions/ArraySegmentExtensions.cs @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.IO; +using System.Linq; +using System.Threading.Tasks; + +namespace Microsoft.Common.Core { + public static class ArraySegmentExtensions { + public static async Task ToByteArrayAsync(this ArraySegment source, int count) { + byte[] data = null; + using (MemoryStream ms = new MemoryStream()) { + await ms.WriteAsync(source.Array, source.Offset, count); + await ms.FlushAsync(); + data = ms.ToArray(); + } + return data; + } + + public static async Task ToByteArrayAsync(this ArraySegment source) { + byte[] data = null; + using (MemoryStream ms = new MemoryStream()) { + await ms.WriteAsync(source.Array, source.Offset, source.Count); + await ms.FlushAsync(); + data = ms.ToArray(); + } + return data; + } + } +} diff --git a/Microsoft.Common.Core/Extensions/AssemblyExtensions.cs b/Microsoft.Common.Core/Extensions/AssemblyExtensions.cs new file mode 100644 index 00000000..4c56a17a --- /dev/null +++ b/Microsoft.Common.Core/Extensions/AssemblyExtensions.cs @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.Reflection; + +namespace Microsoft.Common.Core { + public static class AssemblyExtensions { + public static string GetAssemblyPath(this Assembly assembly) { + var codeBase = assembly.CodeBase; + return new Uri(codeBase).LocalPath; + } + } +} \ No newline at end of file diff --git a/Microsoft.Common.Core/Extensions/CharExtensions.cs b/Microsoft.Common.Core/Extensions/CharExtensions.cs new file mode 100644 index 00000000..3264d383 --- /dev/null +++ b/Microsoft.Common.Core/Extensions/CharExtensions.cs @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +namespace Microsoft.Common.Core { + public static class CharExtensions { + public static char[] LineBreakChars { get; } = new char[] { '\n', '\r' }; + + public static bool IsLineBreak(this char ch) { + return ch == '\r' || ch == '\n'; + } + } +} diff --git a/Microsoft.Common.Core/Extensions/ClipboardExtensions.cs b/Microsoft.Common.Core/Extensions/ClipboardExtensions.cs new file mode 100644 index 00000000..726b9989 --- /dev/null +++ b/Microsoft.Common.Core/Extensions/ClipboardExtensions.cs @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System.Runtime.InteropServices; +using System.Windows.Forms; +using static System.FormattableString; + +namespace Microsoft.Common.Core { + public static class ClipboardExtensions { + public static void CopyToClipboard(this string data) { + try { + Clipboard.SetData(DataFormats.UnicodeText, Invariant($"\"{data}\"")); + } catch (ExternalException) { } + } + } +} diff --git a/Microsoft.Common.Core/Extensions/CompositionBatchExtensions.FactoryReflectionComposablePart.cs b/Microsoft.Common.Core/Extensions/CompositionBatchExtensions.FactoryReflectionComposablePart.cs new file mode 100644 index 00000000..c0b8b4ff --- /dev/null +++ b/Microsoft.Common.Core/Extensions/CompositionBatchExtensions.FactoryReflectionComposablePart.cs @@ -0,0 +1,79 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.ComponentModel.Composition.Primitives; +using System.ComponentModel.Composition.ReflectionModel; +using System.Globalization; +using System.Linq; +using System.Reflection; + +namespace Microsoft.Common.Core.Extensions { + public static partial class CompositionBatchExtensions { + internal class FactoryReflectionComposablePart : ComposablePart { + private readonly ComposablePartDefinition _composablePartDefinition; + private readonly Lazy _composablePart; + private readonly IDictionary> _imports; + + public FactoryReflectionComposablePart(ComposablePartDefinition composablePartDefinition, Delegate valueFactory) { + _composablePartDefinition = composablePartDefinition; + _composablePart = new Lazy(() => CreatePart(valueFactory)); + _imports = new Dictionary>(); + } + + public override IEnumerable ExportDefinitions => _composablePartDefinition.ExportDefinitions; + public override IEnumerable ImportDefinitions => _composablePartDefinition.ImportDefinitions; + public override IDictionary Metadata => _composablePartDefinition.Metadata; + + public override void Activate() { + _composablePart.Value.Activate(); + } + + public override object GetExportedValue(ExportDefinition definition) { + return _composablePart.Value.GetExportedValue(definition); + } + + public override void SetImport(ImportDefinition definition, IEnumerable exports) { + if (_composablePart.IsValueCreated || + _imports == null) { + _composablePart.Value.SetImport(definition, exports); + } else { + _imports.Add(definition, exports); + } + } + + private ComposablePart CreatePart(Delegate valueFactory) { + var args = GetArguments(valueFactory); + var value = valueFactory.DynamicInvoke(args); + var part = AttributedModelServices.CreatePart(_composablePartDefinition, value); + foreach (KeyValuePair> import in _imports) { + part.SetImport(import.Key, import.Value); + } + + _imports.Clear(); + return part; + } + + private object[] GetArguments(Delegate valueFactory) { + object[] arguments = new object[valueFactory.GetMethodInfo().GetParameters().Length]; + + IEnumerable ctorImportDefinitions = ImportDefinitions.Where(ReflectionModelServices.IsImportingParameter); + foreach (ImportDefinition ctorImportDefinition in ctorImportDefinitions) { + ParameterInfo parameterInfo = ReflectionModelServices.GetImportingParameter(ctorImportDefinition).Value; + IEnumerable value; + if (_imports.TryGetValue(ctorImportDefinition, out value)) { + arguments[parameterInfo.Position] = value.Single().Value; + _imports.Remove(ctorImportDefinition); + } else { + throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "There is no export for parameter of type {0}", + parameterInfo.ParameterType)); + } + } + + return arguments; + } + } + } +} \ No newline at end of file diff --git a/Microsoft.Common.Core/Extensions/CompositionBatchExtensions.cs b/Microsoft.Common.Core/Extensions/CompositionBatchExtensions.cs new file mode 100644 index 00000000..e52780bd --- /dev/null +++ b/Microsoft.Common.Core/Extensions/CompositionBatchExtensions.cs @@ -0,0 +1,86 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.ComponentModel.Composition.Hosting; +using System.ComponentModel.Composition.Primitives; +using System.ComponentModel.Composition.ReflectionModel; +using System.Linq; +using System.Reflection; +using System.Threading; + +namespace Microsoft.Common.Core.Extensions { + public static partial class CompositionBatchExtensions { + public static CompositionBatch AddValue(this CompositionBatch batch, TContract value) { + string contractName = AttributedModelServices.GetContractName(typeof(TContract)); + return batch.AddValue(contractName, value); + } + + public static CompositionBatch AddValue(this CompositionBatch batch, string contractName, T value) { + var contractExport = CreateExportDefinition(contractName, typeof(T)); + var partDefinition = CreatePartDefinition(Enumerable.Empty(), contractExport, typeof(T)); + var part = AttributedModelServices.CreatePart(partDefinition, value); + + batch.AddPart(part); + return batch; + } + + public static CompositionBatch AddValueFactory(this CompositionBatch batch, string contractName, ComposablePartDefinition ctorDefinition, Type type, Delegate factory) { + var contractExport = CreateExportDefinition(contractName, type); + var partDefinition = CreatePartDefinition(ctorDefinition.ImportDefinitions, contractExport, type); + var part = new FactoryReflectionComposablePart(partDefinition, factory); + + batch.AddPart(part); + return batch; + } + + private static ExportDefinition CreateExportDefinition(string contractName, Type type) { + LazyMemberInfo memberInfo = new LazyMemberInfo(MemberTypes.TypeInfo, type); + + Lazy> metadata = new Lazy>(() => { + string typeIdentity = AttributedModelServices.GetTypeIdentity(type); + return new Dictionary { + {CompositionConstants.ExportTypeIdentityMetadataName, typeIdentity} + }; + }); + + ExportDefinition exportDefinition = ReflectionModelServices.CreateExportDefinition(memberInfo, contractName, metadata, null); + return exportDefinition; + } + + + private static ComposablePartDefinition CreatePartDefinition(IEnumerable ctorImports, ExportDefinition contractExport, Type type) { + ComposablePartDefinition originalPartDefinition = AttributedModelServices.CreatePartDefinition(type, null); + if (originalPartDefinition == null) { + throw new InvalidOperationException(); + } + + IList imports = originalPartDefinition.ImportDefinitions + .Where(idef => !ReflectionModelServices.IsImportingParameter(idef)) + .Concat(ctorImports) + .ToList(); + + IList exports = originalPartDefinition.ExportDefinitions + .Append(contractExport) + .ToList(); + + IDictionary metadata = originalPartDefinition.Metadata; + + return CreatePartDefinition(type, imports, exports, metadata); + } + + private static ComposablePartDefinition CreatePartDefinition(Type type, IList imports, IList exports, IDictionary metadata) { + return ReflectionModelServices.CreatePartDefinition( + new Lazy(() => type, LazyThreadSafetyMode.PublicationOnly), + false, + new Lazy>(() => imports), + new Lazy>(() => exports), + new Lazy>(() => metadata), + null); + } + + + } +} diff --git a/Microsoft.Common.Core/Extensions/ExceptionExtensions.cs b/Microsoft.Common.Core/Extensions/ExceptionExtensions.cs new file mode 100644 index 00000000..0e621090 --- /dev/null +++ b/Microsoft.Common.Core/Extensions/ExceptionExtensions.cs @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.Runtime.Serialization; +using System.Threading; + +namespace Microsoft.Common.Core { + public static class ExceptionExtensions { + /// + /// Returns true if an exception should not be handled by logging code. + /// + public static bool IsCriticalException(this Exception ex) { + return ex is StackOverflowException || + ex is OutOfMemoryException || + ex is ThreadAbortException || + ex is AccessViolationException || + ex is CriticalException; + } + } + + /// + /// An exception that should not be silently handled and logged. + /// + [Serializable] + class CriticalException : Exception { + public CriticalException() { } + public CriticalException(string message) : base(message) { } + public CriticalException(string message, Exception inner) : base(message, inner) { } + protected CriticalException(SerializationInfo info, StreamingContext context) + : base(info, context) { } + } +} \ No newline at end of file diff --git a/Microsoft.Common.Core/Extensions/IOExtensions.cs b/Microsoft.Common.Core/Extensions/IOExtensions.cs new file mode 100644 index 00000000..1ca19b10 --- /dev/null +++ b/Microsoft.Common.Core/Extensions/IOExtensions.cs @@ -0,0 +1,99 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using Microsoft.Common.Core.IO; + +namespace Microsoft.Common.Core { + public static class IOExtensions { + public static string MakeRelativePath(this string path, string basePath) { + if (string.IsNullOrWhiteSpace(path) || string.IsNullOrWhiteSpace(basePath)) { + return path; + } + var bp = basePath.EndsWith(Path.DirectorySeparatorChar) ? basePath : basePath + Path.DirectorySeparatorChar; + if (path.PathEquals(bp)) { + return string.Empty; + } + return path.StartsWithIgnoreCase(bp) ? path.Substring(bp.Length) : path; + } + + public static bool ExistsOnPath(string fileName) { + return GetFullPath(fileName) != null; + } + + public static string GetFullPath(string fileName) { + if (File.Exists(fileName)) { + return Path.GetFullPath(fileName); + } + + var values = Environment.GetEnvironmentVariable("PATH"); + var paths = values.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries); + foreach (var path in paths) { + var fullPath = Path.Combine(path, fileName); + if (File.Exists(fullPath)) { + return fullPath; + } + } + return null; + } + + /// + /// Recursively enumerate sub-directories and gets all files for the given + /// + public static IEnumerable GetAllFiles(this IDirectoryInfo basedir) { + List files = new List(); + Queue dirs = new Queue(); + dirs.Enqueue(basedir); + while (dirs.Count > 0) { + var dir = dirs.Dequeue(); + foreach (var info in dir.EnumerateFileSystemInfos()) { + var subdir = info as IDirectoryInfo; + if (subdir != null) { + dirs.Enqueue(subdir); + } else { + files.Add(info); + } + } + } + return files; + } + + public static string TrimTrailingSlash(this string path) { + if (!string.IsNullOrEmpty(path) && (path.EndsWith(Path.DirectorySeparatorChar) || path.EndsWith(Path.AltDirectorySeparatorChar))) { + return path.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); + } + return path; + } + + public static bool PathEquals(this string path, string otherPath) { + var pathLength = GetTrailingSlashTrimmedPathLength(path); + var otherPathLength = GetTrailingSlashTrimmedPathLength(otherPath); + + return pathLength == otherPathLength && (pathLength == 0 || string.Compare(path, 0, otherPath, 0, otherPathLength, StringComparison.OrdinalIgnoreCase) == 0); + } + + private static int GetTrailingSlashTrimmedPathLength(string path) { + if (string.IsNullOrEmpty(path)) { + return 0; + } + if (path.EndsWith(Path.DirectorySeparatorChar) || path.EndsWith(Path.AltDirectorySeparatorChar)) { + return path.Length - 1; + } + return path.Length; + } + + public static string EnsureTrailingSlash(this string path) { + if (!string.IsNullOrEmpty(path)) { + if (path[path.Length - 1] == Path.DirectorySeparatorChar || path[path.Length - 1] == Path.AltDirectorySeparatorChar) { + return path; + } + char slash = path.IndexOf(Path.AltDirectorySeparatorChar) >= 0 ? Path.AltDirectorySeparatorChar : Path.DirectorySeparatorChar; + return path + slash; + } + return Path.DirectorySeparatorChar.ToString(); + } + } +} diff --git a/Microsoft.Common.Core/Extensions/MathExtensions.cs b/Microsoft.Common.Core/Extensions/MathExtensions.cs new file mode 100644 index 00000000..cf4ced6b --- /dev/null +++ b/Microsoft.Common.Core/Extensions/MathExtensions.cs @@ -0,0 +1,15 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; + +namespace Microsoft.Common.Core.Extensions { + public static class MathExtensions { + public static T Min(T a, T b) where T : IComparable { + return a.CompareTo(b) <= 0 ? a : b; + } + public static T Max(T a, T b) where T : IComparable { + return a.CompareTo(b) > 0 ? a : b; + } + } +} diff --git a/Microsoft.Common.Core/Extensions/StreamExtensions.cs b/Microsoft.Common.Core/Extensions/StreamExtensions.cs new file mode 100644 index 00000000..f90b1eac --- /dev/null +++ b/Microsoft.Common.Core/Extensions/StreamExtensions.cs @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.IO; +using System.Threading.Tasks; + +namespace Microsoft.Common.Core { + public static class StreamExtensions { + public static async Task CopyAndFlushAsync(this Stream source, Stream destination, IProgress progress = null) { + await source.CopyToAsync(destination, progress); + await destination.FlushAsync(); + } + + public static async Task CopyToAsync(this Stream source, Stream destination, IProgress progress) { + byte[] buffer = new byte[81920]; + int bytesRead = 0; + long bytesTotal = 0; + while ((bytesRead = await source.ReadAsync(buffer, 0, buffer.Length)) > 0) { + await destination.WriteAsync(buffer, 0, bytesRead); + bytesTotal += bytesRead; + progress?.Report(bytesTotal); + } + await destination.FlushAsync(); + } + } +} diff --git a/Microsoft.Common.Core/Extensions/StringBuilderExtensions.cs b/Microsoft.Common.Core/Extensions/StringBuilderExtensions.cs new file mode 100644 index 00000000..18d9ea4d --- /dev/null +++ b/Microsoft.Common.Core/Extensions/StringBuilderExtensions.cs @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System.Text; + +namespace Microsoft.Common.Core { + public static class StringBuilderExtensions { + public static StringBuilder AppendIf(this StringBuilder sb, bool condition, string value) { + if (condition) { + sb.Append(value); + } + + return sb; + } + } +} diff --git a/Microsoft.Common.Core/Extensions/StringExtensions.cs b/Microsoft.Common.Core/Extensions/StringExtensions.cs new file mode 100644 index 00000000..2a1e5fcb --- /dev/null +++ b/Microsoft.Common.Core/Extensions/StringExtensions.cs @@ -0,0 +1,190 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.Globalization; +using System.Security.Cryptography; +using System.Text; + +namespace Microsoft.Common.Core { + public static class StringExtensions { + public static bool EqualsOrdinal(this string s, string other) { + return string.Equals(s, other, StringComparison.Ordinal); + } + public static bool EqualsIgnoreCase(this string s, string other) { + return string.Equals(s, other, StringComparison.OrdinalIgnoreCase); + } + public static bool StartsWithIgnoreCase(this string s, string prefix) { + return s.StartsWith(prefix, StringComparison.OrdinalIgnoreCase); + } + public static bool StartsWithOrdinal(this string s, string prefix) { + return s.StartsWith(prefix, StringComparison.Ordinal); + } + public static bool EndsWithIgnoreCase(this string s, string suffix) { + return s.EndsWith(suffix, StringComparison.OrdinalIgnoreCase); + } + public static bool EndsWithOrdinal(this string s, string suffix) { + return s.EndsWith(suffix, StringComparison.Ordinal); + } + public static bool EndsWith(this string s, char ch) { + return s.Length > 0 && s[s.Length-1] == ch; + } + public static int IndexOfIgnoreCase(this string s, string searchFor) { + return s.IndexOf(searchFor, StringComparison.OrdinalIgnoreCase); + } + public static int IndexOfIgnoreCase(this string s, string searchFor, int startIndex) { + return s.IndexOf(searchFor, startIndex, StringComparison.OrdinalIgnoreCase); + } + public static int IndexOfOrdinal(this string s, string searchFor) { + return s.IndexOf(searchFor, StringComparison.Ordinal); + } + public static int LastIndexOfIgnoreCase(this string s, string searchFor) { + return s.LastIndexOf(searchFor, StringComparison.OrdinalIgnoreCase); + } + public static int LastIndexOfIgnoreCase(this string s, string searchFor, int startIndex) { + return s.LastIndexOf(searchFor, startIndex, StringComparison.OrdinalIgnoreCase); + } + public static bool ContainsIgnoreCase(this string s, string prefix) { + return s.IndexOf(prefix, StringComparison.OrdinalIgnoreCase) >= 0; + } + + public static string TrimQuotes(this string s) { + if (s.Length > 0) { + char quote = s[0]; + if (quote == '\'' || quote == '\"') { + if (s.Length > 1 && s[s.Length - 1] == quote) { + return s.Substring(1, s.Length - 2); + } + return s.Substring(1); + } + } + return s; + } + + public static string Replace(this string s, string oldValue, string newValue, int start, int length) { + if (string.IsNullOrEmpty(oldValue)) { + throw new ArgumentException("oldValue can't be null or empty string", nameof(oldValue)); + } + + if (string.IsNullOrEmpty(s)) { + return s; + } + + if (start < 0) { + start = 0; + } + + if (length < 0) { + length = 0; + } + + return new StringBuilder(s) + .Replace(oldValue, newValue, start, length) + .ToString(); + } + + public static string RemoveWhiteSpaceLines(this string text) { + if (string.IsNullOrWhiteSpace(text)) { + return string.Empty; + } + + var sb = new StringBuilder(text); + var lineBreakIndex = sb.Length; + var isWhiteSpaceOnly = true; + for (var i = sb.Length - 1; i >= 0; i--) { + var ch = sb[i]; + if (ch == '\r' || ch == '\n') { + if (ch == '\n' && i > 0 && sb[i - 1] == '\r') { + i--; + } + + if (isWhiteSpaceOnly) { + sb.Remove(i, lineBreakIndex - i); + } else if (i == 0) { + var rn = sb.Length > 1 && sb[0] == '\r' && sb[1] == '\n'; + sb.Remove(0, rn ? 2 : 1); + break; + } + + lineBreakIndex = i; + isWhiteSpaceOnly = true; + } + + isWhiteSpaceOnly = isWhiteSpaceOnly && char.IsWhiteSpace(ch); + } + + return sb.ToString(); + } + + public static int SubstringToHex(this string s, int position, int count) { + int mul = 1 << (4 * (count - 1)); + int result = 0; + + for (int i = 0; i < count; i++) { + char ch = s[position + i]; + int z; + if (ch >= '0' && ch <= '9') { + z = ch - '0'; + } else if (ch >= 'a' && ch <= 'f') { + z = ch - 'a' + 10; + } else if (ch >= 'A' && ch <= 'F') { + z = ch - 'A' + 10; + } else { + return -1; + } + + result += z * mul; + mul >>= 4; + } + return result; + } + /// + /// Given a string (typically text from a file) determines + /// which line break sequence should be used when editing or + /// formatting the file. If no line breaks found, LF is returned. + /// + public static string GetDefaultLineBreakSequence(this string s) { + int i = s.IndexOfAny(CharExtensions.LineBreakChars); + if (i >= 0) { + if (s[i] == '\n') { + if (i + 1 < s.Length && s[i + 1] == '\r') { + return "\n\r"; + } + return "\n"; + } + if (s[i] == '\r') { + if (i + 1 < s.Length && s[i + 1] == '\n') { + return "\r\n"; + } + return "\r"; + } + } + return "\n"; // default + } + + public static string GetMD5Hash(this string input) { + SHA512 sha = SHA512.Create(); + byte[] inputBytes = Encoding.Unicode.GetBytes(input); + byte[] hash = sha.ComputeHash(inputBytes); + return BitConverter.ToString(hash); + } + + public static string FormatInvariant(this string format, object arg) => + string.Format(CultureInfo.InvariantCulture, format, arg); + + public static string FormatInvariant(this string format, params object[] args) => + string.Format(CultureInfo.InvariantCulture, format, args); + + public static long ToLongOrDefault(this string value) { + long ret; + long.TryParse(value, out ret); + return ret; + } + + public static DateTime ToDateTimeOrDefault(this string value) { + DateTime ret; + DateTime.TryParse(value, out ret); + return ret; + } + } +} diff --git a/Microsoft.Common.Core/Extensions/TaskExtensions.cs b/Microsoft.Common.Core/Extensions/TaskExtensions.cs new file mode 100644 index 00000000..28fa04f5 --- /dev/null +++ b/Microsoft.Common.Core/Extensions/TaskExtensions.cs @@ -0,0 +1,182 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.Linq; +using System.Runtime.ExceptionServices; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.Common.Core { + public static class TaskExtensions { + public static Task FailOnTimeout(this Task task, int millisecondsTimeout) { + return task.TimeoutAfterImpl(millisecondsTimeout); + } + + public static Task FailOnTimeout(this Task task, int millisecondsTimeout) { + return (Task) task.TimeoutAfterImpl(millisecondsTimeout); + } + + public static Task TimeoutAfterImpl(this Task task, int millisecondsTimeout) { + if (task.IsCompleted || (millisecondsTimeout == Timeout.Infinite)) { + return task; + } + + if (millisecondsTimeout == 0) { + return Task.FromException(new TimeoutException()); + } + + var tcs = new TaskCompletionSource(); + var cancelByTimeout = new TimerCallback(state => ((TaskCompletionSource)state).TrySetException(new TimeoutException())); + var timer = new Timer(cancelByTimeout, tcs, millisecondsTimeout, Timeout.Infinite); + var taskState = new TimeoutAfterState(timer, tcs); + + var continuation = new Action((source, state) => { + var timeoutAfterState = (TimeoutAfterState)state; + timeoutAfterState.Timer.Dispose(); + + switch (source.Status) { + case TaskStatus.Faulted: + timeoutAfterState.Tcs.TrySetException(source.Exception); + break; + case TaskStatus.Canceled: + timeoutAfterState.Tcs.TrySetCanceled(); + break; + case TaskStatus.RanToCompletion: + var typedTask = source as Task; + timeoutAfterState.Tcs.TrySetResult(typedTask != null ? typedTask.Result : default(T)); + break; + } + }); + + task.ContinueWith(continuation, taskState, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); + return tcs.Task; + } + + public static Task ContinueOnRanToCompletion(this Task task, Action action) { + return task.ContinueWith(t => action(t.Result), TaskContinuationOptions.OnlyOnRanToCompletion); + } + + /// + /// Rethrows task exceptions back to the callers synchronization context if it is possible + /// + /// + /// is always ignored. + /// + public static void DoNotWait(this Task task) { + if (task.IsCompleted) { + ReThrowTaskException(task); + return; + } + + var synchronizationContext = SynchronizationContext.Current; + if (synchronizationContext != null && synchronizationContext.GetType() != typeof (SynchronizationContext)) { + task.ContinueWith(DoNotWaitSynchronizationContextContinuation, synchronizationContext, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); + } else { + task.ContinueWith(DoNotWaitThreadContinuation, TaskContinuationOptions.ExecuteSynchronously); + } + } + + private static void ReThrowTaskException(object state) { + var task = (Task)state; + if (task.IsFaulted && task.Exception != null) { + var exception = task.Exception.InnerException; + ExceptionDispatchInfo.Capture(exception).Throw(); + } + } + + private static void DoNotWaitThreadContinuation(Task task) { + if (task.IsFaulted && task.Exception != null) { + var exception = task.Exception.InnerException; + ThreadPool.QueueUserWorkItem(s => ((ExceptionDispatchInfo)s).Throw(), ExceptionDispatchInfo.Capture(exception)); + } + } + + private static void DoNotWaitSynchronizationContextContinuation(Task task, object state) { + var context = (SynchronizationContext) state; + context.Post(ReThrowTaskException, task); + } + + /// + /// Waits for a task to complete. If an exception occurs, the exception + /// will be raised without being wrapped in a + /// . + /// + public static void WaitAndUnwrapExceptions(this Task task) { + task.GetAwaiter().GetResult(); + } + + /// + /// Waits for a task to complete. If an exception occurs, the exception + /// will be raised without being wrapped in a + /// . + /// + public static T WaitAndUnwrapExceptions(this Task task) { + return task.GetAwaiter().GetResult(); + } + + /// + /// Waits for a task to complete within a given timeout. + /// Returns task result or default(T) if task did not complete + /// within the timeout specified. + /// + public static T WaitTimeout(this Task task, int msTimeout) { + try { + task.Wait(msTimeout); + } catch(AggregateException) { } + + if(!task.IsCompleted) { + // Caller most probably will abandon the task on timeout, + // so make sure all exceptions are observed + task.ContinueWith(t => t.Exception, TaskContinuationOptions.OnlyOnFaulted); + throw new TimeoutException(); + } + return task.WaitAndUnwrapExceptions(); + } + + /// + /// Silently handles the specified exception. + /// + public static Task SilenceException(this Task task) where T : Exception { + var tcs = new TaskCompletionSource(); + task.ContinueWith(SilenceExceptionContinuation, tcs, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); + return tcs.Task; + } + + private static void SilenceExceptionContinuation(Task task, object state) { + var tcs = (TaskCompletionSource)state; + + switch (task.Status) { + case TaskStatus.Faulted: + var unhandledExceptions = task.Exception?.InnerExceptions + .Where(e => !(e is T)) + .ToList(); + + if (unhandledExceptions?.Count == 1) { + tcs.TrySetException(unhandledExceptions[0]); + } else if (unhandledExceptions?.Count > 1) { + tcs.TrySetException(unhandledExceptions); + } else { + tcs.TrySetResult(null); + } + break; + case TaskStatus.Canceled: + tcs.TrySetCanceled(); + break; + case TaskStatus.RanToCompletion: + tcs.TrySetResult(null); + break; + } + } + + public class TimeoutAfterState { + public Timer Timer { get; } + public TaskCompletionSource Tcs { get; } + + public TimeoutAfterState(Timer timer, TaskCompletionSource tcs) { + Timer = timer; + Tcs = tcs; + } + } + } +} diff --git a/Microsoft.Common.Core/IO/DirectoryInfoProxy.cs b/Microsoft.Common.Core/IO/DirectoryInfoProxy.cs new file mode 100644 index 00000000..f498364a --- /dev/null +++ b/Microsoft.Common.Core/IO/DirectoryInfoProxy.cs @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace Microsoft.Common.Core.IO { + internal sealed class DirectoryInfoProxy : IDirectoryInfo { + private readonly DirectoryInfo _directoryInfo; + + public DirectoryInfoProxy(string directoryPath) { + _directoryInfo = new DirectoryInfo(directoryPath); + } + + public DirectoryInfoProxy(DirectoryInfo directoryInfo) { + _directoryInfo = directoryInfo; + } + + public bool Exists => _directoryInfo.Exists; + public string FullName => _directoryInfo.FullName; + public FileAttributes Attributes => _directoryInfo.Attributes; + public IDirectoryInfo Parent => _directoryInfo.Parent != null ? new DirectoryInfoProxy(_directoryInfo.Parent) : null; + + public void Delete() { + _directoryInfo.Delete(); + } + + public IEnumerable EnumerateFileSystemInfos() { + return _directoryInfo + .EnumerateFileSystemInfos() + .Select(CreateFileSystemInfoProxy); + } + + private static IFileSystemInfo CreateFileSystemInfoProxy(FileSystemInfo fileSystemInfo) { + var directoryInfo = fileSystemInfo as DirectoryInfo; + return directoryInfo != null ? (IFileSystemInfo)new DirectoryInfoProxy(directoryInfo) : new FileInfoProxy((FileInfo)fileSystemInfo); + } + } +} \ No newline at end of file diff --git a/Microsoft.Common.Core/IO/FileInfoProxy.cs b/Microsoft.Common.Core/IO/FileInfoProxy.cs new file mode 100644 index 00000000..f7bb7518 --- /dev/null +++ b/Microsoft.Common.Core/IO/FileInfoProxy.cs @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System.IO; + +namespace Microsoft.Common.Core.IO { + internal sealed class FileInfoProxy : IFileInfo { + private readonly FileInfo _fileInfo; + + public FileInfoProxy(FileInfo fileInfo) { + _fileInfo = fileInfo; + } + + public bool Exists => _fileInfo.Exists; + public string FullName => _fileInfo.FullName; + public FileAttributes Attributes => _fileInfo.Attributes; + public IDirectoryInfo Directory => _fileInfo.Directory != null ? new DirectoryInfoProxy(_fileInfo.Directory) : null; + + public StreamWriter CreateText() { + return _fileInfo.CreateText(); + } + + public void Delete() { + _fileInfo.Delete(); + } + } +} \ No newline at end of file diff --git a/Microsoft.Common.Core/IO/FileSystem.cs b/Microsoft.Common.Core/IO/FileSystem.cs new file mode 100644 index 00000000..2a6cea64 --- /dev/null +++ b/Microsoft.Common.Core/IO/FileSystem.cs @@ -0,0 +1,189 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; + +using Microsoft.Extensions.FileSystemGlobbing; + +namespace Microsoft.Common.Core.IO { + public sealed class FileSystem : IFileSystem { + public IFileSystemWatcher CreateFileSystemWatcher(string path, string filter) => new FileSystemWatcherProxy(path, filter); + + public IDirectoryInfo GetDirectoryInfo(string directoryPath) => new DirectoryInfoProxy(directoryPath); + + public bool FileExists(string path) => File.Exists(path); + + public long FileSize(string path) { + var fileInfo = new FileInfo(path); + return fileInfo.Length; + } + + public string ReadAllText(string path) => File.ReadAllText(path); + + public void WriteAllText(string path, string content) => File.WriteAllText(path, content); + + public IEnumerable FileReadAllLines(string path) => File.ReadLines(path); + + public void FileWriteAllLines(string path, IEnumerable contents) => File.WriteAllLines(path, contents); + + public byte[] FileReadAllBytes(string path) => File.ReadAllBytes(path); + + public void FileWriteAllBytes(string path, byte[] bytes) => File.WriteAllBytes(path, bytes); + + public Stream CreateFile(string path) => File.Create(path); + public Stream FileOpen(string path, FileMode mode) => File.Open(path, mode); + + public bool DirectoryExists(string path) => Directory.Exists(path); + + public FileAttributes GetFileAttributes(string path) => File.GetAttributes(path); + + public string ToLongPath(string path) { + var sb = new StringBuilder(NativeMethods.MAX_PATH); + NativeMethods.GetLongPathName(path, sb, sb.Capacity); + return sb.ToString(); + } + + public string ToShortPath(string path) { + var sb = new StringBuilder(NativeMethods.MAX_PATH); + NativeMethods.GetShortPathName(path, sb, sb.Capacity); + return sb.ToString(); + } + + public IFileVersionInfo GetVersionInfo(string path) { + var fvi = System.Diagnostics.FileVersionInfo.GetVersionInfo(path); + return new FileVersionInfo(fvi.FileMajorPart, fvi.FileMinorPart); + } + + public void DeleteFile(string path) => File.Delete(path); + + public void DeleteDirectory(string path, bool recursive) => Directory.Delete(path, recursive); + + public string[] GetFileSystemEntries(string path, string searchPattern, SearchOption options) => Directory.GetFileSystemEntries(path, searchPattern, options); + + public void CreateDirectory(string path) => Directory.CreateDirectory(path); + + public string CompressFile(string path, string relativeTodir) { + string zipFilePath = Path.GetTempFileName(); + using (FileStream zipStream = new FileStream(zipFilePath, FileMode.Create)) + using (ZipArchive archive = new ZipArchive(zipStream, ZipArchiveMode.Create)) { + string entryName = Path.GetFileName(path); + if (!string.IsNullOrWhiteSpace(relativeTodir)) { + entryName = path.MakeRelativePath(relativeTodir).Replace('\\', '/'); + } + archive.CreateEntryFromFile(path, entryName); + } + return zipFilePath; + } + + public string CompressFiles(IEnumerable paths, string relativeTodir, IProgress progress, CancellationToken ct) { + string zipFilePath = Path.GetTempFileName(); + using (FileStream zipStream = new FileStream(zipFilePath, FileMode.Create)) + using (ZipArchive archive = new ZipArchive(zipStream, ZipArchiveMode.Create)) { + foreach(string path in paths) { + string entryName = null; + if (!string.IsNullOrWhiteSpace(relativeTodir)) { + entryName = path.MakeRelativePath(relativeTodir).Replace('\\', '/'); + } else { + entryName = path.MakeRelativePath(Path.GetDirectoryName(path)).Replace('\\', '/'); + } + progress?.Report(path); + archive.CreateEntryFromFile(path, entryName); + } + } + return zipFilePath; + } + + public string CompressDirectory(string path) { + Matcher matcher = new Matcher(StringComparison.OrdinalIgnoreCase); + matcher.AddInclude("*.*"); + return CompressDirectory(path, matcher, new Progress((p) => { }), CancellationToken.None); + } + + public string CompressDirectory(string path, Matcher matcher, IProgress progress, CancellationToken ct) { + string zipFilePath = Path.GetTempFileName(); + using (FileStream zipStream = new FileStream(zipFilePath, FileMode.Create)) + using (ZipArchive archive = new ZipArchive(zipStream, ZipArchiveMode.Create)) { + Queue dirs = new Queue(); + dirs.Enqueue(path); + while (dirs.Count > 0) { + var dir = dirs.Dequeue(); + var subdirs = Directory.GetDirectories(dir); + foreach(var subdir in subdirs) { + dirs.Enqueue(subdir); + } + + var files = matcher.GetResultsInFullPath(dir); + foreach (var file in files) { + if (ct.IsCancellationRequested) { + return string.Empty; + } + progress?.Report(file); + string entryName = file.MakeRelativePath(dir).Replace('\\', '/'); + archive.CreateEntryFromFile(file, entryName); + } + } + } + return zipFilePath; + } + + public string GetDownloadsPath(string fileName) { + if (string.IsNullOrWhiteSpace(fileName)) { + return GetKnownFolderPath(KnownFolderGuids.Downloads); + } else { + return Path.Combine(GetKnownFolderPath(KnownFolderGuids.Downloads), fileName); + } + } + + private string GetKnownFolderPath(string knownFolder) { + IntPtr knownFolderPath; + uint flags = (uint)NativeMethods.KnownFolderflags.KF_FLAG_DEFAULT_PATH; + int result = NativeMethods.SHGetKnownFolderPath(new Guid(knownFolder), flags, IntPtr.Zero, out knownFolderPath); + if (result >= 0) { + return Marshal.PtrToStringUni(knownFolderPath); + } else { + return string.Empty; + } + } + + private static class NativeMethods { + public const int MAX_PATH = 260; + + [Flags] + public enum KnownFolderflags : uint { + KF_FLAG_DEFAULT = 0x00000000, + KF_FLAG_SIMPLE_IDLIST = 0x00000100, + KF_FLAG_NOT_PARENT_RELATIVE = 0x00000200, + KF_FLAG_DEFAULT_PATH = 0x00000400, + KF_FLAG_INIT = 0x00000800, + KF_FLAG_NO_ALIAS = 0x00001000, + KF_FLAG_DONT_UNEXPAND = 0x00002000, + KF_FLAG_DONT_VERIFY = 0x00004000, + KF_FLAG_CREATE = 0x00008000, + KF_FLAG_NO_APPCONTAINER_REDIRECTION = 0x00010000, + KF_FLAG_ALIAS_ONLY = 0x80000000, + } + + [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] + public static extern uint GetLongPathName([MarshalAs(UnmanagedType.LPWStr)] string lpFileName, + [MarshalAs(UnmanagedType.LPWStr)] StringBuilder lpBuffer, + int nBufferLength); + + [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] + public static extern uint GetShortPathName([MarshalAs(UnmanagedType.LPWStr)] string lpFileName, + [MarshalAs(UnmanagedType.LPWStr)] StringBuilder lpBuffer, + int nBufferLength); + + [DllImport("Shell32.dll")] + public static extern int SHGetKnownFolderPath([MarshalAs(UnmanagedType.LPStruct)] Guid rfid, + uint dwFlags, + IntPtr hToken, + out IntPtr ppszPath); + } + } +} \ No newline at end of file diff --git a/Microsoft.Common.Core/IO/FileSystemWatcherProxy.cs b/Microsoft.Common.Core/IO/FileSystemWatcherProxy.cs new file mode 100644 index 00000000..4f2ade20 --- /dev/null +++ b/Microsoft.Common.Core/IO/FileSystemWatcherProxy.cs @@ -0,0 +1,63 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System.IO; + +namespace Microsoft.Common.Core.IO { + internal sealed class FileSystemWatcherProxy : IFileSystemWatcher { + private readonly FileSystemWatcher _fileSystemWatcher; + + public FileSystemWatcherProxy(string path, string filter) { + _fileSystemWatcher = new FileSystemWatcher(path, filter); + } + + public void Dispose() { + _fileSystemWatcher.Dispose(); + } + + public bool EnableRaisingEvents { + get { return _fileSystemWatcher.EnableRaisingEvents; } + set { _fileSystemWatcher.EnableRaisingEvents = value; } + } + + public bool IncludeSubdirectories { + get { return _fileSystemWatcher.IncludeSubdirectories; } + set { _fileSystemWatcher.IncludeSubdirectories = value; } + } + + public int InternalBufferSize { + get { return _fileSystemWatcher.InternalBufferSize; } + set { _fileSystemWatcher.InternalBufferSize = value; } + } + + public NotifyFilters NotifyFilter { + get { return _fileSystemWatcher.NotifyFilter; } + set { _fileSystemWatcher.NotifyFilter = value; } + } + + public event FileSystemEventHandler Changed { + add { _fileSystemWatcher.Changed += value; } + remove { _fileSystemWatcher.Changed -= value; } + } + + public event FileSystemEventHandler Created { + add { _fileSystemWatcher.Created += value; } + remove { _fileSystemWatcher.Created -= value; } + } + + public event FileSystemEventHandler Deleted { + add { _fileSystemWatcher.Deleted += value; } + remove { _fileSystemWatcher.Deleted -= value; } + } + + public event RenamedEventHandler Renamed { + add { _fileSystemWatcher.Renamed += value; } + remove { _fileSystemWatcher.Renamed -= value; } + } + + public event ErrorEventHandler Error { + add { _fileSystemWatcher.Error += value; } + remove { _fileSystemWatcher.Error -= value; } + } + } +} \ No newline at end of file diff --git a/Microsoft.Common.Core/IO/FileVersionInfo.cs b/Microsoft.Common.Core/IO/FileVersionInfo.cs new file mode 100644 index 00000000..d815b09e --- /dev/null +++ b/Microsoft.Common.Core/IO/FileVersionInfo.cs @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +namespace Microsoft.Common.Core.IO { + internal class FileVersionInfo : IFileVersionInfo { + public FileVersionInfo(int major, int minor) { + FileMajorPart = major; + FileMinorPart = minor; + } + public int FileMajorPart { get; } + + public int FileMinorPart { get; } + } +} diff --git a/Microsoft.Common.Core/IO/IDirectoryInfo.cs b/Microsoft.Common.Core/IO/IDirectoryInfo.cs new file mode 100644 index 00000000..a4b82e41 --- /dev/null +++ b/Microsoft.Common.Core/IO/IDirectoryInfo.cs @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System.Collections.Generic; + +namespace Microsoft.Common.Core.IO { + public interface IDirectoryInfo : IFileSystemInfo { + IDirectoryInfo Parent { get; } + IEnumerable EnumerateFileSystemInfos(); + } +} \ No newline at end of file diff --git a/Microsoft.Common.Core/IO/IFileInfo.cs b/Microsoft.Common.Core/IO/IFileInfo.cs new file mode 100644 index 00000000..26e5c837 --- /dev/null +++ b/Microsoft.Common.Core/IO/IFileInfo.cs @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System.IO; + +namespace Microsoft.Common.Core.IO { + public interface IFileInfo : IFileSystemInfo { + IDirectoryInfo Directory { get; } + StreamWriter CreateText(); + } +} \ No newline at end of file diff --git a/Microsoft.Common.Core/IO/IFileSystem.cs b/Microsoft.Common.Core/IO/IFileSystem.cs new file mode 100644 index 00000000..f7e3dfc6 --- /dev/null +++ b/Microsoft.Common.Core/IO/IFileSystem.cs @@ -0,0 +1,48 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using Microsoft.Extensions.FileSystemGlobbing; + +namespace Microsoft.Common.Core.IO { + public interface IFileSystem { + IFileSystemWatcher CreateFileSystemWatcher(string directory, string filter); + IDirectoryInfo GetDirectoryInfo(string directoryPath); + bool FileExists(string fullPath); + bool DirectoryExists(string fullPath); + + long FileSize(string path); + + FileAttributes GetFileAttributes(string fullPath); + string ToLongPath(string path); + string ToShortPath(string path); + + string ReadAllText(string path); + void WriteAllText(string path, string content); + + IEnumerable FileReadAllLines(string path); + void FileWriteAllLines(string path, IEnumerable contents); + + byte[] FileReadAllBytes(string path); + void FileWriteAllBytes(string path, byte[] bytes); + + Stream CreateFile(string path); + Stream FileOpen(string path, FileMode mode); + + IFileVersionInfo GetVersionInfo(string path); + void DeleteFile(string path); + void DeleteDirectory(string path, bool recursive); + string[] GetFileSystemEntries(string path, string searchPattern, SearchOption options); + void CreateDirectory(string path); + + string GetDownloadsPath(string fileName = ""); + + string CompressFile(string path, string relativeTodir = null); + string CompressFiles(IEnumerable paths, string relativeToDir, IProgress progress, CancellationToken ct); + string CompressDirectory(string path); + string CompressDirectory(string path, Matcher matcher, IProgress progress, CancellationToken ct); + } +} diff --git a/Microsoft.Common.Core/IO/IFileSystemInfo.cs b/Microsoft.Common.Core/IO/IFileSystemInfo.cs new file mode 100644 index 00000000..1ddc1721 --- /dev/null +++ b/Microsoft.Common.Core/IO/IFileSystemInfo.cs @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System.IO; + +namespace Microsoft.Common.Core.IO { + public interface IFileSystemInfo { + bool Exists { get; } + string FullName { get; } + FileAttributes Attributes { get; } + + void Delete(); + } +} \ No newline at end of file diff --git a/Microsoft.Common.Core/IO/IFileSystemWatcher.cs b/Microsoft.Common.Core/IO/IFileSystemWatcher.cs new file mode 100644 index 00000000..df6ba208 --- /dev/null +++ b/Microsoft.Common.Core/IO/IFileSystemWatcher.cs @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.IO; + +namespace Microsoft.Common.Core.IO { + public interface IFileSystemWatcher : IDisposable { + bool EnableRaisingEvents { get; set; } + bool IncludeSubdirectories { get; set; } + int InternalBufferSize { get; set; } + NotifyFilters NotifyFilter { get; set; } + + event FileSystemEventHandler Changed; + event FileSystemEventHandler Created; + event FileSystemEventHandler Deleted; + event RenamedEventHandler Renamed; + event ErrorEventHandler Error; + } +} \ No newline at end of file diff --git a/Microsoft.Common.Core/IO/IFileVersionInfo.cs b/Microsoft.Common.Core/IO/IFileVersionInfo.cs new file mode 100644 index 00000000..6e8682c4 --- /dev/null +++ b/Microsoft.Common.Core/IO/IFileVersionInfo.cs @@ -0,0 +1,9 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +namespace Microsoft.Common.Core.IO { + public interface IFileVersionInfo { + int FileMajorPart { get; } + int FileMinorPart { get; } + } +} diff --git a/Microsoft.Common.Core/IO/KnownFolderGuids.cs b/Microsoft.Common.Core/IO/KnownFolderGuids.cs new file mode 100644 index 00000000..ab6436a4 --- /dev/null +++ b/Microsoft.Common.Core/IO/KnownFolderGuids.cs @@ -0,0 +1,98 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Microsoft.Common.Core.IO { + internal class KnownFolderGuids { + public const string AddNewPrograms = "{DE61D971-5EBC-4F02-A3A9-6C82895E5C04}"; + public const string AdminTools = "{724EF170-A42D-4FEF-9F26-B60E846FBA4F}"; + public const string AppDataLow = "{A520A1A4-1780-4FF6-BD18-167343C5AF16}"; + public const string AppUpdates = "{A305CE99-F527-492B-8B1A-7E76FA98D6E4}"; + public const string CDBurning = "{9E52AB10-F80D-49DF-ACB8-4330F5687855}"; + public const string ChangeRemovePrograms = "{DF7266AC-9274-4867-8D55-3BD661DE872D}"; + public const string CommonAdminTools = "{D0384E7D-BAC3-4797-8F14-CBA229B392B5}"; + public const string CommonOEMLinks = "{C1BAE2D0-10DF-4334-BEDD-7AA20B227A9D}"; + public const string CommonPrograms = "{0139D44E-6AFE-49F2-8690-3DAFCAE6FFB8}"; + public const string CommonStartMenu = "{A4115719-D62E-491D-AA7C-E74B8BE3B067}"; + public const string CommonStartup = "{82A5EA35-D9CD-47C5-9629-E15D2F714E6E}"; + public const string CommonTemplates = "{B94237E7-57AC-4347-9151-B08C6C32D1F7}"; + public const string Computer = "{0AC0837C-BBF8-452A-850D-79D08E667CA7}"; + public const string Conflict = "{4BFEFB45-347D-4006-A5BE-AC0CB0567192}"; + public const string Connections = "{6F0CD92B-2E97-45D1-88FF-B0D186B8DEDD}"; + public const string Contacts = "{56784854-C6CB-462B-8169-88E350ACB882}"; + public const string ControlPanel = "{82A74AEB-AEB4-465C-A014-D097EE346D63}"; + public const string Cookies = "{2B0F765D-C0E9-4171-908E-08A611B84FF6}"; + public const string Desktop = "{B4BFCC3A-DB2C-424C-B029-7FE99A87C641}"; + public const string Documents = "{FDD39AD0-238F-46AF-ADB4-6C85480369C7}"; + public const string Downloads = "{374DE290-123F-4565-9164-39C4925E467B}"; + public const string Favorites = "{1777F761-68AD-4D8A-87BD-30B759FA33DD}"; + public const string Fonts = "{FD228CB7-AE11-4AE3-864C-16F3910AB8FE}"; + public const string Games = "{CAC52C1A-B53D-4EDC-92D7-6B2E8AC19434}"; + public const string GameTasks = "{054FAE61-4DD8-4787-80B6-090220C4B700}"; + public const string History = "{D9DC8A3B-B784-432E-A781-5A1130A75963}"; + public const string Internet = "{4D9F7874-4E0C-4904-967B-40B0D20C3E4B}"; + public const string InternetCache = "{352481E8-33BE-4251-BA85-6007CAEDCF9D}"; + public const string Links = "{BFB9D5E0-C6A9-404C-B2B2-AE6DB6AF4968}"; + public const string LocalAppData = "{F1B32785-6FBA-4FCF-9D55-7B8E7F157091}"; + public const string LocalizedResourcesDir = "{2A00375E-224C-49DE-B8D1-440DF7EF3DDC}"; + public const string Music = "{4BD8D571-6D19-48D3-BE97-422220080E43}"; + public const string NetHood = "{C5ABBF53-E17F-4121-8900-86626FC2C973}"; + public const string Network = "{D20BEEC4-5CA8-4905-AE3B-BF251EA09B53}"; + public const string OriginalImages = "{2C36C0AA-5812-4B87-BFD0-4CD0DFB19B39}"; + public const string PhotoAlbums = "{69D2CF90-FC33-4FB7-9A0C-EBB0F0FCB43C}"; + public const string Pictures = "{33E28130-4E1E-4676-835A-98395C3BC3BB}"; + public const string Playlists = "{DE92C1C7-837F-4F69-A3BB-86E631204A23}"; + public const string Printers = "{76FC4E2D-D6AD-4519-A663-37BD56068185}"; + public const string PrintHood = "{9274BD8D-CFD1-41C3-B35E-B13F55A758F4}"; + public const string Profile = "{5E6C858F-0E22-4760-9AFE-EA3317B67173}"; + public const string ProgramData = "{62AB5D82-FDC1-4DC3-A9DD-070D1D495D97}"; + public const string ProgramFiles = "{905E63B6-C1BF-494E-B29C-65B732D3D21A}"; + public const string ProgramFilesCommon = "{F7F1ED05-9F6D-47A2-AAAE-29D317C6F066}"; + public const string ProgramFilesCommonX64 = "{6365D5A7-0F0D-45E5-87F6-0DA56B6A4F7D}"; + public const string ProgramFilesCommonX86 = "{DE974D24-D9C6-4D3E-BF91-F4455120B917}"; + public const string ProgramFilesX64 = "{6D809377-6AF0-444B-8957-A3773F02200E}"; + public const string ProgramFilesX86 = "{7C5A40EF-A0FB-4BFC-874A-C0F2E0B9FA8E}"; + public const string Programs = "{A77F5D77-2E2B-44C3-A6A2-ABA601054A51}"; + public const string Public = "{DFDF76A2-C82A-4D63-906A-5644AC457385}"; + public const string PublicDesktop = "{C4AA340D-F20F-4863-AFEF-F87EF2E6BA25}"; + public const string PublicDocuments = "{ED4824AF-DCE4-45A8-81E2-FC7965083634}"; + public const string PublicDownloads = "{3D644C9B-1FB8-4F30-9B45-F670235F79C0}"; + public const string PublicGameTasks = "{DEBF2536-E1A8-4C59-B6A2-414586476AEA}"; + public const string PublicMusic = "{3214FAB5-9757-4298-BB61-92A9DEAA44FF}"; + public const string PublicPictures = "{B6EBFB86-6907-413C-9AF7-4FC2ABF07CC5}"; + public const string PublicVideos = "{2400183A-6185-49FB-A2D8-4A392A602BA3}"; + public const string QuickLaunch = "{52A4F021-7B75-48A9-9F6B-4B87A210BC8F}"; + public const string Recent = "{AE50C081-EBD2-438A-8655-8A092E34987A}"; + public const string RecordedTV = "{BD85E001-112E-431E-983B-7B15AC09FFF1}"; + public const string RecycleBin = "{B7534046-3ECB-4C18-BE4E-64CD4CB7D6AC}"; + public const string ResourceDir = "{8AD10C31-2ADB-4296-A8F7-E4701232C972}"; + public const string RoamingAppData = "{3EB685DB-65F9-4CF6-A03A-E3EF65729F3D}"; + public const string SampleMusic = "{B250C668-F57D-4EE1-A63C-290EE7D1AA1F}"; + public const string SamplePictures = "{C4900540-2379-4C75-844B-64E6FAF8716B}"; + public const string SamplePlaylists = "{15CA69B3-30EE-49C1-ACE1-6B5EC372AFB5}"; + public const string SampleVideos = "{859EAD94-2E85-48AD-A71A-0969CB56A6CD}"; + public const string SavedGames = "{4C5C32FF-BB9D-43B0-B5B4-2D72E54EAAA4}"; + public const string SavedSearches = "{7D1D3A04-DEBB-4115-95CF-2F29DA2920DA}"; + public const string SEARCH_CSC = "{EE32E446-31CA-4ABA-814F-A5EBD2FD6D5E}"; + public const string SEARCH_MAPI = "{98EC0E18-2098-4D44-8644-66979315A281}"; + public const string SearchHome = "{190337D1-B8CA-4121-A639-6D472D16972A}"; + public const string SendTo = "{8983036C-27C0-404B-8F08-102D10DCFD74}"; + public const string SidebarDefaultParts = "{7B396E54-9EC5-4300-BE0A-2482EBAE1A26}"; + public const string SidebarParts = "{A75D362E-50FC-4FB7-AC2C-A8BEAA314493}"; + public const string StartMenu = "{625B53C3-AB48-4EC1-BA1F-A1EF4146FC19}"; + public const string Startup = "{B97D20BB-F46A-4C97-BA10-5E3608430854}"; + public const string SyncManager = "{43668BF8-C14E-49B2-97C9-747784D784B7}"; + public const string SyncResults = "{289A9A43-BE44-4057-A41B-587A76D7E7F9}"; + public const string SyncSetup = "{0F214138-B1D3-4A90-BBA9-27CBC0C5389A}"; + public const string System = "{1AC14E77-02E7-4E5D-B744-2EB1AE5198B7}"; + public const string SystemX86 = "{D65231B0-B2F1-4857-A4CE-A8E7C6EA7D27}"; + public const string Templates = "{A63293E8-664E-48DB-A079-DF759E0509F7}"; + public const string TreeProperties = "{5B3749AD-B49F-49C1-83EB-15370FBD4882}"; + public const string UserProfiles = "{0762D272-C50A-4BB0-A382-697DCD729B80}"; + public const string UsersFiles = "{F3CE0F7C-4901-4ACC-8648-D5D44B04EF8F}"; + public const string Videos = "{18989B1D-99B5-455B-841C-AB7C74E4DDFC}"; + public const string Windows = "{F38BF404-1D43-42F2-9305-67DE0B28FC23}"; + } +} diff --git a/Microsoft.Common.Core/Key.snk b/Microsoft.Common.Core/Key.snk new file mode 100644 index 00000000..a77912ae Binary files /dev/null and b/Microsoft.Common.Core/Key.snk differ diff --git a/Microsoft.Common.Core/Lazy.cs b/Microsoft.Common.Core/Lazy.cs new file mode 100644 index 00000000..56f3f792 --- /dev/null +++ b/Microsoft.Common.Core/Lazy.cs @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.Threading; + +namespace Microsoft.Common.Core { + public static class Lazy { + public static Lazy Create(Func valueFactory) { + return new Lazy(valueFactory); + } + + public static Lazy Create(Func valueFactory, bool isThreadSafe) { + return new Lazy(valueFactory, isThreadSafe); + } + + public static Lazy Create(Func valueFactory, LazyThreadSafetyMode mode) { + return new Lazy(valueFactory, mode); + } + } +} diff --git a/Microsoft.Common.Core/Logging/IActionLog.cs b/Microsoft.Common.Core/Logging/IActionLog.cs new file mode 100644 index 00000000..e9f652fd --- /dev/null +++ b/Microsoft.Common.Core/Logging/IActionLog.cs @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System.Threading.Tasks; + +namespace Microsoft.Common.Core.Logging { + /// + /// Represents action logger. Log can be a text file, + /// an application output window or telemetry. + /// + public interface IActionLog { + Task WriteAsync(LogVerbosity verbosity, MessageCategory category, string message); + Task WriteFormatAsync(LogVerbosity verbosity, MessageCategory category, string format, params object[] arguments); + Task WriteLineAsync(LogVerbosity verbosity, MessageCategory category, string message); + void Flush(); + LogVerbosity LogVerbosity { get; } + } +} diff --git a/Microsoft.Common.Core/Logging/IActionLogWriter.cs b/Microsoft.Common.Core/Logging/IActionLogWriter.cs new file mode 100644 index 00000000..c3d6ca17 --- /dev/null +++ b/Microsoft.Common.Core/Logging/IActionLogWriter.cs @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System.Threading.Tasks; + +namespace Microsoft.Common.Core.Logging { + public interface IActionLogWriter { + Task WriteAsync(MessageCategory category, string message); + void Flush(); + } +} \ No newline at end of file diff --git a/Microsoft.Common.Core/Logging/ILoggerProvider.cs b/Microsoft.Common.Core/Logging/ILoggerProvider.cs new file mode 100644 index 00000000..240c4b33 --- /dev/null +++ b/Microsoft.Common.Core/Logging/ILoggerProvider.cs @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; + +namespace Microsoft.Common.Core.Logging { + public interface ILoggingServices: IDisposable { + ILoggingPermissions Permissions { get; } + IActionLog GetOrCreateLog(string appName); + } +} diff --git a/Microsoft.Common.Core/Logging/ILoggingPermissions.cs b/Microsoft.Common.Core/Logging/ILoggingPermissions.cs new file mode 100644 index 00000000..7fac3beb --- /dev/null +++ b/Microsoft.Common.Core/Logging/ILoggingPermissions.cs @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +namespace Microsoft.Common.Core.Logging { + public interface ILoggingPermissions { + /// + /// Defines maximum allowable logging level. + /// + LogVerbosity MaxVerbosity { get; } + + /// + /// Is user permitted to send feedback + /// + bool IsFeedbackPermitted { get; } + + /// + /// Currently set logging level (usually via Tools | Options). + /// Cannot exceeed maximum level. + /// + LogVerbosity CurrentVerbosity { get; set; } + } +} diff --git a/Microsoft.Common.Core/Logging/Implementation/FileLogWriter.cs b/Microsoft.Common.Core/Logging/Implementation/FileLogWriter.cs new file mode 100644 index 00000000..d37d7b4b --- /dev/null +++ b/Microsoft.Common.Core/Logging/Implementation/FileLogWriter.cs @@ -0,0 +1,113 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.Collections.Concurrent; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Threading.Tasks.Dataflow; +using static System.FormattableString; + +namespace Microsoft.Common.Core.Logging { + internal sealed class FileLogWriter : IActionLogWriter { + private const int _maxTimeout = 5000; + private const int _maxBufferSize = 1024; + private static readonly ConcurrentDictionary _writers = new ConcurrentDictionary(); + private readonly char[] _lineBreaks = { '\n' }; + private readonly string _filePath; + private readonly ActionBlock _messages; + private readonly StringBuilder _sb = new StringBuilder(); + private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1); + + private FileLogWriter(string filePath) { + _filePath = filePath; + _messages = new ActionBlock(new Func(WriteToFile)); + + AppDomain.CurrentDomain.ProcessExit += OnProcessExit; + AppDomain.CurrentDomain.UnhandledException += OnUnhandledException; + } + + private async Task WriteToFile(string message) { + try { + await WriteBuffer(message, flush: false); + } catch (UnauthorizedAccessException ex) { + Trace.Fail(ex.ToString()); + } catch (PathTooLongException ex) { + Trace.Fail(ex.ToString()); + } catch (DirectoryNotFoundException ex) { + Trace.Fail(ex.ToString()); + } catch (NotSupportedException ex) { + Trace.Fail(ex.ToString()); + } catch (IOException ex) { + Trace.Fail(ex.ToString()); + } + } + + private void OnUnhandledException(object sender, UnhandledExceptionEventArgs e) { + WriteBuffer(string.Empty, flush: true).Wait(_maxTimeout); + } + + private void OnProcessExit(object sender, EventArgs e) { + WriteBuffer(string.Empty, flush: true).Wait(_maxTimeout); + } + + private async Task WriteBuffer(string message, bool flush) { + await _semaphore.WaitAsync(); + try { + _sb.Append(message); + if (_sb.Length > _maxBufferSize || flush) { + using (var stream = File.AppendText(_filePath)) { + await stream.WriteAsync(_sb.ToString()); + } + _sb.Clear(); + } + } finally { + _semaphore.Release(); + } + } + + public Task WriteAsync(MessageCategory category, string message) { + return _messages.SendAsync(GetStringToWrite(category, message)); + } + + public void Flush() { + WriteBuffer(string.Empty, flush: true).Wait(_maxTimeout); + } + + + private string GetStringToWrite(MessageCategory category, string message) { + var categoryString = GetCategoryString(category); + var prefix = Invariant($"[{DateTime.Now:yy-M-dd_HH-mm-ss}]{categoryString}:"); + if (!message.Take(message.Length - 1).Contains('\n')) { + return prefix + message; + } + + var emptyPrefix = new string(' ', prefix.Length); + var lines = message.Split(_lineBreaks, StringSplitOptions.RemoveEmptyEntries) + .Select((line, i) => i == 0 ? prefix + line + "\n" : emptyPrefix + line + "\n"); + return string.Concat(lines); + } + + public static FileLogWriter InTempFolder(string fileName) { + return _writers.GetOrAdd(fileName, _ => { + var path = Path.Combine(Path.GetTempPath(), Invariant($@"{fileName}_{DateTime.Now:yyyyMdd_HHmmss}_pid{Process.GetCurrentProcess().Id}.log")); + return new FileLogWriter(path); + }); + } + + private static string GetCategoryString(MessageCategory category) { + switch (category) { + case MessageCategory.Error: + return "[ERROR]"; + case MessageCategory.Warning: + return "[WARNING]"; + default: + return string.Empty; + } + } + } +} \ No newline at end of file diff --git a/Microsoft.Common.Core/Logging/Implementation/LoggingPermissions.cs b/Microsoft.Common.Core/Logging/Implementation/LoggingPermissions.cs new file mode 100644 index 00000000..3588e5b9 --- /dev/null +++ b/Microsoft.Common.Core/Logging/Implementation/LoggingPermissions.cs @@ -0,0 +1,102 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.ComponentModel.Composition; +using Microsoft.Common.Core.Extensions; +using Microsoft.Common.Core.OS; +using Microsoft.Common.Core.Shell; +using Microsoft.Common.Core.Telemetry; +using Microsoft.Win32; + +namespace Microsoft.Common.Core.Logging { + /// + /// Determines logging permissions depending on the current + /// telemetry settings and registry keys. + /// + /// + /// Rules: + /// a. Feedback and logging is permitted if telemetry is enabled. If telemetry is off, + /// admin can selectively enable feedback and logging in registry under HKLM. + /// b. If telemetry is on, default logging level is 'Normal'. This allows recording of all events + /// but security and privacy related data such as cross-process traffic or commands and data + /// in the interactive window. + /// c. Admin can limit level of logging and disable feedback sending even if app telemetry is on. + /// + [Export(typeof(ILoggingPermissions))] + internal sealed class LoggingPermissions : ILoggingPermissions { + internal const string LogVerbosityValueName = "LogVerbosity"; + internal const string FeedbackValueName = "Feedback"; + + private readonly IApplicationConstants _appConstants; + private readonly ITelemetryService _telemetryService; + private readonly IRegistry _registry; + + private LogVerbosity _currentVerbosity; + private LogVerbosity? _registryVerbosity; + private int? _registryFeedbackSetting; + + [ImportingConstructor] + public LoggingPermissions(IApplicationConstants appConstants, ITelemetryService telemetryService, [Import(AllowDefault = true)] IRegistry registry) { + _appConstants = appConstants; + _telemetryService = telemetryService; + _registry = registry ?? new RegistryImpl(); + + _registryVerbosity = GetLogLevelFromRegistry(); + _registryFeedbackSetting = GetFeedbackFromRegistry(); + } + + public LogVerbosity CurrentVerbosity { + get { return _currentVerbosity; } + set { _currentVerbosity = MathExtensions.Min(value, MaxVerbosity); } + } + + public LogVerbosity MaxVerbosity => GetEffectiveVerbosity(); + + public bool IsFeedbackPermitted => GetEffectiveFeedbackSetting(); + + private LogVerbosity GetEffectiveVerbosity() { + LogVerbosity adminSetValue; + if (_telemetryService.IsEnabled) { + adminSetValue = _registryVerbosity.HasValue ? _registryVerbosity.Value : LogVerbosity.Traffic; + return MathExtensions.Min(adminSetValue, LogVerbosity.Traffic); + } + // If telemetry is disabled, registry setting allows increase in the logging level. + adminSetValue = _registryVerbosity.HasValue ? _registryVerbosity.Value : LogVerbosity.None; + return MathExtensions.Max(_registryVerbosity.HasValue ? _registryVerbosity.Value : LogVerbosity.None, LogVerbosity.Minimal); + } + + private bool GetEffectiveFeedbackSetting() { + int adminSetValue; + if (_telemetryService.IsEnabled) { + adminSetValue = _registryFeedbackSetting.HasValue ? _registryFeedbackSetting.Value : 1; + return MathExtensions.Min(adminSetValue, 1) == 1; + } + // If telemetry is disabled, registry setting allows enabling the feedback. + adminSetValue = _registryFeedbackSetting.HasValue ? _registryFeedbackSetting.Value : 0; + return MathExtensions.Max(adminSetValue, 0) == 1; + } + + private LogVerbosity? GetLogLevelFromRegistry() { + return (LogVerbosity?)GetValueFromRegistry(LogVerbosityValueName, (int)LogVerbosity.None, (int)LogVerbosity.Traffic); + } + + private int? GetFeedbackFromRegistry() { + return GetValueFromRegistry(FeedbackValueName, 0, 1); + } + + private int? GetValueFromRegistry(string name, int minValue, int maxValue) { + using (var hlkm = _registry.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32)) { + try { + using (var key = hlkm.OpenSubKey(_appConstants.LocalMachineHive)) { + var value = (int?)key.GetValue(name); + if (value.HasValue && value.Value >= minValue && value.Value <= maxValue) { + return value; + } + } + } catch (Exception) { } + } + return null; + } + } +} diff --git a/Microsoft.Common.Core/Logging/Implementation/LoggingServices.cs b/Microsoft.Common.Core/Logging/Implementation/LoggingServices.cs new file mode 100644 index 00000000..94174bba --- /dev/null +++ b/Microsoft.Common.Core/Logging/Implementation/LoggingServices.cs @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System.ComponentModel.Composition; +using System.Threading; +using Microsoft.Common.Core.Shell; + +namespace Microsoft.Common.Core.Logging.Implementation { + internal sealed class LoggingServices : ILoggingServices { + private static Logger _instance; + private readonly IApplicationConstants _appConstants; + + public LoggingServices(ILoggingPermissions permissions, IApplicationConstants appConstants) { + Permissions = permissions; + _appConstants = appConstants; + } + + public ILoggingPermissions Permissions { get; } + + public IActionLog GetOrCreateLog(string appName) { + if (_instance == null) { + var instance = new Logger(_appConstants.ApplicationName, Permissions, writer: null); + Interlocked.CompareExchange(ref _instance, instance, null); + } + return _instance; + } + + public void Dispose() { + _instance?.Dispose(); + } + } +} diff --git a/Microsoft.Common.Core/Logging/Implementation/NullLogWriter.cs b/Microsoft.Common.Core/Logging/Implementation/NullLogWriter.cs new file mode 100644 index 00000000..40891bc2 --- /dev/null +++ b/Microsoft.Common.Core/Logging/Implementation/NullLogWriter.cs @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System.Threading.Tasks; + +namespace Microsoft.Common.Core.Logging { + internal sealed class NullLogWriter : IActionLogWriter { + public static IActionLogWriter Instance { get; } = new NullLogWriter(); + + private NullLogWriter() { } + public Task WriteAsync(MessageCategory category, string message) => Task.CompletedTask; + public void Flush() { } + } +} \ No newline at end of file diff --git a/Microsoft.Common.Core/Logging/LogVerbosity.cs b/Microsoft.Common.Core/Logging/LogVerbosity.cs new file mode 100644 index 00000000..8bcacda0 --- /dev/null +++ b/Microsoft.Common.Core/Logging/LogVerbosity.cs @@ -0,0 +1,37 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +namespace Microsoft.Common.Core.Logging { + /// + /// Defines verbosity of logging the application performs + /// + public enum LogVerbosity { + /// + /// Logging is completely off + /// + None, + + /// + /// Limited set of events is recorded in the OS events log such as + /// application processes lifetime, version of R and tools, success + /// and failure connecting to remote machines. + /// + Minimal, + + /// + /// In addition to the events recorded in the OS Application log + /// a log file is created in the TEMP folder. The log file receives + /// additional information on the internal events which may come + /// useful in case of troubleshooting connections or the product + /// installation. + /// + Normal, + + /// + /// Application creates additional log file that receive complete traffic + /// between host the and tools (Visual Studio) processes. The traffic + /// log may contain private data and other private information. + /// + Traffic + } +} diff --git a/Microsoft.Common.Core/Logging/Logger.cs b/Microsoft.Common.Core/Logging/Logger.cs new file mode 100644 index 00000000..ea703f38 --- /dev/null +++ b/Microsoft.Common.Core/Logging/Logger.cs @@ -0,0 +1,90 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.Globalization; +using System.Threading.Tasks; +using Microsoft.Common.Core.Threading; + +namespace Microsoft.Common.Core.Logging { + /// + /// Application event logger + /// + internal sealed class Logger : IActionLog, IDisposable { + private IActionLogWriter[] _logs; + private readonly ILoggingPermissions _permissions; + private readonly string _appName; + private readonly IActionLogWriter _writer; + private readonly BinaryAsyncLock _initializationLock = new BinaryAsyncLock(); + + public void Dispose() { + if (_logs != null) { + foreach (var log in _logs) { + (log as IDisposable)?.Dispose(); + } + } + } + + internal Logger(string appName, ILoggingPermissions permissions, IActionLogWriter writer) { + _appName = appName; + _permissions = permissions; + _writer = writer; + } + + private async Task EnsureCreatedAsync() { + var token = await _initializationLock.WaitAsync(); + try { + if (!token.IsSet) { + // Delay-create log since permission is established when settings are loaded + // which may happen after ctor is called. + _logs = new IActionLogWriter[Enum.GetValues(typeof(LogVerbosity)).Length]; + _logs[(int)LogVerbosity.None] = NullLogWriter.Instance; + + IActionLogWriter mainWriter = NullLogWriter.Instance; + if (_permissions.CurrentVerbosity >= LogVerbosity.Minimal) { + mainWriter = _writer ?? FileLogWriter.InTempFolder(_appName); + } + + // Unfortunately, creation of event sources in OS logs requires local admin rights. + // http://www.christiano.ch/wordpress/2009/12/02/iis7-web-application-writing-to-event-log-generates-security-exception/ + // So we can't use OS event logs as in Dev15 there is no MSI which could elevate.. + // _maxLogLevel >= LogLevel.Minimal ? (_writer ?? new ApplicationLogWriter(_appName)) : NullLogWriter.Instance; + _logs[(int)LogVerbosity.Minimal] = mainWriter; + _logs[(int)LogVerbosity.Normal] = _permissions.CurrentVerbosity >= LogVerbosity.Normal ? mainWriter : NullLogWriter.Instance; + + if (_permissions.CurrentVerbosity == LogVerbosity.Traffic) { + _logs[(int)LogVerbosity.Traffic] = _writer ?? FileLogWriter.InTempFolder(_appName + ".traffic"); + } else { + _logs[(int)LogVerbosity.Traffic] = NullLogWriter.Instance; + } + } + } finally { + token.Set(); + } + } + + #region IActionLog + public async Task WriteAsync(LogVerbosity verbosity, MessageCategory category, string message) { + await EnsureCreatedAsync(); + await _logs[(int)verbosity].WriteAsync(category, message); + } + public async Task WriteFormatAsync(LogVerbosity verbosity, MessageCategory category, string format, params object[] arguments) { + await EnsureCreatedAsync(); + string message = string.Format(CultureInfo.InvariantCulture, format, arguments); + await _logs[(int)verbosity].WriteAsync(category, message); + } + public async Task WriteLineAsync(LogVerbosity verbosity, MessageCategory category, string message) { + await EnsureCreatedAsync(); + await _logs[(int)verbosity].WriteAsync(category, message + Environment.NewLine); + } + + public void Flush() { + foreach (var l in _logs) { + l?.Flush(); + } + } + + public LogVerbosity LogVerbosity => _permissions.CurrentVerbosity; + #endregion + } +} diff --git a/Microsoft.Common.Core/Logging/MessageCategory.cs b/Microsoft.Common.Core/Logging/MessageCategory.cs new file mode 100644 index 00000000..5d8167d5 --- /dev/null +++ b/Microsoft.Common.Core/Logging/MessageCategory.cs @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +namespace Microsoft.Common.Core.Logging { + /// + /// Log message category + /// + public enum MessageCategory { + /// + /// General informational message + /// + General, + + /// + /// A warning message + /// + Warning, + + /// + /// An error message + /// + Error + } +} diff --git a/Microsoft.Common.Core/Microsoft.Common.Core.csproj b/Microsoft.Common.Core/Microsoft.Common.Core.csproj new file mode 100644 index 00000000..24f73be2 --- /dev/null +++ b/Microsoft.Common.Core/Microsoft.Common.Core.csproj @@ -0,0 +1,171 @@ + + + + + Debug + AnyCPU + {5DA4C00B-9F16-4EF9-894D-20329544265E} + Library + Properties + Microsoft.Common.Core + Microsoft.Common.Core + v4.6 + 512 + + + + true + full + false + bin\Debug\ + TRACE;DEBUG;VS14 + prompt + 4 + true + + + pdbonly + true + bin\Release\ + TRACE;VS14 + prompt + 4 + true + + + true + + + Key.snk + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Microsoft.Common.Core/Microsoft.Common.Core.nuget.props b/Microsoft.Common.Core/Microsoft.Common.Core.nuget.props new file mode 100644 index 00000000..bbc139e2 --- /dev/null +++ b/Microsoft.Common.Core/Microsoft.Common.Core.nuget.props @@ -0,0 +1,9 @@ + + + + $(UserProfile)\.nuget\packages\ + + + + + \ No newline at end of file diff --git a/Microsoft.Common.Core/Microsoft.Common.Core.nuget.targets b/Microsoft.Common.Core/Microsoft.Common.Core.nuget.targets new file mode 100644 index 00000000..fba27696 --- /dev/null +++ b/Microsoft.Common.Core/Microsoft.Common.Core.nuget.targets @@ -0,0 +1,9 @@ + + + + $(UserProfile)\.nuget\packages\ + + + + + \ No newline at end of file diff --git a/Microsoft.Common.Core/NativeMethods.cs b/Microsoft.Common.Core/NativeMethods.cs new file mode 100644 index 00000000..3e004d70 --- /dev/null +++ b/Microsoft.Common.Core/NativeMethods.cs @@ -0,0 +1,70 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.Runtime.InteropServices; +using System.Text; + +namespace Microsoft.Common.Core { + internal static unsafe class NativeMethods { + public const uint FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100; + public const uint FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200; + public const uint FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000; + public const uint FORMAT_MESSAGE_ARGUMENT_ARRAY = 0x00002000; + public const uint FORMAT_MESSAGE_FROM_HMODULE = 0x00000800; + public const uint FORMAT_MESSAGE_FROM_STRING = 0x00000400; + + [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] + public static extern uint FormatMessage(uint dwFlags, IntPtr lpSource, int dwMessageId, + uint dwLanguageId, ref IntPtr lpBuffer, uint nSize, IntPtr pArguments); + + [DllImport("ntdll.dll")] + public static extern int RtlNtStatusToDosError(int Status); + + + public const int CRED_MAX_USERNAME_LENGTH = 513; + public const int CRED_MAX_CREDENTIAL_BLOB_SIZE = 512; + public const int CREDUI_MAX_USERNAME_LENGTH = CRED_MAX_USERNAME_LENGTH; + public const int CREDUI_MAX_PASSWORD_LENGTH = (CRED_MAX_CREDENTIAL_BLOB_SIZE / 2); + + public const int CREDUI_FLAGS_INCORRECT_PASSWORD = 0x1; + public const int CREDUI_FLAGS_DO_NOT_PERSIST = 0x2; + public const int CREDUI_FLAGS_REQUEST_ADMINISTRATOR = 0x4; + public const int CREDUI_FLAGS_EXCLUDE_CERTIFICATES = 0x8; + public const int CREDUI_FLAGS_REQUIRE_CERTIFICATE = 0x10; + public const int CREDUI_FLAGS_SHOW_SAVE_CHECK_BOX = 0x40; + public const int CREDUI_FLAGS_ALWAYS_SHOW_UI = 0x80; + public const int CREDUI_FLAGS_REQUIRE_SMARTCARD = 0x100; + public const int CREDUI_FLAGS_PASSWORD_ONLY_OK = 0x200; + public const int CREDUI_FLAGS_VALIDATE_USERNAME = 0x400; + public const int CREDUI_FLAGS_COMPLETE_USERNAME = 0x800; + public const int CREDUI_FLAGS_PERSIST = 0x1000; + public const int CREDUI_FLAGS_SERVER_CREDENTIAL = 0x4000; + public const int CREDUI_FLAGS_EXPECT_CONFIRMATION = 0x20000; + public const int CREDUI_FLAGS_GENERIC_CREDENTIALS = 0x40000; + public const int CREDUI_FLAGS_USERNAME_TARGET_CREDENTIALS = 0x80000; + public const int CREDUI_FLAGS_KEEP_USERNAME = 0x100000; + + [DllImport("credui", CharSet = CharSet.Auto)] + public static extern int CredUIPromptForCredentials( + ref CREDUI_INFO pUiInfo, + string pszTargetName, + IntPtr Reserved, + int dwAuthError, + StringBuilder pszUserName, + int ulUserNameMaxChars, + IntPtr pszPassword, + int ulPasswordMaxChars, + ref bool pfSave, + int dwFlags); + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] + public struct CREDUI_INFO { + public int cbSize; + public IntPtr hwndParent; + public string pszMessageText; + public string pszCaptionText; + public IntPtr hbmBanner; + } + } +} diff --git a/Microsoft.Common.Core/Net/FileDownloader.cs b/Microsoft.Common.Core/Net/FileDownloader.cs new file mode 100644 index 00000000..7257fb9b --- /dev/null +++ b/Microsoft.Common.Core/Net/FileDownloader.cs @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.Net; +using System.Threading; + +namespace Microsoft.Common.Core.Net { + public sealed class FileDownloader : IFileDownloader { + public string Download(string url, string dstPath, CancellationToken ct) { + try { + using (var client = new WebClient()) { + client.DownloadFileAsync(new Uri(url, UriKind.Absolute), dstPath); + while (client.IsBusy && !ct.IsCancellationRequested) { + Thread.Sleep(200); + } + } + } catch (WebException ex) { + return ex.Message; + } + return null; + } + } +} diff --git a/Microsoft.Common.Core/Net/IFileDownloader.cs b/Microsoft.Common.Core/Net/IFileDownloader.cs new file mode 100644 index 00000000..1a6c649b --- /dev/null +++ b/Microsoft.Common.Core/Net/IFileDownloader.cs @@ -0,0 +1,10 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System.Threading; + +namespace Microsoft.Common.Core.Net { + public interface IFileDownloader { + string Download(string url, string dstPath, CancellationToken ct); + } +} diff --git a/Microsoft.Common.Core/Net/Network.cs b/Microsoft.Common.Core/Net/Network.cs new file mode 100644 index 00000000..8219a205 --- /dev/null +++ b/Microsoft.Common.Core/Net/Network.cs @@ -0,0 +1,41 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.Net.NetworkInformation; +using System.Net.Sockets; +using System.Threading.Tasks; + +namespace Microsoft.Common.Core.Net { + public static class NetworkExtensions { + /// + /// Checks machine status via ping. + /// + /// Empty string if machine is online, exception message if ping failed. + public static async Task GetMachineOnlineStatusAsync(this Uri url, int timeout = 3000) { + if (url.IsFile) { + return string.Empty; + } + + try { + var ping = new Ping(); + var reply = await ping.SendPingAsync(url.Host, timeout); + if (reply.Status != IPStatus.Success) { + return reply.Status.ToString(); + } + } catch (PingException pex) { + var pingMessage = pex.InnerException?.Message ?? pex.Message; + if (!string.IsNullOrEmpty(pingMessage)) { + return pingMessage; + } + } catch (SocketException sx) { + return sx.Message; + } + return string.Empty; + } + + public static bool IsHttps(this Uri url) { + return url.Scheme.EqualsIgnoreCase("https"); + } + } +} diff --git a/Microsoft.Common.Core/Net/WebSocketHelper.cs b/Microsoft.Common.Core/Net/WebSocketHelper.cs new file mode 100644 index 00000000..da3a2c90 --- /dev/null +++ b/Microsoft.Common.Core/Net/WebSocketHelper.cs @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.Net.WebSockets; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.Common.Core { + public class WebSocketHelper { + private static async Task DoWebSocketReceiveSendAsync(WebSocket receiver, WebSocket sender, CancellationToken ct) { + if (receiver == null || sender == null) { + return; + } + + ArraySegment receiveBuffer = new ArraySegment(new byte[65335]); + while (receiver.State == WebSocketState.Open && sender.State == WebSocketState.Open) { + if (ct.IsCancellationRequested) { + receiver.CloseAsync(WebSocketCloseStatus.NormalClosure, "Normal closure", CancellationToken.None).SilenceException().DoNotWait(); + sender.CloseAsync(WebSocketCloseStatus.NormalClosure, "Normal closure", CancellationToken.None).SilenceException().DoNotWait(); + return; + } + + WebSocketReceiveResult result = await receiver.ReceiveAsync(receiveBuffer, ct); + + byte[] data = await receiveBuffer.ToByteArrayAsync(result.Count); + ArraySegment sendBuffer = new ArraySegment(data); + await sender.SendAsync(sendBuffer, result.MessageType, result.EndOfMessage, ct); + + if (result.MessageType == WebSocketMessageType.Close) { + await receiver.CloseAsync(WebSocketCloseStatus.NormalClosure, "Normal closure", ct); + } + } + } + + public static Task SendReceiveAsync(WebSocket ws1, WebSocket ws2, CancellationToken ct) { + return Task.WhenAll( + DoWebSocketReceiveSendAsync(ws1, ws2, ct), + DoWebSocketReceiveSendAsync(ws2, ws1, ct)); + } + } +} diff --git a/Microsoft.Common.Core/OS/ErrorCodeConverter.cs b/Microsoft.Common.Core/OS/ErrorCodeConverter.cs new file mode 100644 index 00000000..34cd0e7d --- /dev/null +++ b/Microsoft.Common.Core/OS/ErrorCodeConverter.cs @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.ComponentModel; +using System.Runtime.InteropServices; + +namespace Microsoft.Common.Core.OS { + public static class ErrorCodeConverter { + public static string MessageFromErrorCode(int errorCode) { + // Twy Win32 first + uint flags = NativeMethods.FORMAT_MESSAGE_ALLOCATE_BUFFER | NativeMethods.FORMAT_MESSAGE_FROM_SYSTEM | NativeMethods.FORMAT_MESSAGE_IGNORE_INSERTS; + IntPtr lpMsgBuf = IntPtr.Zero; + + var length = NativeMethods.FormatMessage(flags, IntPtr.Zero, errorCode, 0, ref lpMsgBuf, 0, IntPtr.Zero); + if (length == 0) { + // If failed, try to convert NTSTATUS to Win32 error + int code = NativeMethods.RtlNtStatusToDosError(errorCode); + return new Win32Exception(code).Message; + } + + string message = null; + if (lpMsgBuf != IntPtr.Zero) { + message = Marshal.PtrToStringUni(lpMsgBuf); + Marshal.FreeHGlobal(lpMsgBuf); + } + return message ?? string.Empty; + } + } +} diff --git a/Microsoft.Common.Core/OS/IProcessServices.cs b/Microsoft.Common.Core/OS/IProcessServices.cs new file mode 100644 index 00000000..df0896c3 --- /dev/null +++ b/Microsoft.Common.Core/OS/IProcessServices.cs @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System.Diagnostics; + +namespace Microsoft.Common.Core.OS { + public interface IProcessServices { + Process Start(ProcessStartInfo psi); + Process Start(string path); + } +} diff --git a/Microsoft.Common.Core/OS/IRegistry.cs b/Microsoft.Common.Core/OS/IRegistry.cs new file mode 100644 index 00000000..e11b90e0 --- /dev/null +++ b/Microsoft.Common.Core/OS/IRegistry.cs @@ -0,0 +1,8 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +namespace Microsoft.Common.Core.OS { + public interface IRegistry { + IRegistryKey OpenBaseKey(Win32.RegistryHive hive, Win32.RegistryView view); + } +} diff --git a/Microsoft.Common.Core/OS/IRegistryKey.cs b/Microsoft.Common.Core/OS/IRegistryKey.cs new file mode 100644 index 00000000..e6eea530 --- /dev/null +++ b/Microsoft.Common.Core/OS/IRegistryKey.cs @@ -0,0 +1,13 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; + +namespace Microsoft.Common.Core.OS { + public interface IRegistryKey : IDisposable { + object GetValue(string name); + void SetValue(string name, object value); + string[] GetSubKeyNames(); + IRegistryKey OpenSubKey(string name, bool writable = false); + } +} diff --git a/Microsoft.Common.Core/OS/ProcessServices.cs b/Microsoft.Common.Core/OS/ProcessServices.cs new file mode 100644 index 00000000..fe85cac6 --- /dev/null +++ b/Microsoft.Common.Core/OS/ProcessServices.cs @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System.Diagnostics; + +namespace Microsoft.Common.Core.OS { + public sealed class ProcessServices : IProcessServices { + public Process Start(ProcessStartInfo psi) { + return Process.Start(psi); + } + + public Process Start(string path) { + return Process.Start(path); + } + } +} diff --git a/Microsoft.Common.Core/OS/RegistryImpl.cs b/Microsoft.Common.Core/OS/RegistryImpl.cs new file mode 100644 index 00000000..5a5f781a --- /dev/null +++ b/Microsoft.Common.Core/OS/RegistryImpl.cs @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using Microsoft.Win32; + +namespace Microsoft.Common.Core.OS { + public sealed class RegistryImpl : IRegistry { + public IRegistryKey OpenBaseKey(RegistryHive hive, RegistryView view) { + return new RegistryKeyImpl(RegistryKey.OpenBaseKey(hive, view)); + } + } +} diff --git a/Microsoft.Common.Core/OS/RegistryKeyImpl.cs b/Microsoft.Common.Core/OS/RegistryKeyImpl.cs new file mode 100644 index 00000000..67d32005 --- /dev/null +++ b/Microsoft.Common.Core/OS/RegistryKeyImpl.cs @@ -0,0 +1,39 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using Microsoft.Win32; + +namespace Microsoft.Common.Core.OS { + internal sealed class RegistryKeyImpl : IRegistryKey { + RegistryKey _key; + + public RegistryKeyImpl(RegistryKey key) { + _key = key; + } + + public void Dispose() { + _key?.Dispose(); + _key = null; + } + + public string[] GetSubKeyNames() { + return _key != null ? _key.GetSubKeyNames() : new string[0]; + } + + public object GetValue(string name) { + return _key != null ? _key.GetValue(name) : null; + } + + public void SetValue(string name, object value) { + _key?.SetValue(name, value); + } + + public IRegistryKey OpenSubKey(string name, bool writable = false) { + var key = _key.OpenSubKey(name, writable); + if(key == null && writable) { + key = _key.CreateSubKey(name, true); + } + return new RegistryKeyImpl(key); + } + } +} diff --git a/Microsoft.Common.Core/Security/Credentials.cs b/Microsoft.Common.Core/Security/Credentials.cs new file mode 100644 index 00000000..0f76917c --- /dev/null +++ b/Microsoft.Common.Core/Security/Credentials.cs @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.Net; +using System.Security; + +namespace Microsoft.Common.Core.Security { + public sealed class Credentials : ICredentials { + // Although NetworkCredential does support SecureString, it still exposes + // plain text password via property and it is visible in a debugger. + public string UserName { get; set; } + public SecureString Password { get; set; } + + public NetworkCredential GetCredential(Uri uri, string authType) { + return new NetworkCredential(UserName, Password); + } + } +} diff --git a/Microsoft.Common.Core/Security/ISecurityService.cs b/Microsoft.Common.Core/Security/ISecurityService.cs new file mode 100644 index 00000000..ce689eb0 --- /dev/null +++ b/Microsoft.Common.Core/Security/ISecurityService.cs @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System.Security.Cryptography.X509Certificates; +using System.Threading.Tasks; + +namespace Microsoft.Common.Core.Security { + public interface ISecurityService { + Task GetUserCredentialsAsync(string authority, bool invalidateStoredCredentials); + Task ValidateX509CertificateAsync(X509Certificate certificate, string message); + } +} diff --git a/Microsoft.Common.Core/Security/SecurityService.cs b/Microsoft.Common.Core/Security/SecurityService.cs new file mode 100644 index 00000000..492cc866 --- /dev/null +++ b/Microsoft.Common.Core/Security/SecurityService.cs @@ -0,0 +1,77 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.ComponentModel.Composition; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Security.Cryptography.X509Certificates; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Common.Core.Shell; +using static Microsoft.Common.Core.NativeMethods; + +namespace Microsoft.Common.Core.Security { + [Export(typeof(ISecurityService))] + internal class SecurityService : ISecurityService { + private readonly Lazy _coreShellLazy; + + [ImportingConstructor] + public SecurityService([Import(AllowDefault = true)] Lazy coreShellLazy) { + _coreShellLazy = coreShellLazy; + } + + public async Task GetUserCredentialsAsync(string authority, bool invalidateStoredCredentials) { + var showDialog = invalidateStoredCredentials; + var credentials = new Credentials(); + + var passwordStorage = IntPtr.Zero; + + try { + var userNameBuilder = new StringBuilder(CREDUI_MAX_USERNAME_LENGTH + 1); + var save = false; + var flags = CREDUI_FLAGS_EXCLUDE_CERTIFICATES | CREDUI_FLAGS_PERSIST | CREDUI_FLAGS_EXPECT_CONFIRMATION | CREDUI_FLAGS_GENERIC_CREDENTIALS; + + if(showDialog) { + flags |= CREDUI_FLAGS_ALWAYS_SHOW_UI; + } + + await _coreShellLazy.Value.SwitchToMainThreadAsync(); + var credui = new CREDUI_INFO { + cbSize = Marshal.SizeOf(typeof(CREDUI_INFO)), + hwndParent = _coreShellLazy.Value.AppConstants.ApplicationWindowHandle + }; + + // For password, use native memory so it can be securely freed. + passwordStorage = SecurityUtilities.CreatePasswordBuffer(); + var err = CredUIPromptForCredentials(ref credui, authority, IntPtr.Zero, 0, userNameBuilder, userNameBuilder.Capacity, passwordStorage, CREDUI_MAX_PASSWORD_LENGTH, ref save, flags); + if (err != 0) { + throw new OperationCanceledException(); + } + + credentials.UserName = userNameBuilder.ToString(); + credentials.Password = SecurityUtilities.SecureStringFromNativeBuffer(passwordStorage); + credentials.Password.MakeReadOnly(); + } finally { + if (passwordStorage != IntPtr.Zero) { + Marshal.ZeroFreeGlobalAllocUnicode(passwordStorage); + } + } + + return credentials; + } + + public async Task ValidateX509CertificateAsync(X509Certificate certificate, string message) { + var certificate2 = certificate as X509Certificate2; + Debug.Assert(certificate2 != null); + if (certificate2 == null || !certificate2.Verify()) { + await _coreShellLazy.Value.SwitchToMainThreadAsync(); + if (_coreShellLazy.Value.ShowMessage(message, MessageButtons.OKCancel, MessageType.Warning) == MessageButtons.OK) { + certificate2.Reset(); + return true; + } + } + return false; + } + } +} diff --git a/Microsoft.Common.Core/Security/SecurityUtilities.cs b/Microsoft.Common.Core/Security/SecurityUtilities.cs new file mode 100644 index 00000000..e8cdb0a9 --- /dev/null +++ b/Microsoft.Common.Core/Security/SecurityUtilities.cs @@ -0,0 +1,44 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.Runtime.InteropServices; +using System.Security; + +namespace Microsoft.Common.Core.Security { + public static class SecurityUtilities { + public static IntPtr CreatePasswordBuffer() { + return CreateSecureStringBuffer(NativeMethods.CREDUI_MAX_PASSWORD_LENGTH); + } + + public static SecureString ToSecureString(this string s) { + if (s == null) { + return null; + } + var sec = new SecureString(); + foreach (var ch in s) { + sec.AppendChar(ch); + } + return sec; + } + + public static IntPtr CreateSecureStringBuffer(int length) { + var sec = new SecureString(); + for (int i = 0; i <= length; i++) { + sec.AppendChar('\0'); + } + return Marshal.SecureStringToGlobalAllocUnicode(sec); + } + + public static SecureString SecureStringFromNativeBuffer(IntPtr nativeBuffer) { + var ss = new SecureString(); + unsafe + { + for (char* p = (char*)nativeBuffer; *p != '\0'; p++) { + ss.AppendChar(*p); + } + } + return ss; + } + } +} diff --git a/Microsoft.Common.Core/Services/CoreServices.cs b/Microsoft.Common.Core/Services/CoreServices.cs new file mode 100644 index 00000000..e6741f1f --- /dev/null +++ b/Microsoft.Common.Core/Services/CoreServices.cs @@ -0,0 +1,55 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System.ComponentModel.Composition; +using Microsoft.Common.Core.IO; +using Microsoft.Common.Core.Logging; +using Microsoft.Common.Core.Logging.Implementation; +using Microsoft.Common.Core.OS; +using Microsoft.Common.Core.Security; +using Microsoft.Common.Core.Shell; +using Microsoft.Common.Core.Tasks; +using Microsoft.Common.Core.Telemetry; + +namespace Microsoft.Common.Core.Services { + [Export(typeof(ICoreServices))] + public sealed class CoreServices : ICoreServices { + private readonly IApplicationConstants _appConstants; + private IActionLog _log; + + [ImportingConstructor] + public CoreServices( + IApplicationConstants appConstants + , ITelemetryService telemetry + , ILoggingPermissions permissions + , ISecurityService security + , ITaskService tasks + , [Import(AllowDefault = true)] IActionLog log = null + , [Import(AllowDefault = true)] IFileSystem fs = null + , [Import(AllowDefault = true)] IRegistry registry = null + , [Import(AllowDefault = true)] IProcessServices ps = null) { + + LoggingServices = new LoggingServices(permissions, appConstants); + _appConstants = appConstants; + _log = log; + + Telemetry = telemetry; + Security = security; + Tasks = tasks; + + ProcessServices = ps ?? new ProcessServices(); + Registry = registry ?? new RegistryImpl(); + FileSystem = fs ?? new FileSystem(); + } + + public IActionLog Log => _log ?? (_log = LoggingServices.GetOrCreateLog(_appConstants.ApplicationName)); + + public IFileSystem FileSystem { get; } + public IProcessServices ProcessServices { get; } + public IRegistry Registry { get; } + public ISecurityService Security { get; } + public ITelemetryService Telemetry { get; } + public ITaskService Tasks { get; } + public ILoggingServices LoggingServices { get; } + } +} diff --git a/Microsoft.Common.Core/Services/ICoreServices.cs b/Microsoft.Common.Core/Services/ICoreServices.cs new file mode 100644 index 00000000..6ac1527f --- /dev/null +++ b/Microsoft.Common.Core/Services/ICoreServices.cs @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using Microsoft.Common.Core.IO; +using Microsoft.Common.Core.Logging; +using Microsoft.Common.Core.OS; +using Microsoft.Common.Core.Security; +using Microsoft.Common.Core.Tasks; +using Microsoft.Common.Core.Telemetry; + +namespace Microsoft.Common.Core.Services { + public interface ICoreServices { + IActionLog Log { get; } + IFileSystem FileSystem { get; } + ILoggingServices LoggingServices { get; } + IProcessServices ProcessServices { get; } + IRegistry Registry { get; } + ISecurityService Security { get; } + ITelemetryService Telemetry { get; } + ITaskService Tasks { get; } + } +} diff --git a/Microsoft.Common.Core/Settings/ISettingsStorage.cs b/Microsoft.Common.Core/Settings/ISettingsStorage.cs new file mode 100644 index 00000000..33ed58d2 --- /dev/null +++ b/Microsoft.Common.Core/Settings/ISettingsStorage.cs @@ -0,0 +1,46 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; + +namespace Microsoft.Common.Core.Settings { + /// + /// Settings storage. Exported via MEF for a particular content type. + /// Editor uses exported object to retrieve its settings such as indentation + /// style, tab size, formatting options and so on. + /// + public interface ISettingsStorage { + event EventHandler SettingsChanged; + + void LoadFromStorage(); + + string GetString(string name, string defaultValue); + int GetInteger(string name, int defaultValue); + bool GetBoolean(string name, bool defaultValue); + } + + /// + /// Writable settings storage. Exported via MEF for a particular content type. + /// Editor uses exported object to store settings such as indentation style, + /// tab size, formatting options and so on. + /// + public interface IWritableSettingsStorage : ISettingsStorage { + void ResetSettings(); + + void SetString(string name, string value); + void SetInteger(string name, int value); + void SetBoolean(string name, bool value); + + /// + /// Tells storage that multiple options are about to be changed. Storage should stop + /// firing events on every settings change and instead postpone even firing until + /// is called. + /// + void BeginBatchChange(); + + /// + /// Ends multiple settings change. Storage will file a single 'settings changed' event. + /// + void EndBatchChange(); + } +} diff --git a/Microsoft.Common.Core/Shell/CoreShell.cs b/Microsoft.Common.Core/Shell/CoreShell.cs new file mode 100644 index 00000000..011c9fcb --- /dev/null +++ b/Microsoft.Common.Core/Shell/CoreShell.cs @@ -0,0 +1,48 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Linq; +using System.Reflection; + +namespace Microsoft.Common.Core.Shell { + public static class CoreShell { + // Normally shell object is set by the package or other top-level + // application object that implements services needed by various + // modules such as MEF composition container and so on. However, + // in tests the application is not and objects often are instantiated + // in isolation. In this case code uses reflection to instatiate + // service provider with a specific name. + [SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods", + MessageId = "System.Reflection.Assembly.LoadFrom", + Justification ="Needed for test shell creation")] + public static void TryCreateTestInstance(string assemblyName, string className) { + string thisAssembly = Assembly.GetExecutingAssembly().GetAssemblyPath(); + string assemblyLoc = Path.GetDirectoryName(thisAssembly); + string packageTestAssemblyPath = Path.Combine(assemblyLoc, assemblyName); + Assembly testAssembly = null; + + // Catch exception when loading assembly since it is missing in non-test + // environment but do throw when it is present but test types cannot be created. + try { + testAssembly = Assembly.LoadFrom(packageTestAssemblyPath); + } + catch(Exception) { } + + if (testAssembly != null) { + Type[] types = testAssembly.GetTypes(); + IEnumerable classes = types.Where(x => x.IsClass); + + Type testAppShell = classes.FirstOrDefault(c => c.Name.Contains(className)); + Debug.Assert(testAppShell != null); + + MethodInfo mi = testAppShell.GetMethod("Create", BindingFlags.Static | BindingFlags.Public); + mi.Invoke(null, null); + } + } + } +} diff --git a/Microsoft.Common.Core/Shell/CoreShellExtensions.cs b/Microsoft.Common.Core/Shell/CoreShellExtensions.cs new file mode 100644 index 00000000..1c2ea012 --- /dev/null +++ b/Microsoft.Common.Core/Shell/CoreShellExtensions.cs @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Common.Core.Threading; + +namespace Microsoft.Common.Core.Shell { + public static class CoreShellExtensions { + public static MainThreadAwaitable SwitchToMainThreadAsync(this ICoreShell coreShell) => new MainThreadAwaitable((IMainThread)coreShell); + + public static async Task ShowErrorMessageAsync(this ICoreShell coreShell, string message) { + await coreShell.SwitchToMainThreadAsync(); + coreShell.ShowErrorMessage(message); + } + + public static async Task ShowMessageAsync(this ICoreShell coreShell, string message, MessageButtons buttons) { + await coreShell.SwitchToMainThreadAsync(); + return coreShell.ShowMessage(message, buttons); + } + + [Conditional("TRACE")] + public static void AssertIsOnMainThread(this ICoreShell coreShell, [CallerMemberName] string memberName = "", [CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0) { + if (coreShell.MainThread != Thread.CurrentThread) { + Trace.Fail(FormattableString.Invariant($"{memberName} at {sourceFilePath}:{sourceLineNumber} was incorrectly called from a background thread.")); + } + } + } +} diff --git a/Microsoft.Common.Core/Shell/IApplicationConstants.cs b/Microsoft.Common.Core/Shell/IApplicationConstants.cs new file mode 100644 index 00000000..e292ad26 --- /dev/null +++ b/Microsoft.Common.Core/Shell/IApplicationConstants.cs @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; + +namespace Microsoft.Common.Core.Shell { + /// + /// Defines application constants such as locale, registry key names, etc. + /// Implemented by the host application. Imported via MEF. + /// + public interface IApplicationConstants { + /// + /// Application name to use in log, system events, etc. + /// + string ApplicationName { get; } + + /// + /// Application locale ID (LCID) + /// + uint LocaleId { get; } + + /// + /// Root of HLKM application hive for admin-level settings. + /// + string LocalMachineHive { get; } + + /// + /// Application top level window handle. Typically used as a parent for native dialogs. + /// + IntPtr ApplicationWindowHandle { get; } + + UIColorTheme UIColorTheme { get; } + } +} diff --git a/Microsoft.Common.Core/Shell/ICompositionCatalog.cs b/Microsoft.Common.Core/Shell/ICompositionCatalog.cs new file mode 100644 index 00000000..f563e479 --- /dev/null +++ b/Microsoft.Common.Core/Shell/ICompositionCatalog.cs @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System.ComponentModel.Composition; +using System.ComponentModel.Composition.Hosting; + +namespace Microsoft.Common.Core.Shell { + public interface ICompositionCatalog { + /// + /// Host application MEF composition service. + /// + ICompositionService CompositionService { get; } + + /// + /// Visual Studio MEF export provider. + /// + ExportProvider ExportProvider { get; } + } +} diff --git a/Microsoft.Common.Core/Shell/ICoreShell.cs b/Microsoft.Common.Core/Shell/ICoreShell.cs new file mode 100644 index 00000000..a7a1df9f --- /dev/null +++ b/Microsoft.Common.Core/Shell/ICoreShell.cs @@ -0,0 +1,106 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.ComponentModel.Design; +using System.Threading; +using Microsoft.Common.Core.Services; +using Microsoft.Common.Core.Settings; + +namespace Microsoft.Common.Core.Shell { + /// + /// Basic shell provides access to services such as + /// composition container, export provider, global VS IDE + /// services and so on. + /// + public interface ICoreShell : ICompositionCatalog { + /// + /// Provides a way to execute action on UI thread while + /// UI thread is waiting for the completion of the action. + /// May be implemented using ThreadHelper in VS or via + /// SynchronizationContext in all-managed application. + /// + /// This can be blocking or non blocking dispatch, preferrably + /// non blocking + /// + /// Action to execute + void DispatchOnUIThread(Action action); + + /// + /// Provides access to the application main thread, so users can know if the task they are trying + /// to execute is executing from the right thread. + /// + Thread MainThread { get; } + + /// + /// Fires when host application enters idle state. + /// + event EventHandler Idle; + + /// + /// Fires when host application is terminating + /// + event EventHandler Terminating; + + /// + /// Displays error message in a host-specific UI + /// + void ShowErrorMessage(string message); + + /// + /// Shows the context menu with the specified command ID at the specified location + /// + /// + /// + /// + void ShowContextMenu(CommandID commandId, int x, int y, object commandTarget = null); + + /// + /// Displays message with specified buttons in a host-specific UI + /// + MessageButtons ShowMessage(string message, MessageButtons buttons, MessageType messageType = MessageType.Information); + + /// + /// If the specified file is opened as a document, and it has unsaved changes, save those changes. + /// + /// The full path to the document to be saved. + /// The path to which the file was saved. This is either the original path or a new path specified by the user. + string SaveFileIfDirty(string fullPath); + + /// + /// Informs the environment to update the state of the commands + /// + /// True if the update is performed immediately + void UpdateCommandStatus(bool immediate = false); + + /// + /// Tells if code runs in unit test environment + /// + bool IsUnitTestEnvironment { get; } + + /// + /// File dialogs + /// + IFileDialog FileDialog { get; } + + /// + /// Modal dialog with progress bar + /// + IProgressDialog ProgressDialog { get; } + + /// + /// Application core services + /// + ICoreServices Services { get; } + + /// + /// Application constants + /// + IApplicationConstants AppConstants { get; } + + /// + /// Persistent storage for any settings application may need to keep between sessions. + /// + IWritableSettingsStorage SettingsStorage { get; } + } +} diff --git a/Microsoft.Common.Core/Shell/IFileDialog.cs b/Microsoft.Common.Core/Shell/IFileDialog.cs new file mode 100644 index 00000000..6f6d1732 --- /dev/null +++ b/Microsoft.Common.Core/Shell/IFileDialog.cs @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +namespace Microsoft.Common.Core.Shell { + public interface IFileDialog { + /// + /// Shows the open file dialog. + /// + /// + /// + /// + /// Full path to the file selected, or null. + string ShowOpenFileDialog(string filter, string initialPath = null, string title = null); + + /// + /// Shows the browse directory dialog. + /// + /// + /// + /// + /// Full path to the directory selected, or null. + string ShowBrowseDirectoryDialog(string initialPath = null, string title = null); + + /// + /// Shows the save file dialog. + /// + /// + /// + /// + /// Full path to the file selected, or null. + string ShowSaveFileDialog(string filter, string initialPath = null, string title = null); + } +} \ No newline at end of file diff --git a/Microsoft.Common.Core/Shell/IIdleTimeService.cs b/Microsoft.Common.Core/Shell/IIdleTimeService.cs new file mode 100644 index 00000000..cd200628 --- /dev/null +++ b/Microsoft.Common.Core/Shell/IIdleTimeService.cs @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + + +using System.Threading; + +namespace Microsoft.Languages.Editor.Host { + public interface IIdleTimeService { + void DoIdle(); + } +} diff --git a/Microsoft.Common.Core/Shell/IProgressDialog.cs b/Microsoft.Common.Core/Shell/IProgressDialog.cs new file mode 100644 index 00000000..cb3971b7 --- /dev/null +++ b/Microsoft.Common.Core/Shell/IProgressDialog.cs @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.Common.Core.Shell { + public interface IProgressDialog { + /// + /// Shows progress bar that blocks hosting shell + /// + /// + void Show(Func method, string waitMessage, int delayToShowDialogMs = 0); + + /// + /// Shows progress bar that blocks hosting shell + /// + /// + TResult Show(Func> method, string waitMessage, int delayToShowDialogMs = 0); + + /// + /// Shows progress bar that blocks hosting shell + /// + /// + void Show(Func, CancellationToken, Task> method, string waitMessage, int totalSteps = 100, int delayToShowDialogMs = 0); + + /// + /// Shows progress bar that blocks hosting shell + /// + /// + T Show(Func, CancellationToken, Task> method, string waitMessage, int totalSteps = 100, int delayToShowDialogMs = 0); + } +} \ No newline at end of file diff --git a/Microsoft.Common.Core/Shell/MessageButtons.cs b/Microsoft.Common.Core/Shell/MessageButtons.cs new file mode 100644 index 00000000..690c9b43 --- /dev/null +++ b/Microsoft.Common.Core/Shell/MessageButtons.cs @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; + +namespace Microsoft.Common.Core.Shell { + + /// + /// Specifies which buttons to show in a message box. + /// Also used as a return value to tell which button + /// was pressed. + /// + [Flags] + public enum MessageButtons { + OK = 0, + Cancel = 0x01, + Yes = 0x02, + No = 0x04, + OKCancel = OK | Cancel, + YesNo = Yes | No, + YesNoCancel = YesNo | Cancel, + } +} \ No newline at end of file diff --git a/Microsoft.Common.Core/Shell/MessageType.cs b/Microsoft.Common.Core/Shell/MessageType.cs new file mode 100644 index 00000000..bc2b5d63 --- /dev/null +++ b/Microsoft.Common.Core/Shell/MessageType.cs @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +namespace Microsoft.Common.Core.Shell { + + /// + /// Specifies which icon to show in a message box. + /// + public enum MessageType { + Information, + Warning, + Error + } +} \ No newline at end of file diff --git a/Microsoft.Common.Core/Shell/ProgressBarSession.cs b/Microsoft.Common.Core/Shell/ProgressBarSession.cs new file mode 100644 index 00000000..370cebed --- /dev/null +++ b/Microsoft.Common.Core/Shell/ProgressBarSession.cs @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.Threading; + +namespace Microsoft.Common.Core.Shell { + public class ProgressBarSession : IDisposable { + private readonly IDisposable _disposable; + public CancellationToken UserCancellationToken { get; } + + public ProgressBarSession(IDisposable disposable = null, CancellationToken cancellationToken = default(CancellationToken)) { + _disposable = disposable; + UserCancellationToken = cancellationToken; + } + + public void Dispose() { + _disposable?.Dispose(); + } + } +} \ No newline at end of file diff --git a/Microsoft.Common.Core/Shell/ProgressDialogData.cs b/Microsoft.Common.Core/Shell/ProgressDialogData.cs new file mode 100644 index 00000000..d40611c9 --- /dev/null +++ b/Microsoft.Common.Core/Shell/ProgressDialogData.cs @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +namespace Microsoft.Common.Core.Shell { + public struct ProgressDialogData { + public int Step { get; } + public string ProgressText { get; } + public string StatusBarText { get; } + public string WaitMessage { get; } + + public ProgressDialogData(int step, string progressText = null, string statusBarText = null, string waitMessage = null) { + Step = step; + ProgressText = progressText; + StatusBarText = statusBarText; + WaitMessage = waitMessage; + } + } +} \ No newline at end of file diff --git a/Microsoft.Common.Core/Shell/UIColorTheme.cs b/Microsoft.Common.Core/Shell/UIColorTheme.cs new file mode 100644 index 00000000..db3957fe --- /dev/null +++ b/Microsoft.Common.Core/Shell/UIColorTheme.cs @@ -0,0 +1,9 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +namespace Microsoft.Common.Core.Shell { + public enum UIColorTheme { + Light, + Dark + } +} diff --git a/Microsoft.Common.Core/TaskUtilities.cs b/Microsoft.Common.Core/TaskUtilities.cs new file mode 100644 index 00000000..0bad2210 --- /dev/null +++ b/Microsoft.Common.Core/TaskUtilities.cs @@ -0,0 +1,117 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Common.Core.Tasks; +using Microsoft.Common.Core.Threading; +using static System.FormattableString; + +namespace Microsoft.Common.Core { + public static class TaskUtilities { + public static Task CreateCanceled(OperationCanceledException exception = null) { + exception = exception ?? new OperationCanceledException(); + var atmb = new AsyncTaskMethodBuilder(); + atmb.SetException(exception); + return atmb.Task; + } + + public static Task CreateCanceled(OperationCanceledException exception = null) { + exception = exception ?? new OperationCanceledException(); + var atmb = new AsyncTaskMethodBuilder(); + atmb.SetException(exception); + return atmb.Task; + } + + public static bool IsOnBackgroundThread() { + var taskScheduler = TaskScheduler.Current; + var syncContext = SynchronizationContext.Current; + return taskScheduler == TaskScheduler.Default && (syncContext == null || syncContext.GetType() == typeof(SynchronizationContext)); + } + + /// + /// If awaited on a thread with custom scheduler or synchronization context, invokes the continuation + /// on a background (thread pool) thread. If already on such a thread, await is a no-op. + /// + public static BackgroundThreadAwaitable SwitchToBackgroundThread() { + return new BackgroundThreadAwaitable(); + } + + [Conditional("TRACE")] + public static void AssertIsOnBackgroundThread( + [CallerMemberName] string memberName = "", + [CallerFilePath] string sourceFilePath = "", + [CallerLineNumber] int sourceLineNumber = 0 + ) { + if (!IsOnBackgroundThread()) { + Trace.Fail(Invariant($"{memberName} at {sourceFilePath}:{sourceLineNumber} was incorrectly called from a non-background thread.")); + } + } + + public static Task WhenAllCancelOnFailure(params Func[] functions) => WhenAllCancelOnFailure(functions, default(CancellationToken)); + + public static Task WhenAllCancelOnFailure(IEnumerable source, Func taskFactory, CancellationToken cancellationToken) { + var functions = source.Select(s => SourceToFunctionConverter(s, taskFactory)); + return WhenAllCancelOnFailure(functions, cancellationToken); + } + + private static Func SourceToFunctionConverter(TSource source, Func taskFactory) + => ct => taskFactory(source, ct); + + public static Task WhenAllCancelOnFailure(IEnumerable> functions, CancellationToken cancellationToken) { + var functionsList = functions.ToList(); + var cts = new CancellationTokenSource(); + var tcs = new TaskCompletionSourceEx(); + var state = new WhenAllCancelOnFailureContinuationState(functionsList.Count, tcs, cts); + + foreach (var function in functionsList) { + var task = function(CancellationTokenSource.CreateLinkedTokenSource(cts.Token, cancellationToken).Token); + task.ContinueWith(WhenAllCancelOnFailureContinuation, state, default(CancellationToken), TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); + } + + return tcs.Task; + } + + private static void WhenAllCancelOnFailureContinuation(Task task, object state) { + var continuationState = (WhenAllCancelOnFailureContinuationState) state; + switch (task.Status) { + case TaskStatus.RanToCompletion: + if (Interlocked.Decrement(ref continuationState.Count) == 0) { + continuationState.TaskCompletionSource.TrySetResult(true); + } + break; + case TaskStatus.Canceled: + try { + task.GetAwaiter().GetResult(); + } catch (OperationCanceledException ex) { + if (continuationState.TaskCompletionSource.TrySetCanceled(ex)) { + continuationState.CancellationTokenSource.Cancel(); + } + } + break; + case TaskStatus.Faulted: + if (continuationState.TaskCompletionSource.TrySetException(task.Exception)) { + continuationState.CancellationTokenSource.Cancel(); + } + break; + } + } + + private class WhenAllCancelOnFailureContinuationState { + public int Count; + public readonly TaskCompletionSourceEx TaskCompletionSource; + public readonly CancellationTokenSource CancellationTokenSource; + + public WhenAllCancelOnFailureContinuationState(int count, TaskCompletionSourceEx taskCompletionSource, CancellationTokenSource cancellationTokenSource) { + Count = count; + TaskCompletionSource = taskCompletionSource; + CancellationTokenSource = cancellationTokenSource; + } + } + } +} diff --git a/Microsoft.Common.Core/Tasks/EventTaskSource.cs b/Microsoft.Common.Core/Tasks/EventTaskSource.cs new file mode 100644 index 00000000..324d70d1 --- /dev/null +++ b/Microsoft.Common.Core/Tasks/EventTaskSource.cs @@ -0,0 +1,87 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.Common.Core.Tasks { + public sealed class EventTaskSource : EventTaskSource { + public EventTaskSource(Action subscribe, Action unsubscribe) + : base(subscribe, unsubscribe, a => (o, e) => a(o, e)) { + } + } + + public class EventTaskSource : EventTaskSource, TEventArgs> { + public EventTaskSource(Action> subscribe, Action> unsubscribe) + : base(subscribe, unsubscribe, a => (o, e) => a(o, e)) { + } + } + + public class EventTaskSource { + private readonly Action _subscribe; + private readonly Action _unsubscribe; + private readonly Func, TEventHandler> _handlerConverter; + + public EventTaskSource(Action subscribe, Action unsubscribe, Func, TEventHandler> handlerConverter) { + _subscribe = subscribe; + _unsubscribe = unsubscribe; + _handlerConverter = handlerConverter; + } + + public Task Create(T instance, CancellationToken cancellationToken = default(CancellationToken)) { + return Create(instance, null, cancellationToken); + } + + public Task Create(T instance, Action callback, CancellationToken cancellationToken = default(CancellationToken)) { + var tcs = new TaskCompletionSource(); + var reference = new HandlerReference(instance, tcs, _unsubscribe, _handlerConverter, callback); + if (cancellationToken != CancellationToken.None) { + cancellationToken.Register(reference.Cancel); + } + _subscribe(instance, reference.Handler); + return tcs.Task; + } + + private class HandlerReference { + private T _instance; + private TaskCompletionSource _tcs; + private Action _unsubscribe; + private readonly Action _callback; + public TEventHandler Handler { get; } + + public HandlerReference(T instance, TaskCompletionSource tcs, Action unsubscribe, Func, TEventHandler> handlerConverter, Action callback) { + _instance = instance; + _tcs = tcs; + _unsubscribe = unsubscribe; + _callback = callback; + Handler = handlerConverter(TypedHandler); + } + + public void Cancel() { + var tcs = Unsubscribe(); + tcs?.SetCanceled(); + } + + private void TypedHandler(object sender, TEventArgs e) { + var tcs = Unsubscribe(); + _callback?.Invoke(e); + tcs?.SetResult(e); + } + + private TaskCompletionSource Unsubscribe() { + var tcs = Interlocked.Exchange(ref _tcs, null); + if (tcs == null) { + return null; + } + + var instance = _instance; + var unsubscribe = _unsubscribe; + _instance = default(T); + _unsubscribe = null; + unsubscribe(instance, Handler); + return tcs; + } + } + } +} diff --git a/Microsoft.Common.Core/Tasks/ITaskService.cs b/Microsoft.Common.Core/Tasks/ITaskService.cs new file mode 100644 index 00000000..94a99363 --- /dev/null +++ b/Microsoft.Common.Core/Tasks/ITaskService.cs @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.Common.Core.Tasks { + public interface ITaskService { + bool Wait(Task task, CancellationToken cancellationToken = default(CancellationToken), int ms = Timeout.Infinite); + } +} diff --git a/Microsoft.Common.Core/Tasks/TaskCompletionSourceEx.cs b/Microsoft.Common.Core/Tasks/TaskCompletionSourceEx.cs new file mode 100644 index 00000000..32d51401 --- /dev/null +++ b/Microsoft.Common.Core/Tasks/TaskCompletionSourceEx.cs @@ -0,0 +1,102 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information + +using System; +using System.Runtime.CompilerServices; +using System.Threading; +using System.Threading.Tasks; +using static System.FormattableString; + +namespace Microsoft.Common.Core.Tasks { + public class TaskCompletionSourceEx { + private readonly AsyncTaskMethodBuilder _atmb; + private int _completed; + + public Task Task { get; } + + public TaskCompletionSourceEx() { + _atmb = AsyncTaskMethodBuilder.Create(); + Task = _atmb.Task; + } + + public bool TrySetResult(TResult result) { + if (Task.IsCompleted) { + return false; + } + + if (Interlocked.CompareExchange(ref _completed, 1, 0) == 0) { + _atmb.SetResult(result); + return true; + } + + SpinUntilCompleted(); + return false; + } + + public bool TrySetCanceled(OperationCanceledException exception = null, CancellationToken cancellationToken = default(CancellationToken)) { + if (Task.IsCompleted) { + return false; + } + + if (Interlocked.CompareExchange(ref _completed, 1, 0) == 0) { + exception = exception ?? new OperationCanceledException(cancellationToken); + _atmb.SetException(exception); + return true; + } + + SpinUntilCompleted(); + return false; + } + + public bool TrySetException(Exception exception) { + if (exception == null) { + throw new ArgumentNullException(nameof(exception)); + } + + if (exception is OperationCanceledException) { + throw new ArgumentOutOfRangeException(nameof(exception), Invariant($"Use {nameof(TrySetCanceled)} to cancel task")); + } + + if (Task.IsCompleted) { + return false; + } + + if (Interlocked.CompareExchange(ref _completed, 1, 0) == 0) { + _atmb.SetException(exception); + return true; + } + + SpinUntilCompleted(); + return false; + } + + private void SpinUntilCompleted() { + if (Task.IsCompleted) { + return; + } + + var sw = new SpinWait(); + while (!Task.IsCompleted) { + sw.SpinOnce(); + } + } + + public void SetResult(TResult result) { + if (!TrySetResult(result)) { + throw new InvalidOperationException("Task already completed"); + } + } + + public void SetCanceled(OperationCanceledException exception = null, CancellationToken cancellationToken = default(CancellationToken)) { + if (!TrySetCanceled(exception, cancellationToken)) { + throw new InvalidOperationException("Task already completed"); + } + } + + public void SetException(Exception exception) { + if (!TrySetException(exception)) { + throw new InvalidOperationException("Task already completed"); + } + } + } +} \ No newline at end of file diff --git a/Microsoft.Common.Core/Telemetry/ITelemetryRecorder.cs b/Microsoft.Common.Core/Telemetry/ITelemetryRecorder.cs new file mode 100644 index 00000000..f90b0fbd --- /dev/null +++ b/Microsoft.Common.Core/Telemetry/ITelemetryRecorder.cs @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; + +namespace Microsoft.Common.Core.Telemetry { + /// + /// Represents object that records telemetry events and is called by + /// the telemetry service. In Visual Studio environment maps to IVsTelemetryService + /// whereas in tests can be replaced by an object that writes events to a string. + /// + public interface ITelemetryRecorder : IDisposable { + /// + /// True if telemetry is actually being recorded + /// + bool IsEnabled { get; } + + /// + /// Indicates if telemetry can collect private information + /// + bool CanCollectPrivateInformation { get; } + + /// + /// Records event with parameters. Perameters are + /// a collection of string/object pairs. + /// + void RecordEvent(string eventName, object parameters = null); + } +} diff --git a/Microsoft.Common.Core/Telemetry/ITelemetryService.cs b/Microsoft.Common.Core/Telemetry/ITelemetryService.cs new file mode 100644 index 00000000..b7ebd202 --- /dev/null +++ b/Microsoft.Common.Core/Telemetry/ITelemetryService.cs @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System.Collections.Generic; + +namespace Microsoft.Common.Core.Telemetry { + /// + /// Application telemetry service. In Visual Studio maps to IVsTelemetrySession. + /// + public interface ITelemetryService { + /// + /// True of user opted in and telemetry is being collected + /// + bool IsEnabled { get; } + + /// + /// Records event with parameters + /// + /// Telemetry area name such as 'Project'. + /// Event name. + /// + /// Either string/object dictionary or anonymous + /// collection of string/object pairs. + /// + void ReportEvent(TelemetryArea area, string eventName, object parameters = null); + } +} diff --git a/Microsoft.Common.Core/Telemetry/PropertyNames.cs b/Microsoft.Common.Core/Telemetry/PropertyNames.cs new file mode 100644 index 00000000..3b3e6d21 --- /dev/null +++ b/Microsoft.Common.Core/Telemetry/PropertyNames.cs @@ -0,0 +1,9 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + + +namespace Microsoft.Common.Core.Telemetry { + internal static class PropertyNames { + public const string ProjectGuid = nameof(ProjectGuid); + } +} diff --git a/Microsoft.Common.Core/Telemetry/TelemetryArea.cs b/Microsoft.Common.Core/Telemetry/TelemetryArea.cs new file mode 100644 index 00000000..8b7c3922 --- /dev/null +++ b/Microsoft.Common.Core/Telemetry/TelemetryArea.cs @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +//----------------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +//----------------------------------------------------------------------------- +namespace Microsoft.Common.Core.Telemetry { + /// + /// Area names show up as part of telemetry event names like: + /// VS/RTools/[area]/[event] + public enum TelemetryArea { + // Keep these sorted + Build, + Configuration, + DataGrid, + Debugger, + Editor, + History, + Options, + Packages, + Plotting, + Project, + Repl, + SQL, + VariableExplorer, + } +} diff --git a/Microsoft.Common.Core/Telemetry/TelemetryServiceBase.cs b/Microsoft.Common.Core/Telemetry/TelemetryServiceBase.cs new file mode 100644 index 00000000..33bb3405 --- /dev/null +++ b/Microsoft.Common.Core/Telemetry/TelemetryServiceBase.cs @@ -0,0 +1,90 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.Collections.Generic; +using Microsoft.Common.Core.Diagnostics; + +namespace Microsoft.Common.Core.Telemetry { + /// + /// Base telemetry service implementation, common to production code and test cases. + /// + public abstract class TelemetryServiceBase : ITelemetryService, IDisposable + where TRecorder: class, ITelemetryRecorder { + + public string EventNamePrefix { get; private set; } + public string PropertyNamePrefix { get; private set; } + + /// + /// Current active telemetry writer. Inside Visual Studio it + /// uses IVsTelemetryService, in unit or component tests + /// recorder is a simple string container or a disk file. + /// + public TRecorder TelemetryRecorder { get; private set; } + + protected TelemetryServiceBase(string eventNamePrefix, string propertyNamePrefix, TRecorder telemetryRecorder) { + TelemetryRecorder = telemetryRecorder; + EventNamePrefix = eventNamePrefix; + PropertyNamePrefix = propertyNamePrefix; + } + + #region ITelemetryService + /// + /// True of user opted in and telemetry is being collected + /// + public bool IsEnabled { + get { + return this.TelemetryRecorder?.IsEnabled == true; + } + } + + public bool CanCollectPrivateInformation { + get { + return (this.TelemetryRecorder?.IsEnabled == true && this.TelemetryRecorder?.CanCollectPrivateInformation == true); + } + } + + /// + /// Records event with parameters + /// + /// Telemetry area name such as 'Toolbox'. + /// Event name. + /// + /// Either string/object dictionary or anonymous + /// collection of string/object pairs. + /// + /// + public void ReportEvent(TelemetryArea area, string eventName, object parameters = null) { + Check.ArgumentStringNullOrEmpty("eventName", eventName); + + string completeEventName = MakeEventName(area, eventName); + if (parameters == null) { + this.TelemetryRecorder.RecordEvent(completeEventName); + } else if (parameters is string) { + this.TelemetryRecorder.RecordEvent(completeEventName, parameters as string); + } else { + IDictionary dict = DictionaryExtension.FromAnonymousObject(parameters); + IDictionary dictWithPrefix = new Dictionary(); + + foreach (KeyValuePair kvp in dict) { + Check.ArgumentStringNullOrEmpty("parameterName", kvp.Key); + dictWithPrefix[this.PropertyNamePrefix + area.ToString() + "." + kvp.Key] = kvp.Value ?? string.Empty; + } + this.TelemetryRecorder.RecordEvent(completeEventName, dictWithPrefix); + } + } + #endregion + + private string MakeEventName(TelemetryArea area, string eventName) { + return this.EventNamePrefix + area.ToString() + "/" + eventName; + } + + protected virtual void Dispose(bool disposing) { } + + public void Dispose() { + Dispose(true); + TelemetryRecorder?.Dispose(); + TelemetryRecorder = null; + } + } +} diff --git a/Microsoft.Common.Core/Threading/AsyncCountdownEvent.cs b/Microsoft.Common.Core/Threading/AsyncCountdownEvent.cs new file mode 100644 index 00000000..740f062e --- /dev/null +++ b/Microsoft.Common.Core/Threading/AsyncCountdownEvent.cs @@ -0,0 +1,54 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Common.Core.Disposables; + +namespace Microsoft.Common.Core.Threading { + public class AsyncCountdownEvent { + private readonly AsyncManualResetEvent _mre = new AsyncManualResetEvent(); + private int _count; + + public AsyncCountdownEvent(int initialCount) { + if (initialCount < 0) { + throw new ArgumentOutOfRangeException(nameof(initialCount)); + } + + _count = initialCount; + if (initialCount == 0) { + _mre.Set(); + } + } + + public Task WaitAsync() => _mre.WaitAsync(); + + public Task WaitAsync(CancellationToken cancellationToken) => _mre.WaitAsync(cancellationToken); + + public void Signal() { + if (_count <= 0) { + throw new InvalidOperationException(); + } + + var count = Interlocked.Decrement(ref _count); + if (count < 0) { + throw new InvalidOperationException(); + } + + if (count == 0) { + _mre.Set(); + } + } + + public void AddOne() { + _mre.Reset(); + Interlocked.Increment(ref _count); + } + + public IDisposable AddOneDisposable() { + AddOne(); + return Disposable.Create(Signal); + } + } +} \ No newline at end of file diff --git a/Microsoft.Common.Core/Threading/AsyncManualResetEvent.cs b/Microsoft.Common.Core/Threading/AsyncManualResetEvent.cs new file mode 100644 index 00000000..257f02a5 --- /dev/null +++ b/Microsoft.Common.Core/Threading/AsyncManualResetEvent.cs @@ -0,0 +1,69 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.Common.Core.Threading { + /// + /// Async version of the ManualResetEvent + /// + public class AsyncManualResetEvent { + private TaskCompletionSource _tcs; + public bool IsSet => _tcs.Task.IsCompleted; + + public Task WaitAsync() => _tcs.Task; + public void Set() => _tcs.TrySetResult(true); + + public Task WaitAsync(CancellationToken cancellationToken) { + if (cancellationToken.IsCancellationRequested) { + return Task.FromCanceled(cancellationToken); + } + + var tcs = new TaskCompletionSource(); + cancellationToken.Register(CancelTcs, tcs); + _tcs.Task.ContinueWith(WaitContinuation, tcs, TaskContinuationOptions.ExecuteSynchronously); + return tcs.Task; + } + + private void WaitContinuation(Task task, object state) { + var tcs = (TaskCompletionSource) state; + switch (task.Status) { + case TaskStatus.Faulted: + tcs.TrySetException(task.Exception); + break; + case TaskStatus.Canceled: + tcs.TrySetCanceled(); + break; + case TaskStatus.RanToCompletion: + tcs.TrySetResult(task.Result); + break; + } + } + + public AsyncManualResetEvent(bool isSet = false) { + _tcs = new TaskCompletionSource(); + if (isSet) { + _tcs.SetResult(true); + } + } + + public void Reset() { + while (true) { + var tcs = _tcs; + if (!tcs.Task.IsCompleted) { + return; + } + + if (Interlocked.CompareExchange(ref _tcs, new TaskCompletionSource(), tcs) == tcs) { + return; + } + } + } + + private static void CancelTcs(object obj) { + var tcs = (TaskCompletionSource) obj; + tcs.TrySetCanceled(); + } + } +} \ No newline at end of file diff --git a/Microsoft.Common.Core/Threading/AsyncReaderWriterLock.cs b/Microsoft.Common.Core/Threading/AsyncReaderWriterLock.cs new file mode 100644 index 00000000..373d2ff8 --- /dev/null +++ b/Microsoft.Common.Core/Threading/AsyncReaderWriterLock.cs @@ -0,0 +1,352 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.Common.Core.Threading { + /// + /// Async lock-free version of ReaderWriterLock with cancellation and reentrancy support. Upgrades aren't supported + /// + /// + /// + /// This lock prefers writers over readers. If writer lock is requested, all furhter reader locks will be provided only after writer lock is released. + /// For example, if reader holds a lock and several locks are requested in order Writer-Reader-Writer, they will be provider as Writer-Writer-Reader + /// after current lock is released + /// + /// + /// Cancellation affects only unfulfilled lock requests. Canceled requests affect the waiting queue also prefering writers over readers. + /// For example, if reader holds a lock and several locks are requested in order Writer-Reader-Writer, the waiting queue will be Writer-Writer-Reader, + /// sp cancelling first writer request will not fulfill following reader request, but instead will put the second waiter in front of the queue. + /// + /// + /// async/await doesn't support reentrancy on the language level, so to support it uses structure. + /// It can be passed as a method argument in a way similar to the . + /// There are 4 possible types of reentrancy: + /// + /// + /// Reader requested inside Reader lock + /// Reader locks don't block each other, so it will be treated as another reader lock request. The difference is that it will have priority over writer. + /// + /// + /// Reader requested inside Writer lock + /// Lock will increment reentrancy counter of the Writer lock, so it will require them both to be released before next lock can be provided + /// + /// + /// Writer requested inside Writer lock + /// Lock will increment reentrancy counter of the Writer lock, so it will require them both to be released before next lock can be provided + /// + /// + /// Writer requested inside reader lock + /// That is considered an upgrade, which aren't supported right now, so in this case request will be treated as non-reentrant + /// + /// + /// + /// + public class AsyncReaderWriterLock { + private ReaderLockSource _readerTail; + private WriterLockSource _writerTail; + private WriterLockSource _lastAcquiredWriter; + + private static readonly IReentrancyTokenFactory ReaderLockTokenFactory; + private static readonly IReentrancyTokenFactory WriterLockTokenFactory; + + static AsyncReaderWriterLock() { + ReaderLockTokenFactory = ReentrancyToken.CreateFactory(); + WriterLockTokenFactory = ReentrancyToken.CreateFactory(); + } + + public AsyncReaderWriterLock() { + _readerTail = new ReaderLockSource(this); + _writerTail = new WriterLockSource(this); + + _readerTail.CompleteTasks(); + _writerTail.TryCompleteTask(); + _writerTail.Task.Result.Dispose(); + } + + public Task ReaderLockAsync(CancellationToken cancellationToken = default(CancellationToken), ReentrancyToken reentrancyToken = default(ReentrancyToken)) { + Task task; + var writerFromToken = WriterLockTokenFactory.GetSource(reentrancyToken); + if (writerFromToken != null && writerFromToken.TryReenter(out task)) { + return task; + } + + var readerFromToken = ReaderLockTokenFactory.GetSource(reentrancyToken); + if (readerFromToken != null && readerFromToken.TryReenter(out task)) { + return task; + } + + while (true) { + if (cancellationToken.IsCancellationRequested) { + return Task.FromCanceled(cancellationToken); + } + + task = _readerTail.WaitAsync(cancellationToken); + if (task != null) { + return task; + } + } + } + + public Task WriterLockAsync(CancellationToken cancellationToken = default(CancellationToken), ReentrancyToken reentrancyToken = default(ReentrancyToken)) { + Task task; + var writerFromToken = WriterLockTokenFactory.GetSource(reentrancyToken); + if (writerFromToken != null && writerFromToken.TryReenter(out task)) { + return task; + } + + while (true) { + if (cancellationToken.IsCancellationRequested) { + return Task.FromCanceled(cancellationToken); + } + + WriterLockSource oldWriter = _writerTail; + WriterLockSource newWriter; + if (!oldWriter.TrySetNext(out newWriter)) { + continue; + } + + var reader = oldWriter.IsCompleted && _lastAcquiredWriter == oldWriter + ? Interlocked.Exchange(ref _readerTail, new ReaderLockSource(this)) + : null; + + if (Interlocked.CompareExchange(ref _writerTail, newWriter, oldWriter) != oldWriter) { + throw new InvalidOperationException(); + } + + if (reader != null) { // oldWriter.IsCompleted + reader.RegisterWait(newWriter, cancellationToken); + } else { + oldWriter.RegisterWait(cancellationToken); + } + + return newWriter.Task; + } + } + + private void CompleteNextTask(WriterLockSource writer) { + var reader = _readerTail; + while (writer != null && !writer.TryCompleteTask()) { + writer = writer.NextWriter; + } + + // No writer source left - complete reader source tasks + if (writer == null) { + reader.CompleteTasks(); + } + } + + private void CompleteReaderTasksIfRequired(WriterLockSource writer) { + var reader = _readerTail; + while (writer != null && writer.IsCompleted) { + writer = writer.NextWriter; + } + + // No writer source left - complete reader source tasks + if (writer == null) { + reader.CompleteTasks(); + } + } + + private class ReaderLockSource { + private readonly AsyncReaderWriterLock _host; + private readonly TaskCompletionSource _rootTcs; + private WriterLockSource _writer; + private int _count; + + public ReaderLockSource(AsyncReaderWriterLock host) { + _host = host; + _rootTcs = new TaskCompletionSource(); + } + + public Task WaitAsync(CancellationToken cancellationToken) { + if (!TryIncrement()) { + return null; + } + + if (_rootTcs.Task.Status == TaskStatus.RanToCompletion) { + return Task.FromResult(new Token(Decrement, this)); + } + + var tcs = new TaskCompletionSource(); + + if (cancellationToken.CanBeCanceled) { + cancellationToken.Register(Cancellation, tcs, false); + } + + _rootTcs.Task.ContinueWith(Continuation, tcs, cancellationToken, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); + + return tcs.Task; + } + + public bool TryReenter(out Task task) { + while (true) { + var count = _count; + if (count == 0) { + task = null; + return false; + } + + if (Interlocked.CompareExchange(ref _count, count + 1, count) == count) { + IAsyncReaderWriterLockToken token = new Token(Decrement, this); + task = Task.FromResult(token); + return true; + } + } + } + + private void Continuation(Task task, object state) + => ((TaskCompletionSource)state).TrySetResult(new Token(Decrement, this)); + + private void Cancellation(object state) { + if (((TaskCompletionSource) state).TrySetCanceled()) { + Decrement(); + } + } + + public void CompleteTasks() => _rootTcs.TrySetResult(true); + + public void RegisterWait(WriterLockSource writer, CancellationToken cancellationToken) { + Interlocked.Exchange(ref _writer, writer); + + CompleteTasks(); + + if (cancellationToken.IsCancellationRequested) { + CancelWaitReaders(cancellationToken); + } else if (_count == 0) { + writer.TryCompleteTask(); + } else if (cancellationToken.CanBeCanceled) { + cancellationToken.Register(CancelWaitReaders, cancellationToken, false); + } + } + + private void CancelWaitReaders(object state) { + if (!_writer.TryCancelTask((CancellationToken) state)) { + return; + } + + _host.CompleteReaderTasksIfRequired(_writer.NextWriter); + } + + private bool TryIncrement() { + // _writer != null means that current ReaderLockSource can't create any more readers + // see WriterLockAsync + if (_writer != null) { + return false; + } + + Interlocked.Increment(ref _count); + // If _writer != null became not null when _count was incremented, Decrement it back + if (_writer != null) { + Decrement(); + return false; + } + + return true; + } + + private void Decrement() { + var count = Interlocked.Decrement(ref _count); + + if (count == 0) { + _host.CompleteNextTask(_writer); + } + } + } + + private class WriterLockSource { + private readonly TaskCompletionSource _tcs; + private readonly AsyncReaderWriterLock _host; + private WriterLockSource _nextWriter; + private int _reentrancyCount; + + public Task Task => _tcs.Task; + public WriterLockSource NextWriter => _nextWriter; + public bool IsCompleted => _tcs.Task.IsCanceled || _reentrancyCount == 0; + + public WriterLockSource(AsyncReaderWriterLock host) { + _reentrancyCount = 1; + _host = host; + _tcs = new TaskCompletionSource(); + } + + public bool TrySetNext(out WriterLockSource next) { + if (_nextWriter != null) { + next = null; + return false; + } + + next = new WriterLockSource(_host); + return Interlocked.CompareExchange(ref _nextWriter, next, null) == null; + } + + public bool TryReenter(out Task task) { + while (true) { + var count = _reentrancyCount; + if (count == 0) { + task = null; + return false; + } + + if (Interlocked.CompareExchange(ref _reentrancyCount, count + 1, count) == count) { + IAsyncReaderWriterLockToken token = new Token(DecrementReentrancy, this); + task = System.Threading.Tasks.Task.FromResult(token); + return true; + } + } + } + + public bool TryCompleteTask() { + var isSet = _tcs.TrySetResult(new Token(DecrementReentrancy, this)); + if (isSet) { + Interlocked.Exchange(ref _host._lastAcquiredWriter, this); + } + return isSet; + } + + public bool TryCancelTask(CancellationToken cancellationToken) => _tcs.TrySetCanceled(cancellationToken); + + public void RegisterWait(CancellationToken cancellationToken) { + if (cancellationToken.IsCancellationRequested) { + _nextWriter.TryCancelTask(cancellationToken); + } + + if (cancellationToken.CanBeCanceled) { + cancellationToken.Register(CancelWait, cancellationToken, false); + } + } + + private void DecrementReentrancy() { + if (Interlocked.Decrement(ref _reentrancyCount) == 0) { + _host.CompleteNextTask(this); + } + } + + private void CancelWait(object state) { + if (_nextWriter.TryCancelTask((CancellationToken) state)) { + var writer = _host._lastAcquiredWriter; + _host.CompleteReaderTasksIfRequired(writer); + } + } + } + + private class Token : IAsyncReaderWriterLockToken { + private Action _dispose; + public ReentrancyToken Reentrancy { get; } + + public Token(Action dispose, WriterLockSource reentrancySource) { + _dispose = dispose; + Reentrancy = WriterLockTokenFactory.Create(reentrancySource); + } + + public Token(Action dispose, ReaderLockSource reentrancySource) { + _dispose = dispose; + Reentrancy = ReaderLockTokenFactory.Create(reentrancySource); + } + + public void Dispose() { + var dispose = Interlocked.Exchange(ref _dispose, null); + dispose?.Invoke(); + } + } + } +} \ No newline at end of file diff --git a/Microsoft.Common.Core/Threading/BackgroundThreadAwaitable.cs b/Microsoft.Common.Core/Threading/BackgroundThreadAwaitable.cs new file mode 100644 index 00000000..e0df1927 --- /dev/null +++ b/Microsoft.Common.Core/Threading/BackgroundThreadAwaitable.cs @@ -0,0 +1,10 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +namespace Microsoft.Common.Core.Threading { + public struct BackgroundThreadAwaitable { + public BackgroundThreadAwaiter GetAwaiter() { + return new BackgroundThreadAwaiter(); + } + } +} \ No newline at end of file diff --git a/Microsoft.Common.Core/Threading/BackgroundThreadAwaiter.cs b/Microsoft.Common.Core/Threading/BackgroundThreadAwaiter.cs new file mode 100644 index 00000000..65761f8d --- /dev/null +++ b/Microsoft.Common.Core/Threading/BackgroundThreadAwaiter.cs @@ -0,0 +1,28 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Threading; + +namespace Microsoft.Common.Core.Threading { + public struct BackgroundThreadAwaiter : ICriticalNotifyCompletion { + private static readonly WaitCallback WaitCallback = state => ((Action)state)(); + + public bool IsCompleted => TaskUtilities.IsOnBackgroundThread(); + + public void OnCompleted(Action continuation) { + Trace.Assert(continuation != null); + ThreadPool.QueueUserWorkItem(WaitCallback, continuation); + } + + public void UnsafeOnCompleted(Action continuation) { + Trace.Assert(continuation != null); + ThreadPool.UnsafeQueueUserWorkItem(WaitCallback, continuation); + } + + public void GetResult() { + } + } +} \ No newline at end of file diff --git a/Microsoft.Common.Core/Threading/BinaryAsyncLock.cs b/Microsoft.Common.Core/Threading/BinaryAsyncLock.cs new file mode 100644 index 00000000..946a38f5 --- /dev/null +++ b/Microsoft.Common.Core/Threading/BinaryAsyncLock.cs @@ -0,0 +1,199 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.Common.Core.Threading { + /// + /// BinaryAsyncLock is a helper primitive that can be used instead of SemaphoreSlim.WaitAsync + double-checked locking + /// + /// + /// After BinaryAsyncLock is created or reset, the first caller of will immediately get + /// that is not set. All other callers will either wait until is called and then will get , + /// or until until is called and next awaiting caller will get , + /// + public class BinaryAsyncLock { + private static readonly Task CompletedTask = Task.FromResult(new Token()); + private TokenSource _tail; + + public bool IsSet => _tail != null && _tail.IsSet; + + public BinaryAsyncLock(bool isSet = false) { + _tail = isSet ? new TokenSource(CompletedTask) : null; + } + + public Task WaitAsync(CancellationToken cancellationToken = default(CancellationToken)) { + while (true) { + if (cancellationToken.IsCancellationRequested) { + return Task.FromCanceled(cancellationToken); + } + + var oldTail = _tail; + if (oldTail != null && oldTail.IsSet) { + return oldTail.Task; + } + + TokenSource newTail; + if (oldTail == null) { + newTail = new TokenSource(this); + } else { + newTail = new TokenSource(); + if (oldTail.CompareExchangeNext(newTail, null) != null) { + // Another thread has provided a new tail + continue; + } + } + + if (Interlocked.CompareExchange(ref _tail, newTail, oldTail) == oldTail) { + if (cancellationToken.CanBeCanceled) { + newTail.RegisterCancellation(cancellationToken); + } + + return newTail.Task; + } + } + } + + /// + /// Creates a task that is completed when lock is in Unset state and no reset waiters are in front of current one + /// and all tokens that were issued prior this one are released + /// + /// + /// Method tries to replace current tail with the new Reset TokenSource (when its task is completed, lock will be in Unset state), + /// and if it fails, it means that another thread has updated the tail, so method tries again with that new tail. + /// If there is no tail, it is considered that lock is in the Unset state already, but no one has requested a token yet + /// If there is a tail, method tries to set its to the new TokenSource, + /// and if it fails, it means that another thread has updated the property or the tail, so method tries again with that new tail. + /// If replacing tail succeeded, method stops adding Set tokens. If there are no unreleased set tokens, new tail task is set to completed. + /// + public Task ResetAsync(CancellationToken cancellationToken = default(CancellationToken)) { + while (true) { + if (cancellationToken.IsCancellationRequested) { + return Task.FromCanceled(cancellationToken); + } + + var oldTail = _tail; + var newTail = oldTail == null || oldTail.IsSet ? new TokenSource(this) : new TokenSource(true); + + if (oldTail?.CompareExchangeNext(newTail, null) != null) { + // Another thread has provided a new tail + continue; + } + + if (Interlocked.CompareExchange(ref _tail, newTail, oldTail) == oldTail) { + if (cancellationToken.CanBeCanceled) { + newTail.RegisterCancellation(cancellationToken); + } + + return newTail.Task; + } + } + } + + public void EnqueueReset() { + ResetAsync().ContinueWith(t => { + if (t.Status == TaskStatus.RanToCompletion) { + t.Result.Reset(); + } + }); + } + + private void TokenSet(TokenSource tokenSource) { + while (tokenSource != null) { + Interlocked.CompareExchange(ref _tail, new TokenSource(CompletedTask), tokenSource); + + tokenSource = tokenSource.Next; + if (tokenSource?.Tcs == null) { + return; + } + + if (tokenSource.ResetOnSet && tokenSource.Tcs.TrySetResult(new Token(this, tokenSource))) { + return; + } + + tokenSource.Tcs.TrySetResult(new Token()); + } + } + + private void TokenReset(TokenSource tokenSource, bool setIfLast) { + while (tokenSource != null) { + var newTail = setIfLast ? new TokenSource(CompletedTask) : null; + Interlocked.CompareExchange(ref _tail, newTail, tokenSource); + + tokenSource = tokenSource.Next; + if (tokenSource?.Tcs == null) { + return; + } + + // Try to reset tokenSource. If tokenSource.Tcs is canceled, try set result for the next one. + if (tokenSource.Tcs.TrySetResult(new Token(this, tokenSource))) { + return; + } + } + } + + private class Token : IBinaryAsyncLockToken { + private readonly BinaryAsyncLock _binaryAsyncLock; + private readonly TokenSource _tokenSource; + + public Token() { + IsSet = true; + } + + public Token(BinaryAsyncLock binaryAsyncLock, TokenSource tokenSource) { + _binaryAsyncLock = binaryAsyncLock; + _tokenSource = tokenSource; + IsSet = false; + } + + public bool IsSet { get; } + public void Reset() => _binaryAsyncLock?.TokenReset(_tokenSource, false); + public void Set() => _binaryAsyncLock?.TokenSet(_tokenSource); + public void SetIfLast() => _binaryAsyncLock?.TokenReset(_tokenSource, true); + } + + private class TokenSource { + private TokenSource _next; + + public TaskCompletionSource Tcs { get; } + public Task Task { get; } + public TokenSource Next => _next; + public bool ResetOnSet { get; } + public bool IsSet => Task.Status == TaskStatus.RanToCompletion && Task.Result.IsSet; + + public TokenSource(BinaryAsyncLock binaryAsyncLock) { + Task = System.Threading.Tasks.Task.FromResult(new Token(binaryAsyncLock, this)); + } + + public TokenSource(Task task) { + Task = task; + } + + public TokenSource(bool resetOnSet = false) { + ResetOnSet = resetOnSet; + Tcs = new TaskCompletionSource(); + Task = Tcs.Task; + } + + public TokenSource CompareExchangeNext(TokenSource value, TokenSource comparand) + => Interlocked.CompareExchange(ref _next, value, comparand); + + public void RegisterCancellation(CancellationToken cancellationToken) { + cancellationToken.Register(CancelTcs, cancellationToken); + } + + private void CancelTcs(object state) { + CancellationToken ct = (CancellationToken) state; + Tcs?.TrySetCanceled(ct); + } + } + } + + public interface IBinaryAsyncLockToken { + bool IsSet { get; } + void Reset(); + void Set(); + void SetIfLast(); + } +} diff --git a/Microsoft.Common.Core/Threading/DelayedAsyncAction.cs b/Microsoft.Common.Core/Threading/DelayedAsyncAction.cs new file mode 100644 index 00000000..6296c29e --- /dev/null +++ b/Microsoft.Common.Core/Threading/DelayedAsyncAction.cs @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.Common.Core.Threading { + + public class DelayedAsyncAction { + private readonly int _timeout; + private readonly Timer _timer; + private Func _action; + + /// + /// DelayedAsyncAction invokes after specified when is called. + /// If is called again before , previous invocation request is cancelled and will be invoked only once + /// + public DelayedAsyncAction(int timeout = 0, Func action = null) { + if (timeout < 0) { + throw new ArgumentOutOfRangeException(nameof(timeout)); + } + + _action = action; + _timeout = timeout; + _timer = new Timer(Callback, this, -1, -1); + } + + public void Invoke(Func action = null) { + if (action != null) { + Volatile.Write(ref _action, action); + } + _timer.Change(_timeout, -1); + } + + private static TimerCallback Callback { get; } = s => { + var delayedAction = ((DelayedAsyncAction) s); + var action = Volatile.Read(ref delayedAction._action); + action().DoNotWait(); + }; + } +} \ No newline at end of file diff --git a/Microsoft.Common.Core/Threading/IAsyncReaderWriterLockToken.cs b/Microsoft.Common.Core/Threading/IAsyncReaderWriterLockToken.cs new file mode 100644 index 00000000..66756f36 --- /dev/null +++ b/Microsoft.Common.Core/Threading/IAsyncReaderWriterLockToken.cs @@ -0,0 +1,7 @@ +using System; + +namespace Microsoft.Common.Core.Threading { + public interface IAsyncReaderWriterLockToken : IDisposable { + ReentrancyToken Reentrancy { get; } + } +} \ No newline at end of file diff --git a/Microsoft.Common.Core/Threading/IMainThread.cs b/Microsoft.Common.Core/Threading/IMainThread.cs new file mode 100644 index 00000000..5a994493 --- /dev/null +++ b/Microsoft.Common.Core/Threading/IMainThread.cs @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; + +namespace Microsoft.Common.Core.Threading { + public interface IMainThread { + int ThreadId { get; } + void Post(Action action); + } +} \ No newline at end of file diff --git a/Microsoft.Common.Core/Threading/IReentrancyTokenFactory.cs b/Microsoft.Common.Core/Threading/IReentrancyTokenFactory.cs new file mode 100644 index 00000000..5bfbb521 --- /dev/null +++ b/Microsoft.Common.Core/Threading/IReentrancyTokenFactory.cs @@ -0,0 +1,6 @@ +namespace Microsoft.Common.Core.Threading { + internal interface IReentrancyTokenFactory where TSource : class { + TSource GetSource(ReentrancyToken token); + ReentrancyToken Create(TSource source); + } +} \ No newline at end of file diff --git a/Microsoft.Common.Core/Threading/MainThreadAwaitable.cs b/Microsoft.Common.Core/Threading/MainThreadAwaitable.cs new file mode 100644 index 00000000..466b245b --- /dev/null +++ b/Microsoft.Common.Core/Threading/MainThreadAwaitable.cs @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +namespace Microsoft.Common.Core.Threading { + public struct MainThreadAwaitable { + private readonly IMainThread _mainThread; + + public MainThreadAwaitable(IMainThread mainThread) { + _mainThread = mainThread; + } + + public MainThreadAwaiter GetAwaiter() { + return new MainThreadAwaiter(_mainThread); + } + } +} \ No newline at end of file diff --git a/Microsoft.Common.Core/Threading/MainThreadAwaiter.cs b/Microsoft.Common.Core/Threading/MainThreadAwaiter.cs new file mode 100644 index 00000000..26ff5e20 --- /dev/null +++ b/Microsoft.Common.Core/Threading/MainThreadAwaiter.cs @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Threading; + +namespace Microsoft.Common.Core.Threading { + public struct MainThreadAwaiter : ICriticalNotifyCompletion { + private readonly IMainThread _mainThread; + + public MainThreadAwaiter(IMainThread mainThread) { + _mainThread = mainThread; + } + + public bool IsCompleted => Thread.CurrentThread.ManagedThreadId == _mainThread.ThreadId; + + public void OnCompleted(Action continuation) { + Trace.Assert(continuation != null); + _mainThread.Post(continuation); + } + + public void UnsafeOnCompleted(Action continuation) { + Trace.Assert(continuation != null); + _mainThread.Post(continuation); + } + + public void GetResult() { + if (Thread.CurrentThread.ManagedThreadId != _mainThread.ThreadId) { + throw new InvalidOperationException(); + } + } + } +} \ No newline at end of file diff --git a/Microsoft.Common.Core/Threading/ReentrancyToken.cs b/Microsoft.Common.Core/Threading/ReentrancyToken.cs new file mode 100644 index 00000000..0fcff2fc --- /dev/null +++ b/Microsoft.Common.Core/Threading/ReentrancyToken.cs @@ -0,0 +1,21 @@ +namespace Microsoft.Common.Core.Threading { + public struct ReentrancyToken { + private readonly object _source; + + private ReentrancyToken(object source) { + _source = source; + } + + internal static IReentrancyTokenFactory CreateFactory() where TSource : class => new Factory(); + + private class Factory : IReentrancyTokenFactory where TSource : class { + public TSource GetSource(ReentrancyToken token) { + return token._source as TSource; + } + + public ReentrancyToken Create(TSource source) { + return new ReentrancyToken(source); + } + } + } +} \ No newline at end of file diff --git a/Microsoft.Common.Core/Versions/Toolset.cs b/Microsoft.Common.Core/Versions/Toolset.cs new file mode 100644 index 00000000..711889b5 --- /dev/null +++ b/Microsoft.Common.Core/Versions/Toolset.cs @@ -0,0 +1,13 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +namespace Microsoft.Common.Core { + public static class Toolset { +#if VS14 + public const string Version = "14.0"; +#endif +#if VS15 + public const string Version = "15.0"; +#endif + } +} diff --git a/Microsoft.Common.Core/project.json b/Microsoft.Common.Core/project.json new file mode 100644 index 00000000..6e9135e7 --- /dev/null +++ b/Microsoft.Common.Core/project.json @@ -0,0 +1,13 @@ +{ + "dependencies": { + "MicroBuild.Core": "0.2.0", + "Microsoft.Extensions.FileSystemGlobbing": "1.0.0", + "Microsoft.Tpl.Dataflow": "4.5.24" + }, + "frameworks": { + "net46": { } + }, + "runtimes": { + "win": { } + } +} \ No newline at end of file diff --git a/Microsoft.VisualStudio.Project/AllFilesProjectElement.cs b/Microsoft.VisualStudio.Project/AllFilesProjectElement.cs deleted file mode 100644 index 903137a8..00000000 --- a/Microsoft.VisualStudio.Project/AllFilesProjectElement.cs +++ /dev/null @@ -1,53 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - - -namespace Microsoft.VisualStudioTools.Project { - /// - /// Represents a project element which lives on disk and is visible when Show All Files - /// is enabled. - /// - sealed class AllFilesProjectElement : VirtualProjectElement { - private string _itemType; - - public AllFilesProjectElement(string path, string itemType, CommonProjectNode project) - : base(project) { - Rename(path); - } - - public override bool IsExcluded { - get { - return true; - } - } - - public new CommonProjectNode ItemProject { - get { - return (CommonProjectNode)base.ItemProject; - } - } - - protected override string ItemType { - get { - return _itemType; - } - set { - _itemType = value; - OnItemTypeChanged(); - } - } - } -} diff --git a/Microsoft.VisualStudio.Project/AssemblyReferenceNode.cs b/Microsoft.VisualStudio.Project/AssemblyReferenceNode.cs deleted file mode 100644 index 5df33b08..00000000 --- a/Microsoft.VisualStudio.Project/AssemblyReferenceNode.cs +++ /dev/null @@ -1,411 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Diagnostics; -using System.IO; -using System.Reflection; -using System.Runtime.InteropServices; -using Microsoft.VisualStudio.Shell.Interop; - -namespace Microsoft.VisualStudioTools.Project { - internal class AssemblyReferenceNode : ReferenceNode { - #region fieds - /// - /// The name of the assembly this refernce represents - /// - private System.Reflection.AssemblyName assemblyName; - private AssemblyName resolvedAssemblyName; - - private string assemblyPath = String.Empty; - - /// - /// Defines the listener that would listen on file changes on the nested project node. - /// - private FileChangeManager fileChangeListener; - - /// - /// A flag for specifying if the object was disposed. - /// - private bool isDisposed; - #endregion - - #region properties - /// - /// The name of the assembly this reference represents. - /// - /// - internal System.Reflection.AssemblyName AssemblyName { - get { - return this.assemblyName; - } - } - - /// - /// Returns the name of the assembly this reference refers to on this specific - /// machine. It can be different from the AssemblyName property because it can - /// be more specific. - /// - internal System.Reflection.AssemblyName ResolvedAssembly { - get { return resolvedAssemblyName; } - } - - public override string Url { - get { - return this.assemblyPath; - } - } - - public override string Caption { - get { - return this.assemblyName.Name; - } - } - - private Automation.OAAssemblyReference assemblyRef; - internal override object Object { - get { - if (null == assemblyRef) { - assemblyRef = new Automation.OAAssemblyReference(this); - } - return assemblyRef; - } - } - #endregion - - #region ctors - /// - /// Constructor for the ReferenceNode - /// - public AssemblyReferenceNode(ProjectNode root, ProjectElement element) - : base(root, element) { - this.GetPathNameFromProjectFile(); - - this.InitializeFileChangeEvents(); - - if (File.Exists(assemblyPath)) { - this.fileChangeListener.ObserveItem(this.assemblyPath); - } - - string include = this.ItemNode.GetMetadata(ProjectFileConstants.Include); - - this.CreateFromAssemblyName(new System.Reflection.AssemblyName(include)); - } - - /// - /// Constructor for the AssemblyReferenceNode - /// - public AssemblyReferenceNode(ProjectNode root, string assemblyPath) - : base(root) { - // Validate the input parameters. - if (null == root) { - throw new ArgumentNullException("root"); - } - if (string.IsNullOrEmpty(assemblyPath)) { - throw new ArgumentNullException("assemblyPath"); - } - - this.InitializeFileChangeEvents(); - - // The assemblyPath variable can be an actual path on disk or a generic assembly name. - if (File.Exists(assemblyPath)) { - // The assemblyPath parameter is an actual file on disk; try to load it. - this.assemblyName = System.Reflection.AssemblyName.GetAssemblyName(assemblyPath); - this.assemblyPath = assemblyPath; - - // We register with listeningto chnages onteh path here. The rest of teh cases will call into resolving the assembly and registration is done there. - this.fileChangeListener.ObserveItem(this.assemblyPath); - } else { - // The file does not exist on disk. This can be because the file / path is not - // correct or because this is not a path, but an assembly name. - // Try to resolve the reference as an assembly name. - this.CreateFromAssemblyName(new System.Reflection.AssemblyName(assemblyPath)); - } - } - #endregion - - #region methods - - /// - /// Links a reference node to the project and hierarchy. - /// - protected override void BindReferenceData() { - UIThread.MustBeCalledFromUIThread(); - - Debug.Assert(this.assemblyName != null, "The AssemblyName field has not been initialized"); - - // If the item has not been set correctly like in case of a new reference added it now. - // The constructor for the AssemblyReference node will create a default project item. In that case the Item is null. - // We need to specify here the correct project element. - if (this.ItemNode == null || this.ItemNode is VirtualProjectElement) { - this.ItemNode = new MsBuildProjectElement(this.ProjectMgr, this.assemblyName.FullName, ProjectFileConstants.Reference); - } - - // Set the basic information we know about - this.ItemNode.SetMetadata(ProjectFileConstants.Name, this.assemblyName.Name); - this.ItemNode.SetMetadata(ProjectFileConstants.AssemblyName, Path.GetFileName(this.assemblyPath)); - - this.SetReferenceProperties(); - } - - /// - /// Disposes the node - /// - /// - protected override void Dispose(bool disposing) { - if (this.isDisposed) { - return; - } - - try { - this.UnregisterFromFileChangeService(); - } finally { - base.Dispose(disposing); - this.isDisposed = true; - } - } - - private void CreateFromAssemblyName(AssemblyName name) { - this.assemblyName = name; - - // Use MsBuild to resolve the assemblyname - this.ResolveAssemblyReference(); - - if (String.IsNullOrEmpty(this.assemblyPath) && (this.ItemNode is MsBuildProjectElement)) { - // Try to get the assmbly name from the hintpath. - this.GetPathNameFromProjectFile(); - if (this.assemblyPath == null) { - // Try to get the assembly name from the path - this.assemblyName = System.Reflection.AssemblyName.GetAssemblyName(this.assemblyPath); - } - } - if (null == resolvedAssemblyName) { - resolvedAssemblyName = assemblyName; - } - } - - /// - /// Checks if an assembly is already added. The method parses all references and compares the full assemblynames, or the location of the assemblies to decide whether two assemblies are the same. - /// - /// true if the assembly has already been added. - protected override bool IsAlreadyAdded() { - ReferenceContainerNode referencesFolder = this.ProjectMgr.GetReferenceContainer() as ReferenceContainerNode; - Debug.Assert(referencesFolder != null, "Could not find the References node"); - if (referencesFolder == null) { - // Return true so that our caller does not try and add us. - return true; - } - - bool shouldCheckPath = !string.IsNullOrEmpty(this.Url); - - for (HierarchyNode n = referencesFolder.FirstChild; n != null; n = n.NextSibling) { - AssemblyReferenceNode assemblyRefererenceNode = n as AssemblyReferenceNode; - if (null != assemblyRefererenceNode) { - // We will check if the full assemblynames are the same or if the Url of the assemblies is the same. - if (String.Compare(assemblyRefererenceNode.AssemblyName.FullName, this.assemblyName.FullName, StringComparison.OrdinalIgnoreCase) == 0 || - (shouldCheckPath && CommonUtils.IsSamePath(assemblyRefererenceNode.Url, this.Url))) { - return true; - } - } - } - - return false; - } - - /// - /// Determines if this is node a valid node for painting the default reference icon. - /// - /// - protected override bool CanShowDefaultIcon() { - return File.Exists(assemblyPath); - } - - private void GetPathNameFromProjectFile() { - string result = this.ItemNode.GetMetadata(ProjectFileConstants.HintPath); - if (String.IsNullOrEmpty(result)) { - result = this.ItemNode.GetMetadata(ProjectFileConstants.AssemblyName); - if (String.IsNullOrEmpty(result)) { - this.assemblyPath = String.Empty; - } else if (!result.EndsWith(".dll", StringComparison.OrdinalIgnoreCase)) { - result += ".dll"; - this.assemblyPath = result; - } - } else { - this.assemblyPath = CommonUtils.GetAbsoluteFilePath(this.ProjectMgr.ProjectHome, result); - } - } - - protected override void ResolveReference() { - this.ResolveAssemblyReference(); - } - - private void SetHintPathAndPrivateValue() { - - // Private means local copy; we want to know if it is already set to not override the default - string privateValue = this.ItemNode.GetMetadata(ProjectFileConstants.Private); - - // Get the list of items which require HintPath - var references = this.ProjectMgr.CurrentConfig.GetItems(MsBuildGeneratedItemType.ReferenceCopyLocalPaths); - - - // Now loop through the generated References to find the corresponding one - foreach (var reference in references) { - string fileName = Path.GetFileNameWithoutExtension(reference.EvaluatedInclude); - if (String.Compare(fileName, this.assemblyName.Name, StringComparison.OrdinalIgnoreCase) == 0) { - // We found it, now set some properties based on this. - - // Remove the HintPath, we will re-add it below if it is needed - if (!String.IsNullOrEmpty(this.assemblyPath)) { - this.ItemNode.SetMetadata(ProjectFileConstants.HintPath, null); - } - - string hintPath = reference.GetMetadataValue(ProjectFileConstants.HintPath); - if (!String.IsNullOrEmpty(hintPath)) { - hintPath = CommonUtils.GetRelativeFilePath(this.ProjectMgr.ProjectHome, hintPath); - - this.ItemNode.SetMetadata(ProjectFileConstants.HintPath, hintPath); - // If this is not already set, we default to true - if (String.IsNullOrEmpty(privateValue)) { - this.ItemNode.SetMetadata(ProjectFileConstants.Private, true.ToString()); - } - } - break; - } - - } - - } - - /// - /// This function ensures that some properies of the reference are set. - /// - private void SetReferenceProperties() { - UIThread.MustBeCalledFromUIThread(); - - // Set a default HintPath for msbuild to be able to resolve the reference. - this.ItemNode.SetMetadata(ProjectFileConstants.HintPath, this.assemblyPath); - - // Resolve assembly referernces. This is needed to make sure that properties like the full path - // to the assembly or the hint path are set. - if (!ProjectMgr.BuildProject.Targets.ContainsKey(MsBuildTarget.ResolveAssemblyReferences)) { - return; - } - - if (this.ProjectMgr.Build(MsBuildTarget.ResolveAssemblyReferences) != MSBuildResult.Successful) { - return; - } - - // Check if we have to resolve again the path to the assembly. - if (string.IsNullOrEmpty(this.assemblyPath)) { - ResolveReference(); - } - - // Make sure that the hint path if set (if needed). - SetHintPathAndPrivateValue(); - } - - /// - /// Does the actual job of resolving an assembly reference. We need a private method that does not violate - /// calling virtual method from the constructor. - /// - private void ResolveAssemblyReference() { - if (this.ProjectMgr == null || this.ProjectMgr.IsClosed) { - return; - } - - var group = this.ProjectMgr.CurrentConfig.GetItems(ProjectFileConstants.ReferencePath); - foreach (var item in group) { - string fullPath = CommonUtils.GetAbsoluteFilePath(this.ProjectMgr.ProjectHome, item.EvaluatedInclude); - - System.Reflection.AssemblyName name = System.Reflection.AssemblyName.GetAssemblyName(fullPath); - - // Try with full assembly name and then with weak assembly name. - if (String.Equals(name.FullName, this.assemblyName.FullName, StringComparison.OrdinalIgnoreCase) || String.Equals(name.Name, this.assemblyName.Name, StringComparison.OrdinalIgnoreCase)) { - if (!CommonUtils.IsSamePath(fullPath, this.assemblyPath)) { - // set the full path now. - this.assemblyPath = fullPath; - - // We have a new item to listen too, since the assembly reference is resolved from a different place. - this.fileChangeListener.ObserveItem(this.assemblyPath); - } - - this.resolvedAssemblyName = name; - - // No hint path is needed since the assembly path will always be resolved. - return; - } - } - } - - /// - /// Registers with File change events - /// - private void InitializeFileChangeEvents() { - this.fileChangeListener = new FileChangeManager(this.ProjectMgr.Site); - this.fileChangeListener.FileChangedOnDisk += this.OnAssemblyReferenceChangedOnDisk; - } - - /// - /// Unregisters this node from file change notifications. - /// - private void UnregisterFromFileChangeService() { - this.fileChangeListener.FileChangedOnDisk -= this.OnAssemblyReferenceChangedOnDisk; - this.fileChangeListener.Dispose(); - } - - /// - /// Event callback. Called when one of the assembly file is changed. - /// - /// The FileChangeManager object. - /// Event args containing the file name that was updated. - protected virtual void OnAssemblyReferenceChangedOnDisk(object sender, FileChangedOnDiskEventArgs e) { - Debug.Assert(e != null, "No event args specified for the FileChangedOnDisk event"); - if (e == null) { - return; - } - - // We only care about file deletes, so check for one before enumerating references. - if ((e.FileChangeFlag & _VSFILECHANGEFLAGS.VSFILECHG_Del) == 0) { - return; - } - - - if (CommonUtils.IsSamePath(e.FileName, this.assemblyPath)) { - ProjectMgr.OnInvalidateItems(this.Parent); - } - } - - /// - /// Overridden method. The method updates the build dependency list before removing the node from the hierarchy. - /// - public override void Remove(bool removeFromStorage) { - if (this.ProjectMgr == null) { - return; - } - base.RemoveNonDocument(removeFromStorage); - this.ItemNode.RemoveFromProjectFile(); - - // Notify hierarchy event listeners that items have been invalidated - ProjectMgr.OnInvalidateItems(this); - - // Dispose the node now that is deleted. - Dispose(true); - } - - - #endregion - } -} diff --git a/Microsoft.VisualStudio.Project/Attributes.cs b/Microsoft.VisualStudio.Project/Attributes.cs deleted file mode 100644 index 072cca19..00000000 --- a/Microsoft.VisualStudio.Project/Attributes.cs +++ /dev/null @@ -1,65 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.ComponentModel; - -namespace Microsoft.VisualStudioTools.Project { - [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field, Inherited = false, AllowMultiple = false)] - internal sealed class SRDisplayNameAttribute : DisplayNameAttribute { - string _name; - - public SRDisplayNameAttribute(string name) { - _name = name; - } - - public override string DisplayName { - get { - return SR.GetString(_name); - } - } - } - - [AttributeUsage(AttributeTargets.All)] - internal sealed class SRDescriptionAttribute : DescriptionAttribute { - private bool _replaced; - - public SRDescriptionAttribute(string description) - : base(description) { - } - - public override string Description { - get { - if (!_replaced) { - _replaced = true; - DescriptionValue = SR.GetString(base.Description); - } - return base.Description; - } - } - } - - [AttributeUsage(AttributeTargets.All)] - internal sealed class SRCategoryAttribute : CategoryAttribute { - public SRCategoryAttribute(string category) - : base(category) { - } - - protected override string GetLocalizedString(string value) { - return SR.GetString(value); - } - } -} diff --git a/Microsoft.VisualStudio.Project/Automation/AutomationScope.cs b/Microsoft.VisualStudio.Project/Automation/AutomationScope.cs deleted file mode 100644 index 4d2deabe..00000000 --- a/Microsoft.VisualStudio.Project/Automation/AutomationScope.cs +++ /dev/null @@ -1,97 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using Microsoft.VisualStudio.Shell.Interop; -using ErrorHandler = Microsoft.VisualStudio.ErrorHandler; - -namespace Microsoft.VisualStudioTools.Project.Automation -{ - /// - /// Helper class that handle the scope of an automation function. - /// It should be used inside a "using" directive to define the scope of the - /// automation function and make sure that the ExitAutomation method is called. - /// - internal sealed class AutomationScope : IDisposable - { - private IVsExtensibility3 extensibility; - private bool inAutomation; - private bool isDisposed; - - /// - /// Defines the beginning of the scope of an automation function. This constuctor - /// calls EnterAutomationFunction to signal the Shell that the current function is - /// changing the status of the automation objects. - /// - public AutomationScope(IServiceProvider provider) - { - Utilities.ArgumentNotNull("provider", provider); - - extensibility = provider.GetService(typeof(EnvDTE.IVsExtensibility)) as IVsExtensibility3; - if (null == extensibility) - { - throw new InvalidOperationException(); - } - ErrorHandler.ThrowOnFailure(extensibility.EnterAutomationFunction()); - inAutomation = true; - } - - /// - /// Ends the scope of the automation function. This function is also called by the - /// Dispose method. - /// - public void ExitAutomation() - { - if (inAutomation) - { - ErrorHandler.ThrowOnFailure(extensibility.ExitAutomationFunction()); - inAutomation = false; - } - } - - /// - /// Gets the IVsExtensibility3 interface used in the automation function. - /// - public IVsExtensibility3 Extensibility - { - get { return extensibility; } - } - - /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// - public void Dispose() - { - this.Dispose(true); - GC.SuppressFinalize(this); - } - - #region IDisposable Members - private void Dispose(bool disposing) - { - if (!this.isDisposed) - { - if (disposing) - { - ExitAutomation(); - } - - this.isDisposed = true; - } - } - #endregion - } -} diff --git a/Microsoft.VisualStudio.Project/Automation/OAFileItem.cs b/Microsoft.VisualStudio.Project/Automation/OAFileItem.cs deleted file mode 100644 index 161d7ead..00000000 --- a/Microsoft.VisualStudio.Project/Automation/OAFileItem.cs +++ /dev/null @@ -1,318 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Diagnostics.CodeAnalysis; -using System.Globalization; -using System.IO; -using System.Runtime.InteropServices; -using EnvDTE; -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.Shell; -using Microsoft.VisualStudio.Shell.Interop; -using VSConstants = Microsoft.VisualStudio.VSConstants; - -namespace Microsoft.VisualStudioTools.Project.Automation { - /// - /// Represents an automation object for a file in a project - /// - [ComVisible(true)] - public class OAFileItem : OAProjectItem { - #region ctors - internal OAFileItem(OAProject project, FileNode node) - : base(project, node) { - } - - #endregion - - private new FileNode Node { - get { - return (FileNode)base.Node; - } - } - - public override string Name { - get { - return this.Node.FileName; - } - set { - UIThread.Invoke(() => base.Name = value); - } - } - - #region overridden methods - /// - /// Returns the dirty state of the document. - /// - /// Is thrown if the project is closed or it the service provider attached to the project is invalid. - /// Is thrown if the dirty state cannot be retrived. - public override bool IsDirty { - get { - CheckProjectIsValid(); - - bool isDirty = false; - - using (AutomationScope scope = new AutomationScope(this.Node.ProjectMgr.Site)) { - UIThread.Invoke(() => { - DocumentManager manager = this.Node.GetDocumentManager(); - Utilities.CheckNotNull(manager); - - isDirty = manager.IsDirty; - }); - } - return isDirty; - } - - } - - /// - /// Gets the Document associated with the item, if one exists. - /// - public override EnvDTE.Document Document { - get { - CheckProjectIsValid(); - - EnvDTE.Document document = null; - - using (AutomationScope scope = new AutomationScope(this.Node.ProjectMgr.Site)) { - UIThread.Invoke(() => { - IVsUIHierarchy hier; - uint itemid; - - IVsWindowFrame windowFrame; - - VsShellUtilities.IsDocumentOpen(this.Node.ProjectMgr.Site, this.Node.Url, VSConstants.LOGVIEWID_Any, out hier, out itemid, out windowFrame); - - if (windowFrame != null) { - object var; - ErrorHandler.ThrowOnFailure(windowFrame.GetProperty((int)__VSFPROPID.VSFPROPID_DocCookie, out var)); - object documentAsObject; - ErrorHandler.ThrowOnFailure(scope.Extensibility.GetDocumentFromDocCookie((int)var, out documentAsObject)); - Utilities.CheckNotNull(documentAsObject); - - document = (Document)documentAsObject; - } - }); - } - - return document; - } - } - - - /// - /// Opens the file item in the specified view. - /// - /// Specifies the view kind in which to open the item (file) - /// Window object - public override EnvDTE.Window Open(string viewKind) { - CheckProjectIsValid(); - - IVsWindowFrame windowFrame = null; - IntPtr docData = IntPtr.Zero; - - using (AutomationScope scope = new AutomationScope(this.Node.ProjectMgr.Site)) { - UIThread.Invoke(() => { - try { - // Validate input params - Guid logicalViewGuid = VSConstants.LOGVIEWID_Primary; - try { - if (!(String.IsNullOrEmpty(viewKind))) { - logicalViewGuid = new Guid(viewKind); - } - } catch (FormatException) { - // Not a valid guid - throw new ArgumentException(SR.GetString(SR.ParameterMustBeAValidGuid), "viewKind"); - } - - uint itemid; - IVsHierarchy ivsHierarchy; - uint docCookie; - IVsRunningDocumentTable rdt = this.Node.ProjectMgr.Site.GetService(typeof(SVsRunningDocumentTable)) as IVsRunningDocumentTable; - if (rdt == null) { - throw new InvalidOperationException("Could not get running document table from the services exposed by this project"); - } - - ErrorHandler.ThrowOnFailure(rdt.FindAndLockDocument((uint)_VSRDTFLAGS.RDT_NoLock, this.Node.Url, out ivsHierarchy, out itemid, out docData, out docCookie)); - - // Open the file using the IVsProject interface - // We get the outer hierarchy so that projects can customize opening. - var project = Node.ProjectMgr.GetOuterInterface(); - ErrorHandler.ThrowOnFailure(project.OpenItem(Node.ID, ref logicalViewGuid, docData, out windowFrame)); - } finally { - if (docData != IntPtr.Zero) { - Marshal.Release(docData); - } - } - }); - } - - // Get the automation object and return it - return ((windowFrame != null) ? VsShellUtilities.GetWindowObject(windowFrame) : null); - } - - /// - /// Saves the project item. - /// - /// The name with which to save the project or project item. - /// Is thrown if the save operation failes. - /// Is thrown if fileName is null. - public override void Save(string fileName) { - UIThread.Invoke(() => { - this.DoSave(false, fileName); - }); - } - - /// - /// Saves the project item. - /// - /// The file name with which to save the solution, project, or project item. If the file exists, it is overwritten - /// true if the rename was successful. False if Save as failes - public override bool SaveAs(string fileName) { - try { - UIThread.Invoke(() => { - this.DoSave(true, fileName); - }); - } catch (InvalidOperationException) { - return false; - } catch (COMException) { - return false; - } - return true; - - } - - /// - /// Gets a value indicating whether the project item is open in a particular view type. - /// - /// A Constants.vsViewKind* indicating the type of view to check./param> - /// A Boolean value indicating true if the project is open in the given view type; false if not. - public override bool get_IsOpen(string viewKind) { - CheckProjectIsValid(); - - // Validate input params - Guid logicalViewGuid = VSConstants.LOGVIEWID_Primary; - try { - if (!(String.IsNullOrEmpty(viewKind))) { - logicalViewGuid = new Guid(viewKind); - } - } catch (FormatException) { - // Not a valid guid - throw new ArgumentException(SR.GetString(SR.ParameterMustBeAValidGuid), "viewKind"); - } - - bool isOpen = false; - - using (AutomationScope scope = new AutomationScope(this.Node.ProjectMgr.Site)) { - UIThread.Invoke(() => { - IVsUIHierarchy hier; - uint itemid; - - IVsWindowFrame windowFrame; - - isOpen = VsShellUtilities.IsDocumentOpen(this.Node.ProjectMgr.Site, this.Node.Url, logicalViewGuid, out hier, out itemid, out windowFrame); - }); - } - - return isOpen; - } - - /// - /// Gets the ProjectItems for the object. - /// - public override ProjectItems ProjectItems { - get { - return UIThread.Invoke(() => { - if (this.Project.ProjectNode.CanFileNodesHaveChilds) - return new OAProjectItems(this.Project, this.Node); - else - return base.ProjectItems; - }); - } - } - - - #endregion - - #region helpers - /// - /// Saves or Save As the file - /// - /// Flag determining which Save method called , the SaveAs or the Save. - /// The name of the project file. - private void DoSave(bool isCalledFromSaveAs, string fileName) { - Utilities.ArgumentNotNull("fileName", fileName); - - CheckProjectIsValid(); - - using (AutomationScope scope = new AutomationScope(this.Node.ProjectMgr.Site)) { - - UIThread.Invoke(() => { - IntPtr docData = IntPtr.Zero; - - try { - IVsRunningDocumentTable rdt = this.Node.ProjectMgr.Site.GetService(typeof(SVsRunningDocumentTable)) as IVsRunningDocumentTable; - if (rdt == null) { - throw new InvalidOperationException("Could not get running document table from the services exposed by this project"); - } - - // First we see if someone else has opened the requested view of the file. - uint itemid; - IVsHierarchy ivsHierarchy; - uint docCookie; - int canceled; - string url = this.Node.Url; - - ErrorHandler.ThrowOnFailure(rdt.FindAndLockDocument((uint)_VSRDTFLAGS.RDT_NoLock, url, out ivsHierarchy, out itemid, out docData, out docCookie)); - - // If an empty file name is passed in for Save then make the file name the project name. - if (!isCalledFromSaveAs && fileName.Length == 0) { - ErrorHandler.ThrowOnFailure(this.Node.ProjectMgr.SaveItem(VSSAVEFLAGS.VSSAVE_SilentSave, url, this.Node.ID, docData, out canceled)); - } else { - Utilities.ValidateFileName(this.Node.ProjectMgr.Site, fileName); - - // Compute the fullpath from the directory of the existing Url. - string fullPath = CommonUtils.GetAbsoluteFilePath(Path.GetDirectoryName(url), fileName); - - if (!isCalledFromSaveAs) { - if (!CommonUtils.IsSamePath(this.Node.Url, fullPath)) { - throw new InvalidOperationException(); - } - - ErrorHandler.ThrowOnFailure(this.Node.ProjectMgr.SaveItem(VSSAVEFLAGS.VSSAVE_SilentSave, fullPath, this.Node.ID, docData, out canceled)); - } else { - ErrorHandler.ThrowOnFailure(this.Node.ProjectMgr.SaveItem(VSSAVEFLAGS.VSSAVE_SilentSave, fullPath, this.Node.ID, docData, out canceled)); - } - } - - if (canceled == 1) { - throw new InvalidOperationException(); - } - } catch (COMException e) { - throw new InvalidOperationException(e.Message); - } finally { - if (docData != IntPtr.Zero) { - Marshal.Release(docData); - } - } - }); - } - - } - #endregion - - } -} diff --git a/Microsoft.VisualStudio.Project/Automation/OAFolderItem.cs b/Microsoft.VisualStudio.Project/Automation/OAFolderItem.cs deleted file mode 100644 index c58aa2c0..00000000 --- a/Microsoft.VisualStudio.Project/Automation/OAFolderItem.cs +++ /dev/null @@ -1,56 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System.Diagnostics.CodeAnalysis; -using System.Runtime.InteropServices; -using EnvDTE; - -namespace Microsoft.VisualStudioTools.Project.Automation { - /// - /// Represents an automation object for a folder in a project - /// - [ComVisible(true)] - public class OAFolderItem : OAProjectItem { - #region ctors - internal OAFolderItem(OAProject project, FolderNode node) - : base(project, node) { - } - - #endregion - - private new FolderNode Node { - get { - return (FolderNode)base.Node; - } - } - - - #region overridden methods - public override ProjectItems Collection { - get { - ProjectItems items = new OAProjectItems(this.Project, this.Node.Parent); - return items; - } - } - - public override ProjectItems ProjectItems { - get { - return new OAProjectItems(Project, Node); - } - } - #endregion - } -} diff --git a/Microsoft.VisualStudio.Project/Automation/OANavigableProjectItems.cs b/Microsoft.VisualStudio.Project/Automation/OANavigableProjectItems.cs deleted file mode 100644 index 92ecac08..00000000 --- a/Microsoft.VisualStudio.Project/Automation/OANavigableProjectItems.cs +++ /dev/null @@ -1,226 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.InteropServices; - -namespace Microsoft.VisualStudioTools.Project.Automation { - /// - /// This can navigate a collection object only (partial implementation of ProjectItems interface) - /// - [ComVisible(true)] - public class OANavigableProjectItems : EnvDTE.ProjectItems { - #region fields - private OAProject project; - private HierarchyNode nodeWithItems; - #endregion - - #region properties - /// - /// Defines a relationship to the associated project. - /// - internal OAProject Project { - get { - return this.project; - } - } - - /// - /// Defines the node that contains the items - /// - internal HierarchyNode NodeWithItems { - get { - return this.nodeWithItems; - } - } - #endregion - - #region ctor - /// - /// Constructor. - /// - /// The associated project. - /// The node that defines the items. - internal OANavigableProjectItems(OAProject project, HierarchyNode nodeWithItems) { - this.project = project; - this.nodeWithItems = nodeWithItems; - } - - #endregion - - #region EnvDTE.ProjectItems - - /// - /// Gets a value indicating the number of objects in the collection. - /// - public virtual int Count { - get { - int count = 0; - UIThread.Invoke(() => { - for (HierarchyNode child = this.NodeWithItems.FirstChild; child != null; child = child.NextSibling) { - if (!child.IsNonMemberItem && child.GetAutomationObject() is EnvDTE.ProjectItem) { - count += 1; - } - } - }); - return count; - } - } - - /// - /// Gets the immediate parent object of a ProjectItems collection. - /// - public virtual object Parent { - get { - return this.nodeWithItems.GetAutomationObject(); - } - } - - /// - /// Gets an enumeration indicating the type of object. - /// - public virtual string Kind { - get { - // TODO: Add OAProjectItems.Kind getter implementation - return null; - } - } - - /// - /// Gets the top-level extensibility object. - /// - public virtual EnvDTE.DTE DTE { - get { - return (EnvDTE.DTE)this.project.DTE; - } - } - - /// - /// Gets the project hosting the project item or items. - /// - public virtual EnvDTE.Project ContainingProject { - get { - return this.project; - } - } - - /// - /// Adds one or more ProjectItem objects from a directory to the ProjectItems collection. - /// - /// The directory from which to add the project item. - /// A ProjectItem object. - public virtual EnvDTE.ProjectItem AddFromDirectory(string directory) { - throw new NotImplementedException(); - } - - /// - /// Creates a new project item from an existing item template file and adds it to the project. - /// - /// The full path and file name of the template project file. - /// The file name to use for the new project item. - /// A ProjectItem object. - public virtual EnvDTE.ProjectItem AddFromTemplate(string fileName, string name) { - throw new NotImplementedException(); - } - - /// - /// Creates a new folder in Solution Explorer. - /// - /// The name of the folder node in Solution Explorer. - /// The type of folder to add. The available values are based on vsProjectItemsKindConstants and vsProjectItemKindConstants - /// A ProjectItem object. - public virtual EnvDTE.ProjectItem AddFolder(string name, string kind) { - throw new NotImplementedException(); - } - - /// - /// Copies a source file and adds it to the project. - /// - /// The path and file name of the project item to be added. - /// A ProjectItem object. - public virtual EnvDTE.ProjectItem AddFromFileCopy(string filePath) { - throw new NotImplementedException(); - } - - /// - /// Adds a project item from a file that is installed in a project directory structure. - /// - /// The file name of the item to add as a project item. - /// A ProjectItem object. - public virtual EnvDTE.ProjectItem AddFromFile(string fileName) { - throw new NotImplementedException(); - } - - /// - /// Get Project Item from index - /// - /// Either index by number (1-based) or by name can be used to get the item - /// Project Item. ArgumentException if invalid index is specified - public virtual EnvDTE.ProjectItem Item(object index) { - // Changed from MPFProj: throws ArgumentException instead of returning null (http://mpfproj10.codeplex.com/workitem/9158) - if (index is int) { - int realIndex = (int)index - 1; - if (realIndex >= 0) { - for (HierarchyNode child = this.NodeWithItems.FirstChild; child != null; child = child.NextSibling) { - if (child.IsNonMemberItem) { - continue; - } - var item = child.GetAutomationObject() as EnvDTE.ProjectItem; - if (item != null) { - if (realIndex == 0) { - return item; - } - realIndex -= 1; - } - } - } - } else if (index is string) { - string name = (string)index; - for (HierarchyNode child = this.NodeWithItems.FirstChild; child != null; child = child.NextSibling) { - if (child.IsNonMemberItem) { - continue; - } - var item = child.GetAutomationObject() as EnvDTE.ProjectItem; - if (item != null && String.Compare(item.Name, name, StringComparison.OrdinalIgnoreCase) == 0) { - return item; - } - } - } - throw new ArgumentException("Failed to find item: " + index); - } - - /// - /// Returns an enumeration for items in a collection. - /// - /// An IEnumerator for this object. - public virtual IEnumerator GetEnumerator() { - for (HierarchyNode child = this.NodeWithItems.FirstChild; child != null; child = child.NextSibling) { - if (child.IsNonMemberItem) { - continue; - } - var item = child.GetAutomationObject() as EnvDTE.ProjectItem; - if (item != null) { - yield return item; - } - } - } - - #endregion - } -} diff --git a/Microsoft.VisualStudio.Project/Automation/OANullProperty.cs b/Microsoft.VisualStudio.Project/Automation/OANullProperty.cs deleted file mode 100644 index 050d9bea..00000000 --- a/Microsoft.VisualStudio.Project/Automation/OANullProperty.cs +++ /dev/null @@ -1,90 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Runtime.InteropServices; - -namespace Microsoft.VisualStudioTools.Project.Automation { - /// - /// This object defines a so called null object that is returned as instead of null. This is because callers in VSCore usually crash if a null propery is returned for them. - /// - [ComVisible(true)] - public class OANullProperty : EnvDTE.Property { - #region fields - private OAProperties parent; - #endregion - - #region ctors - - public OANullProperty(OAProperties parent) { - this.parent = parent; - } - #endregion - - #region EnvDTE.Property - - public object Application { - get { return String.Empty; } - } - - public EnvDTE.Properties Collection { - get { - //todo: EnvDTE.Property.Collection - return this.parent; - } - } - - public EnvDTE.DTE DTE { - get { return null; } - } - - public object get_IndexedValue(object index1, object index2, object index3, object index4) { - return String.Empty; - } - - public void let_Value(object value) { - //todo: let_Value - } - - public string Name { - get { return String.Empty; } - } - - public short NumIndices { - get { return 0; } - } - - public object Object { - get { return this.parent.Target; } - set { - } - } - - public EnvDTE.Properties Parent { - get { return this.parent; } - } - - public void set_IndexedValue(object index1, object index2, object index3, object index4, object value) { - - } - - public object Value { - get { return String.Empty; } - set { } - } - #endregion - } -} diff --git a/Microsoft.VisualStudio.Project/Automation/OAProject.cs b/Microsoft.VisualStudio.Project/Automation/OAProject.cs deleted file mode 100644 index 7bc7b6de..00000000 --- a/Microsoft.VisualStudio.Project/Automation/OAProject.cs +++ /dev/null @@ -1,420 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Globalization; -using System.Runtime.InteropServices; -using EnvDTE; -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.Shell.Interop; - -namespace Microsoft.VisualStudioTools.Project.Automation { - [ComVisible(true)] - public class OAProject : EnvDTE.Project, EnvDTE.ISupportVSProperties { - #region fields - private ProjectNode project; - EnvDTE.ConfigurationManager configurationManager; - #endregion - - #region properties - public object Project { - get { return this.project; } - } - internal ProjectNode ProjectNode { - get { return this.project; } - } - #endregion - - #region ctor - internal OAProject(ProjectNode project) { - this.project = project; - } - #endregion - - #region EnvDTE.Project - /// - /// Gets or sets the name of the object. - /// - public virtual string Name { - get { - return project.Caption; - } - set { - CheckProjectIsValid(); - - using (AutomationScope scope = new AutomationScope(this.project.Site)) { - UIThread.Invoke(() => { - project.SetEditLabel(value); - }); - } - } - } - - /// - /// Microsoft Internal Use Only. Gets the file name of the project. - /// - public virtual string FileName { - get { - return project.ProjectFile; - } - } - - /// - /// Microsoft Internal Use Only. Specfies if the project is dirty. - /// - public virtual bool IsDirty { - get { - int dirty; - - ErrorHandler.ThrowOnFailure(project.IsDirty(out dirty)); - return dirty != 0; - } - set { - CheckProjectIsValid(); - - using (AutomationScope scope = new AutomationScope(this.project.Site)) { - UIThread.Invoke(() => { - project.isDirty = value; - }); - } - } - } - - internal void CheckProjectIsValid() { - if (this.project == null || this.project.Site == null || this.project.IsClosed) { - throw new InvalidOperationException(); - } - } - - /// - /// Gets the Projects collection containing the Project object supporting this property. - /// - public virtual EnvDTE.Projects Collection { - get { return null; } - } - - /// - /// Gets the top-level extensibility object. - /// - public virtual EnvDTE.DTE DTE { - get { - return (EnvDTE.DTE)this.project.Site.GetService(typeof(EnvDTE.DTE)); - } - } - - /// - /// Gets a GUID string indicating the kind or type of the object. - /// - public virtual string Kind { - get { return project.ProjectGuid.ToString("B"); } - } - - /// - /// Gets a ProjectItems collection for the Project object. - /// - public virtual EnvDTE.ProjectItems ProjectItems { - get { - return new OAProjectItems(this, project); - } - } - - /// - /// Gets a collection of all properties that pertain to the Project object. - /// - public virtual EnvDTE.Properties Properties { - get { - return new OAProperties(this.project.NodeProperties); - } - } - - /// - /// Returns the name of project as a relative path from the directory containing the solution file to the project file - /// - /// Unique name if project is in a valid state. Otherwise null - public virtual string UniqueName { - get { - if (this.project == null || this.project.IsClosed) { - return null; - } else { - // Get Solution service - IVsSolution solution = this.project.GetService(typeof(IVsSolution)) as IVsSolution; - Utilities.CheckNotNull(solution); - - // Ask solution for unique name of project - string uniqueName; - - ErrorHandler.ThrowOnFailure( - solution.GetUniqueNameOfProject( - project.GetOuterInterface(), - out uniqueName - ) - ); - return uniqueName; - } - } - } - - /// - /// Gets an interface or object that can be accessed by name at run time. - /// - public virtual object Object { - get { return this.project.Object; } - } - - /// - /// Gets the requested Extender object if it is available for this object. - /// - /// The name of the extender object. - /// An Extender object. - public virtual object get_Extender(string name) { - Utilities.ArgumentNotNull("name", name); - - return DTE.ObjectExtenders.GetExtender(project.NodeProperties.ExtenderCATID.ToUpper(), name, project.NodeProperties); - } - - /// - /// Gets a list of available Extenders for the object. - /// - public virtual object ExtenderNames { - get { return DTE.ObjectExtenders.GetExtenderNames(project.NodeProperties.ExtenderCATID.ToUpper(), project.NodeProperties); } - } - - /// - /// Gets the Extender category ID (CATID) for the object. - /// - public virtual string ExtenderCATID { - get { return project.NodeProperties.ExtenderCATID; } - } - - /// - /// Gets the full path and name of the Project object's file. - /// - public virtual string FullName { - get { - string filename; - uint format; - ErrorHandler.ThrowOnFailure(project.GetCurFile(out filename, out format)); - return filename; - } - } - - /// - /// Gets or sets a value indicatingwhether the object has not been modified since last being saved or opened. - /// - public virtual bool Saved { - get { - return !this.IsDirty; - } - set { - IsDirty = !value; - } - } - - /// - /// Gets the ConfigurationManager object for this Project . - /// - public virtual EnvDTE.ConfigurationManager ConfigurationManager { - get { - return UIThread.Invoke(() => { - if (this.configurationManager == null) { - IVsExtensibility3 extensibility = this.project.Site.GetService(typeof(IVsExtensibility)) as IVsExtensibility3; - - Utilities.CheckNotNull(extensibility); - - object configurationManagerAsObject; - ErrorHandler.ThrowOnFailure(extensibility.GetConfigMgr( - this.project.GetOuterInterface(), - VSConstants.VSITEMID_ROOT, - out configurationManagerAsObject - )); - - Utilities.CheckNotNull(configurationManagerAsObject); - - this.configurationManager = (ConfigurationManager)configurationManagerAsObject; - } - - return this.configurationManager; - }); - } - } - - /// - /// Gets the Globals object containing add-in values that may be saved in the solution (.sln) file, the project file, or in the user's profile data. - /// - public virtual EnvDTE.Globals Globals { - get { return null; } - } - - /// - /// Gets a ProjectItem object for the nested project in the host project. - /// - public virtual EnvDTE.ProjectItem ParentProjectItem { - get { return null; } - } - - /// - /// Gets the CodeModel object for the project. - /// - public virtual EnvDTE.CodeModel CodeModel { - get { return null; } - } - - /// - /// Saves the project. - /// - /// The file name with which to save the solution, project, or project item. If the file exists, it is overwritten - /// Is thrown if the save operation failes. - /// Is thrown if fileName is null. - public virtual void SaveAs(string fileName) { - UIThread.Invoke(() => { - this.DoSave(true, fileName); - }); - } - - /// - /// Saves the project - /// - /// The file name of the project - /// Is thrown if the save operation failes. - /// Is thrown if fileName is null. - public virtual void Save(string fileName) { - UIThread.Invoke(() => { - this.DoSave(false, fileName); - }); - } - - /// - /// Removes the project from the current solution. - /// - public virtual void Delete() { - CheckProjectIsValid(); - - using (AutomationScope scope = new AutomationScope(this.project.Site)) { - UIThread.Invoke(() => { - this.project.Remove(false); - }); - } - } - #endregion - - #region ISupportVSProperties methods - /// - /// Microsoft Internal Use Only. - /// - public virtual void NotifyPropertiesDelete() { - } - #endregion - - #region private methods - /// - /// Saves or Save Asthe project. - /// - /// Flag determining which Save method called , the SaveAs or the Save. - /// The name of the project file. - private void DoSave(bool isCalledFromSaveAs, string fileName) { - Utilities.ArgumentNotNull("fileName", fileName); - - CheckProjectIsValid(); - - using (AutomationScope scope = new AutomationScope(this.project.Site)) { - // If an empty file name is passed in for Save then make the file name the project name. - if (!isCalledFromSaveAs && string.IsNullOrEmpty(fileName)) { - // Use the solution service to save the project file. Note that we have to use the service - // so that all the shell's elements are aware that we are inside a save operation and - // all the file change listenters registered by the shell are suspended. - - // Get the cookie of the project file from the RTD. - IVsRunningDocumentTable rdt = this.project.Site.GetService(typeof(SVsRunningDocumentTable)) as IVsRunningDocumentTable; - Utilities.CheckNotNull(rdt); - - IVsHierarchy hier; - uint itemid; - IntPtr unkData; - uint cookie; - ErrorHandler.ThrowOnFailure(rdt.FindAndLockDocument((uint)_VSRDTFLAGS.RDT_NoLock, this.project.Url, out hier, - out itemid, out unkData, out cookie)); - if (IntPtr.Zero != unkData) { - Marshal.Release(unkData); - } - - // Verify that we have a cookie. - if (0 == cookie) { - // This should never happen because if the project is open, then it must be in the RDT. - throw new InvalidOperationException(); - } - - // Get the IVsHierarchy for the project. - IVsHierarchy prjHierarchy = project.GetOuterInterface(); - - // Now get the soulution. - IVsSolution solution = this.project.Site.GetService(typeof(SVsSolution)) as IVsSolution; - // Verify that we have both solution and hierarchy. - Utilities.CheckNotNull(prjHierarchy); - Utilities.CheckNotNull(solution); - - - ErrorHandler.ThrowOnFailure(solution.SaveSolutionElement((uint)__VSSLNSAVEOPTIONS.SLNSAVEOPT_SaveIfDirty, prjHierarchy, cookie)); - } else { - - // We need to make some checks before we can call the save method on the project node. - // This is mainly because it is now us and not the caller like in case of SaveAs or Save that should validate the file name. - // The IPersistFileFormat.Save method only does a validation that is necessary to be performed. Example: in case of Save As the - // file name itself is not validated only the whole path. (thus a file name like file\file is accepted, since as a path is valid) - - // 1. The file name has to be valid. - string fullPath = fileName; - try { - fullPath = CommonUtils.GetAbsoluteFilePath(((ProjectNode)Project).ProjectFolder, fileName); - } - // We want to be consistent in the error message and exception we throw. fileName could be for example #¤&%"¤&"% and that would trigger an ArgumentException on Path.IsRooted. - catch (ArgumentException ex) { - throw new InvalidOperationException(SR.GetString(SR.ErrorInvalidFileName, fileName), ex); - } - - // It might be redundant but we validate the file and the full path of the file being valid. The SaveAs would also validate the path. - // If we decide that this is performance critical then this should be refactored. - Utilities.ValidateFileName(this.project.Site, fullPath); - - if (!isCalledFromSaveAs) { - // 2. The file name has to be the same - if (!CommonUtils.IsSamePath(fullPath, this.project.Url)) { - throw new InvalidOperationException(); - } - - ErrorHandler.ThrowOnFailure(this.project.Save(fullPath, 1, 0)); - } else { - ErrorHandler.ThrowOnFailure(this.project.Save(fullPath, 0, 0)); - } - } - } - - } - #endregion - } - - /// - /// Specifies an alternate name for a property which cannot be fully captured using - /// .NET attribute names. - /// - [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] - class PropertyNameAttribute : Attribute { - public readonly string Name; - - public PropertyNameAttribute(string name) { - Name = name; - } - } -} diff --git a/Microsoft.VisualStudio.Project/Automation/OAProjectConfigurationProperties.cs b/Microsoft.VisualStudio.Project/Automation/OAProjectConfigurationProperties.cs deleted file mode 100644 index 7a4763a8..00000000 --- a/Microsoft.VisualStudio.Project/Automation/OAProjectConfigurationProperties.cs +++ /dev/null @@ -1,395 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Collections.Generic; -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.OLE.Interop; -using Microsoft.VisualStudio.Shell.Interop; -using Microsoft.VisualStudioTools.Project; -using VSLangProj; - -namespace Microsoft.VisualStudioTools.Project.Automation { - class OAProjectConfigurationProperties : ConnectionPointContainer, ProjectConfigurationProperties, IConnectionPointContainer, IEventSource { - private readonly ProjectNode _project; - private readonly List _sinks = new List(); - private readonly HierarchyListener _hierarchyListener; - - public OAProjectConfigurationProperties(ProjectNode node) { - _project = node; - AddEventSource(this); - _hierarchyListener = new HierarchyListener(_project, this); - } - - #region ProjectConfigurationProperties Members - - public bool AllowUnsafeBlocks { - get { - throw new NotImplementedException(); - } - set { - throw new NotImplementedException(); - } - } - - public uint BaseAddress { - get { - throw new NotImplementedException(); - } - set { - throw new NotImplementedException(); - } - } - - public bool CheckForOverflowUnderflow { - get { - throw new NotImplementedException(); - } - set { - throw new NotImplementedException(); - } - } - - public string ConfigurationOverrideFile { - get { - throw new NotImplementedException(); - } - set { - throw new NotImplementedException(); - } - } - - public bool DebugSymbols { - get { - throw new NotImplementedException(); - } - set { - throw new NotImplementedException(); - } - } - - public string DefineConstants { - get { - throw new NotImplementedException(); - } - set { - throw new NotImplementedException(); - } - } - - public bool DefineDebug { - get { - throw new NotImplementedException(); - } - set { - throw new NotImplementedException(); - } - } - - public bool DefineTrace { - get { - throw new NotImplementedException(); - } - set { - throw new NotImplementedException(); - } - } - - public string DocumentationFile { - get { - throw new NotImplementedException(); - } - set { - throw new NotImplementedException(); - } - } - - public bool EnableASPDebugging { - get { - throw new NotImplementedException(); - } - set { - throw new NotImplementedException(); - } - } - - public bool EnableASPXDebugging { - get { - throw new NotImplementedException(); - } - set { - throw new NotImplementedException(); - } - } - - public bool EnableSQLServerDebugging { - get { - throw new NotImplementedException(); - } - set { - throw new NotImplementedException(); - } - } - - public bool EnableUnmanagedDebugging { - get { - throw new NotImplementedException(); - } - set { - throw new NotImplementedException(); - } - } - - public string ExtenderCATID { - get { throw new NotImplementedException(); } - } - - public object ExtenderNames { - get { throw new NotImplementedException(); } - } - - public uint FileAlignment { - get { - throw new NotImplementedException(); - } - set { - throw new NotImplementedException(); - } - } - - public bool IncrementalBuild { - get { - throw new NotImplementedException(); - } - set { - throw new NotImplementedException(); - } - } - - public string IntermediatePath { - get { - throw new NotImplementedException(); - } - set { - throw new NotImplementedException(); - } - } - - public bool Optimize { - get { - throw new NotImplementedException(); - } - set { - throw new NotImplementedException(); - } - } - - public string OutputPath { - get { - return UIThread.Invoke(() => _project.GetProjectProperty("OutputPath")); - } - set { - UIThread.Invoke(() => _project.SetProjectProperty("OutputPath", value)); - } - } - - public bool RegisterForComInterop { - get { - throw new NotImplementedException(); - } - set { - throw new NotImplementedException(); - } - } - - public bool RemoteDebugEnabled { - get { - throw new NotImplementedException(); - } - set { - throw new NotImplementedException(); - } - } - - public string RemoteDebugMachine { - get { - throw new NotImplementedException(); - } - set { - throw new NotImplementedException(); - } - } - - public bool RemoveIntegerChecks { - get { - throw new NotImplementedException(); - } - set { - throw new NotImplementedException(); - } - } - - public prjStartAction StartAction { - get { - throw new NotImplementedException(); - } - set { - throw new NotImplementedException(); - } - } - - public string StartArguments { - get { - throw new NotImplementedException(); - } - set { - throw new NotImplementedException(); - } - } - - public string StartPage { - get { - throw new NotImplementedException(); - } - set { - throw new NotImplementedException(); - } - } - - public string StartProgram { - get { - throw new NotImplementedException(); - } - set { - throw new NotImplementedException(); - } - } - - public string StartURL { - get { - throw new NotImplementedException(); - } - set { - throw new NotImplementedException(); - } - } - - public bool StartWithIE { - get { - throw new NotImplementedException(); - } - set { - throw new NotImplementedException(); - } - } - - public string StartWorkingDirectory { - get { - throw new NotImplementedException(); - } - set { - throw new NotImplementedException(); - } - } - - public bool TreatWarningsAsErrors { - get { - throw new NotImplementedException(); - } - set { - throw new NotImplementedException(); - } - } - - public prjWarningLevel WarningLevel { - get { - throw new NotImplementedException(); - } - set { - throw new NotImplementedException(); - } - } - - public string __id { - get { throw new NotImplementedException(); } - } - - public object get_Extender(string ExtenderName) { - throw new NotImplementedException(); - } - - #endregion - - #region IEventSource Members - - public void OnSinkAdded(IPropertyNotifySink sink) { - _sinks.Add(sink); - } - - public void OnSinkRemoved(IPropertyNotifySink sink) { - _sinks.Remove(sink); - } - - #endregion - - internal class HierarchyListener : IVsHierarchyEvents { - private readonly IVsHierarchy _hierarchy; - private readonly uint _cookie; - private readonly OAProjectConfigurationProperties _props; - - public HierarchyListener(IVsHierarchy hierarchy, OAProjectConfigurationProperties props) { - _hierarchy = hierarchy; - _props = props; - ErrorHandler.ThrowOnFailure(_hierarchy.AdviseHierarchyEvents(this, out _cookie)); - } - - ~HierarchyListener() { - _hierarchy.UnadviseHierarchyEvents(_cookie); - } - - #region IVsHierarchyEvents Members - - public int OnInvalidateIcon(IntPtr hicon) { - return VSConstants.S_OK; - } - - public int OnInvalidateItems(uint itemidParent) { - return VSConstants.S_OK; - } - - public int OnItemAdded(uint itemidParent, uint itemidSiblingPrev, uint itemidAdded) { - return VSConstants.S_OK; - } - - public int OnItemDeleted(uint itemid) { - return VSConstants.S_OK; - } - - public int OnItemsAppended(uint itemidParent) { - return VSConstants.S_OK; - } - - public int OnPropertyChanged(uint itemid, int propid, uint flags) { - foreach (var sink in _props._sinks) { - sink.OnChanged(propid); - } - return VSConstants.S_OK; - } - - #endregion - } - } -} diff --git a/Microsoft.VisualStudio.Project/Automation/OAProjectItem.cs b/Microsoft.VisualStudio.Project/Automation/OAProjectItem.cs deleted file mode 100644 index 4d555f2d..00000000 --- a/Microsoft.VisualStudio.Project/Automation/OAProjectItem.cs +++ /dev/null @@ -1,362 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Diagnostics; -using System.Runtime.InteropServices; -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.Shell.Interop; - -namespace Microsoft.VisualStudioTools.Project.Automation { - [ComVisible(true)] - public class OAProjectItem : EnvDTE.ProjectItem { - - #region fields - private HierarchyNode node; - private OAProject project; - #endregion - - #region properties - internal HierarchyNode Node { - get { - return this.node; - } - } - - /// - /// Returns the automation project - /// - protected OAProject Project { - get { - return this.project; - } - } - #endregion - - #region ctors - internal OAProjectItem(OAProject project, HierarchyNode node) { - this.node = node; - this.project = project; - } - #endregion - - #region EnvDTE.ProjectItem - - /// - /// Gets the requested Extender if it is available for this object - /// - /// The name of the extender. - /// The extender object. - public virtual object get_Extender(string extenderName) { - return null; - } - - /// - /// Gets an object that can be accessed by name at run time. - /// - public virtual object Object { - get { - return this.node.Object; - } - } - - /// - /// Gets the Document associated with the item, if one exists. - /// - public virtual EnvDTE.Document Document { - get { - return null; - } - } - - /// - /// Gets the number of files associated with a ProjectItem. - /// - public virtual short FileCount { - get { - return (short)1; - } - } - - /// - /// Gets a collection of all properties that pertain to the object. - /// - public virtual EnvDTE.Properties Properties { - get { - if (this.node.NodeProperties == null) { - return null; - } - return new OAProperties(this.node.NodeProperties); - } - } - - - /// - /// Gets the FileCodeModel object for the project item. - /// - public virtual EnvDTE.FileCodeModel FileCodeModel { - get { - return null; - } - } - - /// - /// Gets a ProjectItems for the object. - /// - public virtual EnvDTE.ProjectItems ProjectItems { - get { - return null; - } - } - - /// - /// Gets a GUID string indicating the kind or type of the object. - /// - public virtual string Kind { - get { - Guid guid; - ErrorHandler.ThrowOnFailure(this.node.GetGuidProperty((int)__VSHPROPID.VSHPROPID_TypeGuid, out guid)); - return guid.ToString("B"); - } - } - - /// - /// Saves the project item. - /// - /// The name with which to save the project or project item. - /// Implemented by subclasses. - public virtual void Save(string fileName) { - throw new NotImplementedException(); - } - - /// - /// Gets the top-level extensibility object. - /// - public virtual EnvDTE.DTE DTE { - get { - return (EnvDTE.DTE)this.project.DTE; - } - } - - /// - /// Gets the ProjectItems collection containing the ProjectItem object supporting this property. - /// - public virtual EnvDTE.ProjectItems Collection { - get { - // Get the parent node - HierarchyNode parentNode = this.node.Parent; - Debug.Assert(parentNode != null, "Failed to get the parent node"); - - // Get the ProjectItems object for the parent node - if (parentNode is ProjectNode) { - // The root node for the project - return ((OAProject)parentNode.GetAutomationObject()).ProjectItems; - } else { - // Not supported. Override this method in derived classes to return appropriate collection object - throw new InvalidOperationException(); - } - } - } - /// - /// Gets a list of available Extenders for the object. - /// - public virtual object ExtenderNames { - get { - return null; - } - } - - /// - /// Gets the ConfigurationManager object for this ProjectItem. - /// - /// We do not support config management based per item. - public virtual EnvDTE.ConfigurationManager ConfigurationManager { - get { - return null; - } - } - - /// - /// Gets the project hosting the ProjectItem. - /// - public virtual EnvDTE.Project ContainingProject { - get { - return this.project; - } - } - - /// - /// Gets or sets a value indicating whether or not the object has been modified since last being saved or opened. - /// - public virtual bool Saved { - get { - return !this.IsDirty; - - } - set { - throw new NotImplementedException(); - } - } - - /// - /// Gets the Extender category ID (CATID) for the object. - /// - public virtual string ExtenderCATID { - get { - return null; - } - } - - /// - /// If the project item is the root of a subproject, then the SubProject property returns the Project object for the subproject. - /// - public virtual EnvDTE.Project SubProject { - get { - return null; - } - } - - /// - /// Microsoft Internal Use Only. Checks if the document associated to this item is dirty. - /// - public virtual bool IsDirty { - get { - return false; - } - set { - } - } - - /// - /// Gets or sets the name of the object. - /// - public virtual string Name { - get { - return this.node.Caption; - } - set { - CheckProjectIsValid(); - - using (AutomationScope scope = new AutomationScope(this.Node.ProjectMgr.Site)) { - UIThread.Invoke(() => this.node.SetEditLabel(value)); - } - } - } - - protected void CheckProjectIsValid() { - Utilities.CheckNotNull(this.node); - Utilities.CheckNotNull(this.node.ProjectMgr); - Utilities.CheckNotNull(this.node.ProjectMgr.Site); - if (this.node.ProjectMgr.IsClosed) { - throw new InvalidOperationException(); - } - } - - /// - /// Removes the project item from hierarchy. - /// - public virtual void Remove() { - CheckProjectIsValid(); - - using (AutomationScope scope = new AutomationScope(this.Node.ProjectMgr.Site)) { - UIThread.Invoke(() => this.node.Remove(false)); - } - } - - /// - /// Removes the item from its project and its storage. - /// - public virtual void Delete() { - CheckProjectIsValid(); - - using (AutomationScope scope = new AutomationScope(this.Node.ProjectMgr.Site)) { - UIThread.Invoke(() => this.node.Remove(true)); - } - } - - /// - /// Saves the project item. - /// - /// The file name with which to save the solution, project, or project item. If the file exists, it is overwritten. - /// true if save was successful - /// This method is implemented on subclasses. - public virtual bool SaveAs(string newFileName) { - throw new NotImplementedException(); - } - - /// - /// Gets a value indicating whether the project item is open in a particular view type. - /// - /// A Constants.vsViewKind* indicating the type of view to check./param> - /// A Boolean value indicating true if the project is open in the given view type; false if not. - public virtual bool get_IsOpen(string viewKind) { - throw new NotImplementedException(); - } - - /// - /// Gets the full path and names of the files associated with a project item. - /// - /// The index of the item - /// The full path of the associated item - /// Is thrown if index is not one - public virtual string get_FileNames(short index) { - // This method should really only be called with 1 as the parameter, but - // there used to be a bug in VB/C# that would work with 0. To avoid breaking - // existing automation they are still accepting 0. To be compatible with them - // we accept it as well. - if (index < 0) { - throw new ArgumentOutOfRangeException("index"); - } - return this.node.Url; - } - - /// - /// Expands the view of Solution Explorer to show project items. - /// - public virtual void ExpandView() { - CheckProjectIsValid(); - - using (AutomationScope scope = new AutomationScope(this.Node.ProjectMgr.Site)) { - UIThread.Invoke(() => node.ExpandItem(EXPANDFLAGS.EXPF_ExpandFolder)); - } - } - - /// - /// Opens the project item in the specified view. Not implemented because this abstract class dont know what to open - /// - /// Specifies the view kind in which to open the item - /// Window object - public virtual EnvDTE.Window Open(string ViewKind) { - throw new NotImplementedException(); - } - - // We're managed and we don't use COM’s IDispatch which would resolve parametrized property FileNames and IsOpen correctly. - // Powershell scripts are using reflection to find (or rather, not find) the methodss. Thus FileNames call ends with exception: method's not defined. - // Implementing these as regular methods satisfies the situation. - // This is required for Nuget support. - - public string FileNames(short index) { - return get_FileNames(index); - } - - public bool IsOpen(string viewKind) { - return get_IsOpen(viewKind); - } - - #endregion - - } -} diff --git a/Microsoft.VisualStudio.Project/Automation/OAProjectItems.cs b/Microsoft.VisualStudio.Project/Automation/OAProjectItems.cs deleted file mode 100644 index 4f126c7b..00000000 --- a/Microsoft.VisualStudio.Project/Automation/OAProjectItems.cs +++ /dev/null @@ -1,241 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Globalization; -using System.IO; -using System.Runtime.InteropServices; -using EnvDTE; -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.Shell.Interop; - -namespace Microsoft.VisualStudioTools.Project.Automation { - /// - /// Contains ProjectItem objects - /// - [ComVisible(true)] - public class OAProjectItems : OANavigableProjectItems { - #region ctor - internal OAProjectItems(OAProject project, HierarchyNode nodeWithItems) - : base(project, nodeWithItems) { - } - #endregion - - #region EnvDTE.ProjectItems - - /// - /// Creates a new project item from an existing directory and all files and subdirectories - /// contained within it. - /// - /// The full path of the directory to add. - /// A ProjectItem object. - public override ProjectItem AddFromDirectory(string directory) { - CheckProjectIsValid(); - - return UIThread.Invoke(() => { - ProjectItem result = AddFolder(directory, null); - - foreach (string subdirectory in Directory.EnumerateDirectories(directory)) { - result.ProjectItems.AddFromDirectory(Path.Combine(directory, subdirectory)); - } - - foreach (var extension in this.Project.ProjectNode.CodeFileExtensions) { - foreach (string filename in Directory.EnumerateFiles(directory, "*" + extension)) { - result.ProjectItems.AddFromFile(Path.Combine(directory, filename)); - } - } - return result; - }); - } - - /// - /// Creates a new project item from an existing item template file and adds it to the project. - /// - /// The full path and file name of the template project file. - /// The file name to use for the new project item. - /// A ProjectItem object. - public override EnvDTE.ProjectItem AddFromTemplate(string fileName, string name) { - CheckProjectIsValid(); - - ProjectNode proj = this.Project.ProjectNode; - EnvDTE.ProjectItem itemAdded = null; - - using (AutomationScope scope = new AutomationScope(this.Project.ProjectNode.Site)) { - // Determine the operation based on the extension of the filename. - // We should run the wizard only if the extension is vstemplate - // otherwise it's a clone operation - VSADDITEMOPERATION op; - UIThread.Invoke(() => { - if (Utilities.IsTemplateFile(fileName)) { - op = VSADDITEMOPERATION.VSADDITEMOP_RUNWIZARD; - } else { - op = VSADDITEMOPERATION.VSADDITEMOP_CLONEFILE; - } - - VSADDRESULT[] result = new VSADDRESULT[1]; - - // It is not a very good idea to throw since the AddItem might return Cancel or Abort. - // The problem is that up in the call stack the wizard code does not check whether it has received a ProjectItem or not and will crash. - // The other problem is that we cannot get add wizard dialog back if a cancel or abort was returned because we throw and that code will never be executed. Typical catch 22. - ErrorHandler.ThrowOnFailure(proj.AddItem(this.NodeWithItems.ID, op, name, 0, new string[1] { fileName }, IntPtr.Zero, result)); - - string fileDirectory = proj.GetBaseDirectoryForAddingFiles(this.NodeWithItems); - string templateFilePath = System.IO.Path.Combine(fileDirectory, name); - itemAdded = this.EvaluateAddResult(result[0], templateFilePath); - }); - } - - return itemAdded; - } - - private void CheckProjectIsValid() { - if (this.Project == null || this.Project.ProjectNode == null || this.Project.ProjectNode.Site == null || this.Project.ProjectNode.IsClosed) { - throw new InvalidOperationException(); - } - } - - /// - /// Adds a folder to the collection of ProjectItems with the given name. - /// - /// The kind must be null, empty string, or the string value of vsProjectItemKindPhysicalFolder. - /// Virtual folders are not supported by this implementation. - /// - /// The name of the new folder to add - /// A string representing a Guid of the folder kind. - /// A ProjectItem representing the newly added folder. - public override ProjectItem AddFolder(string name, string kind) { - Project.CheckProjectIsValid(); - - //Verify name is not null or empty - Utilities.ValidateFileName(this.Project.ProjectNode.Site, name); - - //Verify that kind is null, empty, or a physical folder - if (!(string.IsNullOrEmpty(kind) || kind.Equals(EnvDTE.Constants.vsProjectItemKindPhysicalFolder))) { - throw new ArgumentException("Parameter specification for AddFolder was not meet", "kind"); - } - - return UIThread.Invoke(() => { - var existingChild = this.NodeWithItems.FindImmediateChildByName(name); - if (existingChild != null) { - if (existingChild.IsNonMemberItem && ErrorHandler.Succeeded(existingChild.IncludeInProject(false))) { - return existingChild.GetAutomationObject() as ProjectItem; - } - throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, "Folder already exists with the name '{0}'", name)); - } - - ProjectNode proj = this.Project.ProjectNode; - - HierarchyNode newFolder = null; - using (AutomationScope scope = new AutomationScope(this.Project.ProjectNode.Site)) { - - //In the case that we are adding a folder to a folder, we need to build up - //the path to the project node. - name = Path.Combine(NodeWithItems.FullPathToChildren, name); - - newFolder = proj.CreateFolderNodes(name); - } - - return newFolder.GetAutomationObject() as ProjectItem; - }); - } - - /// - /// Copies a source file and adds it to the project. - /// - /// The path and file name of the project item to be added. - /// A ProjectItem object. - public override EnvDTE.ProjectItem AddFromFileCopy(string filePath) { - return this.AddItem(filePath, VSADDITEMOPERATION.VSADDITEMOP_CLONEFILE); - } - - /// - /// Adds a project item from a file that is installed in a project directory structure. - /// - /// The file name of the item to add as a project item. - /// A ProjectItem object. - public override EnvDTE.ProjectItem AddFromFile(string fileName) { - return this.AddItem(fileName, VSADDITEMOPERATION.VSADDITEMOP_LINKTOFILE); - } - - #endregion - - #region helper methods - /// - /// Adds an item to the project. - /// - /// The full path of the item to add. - /// The to use when adding the item. - /// A ProjectItem object. - protected virtual EnvDTE.ProjectItem AddItem(string path, VSADDITEMOPERATION op) { - CheckProjectIsValid(); - return UIThread.Invoke(() => { - ProjectNode proj = this.Project.ProjectNode; - EnvDTE.ProjectItem itemAdded = null; - using (AutomationScope scope = new AutomationScope(this.Project.ProjectNode.Site)) { - VSADDRESULT[] result = new VSADDRESULT[1]; - ErrorHandler.ThrowOnFailure(proj.AddItem(this.NodeWithItems.ID, op, path, 0, new string[1] { path }, IntPtr.Zero, result)); - - string realPath = null; - if (op != VSADDITEMOPERATION.VSADDITEMOP_LINKTOFILE) { - string fileName = Path.GetFileName(path); - string fileDirectory = proj.GetBaseDirectoryForAddingFiles(this.NodeWithItems); - realPath = Path.Combine(fileDirectory, fileName); - } else { - realPath = path; - } - - itemAdded = this.EvaluateAddResult(result[0], realPath); - } - - return itemAdded; - }); - } - - /// - /// Evaluates the result of an add operation. - /// - /// The returned by the Add methods - /// The full path of the item added. - /// A ProjectItem object. - private EnvDTE.ProjectItem EvaluateAddResult(VSADDRESULT result, string path) { - return UIThread.Invoke(() => { - if (result != VSADDRESULT.ADDRESULT_Failure) { - if (Directory.Exists(path)) { - path = CommonUtils.EnsureEndSeparator(path); - } - HierarchyNode nodeAdded = this.NodeWithItems.ProjectMgr.FindNodeByFullPath(path); - Debug.Assert(nodeAdded != null, "We should have been able to find the new element in the hierarchy"); - if (nodeAdded != null) { - EnvDTE.ProjectItem item = null; - var fileNode = nodeAdded as FileNode; - if (fileNode != null) { - item = new OAFileItem(this.Project, fileNode); - } else { - item = new OAProjectItem(this.Project, nodeAdded); - } - - return item; - } - } - return null; - }); - } - #endregion - - } -} diff --git a/Microsoft.VisualStudio.Project/Automation/OAProperties.cs b/Microsoft.VisualStudio.Project/Automation/OAProperties.cs deleted file mode 100644 index a66ff35e..00000000 --- a/Microsoft.VisualStudio.Project/Automation/OAProperties.cs +++ /dev/null @@ -1,211 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Globalization; -using System.Reflection; -using System.Runtime.InteropServices; - -namespace Microsoft.VisualStudioTools.Project.Automation { - /// - /// Contains all of the properties of a given object that are contained in a generic collection of properties. - /// - [ComVisible(true)] - public class OAProperties : EnvDTE.Properties { - private NodeProperties target; - private Dictionary properties = new Dictionary(); - - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")] - public OAProperties(NodeProperties target) { - Utilities.ArgumentNotNull("target", target); - - this.target = target; - this.AddPropertiesFromType(target.GetType()); - } - - /// - /// Defines the NodeProperties object that contains the defines the properties. - /// - public NodeProperties Target { - get { - return this.target; - } - } - - #region EnvDTE.Properties - - /// - /// Microsoft Internal Use Only. - /// - public virtual object Application { - get { return null; } - } - - /// - /// Gets a value indicating the number of objects in the collection. - /// - public int Count { - get { return properties.Count; } - } - - /// - /// Gets the top-level extensibility object. - /// - public virtual EnvDTE.DTE DTE { - get { - if (this.target.HierarchyNode == null || this.target.HierarchyNode.ProjectMgr == null || this.target.HierarchyNode.ProjectMgr.IsClosed || - this.target.HierarchyNode.ProjectMgr.Site == null) { - throw new InvalidOperationException(); - } - return this.target.HierarchyNode.ProjectMgr.Site.GetService(typeof(EnvDTE.DTE)) as EnvDTE.DTE; - } - } - - /// - /// Gets an enumeration for items in a collection. - /// - /// An enumerator. - public IEnumerator GetEnumerator() { - if (this.properties.Count == 0) { - yield return new OANullProperty(this); - } - - IEnumerator enumerator = this.properties.Values.GetEnumerator(); - - while (enumerator.MoveNext()) { - yield return enumerator.Current; - } - } - - /// - /// Returns an indexed member of a Properties collection. - /// - /// The index at which to return a mamber. - /// A Property object. - public virtual EnvDTE.Property Item(object index) { - if (index is string) { - string indexAsString = (string)index; - if (this.properties.ContainsKey(indexAsString)) { - return (EnvDTE.Property)this.properties[indexAsString]; - } - } else if (index is int) { - int realIndex = (int)index - 1; - if (realIndex >= 0 && realIndex < this.properties.Count) { - IEnumerator enumerator = this.properties.Values.GetEnumerator(); - - int i = 0; - while (enumerator.MoveNext()) { - if (i++ == realIndex) { - return (EnvDTE.Property)enumerator.Current; - } - } - } - } - - throw new ArgumentException(SR.GetString(SR.InvalidParameter), "index"); - } - /// - /// Gets the immediate parent object of a Properties collection. - /// - public virtual object Parent { - get { return null; } - } - #endregion - - #region methods - /// - /// Add properties to the collection of properties filtering only those properties which are com-visible and AutomationBrowsable - /// - /// The type of NodeProperties the we should filter on - private void AddPropertiesFromType(Type targetType) { - Utilities.ArgumentNotNull("targetType", targetType); - - // If the type is not COM visible, we do not expose any of the properties - if (!IsComVisible(targetType)) { - return; - } - - // Add all properties being ComVisible and AutomationVisible - PropertyInfo[] propertyInfos = targetType.GetProperties(); - foreach (PropertyInfo propertyInfo in propertyInfos) { - if (!IsInMap(propertyInfo) && IsComVisible(propertyInfo) && IsAutomationVisible(propertyInfo)) { - AddProperty(propertyInfo); - } - } - } - #endregion - - #region virtual methods - /// - /// Creates a new OAProperty object and adds it to the current list of properties - /// - /// The property to be associated with an OAProperty object - private void AddProperty(PropertyInfo propertyInfo) { - var attrs = propertyInfo.GetCustomAttributes(typeof(PropertyNameAttribute), false); - string name = propertyInfo.Name; - if (attrs.Length > 0) { - name = ((PropertyNameAttribute)attrs[0]).Name; - } - this.properties.Add(name, new OAProperty(this, propertyInfo)); - } - #endregion - - #region helper methods - - private bool IsInMap(PropertyInfo propertyInfo) { - return this.properties.ContainsKey(propertyInfo.Name); - } - - private static bool IsAutomationVisible(PropertyInfo propertyInfo) { - object[] customAttributesOnProperty = propertyInfo.GetCustomAttributes(typeof(AutomationBrowsableAttribute), true); - - foreach (AutomationBrowsableAttribute attr in customAttributesOnProperty) { - if (!attr.Browsable) { - return false; - } - } - return true; - } - - private static bool IsComVisible(Type targetType) { - object[] customAttributesOnProperty = targetType.GetCustomAttributes(typeof(ComVisibleAttribute), true); - - foreach (ComVisibleAttribute attr in customAttributesOnProperty) { - if (!attr.Value) { - return false; - } - } - return true; - } - - private static bool IsComVisible(PropertyInfo propertyInfo) { - object[] customAttributesOnProperty = propertyInfo.GetCustomAttributes(typeof(ComVisibleAttribute), true); - - foreach (ComVisibleAttribute attr in customAttributesOnProperty) { - if (!attr.Value) { - return false; - } - } - return true; - } - - #endregion - } -} diff --git a/Microsoft.VisualStudio.Project/Automation/OAProperty.cs b/Microsoft.VisualStudio.Project/Automation/OAProperty.cs deleted file mode 100644 index e53049f7..00000000 --- a/Microsoft.VisualStudio.Project/Automation/OAProperty.cs +++ /dev/null @@ -1,183 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System.Diagnostics; -using System.Reflection; -using System.Runtime.ExceptionServices; -using System.Runtime.InteropServices; - -namespace Microsoft.VisualStudioTools.Project.Automation { - [ComVisible(true)] - public class OAProperty : EnvDTE.Property { - private const string WrappedStacktraceKey = - "$$Microsoft.VisualStudioTools.Project.Automation.WrappedStacktraceKey$$"; - - #region fields - private OAProperties parent; - private PropertyInfo pi; - #endregion - - #region ctors - - public OAProperty(OAProperties parent, PropertyInfo pi) { - this.parent = parent; - this.pi = pi; - } - #endregion - - #region EnvDTE.Property - /// - /// Microsoft Internal Use Only. - /// - public object Application { - get { return null; } - } - - /// - /// Gets the Collection containing the Property object supporting this property. - /// - public EnvDTE.Properties Collection { - get { - //todo: EnvDTE.Property.Collection - return this.parent; - } - } - - /// - /// Gets the top-level extensibility object. - /// - public EnvDTE.DTE DTE { - get { - return this.parent.DTE; - } - } - - /// - /// Returns one element of a list. - /// - /// The index of the item to display. - /// The index of the item to display. Reserved for future use. - /// The index of the item to display. Reserved for future use. - /// The index of the item to display. Reserved for future use. - /// The value of a property - public object get_IndexedValue(object index1, object index2, object index3, object index4) { - Debug.Assert(pi.GetIndexParameters().Length == 0); - return this.Value; - } - - /// - /// Setter function to set properties values. - /// - /// - public void let_Value(object value) { - this.Value = value; - } - - /// - /// Gets the name of the object. - /// - public string Name { - get { - var attrs = pi.GetCustomAttributes(typeof(PropertyNameAttribute), true); - if (attrs.Length > 0) { - return ((PropertyNameAttribute)attrs[0]).Name; - } - return pi.Name; - } - } - - /// - /// Gets the number of indices required to access the value. - /// - public short NumIndices { - get { return (short)pi.GetIndexParameters().Length; } - } - - /// - /// Sets or gets the object supporting the Property object. - /// - public object Object { - get { - return this.parent.Target; - } - set { - } - } - - /// - /// Microsoft Internal Use Only. - /// - public EnvDTE.Properties Parent { - get { return this.parent; } - } - - /// - /// Sets the value of the property at the specified index. - /// - /// The index of the item to set. - /// Reserved for future use. - /// Reserved for future use. - /// Reserved for future use. - /// The value to set. - public void set_IndexedValue(object index1, object index2, object index3, object index4, object value) { - Debug.Assert(pi.GetIndexParameters().Length == 0); - UIThread.Invoke(() => { - this.Value = value; - }); - } - - /// - /// Gets or sets the value of the property returned by the Property object. - /// - public object Value { - get { - using (AutomationScope scope = new AutomationScope(this.parent.Target.HierarchyNode.ProjectMgr.Site)) { - return UIThread.Invoke(() => { - try { - return pi.GetValue(this.parent.Target, null); - } catch (TargetInvocationException ex) { - // If the property raised an exception, we want to - // rethrow that exception and not the outer one. - if (ex.InnerException != null) { - ex.InnerException.Data[WrappedStacktraceKey] = ex.InnerException.StackTrace; - throw ex.InnerException; - } - throw; - } - }); - } - } - set { - using (AutomationScope scope = new AutomationScope(this.parent.Target.HierarchyNode.ProjectMgr.Site)) { - UIThread.Invoke(() => { - try { - this.pi.SetValue(this.parent.Target, value, null); - } catch (TargetInvocationException ex) { - // If the property raised an exception, we want to - // rethrow that exception and not the outer one. - if (ex.InnerException != null) { - ex.InnerException.Data[WrappedStacktraceKey] = ex.InnerException.StackTrace; - throw ex.InnerException; - } - throw; - } - }); - } - } - } - #endregion - } -} diff --git a/Microsoft.VisualStudio.Project/Automation/OAReferenceFolderItem.cs b/Microsoft.VisualStudio.Project/Automation/OAReferenceFolderItem.cs deleted file mode 100644 index f48940df..00000000 --- a/Microsoft.VisualStudio.Project/Automation/OAReferenceFolderItem.cs +++ /dev/null @@ -1,54 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.InteropServices; - -namespace Microsoft.VisualStudioTools.Project.Automation { - /// - /// Contains OAReferenceItem objects - /// - [ComVisible(true), CLSCompliant(false)] - public class OAReferenceFolderItem : OAProjectItem { - #region ctors - internal OAReferenceFolderItem(OAProject project, ReferenceContainerNode node) - : base(project, node) { - } - - #endregion - - private new ReferenceContainerNode Node { - get { - return (ReferenceContainerNode)base.Node; - } - } - - #region overridden methods - /// - /// Returns the project items collection of all the references defined for this project. - /// - public override EnvDTE.ProjectItems ProjectItems { - get { - return new OANavigableProjectItems(this.Project, this.Node); - } - } - - - #endregion - } -} diff --git a/Microsoft.VisualStudio.Project/Automation/OAReferenceItem.cs b/Microsoft.VisualStudio.Project/Automation/OAReferenceItem.cs deleted file mode 100644 index 38fdebd7..00000000 --- a/Microsoft.VisualStudio.Project/Automation/OAReferenceItem.cs +++ /dev/null @@ -1,91 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.InteropServices; - -namespace Microsoft.VisualStudioTools.Project.Automation { - /// - /// Represents the automation object equivalent to a ReferenceNode object - /// - [ComVisible(true), CLSCompliant(false)] - public class OAReferenceItem : OAProjectItem { - #region ctors - internal OAReferenceItem(OAProject project, ReferenceNode node) - : base(project, node) { - } - - #endregion - - private new ReferenceNode Node { - get { - return (ReferenceNode)base.Node; - } - } - - #region overridden methods - /// - /// Not implemented. If called throws invalid operation exception. - /// - public override void Delete() { - throw new InvalidOperationException(); - } - - - /// - /// Not implemented. If called throws invalid operation exception. - /// - /// A Constants. vsViewKind indicating the type of view to use. - /// - public override EnvDTE.Window Open(string viewKind) { - throw new InvalidOperationException(); - } - - /// - /// Gets or sets the name of the object. - /// - public override string Name { - get { - return base.Name; - } - set { - throw new InvalidOperationException(); - } - } - - /// - /// Gets the ProjectItems collection containing the ProjectItem object supporting this property. - /// - public override EnvDTE.ProjectItems Collection { - get { - // Get the parent node (ReferenceContainerNode) - ReferenceContainerNode parentNode = this.Node.Parent as ReferenceContainerNode; - Debug.Assert(parentNode != null, "Failed to get the parent node"); - - // Get the ProjectItems object for the parent node - if (parentNode != null) { - // The root node for the project - return ((OAReferenceFolderItem)parentNode.GetAutomationObject()).ProjectItems; - } - - return null; - } - } - #endregion - } -} diff --git a/Microsoft.VisualStudio.Project/Automation/VSProject/OAAssemblyReference.cs b/Microsoft.VisualStudio.Project/Automation/VSProject/OAAssemblyReference.cs deleted file mode 100644 index 2f328d02..00000000 --- a/Microsoft.VisualStudio.Project/Automation/VSProject/OAAssemblyReference.cs +++ /dev/null @@ -1,148 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System.Diagnostics.CodeAnalysis; -using System.Reflection; -using System.Runtime.InteropServices; -using System.Text; -using VSLangProj; - -namespace Microsoft.VisualStudioTools.Project.Automation { - [ComVisible(true)] - public class OAAssemblyReference : OAReferenceBase { - internal OAAssemblyReference(AssemblyReferenceNode assemblyReference) : - base(assemblyReference) { - } - - internal new AssemblyReferenceNode BaseReferenceNode { - get { - return (AssemblyReferenceNode)base.BaseReferenceNode; - } - } - - #region Reference override - public override int BuildNumber { - get { - if ((null == BaseReferenceNode.ResolvedAssembly) || - (null == BaseReferenceNode.ResolvedAssembly.Version)) { - return 0; - } - return BaseReferenceNode.ResolvedAssembly.Version.Build; - } - } - public override string Culture { - get { - if ((null == BaseReferenceNode.ResolvedAssembly) || - (null == BaseReferenceNode.ResolvedAssembly.CultureInfo)) { - return string.Empty; - } - return BaseReferenceNode.ResolvedAssembly.CultureInfo.Name; - } - } - public override string Identity { - get { - // Note that in this function we use the assembly name instead of the resolved one - // because the identity of this reference is the assembly name needed by the project, - // not the specific instance found in this machine / environment. - if (null == BaseReferenceNode.AssemblyName) { - return null; - } - // changed from MPFProj, http://mpfproj10.codeplex.com/workitem/11274 - return BaseReferenceNode.AssemblyName.Name; - } - } - public override int MajorVersion { - get { - if ((null == BaseReferenceNode.ResolvedAssembly) || - (null == BaseReferenceNode.ResolvedAssembly.Version)) { - return 0; - } - return BaseReferenceNode.ResolvedAssembly.Version.Major; - } - } - public override int MinorVersion { - get { - if ((null == BaseReferenceNode.ResolvedAssembly) || - (null == BaseReferenceNode.ResolvedAssembly.Version)) { - return 0; - } - return BaseReferenceNode.ResolvedAssembly.Version.Minor; - } - } - - public override string PublicKeyToken { - get { - if ((null == BaseReferenceNode.ResolvedAssembly) || - (null == BaseReferenceNode.ResolvedAssembly.GetPublicKeyToken())) { - return null; - } - StringBuilder builder = new StringBuilder(); - byte[] publicKeyToken = BaseReferenceNode.ResolvedAssembly.GetPublicKeyToken(); - for (int i = 0; i < publicKeyToken.Length; i++) { - // changed from MPFProj: - // http://mpfproj10.codeplex.com/WorkItem/View.aspx?WorkItemId=8257 - builder.AppendFormat("{0:x2}", publicKeyToken[i]); - } - return builder.ToString(); - } - } - - public override string Name { - get { - if (null != BaseReferenceNode.ResolvedAssembly) { - return BaseReferenceNode.ResolvedAssembly.Name; - } - if (null != BaseReferenceNode.AssemblyName) { - return BaseReferenceNode.AssemblyName.Name; - } - return null; - } - } - public override int RevisionNumber { - get { - if ((null == BaseReferenceNode.ResolvedAssembly) || - (null == BaseReferenceNode.ResolvedAssembly.Version)) { - return 0; - } - return BaseReferenceNode.ResolvedAssembly.Version.Revision; - } - } - public override bool StrongName { - get { - if ((null == BaseReferenceNode.ResolvedAssembly) || - (0 == (BaseReferenceNode.ResolvedAssembly.Flags & AssemblyNameFlags.PublicKey))) { - return false; - } - return true; - } - } - public override prjReferenceType Type { - get { - return prjReferenceType.prjReferenceTypeAssembly; - } - } - public override string Version { - get { - if ((null == BaseReferenceNode.ResolvedAssembly) || - (null == BaseReferenceNode.ResolvedAssembly.Version)) { - return string.Empty; - } - return BaseReferenceNode.ResolvedAssembly.Version.ToString(); - } - } - #endregion - } -} diff --git a/Microsoft.VisualStudio.Project/Automation/VSProject/OAProjectReference.cs b/Microsoft.VisualStudio.Project/Automation/VSProject/OAProjectReference.cs deleted file mode 100644 index bd427cb1..00000000 --- a/Microsoft.VisualStudio.Project/Automation/VSProject/OAProjectReference.cs +++ /dev/null @@ -1,98 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.InteropServices; -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.Shell; -using Microsoft.VisualStudio.Shell.Interop; -using VSLangProj; - -namespace Microsoft.VisualStudioTools.Project.Automation -{ - /// - /// Represents a project reference of the solution - /// - [ComVisible(true)] - public class OAProjectReference : OAReferenceBase - { - internal OAProjectReference(ProjectReferenceNode projectReference) : - base(projectReference) - { - } - - internal new ProjectReferenceNode BaseReferenceNode { - get { return (ProjectReferenceNode)base.BaseReferenceNode; } - } - - #region Reference override - public override string Culture - { - get { return string.Empty; } - } - public override string Name - { - get { return BaseReferenceNode.ReferencedProjectName; } - } - public override string Identity - { - get - { - return BaseReferenceNode.Caption; - } - } - public override string Path - { - get - { - return BaseReferenceNode.ReferencedProjectOutputPath; - } - } - public override EnvDTE.Project SourceProject - { - get - { - if (Guid.Empty == BaseReferenceNode.ReferencedProjectGuid) - { - return null; - } - IVsHierarchy hierarchy = VsShellUtilities.GetHierarchy(BaseReferenceNode.ProjectMgr.Site, BaseReferenceNode.ReferencedProjectGuid); - if (null == hierarchy) - { - return null; - } - object extObject; - if (Microsoft.VisualStudio.ErrorHandler.Succeeded( - hierarchy.GetProperty(VSConstants.VSITEMID_ROOT, (int)__VSHPROPID.VSHPROPID_ExtObject, out extObject))) - { - return extObject as EnvDTE.Project; - } - return null; - } - } - public override prjReferenceType Type - { - // TODO: Write the code that finds out the type of the output of the source project. - get { return prjReferenceType.prjReferenceTypeAssembly; } - } - public override string Version - { - get { return string.Empty; } - } - #endregion - } -} diff --git a/Microsoft.VisualStudio.Project/Automation/VSProject/OAReferenceBase.cs b/Microsoft.VisualStudio.Project/Automation/VSProject/OAReferenceBase.cs deleted file mode 100644 index e72dbde6..00000000 --- a/Microsoft.VisualStudio.Project/Automation/VSProject/OAReferenceBase.cs +++ /dev/null @@ -1,202 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Runtime.InteropServices; -using VSLangProj; -using VSLangProj80; - -namespace Microsoft.VisualStudioTools.Project.Automation { - /// - /// Represents the automation equivalent of ReferenceNode - /// - /// - [ComVisible(true)] - public abstract class OAReferenceBase : Reference3 { - #region fields - private ReferenceNode referenceNode; - #endregion - - #region ctors - internal OAReferenceBase(ReferenceNode referenceNode) { - this.referenceNode = referenceNode; - } - #endregion - - #region properties - internal ReferenceNode BaseReferenceNode { - get { return referenceNode; } - } - #endregion - - #region Reference Members - public virtual int BuildNumber { - get { return 0; } - } - - public virtual References Collection { - get { - return BaseReferenceNode.Parent.Object as References; - } - } - - public virtual EnvDTE.Project ContainingProject { - get { - return BaseReferenceNode.ProjectMgr.GetAutomationObject() as EnvDTE.Project; - } - } - - public virtual bool CopyLocal { - get { - throw new NotImplementedException(); - } - set { - throw new NotImplementedException(); - } - } - - public virtual string Culture { - get { throw new NotImplementedException(); } - } - - public virtual EnvDTE.DTE DTE { - get { - return BaseReferenceNode.ProjectMgr.Site.GetService(typeof(EnvDTE.DTE)) as EnvDTE.DTE; - } - } - - public virtual string Description { - get { - return this.Name; - } - } - - public virtual string ExtenderCATID { - get { throw new NotImplementedException(); } - } - - public virtual object ExtenderNames { - get { throw new NotImplementedException(); } - } - - public virtual string Identity { - get { throw new NotImplementedException(); } - } - - public virtual int MajorVersion { - get { return 0; } - } - - public virtual int MinorVersion { - get { return 0; } - } - - public virtual string Name { - get { throw new NotImplementedException(); } - } - - public virtual string Path { - get { - return BaseReferenceNode.Url; - } - } - - public virtual string PublicKeyToken { - get { throw new NotImplementedException(); } - } - - public virtual void Remove() { - BaseReferenceNode.Remove(false); - } - - public virtual int RevisionNumber { - get { return 0; } - } - - public virtual EnvDTE.Project SourceProject { - get { return null; } - } - - public virtual bool StrongName { - get { return false; } - } - - public virtual prjReferenceType Type { - get { throw new NotImplementedException(); } - } - - public virtual string Version { - get { return new Version().ToString(); } - } - - public virtual object get_Extender(string ExtenderName) { - throw new NotImplementedException(); - } - #endregion - - public string Aliases { - get { - throw new NotImplementedException(); - } - set { - throw new NotImplementedException(); - } - } - - public bool AutoReferenced { - get { throw new NotImplementedException(); } - } - - public virtual bool Isolated { - get { - throw new NotImplementedException(); - } - set { - throw new NotImplementedException(); - } - } - - public uint RefType { - get { throw new NotImplementedException(); } - } - - public virtual bool Resolved { - get { throw new NotImplementedException(); } - } - - public string RuntimeVersion { - get { throw new NotImplementedException(); } - } - - public virtual bool SpecificVersion { - get { - throw new NotImplementedException(); - } - set { - throw new NotImplementedException(); - } - } - - public virtual string SubType { - get { - throw new NotImplementedException(); - } - set { - throw new NotImplementedException(); - } - } - } -} diff --git a/Microsoft.VisualStudio.Project/Automation/VSProject/OAReferences.cs b/Microsoft.VisualStudio.Project/Automation/VSProject/OAReferences.cs deleted file mode 100644 index 0776a950..00000000 --- a/Microsoft.VisualStudio.Project/Automation/VSProject/OAReferences.cs +++ /dev/null @@ -1,333 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.InteropServices; -using Microsoft.VisualStudio.Shell.Interop; -using VSLangProj; -using ErrorHandler = Microsoft.VisualStudio.ErrorHandler; - -namespace Microsoft.VisualStudioTools.Project.Automation -{ - /// - /// Represents the automation object for the equivalent ReferenceContainerNode object - /// - [ComVisible(true)] - public class OAReferences : ConnectionPointContainer, - IEventSource<_dispReferencesEvents>, - References, - ReferencesEvents - { - private readonly ProjectNode _project; - private ReferenceContainerNode _container; - - /// - /// Creates a new automation references object. If the project type doesn't - /// support references containerNode is null. - /// - /// - /// - internal OAReferences(ReferenceContainerNode containerNode, ProjectNode project) - { - _container = containerNode; - _project = project; - - AddEventSource<_dispReferencesEvents>(this as IEventSource<_dispReferencesEvents>); - if (_container != null) { - _container.OnChildAdded += new EventHandler(OnReferenceAdded); - _container.OnChildRemoved += new EventHandler(OnReferenceRemoved); - } - } - - #region Private Members - private Reference AddFromSelectorData(VSCOMPONENTSELECTORDATA selector) - { - if (_container == null) { - return null; - } - ReferenceNode refNode = _container.AddReferenceFromSelectorData(selector); - if (null == refNode) - { - return null; - } - - return refNode.Object as Reference; - } - - private Reference FindByName(string stringIndex) - { - foreach (Reference refNode in this) - { - if (0 == string.Compare(refNode.Name, stringIndex, StringComparison.Ordinal)) - { - return refNode; - } - } - return null; - } - #endregion - - #region References Members - - public Reference Add(string bstrPath) - { - // ignore requests from the designer which are framework assemblies and start w/ a *. - if (string.IsNullOrEmpty(bstrPath) || bstrPath.StartsWith("*")) - { - return null; - } - VSCOMPONENTSELECTORDATA selector = new VSCOMPONENTSELECTORDATA(); - selector.type = VSCOMPONENTTYPE.VSCOMPONENTTYPE_File; - selector.bstrFile = bstrPath; - - return AddFromSelectorData(selector); - } - - public Reference AddActiveX(string bstrTypeLibGuid, int lMajorVer, int lMinorVer, int lLocaleId, string bstrWrapperTool) - { - VSCOMPONENTSELECTORDATA selector = new VSCOMPONENTSELECTORDATA(); - selector.type = VSCOMPONENTTYPE.VSCOMPONENTTYPE_Com2; - selector.guidTypeLibrary = new Guid(bstrTypeLibGuid); - selector.lcidTypeLibrary = (uint)lLocaleId; - selector.wTypeLibraryMajorVersion = (ushort)lMajorVer; - selector.wTypeLibraryMinorVersion = (ushort)lMinorVer; - - return AddFromSelectorData(selector); - } - - public Reference AddProject(EnvDTE.Project project) - { - if (null == project || _container == null) - { - return null; - } - // Get the soulution. - IVsSolution solution = _container.ProjectMgr.Site.GetService(typeof(SVsSolution)) as IVsSolution; - if (null == solution) - { - return null; - } - - // Get the hierarchy for this project. - IVsHierarchy projectHierarchy; - ErrorHandler.ThrowOnFailure(solution.GetProjectOfUniqueName(project.UniqueName, out projectHierarchy)); - - // Create the selector data. - VSCOMPONENTSELECTORDATA selector = new VSCOMPONENTSELECTORDATA(); - selector.type = VSCOMPONENTTYPE.VSCOMPONENTTYPE_Project; - - // Get the project reference string. - ErrorHandler.ThrowOnFailure(solution.GetProjrefOfProject(projectHierarchy, out selector.bstrProjRef)); - - selector.bstrTitle = project.Name; - selector.bstrFile = System.IO.Path.GetDirectoryName(project.FullName); - - return AddFromSelectorData(selector); - } - - public EnvDTE.Project ContainingProject - { - get - { - return _project.GetAutomationObject() as EnvDTE.Project; - } - } - - public int Count - { - get - { - if (_container == null) - { - return 0; - } - return _container.EnumReferences().Count; - } - } - - public EnvDTE.DTE DTE - { - get - { - return _project.Site.GetService(typeof(EnvDTE.DTE)) as EnvDTE.DTE; - } - } - - public Reference Find(string bstrIdentity) - { - if (string.IsNullOrEmpty(bstrIdentity)) - { - return null; - } - foreach (Reference refNode in this) - { - if (null != refNode) - { - if (0 == string.Compare(bstrIdentity, refNode.Identity, StringComparison.Ordinal)) - { - return refNode; - } - } - } - return null; - } - - public IEnumerator GetEnumerator() - { - if (_container == null) { - return new List().GetEnumerator(); - } - - List references = new List(); - IEnumerator baseEnum = _container.EnumReferences().GetEnumerator(); - if (null == baseEnum) - { - return references.GetEnumerator(); - } - while (baseEnum.MoveNext()) - { - ReferenceNode refNode = baseEnum.Current as ReferenceNode; - if (null == refNode) - { - continue; - } - Reference reference = refNode.Object as Reference; - if (null != reference) - { - references.Add(reference); - } - } - return references.GetEnumerator(); - } - - public Reference Item(object index) - { - if (_container == null) - { - throw new ArgumentOutOfRangeException("index"); - } - - string stringIndex = index as string; - if (null != stringIndex) - { - return FindByName(stringIndex); - } - // Note that this cast will throw if the index is not convertible to int. - int intIndex = (int)index; - IList refs = _container.EnumReferences(); - if (null == refs) - { - throw new ArgumentOutOfRangeException("index"); - } - if ((intIndex <= 0) || (intIndex > refs.Count)) - { - throw new ArgumentOutOfRangeException("index"); - } - // Let the implementation of IList<> throw in case of index not correct. - return refs[intIndex - 1].Object as Reference; - } - - public object Parent - { - get - { - if (_container == null) - { - return _project.Object; - } - return _container.Parent.Object; - } - } - - #endregion - - #region _dispReferencesEvents_Event Members - public event _dispReferencesEvents_ReferenceAddedEventHandler ReferenceAdded; - public event _dispReferencesEvents_ReferenceChangedEventHandler ReferenceChanged { - add { } - remove { } - } - public event _dispReferencesEvents_ReferenceRemovedEventHandler ReferenceRemoved; - #endregion - - #region Callbacks for the HierarchyNode events - private void OnReferenceAdded(object sender, HierarchyNodeEventArgs args) - { - // Validate the parameters. - if ((_container != sender as ReferenceContainerNode) || - (null == args) || (null == args.Child)) - { - return; - } - - // Check if there is any sink for this event. - if (null == ReferenceAdded) - { - return; - } - - // Check that the removed item implements the Reference interface. - Reference reference = args.Child.Object as Reference; - if (null != reference) - { - ReferenceAdded(reference); - } - } - - private void OnReferenceRemoved(object sender, HierarchyNodeEventArgs args) - { - // Validate the parameters. - if ((_container != sender as ReferenceContainerNode) || - (null == args) || (null == args.Child)) - { - return; - } - - // Check if there is any sink for this event. - if (null == ReferenceRemoved) - { - return; - } - - // Check that the removed item implements the Reference interface. - Reference reference = args.Child.Object as Reference; - if (null != reference) - { - ReferenceRemoved(reference); - } - } - #endregion - - #region IEventSource<_dispReferencesEvents> Members - void IEventSource<_dispReferencesEvents>.OnSinkAdded(_dispReferencesEvents sink) - { - ReferenceAdded += new _dispReferencesEvents_ReferenceAddedEventHandler(sink.ReferenceAdded); - ReferenceChanged += new _dispReferencesEvents_ReferenceChangedEventHandler(sink.ReferenceChanged); - ReferenceRemoved += new _dispReferencesEvents_ReferenceRemovedEventHandler(sink.ReferenceRemoved); - } - - void IEventSource<_dispReferencesEvents>.OnSinkRemoved(_dispReferencesEvents sink) - { - ReferenceAdded -= new _dispReferencesEvents_ReferenceAddedEventHandler(sink.ReferenceAdded); - ReferenceChanged -= new _dispReferencesEvents_ReferenceChangedEventHandler(sink.ReferenceChanged); - ReferenceRemoved -= new _dispReferencesEvents_ReferenceRemovedEventHandler(sink.ReferenceRemoved); - } - #endregion - } -} diff --git a/Microsoft.VisualStudio.Project/Automation/VSProject/OAVSProject.cs b/Microsoft.VisualStudio.Project/Automation/VSProject/OAVSProject.cs deleted file mode 100644 index 8981aacc..00000000 --- a/Microsoft.VisualStudio.Project/Automation/VSProject/OAVSProject.cs +++ /dev/null @@ -1,212 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.InteropServices; -using EnvDTE; -using VSLangProj; - -namespace Microsoft.VisualStudioTools.Project.Automation -{ - /// - /// Represents an automation friendly version of a language-specific project. - /// - [ComVisible(true), CLSCompliant(false)] - public class OAVSProject : VSProject - { - #region fields - private ProjectNode project; - private OAVSProjectEvents events; - #endregion - - #region ctors - internal OAVSProject(ProjectNode project) - { - this.project = project; - } - #endregion - - #region VSProject Members - - public virtual ProjectItem AddWebReference(string bstrUrl) - { - throw new NotImplementedException(); - } - - public virtual BuildManager BuildManager - { - get - { - throw new NotImplementedException(); - //return new OABuildManager(this.project); - } - } - - public virtual void CopyProject(string bstrDestFolder, string bstrDestUNCPath, prjCopyProjectOption copyProjectOption, string bstrUsername, string bstrPassword) - { - throw new NotImplementedException(); - } - - public virtual ProjectItem CreateWebReferencesFolder() - { - throw new NotImplementedException(); - } - - public virtual DTE DTE - { - get - { - return (EnvDTE.DTE)this.project.Site.GetService(typeof(EnvDTE.DTE)); - } - } - - public virtual VSProjectEvents Events - { - get - { - if (events == null) - events = new OAVSProjectEvents(this); - return events; - } - } - - public virtual void Exec(prjExecCommand command, int bSuppressUI, object varIn, out object pVarOut) - { - throw new NotImplementedException(); ; - } - - public virtual void GenerateKeyPairFiles(string strPublicPrivateFile, string strPublicOnlyFile) - { - throw new NotImplementedException(); ; - } - - public virtual string GetUniqueFilename(object pDispatch, string bstrRoot, string bstrDesiredExt) - { - throw new NotImplementedException(); ; - } - - public virtual Imports Imports - { - get - { - throw new NotImplementedException(); - } - } - - public virtual EnvDTE.Project Project - { - get - { - return this.project.GetAutomationObject() as EnvDTE.Project; - } - } - - public virtual References References - { - get - { - ReferenceContainerNode references = project.GetReferenceContainer() as ReferenceContainerNode; - if (null == references) - { - return new OAReferences(null, project); - } - return references.Object as References; - } - } - - public virtual void Refresh() - { - } - - public virtual string TemplatePath - { - get - { - throw new NotImplementedException(); - } - } - - public virtual ProjectItem WebReferencesFolder - { - get - { - throw new NotImplementedException(); - } - } - - public virtual bool WorkOffline - { - get - { - throw new NotImplementedException(); - } - set - { - throw new NotImplementedException(); - } - } - - #endregion - } - - /// - /// Provides access to language-specific project events - /// - [ComVisible(true), CLSCompliant(false)] - public class OAVSProjectEvents : VSProjectEvents - { - #region fields - private OAVSProject vsProject; - #endregion - - #region ctors - public OAVSProjectEvents(OAVSProject vsProject) - { - this.vsProject = vsProject; - } - #endregion - - #region VSProjectEvents Members - - public virtual BuildManagerEvents BuildManagerEvents - { - get - { - return vsProject.BuildManager as BuildManagerEvents; - } - } - - public virtual ImportsEvents ImportsEvents - { - get - { - throw new NotImplementedException(); - } - } - - public virtual ReferencesEvents ReferencesEvents - { - get - { - return vsProject.References as ReferencesEvents; - } - } - - #endregion - } - -} diff --git a/Microsoft.VisualStudio.Project/Automation/VSProject/OAVSProjectItem.cs b/Microsoft.VisualStudio.Project/Automation/VSProject/OAVSProjectItem.cs deleted file mode 100644 index 042edd00..00000000 --- a/Microsoft.VisualStudio.Project/Automation/VSProject/OAVSProjectItem.cs +++ /dev/null @@ -1,82 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System.Diagnostics.CodeAnalysis; -using System.Runtime.InteropServices; -using EnvDTE; -using VSLangProj; - -namespace Microsoft.VisualStudioTools.Project.Automation -{ - /// - /// Represents a language-specific project item - /// - [ComVisible(true)] - public class OAVSProjectItem : VSProjectItem - { - #region fields - private FileNode fileNode; - #endregion - - #region ctors - internal OAVSProjectItem(FileNode fileNode) - { - this.FileNode = fileNode; - } - #endregion - - #region VSProjectItem Members - - public virtual EnvDTE.Project ContainingProject - { - get { return fileNode.ProjectMgr.GetAutomationObject() as EnvDTE.Project; } - } - - public virtual ProjectItem ProjectItem - { - get { return fileNode.GetAutomationObject() as ProjectItem; } - } - - public virtual DTE DTE - { - get { return (DTE)this.fileNode.ProjectMgr.Site.GetService(typeof(DTE)); } - } - - public void RunCustomTool() - { - } - - #endregion - - #region public properties - /// - /// File Node property - /// - internal FileNode FileNode - { - get - { - return fileNode; - } - set - { - fileNode = value; - } - } - #endregion - - } -} diff --git a/Microsoft.VisualStudio.Project/BuildDependency.cs b/Microsoft.VisualStudio.Project/BuildDependency.cs deleted file mode 100644 index 7ace8a1d..00000000 --- a/Microsoft.VisualStudio.Project/BuildDependency.cs +++ /dev/null @@ -1,93 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.Shell; -using Microsoft.VisualStudio.Shell.Interop; - -namespace Microsoft.VisualStudioTools.Project { - public class BuildDependency : IVsBuildDependency { - Guid referencedProjectGuid = Guid.Empty; - ProjectNode projectMgr = null; - - internal BuildDependency(ProjectNode projectMgr, Guid projectReference) { - this.referencedProjectGuid = projectReference; - this.projectMgr = projectMgr; - } - - #region IVsBuildDependency methods - public int get_CanonicalName(out string canonicalName) { - canonicalName = null; - return VSConstants.S_OK; - } - - public int get_Type(out System.Guid guidType) { - // All our dependencies are build projects - guidType = VSConstants.GUID_VS_DEPTYPE_BUILD_PROJECT; - return VSConstants.S_OK; - } - - public int get_Description(out string description) { - description = null; - return VSConstants.S_OK; - } - - [CLSCompliant(false)] - public int get_HelpContext(out uint helpContext) { - helpContext = 0; - return VSConstants.E_NOTIMPL; - } - - public int get_HelpFile(out string helpFile) { - helpFile = null; - return VSConstants.E_NOTIMPL; - } - - public int get_MustUpdateBefore(out int mustUpdateBefore) { - // Must always update dependencies - mustUpdateBefore = 1; - - return VSConstants.S_OK; - } - - public int get_ReferredProject(out object unknownProject) { - unknownProject = null; - - unknownProject = this.GetReferencedHierarchy(); - - // If we cannot find the referenced hierarchy return S_FALSE. - return (unknownProject == null) ? VSConstants.S_FALSE : VSConstants.S_OK; - } - - #endregion - - #region helper methods - private IVsHierarchy GetReferencedHierarchy() { - IVsHierarchy hierarchy = null; - - if (this.referencedProjectGuid == Guid.Empty || this.projectMgr == null || this.projectMgr.IsClosed) { - return hierarchy; - } - - return VsShellUtilities.GetHierarchy(this.projectMgr.Site, this.referencedProjectGuid); - - } - - #endregion - - } -} diff --git a/Microsoft.VisualStudio.Project/BuildPropertyPage.cs b/Microsoft.VisualStudio.Project/BuildPropertyPage.cs deleted file mode 100644 index d7108a34..00000000 --- a/Microsoft.VisualStudio.Project/BuildPropertyPage.cs +++ /dev/null @@ -1,26 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - - -namespace Microsoft.VisualStudioTools.Project { - /// - /// Enumerated list of the properties shown on the build property page - /// - internal enum BuildPropertyPageTag { - OutputPath - } - -} diff --git a/Microsoft.VisualStudio.Project/Command.cs b/Microsoft.VisualStudio.Project/Command.cs deleted file mode 100644 index 442fb2a6..00000000 --- a/Microsoft.VisualStudio.Project/Command.cs +++ /dev/null @@ -1,64 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using Microsoft.VisualStudio.OLE.Interop; - -namespace Microsoft.VisualStudioTools { - /// - /// Base class for available commands. To add a new command you must first update the .vsct file so that - /// our commands are registered and available. Then you need to subclass Command and at a new instance of - /// the command in CommandTable. PythonToolsPackage will then register the command on startup. - /// - internal abstract class Command { - /// - /// Provides the implementation of what should happen when the command is executed. - /// - /// sender is the MenuCommand or OleMenuCommand object which is causing the event to be fired. - /// - public abstract void DoCommand(object sender, EventArgs args); - - /// - /// Enables a command to hook into our edit filter for Python text buffers. - /// - /// Called with the OLECMD object for the command being processed. Returns null - /// if the command does not want to handle this message or the HRESULT that - /// should be returned from the QueryStatus call. - /// - public virtual int? EditFilterQueryStatus(ref OLECMD cmd, IntPtr pCmdText) { - return null; - } - - /// - /// Provides the CommandId for this command which corresponds to the CommandId in the vsct file - /// and PkgCmdId.cs. - /// - public abstract int CommandId { - get; - } - - /// - /// Provides an event handler that will be invoked before the menu containing the command - /// is displayed. This can enable, disable, or hide the menu command. By default returns - /// null. - /// - public virtual EventHandler BeforeQueryStatus { - get { - return null; - } - } - } -} diff --git a/Microsoft.VisualStudio.Project/CommonConfigProvider.cs b/Microsoft.VisualStudio.Project/CommonConfigProvider.cs deleted file mode 100644 index f3a39a8e..00000000 --- a/Microsoft.VisualStudio.Project/CommonConfigProvider.cs +++ /dev/null @@ -1,63 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using Microsoft.VisualStudio; - -namespace Microsoft.VisualStudioTools.Project { - /// - /// Enables the Any CPU Platform form name for Dynamic Projects. - /// Hooks language specific project config. - /// - internal class CommonConfigProvider : ConfigProvider { - private CommonProjectNode _project; - - public CommonConfigProvider(CommonProjectNode project) - : base(project) { - _project = project; - } - - #region overridden methods - - protected override ProjectConfig CreateProjectConfiguration(string configName) { - return _project.MakeConfiguration(configName); - } - - public override int GetPlatformNames(uint celt, string[] names, uint[] actual) { - if (names != null) { - names[0] = "Any CPU"; - } - - if (actual != null) { - actual[0] = 1; - } - - return VSConstants.S_OK; - } - - public override int GetSupportedPlatformNames(uint celt, string[] names, uint[] actual) { - if (names != null) { - names[0] = "Any CPU"; - } - - if (actual != null) { - actual[0] = 1; - } - - return VSConstants.S_OK; - } - #endregion - } -} diff --git a/Microsoft.VisualStudio.Project/CommonConstants.cs b/Microsoft.VisualStudio.Project/CommonConstants.cs deleted file mode 100644 index e0c3ed12..00000000 --- a/Microsoft.VisualStudio.Project/CommonConstants.cs +++ /dev/null @@ -1,123 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.OLE.Interop; -using OleConstants = Microsoft.VisualStudio.OLE.Interop.Constants; -using VsCommands2K = Microsoft.VisualStudio.VSConstants.VSStd2KCmdID; - -namespace Microsoft.VisualStudioTools { - internal static class CommonConstants { - /// - /// . - /// - public const string UIContextNoSolution = "ADFC4E64-0397-11D1-9F4E-00A0C911004F"; - - /// - /// . - /// - public const string UIContextSolutionExists = "f1536ef8-92ec-443c-9ed7-fdadf150da82"; - - /// - /// Do not change this constant. It is a guid of the Visual Studio "Recent" page in - /// the "Add Reference" dialog. - /// - internal const string AddReferenceMRUPageGuid = "{19B97F03-9594-4c1c-BE28-25FF030113B3}"; - - internal const string TextEditorPackage = "{F5E7E720-1401-11D1-883B-0000F87579D2}"; - - /// - /// Do not change this constant. This is Visual Studio core text editor GUID. - /// - public static readonly Guid CMDUIGUID_TextEditor = new Guid("{8B382828-6202-11d1-8870-0000F87579D2}"); - - internal const string LibraryGuid = "c0000061-2c33-4277-bf44-7e5f2677d6b8"; - internal const string FileNodePropertiesGuid = "c000008b-a973-4d60-9518-5ea1411ccd67"; - internal const string SearchPathsPropertiesGuid = "D94E2410-B416-4CB2-B892-AE83D7BF7356"; - internal const string FolderNodePropertiesGuid = "c0000081-fb55-4d5d-901b-ee624db34961"; - internal const string ProjectNodePropertiesGuid = "c0000016-9ab0-4d58-80e6-54f29e8d3144"; - internal static Guid NoSharedCommandsGuid = new Guid("{C4EBB0A2-969D-49D9-B87A-DCA1D3DF3A5B}"); - internal static Guid SearchPathItemTypeGuid = new Guid("{245F8B38-B204-4676-8F59-7415C34C06EA}"); - - //"Set As StartUp File" command - public const string StartupFile = "StartupFile"; - public const uint SetAsStartupFileCmdId = 0x3001; - - // Constants to handle the scrollbars. - public const int ConsoleHorizontalScrollbar = 0; - public const int ConsoleVerticalScrollbar = 1; - - //Start Without Debugging command - public const int StartWithoutDebuggingCmdId = 0x4004; - - //Start Debugging command - public const int StartDebuggingCmdId = 0x4005; - - //Working Directory project property - public const string WorkingDirectory = "WorkingDirectory"; - - //"Open Folder in Windows Explorer" command ID. - //Don't change this! This is Visual Studio constant. - public const VsCommands2K OpenFolderInExplorerCmdId = (VsCommands2K)1635; - - //Sort priority for the Working Directory node - //We want this node to be the first node in the Search Path subtree - public const int WorkingDirectorySortPriority = 100; - - //Project Home project property - public const string ProjectHome = "ProjectHome"; - - //TODO: Is there a constant in the SDK for this? - public const int SizeOfVariant = 16; - - //"Command line arguments" project property - public const string CommandLineArguments = "CommandLineArguments"; - - public const string IsWindowsApplication = "IsWindowsApplication"; - - public const string PublishUrl = "PublishUrl"; - - //These are VS internal constants - don't change them - public static Guid Std97CmdGroupGuid = typeof(VSConstants.VSStd97CmdID).GUID; - public static Guid Std2KCmdGroupGuid = typeof(VSConstants.VSStd2KCmdID).GUID; - - //Command statuses - public const int NotSupportedInvisibleCmdStatus = (int)OleConstants.OLECMDERR_E_NOTSUPPORTED | - (int)OleConstants.OLECMDSTATE_INVISIBLE; - public const int SupportedEnabledCmdStatus = (int)(OLECMDF.OLECMDF_SUPPORTED | - OLECMDF.OLECMDF_ENABLED); - public const int SupportedCmdStatus = (int)OLECMDF.OLECMDF_SUPPORTED; - - /// - /// Show all files is enabled, we show the merged view of project + files - /// - public const string ShowAllFiles = "ShowAllFiles"; - /// - /// Show all files is disabled, we show the project - /// - public const string ProjectFiles = "ProjectFiles"; - /// - /// ProjectView property name for project file to enable / disable show all files setting - /// - public const string ProjectView = "ProjectView"; - - /// - /// Item meta data for whether or not a item in msbuild is visible in the project - /// - public const string Visible = "Visible"; - } -} diff --git a/Microsoft.VisualStudio.Project/CommonEditorFactory.cs b/Microsoft.VisualStudio.Project/CommonEditorFactory.cs deleted file mode 100644 index 43afe615..00000000 --- a/Microsoft.VisualStudio.Project/CommonEditorFactory.cs +++ /dev/null @@ -1,337 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Diagnostics.CodeAnalysis; -using System.Globalization; -using System.Runtime.InteropServices; -using Microsoft.VisualStudio.Designer.Interfaces; -using Microsoft.VisualStudio.OLE.Interop; -using Microsoft.VisualStudio.Shell; -using Microsoft.VisualStudio.Shell.Interop; -using Microsoft.VisualStudio.TextManager.Interop; -using ErrorHandler = Microsoft.VisualStudio.ErrorHandler; -using IOleServiceProvider = Microsoft.VisualStudio.OLE.Interop.IServiceProvider; -using VSConstants = Microsoft.VisualStudio.VSConstants; - -namespace Microsoft.VisualStudioTools.Project { - /// - /// Common factory for creating our editor - /// - [SuppressMessage("Microsoft.Design", "CA1001:TypesThatOwnDisposableFieldsShouldBeDisposable")] - public abstract class CommonEditorFactory : IVsEditorFactory { - private Package _package; - private ServiceProvider _serviceProvider; - private readonly bool _promptEncodingOnLoad; - - public CommonEditorFactory(Package package) { - _package = package; - } - - public CommonEditorFactory(Package package, bool promptEncodingOnLoad) { - _package = package; - _promptEncodingOnLoad = promptEncodingOnLoad; - } - - #region IVsEditorFactory Members - - public virtual int SetSite(Microsoft.VisualStudio.OLE.Interop.IServiceProvider psp) { - _serviceProvider = new ServiceProvider(psp); - return VSConstants.S_OK; - } - - public virtual object GetService(Type serviceType) { - return _serviceProvider.GetService(serviceType); - } - - // This method is called by the Environment (inside IVsUIShellOpenDocument:: - // OpenStandardEditor and OpenSpecificEditor) to map a LOGICAL view to a - // PHYSICAL view. A LOGICAL view identifies the purpose of the view that is - // desired (e.g. a view appropriate for Debugging [LOGVIEWID_Debugging], or a - // view appropriate for text view manipulation as by navigating to a find - // result [LOGVIEWID_TextView]). A PHYSICAL view identifies an actual type - // of view implementation that an IVsEditorFactory can create. - // - // NOTE: Physical views are identified by a string of your choice with the - // one constraint that the default/primary physical view for an editor - // *MUST* use a NULL string as its physical view name (*pbstrPhysicalView = NULL). - // - // NOTE: It is essential that the implementation of MapLogicalView properly - // validates that the LogicalView desired is actually supported by the editor. - // If an unsupported LogicalView is requested then E_NOTIMPL must be returned. - // - // NOTE: The special Logical Views supported by an Editor Factory must also - // be registered in the local registry hive. LOGVIEWID_Primary is implicitly - // supported by all editor types and does not need to be registered. - // For example, an editor that supports a ViewCode/ViewDesigner scenario - // might register something like the following: - // HKLM\Software\Microsoft\VisualStudio\9.0\Editors\ - // {...guidEditor...}\ - // LogicalViews\ - // {...LOGVIEWID_TextView...} = s '' - // {...LOGVIEWID_Code...} = s '' - // {...LOGVIEWID_Debugging...} = s '' - // {...LOGVIEWID_Designer...} = s 'Form' - // - public virtual int MapLogicalView(ref Guid logicalView, out string physicalView) { - // initialize out parameter - physicalView = null; - - bool isSupportedView = false; - // Determine the physical view - if (VSConstants.LOGVIEWID_Primary == logicalView || - VSConstants.LOGVIEWID_Debugging == logicalView || - VSConstants.LOGVIEWID_Code == logicalView || - VSConstants.LOGVIEWID_TextView == logicalView) { - // primary view uses NULL as pbstrPhysicalView - isSupportedView = true; - } else if (VSConstants.LOGVIEWID_Designer == logicalView) { - physicalView = "Design"; - isSupportedView = true; - } - - if (isSupportedView) - return VSConstants.S_OK; - else { - // E_NOTIMPL must be returned for any unrecognized rguidLogicalView values - return VSConstants.E_NOTIMPL; - } - } - - public virtual int Close() { - return VSConstants.S_OK; - } - - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - public virtual int CreateEditorInstance( - uint createEditorFlags, - string documentMoniker, - string physicalView, - IVsHierarchy hierarchy, - uint itemid, - System.IntPtr docDataExisting, - out System.IntPtr docView, - out System.IntPtr docData, - out string editorCaption, - out Guid commandUIGuid, - out int createDocumentWindowFlags) { - // Initialize output parameters - docView = IntPtr.Zero; - docData = IntPtr.Zero; - commandUIGuid = Guid.Empty; - createDocumentWindowFlags = 0; - editorCaption = null; - - // Validate inputs - if ((createEditorFlags & (VSConstants.CEF_OPENFILE | VSConstants.CEF_SILENT)) == 0) { - return VSConstants.E_INVALIDARG; - } - - if (_promptEncodingOnLoad && docDataExisting != IntPtr.Zero) { - return VSConstants.VS_E_INCOMPATIBLEDOCDATA; - } - - // Get a text buffer - IVsTextLines textLines = GetTextBuffer(docDataExisting); - - // Assign docData IntPtr to either existing docData or the new text buffer - if (docDataExisting != IntPtr.Zero) { - docData = docDataExisting; - Marshal.AddRef(docData); - } else { - docData = Marshal.GetIUnknownForObject(textLines); - } - - try { - docView = CreateDocumentView(documentMoniker, physicalView, hierarchy, itemid, textLines, out editorCaption, out commandUIGuid); - } finally { - if (docView == IntPtr.Zero) { - if (docDataExisting != docData && docData != IntPtr.Zero) { - // Cleanup the instance of the docData that we have addref'ed - Marshal.Release(docData); - docData = IntPtr.Zero; - } - } - } - return VSConstants.S_OK; - } - - - #endregion - - #region Helper methods - private IVsTextLines GetTextBuffer(System.IntPtr docDataExisting) { - IVsTextLines textLines; - if (docDataExisting == IntPtr.Zero) { - // Create a new IVsTextLines buffer. - Type textLinesType = typeof(IVsTextLines); - Guid riid = textLinesType.GUID; - Guid clsid = typeof(VsTextBufferClass).GUID; - textLines = _package.CreateInstance(ref clsid, ref riid, textLinesType) as IVsTextLines; - - // set the buffer's site - ((IObjectWithSite)textLines).SetSite(_serviceProvider.GetService(typeof(IOleServiceProvider))); - } else { - // Use the existing text buffer - Object dataObject = Marshal.GetObjectForIUnknown(docDataExisting); - textLines = dataObject as IVsTextLines; - if (textLines == null) { - // Try get the text buffer from textbuffer provider - IVsTextBufferProvider textBufferProvider = dataObject as IVsTextBufferProvider; - if (textBufferProvider != null) { - textBufferProvider.GetTextBuffer(out textLines); - } - } - if (textLines == null) { - // Unknown docData type then, so we have to force VS to close the other editor. - ErrorHandler.ThrowOnFailure((int)VSConstants.VS_E_INCOMPATIBLEDOCDATA); - } - - } - return textLines; - } - - private IntPtr CreateDocumentView(string documentMoniker, string physicalView, IVsHierarchy hierarchy, uint itemid, IVsTextLines textLines, out string editorCaption, out Guid cmdUI) { - //Init out params - editorCaption = string.Empty; - cmdUI = Guid.Empty; - - if (string.IsNullOrEmpty(physicalView)) { - // create code window as default physical view - return CreateCodeView(documentMoniker, textLines, ref editorCaption, ref cmdUI); - } else if (string.Compare(physicalView, "design", true, CultureInfo.InvariantCulture) == 0) { - // Create Form view - return CreateFormView(hierarchy, itemid, textLines, ref editorCaption, ref cmdUI); - } - - // We couldn't create the view - // Return special error code so VS can try another editor factory. - ErrorHandler.ThrowOnFailure((int)VSConstants.VS_E_UNSUPPORTEDFORMAT); - - return IntPtr.Zero; - } - - private IntPtr CreateFormView(IVsHierarchy hierarchy, uint itemid, IVsTextLines textLines, ref string editorCaption, ref Guid cmdUI) { - // Request the Designer Service - IVSMDDesignerService designerService = (IVSMDDesignerService)GetService(typeof(IVSMDDesignerService)); - - // Create loader for the designer - IVSMDDesignerLoader designerLoader = (IVSMDDesignerLoader)designerService.CreateDesignerLoader("Microsoft.VisualStudio.Designer.Serialization.VSDesignerLoader"); - - bool loaderInitalized = false; - try { - IOleServiceProvider provider = _serviceProvider.GetService(typeof(IOleServiceProvider)) as IOleServiceProvider; - // Initialize designer loader - designerLoader.Initialize(provider, hierarchy, (int)itemid, textLines); - loaderInitalized = true; - - // Create the designer - IVSMDDesigner designer = designerService.CreateDesigner(provider, designerLoader); - - // Get editor caption - editorCaption = designerLoader.GetEditorCaption((int)READONLYSTATUS.ROSTATUS_Unknown); - - // Get view from designer - object docView = designer.View; - - // Get command guid from designer - cmdUI = designer.CommandGuid; - - return Marshal.GetIUnknownForObject(docView); - - } catch { - // The designer loader may have created a reference to the shell or the text buffer. - // In case we fail to create the designer we should manually dispose the loader - // in order to release the references to the shell and the textbuffer - if (loaderInitalized) { - designerLoader.Dispose(); - } - throw; - } - } - - private IntPtr CreateCodeView(string documentMoniker, IVsTextLines textLines, ref string editorCaption, ref Guid cmdUI) { - Type codeWindowType = typeof(IVsCodeWindow); - Guid riid = codeWindowType.GUID; - Guid clsid = typeof(VsCodeWindowClass).GUID; - IVsCodeWindow window = (IVsCodeWindow)_package.CreateInstance(ref clsid, ref riid, codeWindowType); - ErrorHandler.ThrowOnFailure(window.SetBuffer(textLines)); - ErrorHandler.ThrowOnFailure(window.SetBaseEditorCaption(null)); - ErrorHandler.ThrowOnFailure(window.GetEditorCaption(READONLYSTATUS.ROSTATUS_Unknown, out editorCaption)); - - IVsUserData userData = textLines as IVsUserData; - if (userData != null) { - if (_promptEncodingOnLoad) { - var guid = VSConstants.VsTextBufferUserDataGuid.VsBufferEncodingPromptOnLoad_guid; - userData.SetData(ref guid, (uint)1); - } - } - - InitializeLanguageService(textLines); - - cmdUI = VSConstants.GUID_TextEditorFactory; - return Marshal.GetIUnknownForObject(window); - } - - /// - /// Initializes the language service for the given file. This allows files with different - /// extensions to be opened by the editor type and get correct highlighting and intellisense - /// controllers. - /// - /// New in 1.1 - /// - protected virtual void InitializeLanguageService(IVsTextLines textLines) { - } - - #endregion - - protected void InitializeLanguageService(IVsTextLines textLines, Guid langSid) { - IVsUserData userData = textLines as IVsUserData; - if (userData != null) { - if (langSid != Guid.Empty) { - Guid vsCoreSid = new Guid("{8239bec4-ee87-11d0-8c98-00c04fc2ab22}"); - Guid currentSid; - ErrorHandler.ThrowOnFailure(textLines.GetLanguageServiceID(out currentSid)); - // If the language service is set to the default SID, then - // set it to our language - if (currentSid == vsCoreSid) { - ErrorHandler.ThrowOnFailure(textLines.SetLanguageServiceID(ref langSid)); - } else if (currentSid != langSid) { - // Some other language service has it, so return VS_E_INCOMPATIBLEDOCDATA - throw new COMException("Incompatible doc data", VSConstants.VS_E_INCOMPATIBLEDOCDATA); - } - - Guid bufferDetectLang = VSConstants.VsTextBufferUserDataGuid.VsBufferDetectLangSID_guid; - ErrorHandler.ThrowOnFailure(userData.SetData(ref bufferDetectLang, false)); - } - } - } - } -} diff --git a/Microsoft.VisualStudio.Project/CommonFileNode.cs b/Microsoft.VisualStudio.Project/CommonFileNode.cs deleted file mode 100644 index caa44703..00000000 --- a/Microsoft.VisualStudio.Project/CommonFileNode.cs +++ /dev/null @@ -1,349 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Diagnostics; -using System.Globalization; -using System.IO; -using System.Runtime.InteropServices; -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.ComponentModelHost; -using Microsoft.VisualStudio.Editor; -using Microsoft.VisualStudio.OLE.Interop; -using Microsoft.VisualStudio.Shell; -using Microsoft.VisualStudio.Shell.Interop; -using Microsoft.VisualStudio.Text; -using Microsoft.VisualStudio.Text.Editor; -using Microsoft.VisualStudio.TextManager.Interop; -using Microsoft.VisualStudioTools.Project.Automation; -using VsCommands2K = Microsoft.VisualStudio.VSConstants.VSStd2KCmdID; -using VSConstants = Microsoft.VisualStudio.VSConstants; - -namespace Microsoft.VisualStudioTools.Project { - internal class CommonFileNode : FileNode { - private OAVSProjectItem _vsProjectItem; - private CommonProjectNode _project; - - public CommonFileNode(CommonProjectNode root, ProjectElement e) - : base(root, e) { - _project = root; - } - - #region properties - /// - /// Returns bool indicating whether this node is of subtype "Form" - /// - public bool IsFormSubType { - get { - string result = this.ItemNode.GetMetadata(ProjectFileConstants.SubType); - if (!String.IsNullOrEmpty(result) && string.Compare(result, ProjectFileAttributeValue.Form, true, CultureInfo.InvariantCulture) == 0) - return true; - else - return false; - } - } - /// - /// Returns the SubType of a dynamic FileNode. It is - /// - public string SubType { - get { - return this.ItemNode.GetMetadata(ProjectFileConstants.SubType); - } - set { - this.ItemNode.SetMetadata(ProjectFileConstants.SubType, value); - } - } - - protected internal VSLangProj.VSProjectItem VSProjectItem { - get { - if (null == _vsProjectItem) { - _vsProjectItem = new OAVSProjectItem(this); - } - return _vsProjectItem; - } - } - -#if DEV11_OR_LATER - public override __VSPROVISIONALVIEWINGSTATUS ProvisionalViewingStatus { - get { - return __VSPROVISIONALVIEWINGSTATUS.PVS_Enabled; - } - } -#endif - - #endregion - - #region overridden properties - - internal override object Object { - get { - return this.VSProjectItem; - } - } - - #endregion - - #region overridden methods - - public override int ImageIndex { - get { - if (ItemNode.IsExcluded) { - return (int)ProjectNode.ImageName.ExcludedFile; - } else if (!File.Exists(Url)) { - return (int)ProjectNode.ImageName.MissingFile; - } else if (IsFormSubType) { - return (int)ProjectNode.ImageName.WindowsForm; - } else if (this._project.IsCodeFile(FileName)) { - if (CommonUtils.IsSamePath(this.Url, _project.GetStartupFile())) { - return _project.ImageOffset + (int)CommonImageName.StartupFile; - } else { - return _project.ImageOffset + (int)CommonImageName.File; - } - } - return base.ImageIndex; - } - } - - /// - /// Open a file depending on the SubType property associated with the file item in the project file - /// - protected override void DoDefaultAction() { - FileDocumentManager manager = this.GetDocumentManager() as FileDocumentManager; - Utilities.CheckNotNull(manager, "Could not get the FileDocumentManager"); - - Guid viewGuid = - (IsFormSubType ? VSConstants.LOGVIEWID_Designer : VSConstants.LOGVIEWID_Code); - IVsWindowFrame frame; - manager.Open(false, false, viewGuid, out frame, WindowFrameShowAction.Show); - } - - private static Guid CLSID_VsTextBuffer = new Guid("{8E7B96A8-E33D-11d0-A6D5-00C04FB67F6A}"); - - /// - /// Gets the text buffer for the file opening the document if necessary. - /// - public ITextBuffer GetTextBuffer() { - // http://pytools.codeplex.com/workitem/672 - // When we FindAndLockDocument we marshal on the main UI thread, and the docdata we get - // back is marshalled back so that we'll marshal any calls on it back. When we pass it - // into IVsEditorAdaptersFactoryService we don't go through a COM boundary (it's a managed - // call) and we therefore don't get the marshaled value, and it doesn't know what we're - // talking about. So run the whole operation on the UI thread. - return UIThread.Invoke(() => GetTextBufferOnUIThread()); - } - - private ITextBuffer GetTextBufferOnUIThread() { - IVsTextManager textMgr = (IVsTextManager)GetService(typeof(SVsTextManager)); - var model = GetService(typeof(SComponentModel)) as IComponentModel; - var adapter = model.GetService(); - uint itemid; - - IVsRunningDocumentTable rdt = ProjectMgr.GetService(typeof(SVsRunningDocumentTable)) as IVsRunningDocumentTable; - if (rdt != null) { - IVsHierarchy hier; - IVsPersistDocData persistDocData; - uint cookie; - bool docInRdt = true; - IntPtr docData = IntPtr.Zero; - int hr = NativeMethods.E_FAIL; - try { - //Getting a read lock on the document. Must be released later. - hr = rdt.FindAndLockDocument((uint)_VSRDTFLAGS.RDT_ReadLock, GetMkDocument(), out hier, out itemid, out docData, out cookie); - if (ErrorHandler.Failed(hr) || docData == IntPtr.Zero) { - Guid iid = VSConstants.IID_IUnknown; - cookie = 0; - docInRdt = false; - ILocalRegistry localReg = this.ProjectMgr.GetService(typeof(SLocalRegistry)) as ILocalRegistry; - ErrorHandler.ThrowOnFailure(localReg.CreateInstance(CLSID_VsTextBuffer, null, ref iid, (uint)CLSCTX.CLSCTX_INPROC_SERVER, out docData)); - } - persistDocData = Marshal.GetObjectForIUnknown(docData) as IVsPersistDocData; - } finally { - if (docData != IntPtr.Zero) { - Marshal.Release(docData); - } - } - - //Try to get the Text lines - IVsTextLines srpTextLines = persistDocData as IVsTextLines; - if (srpTextLines == null) { - // Try getting a text buffer provider first - IVsTextBufferProvider srpTextBufferProvider = persistDocData as IVsTextBufferProvider; - if (srpTextBufferProvider != null) { - hr = srpTextBufferProvider.GetTextBuffer(out srpTextLines); - } - } - - // Unlock the document in the RDT if necessary - if (docInRdt && rdt != null) { - ErrorHandler.ThrowOnFailure(rdt.UnlockDocument((uint)(_VSRDTFLAGS.RDT_ReadLock | _VSRDTFLAGS.RDT_Unlock_NoSave), cookie)); - } - - if (srpTextLines != null) { - return adapter.GetDocumentBuffer(srpTextLines); - } - } - - IWpfTextView view = GetTextView(); - - return view.TextBuffer; - } - - public IWpfTextView GetTextView() { - var model = GetService(typeof(SComponentModel)) as IComponentModel; - var adapter = model.GetService(); - - IVsTextView viewAdapter; - uint itemid; - IVsUIShellOpenDocument uiShellOpenDocument = GetService(typeof(SVsUIShellOpenDocument)) as IVsUIShellOpenDocument; - IVsUIHierarchy hierarchy; - IVsWindowFrame pWindowFrame; - - VsShellUtilities.OpenDocument( - ProjectMgr.Site, - this.GetMkDocument(), - Guid.Empty, - out hierarchy, - out itemid, - out pWindowFrame, - out viewAdapter); - - ErrorHandler.ThrowOnFailure(pWindowFrame.Show()); - return adapter.GetWpfTextView(viewAdapter); - } - - public new CommonProjectNode ProjectMgr { - get { - return (CommonProjectNode)base.ProjectMgr; - } - } - - /// - /// Handles the exclude from project command. - /// - /// - internal override int ExcludeFromProject() { - Debug.Assert(this.ProjectMgr != null, "The project item " + this.ToString() + " has not been initialised correctly. It has a null ProjectMgr"); - if (!ProjectMgr.QueryEditProjectFile(false) || - !ProjectMgr.Tracker.CanRemoveItems(new[] { Url }, new[] { VSQUERYREMOVEFILEFLAGS.VSQUERYREMOVEFILEFLAGS_NoFlags })) { - return VSConstants.E_FAIL; - } - - ResetNodeProperties(); - ItemNode.RemoveFromProjectFile(); - if (!File.Exists(Url) || IsLinkFile) { - ProjectMgr.OnItemDeleted(this); - Parent.RemoveChild(this); - } else { - ItemNode = new AllFilesProjectElement(Url, ItemNode.ItemTypeName, ProjectMgr); - if (!ProjectMgr.IsShowingAllFiles) { - IsVisible = false; - ProjectMgr.OnInvalidateItems(Parent); - } - ProjectMgr.ReDrawNode(this, UIHierarchyElement.Icon); - ProjectMgr.OnPropertyChanged(this, (int)__VSHPROPID.VSHPROPID_IsNonMemberItem, 0); - } - ((IVsUIShell)GetService(typeof(SVsUIShell))).RefreshPropertyBrowser(0); - return VSConstants.S_OK; - } - - internal override int IncludeInProject(bool includeChildren) { - if (Parent.ItemNode != null && Parent.ItemNode.IsExcluded) { - // if our parent is excluded it needs to first be included - int hr = Parent.IncludeInProject(false); - if (ErrorHandler.Failed(hr)) { - return hr; - } - } - - if (!ProjectMgr.QueryEditProjectFile(false) || - !ProjectMgr.Tracker.CanAddItems(new[] { Url }, new[] { VSQUERYADDFILEFLAGS.VSQUERYADDFILEFLAGS_NoFlags })) { - return VSConstants.E_FAIL; - } - - ResetNodeProperties(); - - ItemNode = ProjectMgr.CreateMsBuildFileItem( - CommonUtils.GetRelativeFilePath(ProjectMgr.ProjectHome, Url), ProjectMgr.GetItemType(Url) - ); - - IsVisible = true; - ProjectMgr.ReDrawNode(this, UIHierarchyElement.Icon); - ProjectMgr.OnPropertyChanged(this, (int)__VSHPROPID.VSHPROPID_IsNonMemberItem, 0); - - // https://nodejstools.codeplex.com/workitem/273, refresh the property browser... - ((IVsUIShell)GetService(typeof(SVsUIShell))).RefreshPropertyBrowser(0); - - if (CommonUtils.IsSamePath(ProjectMgr.GetStartupFile(), Url)) { - ProjectMgr.BoldItem(this, true); - } - - // On include, the file should be added to source control. - this.ProjectMgr.Tracker.OnItemAdded(this.Url, VSADDFILEFLAGS.VSADDFILEFLAGS_NoFlags); - - return VSConstants.S_OK; - } - - /// - /// Handles the menuitems - /// - internal override int QueryStatusOnNode(Guid guidCmdGroup, uint cmd, IntPtr pCmdText, ref QueryStatusResult result) { - if (guidCmdGroup == Microsoft.VisualStudio.Shell.VsMenus.guidStandardCommandSet2K) { - switch ((VsCommands2K)cmd) { - case VsCommands2K.RUNCUSTOMTOOL: - result |= QueryStatusResult.NOTSUPPORTED | QueryStatusResult.INVISIBLE; - return VSConstants.S_OK; - case VsCommands2K.EXCLUDEFROMPROJECT: - if (ItemNode.IsExcluded) { - result |= QueryStatusResult.NOTSUPPORTED | QueryStatusResult.INVISIBLE; - return VSConstants.S_OK; - } - break; - case VsCommands2K.INCLUDEINPROJECT: - if (ItemNode.IsExcluded) { - result |= QueryStatusResult.SUPPORTED | QueryStatusResult.ENABLED; - return VSConstants.S_OK; - } - break; - } - } - - return base.QueryStatusOnNode(guidCmdGroup, cmd, pCmdText, ref result); - } - - /// - /// Common File Node can only be deleted from file system. - /// - internal override bool CanDeleteItem(__VSDELETEITEMOPERATION deleteOperation) { - if (IsLinkFile) { - // we don't delete link items, we only remove them from the project. If we were - // to return true when queried for both delete from storage and remove from project - // the user would be prompted about which they would like to do. - return deleteOperation == __VSDELETEITEMOPERATION.DELITEMOP_RemoveFromProject; - } - return deleteOperation == __VSDELETEITEMOPERATION.DELITEMOP_DeleteFromStorage; - } - #endregion - - public override int QueryService(ref Guid guidService, out object result) { - if (guidService == typeof(VSLangProj.VSProject).GUID) { - result = ProjectMgr.VSProject; - return VSConstants.S_OK; - } - - return base.QueryService(ref guidService, out result); - } - } -} diff --git a/Microsoft.VisualStudio.Project/CommonFolderNode.cs b/Microsoft.VisualStudio.Project/CommonFolderNode.cs deleted file mode 100644 index 132e3a79..00000000 --- a/Microsoft.VisualStudio.Project/CommonFolderNode.cs +++ /dev/null @@ -1,250 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Diagnostics; -using System.IO; -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.Shell.Interop; -using VsCommands2K = Microsoft.VisualStudio.VSConstants.VSStd2KCmdID; -using VSConstants = Microsoft.VisualStudio.VSConstants; - -namespace Microsoft.VisualStudioTools.Project { - - internal class CommonFolderNode : FolderNode { - private CommonProjectNode _project; - - public CommonFolderNode(CommonProjectNode root, ProjectElement element) - : base(root, element) { - _project = root; - } - - public override bool IsNonMemberItem { - get { - return ItemNode is AllFilesProjectElement; - } - } - - public override object GetIconHandle(bool open) { - if (ItemNode.IsExcluded) { - return ProjectMgr.GetIconHandleByName(open ? - ProjectNode.ImageName.OpenExcludedFolder : - ProjectNode.ImageName.ExcludedFolder - ); - } - return base.GetIconHandle(open); - } - - internal override int QueryStatusOnNode(Guid cmdGroup, uint cmd, IntPtr pCmdText, ref QueryStatusResult result) { - //Hide Exclude from Project command, show everything else normal Folder node supports - if (cmdGroup == Microsoft.VisualStudioTools.Project.VsMenus.guidStandardCommandSet2K) { - switch ((VsCommands2K)cmd) { - case VsCommands2K.EXCLUDEFROMPROJECT: - if (ItemNode.IsExcluded) { - result |= QueryStatusResult.NOTSUPPORTED | QueryStatusResult.INVISIBLE; - return VSConstants.S_OK; - } - break; - case VsCommands2K.INCLUDEINPROJECT: - if (ItemNode.IsExcluded) { - result |= QueryStatusResult.SUPPORTED | QueryStatusResult.ENABLED; - return VSConstants.S_OK; - } - break; - case CommonConstants.OpenFolderInExplorerCmdId: - result |= QueryStatusResult.SUPPORTED | QueryStatusResult.ENABLED; - return VSConstants.S_OK; - } - } else if (cmdGroup == ProjectMgr.SharedCommandGuid) { - switch ((SharedCommands)cmd) { - case SharedCommands.AddExistingFolder: - if (!ItemNode.IsExcluded) { - result |= QueryStatusResult.SUPPORTED | QueryStatusResult.ENABLED; - return VSConstants.S_OK; - } - break; - } - } - return base.QueryStatusOnNode(cmdGroup, cmd, pCmdText, ref result); - } - - internal override int ExecCommandOnNode(Guid cmdGroup, uint cmd, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) { - if (cmdGroup == Microsoft.VisualStudioTools.Project.VsMenus.guidStandardCommandSet2K) { - if ((VsCommands2K)cmd == CommonConstants.OpenFolderInExplorerCmdId) { - Process.Start(this.Url); - return VSConstants.S_OK; - } - } else if (cmdGroup == ProjectMgr.SharedCommandGuid) { - switch ((SharedCommands)cmd) { - case SharedCommands.AddExistingFolder: - return ProjectMgr.AddExistingFolderToNode(this); - case SharedCommands.OpenCommandPromptHere: - var psi = new ProcessStartInfo( - Path.Combine( - Environment.SystemDirectory, - "cmd.exe" - ) - ); - psi.WorkingDirectory = FullPathToChildren; - Process.Start(psi); - return VSConstants.S_OK; - } - } - - return base.ExecCommandOnNode(cmdGroup, cmd, nCmdexecopt, pvaIn, pvaOut); - } - - /// - /// Handles the exclude from project command. - /// - /// - internal override int ExcludeFromProject() { - UIThread.MustBeCalledFromUIThread(); - - Debug.Assert(this.ProjectMgr != null, "The project item " + this.ToString() + " has not been initialised correctly. It has a null ProjectMgr"); - if (!ProjectMgr.QueryEditProjectFile(false) || - !ProjectMgr.QueryFolderRemove(Parent, Url)) { - return VSConstants.E_FAIL; - } - - for (var child = FirstChild; child != null; child = child.NextSibling) { - // we automatically exclude all children below us too - int hr = child.ExcludeFromProject(); - if (ErrorHandler.Failed(hr)) { - return hr; - } - } - - ResetNodeProperties(); - ItemNode.RemoveFromProjectFile(); - if (!Directory.Exists(CommonUtils.TrimEndSeparator(Url))) { - ProjectMgr.OnItemDeleted(this); - Parent.RemoveChild(this); - } else { - ItemNode = new AllFilesProjectElement(Url, ItemNode.ItemTypeName, ProjectMgr); - if (!ProjectMgr.IsShowingAllFiles) { - IsVisible = false; - ProjectMgr.OnInvalidateItems(Parent); - } - ProjectMgr.ReDrawNode(this, UIHierarchyElement.Icon); - ProjectMgr.OnPropertyChanged(this, (int)__VSHPROPID.VSHPROPID_IsNonMemberItem, 0); - } - ((IVsUIShell)GetService(typeof(SVsUIShell))).RefreshPropertyBrowser(0); - - return VSConstants.S_OK; - } - - internal override int ExcludeFromProjectWithProgress() { - using (new WaitDialog( - "Excluding files and folders...", - "Excluding files and folders in your project, this may take several seconds...", - ProjectMgr.Site)) { - return base.ExcludeFromProjectWithProgress(); - } - } - - internal override int IncludeInProject(bool includeChildren) { - if (Parent.ItemNode != null && Parent.ItemNode.IsExcluded) { - // if our parent is excluded it needs to first be included - int hr = Parent.IncludeInProject(false); - if (ErrorHandler.Failed(hr)) { - return hr; - } - } - - if (!ProjectMgr.QueryEditProjectFile(false) || - !ProjectMgr.QueryFolderAdd(Parent, Url)) { - return VSConstants.E_FAIL; - } - - ResetNodeProperties(); - ItemNode = ProjectMgr.CreateMsBuildFileItem( - CommonUtils.GetRelativeDirectoryPath(ProjectMgr.ProjectHome, Url), - ProjectFileConstants.Folder - ); - IsVisible = true; - - if (includeChildren) { - for (var child = FirstChild; child != null; child = child.NextSibling) { - // we automatically include all children below us too - int hr = child.IncludeInProject(includeChildren); - if (ErrorHandler.Failed(hr)) { - return hr; - } - } - } - ProjectMgr.ReDrawNode(this, UIHierarchyElement.Icon); - ProjectMgr.OnPropertyChanged(this, (int)__VSHPROPID.VSHPROPID_IsNonMemberItem, 0); - ((IVsUIShell)GetService(typeof(SVsUIShell))).RefreshPropertyBrowser(0); - - // On include, the folder should be added to source control. - this.ProjectMgr.Tracker.OnFolderAdded(this.Url, VSADDDIRECTORYFLAGS.VSADDDIRECTORYFLAGS_NoFlags); - - return VSConstants.S_OK; - } - - internal override int IncludeInProjectWithProgress(bool includeChildren) { - using (new WaitDialog( - "Including files and folders...", - "Including files and folders to your project, this may take several seconds...", - ProjectMgr.Site)) { - - return IncludeInProject(includeChildren); - } - } - - public override void RenameFolder(string newName) { - string oldName = Url; - _project.SuppressFileChangeNotifications(); - try { - base.RenameFolder(newName); - } finally { - _project.RestoreFileChangeNotifications(); - } - - if (ProjectMgr.TryDeactivateSymLinkWatcher(this)) { - ProjectMgr.CreateSymLinkWatcher(Url); - } - } - - public override void Remove(bool removeFromStorage) { - base.Remove(removeFromStorage); - - // if we were a symlink folder, we need to stop watching now. - ProjectMgr.TryDeactivateSymLinkWatcher(this); - } - - public override void Close() { - base.Close(); - - // make sure this thing isn't hanging around... - ProjectMgr.TryDeactivateSymLinkWatcher(this); - } - - /// - /// Common Folder Node can only be deleted from file system. - /// - internal override bool CanDeleteItem(__VSDELETEITEMOPERATION deleteOperation) { - return deleteOperation == __VSDELETEITEMOPERATION.DELITEMOP_DeleteFromStorage; - } - - public new CommonProjectNode ProjectMgr { - get { - return (CommonProjectNode)base.ProjectMgr; - } - } - } -} diff --git a/Microsoft.VisualStudio.Project/CommonNonCodeFileNode.cs b/Microsoft.VisualStudio.Project/CommonNonCodeFileNode.cs deleted file mode 100644 index 5c48f158..00000000 --- a/Microsoft.VisualStudio.Project/CommonNonCodeFileNode.cs +++ /dev/null @@ -1,46 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Diagnostics; -using Microsoft.VisualStudio.Shell.Interop; - -namespace Microsoft.VisualStudioTools.Project { - internal class CommonNonCodeFileNode : CommonFileNode { - public CommonNonCodeFileNode(CommonProjectNode root, ProjectElement e) - : base(root, e) { - } - - - /// - /// Open a file depending on the SubType property associated with the file item in the project file - /// - protected override void DoDefaultAction() { - if ("WebBrowser".Equals(SubType, StringComparison.OrdinalIgnoreCase)) { - CommonPackage.OpenVsWebBrowser(Url); - return; - } - - FileDocumentManager manager = this.GetDocumentManager() as FileDocumentManager; - Utilities.CheckNotNull(manager, "Could not get the FileDocumentManager"); - - Guid viewGuid = Guid.Empty; - IVsWindowFrame frame; - manager.Open(false, false, viewGuid, out frame, WindowFrameShowAction.Show); - } - - } -} diff --git a/Microsoft.VisualStudio.Project/CommonPackage.cs b/Microsoft.VisualStudio.Project/CommonPackage.cs deleted file mode 100644 index 8787f94d..00000000 --- a/Microsoft.VisualStudio.Project/CommonPackage.cs +++ /dev/null @@ -1,297 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Collections.Generic; -using System.ComponentModel.Design; -using System.Diagnostics; -using System.Runtime.InteropServices; -using Microsoft.VisualStudioTools.Navigation; -using Microsoft.VisualStudioTools.Project; -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.ComponentModelHost; -using Microsoft.VisualStudio.Editor; -using Microsoft.VisualStudio.OLE.Interop; -using Microsoft.VisualStudio.Shell; -using Microsoft.VisualStudio.Shell.Interop; -using Microsoft.VisualStudio.Text.Editor; -using Microsoft.VisualStudio.TextManager.Interop; - -namespace Microsoft.VisualStudioTools { - public abstract class CommonPackage : Package, IOleComponent { - private uint _componentID; - private LibraryManager _libraryManager; - private IOleComponentManager _compMgr; - private static readonly object _commandsLock = new object(); - private static readonly Dictionary _commands = new Dictionary(); - - #region Language-specific abstracts - - public abstract Type GetLibraryManagerType(); - internal abstract LibraryManager CreateLibraryManager(CommonPackage package); - public abstract bool IsRecognizedFile(string filename); - - // TODO: - // public abstract bool TryGetStartupFileAndDirectory(out string filename, out string dir); - - #endregion - - internal CommonPackage() { - // This call is essential for ensuring that future calls to methods - // of UIThread will succeed. Unit tests can disable invoking by - // calling UIThread.InitializeAndNeverInvoke before or after this - // call. If this call does not occur here, your process will - // terminate immediately when an attempt is made to use the UIThread - // methods. - UIThread.InitializeAndAlwaysInvokeToCurrentThread(); - -#if DEBUG - AppDomain.CurrentDomain.UnhandledException += (sender, e) => { - if (e.IsTerminating) { - var ex = e.ExceptionObject as Exception; - if (ex != null) { - Debug.Fail( - string.Format("An unhandled exception is about to terminate the process:\n\n{0}", ex.Message), - ex.ToString() - ); - } else { - Debug.Fail(string.Format( - "An unhandled exception is about to terminate the process:\n\n{0}", - e.ExceptionObject - )); - } - } - }; -#endif - } - - internal static Dictionary Commands { - get { - return _commands; - } - } - - internal static object CommandsLock { - get { - return _commandsLock; - } - } - - protected override void Dispose(bool disposing) { - try { - if (_componentID != 0) { - IOleComponentManager mgr = GetService(typeof(SOleComponentManager)) as IOleComponentManager; - if (mgr != null) { - mgr.FRevokeComponent(_componentID); - } - _componentID = 0; - } - if (null != _libraryManager) { - _libraryManager.Dispose(); - _libraryManager = null; - } - } finally { - base.Dispose(disposing); - } - } - - private object CreateService(IServiceContainer container, Type serviceType) { - if (GetLibraryManagerType() == serviceType) { - return _libraryManager = CreateLibraryManager(this); - } - return null; - } - - internal void RegisterCommands(IEnumerable commands, Guid cmdSet) { - OleMenuCommandService mcs = GetService(typeof(IMenuCommandService)) as OleMenuCommandService; - if (null != mcs) { - lock (_commandsLock) { - foreach (var command in commands) { - var beforeQueryStatus = command.BeforeQueryStatus; - CommandID toolwndCommandID = new CommandID(cmdSet, command.CommandId); - OleMenuCommand menuToolWin = new OleMenuCommand(command.DoCommand, toolwndCommandID); - if (beforeQueryStatus != null) { - menuToolWin.BeforeQueryStatus += beforeQueryStatus; - } - mcs.AddCommand(menuToolWin); - _commands[command] = menuToolWin; - } - } - } - } - - /// - /// Gets the current IWpfTextView that is the active document. - /// - /// - public static IWpfTextView GetActiveTextView() { - var monitorSelection = (IVsMonitorSelection)Package.GetGlobalService(typeof(SVsShellMonitorSelection)); - if (monitorSelection == null) { - return null; - } - object curDocument; - if (ErrorHandler.Failed(monitorSelection.GetCurrentElementValue((uint)VSConstants.VSSELELEMID.SEID_DocumentFrame, out curDocument))) { - // TODO: Report error - return null; - } - - IVsWindowFrame frame = curDocument as IVsWindowFrame; - if (frame == null) { - // TODO: Report error - return null; - } - - object docView = null; - if (ErrorHandler.Failed(frame.GetProperty((int)__VSFPROPID.VSFPROPID_DocView, out docView))) { - // TODO: Report error - return null; - } - - if (docView is IVsCodeWindow) { - IVsTextView textView; - if (ErrorHandler.Failed(((IVsCodeWindow)docView).GetPrimaryView(out textView))) { - // TODO: Report error - return null; - } - - var model = (IComponentModel)GetGlobalService(typeof(SComponentModel)); - var adapterFactory = model.GetService(); - var wpfTextView = adapterFactory.GetWpfTextView(textView); - return wpfTextView; - } - return null; - } - - public static IComponentModel ComponentModel { - get { - return (IComponentModel)GetGlobalService(typeof(SComponentModel)); - } - } - - internal static CommonProjectNode GetStartupProject() { - var buildMgr = (IVsSolutionBuildManager)Package.GetGlobalService(typeof(IVsSolutionBuildManager)); - IVsHierarchy hierarchy; - if (buildMgr != null && ErrorHandler.Succeeded(buildMgr.get_StartupProject(out hierarchy)) && hierarchy != null) { - return hierarchy.GetProject().GetCommonProject(); - } - return null; - } - - protected override void Initialize() { - var container = (IServiceContainer)this; - //container.AddService(GetLanguageServiceType(), CreateService, true); - container.AddService(GetLibraryManagerType(), CreateService, true); - - var componentManager = _compMgr = (IOleComponentManager)GetService(typeof(SOleComponentManager)); - OLECRINFO[] crinfo = new OLECRINFO[1]; - crinfo[0].cbSize = (uint)Marshal.SizeOf(typeof(OLECRINFO)); - crinfo[0].grfcrf = (uint)_OLECRF.olecrfNeedIdleTime; - crinfo[0].grfcadvf = (uint)_OLECADVF.olecadvfModal | (uint)_OLECADVF.olecadvfRedrawOff | (uint)_OLECADVF.olecadvfWarningsOff; - crinfo[0].uIdleTimeInterval = 0; - ErrorHandler.ThrowOnFailure(componentManager.FRegisterComponent(this, crinfo, out _componentID)); - - base.Initialize(); - } - - internal static void OpenWebBrowser(string url) { - var uri = new Uri(url); - Process.Start(new ProcessStartInfo(uri.AbsoluteUri)); - return; - } - - internal static void OpenVsWebBrowser(string url) { - UIThread.Invoke(() => { - var web = GetGlobalService(typeof(SVsWebBrowsingService)) as IVsWebBrowsingService; - if (web == null) { - OpenWebBrowser(url); - return; - } - - IVsWindowFrame frame; - ErrorHandler.ThrowOnFailure(web.Navigate(url, (uint)__VSWBNAVIGATEFLAGS.VSNWB_ForceNew, out frame)); - frame.Show(); - }); - } - - #region IOleComponent Members - - public int FContinueMessageLoop(uint uReason, IntPtr pvLoopData, MSG[] pMsgPeeked) { - return 1; - } - - public virtual int FDoIdle(uint grfidlef) { - if (null != _libraryManager) { - _libraryManager.OnIdle(_compMgr); - } - - var onIdle = OnIdle; - if (onIdle != null) { - onIdle(this, new ComponentManagerEventArgs(_compMgr)); - } - - return 0; - } - - internal event EventHandler OnIdle; - - public int FPreTranslateMessage(MSG[] pMsg) { - return 0; - } - - public int FQueryTerminate(int fPromptUser) { - return 1; - } - - public int FReserved1(uint dwReserved, uint message, IntPtr wParam, IntPtr lParam) { - return 1; - } - - public IntPtr HwndGetWindow(uint dwWhich, uint dwReserved) { - return IntPtr.Zero; - } - - public void OnActivationChange(IOleComponent pic, int fSameComponent, OLECRINFO[] pcrinfo, int fHostIsActivating, OLECHOSTINFO[] pchostinfo, uint dwReserved) { - } - - public void OnAppActivate(int fActive, uint dwOtherThreadID) { - } - - public void OnEnterState(uint uStateID, int fEnter) { - } - - public void OnLoseActivation() { - } - - public void Terminate() { - } - - #endregion - } - - class ComponentManagerEventArgs : EventArgs { - private readonly IOleComponentManager _compMgr; - - public ComponentManagerEventArgs(IOleComponentManager compMgr) { - _compMgr = compMgr; - } - - public IOleComponentManager ComponentManager { - get { - return _compMgr; - } - } - } -} diff --git a/Microsoft.VisualStudio.Project/CommonProjectConfig.cs b/Microsoft.VisualStudio.Project/CommonProjectConfig.cs deleted file mode 100644 index d14128e3..00000000 --- a/Microsoft.VisualStudio.Project/CommonProjectConfig.cs +++ /dev/null @@ -1,46 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - - -using System.Runtime.InteropServices; - -using Microsoft.VisualStudio.Shell.Interop; - -namespace Microsoft.VisualStudioTools.Project { - - [ComVisible(true)] - internal class CommonProjectConfig : ProjectConfig { - private readonly CommonProjectNode/*!*/ _project; - - public CommonProjectConfig(CommonProjectNode/*!*/ project, string configuration) - : base(project, configuration) { - _project = project; - } - - public override int DebugLaunch(uint flags) { - IProjectLauncher starter = _project.GetLauncher(); - - __VSDBGLAUNCHFLAGS launchFlags = (__VSDBGLAUNCHFLAGS)flags; - if ((launchFlags & __VSDBGLAUNCHFLAGS.DBGLAUNCH_NoDebug) == __VSDBGLAUNCHFLAGS.DBGLAUNCH_NoDebug) { - //Start project with no debugger - return starter.LaunchProject(false); - } else { - //Start project with debugger - return starter.LaunchProject(true); - } - } - } -} diff --git a/Microsoft.VisualStudio.Project/CommonProjectNode.cs b/Microsoft.VisualStudio.Project/CommonProjectNode.cs deleted file mode 100644 index 28c6c8e8..00000000 --- a/Microsoft.VisualStudio.Project/CommonProjectNode.cs +++ /dev/null @@ -1,1851 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Collections.Generic; -using System.ComponentModel.Design; -using System.Diagnostics; -using System.Diagnostics.Contracts; -using System.Drawing; -using System.IO; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading; -using System.Windows.Forms; -using System.Windows.Threading; -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.ComponentModelHost; -using Microsoft.VisualStudio.Shell; -using Microsoft.VisualStudio.Shell.Interop; -using Microsoft.VisualStudioTools.Navigation; -using Microsoft.VisualStudioTools.Project.Automation; -using MSBuild = Microsoft.Build.Evaluation; -using VsCommands2K = Microsoft.VisualStudio.VSConstants.VSStd2KCmdID; -using VSConstants = Microsoft.VisualStudio.VSConstants; - -namespace Microsoft.VisualStudioTools.Project { - - public enum CommonImageName { - File = 0, - Project = 1, - SearchPathContainer, - SearchPath, - MissingSearchPath, - StartupFile - } - - internal abstract class CommonProjectNode : ProjectNode, IVsProjectSpecificEditorMap2, IVsDeferredSaveProject { - private CommonProjectPackage/*!*/ _package; - private Guid _mruPageGuid = new Guid(CommonConstants.AddReferenceMRUPageGuid); - private VSLangProj.VSProject _vsProject = null; - private static ImageList _imageList; - private ProjectDocumentsListenerForStartupFileUpdates _projectDocListenerForStartupFileUpdates; - private int _imageOffset; - private FileSystemWatcher _watcher, _attributesWatcher; - private int _suppressFileWatcherCount; - private bool _isRefreshing; - private bool _showingAllFiles; - private object _automationObject; - private CommonPropertyPage _propPage; - private readonly Dictionary _fileChangedHandlers = new Dictionary(); - private Queue _fileSystemChanges = new Queue(); - private object _fileSystemChangesLock = new object(); - private MSBuild.Project _userBuildProject; - private readonly Dictionary _symlinkWatchers = new Dictionary(); - private DiskMerger _currentMerger; -#if DEV11_OR_LATER - private IVsHierarchyItemManager _hierarchyManager; - private Dictionary _needBolding; -#else - private readonly HashSet _needBolding = new HashSet(); -#endif - private int _idleTriggered; - - public CommonProjectNode(CommonProjectPackage/*!*/ package, ImageList/*!*/ imageList) { - Contract.Assert(package != null); - Contract.Assert(imageList != null); - - _package = package; - CanFileNodesHaveChilds = true; - SupportsProjectDesigner = true; - _imageList = imageList; - - //Store the number of images in ProjectNode so we know the offset of the language icons. - _imageOffset = ImageHandler.ImageList.Images.Count; - foreach (Image img in ImageList.Images) { - ImageHandler.AddImage(img); - } - - package.OnIdle += OnIdle; - } - - public override int QueryService(ref Guid guidService, out object result) { - if (guidService == typeof(VSLangProj.VSProject).GUID) { - result = VSProject; - return VSConstants.S_OK; - } - - return base.QueryService(ref guidService, out result); - } - - #region abstract methods - - public abstract Type GetProjectFactoryType(); - public abstract Type GetEditorFactoryType(); - public abstract string GetProjectName(); - - public virtual CommonFileNode CreateCodeFileNode(ProjectElement item) { - return new CommonFileNode(this, item); - } - public virtual CommonFileNode CreateNonCodeFileNode(ProjectElement item) { - return new CommonNonCodeFileNode(this, item); - } - public abstract string GetFormatList(); - public abstract Type GetGeneralPropertyPageType(); - public abstract Type GetLibraryManagerType(); - - #endregion - - #region Properties - - public new CommonProjectPackage/*!*/ Package { - get { return _package; } - } - - public int ImageOffset { - get { return _imageOffset; } - } - - /// - /// Get the VSProject corresponding to this project - /// - protected internal VSLangProj.VSProject VSProject { - get { - if (_vsProject == null) - _vsProject = new OAVSProject(this); - return _vsProject; - } - } - - private IVsHierarchy InteropSafeHierarchy { - get { - IntPtr unknownPtr = Utilities.QueryInterfaceIUnknown(this); - if (IntPtr.Zero == unknownPtr) { - return null; - } - IVsHierarchy hier = Marshal.GetObjectForIUnknown(unknownPtr) as IVsHierarchy; - return hier; - } - } - - /// - /// Indicates whether the project is currently is busy refreshing its hierarchy. - /// - public bool IsRefreshing { - get { return _isRefreshing; } - set { _isRefreshing = value; } - } - - /// - /// Language specific project images - /// - public static ImageList ImageList { - get { - return _imageList; - } - set { - _imageList = value; - } - } - - public CommonPropertyPage PropertyPage { - get { return _propPage; } - set { _propPage = value; } - } - - protected internal MSBuild.Project UserBuildProject { - get { - return _userBuildProject; - } - } - - protected bool IsUserProjectFileDirty { - get { - return _userBuildProject != null && - _userBuildProject.Xml.HasUnsavedChanges; - } - } - - #endregion - - #region overridden properties - - public override bool CanShowAllFiles { - get { - return true; - } - } - - public override bool IsShowingAllFiles { - get { - return _showingAllFiles; - } - } - - /// - /// Since we appended the language images to the base image list in the constructor, - /// this should be the offset in the ImageList of the langauge project icon. - /// - public override int ImageIndex { - get { - return _imageOffset + (int)CommonImageName.Project; - } - } - - public override Guid ProjectGuid { - get { - return GetProjectFactoryType().GUID; - } - } - public override string ProjectType { - get { - return GetProjectName(); - } - } - internal override object Object { - get { - return VSProject; - } - } - #endregion - - #region overridden methods - - public override object GetAutomationObject() { - if (_automationObject == null) { - _automationObject = base.GetAutomationObject(); - } - return _automationObject; - } - - internal override int QueryStatusOnNode(Guid cmdGroup, uint cmd, IntPtr pCmdText, ref QueryStatusResult result) { - if (cmdGroup == Microsoft.VisualStudioTools.Project.VsMenus.guidStandardCommandSet2K) { - switch ((VsCommands2K)cmd) { - case VsCommands2K.ECMD_PUBLISHSELECTION: - if (pCmdText != IntPtr.Zero && NativeMethods.OLECMDTEXT.GetFlags(pCmdText) == NativeMethods.OLECMDTEXT.OLECMDTEXTF.OLECMDTEXTF_NAME) { - NativeMethods.OLECMDTEXT.SetText(pCmdText, "Publish " + this.Caption); - } - - if (IsPublishingEnabled) { - result |= QueryStatusResult.SUPPORTED | QueryStatusResult.ENABLED; - } else { - result |= QueryStatusResult.SUPPORTED; - } - return VSConstants.S_OK; - - case VsCommands2K.ECMD_PUBLISHSLNCTX: - if (IsPublishingEnabled) { - result |= QueryStatusResult.SUPPORTED | QueryStatusResult.ENABLED; - } else { - result |= QueryStatusResult.SUPPORTED; - } - return VSConstants.S_OK; - case CommonConstants.OpenFolderInExplorerCmdId: - result |= QueryStatusResult.SUPPORTED | QueryStatusResult.ENABLED; - return VSConstants.S_OK; - } - } else if (cmdGroup == SharedCommandGuid) { - switch ((SharedCommands)cmd) { - case SharedCommands.AddExistingFolder: - result |= QueryStatusResult.SUPPORTED | QueryStatusResult.ENABLED; - return VSConstants.S_OK; - } - } - - return base.QueryStatusOnNode(cmdGroup, cmd, pCmdText, ref result); - } - - private bool IsPublishingEnabled { - get { - return !String.IsNullOrWhiteSpace(GetProjectProperty(CommonConstants.PublishUrl)); - } - } - - internal override int ExecCommandOnNode(Guid cmdGroup, uint cmd, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) { - if (cmdGroup == Microsoft.VisualStudioTools.Project.VsMenus.guidStandardCommandSet2K) { - switch ((VsCommands2K)cmd) { - case VsCommands2K.ECMD_PUBLISHSELECTION: - case VsCommands2K.ECMD_PUBLISHSLNCTX: - Publish(PublishProjectOptions.Default, true); - return VSConstants.S_OK; - case CommonConstants.OpenFolderInExplorerCmdId: - Process.Start(this.ProjectHome); - return VSConstants.S_OK; - } - } else if (cmdGroup == SharedCommandGuid) { - switch ((SharedCommands)cmd) { - case SharedCommands.AddExistingFolder: - return AddExistingFolderToNode(this); - } - } - return base.ExecCommandOnNode(cmdGroup, cmd, nCmdexecopt, pvaIn, pvaOut); - } - - internal int AddExistingFolderToNode(HierarchyNode parent) { - var dir = Dialogs.BrowseForDirectory( - IntPtr.Zero, - parent.FullPathToChildren, - String.Format("Add Existing Folder - {0}", Caption) - ); - if (dir != null) { - DropFilesOrFolders(new[] { dir }, parent); - } - return VSConstants.S_OK; - } - - /// - /// Publishes the project as configured by the user in the Publish option page. - /// - /// If async is true this function begins the publishing and returns w/o waiting for it to complete. No errors are reported. - /// - /// If async is false this function waits for the publish to finish and raises a PublishFailedException with an - /// inner exception indicating the underlying reason for the publishing failure. - /// - /// Returns true if the publish was succeessfully started, false if the project is not configured for publishing - /// - public virtual bool Publish(PublishProjectOptions publishOptions, bool async) { - string publishUrl = publishOptions.DestinationUrl ?? GetProjectProperty(CommonConstants.PublishUrl); - bool found = false; - if (!String.IsNullOrWhiteSpace(publishUrl)) { - var url = new Url(publishUrl); - - var publishers = CommonPackage.ComponentModel.GetExtensions(); - foreach (var publisher in publishers) { - if (publisher.Schema == url.Uri.Scheme) { - var project = new PublishProject(this, publishOptions); - Exception failure = null; - var frame = new DispatcherFrame(); - var thread = new System.Threading.Thread(x => { - try { - publisher.PublishFiles(project, url.Uri); - project.Done(); - frame.Continue = false; - } catch (Exception e) { - failure = e; - project.Failed(e.Message); - frame.Continue = false; - } - }); - thread.Start(); - found = true; - if (!async) { - Dispatcher.PushFrame(frame); - if (failure != null) { - throw new PublishFailedException(String.Format("Publishing of the project {0} failed", Caption), failure); - } - } - break; - } - } - - if (!found) { - var statusBar = (IVsStatusbar)CommonPackage.GetGlobalService(typeof(SVsStatusbar)); - statusBar.SetText(String.Format("Publish failed: Unknown publish scheme ({0})", url.Uri.Scheme)); - } - } else { - var statusBar = (IVsStatusbar)CommonPackage.GetGlobalService(typeof(SVsStatusbar)); - statusBar.SetText(String.Format("Project is not configured for publishing in project properties.")); - } - return found; - } - - public virtual ProjectConfig MakeConfiguration(string activeConfigName) { - return new CommonProjectConfig(this, activeConfigName); - } - - /// - /// As we don't register files/folders in the project file, removing an item is a noop. - /// - public override int RemoveItem(uint reserved, uint itemId, out int result) { - result = 1; - return VSConstants.S_OK; - } - - /// - /// Overriding main project loading method to inject our hierarachy of nodes. - /// - protected override void Reload(out int canceled) { - base.Reload(out canceled); - - BoldStartupItem(); - - OnProjectPropertyChanged += CommonProjectNode_OnProjectPropertyChanged; - - // track file creation/deletes and update our glyphs when files start/stop existing for files in the project. - if (_watcher != null) { - _watcher.EnableRaisingEvents = false; - _watcher.Dispose(); - } - - string userProjectFilename = FileName + PerUserFileExtension; - if (File.Exists(userProjectFilename)) { - _userBuildProject = BuildProject.ProjectCollection.LoadProject(userProjectFilename); - } - - bool? showAllFiles = null; - if (_userBuildProject != null) { - showAllFiles = GetShowAllFilesSetting(_userBuildProject.GetPropertyValue(CommonConstants.ProjectView)); - } - - _showingAllFiles = showAllFiles ?? - GetShowAllFilesSetting(BuildProject.GetPropertyValue(CommonConstants.ProjectView)) ?? - false; - - _watcher = CreateFileSystemWatcher(ProjectHome); - _attributesWatcher = CreateAttributesWatcher(ProjectHome); - - _currentMerger = new DiskMerger(this, this, ProjectHome); - } - - /// - /// Called to ensure that the hierarchy's show all files nodes are in - /// sync with the file system. - /// - protected void SyncFileSystem() { - if (_currentMerger == null) { - _currentMerger = new DiskMerger(this, this, ProjectHome); - } - while (_currentMerger.ContinueMerge(ParentHierarchy != null)) { - } - _currentMerger = null; - } - - private void BoldStartupItem() { - var startupPath = GetStartupFile(); - if (!string.IsNullOrEmpty(startupPath)) { - var startup = FindNodeByFullPath(startupPath); - if (startup != null) { - BoldItem(startup, true); - } - } - } - - private FileSystemWatcher CreateFileSystemWatcher(string dir) { - var watcher = new FileSystemWatcher(dir) { - InternalBufferSize = 1024 * 4, // 4k is minimum buffer size - IncludeSubdirectories = true - }; - - // Set Event Handlers - watcher.Created += new FileSystemEventHandler(FileExistanceChanged); - watcher.Deleted += new FileSystemEventHandler(FileExistanceChanged); - watcher.Renamed += new RenamedEventHandler(FileNameChanged); - watcher.Changed += FileContentsChanged; -#if DEV12_OR_LATER - watcher.Renamed += FileContentsChanged; -#endif - watcher.Error += WatcherError; - - // Delay setting EnableRaisingEvents until everything else is initialized. - watcher.EnableRaisingEvents = true; - - return watcher; - } - - private FileSystemWatcher CreateAttributesWatcher(string dir) { - var watcher = new FileSystemWatcher(dir) { - IncludeSubdirectories = true, - NotifyFilter = NotifyFilters.Attributes, - InternalBufferSize = 1024 * 4, // 4k is minimum buffer size - }; - - // Set Event Handlers - watcher.Changed += FileAttributesChanged; - watcher.Error += WatcherError; - - // Delay setting EnableRaisingEvents until everything else is initialized. - watcher.EnableRaisingEvents = true; - - return watcher; - } - - /// - /// When the file system watcher buffer overflows we need to scan the entire - /// directory for changes. - /// - private void WatcherError(object sender, ErrorEventArgs e) { - lock (_fileSystemChanges) { - _fileSystemChanges.Clear(); // none of the other changes matter now, we'll rescan the world - _currentMerger = null; // abort any current merge now that we have a new one - _fileSystemChanges.Enqueue(new FileSystemChange(this, WatcherChangeTypes.All, null, watcher: sender as FileWatcher)); - TriggerIdle(); - } - } - - protected override void SaveMSBuildProjectFileAs(string newFileName) { - base.SaveMSBuildProjectFileAs(newFileName); - - if (_userBuildProject != null) { - _userBuildProject.Save(FileName + PerUserFileExtension); - } - } - - protected override void SaveMSBuildProjectFile(string filename) { - base.SaveMSBuildProjectFile(filename); - - if (_userBuildProject != null) { - _userBuildProject.Save(filename + PerUserFileExtension); - } - } - - protected override void Dispose(bool disposing) { - if (disposing) { -#if DEV11_OR_LATER - HierarchyManager = null; -#endif - - var pdl = _projectDocListenerForStartupFileUpdates; - _projectDocListenerForStartupFileUpdates = null; - if (pdl != null) { - pdl.Dispose(); - } - - if (this._userBuildProject != null) { - _userBuildProject.ProjectCollection.UnloadProject(_userBuildProject); - } - _package.OnIdle -= OnIdle; - } - - base.Dispose(disposing); - } - - protected internal override int ShowAllFiles() { - UIThread.MustBeCalledFromUIThread(); - - if (!QueryEditProjectFile(false)) { - return VSConstants.E_FAIL; - } - - if (_showingAllFiles) { - UpdateShowAllFiles(this, enabled: false); - } else { - UpdateShowAllFiles(this, enabled: true); - ExpandItem(EXPANDFLAGS.EXPF_ExpandFolder); - } - - BoldStartupItem(); - - _showingAllFiles = !_showingAllFiles; - - string newPropValue = _showingAllFiles ? CommonConstants.ShowAllFiles : CommonConstants.ProjectFiles; - - var projProperty = BuildProject.GetProperty(CommonConstants.ProjectView); - if (projProperty != null && - !projProperty.IsImported && - !String.IsNullOrWhiteSpace(projProperty.EvaluatedValue)) { - // setting is persisted in main project file, update it there. - BuildProject.SetProperty(CommonConstants.ProjectView, newPropValue); - } else { - // save setting in user project file - SetUserProjectProperty(CommonConstants.ProjectView, newPropValue); - } - - // update project state - return VSConstants.S_OK; - } - - private void UpdateShowAllFiles(HierarchyNode node, bool enabled) { - for (var curNode = node.FirstChild; curNode != null; curNode = curNode.NextSibling) { - UpdateShowAllFiles(curNode, enabled); - - var allFiles = curNode.ItemNode as AllFilesProjectElement; - if (allFiles != null) { - curNode.IsVisible = enabled; - if (enabled) { - OnItemAdded(node, curNode); - } else { - RaiseItemDeleted(curNode); - } - } - } - } - - private static bool? GetShowAllFilesSetting(string showAllFilesValue) { - bool? showAllFiles = null; - string showAllFilesSetting = showAllFilesValue.Trim(); - if (String.Equals(showAllFilesSetting, CommonConstants.ProjectFiles)) { - showAllFiles = false; - } else if (String.Equals(showAllFilesSetting, CommonConstants.ShowAllFiles)) { - showAllFiles = true; - } - return showAllFiles; - } - - /// - /// Performs merging of the file system state with the current project hierarchy, bringing them - /// back into sync. - /// - /// The class can be created, and ContinueMerge should be called until it returns false, at which - /// point the file system has been merged. - /// - /// You can wait between calls to ContinueMerge to enable not blocking the UI. - /// - /// If there were changes which came in while the DiskMerger was processing then those changes will still need - /// to be processed after the DiskMerger completes. - /// - class DiskMerger { - private readonly string _initialDir; - private readonly Stack _remainingDirs = new Stack(); - private readonly CommonProjectNode _project; - private readonly FileWatcher _watcher; - - public DiskMerger(CommonProjectNode project, HierarchyNode parent, string dir, FileWatcher watcher = null) { - _project = project; - _initialDir = dir; - _remainingDirs.Push(new DirState(dir, parent)); - _watcher = watcher; - } - - /// - /// Continues processing the merge request, performing a portion of the full merge possibly - /// returning before the merge has completed. - /// - /// Returns true if the merge needs to continue, or false if the merge has completed. - /// - public bool ContinueMerge(bool hierarchyCreated = true) { - if (_remainingDirs.Count == 0) { // all done - if (_watcher != null) { - _watcher.EnableRaisingEvents = true; - } - _project.BoldStartupItem(); - return false; - } - - var dir = _remainingDirs.Pop(); - if (!Directory.Exists(dir.Name)) { - return true; - } - - HashSet missingChildren = new HashSet(dir.Parent.AllChildren); - IEnumerable dirs; - try { - dirs = Directory.EnumerateDirectories(dir.Name); - } catch { - // directory was deleted, we don't have access, etc... - return true; - } - - bool wasExpanded = hierarchyCreated ? dir.Parent.GetIsExpanded() : false; - foreach (var curDir in dirs) { - if (_project.IsFileHidden(curDir)) { - continue; - } - if (IsFileSymLink(curDir)) { - if (IsRecursiveSymLink(dir.Name, curDir)) { - // don't add recursive sym links - continue; - } - - // track symlinks, we won't get events on the directory - _project.CreateSymLinkWatcher(curDir); - } - - var existing = _project.AddAllFilesFolder(dir.Parent, curDir + Path.DirectorySeparatorChar, hierarchyCreated); - missingChildren.Remove(existing); - _remainingDirs.Push(new DirState(curDir, existing)); - } - - IEnumerable files; - try { - files = Directory.EnumerateFiles(dir.Name); - } catch { - // directory was deleted, we don't have access, etc... - - // We are about to return and some of the previous operations may have affect the Parent's Expanded - // state. Set it back to what it was - if (hierarchyCreated) { - dir.Parent.ExpandItem(wasExpanded ? EXPANDFLAGS.EXPF_ExpandFolder : EXPANDFLAGS.EXPF_CollapseFolder); - } - return true; - } - - foreach (var file in files) { - if (_project.IsFileHidden(file)) { - continue; - } - missingChildren.Remove(_project.AddAllFilesFile(dir.Parent, file)); - } - - // remove the excluded children which are no longer there - foreach (var child in missingChildren) { - if (child.ItemNode.IsExcluded) { - _project.RemoveSubTree(child); - } - } - - if (hierarchyCreated) { - dir.Parent.ExpandItem(wasExpanded ? EXPANDFLAGS.EXPF_ExpandFolder : EXPANDFLAGS.EXPF_CollapseFolder); - } - - return true; - } - - class DirState { - public readonly string Name; - public readonly HierarchyNode Parent; - - public DirState(string name, HierarchyNode parent) { - Name = name; - Parent = parent; - } - } - } - - private void MergeDiskNodes(HierarchyNode curParent, string dir) { - var merger = new DiskMerger(this, curParent, dir); - while (merger.ContinueMerge(ParentHierarchy != null)) { - } - } - - private void RemoveSubTree(HierarchyNode node) { - UIThread.MustBeCalledFromUIThread(); - foreach (var child in node.AllChildren) { - RemoveSubTree(child); - } - node.Parent.RemoveChild(node); - _diskNodes.Remove(node.Url); - } - - private static string GetFinalPathName(string dir) { - using (var dirHandle = NativeMethods.CreateFile( - dir, - NativeMethods.FileDesiredAccess.FILE_LIST_DIRECTORY, - NativeMethods.FileShareFlags.FILE_SHARE_DELETE | - NativeMethods.FileShareFlags.FILE_SHARE_READ | - NativeMethods.FileShareFlags.FILE_SHARE_WRITE, - IntPtr.Zero, - NativeMethods.FileCreationDisposition.OPEN_EXISTING, - NativeMethods.FileFlagsAndAttributes.FILE_FLAG_BACKUP_SEMANTICS, - IntPtr.Zero - )) { - if (!dirHandle.IsInvalid) { - uint pathLen = NativeMethods.MAX_PATH + 1; - uint res; - StringBuilder filePathBuilder; - for (; ; ) { - filePathBuilder = new StringBuilder(checked((int)pathLen)); - res = NativeMethods.GetFinalPathNameByHandle( - dirHandle, - filePathBuilder, - pathLen, - 0 - ); - if (res != 0 && res < pathLen) { - // we had enough space, and got the filename. - break; - } - } - - if (res != 0) { - Debug.Assert(filePathBuilder.ToString().StartsWith("\\\\?\\")); - return filePathBuilder.ToString().Substring(4); - } - } - } - return dir; - } - - private static bool IsRecursiveSymLink(string parentDir, string childDir) { - if (IsFileSymLink(parentDir)) { - // figure out the real parent dir so the check below works w/ multiple - // symlinks pointing at each other - parentDir = GetFinalPathName(parentDir); - } - - string finalPath = GetFinalPathName(childDir); - // check and see if we're recursing infinitely... - if (CommonUtils.IsSubpathOf(finalPath, parentDir)) { - // skip this file - return true; - } - return false; - } - - private static bool IsFileSymLink(string path) { - try { - return (File.GetAttributes(path) & FileAttributes.ReparsePoint) != 0; - } catch (UnauthorizedAccessException) { - return false; - } catch (DirectoryNotFoundException) { - return false; - } catch (FileNotFoundException) { - return false; - } - } - - private bool IsFileHidden(string path) { - if (String.Equals(path, FileName, StringComparison.OrdinalIgnoreCase) || - String.Equals(path, FileName + ".user", StringComparison.OrdinalIgnoreCase) || - String.Equals(Path.GetExtension(path), ".sln") || - String.Equals(Path.GetExtension(path), ".suo")) { - return true; - } - - if (!File.Exists(path) && !Directory.Exists(path)) { - // if the file has disappeared avoid the exception... - return true; // Files/directories that don't exist should be hidden. This also fix DiskMerger when adds files that were already deleted - } - - try { - return (File.GetAttributes(path) & (FileAttributes.Hidden | FileAttributes.System)) != 0; - } catch (UnauthorizedAccessException) { - return false; - } catch (DirectoryNotFoundException) { - return false; - } catch (FileNotFoundException) { - return false; - } - } - - /// - /// Adds a file which is displayed when Show All Files is enabled - /// - private HierarchyNode AddAllFilesFile(HierarchyNode curParent, string file) { - var existing = FindNodeByFullPath(file); - if (existing == null) { - var newFile = CreateFileNode(new AllFilesProjectElement(file, GetItemType(file), this)); - AddAllFilesNode(curParent, newFile); - return newFile; - } - return existing; - } - - /// - /// Adds a folder which is displayed when Show All files is enabled - /// - private HierarchyNode AddAllFilesFolder(HierarchyNode curParent, string curDir, bool hierarchyCreated = true) { - var folderNode = FindNodeByFullPath(curDir); - if (folderNode == null) { - folderNode = CreateFolderNode(new AllFilesProjectElement(curDir, "Folder", this)); - AddAllFilesNode(curParent, folderNode); - - if (hierarchyCreated) { - // Solution Explorer will expand the parent when an item is - // added, which we don't want - folderNode.ExpandItem(EXPANDFLAGS.EXPF_CollapseFolder); - } - } - return folderNode; - } - - /// - /// Initializes and adds a file or folder visible only when Show All files is enabled - /// - private void AddAllFilesNode(HierarchyNode parent, HierarchyNode newNode) { - newNode.IsVisible = IsShowingAllFiles; - parent.AddChild(newNode); - } - - private void FileContentsChanged(object sender, FileSystemEventArgs e) { - if (IsClosed) { - return; - } - - FileSystemEventHandler handler; - if (_fileChangedHandlers.TryGetValue(e.FullPath, out handler)) { - handler(sender, e); - } - } - - private void FileAttributesChanged(object sender, FileSystemEventArgs e) { - lock (_fileSystemChanges) { - if (NoPendingFileSystemRescan()) { - _fileSystemChanges.Enqueue(new FileSystemChange(this, WatcherChangeTypes.Changed, e.FullPath)); - TriggerIdle(); - } - } - } - - private bool NoPendingFileSystemRescan() { - return _fileSystemChanges.Count == 0 || _fileSystemChanges.Peek()._type != WatcherChangeTypes.All; - } - - internal void RegisterFileChangeNotification(FileNode node, FileSystemEventHandler handler) { - _fileChangedHandlers[node.Url] = handler; - } - - internal void UnregisterFileChangeNotification(FileNode node) { - _fileChangedHandlers.Remove(node.Url); - } - - protected override ReferenceContainerNode CreateReferenceContainerNode() { - return new CommonReferenceContainerNode(this); - } - - private void FileNameChanged(object sender, RenamedEventArgs e) { - if (IsClosed) { - return; - } - - try { - lock (_fileSystemChanges) { - // we just generate a delete and creation here - we're just updating the hierarchy - // either changing icons or updating the non-project elements, so we don't need to - // generate rename events or anything like that. This saves us from having to - // handle updating the hierarchy in a special way for renames. - if (NoPendingFileSystemRescan()) { - _fileSystemChanges.Enqueue(new FileSystemChange(this, WatcherChangeTypes.Deleted, e.OldFullPath, true)); - _fileSystemChanges.Enqueue(new FileSystemChange(this, WatcherChangeTypes.Created, e.FullPath, true)); - TriggerIdle(); - } - } - } catch (PathTooLongException) { - // A rename event can be reported for a path that's too long, and then access to RenamedEventArgs - // properties will throw this - nothing we can do other than ignoring it. - } - } - - private void FileExistanceChanged(object sender, FileSystemEventArgs e) { - if (IsClosed) { - return; - } - - lock (_fileSystemChanges) { - if (NoPendingFileSystemRescan()) { - _fileSystemChanges.Enqueue(new FileSystemChange(this, e.ChangeType, e.FullPath)); - TriggerIdle(); - } - } - } - - /// - /// If VS is already idle, we won't keep getting idle events, so we need to post a - /// new event to the queue to flip away from idle and back again. - /// - private void TriggerIdle() { - if (Interlocked.CompareExchange(ref _idleTriggered, 1, 0) == 0) { - UIThread.InvokeAsync(Nop).DoNotWait(); - } - } - - private static readonly Action Nop = () => { }; - - internal void CreateSymLinkWatcher(string curDir) { - if (!CommonUtils.HasEndSeparator(curDir)) { - curDir = curDir + Path.DirectorySeparatorChar; - } - _symlinkWatchers[curDir] = CreateFileSystemWatcher(curDir); - } - - internal bool TryDeactivateSymLinkWatcher(HierarchyNode child) { - FileSystemWatcher watcher; - if (_symlinkWatchers.TryGetValue(child.Url, out watcher)) { - _symlinkWatchers.Remove(child.Url); - watcher.EnableRaisingEvents = false; - watcher.Dispose(); - return true; - } - return false; - } - - private void OnIdle(object sender, ComponentManagerEventArgs e) { - Interlocked.Exchange(ref _idleTriggered, 0); - do { -#if DEV10 - BoldDeferredItems(); -#endif - - using (new DebugTimer("ProcessFileChanges while Idle", 100)) { - if (IsClosed) { - return; - } - - DiskMerger merger; - FileSystemChange change = null; - lock (_fileSystemChanges) { - merger = _currentMerger; - if (merger == null) { - if (_fileSystemChanges.Count == 0) { - break; - } - - change = _fileSystemChanges.Dequeue(); - } - } - - if (merger != null) { - // we have more file merges to process, do this - // before reflecting any other pending updates... - if (!merger.ContinueMerge(ParentHierarchy != null)) { - _currentMerger = null; - } - continue; - } -#if DEBUG - try { -#endif - if (change._type == WatcherChangeTypes.All) { - _currentMerger = new DiskMerger(this, this, ProjectHome, change._watcher); - continue; - } else { - change.ProcessChange(); - } -#if DEBUG - } catch (Exception ex) { - Debug.Fail("Unexpected exception while processing change", ex.ToString()); - throw; - } -#endif - } - } while (e.ComponentManager.FContinueIdle() != 0); - } - - /// - /// Represents an individual change to the file system. We process these in bulk on the - /// UI thread. - /// - class FileSystemChange { - private readonly CommonProjectNode _project; - internal readonly WatcherChangeTypes _type; - private readonly string _path; - private readonly bool _isRename; - internal readonly FileWatcher _watcher; - - public FileSystemChange(CommonProjectNode node, WatcherChangeTypes changeType, string path, bool isRename = false, FileWatcher watcher = null) { - _project = node; - _type = changeType; - _path = path; - _isRename = isRename; - _watcher = watcher; - } - - public override string ToString() { - return "FileSystemChange: " + _isRename + " " + _type + " " + _path; - } - - private void RedrawIcon(HierarchyNode node) { - _project.ReDrawNode(node, UIHierarchyElement.Icon); - - for (var child = node.FirstChild; child != null; child = child.NextSibling) { - RedrawIcon(child); - } - } - - public void ProcessChange() { - var child = _project.FindNodeByFullPath(_path); - if ((_type == WatcherChangeTypes.Deleted || _type == WatcherChangeTypes.Changed) && child == null) { - child = _project.FindNodeByFullPath(_path + Path.DirectorySeparatorChar); - } - switch (_type) { - case WatcherChangeTypes.Deleted: - ChildDeleted(child); - break; - case WatcherChangeTypes.Created: ChildCreated(child); break; - case WatcherChangeTypes.Changed: - // we only care about the attributes - if (_project.IsFileHidden(_path)) { - if (child != null) { - // attributes must of changed to hidden, remove the file - goto case WatcherChangeTypes.Deleted; - } - } else { - if (child == null) { - // attributes must of changed from hidden, add the file - goto case WatcherChangeTypes.Created; - } - } - break; - } - } - - private void RemoveAllFilesChildren(HierarchyNode parent) { - for (var current = parent.FirstChild; current != null; current = current.NextSibling) { - // remove our children first - RemoveAllFilesChildren(current); - - _project.TryDeactivateSymLinkWatcher(current); - - // then remove us if we're an all files node - if (current.ItemNode is AllFilesProjectElement) { - _project.OnItemDeleted(current); - parent.RemoveChild(current); - } - } - } - - private void ChildDeleted(HierarchyNode child) { - if (child != null) { - _project.TryDeactivateSymLinkWatcher(child); - UIThread.MustBeCalledFromUIThread(); - - // rapid changes can arrive out of order, if the file or directory - // actually exists ignore the event. - if ((!File.Exists(child.Url) && !Directory.Exists(child.Url)) || - _project.IsFileHidden(child.Url)) { - - if (child.ItemNode == null) { - // nodes should all have ItemNodes, the project is special. - Debug.Assert(child is ProjectNode); - return; - } - - if (child.ItemNode.IsExcluded) { - RemoveAllFilesChildren(child); - // deleting a show all files item, remove the node. - _project.OnItemDeleted(child); - child.Parent.RemoveChild(child); - child.Close(); - } else { - Debug.Assert(!child.IsNonMemberItem); - // deleting an item in the project, fix the icon, also - // fix the icon of all children which we may have not - // received delete notifications for - RedrawIcon(child); - } - } - } - } - - private void ChildCreated(HierarchyNode child) { - if (child != null) { - // creating an item which was in the project, fix the icon. - _project.ReDrawNode(child, UIHierarchyElement.Icon); - } else { - if (_project.IsFileHidden(_path)) { - // don't add hidden files/folders - return; - } - - // creating a new item, need to create the on all files node - HierarchyNode parent = _project.GetParentFolderForPath(_path); - - if (parent == null) { - // we've hit an error while adding too many files, the file system watcher - // couldn't keep up. That's alright, we'll merge the files in correctly - // in a little while... - return; - } - - bool wasExpanded = parent.GetIsExpanded(); - - if (Directory.Exists(_path)) { - if (IsFileSymLink(_path)) { - string parentDir = CommonUtils.GetParent(_path); - if (IsRecursiveSymLink(parentDir, _path)) { - // don't add recusrive sym link directory - return; - } - - // otherwise we're going to need a new file system watcher - _project.CreateSymLinkWatcher(_path); - } - - var folderNode = _project.AddAllFilesFolder(parent, _path + Path.DirectorySeparatorChar); - bool folderNodeWasExpanded = folderNode.GetIsExpanded(); - - // then add the folder nodes - _project.MergeDiskNodes(folderNode, _path); - _project.OnInvalidateItems(folderNode); - - folderNode.ExpandItem(folderNodeWasExpanded ? EXPANDFLAGS.EXPF_ExpandFolder : EXPANDFLAGS.EXPF_CollapseFolder); - - } else if (File.Exists(_path)) { // rapid changes can arrive out of order, make sure the file still exists - _project.AddAllFilesFile(parent, _path); - if (String.Equals(_project.GetStartupFile(), _path, StringComparison.OrdinalIgnoreCase)) { - _project.BoldStartupItem(); - } - } - - parent.ExpandItem(wasExpanded ? EXPANDFLAGS.EXPF_ExpandFolder : EXPANDFLAGS.EXPF_CollapseFolder); - } - } - } - - - public override int GetGuidProperty(int propid, out Guid guid) { - if ((__VSHPROPID)propid == __VSHPROPID.VSHPROPID_PreferredLanguageSID) { - guid = new Guid("{EFB9A1D6-EA71-4F38-9BA7-368C33FCE8DC}");// GetLanguageServiceType().GUID; - } else { - return base.GetGuidProperty(propid, out guid); - } - return VSConstants.S_OK; - } - - protected override NodeProperties CreatePropertiesObject() { - return new CommonProjectNodeProperties(this); - } - - private bool listenForStartupFile = true; - public bool ListenForStartupFileUpdates { get { return listenForStartupFile; } set { listenForStartupFile = value; } } - - public override int SetSite(Microsoft.VisualStudio.OLE.Interop.IServiceProvider site) { - base.SetSite(site); - - //Initialize a new object to track project document changes so that we can update the StartupFile Property accordingly - if (ListenForStartupFileUpdates) - { - _projectDocListenerForStartupFileUpdates = new ProjectDocumentsListenerForStartupFileUpdates((ServiceProvider)Site, this); - _projectDocListenerForStartupFileUpdates.Init(); - } - -#if DEV11_OR_LATER - UpdateHierarchyManager(alwaysCreate: false); -#endif - - return VSConstants.S_OK; - } - - public override void Close() { - if (null != _projectDocListenerForStartupFileUpdates) { - _projectDocListenerForStartupFileUpdates.Dispose(); - _projectDocListenerForStartupFileUpdates = null; - } - LibraryManager libraryManager = ((IServiceContainer)Package).GetService(GetLibraryManagerType()) as LibraryManager; - if (null != libraryManager) { - libraryManager.UnregisterHierarchy(InteropSafeHierarchy); - } - if (_watcher != null) { - _watcher.EnableRaisingEvents = false; - _watcher.Dispose(); - _watcher = null; - } - - if (_attributesWatcher != null) { - _attributesWatcher.EnableRaisingEvents = false; - _attributesWatcher.Dispose(); - _attributesWatcher = null; - } - -#if DEV11_OR_LATER - _needBolding = null; -#else - _needBolding.Clear(); -#endif - - base.Close(); - } - - public override void Load(string filename, string location, string name, uint flags, ref Guid iidProject, out int canceled) { - base.Load(filename, location, name, flags, ref iidProject, out canceled); - LibraryManager libraryManager = Site.GetService(GetLibraryManagerType()) as LibraryManager; - if (null != libraryManager) { - libraryManager.RegisterHierarchy(InteropSafeHierarchy); - } - } - -#if DEV11_OR_LATER - internal IVsHierarchyItemManager HierarchyManager { - get { - if (_hierarchyManager == null) { - UpdateHierarchyManager(true); - } - return _hierarchyManager; - } - private set { - if (_hierarchyManager != null) { - _hierarchyManager.OnItemAdded -= HierarchyManager_OnItemAdded; - } - _hierarchyManager = value; - if (_hierarchyManager != null) { - _hierarchyManager.OnItemAdded += HierarchyManager_OnItemAdded; - - // We now have a hierarchy manager, so bold any items that - // were waiting to be bolded. - if (_needBolding != null) { - var items = _needBolding; - _needBolding = null; - foreach (var keyValue in items) { - BoldItem(keyValue.Key, keyValue.Value); - } - } - } - } - } - - private void UpdateHierarchyManager(bool alwaysCreate) { - if (Site != null && (alwaysCreate || _needBolding != null && _needBolding.Any())) { - var componentModel = Site.GetService(typeof(SComponentModel)) as IComponentModel; - var newManager = componentModel != null ? - componentModel.GetService() : - null; - - if (newManager != _hierarchyManager) { - HierarchyManager = newManager; - } - } else { - HierarchyManager = null; - } - } - - private void HierarchyManager_OnItemAdded(object sender, HierarchyItemEventArgs e) { - if (_needBolding == null) { - return; - } - if (e.Item.HierarchyIdentity.Hierarchy == GetOuterInterface()) { - // An item has been added to our hierarchy, so bold it if we - // need to. - // Typically these are references/environments, since files are - // added lazily through a mechanism that does not raise this - // event. - bool isBold; - if (_needBolding.TryGetValue(e.Item.HierarchyIdentity.ItemID, out isBold)) { - e.Item.IsBold = isBold; - _needBolding.Remove(e.Item.HierarchyIdentity.ItemID); - if (!_needBolding.Any()) { - _needBolding = null; - } - } - } else if (e.Item.HierarchyIdentity.Hierarchy == GetService(typeof(SVsSolution)) && - e.Item.HierarchyIdentity.NestedHierarchy == GetOuterInterface()) { - // Our project is being added to the solution, and we have - // something to bold, so look up all pending items and force - // them to be created. - // Typically these are files, which are lazily created as the - // containing folders are expanded. - // Under VS 2010, this would cause multiple items to be added to - // Solution Explorer, but VS 2012 fixed this issue. - var items = _needBolding; - _needBolding = null; - foreach (var keyValue in items) { - BoldItem(keyValue.Key, keyValue.Value, force: true); - } - } - } - - private void BoldItem(uint id, bool isBold, bool force = false) { - if (HierarchyManager == null) { - // We don't have a hierarchy manager yet (so really we shouldn't - // even be here...), so defer bolding until we get one. - if (_needBolding == null) { - _needBolding = new Dictionary(); - } - _needBolding[id] = isBold; - return; - } - - IVsHierarchyItem item; - if (force) { - item = HierarchyManager.GetHierarchyItem(GetOuterInterface(), id); - } else if (!HierarchyManager.TryGetHierarchyItem(GetOuterInterface(), id, out item)) { - item = null; - } - - if (item != null) { - item.IsBold = isBold; - } else { - // Item hasn't been created yet, so defer bolding until we get - // the notification from the hierarchy manager. - if (_needBolding == null) { - _needBolding = new Dictionary(); - } - _needBolding[id] = isBold; - } - } - - public void BoldItem(HierarchyNode node, bool isBold) { - BoldItem(node.ID, isBold); - } - -#else // DEV11_OR_LATER - - public void BoldItem(HierarchyNode node, bool isBold) { - IVsUIHierarchyWindow2 windows = UIHierarchyUtilities.GetUIHierarchyWindow( - Site as IServiceProvider, - new Guid(ToolWindowGuids80.SolutionExplorer)) as IVsUIHierarchyWindow2; - - // GetItemState will fail if the item has not yet been added to the - // hierarchy. If it succeeds, we can make the item bold. - uint state; - if (windows == null || - ErrorHandler.Failed(windows.GetItemState( - this.GetOuterInterface(), - node.ID, - (uint)__VSHIERARCHYITEMSTATE.HIS_Bold, - out state))) { - - if (isBold) { - _needBolding.Add(node); - } - return; - } - - if (windows == null || - ErrorHandler.Failed(windows.SetItemAttribute( - this.GetOuterInterface(), - node.ID, - (uint)__VSHIERITEMATTRIBUTE.VSHIERITEMATTRIBUTE_Bold, - isBold - ))) { - if (isBold) { - _needBolding.Add(node); - } - return; - } - } - - private void BoldDeferredItems() { - if (_needBolding.Count == 0 || ParentHierarchy == null) { - return; - } - if (IsClosed) { - _needBolding.Clear(); - return; - } - var items = _needBolding.ToArray(); - - AssertHasParentHierarchy(); - IVsUIHierarchyWindow2 windows = UIHierarchyUtilities.GetUIHierarchyWindow( - Site as IServiceProvider, - new Guid(ToolWindowGuids80.SolutionExplorer)) as IVsUIHierarchyWindow2; - - if (windows == null) { - return; - } - - _needBolding.Clear(); - foreach (var node in items) { - // GetItemState will fail if the item has not yet been added to the - // hierarchy. If it succeeds, we can make the item bold. - uint state; - if (ErrorHandler.Failed(windows.GetItemState( - this.GetOuterInterface(), - node.ID, - (uint)__VSHIERARCHYITEMSTATE.HIS_Bold, - out state))) { - _needBolding.Add(node); - continue; - } - - windows.SetItemAttribute( - this.GetOuterInterface(), - node.ID, - (uint)__VSHIERITEMATTRIBUTE.VSHIERITEMATTRIBUTE_Bold, - true - ); - } - } - -#endif // DEV11_OR_LATER - - /// - /// Overriding to provide project general property page - /// - /// - protected override Guid[] GetConfigurationIndependentPropertyPages() { - var pageType = GetGeneralPropertyPageType(); - if (pageType != null) { - return new[] { pageType.GUID }; - } - return new Guid[0]; - } - - /// - /// Create a file node based on an msbuild item. - /// - /// The msbuild item to be analyzed - public override FileNode CreateFileNode(ProjectElement item) { - Utilities.ArgumentNotNull("item", item); - - string url = item.Url; - CommonFileNode newNode; - if (IsCodeFile(url)) { - newNode = CreateCodeFileNode(item); - } else { - newNode = CreateNonCodeFileNode(item); - } - - string link = item.GetMetadata(ProjectFileConstants.Link); - if (!String.IsNullOrWhiteSpace(link) || - !CommonUtils.IsSubpathOf(ProjectHome, url)) { - newNode.SetIsLinkFile(true); - } - - return newNode; - } - - - /// - /// Create a file node based on absolute file name. - /// - public override FileNode CreateFileNode(string absFileName) { - // Avoid adding files to the project multiple times. Ultimately - // we should not use project items and instead should have virtual items. - - string path = CommonUtils.GetRelativeFilePath(ProjectHome, absFileName); - return CreateFileNode(new MsBuildProjectElement(this, path, GetItemType(path))); - } - - internal virtual string GetItemType(string filename) { - if (IsCodeFile(filename)) { - return "Compile"; - } else { - return "Content"; - } - } - - public ProjectElement MakeProjectElement(string type, string path) { - var item = BuildProject.AddItem(type, MSBuild.ProjectCollection.Escape(path))[0]; - return new MsBuildProjectElement(this, item); - } - - public override int IsDirty(out int isDirty) { - int hr = base.IsDirty(out isDirty); - - if (ErrorHandler.Failed(hr)) { - return hr; - } - - if (isDirty == 0 && IsUserProjectFileDirty) { - isDirty = 1; - } - - return VSConstants.S_OK; - } - - /// - /// Creates the format list for the open file dialog - /// - /// The formatlist to return - /// Success - public override int GetFormatList(out string formatlist) { - formatlist = GetFormatList(); - return VSConstants.S_OK; - } - - protected override ConfigProvider CreateConfigProvider() { - return new CommonConfigProvider(this); - } - #endregion - - #region Methods - - /// - /// This method retrieves an instance of a service that - /// allows to start a project or a file with or without debugging. - /// - public abstract IProjectLauncher/*!*/ GetLauncher(); - - /// - /// Returns resolved value of the current working directory property. - /// - public string GetWorkingDirectory() { - string workDir = GetProjectProperty(CommonConstants.WorkingDirectory, resetCache: false); - - return CommonUtils.GetAbsoluteDirectoryPath(ProjectHome, workDir); - } - - /// - /// Returns resolved value of the startup file property. - /// - internal string GetStartupFile() { - string startupFile = GetProjectProperty(CommonConstants.StartupFile, resetCache: false); - - if (string.IsNullOrEmpty(startupFile)) { - //No startup file is assigned - return null; - } - - return CommonUtils.GetAbsoluteFilePath(ProjectHome, startupFile); - } - - /// - /// Whenever project property has changed - refresh project hierarachy. - /// - private void CommonProjectNode_OnProjectPropertyChanged(object sender, ProjectPropertyChangedArgs e) { - switch (e.PropertyName) { - case CommonConstants.StartupFile: - RefreshStartupFile(this, - CommonUtils.GetAbsoluteFilePath(ProjectHome, e.OldValue), - CommonUtils.GetAbsoluteFilePath(ProjectHome, e.NewValue)); - break; - } - } - - /// - /// Returns first immediate child node (non-recursive) of a given type. - /// - private void RefreshStartupFile(HierarchyNode parent, string oldFile, string newFile) { - AssertHasParentHierarchy(); - IVsUIHierarchyWindow2 windows = UIHierarchyUtilities.GetUIHierarchyWindow( - Site, - new Guid(ToolWindowGuids80.SolutionExplorer)) as IVsUIHierarchyWindow2; - - if (windows == null) { - return; - } - - for (HierarchyNode n = parent.FirstChild; n != null; n = n.NextSibling) { - // TODO: Distinguish between real Urls and fake ones (eg. "References") - if (windows != null) { - var absUrl = CommonUtils.GetAbsoluteFilePath(parent.ProjectMgr.ProjectHome, n.Url); - if (CommonUtils.IsSamePath(oldFile, absUrl)) { - windows.SetItemAttribute( - this, - n.ID, - (uint)__VSHIERITEMATTRIBUTE.VSHIERITEMATTRIBUTE_Bold, - false - ); - ReDrawNode(n, UIHierarchyElement.Icon); - } else if (CommonUtils.IsSamePath(newFile, absUrl)) { - windows.SetItemAttribute( - this, - n.ID, - (uint)__VSHIERITEMATTRIBUTE.VSHIERITEMATTRIBUTE_Bold, - true - ); - ReDrawNode(n, UIHierarchyElement.Icon); - } - } - - RefreshStartupFile(n, oldFile, newFile); - } - } - - /// - /// Provide mapping from our browse objects and automation objects to our CATIDs - /// - protected override void InitializeCATIDs() { - // The following properties classes are specific to current language so we can use their GUIDs directly - AddCATIDMapping(typeof(OAProject), typeof(OAProject).GUID); - // The following is not language specific and as such we need a separate GUID - AddCATIDMapping(typeof(FolderNodeProperties), new Guid(CommonConstants.FolderNodePropertiesGuid)); - // These ones we use the same as language file nodes since both refer to files - AddCATIDMapping(typeof(FileNodeProperties), typeof(FileNodeProperties).GUID); - AddCATIDMapping(typeof(IncludedFileNodeProperties), typeof(IncludedFileNodeProperties).GUID); - // Because our property page pass itself as the object to display in its grid, - // we need to make it have the same CATID - // as the browse object of the project node so that filtering is possible. - var genPropPage = GetGeneralPropertyPageType(); - if (genPropPage != null) { - AddCATIDMapping(genPropPage, genPropPage.GUID); - } - // We could also provide CATIDs for references and the references container node, if we wanted to. - } - - /// - /// Creates the services exposed by this project. - /// - protected virtual object CreateServices(Type serviceType) { - object service = null; - if (typeof(VSLangProj.VSProject) == serviceType) { - service = VSProject; - } else if (typeof(EnvDTE.Project) == serviceType) { - service = GetAutomationObject(); - } - - return service; - } - - /// - /// Set value of user project property - /// - /// Name of property - /// Value of property - public virtual void SetUserProjectProperty(string propertyName, string propertyValue) { - Utilities.ArgumentNotNull("propertyName", propertyName); - - if (_userBuildProject == null) { - // user project file doesn't exist yet, create it. - // We set the content of user file explictly so VS2013 won't add ToolsVersion="12" which would result in incompatibility with VS2010,2012 - var root = Microsoft.Build.Construction.ProjectRootElement.Create(BuildProject.ProjectCollection); - root.ToolsVersion = "4.0"; - _userBuildProject = new MSBuild.Project(root, null, null, BuildProject.ProjectCollection); - _userBuildProject.FullPath = FileName + PerUserFileExtension; - } - _userBuildProject.SetProperty(propertyName, propertyValue ?? String.Empty); - } - - /// - /// Get value of user project property - /// - /// Name of property - public virtual string GetUserProjectProperty(string propertyName) { - Utilities.ArgumentNotNull("propertyName", propertyName); - - if (_userBuildProject == null) - return null; - - // If user project file exists during project load/reload userBuildProject is initiated - return _userBuildProject.GetPropertyValue(propertyName); - } - - #endregion - - #region IVsProjectSpecificEditorMap2 Members - - public int GetSpecificEditorProperty(string mkDocument, int propid, out object result) { - // initialize output params - result = null; - - //Validate input - if (string.IsNullOrEmpty(mkDocument)) - throw new ArgumentException("Was null or empty", "mkDocument"); - - // Make sure that the document moniker passed to us is part of this project - // We also don't care if it is not a dynamic language file node - uint itemid; - int hr; - if (ErrorHandler.Failed(hr = ParseCanonicalName(mkDocument, out itemid))) { - return hr; - } - HierarchyNode hierNode = NodeFromItemId(itemid); - if (hierNode == null || ((hierNode as CommonFileNode) == null)) - return VSConstants.E_NOTIMPL; - - switch (propid) { - case (int)__VSPSEPROPID.VSPSEPROPID_UseGlobalEditorByDefault: - // don't show project default editor, every file supports Python. - result = false; - return VSConstants.E_FAIL; - /*case (int)__VSPSEPROPID.VSPSEPROPID_ProjectDefaultEditorName: - result = "Python Editor"; - break;*/ - } - - return VSConstants.S_OK; - } - - public virtual int GetSpecificEditorType(string mkDocument, out Guid guidEditorType) { - // Ideally we should at this point initalize a File extension to EditorFactory guid Map e.g. - // in the registry hive so that more editors can be added without changing this part of the - // code. Dynamic languages only make usage of one Editor Factory and therefore we will return - // that guid - guidEditorType = GetEditorFactoryType().GUID; - return VSConstants.S_OK; - } - - public int GetSpecificLanguageService(string mkDocument, out Guid guidLanguageService) { - guidLanguageService = Guid.Empty; - return VSConstants.E_NOTIMPL; - } - - public int SetSpecificEditorProperty(string mkDocument, int propid, object value) { - return VSConstants.E_NOTIMPL; - } - - #endregion - - #region IVsDeferredSaveProject Members - - /// - /// Implements deferred save support. Enabled by unchecking Tools->Options->Solutions and Projects->Save New Projects Created. - /// - /// In this mode we save the project when the user selects Save All. We need to move all the files in the project - /// over to the new location. - /// - public virtual int SaveProjectToLocation(string pszProjectFilename) { - string oldName = Url; - string basePath = CommonUtils.NormalizeDirectoryPath(Path.GetDirectoryName(this.FileName)); - string newName = Path.GetDirectoryName(pszProjectFilename); - - IVsUIShell shell = this.Site.GetService(typeof(SVsUIShell)) as IVsUIShell; - IVsSolution vsSolution = (IVsSolution)this.GetService(typeof(SVsSolution)); - - int canContinue; - vsSolution.QueryRenameProject(this, FileName, pszProjectFilename, 0, out canContinue); - if (canContinue == 0) { - return VSConstants.OLE_E_PROMPTSAVECANCELLED; - } - - _watcher.EnableRaisingEvents = false; - _watcher.Dispose(); - - // we don't use RenameProjectFile because it sends the OnAfterRenameProject event too soon - // and causes VS to think the solution has changed on disk. We need to send it after all - // updates are complete. - - // save the new project to to disk - SaveMSBuildProjectFileAs(pszProjectFilename); - - if (CommonUtils.IsSameDirectory(ProjectHome, basePath)) { - // ProjectHome was set by SaveMSBuildProjectFileAs to point to the temporary directory. - BuildProject.SetProperty(CommonConstants.ProjectHome, "."); - - // save the project again w/ updated file info - BuildProjectLocationChanged(); - - // remove all the children, saving any dirty files, and collecting the list of open files - MoveFilesForDeferredSave(this, basePath, newName); - } else { - // Project referenced external files only, so just update its location without moving - // files around. - BuildProjectLocationChanged(); - } - - SaveMSBuildProjectFile(FileName); - - // update VS that we've changed the project - this.OnPropertyChanged(this, (int)__VSHPROPID.VSHPROPID_Caption, 0); - - // Update solution - // Note we ignore the errors here because reporting them to the user isn't really helpful. - // We've already completed all of the work to rename everything here. If OnAfterNameProject - // fails for some reason then telling the user it failed is just confusing because all of - // the work is done. And if someone wanted to prevent us from renaming the project file they - // should have responded to QueryRenameProject. Likewise if we can't refresh the property browser - // for any reason then that's not too interesting either - the users project has been saved to - // the new location. - // http://pytools.codeplex.com/workitem/489 - vsSolution.OnAfterRenameProject((IVsProject)this, oldName, pszProjectFilename, 0); - - shell.RefreshPropertyBrowser(0); - - _watcher = CreateFileSystemWatcher(ProjectHome); - _attributesWatcher = CreateAttributesWatcher(ProjectHome); - - return VSConstants.S_OK; - } - - private void MoveFilesForDeferredSave(HierarchyNode node, string basePath, string baseNewPath) { - if (node != null) { - for (var child = node.FirstChild; child != null; child = child.NextSibling) { - var docMgr = child.GetDocumentManager(); - if (docMgr != null && docMgr.IsDirty) { - int cancelled; - child.ProjectMgr.SaveItem( - VSSAVEFLAGS.VSSAVE_Save, - null, - docMgr.DocCookie, - IntPtr.Zero, - out cancelled - ); - } - - IDiskBasedNode diskNode = child as IDiskBasedNode; - if (diskNode != null) { - diskNode.RenameForDeferredSave(basePath, baseNewPath); - } - - MoveFilesForDeferredSave(child, basePath, baseNewPath); - } - } - } - - #endregion - - internal void SuppressFileChangeNotifications() { - _watcher.EnableRaisingEvents = false; - _suppressFileWatcherCount++; - } - - internal void RestoreFileChangeNotifications() { - if (--_suppressFileWatcherCount == 0) { - _watcher.EnableRaisingEvents = true; - } - } - } -} diff --git a/Microsoft.VisualStudio.Project/CommonProjectNodeProperties.cs b/Microsoft.VisualStudio.Project/CommonProjectNodeProperties.cs deleted file mode 100644 index 7dd9d27c..00000000 --- a/Microsoft.VisualStudio.Project/CommonProjectNodeProperties.cs +++ /dev/null @@ -1,426 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.ComponentModel; -using System.Diagnostics.CodeAnalysis; -using System.IO; -using System.Runtime.InteropServices; -using Microsoft.VisualStudio.Shell.Interop; -using Microsoft.VisualStudioTools.Project.Automation; - -namespace Microsoft.VisualStudioTools.Project { - [ComVisible(true)] - [ClassInterface(ClassInterfaceType.AutoDual)] - public class CommonProjectNodeProperties : ProjectNodeProperties, IVsCfgBrowseObject, VSLangProj.ProjectProperties { - private OAProjectConfigurationProperties _activeCfgSettings; - - internal CommonProjectNodeProperties(ProjectNode node) - : base(node) { - } - - #region properties - /// - /// Returns/Sets the StartupFile project property - /// - [SRCategoryAttribute(SR.General)] - [SRDisplayName(SR.StartupFile)] - [SRDescriptionAttribute(SR.StartupFileDescription)] - public string StartupFile { - get { - return UIThread.Invoke(() => { - var res = Node.ProjectMgr.GetProjectProperty(CommonConstants.StartupFile, true); - if (res != null && !Path.IsPathRooted(res)) { - res = CommonUtils.GetAbsoluteFilePath(Node.ProjectMgr.ProjectHome, res); - } - return res; - }); - } - set { - UIThread.Invoke(() => { - this.Node.ProjectMgr.SetProjectProperty( - CommonConstants.StartupFile, - CommonUtils.GetRelativeFilePath( - Node.ProjectMgr.ProjectHome, - Path.Combine(Node.ProjectMgr.ProjectHome, value) - ) - ); - }); - } - } - - /// - /// Returns/Sets the WorkingDirectory project property - /// - [SRCategoryAttribute(SR.General)] - [SRDisplayName(SR.WorkingDirectory)] - [SRDescriptionAttribute(SR.WorkingDirectoryDescription)] - public string WorkingDirectory { - get { - return UIThread.Invoke(() => { - return this.Node.ProjectMgr.GetProjectProperty(CommonConstants.WorkingDirectory, true); - }); - } - set { - UIThread.Invoke(() => { - this.Node.ProjectMgr.SetProjectProperty(CommonConstants.WorkingDirectory, value); - }); - } - } - - /// - /// Returns/Sets the PublishUrl project property which is where the project is published to - /// - [Browsable(false)] - public string PublishUrl { - get { - return UIThread.Invoke(() => { - return this.Node.ProjectMgr.GetProjectProperty(CommonConstants.PublishUrl, true); - }); - } - set { - UIThread.Invoke(() => { - this.Node.ProjectMgr.SetProjectProperty(CommonConstants.PublishUrl, value); - }); - } - } - - //We don't need this property, but still have to provide it, otherwise - //Add New Item wizard (which seems to be unmanaged) fails. - [Browsable(false)] - public string RootNamespace { - get { - return ""; - } - set { - //Do nothing - } - } - - /// - /// Gets the home directory for the project. - /// - [SRCategoryAttribute(SR.Misc)] - [SRDisplayName(SR.ProjectHome)] - [SRDescriptionAttribute(SR.ProjectHomeDescription)] - public string ProjectHome { - get { - return Node.ProjectMgr.ProjectHome; - } - } - - #endregion - - #region IVsCfgBrowseObject Members - - int IVsCfgBrowseObject.GetCfg(out IVsCfg ppCfg) { - return Node.ProjectMgr.ConfigProvider.GetCfgOfName( - Node.ProjectMgr.CurrentConfig.GetPropertyValue(ProjectFileConstants.Configuration), - Node.ProjectMgr.CurrentConfig.GetPropertyValue(ProjectFileConstants.Platform), - out ppCfg); - } - - #endregion - - #region ProjectProperties Members - - [Browsable(false)] - public string AbsoluteProjectDirectory { - get { - return Node.ProjectMgr.ProjectFolder; - } - } - - [Browsable(false)] - public VSLangProj.ProjectConfigurationProperties ActiveConfigurationSettings { - get { - if (_activeCfgSettings == null) { - _activeCfgSettings = new OAProjectConfigurationProperties(Node.ProjectMgr); - } - return _activeCfgSettings; - } - } - - [Browsable(false)] - public string ActiveFileSharePath { - get { throw new NotImplementedException(); } - } - - [Browsable(false)] - public VSLangProj.prjWebAccessMethod ActiveWebAccessMethod { - get { throw new NotImplementedException(); } - } - - [Browsable(false)] - public string ApplicationIcon { - get { - throw new NotImplementedException(); - } - set { - throw new NotImplementedException(); - } - } - - [Browsable(false)] - public string AssemblyKeyContainerName { - get { - throw new NotImplementedException(); - } - set { - throw new NotImplementedException(); - } - } - - [Browsable(false)] - public string AssemblyName { - get { - throw new NotImplementedException(); - } - set { - throw new NotImplementedException(); - } - } - - [Browsable(false)] - public string AssemblyOriginatorKeyFile { - get { - throw new NotImplementedException(); - } - set { - throw new NotImplementedException(); - } - } - - [Browsable(false)] - public VSLangProj.prjOriginatorKeyMode AssemblyOriginatorKeyMode { - get { - throw new NotImplementedException(); - } - set { - throw new NotImplementedException(); - } - } - - [Browsable(false)] - public VSLangProj.prjScriptLanguage DefaultClientScript { - get { - throw new NotImplementedException(); - } - set { - throw new NotImplementedException(); - } - } - - [Browsable(false)] - public VSLangProj.prjHTMLPageLayout DefaultHTMLPageLayout { - get { - throw new NotImplementedException(); - } - set { - throw new NotImplementedException(); - } - } - - [Browsable(false)] - public string DefaultNamespace { - get { - throw new NotImplementedException(); - } - set { - throw new NotImplementedException(); - } - } - - [Browsable(false)] - public VSLangProj.prjTargetSchema DefaultTargetSchema { - get { - throw new NotImplementedException(); - } - set { - throw new NotImplementedException(); - } - } - - [Browsable(false)] - public bool DelaySign { - get { - throw new NotImplementedException(); - } - set { - throw new NotImplementedException(); - } - } - - [Browsable(false)] - public new object ExtenderNames { - get { throw new NotImplementedException(); } - } - - [Browsable(false)] - public string FileSharePath { - get { - throw new NotImplementedException(); - } - set { - throw new NotImplementedException(); - } - } - - [Browsable(false)] - public bool LinkRepair { - get { - throw new NotImplementedException(); - } - set { - throw new NotImplementedException(); - } - } - - [Browsable(false)] - public string LocalPath { - get { throw new NotImplementedException(); } - } - - [Browsable(false)] - public string OfflineURL { - get { throw new NotImplementedException(); } - } - - [Browsable(false)] - public VSLangProj.prjCompare OptionCompare { - get { - throw new NotImplementedException(); - } - set { - throw new NotImplementedException(); - } - } - - [Browsable(false)] - public VSLangProj.prjOptionExplicit OptionExplicit { - get { - throw new NotImplementedException(); - } - set { - throw new NotImplementedException(); - } - } - - [Browsable(false)] - public VSLangProj.prjOptionStrict OptionStrict { - get { - throw new NotImplementedException(); - } - set { - throw new NotImplementedException(); - } - } - - [Browsable(false)] - public string OutputFileName { - get { throw new NotImplementedException(); } - } - - [Browsable(false)] - public VSLangProj.prjOutputType OutputType { - get { - throw new NotImplementedException(); - } - set { - throw new NotImplementedException(); - } - } - - [Browsable(false)] - public VSLangProj.prjProjectType ProjectType { - get { throw new NotImplementedException(); } - } - - [Browsable(false)] - public string ReferencePath { - get { - throw new NotImplementedException(); - } - set { - throw new NotImplementedException(); - } - } - - [Browsable(false)] - public string ServerExtensionsVersion { - get { throw new NotImplementedException(); } - } - - [Browsable(false)] - public string StartupObject { - get { - return UIThread.Invoke(() => { - return Node.ProjectMgr.GetProjectProperty(CommonConstants.StartupFile); - }); - } - set { - UIThread.Invoke(() => { - Node.ProjectMgr.SetProjectProperty( - CommonConstants.StartupFile, - CommonUtils.GetRelativeFilePath(Node.ProjectMgr.ProjectHome, value) - ); - }); - } - } - - [Browsable(false)] - public string URL { - get { return CommonUtils.MakeUri(Node.ProjectMgr.Url, false, UriKind.Absolute).AbsoluteUri; } - } - - [Browsable(false)] - public VSLangProj.prjWebAccessMethod WebAccessMethod { - get { - throw new NotImplementedException(); - } - set { - throw new NotImplementedException(); - } - } - - [Browsable(false)] - public string WebServer { - get { throw new NotImplementedException(); } - } - - [Browsable(false)] - public string WebServerVersion { - get { throw new NotImplementedException(); } - } - - [Browsable(false)] - public string __id { - get { throw new NotImplementedException(); } - } - - [Browsable(false)] - public object __project { - get { throw new NotImplementedException(); } - } - - [Browsable(false)] - public object get_Extender(string ExtenderName) { - throw new NotImplementedException(); - } - - #endregion - } -} diff --git a/Microsoft.VisualStudio.Project/CommonProjectPackage.cs b/Microsoft.VisualStudio.Project/CommonProjectPackage.cs deleted file mode 100644 index 3d87cec0..00000000 --- a/Microsoft.VisualStudio.Project/CommonProjectPackage.cs +++ /dev/null @@ -1,223 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Runtime.InteropServices; -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.OLE.Interop; -using Microsoft.VisualStudio.Shell.Interop; - -namespace Microsoft.VisualStudioTools.Project { - //[DefaultRegistryRoot("Software\\Microsoft\\VisualStudio\\9.0Exp")] - //[PackageRegistration(UseManagedResourcesOnly = true)] - public abstract class CommonProjectPackage : ProjectPackage, IVsInstalledProduct, IOleComponent { - private IOleComponentManager _compMgr; - private uint _componentID; - - public abstract ProjectFactory CreateProjectFactory(); - public abstract CommonEditorFactory CreateEditorFactory(); - public virtual CommonEditorFactory CreateEditorFactoryPromptForEncoding() { - return null; - } - /// - /// This method is called to get the icon that will be displayed in the - /// Help About dialog when this package is selected. - /// - /// The resource id corresponding to the icon to display on the Help About dialog - public abstract uint GetIconIdForAboutBox(); - /// - /// This method is called during Devenv /Setup to get the bitmap to - /// display on the splash screen for this package. - /// - /// The resource id corresponding to the bitmap to display on the splash screen - public abstract uint GetIconIdForSplashScreen(); - /// - /// This methods provides the product official name, it will be - /// displayed in the help about dialog. - /// - public abstract string GetProductName(); - /// - /// This methods provides the product description, it will be - /// displayed in the help about dialog. - /// - public abstract string GetProductDescription(); - /// - /// This methods provides the product version, it will be - /// displayed in the help about dialog. - /// - public abstract string GetProductVersion(); - - protected override void Initialize() { - base.Initialize(); - this.RegisterProjectFactory(CreateProjectFactory()); - var editFactory = CreateEditorFactory(); - if (editFactory != null) { - this.RegisterEditorFactory(editFactory); - } - var encodingEditorFactory = CreateEditorFactoryPromptForEncoding(); - if (encodingEditorFactory != null) { - RegisterEditorFactory(encodingEditorFactory); - } - var componentManager = _compMgr = (IOleComponentManager)GetService(typeof(SOleComponentManager)); - OLECRINFO[] crinfo = new OLECRINFO[1]; - crinfo[0].cbSize = (uint)Marshal.SizeOf(typeof(OLECRINFO)); - crinfo[0].grfcrf = (uint)_OLECRF.olecrfNeedIdleTime; - crinfo[0].grfcadvf = (uint)_OLECADVF.olecadvfModal | (uint)_OLECADVF.olecadvfRedrawOff | (uint)_OLECADVF.olecadvfWarningsOff; - crinfo[0].uIdleTimeInterval = 0; - ErrorHandler.ThrowOnFailure(componentManager.FRegisterComponent(this, crinfo, out _componentID)); - } - - protected override void Dispose(bool disposing) { - try { - if (_componentID != 0) { - IOleComponentManager mgr = GetService(typeof(SOleComponentManager)) as IOleComponentManager; - if (mgr != null) { - mgr.FRevokeComponent(_componentID); - } - _componentID = 0; - } - } finally { - base.Dispose(disposing); - } - } - - /// - /// This method loads a localized string based on the specified resource. - /// - /// Resource to load - /// String loaded for the specified resource - public string GetResourceString(string resourceName) { - string resourceValue; - IVsResourceManager resourceManager = (IVsResourceManager)GetService(typeof(SVsResourceManager)); - if (resourceManager == null) { - throw new InvalidOperationException("Could not get SVsResourceManager service. Make sure the package is Sited before calling this method"); - } - Guid packageGuid = this.GetType().GUID; - int hr = resourceManager.LoadResourceString(ref packageGuid, -1, resourceName, out resourceValue); - Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(hr); - return resourceValue; - } - - #region IVsInstalledProduct Members - - /// - /// This method is called during Devenv /Setup to get the bitmap to - /// display on the splash screen for this package. - /// - /// The resource id corresponding to the bitmap to display on the splash screen - /// HRESULT, indicating success or failure - public int IdBmpSplash(out uint pIdBmp) { - pIdBmp = GetIconIdForSplashScreen(); - return VSConstants.S_OK; - } - - /// - /// This method is called to get the icon that will be displayed in the - /// Help About dialog when this package is selected. - /// - /// The resource id corresponding to the icon to display on the Help About dialog - /// HRESULT, indicating success or failure - public int IdIcoLogoForAboutbox(out uint pIdIco) { - pIdIco = GetIconIdForAboutBox(); - return VSConstants.S_OK; - } - - /// - /// This methods provides the product official name, it will be - /// displayed in the help about dialog. - /// - /// Out parameter to which to assign the product name - /// HRESULT, indicating success or failure - public int OfficialName(out string pbstrName) { - pbstrName = GetProductName(); - return VSConstants.S_OK; - } - - /// - /// This methods provides the product description, it will be - /// displayed in the help about dialog. - /// - /// Out parameter to which to assign the description of the package - /// HRESULT, indicating success or failure - public int ProductDetails(out string pbstrProductDetails) { - pbstrProductDetails = GetProductDescription(); - return VSConstants.S_OK; - } - - /// - /// This methods provides the product version, it will be - /// displayed in the help about dialog. - /// - /// Out parameter to which to assign the version number - /// HRESULT, indicating success or failure - public int ProductID(out string pbstrPID) { - pbstrPID = GetProductVersion(); - return VSConstants.S_OK; - } - - #endregion - - #region IOleComponent Members - - public int FContinueMessageLoop(uint uReason, IntPtr pvLoopData, MSG[] pMsgPeeked) { - return 1; - } - - public int FDoIdle(uint grfidlef) { - var onIdle = OnIdle; - if (onIdle != null) { - onIdle(this, new ComponentManagerEventArgs(_compMgr)); - } - - return 0; - } - - internal event EventHandler OnIdle; - - public int FPreTranslateMessage(MSG[] pMsg) { - return 0; - } - - public int FQueryTerminate(int fPromptUser) { - return 1; - } - - public int FReserved1(uint dwReserved, uint message, IntPtr wParam, IntPtr lParam) { - return 1; - } - - public IntPtr HwndGetWindow(uint dwWhich, uint dwReserved) { - return IntPtr.Zero; - } - - public void OnActivationChange(IOleComponent pic, int fSameComponent, OLECRINFO[] pcrinfo, int fHostIsActivating, OLECHOSTINFO[] pchostinfo, uint dwReserved) { - } - - public void OnAppActivate(int fActive, uint dwOtherThreadID) { - } - - public void OnEnterState(uint uStateID, int fEnter) { - } - - public void OnLoseActivation() { - } - - public void Terminate() { - } - - #endregion - } -} diff --git a/Microsoft.VisualStudio.Project/CommonPropertyPage.cs b/Microsoft.VisualStudio.Project/CommonPropertyPage.cs deleted file mode 100644 index 227a0eb5..00000000 --- a/Microsoft.VisualStudio.Project/CommonPropertyPage.cs +++ /dev/null @@ -1,191 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Collections; -using System.Drawing; -using System.Runtime.InteropServices; -using System.Windows.Forms; -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.OLE.Interop; - -namespace Microsoft.VisualStudioTools.Project { - /// - /// Base class for property pages based on a WinForm control. - /// - [ComVisible(true)] - public abstract class CommonPropertyPage : IPropertyPage { - private IPropertyPageSite _site; - private bool _dirty, _loading; - private CommonProjectNode _project; - - public abstract Control Control { - get; - } - - public abstract void Apply(); - public abstract void LoadSettings(); - - public abstract string Name { - get; - } - - internal virtual CommonProjectNode Project { - get { - return _project; - } - set { - _project = value; - } - } - - protected void SetProjectProperty(string propertyName, string propertyValue) { - // SetProjectProperty's implementation will check whether the value - // has changed. - Project.SetProjectProperty(propertyName, propertyValue); - } - - protected string GetProjectProperty(string propertyName) { - return Project.GetUnevaluatedProperty(propertyName); - } - - public bool Loading { - get { - return _loading; - } - set { - _loading = value; - } - } - - public bool IsDirty { - get { - return _dirty; - } - set { - if (_dirty != value && !Loading) { - _dirty = value; - if (_site != null) { - _site.OnStatusChange((uint)(_dirty ? PropPageStatus.Dirty : PropPageStatus.Clean)); - } - } - } - } - - void IPropertyPage.Activate(IntPtr hWndParent, RECT[] pRect, int bModal) { - NativeMethods.SetParent(Control.Handle, hWndParent); - } - - int IPropertyPage.Apply() { - try { - Apply(); - return VSConstants.S_OK; - } catch (Exception e) { - return Marshal.GetHRForException(e); - } - } - - void IPropertyPage.Deactivate() { - Project = null; - Control.Dispose(); - } - - void IPropertyPage.GetPageInfo(PROPPAGEINFO[] pPageInfo) { - Utilities.ArgumentNotNull("pPageInfo", pPageInfo); - - PROPPAGEINFO info = new PROPPAGEINFO(); - - info.cb = (uint)Marshal.SizeOf(typeof(PROPPAGEINFO)); - info.dwHelpContext = 0; - info.pszDocString = null; - info.pszHelpFile = null; - info.pszTitle = Name; - info.SIZE.cx = Control.Width; - info.SIZE.cy = Control.Height; - pPageInfo[0] = info; - } - - void IPropertyPage.Help(string pszHelpDir) { - } - - int IPropertyPage.IsPageDirty() { - return (IsDirty ? (int)VSConstants.S_OK : (int)VSConstants.S_FALSE); - } - - void IPropertyPage.Move(RECT[] pRect) { - Utilities.ArgumentNotNull("pRect", pRect); - - RECT r = pRect[0]; - - Control.Location = new Point(r.left, r.top); - Control.Size = new Size(r.right - r.left, r.bottom - r.top); - } - - public virtual void SetObjects(uint count, object[] punk) { - if (punk == null) { - return; - } - - if (count > 0) { - if (punk[0] is ProjectConfig) { - ArrayList configs = new ArrayList(); - - for (int i = 0; i < count; i++) { - CommonProjectConfig config = (CommonProjectConfig)punk[i]; - - if (_project == null) { - Project = (CommonProjectNode)config.ProjectMgr; - break; - } - - configs.Add(config); - } - } else if (punk[0] is NodeProperties) { - if (_project == null) { - Project = (CommonProjectNode)(punk[0] as NodeProperties).HierarchyNode.ProjectMgr; - } - } - } else { - Project = null; - } - - if (_project != null) { - LoadSettings(); - } - } - - void IPropertyPage.SetPageSite(IPropertyPageSite pPageSite) { - _site = pPageSite; - } - - void IPropertyPage.Show(uint nCmdShow) { - Control.Visible = true; // TODO: pass SW_SHOW* flags through - Control.Show(); - } - - int IPropertyPage.TranslateAccelerator(MSG[] pMsg) { - Utilities.ArgumentNotNull("pMsg", pMsg); - - MSG msg = pMsg[0]; - - if ((msg.message < NativeMethods.WM_KEYFIRST || msg.message > NativeMethods.WM_KEYLAST) && (msg.message < NativeMethods.WM_MOUSEFIRST || msg.message > NativeMethods.WM_MOUSELAST)) { - return VSConstants.S_FALSE; - } - - return (NativeMethods.IsDialogMessageA(Control.Handle, ref msg)) ? VSConstants.S_OK : VSConstants.S_FALSE; - } - } -} diff --git a/Microsoft.VisualStudio.Project/CommonReferenceContainerNode.cs b/Microsoft.VisualStudio.Project/CommonReferenceContainerNode.cs deleted file mode 100644 index c56b8877..00000000 --- a/Microsoft.VisualStudio.Project/CommonReferenceContainerNode.cs +++ /dev/null @@ -1,54 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using Microsoft.VisualStudio.Shell.Interop; - -namespace Microsoft.VisualStudioTools.Project { - /// - /// Reference container node for project references. - /// - internal class CommonReferenceContainerNode : ReferenceContainerNode { - internal CommonReferenceContainerNode(ProjectNode project) - : base(project) { - } - - protected override ProjectReferenceNode CreateProjectReferenceNode(ProjectElement element) { - return new ProjectReferenceNode(this.ProjectMgr, element); - } - - protected override ProjectReferenceNode CreateProjectReferenceNode(VSCOMPONENTSELECTORDATA selectorData) { - return new ProjectReferenceNode(this.ProjectMgr, selectorData.bstrTitle, selectorData.bstrFile, selectorData.bstrProjRef); - } - - protected override NodeProperties CreatePropertiesObject() { - return new NodeProperties(this); - } - - /// - /// Creates a reference node. By default we don't add references and this returns null. - /// - protected override ReferenceNode CreateReferenceNode(VSCOMPONENTSELECTORDATA selectorData) { - return base.CreateReferenceNode(selectorData); - } - - /// - /// Exposed for derived classes to re-enable reference support. - /// - internal ReferenceNode BaseCreateReferenceNode(ref VSCOMPONENTSELECTORDATA selectorData) { - return base.CreateReferenceNode(selectorData); - } - } -} diff --git a/Microsoft.VisualStudio.Project/CommonUtils.cs b/Microsoft.VisualStudio.Project/CommonUtils.cs deleted file mode 100644 index 73289453..00000000 --- a/Microsoft.VisualStudio.Project/CommonUtils.cs +++ /dev/null @@ -1,523 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Diagnostics; -using System.IO; -using System.Linq; - -namespace Microsoft.VisualStudioTools { - internal static class CommonUtils { - private static readonly char[] InvalidPathChars = GetInvalidPathChars(); - - private static readonly char[] DirectorySeparators = new[] { - Path.DirectorySeparatorChar, - Path.AltDirectorySeparatorChar - }; - - private static char[] GetInvalidPathChars() { - return Path.GetInvalidPathChars().Concat(new[] { '*', '?' }).ToArray(); - } - - internal static bool TryMakeUri(string path, bool isDirectory, UriKind kind, out Uri uri) { - if (isDirectory && !string.IsNullOrEmpty(path) && !HasEndSeparator(path)) { - path += Path.DirectorySeparatorChar; - } - - return Uri.TryCreate(path, kind, out uri); - } - - internal static Uri MakeUri(string path, bool isDirectory, UriKind kind, string throwParameterName = "path") { - try { - if (isDirectory && !string.IsNullOrEmpty(path) && !HasEndSeparator(path)) { - path += Path.DirectorySeparatorChar; - } - - return new Uri(path, kind); - - } catch (UriFormatException ex) { - throw new ArgumentException("Path was invalid", throwParameterName, ex); - } catch (ArgumentException ex) { - throw new ArgumentException("Path was invalid", throwParameterName, ex); - } - } - - /// - /// Normalizes and returns the provided path. - /// - public static string NormalizePath(string path) { - if (string.IsNullOrEmpty(path)) { - return null; - } - - var uri = MakeUri(path, false, UriKind.RelativeOrAbsolute); - if (uri.IsAbsoluteUri) { - if (uri.IsFile) { - return uri.LocalPath; - } else { - return uri.AbsoluteUri.Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); - } - } else { - return Uri.UnescapeDataString(uri.ToString()).Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); - } - } - - /// - /// Normalizes and returns the provided directory path, always - /// ending with '/'. - /// - public static string NormalizeDirectoryPath(string path) { - if (string.IsNullOrEmpty(path)) { - return null; - } - - var uri = MakeUri(path, true, UriKind.RelativeOrAbsolute); - if (uri.IsAbsoluteUri) { - if (uri.IsFile) { - return uri.LocalPath; - } else { - return uri.AbsoluteUri.Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); - } - } else { - return Uri.UnescapeDataString(uri.ToString()).Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); - } - } - - /// - /// Return true if both paths represent the same directory. - /// - public static bool IsSameDirectory(string path1, string path2) { - if (string.IsNullOrEmpty(path1)) { - return string.IsNullOrEmpty(path2); - } else if (string.IsNullOrEmpty(path2)) { - return false; - } - - if (String.Equals(path1, path2, StringComparison.Ordinal)) { - // Quick return, but will only work where the paths are already normalized and - // have matching case. - return true; - } - - Uri uri1, uri2; - return - TryMakeUri(path1, true, UriKind.Absolute, out uri1) && - TryMakeUri(path2, true, UriKind.Absolute, out uri2) && - uri1 == uri2; - } - - /// - /// Return true if both paths represent the same location. - /// - public static bool IsSamePath(string file1, string file2) { - if (string.IsNullOrEmpty(file1)) { - return string.IsNullOrEmpty(file2); - } else if (string.IsNullOrEmpty(file2)) { - return false; - } - - if (String.Equals(file1, file2, StringComparison.Ordinal)) { - // Quick return, but will only work where the paths are already normalized and - // have matching case. - return true; - } - - Uri uri1, uri2; - return - TryMakeUri(file1, false, UriKind.Absolute, out uri1) && - TryMakeUri(file2, false, UriKind.Absolute, out uri2) && - uri1 == uri2; - } - - /// - /// Return true if the path represents a file or directory contained in - /// root or a subdirectory of root. - /// - public static bool IsSubpathOf(string root, string path) { - if (HasEndSeparator(root) && !path.Contains("..") && path.StartsWith(root, StringComparison.Ordinal)) { - // Quick return, but only where the paths are already normalized and - // have matching case. - return true; - } - - var uriRoot = MakeUri(root, true, UriKind.Absolute, "root"); - var uriPath = MakeUri(path, false, UriKind.Absolute, "path"); - - if (uriRoot.Equals(uriPath) || uriRoot.IsBaseOf(uriPath)) { - return true; - } - - // Special case where root and path are the same, but path was provided - // without a terminating separator. - var uriDirectoryPath = MakeUri(path, true, UriKind.Absolute, "path"); - if (uriRoot.Equals(uriDirectoryPath)) { - return true; - } - - return false; - } - - /// - /// Returns a normalized directory path created by joining relativePath to root. - /// The result is guaranteed to end with a backslash. - /// - /// root is not an absolute path, or - /// either path is invalid. - /// An absolute path cannot be - /// created. - public static string GetAbsoluteDirectoryPath(string root, string relativePath) { - string absPath; - - if (string.IsNullOrEmpty(relativePath)) { - return NormalizeDirectoryPath(root); - } - - var relUri = MakeUri(relativePath, true, UriKind.RelativeOrAbsolute, "relativePath"); - Uri absUri; - - if (relUri.IsAbsoluteUri) { - absUri = relUri; - } else { - var rootUri = MakeUri(root, true, UriKind.Absolute, "root"); - try { - absUri = new Uri(rootUri, relUri); - } catch (UriFormatException ex) { - throw new InvalidOperationException("Cannot create absolute path", ex); - } - } - - absPath = absUri.IsFile ? absUri.LocalPath : absUri.AbsoluteUri; - - if (!string.IsNullOrEmpty(absPath) && !HasEndSeparator(absPath)) { - absPath += absUri.IsFile ? Path.DirectorySeparatorChar : Path.AltDirectorySeparatorChar; - } - - return absPath; - } - - /// - /// Returns a normalized file path created by joining relativePath to root. - /// The result is not guaranteed to end with a backslash. - /// - /// root is not an absolute path, or - /// either path is invalid. - public static string GetAbsoluteFilePath(string root, string relativePath) { - var rootUri = MakeUri(root, true, UriKind.Absolute, "root"); - var relUri = MakeUri(relativePath, false, UriKind.RelativeOrAbsolute, "relativePath"); - - Uri absUri; - - if (relUri.IsAbsoluteUri) { - absUri = relUri; - } else { - try { - absUri = new Uri(rootUri, relUri); - } catch (UriFormatException ex) { - throw new InvalidOperationException("Cannot create absolute path", ex); - } - } - - return absUri.IsFile ? absUri.LocalPath : absUri.AbsoluteUri; - } - - /// - /// Returns a relative path from the base path to the other path. This is - /// intended for serialization rather than UI. See CreateFriendlyDirectoryPath - /// for UI strings. - /// - /// Either parameter was an invalid or a - /// relative path. - public static string GetRelativeDirectoryPath(string fromDirectory, string toDirectory) { - var fromUri = MakeUri(fromDirectory, true, UriKind.Absolute, "fromDirectory"); - var toUri = MakeUri(toDirectory, true, UriKind.Absolute, "toDirectory"); - - string relPath; - var sep = toUri.IsFile ? Path.DirectorySeparatorChar : Path.AltDirectorySeparatorChar; - - try { - var relUri = fromUri.MakeRelativeUri(toUri); - if (relUri.IsAbsoluteUri) { - relPath = relUri.IsFile ? relUri.LocalPath : relUri.AbsoluteUri; - } else { - relPath = Uri.UnescapeDataString(relUri.ToString()); - } - } catch (InvalidOperationException ex) { - Trace.WriteLine(string.Format("Error finding path from {0} to {1}", fromUri, toUri)); - Trace.WriteLine(ex); - relPath = toUri.IsFile ? toUri.LocalPath : toUri.AbsoluteUri; - } - - if (!string.IsNullOrEmpty(relPath) && !HasEndSeparator(relPath)) { - relPath += Path.DirectorySeparatorChar; - } - - if (toUri.IsFile) { - return relPath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); - } else { - return relPath.Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); - } - } - - /// - /// Returns a relative path from the base path to the file. This is - /// intended for serialization rather than UI. See CreateFriendlyFilePath - /// for UI strings. - /// - public static string GetRelativeFilePath(string fromDirectory, string toFile) { - var fromUri = MakeUri(fromDirectory, true, UriKind.Absolute, "fromDirectory"); - var toUri = MakeUri(toFile, false, UriKind.Absolute, "toFile"); - - string relPath; - var sep = toUri.IsFile ? Path.DirectorySeparatorChar : Path.AltDirectorySeparatorChar; - - try { - var relUri = fromUri.MakeRelativeUri(toUri); - if (relUri.IsAbsoluteUri) { - relPath = relUri.IsFile ? relUri.LocalPath : relUri.AbsoluteUri; - } else { - relPath = Uri.UnescapeDataString(relUri.ToString()); - } - } catch (InvalidOperationException ex) { - Trace.WriteLine(string.Format("Error finding path from {0} to {1}", fromUri, toUri)); - Trace.WriteLine(ex); - relPath = toUri.IsFile ? toUri.LocalPath : toUri.AbsoluteUri; - } - - if (toUri.IsFile) { - return relPath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); - } else { - return relPath.Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); - } - } - - /// - /// Tries to create a friendly directory path: '.' if the same as base path, - /// relative path if short, absolute path otherwise. - /// - public static string CreateFriendlyDirectoryPath(string basePath, string path) { - var relativePath = GetRelativeDirectoryPath(basePath, path); - - if (relativePath.Length > 1) { - relativePath = TrimEndSeparator(relativePath); - } - - if (string.IsNullOrEmpty(relativePath)) { - relativePath = "."; - } - - return relativePath; - } - - /// - /// Tries to create a friendly file path. - /// - public static string CreateFriendlyFilePath(string basePath, string path) { - return GetRelativeFilePath(basePath, path); - } - - /// - /// Returns the last directory segment of a path. The last segment is - /// assumed to be the string between the second-last and last directory - /// separator characters in the path. If there is no suitable substring, - /// the empty string is returned. - /// - /// The first segment of the path is only returned if it does not - /// contain a colon. Segments equal to "." are ignored and the preceding - /// segment is used. - /// - /// - /// This should be used in place of: - /// Path.GetFileName(CommonUtils.TrimEndSeparator(Path.GetDirectoryName(path))) - /// - public static string GetLastDirectoryName(string path) { - if (string.IsNullOrEmpty(path)) { - return string.Empty; - } - - int last = path.LastIndexOfAny(DirectorySeparators); - - string result = string.Empty; - while (last > 1) { - int first = path.LastIndexOfAny(DirectorySeparators, last - 1); - if (first < 0) { - if (path.IndexOf(':') < last) { - // Don't want to return scheme/drive as a directory - return string.Empty; - } - first = -1; - } - if (first == 1 && path[0] == path[1]) { - // Don't return computer name in UNC path - return string.Empty; - } - - result = path.Substring(first + 1, last - (first + 1)); - if (!string.IsNullOrEmpty(result) && result != ".") { - // Result is valid - break; - } - - last = first; - } - - return result; - } - - /// - /// Returns the path to the parent directory segment of a path. If the - /// last character of the path is a directory separator, the segment - /// prior to that character is removed. Otherwise, the segment following - /// the last directory separator is removed. - /// - /// - /// This should be used in place of: - /// Path.GetDirectoryName(CommonUtils.TrimEndSeparator(path)) + Path.DirectorySeparatorChar - /// - public static string GetParent(string path) { - if (string.IsNullOrEmpty(path)) { - return string.Empty; - } - - int last = path.Length - 1; - if (DirectorySeparators.Contains(path[last])) { - last -= 1; - } - - if (last <= 0) { - return string.Empty; - } - - last = path.LastIndexOfAny(DirectorySeparators, last); - - if (last < 0) { - return string.Empty; - } - - return path.Remove(last + 1); - } - - /// - /// Returns the last segment of the path. If the last character is a - /// directory separator, this will be the segment preceding the - /// separator. Otherwise, it will be the segment following the last - /// separator. - /// - /// - /// - public static string GetFileOrDirectoryName(string path) { - if (string.IsNullOrEmpty(path)) { - return string.Empty; - } - - int last = path.Length - 1; - if (DirectorySeparators.Contains(path[last])) { - last -= 1; - } - - if (last < 0) { - return string.Empty; - } - - int start = path.LastIndexOfAny(DirectorySeparators, last); - - return path.Substring(start + 1, last - start); - } - - /// - /// Returns true if the path has a directory separator character at the end. - /// - public static bool HasEndSeparator(string path) { - return !string.IsNullOrEmpty(path) && DirectorySeparators.Contains(path[path.Length - 1]); - } - - /// - /// Removes up to one directory separator character from the end of path. - /// - public static string TrimEndSeparator(string path) { - if (HasEndSeparator(path)) { - if (path.Length > 2 && path[path.Length - 2] == ':') { - // The slash at the end of a drive specifier is not actually - // a separator. - return path; - } else if (path.Length > 3 && path[path.Length - 2] == path[path.Length - 1] && path[path.Length - 3] == ':') { - // The double slash at the end of a schema is not actually a - // separator. - return path; - } - return path.Remove(path.Length - 1); - } else { - return path; - } - } - - /// - /// Adds a directory separator character to the end of path if required. - /// - public static string EnsureEndSeparator(string path) { - if (string.IsNullOrEmpty(path)) { - return string.Empty; - } else if (!HasEndSeparator(path)) { - return path + Path.DirectorySeparatorChar; - } else { - return path; - } - } - - /// - /// Removes leading @"..\" segments from a path. - /// - private static string TrimUpPaths(string path) { - int actualStart = 0; - while (actualStart + 2 < path.Length) { - if (path[actualStart] == '.' && path[actualStart + 1] == '.' && - (path[actualStart + 2] == Path.DirectorySeparatorChar || path[actualStart + 2] == Path.AltDirectorySeparatorChar)) { - actualStart += 3; - } else { - break; - } - } - - return (actualStart > 0) ? path.Substring(actualStart) : path; - } - - /// - /// Returns true if the path is a valid path, regardless of whether the - /// file exists or not. - /// - public static bool IsValidPath(string path) { - return !string.IsNullOrEmpty(path) && - path.IndexOfAny(InvalidPathChars) < 0; - } - - /// - /// Gets a filename in the specified location with the specified name and extension. - /// If the file already exist it will calculate a name with a number in it. - /// - public static string GetAvailableFilename(string location, string basename, string extension) { - var newPath = Path.Combine(location, basename); - int index = 0; - if (File.Exists(newPath + extension)) { - string candidateNewPath; - do { - candidateNewPath = string.Format("{0}{1}", newPath, ++index); - } while (File.Exists(candidateNewPath + extension)); - newPath = candidateNewPath; - } - string final = newPath + extension; - return final; - } - } -} diff --git a/Microsoft.VisualStudio.Project/ConfigProvider.cs b/Microsoft.VisualStudio.Project/ConfigProvider.cs deleted file mode 100644 index dd71742c..00000000 --- a/Microsoft.VisualStudio.Project/ConfigProvider.cs +++ /dev/null @@ -1,578 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Globalization; -using System.IO; -using System.Runtime.InteropServices; -using Microsoft.Build.Construction; -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.Shell; -using Microsoft.VisualStudio.Shell.Interop; - -/* This file provides a basefunctionallity for IVsCfgProvider2. - Instead of using the IVsProjectCfgEventsHelper object we have our own little sink and call our own helper methods - similiar to the interface. But there is no real benefit in inheriting from the interface in the first place. - Using the helper object seems to be: - a) undocumented - b) not really wise in the managed world -*/ -namespace Microsoft.VisualStudioTools.Project { - - [ComVisible(true)] - internal abstract class ConfigProvider : IVsCfgProvider2 { - internal const string configString = " '$(Configuration)|$(Platform)' == '{0}|{1}' "; - internal const string AnyCPUPlatform = "Any CPU"; - internal const string x86Platform = "x86"; - - private ProjectNode project; - private EventSinkCollection cfgEventSinks = new EventSinkCollection(); - private List, string>> newCfgProps = new List, string>>(); - private Dictionary configurationsList = new Dictionary(); - - public ConfigProvider(ProjectNode manager) { - this.project = manager; - } - - /// - /// The associated project. - /// - internal ProjectNode ProjectMgr { - get { - return this.project; - } - } - - /// - /// If the project system wants to add custom properties to the property group then - /// they provide us with this data. - /// Returns/sets the [() ] collection - /// - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1002:DoNotExposeGenericLists"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] - public virtual List, string>> NewConfigProperties { - get { - return newCfgProps; - } - set { - newCfgProps = value; - } - } - - /// - /// Creates new Project Configuartion objects based on the configuration name. - /// - /// The name of the configuration - /// An instance of a ProjectConfig object. - internal ProjectConfig GetProjectConfiguration(string configName) { - // if we already created it, return the cached one - if (configurationsList.ContainsKey(configName)) { - return configurationsList[configName]; - } - - ProjectConfig requestedConfiguration = CreateProjectConfiguration(configName); - configurationsList.Add(configName, requestedConfiguration); - - return requestedConfiguration; - } - - protected abstract ProjectConfig CreateProjectConfiguration(string configName); - - #region IVsCfgProvider2 methods - - /// - /// Copies an existing configuration name or creates a new one. - /// - /// The name of the new configuration. - /// the name of the configuration to copy, or a null reference, indicating that AddCfgsOfCfgName should create a new configuration. - /// Flag indicating whether or not the new configuration is private. If fPrivate is set to true, the configuration is private. If set to false, the configuration is public. This flag can be ignored. - /// If the method succeeds, it returns S_OK. If it fails, it returns an error code. - public virtual int AddCfgsOfCfgName(string name, string cloneName, int fPrivate) { - // We need to QE/QS the project file - if (!this.ProjectMgr.QueryEditProjectFile(false)) { - throw Marshal.GetExceptionForHR(VSConstants.OLE_E_PROMPTSAVECANCELLED); - } - - // First create the condition that represent the configuration we want to clone - string condition = (cloneName == null ? String.Empty : String.Format(CultureInfo.InvariantCulture, configString, cloneName).Trim()); - - // Get all configs - List configGroup = new List(this.project.BuildProject.Xml.PropertyGroups); - ProjectPropertyGroupElement configToClone = null; - - if (cloneName != null) { - // Find the configuration to clone - foreach (ProjectPropertyGroupElement currentConfig in configGroup) { - // Only care about conditional property groups - if (currentConfig.Condition == null || currentConfig.Condition.Length == 0) - continue; - - // Skip if it isn't the group we want - if (String.Compare(currentConfig.Condition.Trim(), condition, StringComparison.OrdinalIgnoreCase) != 0) - continue; - - configToClone = currentConfig; - } - } - - ProjectPropertyGroupElement newConfig = null; - if (configToClone != null) { - // Clone the configuration settings - newConfig = this.project.ClonePropertyGroup(configToClone); - //Will be added later with the new values to the path - - foreach (ProjectPropertyElement property in newConfig.Properties) { - if (property.Name.Equals("OutputPath", StringComparison.OrdinalIgnoreCase)) { - property.Parent.RemoveChild(property); - } - } - } else { - // no source to clone from, lets just create a new empty config - newConfig = this.project.BuildProject.Xml.AddPropertyGroup(); - // Get the list of property name, condition value from the config provider - IList, string>> propVals = this.NewConfigProperties; - foreach (KeyValuePair, string> data in propVals) { - KeyValuePair propData = data.Key; - string value = data.Value; - ProjectPropertyElement newProperty = newConfig.AddProperty(propData.Key, value); - if (!String.IsNullOrEmpty(propData.Value)) - newProperty.Condition = propData.Value; - } - } - - - //add the output path - string outputBasePath = this.ProjectMgr.OutputBaseRelativePath; - newConfig.AddProperty("OutputPath", CommonUtils.NormalizeDirectoryPath(Path.Combine(outputBasePath, name))); - - // Set the condition that will define the new configuration - string newCondition = String.Format(CultureInfo.InvariantCulture, configString, name, "default"); - newConfig.Condition = newCondition; - - NotifyOnCfgNameAdded(name); - return VSConstants.S_OK; - } - - /// - /// Copies an existing platform name or creates a new one. - /// - /// The name of the new platform. - /// The name of the platform to copy, or a null reference, indicating that AddCfgsOfPlatformName should create a new platform. - /// If the method succeeds, it returns S_OK. If it fails, it returns an error code. - public virtual int AddCfgsOfPlatformName(string platformName, string clonePlatformName) { - return VSConstants.E_NOTIMPL; - } - - /// - /// Deletes a specified configuration name. - /// - /// The name of the configuration to be deleted. - /// If the method succeeds, it returns S_OK. If it fails, it returns an error code. - public virtual int DeleteCfgsOfCfgName(string name) { - // We need to QE/QS the project file - if (!this.ProjectMgr.QueryEditProjectFile(false)) { - throw Marshal.GetExceptionForHR(VSConstants.OLE_E_PROMPTSAVECANCELLED); - } - - if (name == null) { - // The configuration " '$(Configuration)' == " does not exist, so technically the goal - // is achieved so return S_OK - return VSConstants.S_OK; - } - // Verify that this config exist - string[] configs = GetPropertiesConditionedOn(ProjectFileConstants.Configuration); - foreach (string config in configs) { - if (String.Compare(config, name, StringComparison.OrdinalIgnoreCase) == 0) { - // Create condition of config to remove - string condition = String.Format(CultureInfo.InvariantCulture, configString, config, "default"); - - foreach (ProjectPropertyGroupElement element in this.project.BuildProject.Xml.PropertyGroups) { - if (String.Equals(element.Condition, condition, StringComparison.OrdinalIgnoreCase)) { - element.Parent.RemoveChild(element); - } - } - - NotifyOnCfgNameDeleted(name); - } - } - - return VSConstants.S_OK; - } - - /// - /// Deletes a specified platform name. - /// - /// The platform name to delet. - /// If the method succeeds, it returns S_OK. If it fails, it returns an error code. - public virtual int DeleteCfgsOfPlatformName(string platName) { - return VSConstants.E_NOTIMPL; - } - - /// - /// Returns the existing configurations stored in the project file. - /// - /// Specifies the requested number of property names. If this number is unknown, celt can be zero. - /// On input, an allocated array to hold the number of configuration property names specified by celt. This parameter can also be a null reference if the celt parameter is zero. - /// On output, names contains configuration property names. - /// The actual number of property names returned. - /// If the method succeeds, it returns S_OK. If it fails, it returns an error code. - public virtual int GetCfgNames(uint celt, string[] names, uint[] actual) { - // get's called twice, once for allocation, then for retrieval - int i = 0; - - string[] configList = GetPropertiesConditionedOn(ProjectFileConstants.Configuration); - - if (names != null) { - foreach (string config in configList) { - names[i++] = config; - if (i == celt) - break; - } - } else - i = configList.Length; - - if (actual != null) { - actual[0] = (uint)i; - } - - return VSConstants.S_OK; - } - - /// - /// Returns the configuration associated with a specified configuration or platform name. - /// - /// The name of the configuration to be returned. - /// The name of the platform for the configuration to be returned. - /// The implementation of the IVsCfg interface. - /// If the method succeeds, it returns S_OK. If it fails, it returns an error code. - public virtual int GetCfgOfName(string name, string platName, out IVsCfg cfg) { - cfg = null; - cfg = this.GetProjectConfiguration(name); - - return VSConstants.S_OK; - } - - /// - /// Returns a specified configuration property. - /// - /// Specifies the property identifier for the property to return. For valid propid values, see __VSCFGPROPID. - /// The value of the property. - /// If the method succeeds, it returns S_OK. If it fails, it returns an error code. - public virtual int GetCfgProviderProperty(int propid, out object var) { - var = false; - switch ((__VSCFGPROPID)propid) { - case __VSCFGPROPID.VSCFGPROPID_SupportsCfgAdd: - var = true; - break; - - case __VSCFGPROPID.VSCFGPROPID_SupportsCfgDelete: - var = true; - break; - - case __VSCFGPROPID.VSCFGPROPID_SupportsCfgRename: - var = true; - break; - - case __VSCFGPROPID.VSCFGPROPID_SupportsPlatformAdd: - var = false; - break; - - case __VSCFGPROPID.VSCFGPROPID_SupportsPlatformDelete: - var = false; - break; - } - return VSConstants.S_OK; - } - - /// - /// Returns the per-configuration objects for this object. - /// - /// Number of configuration objects to be returned or zero, indicating a request for an unknown number of objects. - /// On input, pointer to an interface array or a null reference. On output, this parameter points to an array of IVsCfg interfaces belonging to the requested configuration objects. - /// The number of configuration objects actually returned or a null reference, if this information is not necessary. - /// Flags that specify settings for project configurations, or a null reference (Nothing in Visual Basic) if no additional flag settings are required. For valid prgrFlags values, see __VSCFGFLAGS. - /// If the method succeeds, it returns S_OK. If it fails, it returns an error code. - public virtual int GetCfgs(uint celt, IVsCfg[] a, uint[] actual, uint[] flags) { - if (flags != null) - flags[0] = 0; - - int i = 0; - string[] configList = GetPropertiesConditionedOn(ProjectFileConstants.Configuration); - - if (a != null) { - foreach (string configName in configList) { - a[i] = this.GetProjectConfiguration(configName); - - i++; - if (i == celt) - break; - } - } else - i = configList.Length; - - if (actual != null) - actual[0] = (uint)i; - - return VSConstants.S_OK; - } - - /// - /// Returns one or more platform names. - /// - /// Specifies the requested number of platform names. If this number is unknown, celt can be zero. - /// On input, an allocated array to hold the number of platform names specified by celt. This parameter can also be a null reference if the celt parameter is zero. On output, names contains platform names. - /// The actual number of platform names returned. - /// If the method succeeds, it returns S_OK. If it fails, it returns an error code. - public virtual int GetPlatformNames(uint celt, string[] names, uint[] actual) { - string[] platforms = this.GetPlatformsFromProject(); - return GetPlatforms(celt, names, actual, platforms); - } - - /// - /// Returns the set of platforms that are installed on the user's machine. - /// - /// Specifies the requested number of supported platform names. If this number is unknown, celt can be zero. - /// On input, an allocated array to hold the number of names specified by celt. This parameter can also be a null reference (Nothing in Visual Basic)if the celt parameter is zero. On output, names contains the names of supported platforms - /// The actual number of platform names returned. - /// If the method succeeds, it returns S_OK. If it fails, it returns an error code. - public virtual int GetSupportedPlatformNames(uint celt, string[] names, uint[] actual) { - string[] platforms = this.GetSupportedPlatformsFromProject(); - return GetPlatforms(celt, names, actual, platforms); - } - - /// - /// Assigns a new name to a configuration. - /// - /// The old name of the target configuration. - /// The new name of the target configuration. - /// If the method succeeds, it returns S_OK. If it fails, it returns an error code. - public virtual int RenameCfgsOfCfgName(string old, string newname) { - // First create the condition that represent the configuration we want to rename - string condition = String.Format(CultureInfo.InvariantCulture, configString, old, "default").Trim(); - - foreach (ProjectPropertyGroupElement config in this.project.BuildProject.Xml.PropertyGroups) { - // Only care about conditional property groups - if (config.Condition == null || config.Condition.Length == 0) - continue; - - // Skip if it isn't the group we want - if (String.Compare(config.Condition.Trim(), condition, StringComparison.OrdinalIgnoreCase) != 0) - continue; - - // Change the name - config.Condition = String.Format(CultureInfo.InvariantCulture, configString, newname, "default"); - // Update the name in our config list - if (configurationsList.ContainsKey(old)) { - ProjectConfig configuration = configurationsList[old]; - configurationsList.Remove(old); - configurationsList.Add(newname, configuration); - // notify the configuration of its new name - configuration.ConfigName = newname; - } - - NotifyOnCfgNameRenamed(old, newname); - } - - return VSConstants.S_OK; - } - - /// - /// Cancels a registration for configuration event notification. - /// - /// The cookie used for registration. - /// If the method succeeds, it returns S_OK. If it fails, it returns an error code. - public virtual int UnadviseCfgProviderEvents(uint cookie) { - this.cfgEventSinks.RemoveAt(cookie); - return VSConstants.S_OK; - } - - /// - /// Registers the caller for configuration event notification. - /// - /// Reference to the IVsCfgProviderEvents interface to be called to provide notification of configuration events. - /// Reference to a token representing the completed registration - /// If the method succeeds, it returns S_OK. If it fails, it returns an error code. - public virtual int AdviseCfgProviderEvents(IVsCfgProviderEvents sink, out uint cookie) { - cookie = this.cfgEventSinks.Add(sink); - return VSConstants.S_OK; - } - - #endregion - - #region helper methods - /// - /// Called when a new configuration name was added. - /// - /// The name of configuration just added. - private void NotifyOnCfgNameAdded(string name) { - foreach (IVsCfgProviderEvents sink in this.cfgEventSinks) { - ErrorHandler.ThrowOnFailure(sink.OnCfgNameAdded(name)); - } - } - - /// - /// Called when a config name was deleted. - /// - /// The name of the configuration. - private void NotifyOnCfgNameDeleted(string name) { - foreach (IVsCfgProviderEvents sink in this.cfgEventSinks) { - ErrorHandler.ThrowOnFailure(sink.OnCfgNameDeleted(name)); - } - } - - /// - /// Called when a config name was renamed - /// - /// Old configuration name - /// New configuration name - private void NotifyOnCfgNameRenamed(string oldName, string newName) { - foreach (IVsCfgProviderEvents sink in this.cfgEventSinks) { - ErrorHandler.ThrowOnFailure(sink.OnCfgNameRenamed(oldName, newName)); - } - } - - /// - /// Called when a platform name was added - /// - /// The name of the platform. - private void NotifyOnPlatformNameAdded(string platformName) { - foreach (IVsCfgProviderEvents sink in this.cfgEventSinks) { - ErrorHandler.ThrowOnFailure(sink.OnPlatformNameAdded(platformName)); - } - } - - /// - /// Called when a platform name was deleted - /// - /// The name of the platform. - private void NotifyOnPlatformNameDeleted(string platformName) { - foreach (IVsCfgProviderEvents sink in this.cfgEventSinks) { - ErrorHandler.ThrowOnFailure(sink.OnPlatformNameDeleted(platformName)); - } - } - - /// - /// Gets all the platforms defined in the project - /// - /// An array of platform names. - private string[] GetPlatformsFromProject() { - string[] platforms = GetPropertiesConditionedOn(ProjectFileConstants.Platform); - - if (platforms == null || platforms.Length == 0) { - return new string[] { x86Platform, AnyCPUPlatform }; - } - - for (int i = 0; i < platforms.Length; i++) { - platforms[i] = ConvertPlatformToVsProject(platforms[i]); - } - - return platforms; - } - - /// - /// Return the supported platform names. - /// - /// An array of supported platform names. - protected string[] GetSupportedPlatformsFromProject() { - string platforms = this.ProjectMgr.BuildProject.GetPropertyValue(ProjectFileConstants.AvailablePlatforms); - - if (platforms == null) { - return new string[] { }; - } - - if (platforms.Contains(",")) { - return platforms.Split(','); - } - - return new string[] { platforms }; - } - - /// - /// Helper function to convert AnyCPU to Any CPU. - /// - /// The oldname. - /// The new name. - private static string ConvertPlatformToVsProject(string oldPlatformName) { - if (String.Compare(oldPlatformName, ProjectFileValues.AnyCPU, StringComparison.OrdinalIgnoreCase) == 0) { - return AnyCPUPlatform; - } - - return oldPlatformName; - } - - /// - /// Common method for handling platform names. - /// - /// Specifies the requested number of platform names. If this number is unknown, celt can be zero. - /// On input, an allocated array to hold the number of platform names specified by celt. This parameter can also be null if the celt parameter is zero. On output, names contains platform names - /// A count of the actual number of platform names returned. - /// An array of available platform names - /// A count of the actual number of platform names returned. - /// The platforms array is never null. It is assured by the callers. - protected static int GetPlatforms(uint celt, string[] names, uint[] actual, string[] platforms) { - Utilities.ArgumentNotNull("platforms", platforms); - if (names == null) { - if (actual == null || actual.Length == 0) { - throw new ArgumentException(SR.GetString(SR.InvalidParameter), "actual"); - } - - actual[0] = (uint)platforms.Length; - return VSConstants.S_OK; - } - - //Degenarate case - if (celt == 0) { - if (actual != null && actual.Length != 0) { - actual[0] = (uint)platforms.Length; - } - - return VSConstants.S_OK; - } - - uint returned = 0; - for (int i = 0; i < platforms.Length && names.Length > returned; i++) { - names[returned] = platforms[i]; - returned++; - } - - if (actual != null && actual.Length != 0) { - actual[0] = returned; - } - - if (celt > returned) { - return VSConstants.S_FALSE; - } - - return VSConstants.S_OK; - } - #endregion - - /// - /// Get all the configurations in the project. - /// - protected string[] GetPropertiesConditionedOn(string constant) { - List configurations = null; - this.project.BuildProject.ReevaluateIfNecessary(); - this.project.BuildProject.ConditionedProperties.TryGetValue(constant, out configurations); - - return (configurations == null) ? new string[] { } : configurations.ToArray(); - } - - } -} diff --git a/Microsoft.VisualStudio.Project/DataObject.cs b/Microsoft.VisualStudio.Project/DataObject.cs deleted file mode 100644 index f1c9ee6d..00000000 --- a/Microsoft.VisualStudio.Project/DataObject.cs +++ /dev/null @@ -1,491 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.InteropServices; -using System.Security.Permissions; -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.OLE.Interop; -using Microsoft.VisualStudio.Shell; - -namespace Microsoft.VisualStudioTools.Project { - internal enum tagDVASPECT { - DVASPECT_CONTENT = 1, - DVASPECT_THUMBNAIL = 2, - DVASPECT_ICON = 4, - DVASPECT_DOCPRINT = 8 - } - - internal enum tagTYMED { - TYMED_HGLOBAL = 1, - TYMED_FILE = 2, - TYMED_ISTREAM = 4, - TYMED_ISTORAGE = 8, - TYMED_GDI = 16, - TYMED_MFPICT = 32, - TYMED_ENHMF = 64, - TYMED_NULL = 0 - } - - internal sealed class DataCacheEntry : IDisposable { - #region fields - /// - /// Defines an object that will be a mutex for this object for synchronizing thread calls. - /// - private static volatile object Mutex = new object(); - - private FORMATETC format; - - private long data; - - private DATADIR dataDir; - - private bool isDisposed; - #endregion - - #region properties - internal FORMATETC Format { - get { - return this.format; - } - } - - internal long Data { - get { - return this.data; - } - } - - internal DATADIR DataDir { - get { - return this.dataDir; - } - } - - #endregion - - /// - /// The IntPtr is data allocated that should be removed. It is allocated by the ProcessSelectionData method. - /// - internal DataCacheEntry(FORMATETC fmt, IntPtr data, DATADIR dir) { - this.format = fmt; - this.data = (long)data; - this.dataDir = dir; - } - - #region Dispose - ~DataCacheEntry() { - Dispose(false); - } - - /// - /// The IDispose interface Dispose method for disposing the object determinastically. - /// - public void Dispose() { - Dispose(true); - GC.SuppressFinalize(this); - } - - /// - /// The method that does the cleanup. - /// - /// - private void Dispose(bool disposing) { - // Everybody can go here. - if (!this.isDisposed) { - // Synchronize calls to the Dispose simulteniously. - lock (Mutex) { - if (disposing && this.data != 0) { - Marshal.FreeHGlobal((IntPtr)this.data); - this.data = 0; - } - - this.isDisposed = true; - } - } - } - #endregion - } - - /// - /// Unfortunately System.Windows.Forms.IDataObject and - /// Microsoft.VisualStudio.OLE.Interop.IDataObject are different... - /// - internal sealed class DataObject : IDataObject { - #region fields - internal const int DATA_S_SAMEFORMATETC = 0x00040130; - EventSinkCollection map; - ArrayList entries; - #endregion - - internal DataObject() { - this.map = new EventSinkCollection(); - this.entries = new ArrayList(); - } - - internal void SetData(FORMATETC format, IntPtr data) { - this.entries.Add(new DataCacheEntry(format, data, DATADIR.DATADIR_SET)); - } - - #region IDataObject methods - int IDataObject.DAdvise(FORMATETC[] e, uint adv, IAdviseSink sink, out uint cookie) { - Utilities.ArgumentNotNull("e", e); - - STATDATA sdata = new STATDATA(); - - sdata.ADVF = adv; - sdata.FORMATETC = e[0]; - sdata.pAdvSink = sink; - cookie = this.map.Add(sdata); - sdata.dwConnection = cookie; - return 0; - } - - void IDataObject.DUnadvise(uint cookie) { - this.map.RemoveAt(cookie); - } - - int IDataObject.EnumDAdvise(out IEnumSTATDATA e) { - e = new EnumSTATDATA((IEnumerable)this.map); - return 0; //?? - } - - int IDataObject.EnumFormatEtc(uint direction, out IEnumFORMATETC penum) { - penum = new EnumFORMATETC((DATADIR)direction, (IEnumerable)this.entries); - return 0; - } - - int IDataObject.GetCanonicalFormatEtc(FORMATETC[] format, FORMATETC[] fmt) { - throw new System.Runtime.InteropServices.COMException("", DATA_S_SAMEFORMATETC); - } - - void IDataObject.GetData(FORMATETC[] fmt, STGMEDIUM[] m) { - STGMEDIUM retMedium = new STGMEDIUM(); - - if (fmt == null || fmt.Length < 1) - return; - - foreach (DataCacheEntry e in this.entries) { - if (e.Format.cfFormat == fmt[0].cfFormat /*|| fmt[0].cfFormat == InternalNativeMethods.CF_HDROP*/) { - retMedium.tymed = e.Format.tymed; - - // Caller must delete the memory. - retMedium.unionmember = DragDropHelper.CopyHGlobal(new IntPtr(e.Data)); - break; - } - } - - if (m != null && m.Length > 0) - m[0] = retMedium; - } - - void IDataObject.GetDataHere(FORMATETC[] fmt, STGMEDIUM[] m) { - } - - int IDataObject.QueryGetData(FORMATETC[] fmt) { - if (fmt == null || fmt.Length < 1) - return VSConstants.S_FALSE; - - foreach (DataCacheEntry e in this.entries) { - if (e.Format.cfFormat == fmt[0].cfFormat /*|| fmt[0].cfFormat == InternalNativeMethods.CF_HDROP*/) - return VSConstants.S_OK; - } - - return VSConstants.S_FALSE; - } - - void IDataObject.SetData(FORMATETC[] fmt, STGMEDIUM[] m, int fRelease) { - } - #endregion - } - - [SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)] - internal static class DragDropHelper { -#pragma warning disable 414 - internal static readonly ushort CF_VSREFPROJECTITEMS; - internal static readonly ushort CF_VSSTGPROJECTITEMS; - internal static readonly ushort CF_VSPROJECTCLIPDESCRIPTOR; -#pragma warning restore 414 - - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline")] - static DragDropHelper() { - CF_VSREFPROJECTITEMS = (ushort)UnsafeNativeMethods.RegisterClipboardFormat("CF_VSREFPROJECTITEMS"); - CF_VSSTGPROJECTITEMS = (ushort)UnsafeNativeMethods.RegisterClipboardFormat("CF_VSSTGPROJECTITEMS"); - CF_VSPROJECTCLIPDESCRIPTOR = (ushort)UnsafeNativeMethods.RegisterClipboardFormat("CF_PROJECTCLIPBOARDDESCRIPTOR"); - } - - - public static FORMATETC CreateFormatEtc(ushort iFormat) { - FORMATETC fmt = new FORMATETC(); - fmt.cfFormat = iFormat; - fmt.ptd = IntPtr.Zero; - fmt.dwAspect = (uint)DVASPECT.DVASPECT_CONTENT; - fmt.lindex = -1; - fmt.tymed = (uint)TYMED.TYMED_HGLOBAL; - return fmt; - } - - public static int QueryGetData(Microsoft.VisualStudio.OLE.Interop.IDataObject pDataObject, ref FORMATETC fmtetc) { - FORMATETC[] af = new FORMATETC[1]; - af[0] = fmtetc; - int result = pDataObject.QueryGetData(af); - if (result == VSConstants.S_OK) { - fmtetc = af[0]; - return VSConstants.S_OK; - } - return result; - } - - public static STGMEDIUM GetData(Microsoft.VisualStudio.OLE.Interop.IDataObject pDataObject, ref FORMATETC fmtetc) { - FORMATETC[] af = new FORMATETC[1]; - af[0] = fmtetc; - STGMEDIUM[] sm = new STGMEDIUM[1]; - pDataObject.GetData(af, sm); - fmtetc = af[0]; - return sm[0]; - } - - /// - /// Retrieves data from a VS format. - /// - public static List GetDroppedFiles(ushort format, Microsoft.VisualStudio.OLE.Interop.IDataObject dataObject, out DropDataType ddt) { - ddt = DropDataType.None; - List droppedFiles = new List(); - - // try HDROP - FORMATETC fmtetc = CreateFormatEtc(format); - - if (QueryGetData(dataObject, ref fmtetc) == VSConstants.S_OK) { - STGMEDIUM stgmedium = DragDropHelper.GetData(dataObject, ref fmtetc); - if (stgmedium.tymed == (uint)TYMED.TYMED_HGLOBAL) { - // We are releasing the cloned hglobal here. - IntPtr dropInfoHandle = stgmedium.unionmember; - if (dropInfoHandle != IntPtr.Zero) { - ddt = DropDataType.Shell; - try { - uint numFiles = UnsafeNativeMethods.DragQueryFile(dropInfoHandle, 0xFFFFFFFF, null, 0); - - // We are a directory based project thus a projref string is placed on the clipboard. - // We assign the maximum length of a projref string. - // The format of a projref is : || - uint lenght = (uint)Guid.Empty.ToString().Length + 2 * NativeMethods.MAX_PATH + 2; - char[] moniker = new char[lenght + 1]; - for (uint fileIndex = 0; fileIndex < numFiles; fileIndex++) { - uint queryFileLength = UnsafeNativeMethods.DragQueryFile(dropInfoHandle, fileIndex, moniker, lenght); - string filename = new String(moniker, 0, (int)queryFileLength); - droppedFiles.Add(filename); - } - } finally { - Marshal.FreeHGlobal(dropInfoHandle); - } - } - } - } - - return droppedFiles; - } - - public static string GetSourceProjectPath(Microsoft.VisualStudio.OLE.Interop.IDataObject dataObject) { - string projectPath = null; - FORMATETC fmtetc = CreateFormatEtc(CF_VSPROJECTCLIPDESCRIPTOR); - - if (QueryGetData(dataObject, ref fmtetc) == VSConstants.S_OK) { - STGMEDIUM stgmedium = DragDropHelper.GetData(dataObject, ref fmtetc); - if (stgmedium.tymed == (uint)TYMED.TYMED_HGLOBAL) { - // We are releasing the cloned hglobal here. - IntPtr dropInfoHandle = stgmedium.unionmember; - if (dropInfoHandle != IntPtr.Zero) { - try { - string path = GetData(dropInfoHandle); - - // Clone the path that we can release our memory. - if (!String.IsNullOrEmpty(path)) { - projectPath = String.Copy(path); - } - } finally { - Marshal.FreeHGlobal(dropInfoHandle); - } - } - } - } - - return projectPath; - } - - /// - /// Returns the data packed after the DROPFILES structure. - /// - /// - /// - internal static string GetData(IntPtr dropHandle) { - IntPtr data = UnsafeNativeMethods.GlobalLock(dropHandle); - try { - _DROPFILES df = (_DROPFILES)Marshal.PtrToStructure(data, typeof(_DROPFILES)); - if (df.fWide != 0) { - IntPtr pdata = new IntPtr((long)data + df.pFiles); - return Marshal.PtrToStringUni(pdata); - } - } finally { - if (data != IntPtr.Zero) { - UnsafeNativeMethods.GlobalUnLock(data); - } - } - - return null; - } - - internal static IntPtr CopyHGlobal(IntPtr data) { - IntPtr src = UnsafeNativeMethods.GlobalLock(data); - var size = UnsafeNativeMethods.GlobalSize(data).ToInt32(); - IntPtr ptr = Marshal.AllocHGlobal(size); - IntPtr buffer = UnsafeNativeMethods.GlobalLock(ptr); - - try { - for (int i = 0; i < size; i++) { - byte val = Marshal.ReadByte(new IntPtr((long)src + i)); - - Marshal.WriteByte(new IntPtr((long)buffer + i), val); - } - } finally { - if (buffer != IntPtr.Zero) { - UnsafeNativeMethods.GlobalUnLock(buffer); - } - - if (src != IntPtr.Zero) { - UnsafeNativeMethods.GlobalUnLock(src); - } - } - return ptr; - } - - internal static void CopyStringToHGlobal(string s, IntPtr data, int bufferSize) { - Int16 nullTerminator = 0; - int dwSize = Marshal.SizeOf(nullTerminator); - - if ((s.Length + 1) * Marshal.SizeOf(s[0]) > bufferSize) - throw new System.IO.InternalBufferOverflowException(); - // IntPtr memory already locked... - for (int i = 0, len = s.Length; i < len; i++) { - Marshal.WriteInt16(data, i * dwSize, s[i]); - } - // NULL terminate it - Marshal.WriteInt16(new IntPtr((long)data + (s.Length * dwSize)), nullTerminator); - } - - } // end of dragdrophelper - - internal class EnumSTATDATA : IEnumSTATDATA { - IEnumerable i; - - IEnumerator e; - - public EnumSTATDATA(IEnumerable i) { - this.i = i; - this.e = i.GetEnumerator(); - } - - void IEnumSTATDATA.Clone(out IEnumSTATDATA clone) { - clone = new EnumSTATDATA(i); - } - - int IEnumSTATDATA.Next(uint celt, STATDATA[] d, out uint fetched) { - uint rc = 0; - //uint size = (fetched != null) ? fetched[0] : 0; - for (uint i = 0; i < celt; i++) { - if (e.MoveNext()) { - STATDATA sdata = (STATDATA)e.Current; - - rc++; - if (d != null && d.Length > i) { - d[i] = sdata; - } - } - } - - fetched = rc; - return 0; - } - - int IEnumSTATDATA.Reset() { - e.Reset(); - return 0; - } - - int IEnumSTATDATA.Skip(uint celt) { - for (uint i = 0; i < celt; i++) { - e.MoveNext(); - } - - return 0; - } - } - - internal class EnumFORMATETC : IEnumFORMATETC { - IEnumerable cache; // of DataCacheEntrys. - - DATADIR dir; - - IEnumerator e; - - public EnumFORMATETC(DATADIR dir, IEnumerable cache) { - this.cache = cache; - this.dir = dir; - e = cache.GetEnumerator(); - } - - void IEnumFORMATETC.Clone(out IEnumFORMATETC clone) { - clone = new EnumFORMATETC(dir, cache); - } - - int IEnumFORMATETC.Next(uint celt, FORMATETC[] d, uint[] fetched) { - uint rc = 0; - //uint size = (fetched != null) ? fetched[0] : 0; - for (uint i = 0; i < celt; i++) { - if (e.MoveNext()) { - DataCacheEntry entry = (DataCacheEntry)e.Current; - - rc++; - if (d != null && d.Length > i) { - d[i] = entry.Format; - } - } else { - return VSConstants.S_FALSE; - } - } - - if (fetched != null && fetched.Length > 0) - fetched[0] = rc; - return VSConstants.S_OK; - } - - int IEnumFORMATETC.Reset() { - e.Reset(); - return 0; - } - - int IEnumFORMATETC.Skip(uint celt) { - for (uint i = 0; i < celt; i++) { - e.MoveNext(); - } - - return 0; - } - } -} diff --git a/Microsoft.VisualStudio.Project/DebugTimer.cs b/Microsoft.VisualStudio.Project/DebugTimer.cs deleted file mode 100644 index 1faadf1a..00000000 --- a/Microsoft.VisualStudio.Project/DebugTimer.cs +++ /dev/null @@ -1,63 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Diagnostics; - -namespace Microsoft.VisualStudioTools { - struct DebugTimer : IDisposable { -#if DEBUG - internal static Stopwatch _timer = MakeStopwatch(); - private readonly long _start, _minReportTime; - private readonly string _description; - - private static Stopwatch MakeStopwatch() { - var res = new Stopwatch(); - res.Start(); - return res; - } -#endif - - /// - /// Creates a new DebugTimer which logs timing information from when it's created - /// to when it's disposed. - /// - /// The message which is logged in addition to the timing information - /// The minimum amount of time (in milliseconds) which needs to elapse for a message to be logged - public DebugTimer(string description, long minReportTime = 0) { -#if DEBUG - _start = _timer.ElapsedMilliseconds; - _description = description; - _minReportTime = minReportTime; -#endif - } - - - #region IDisposable Members - - public void Dispose() { -#if DEBUG - var elapsed = _timer.ElapsedMilliseconds - _start; - if (elapsed >= _minReportTime) { - Debug.WriteLine(String.Format("{0}: {1}ms elapsed", _description, elapsed)); - Console.WriteLine(String.Format("{0}: {1}ms elapsed", _description, elapsed)); - } -#endif - } - - #endregion - } -} diff --git a/Microsoft.VisualStudio.Project/DependentFileNode.cs b/Microsoft.VisualStudio.Project/DependentFileNode.cs deleted file mode 100644 index db033528..00000000 --- a/Microsoft.VisualStudio.Project/DependentFileNode.cs +++ /dev/null @@ -1,146 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.InteropServices; -using System.Text; -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.Shell.Interop; -using OleConstants = Microsoft.VisualStudio.OLE.Interop.Constants; -using VsCommands = Microsoft.VisualStudio.VSConstants.VSStd97CmdID; -using VsCommands2K = Microsoft.VisualStudio.VSConstants.VSStd2KCmdID; - -namespace Microsoft.VisualStudioTools.Project { - /// - /// Defines the logic for all dependent file nodes (solution explorer icon, commands etc.) - /// - - internal class DependentFileNode : FileNode { - #region fields - /// - /// Defines if the node has a name relation to its parent node - /// e.g. Form1.ext and Form1.resx are name related (until first occurence of extention separator) - /// - #endregion - - #region Properties - public override int ImageIndex { - get { return (this.CanShowDefaultIcon() ? (int)ProjectNode.ImageName.DependentFile : (int)ProjectNode.ImageName.MissingFile); } - } - #endregion - - #region ctor - /// - /// Constructor for the DependentFileNode - /// - /// Root of the hierarchy - /// Associated project element - internal DependentFileNode(ProjectNode root, MsBuildProjectElement element) - : base(root, element) { - this.HasParentNodeNameRelation = false; - } - - - #endregion - - #region overridden methods - /// - /// Disable rename - /// - /// new label - /// E_NOTIMPL in order to tell the call that we do not support rename - public override string GetEditLabel() { - throw new NotImplementedException(); - } - - /// - /// Gets a handle to the icon that should be set for this node - /// - /// Whether the folder is open, ignored here. - /// Handle to icon for the node - public override object GetIconHandle(bool open) { - return this.ProjectMgr.ImageHandler.GetIconHandle(this.ImageIndex); - } - - /// - /// Disable certain commands for dependent file nodes - /// - internal override int QueryStatusOnNode(Guid cmdGroup, uint cmd, IntPtr pCmdText, ref QueryStatusResult result) { - if (cmdGroup == VsMenus.guidStandardCommandSet97) { - switch ((VsCommands)cmd) { - case VsCommands.Copy: - case VsCommands.Paste: - case VsCommands.Cut: - case VsCommands.Rename: - result |= QueryStatusResult.NOTSUPPORTED; - return VSConstants.S_OK; - - case VsCommands.ViewCode: - case VsCommands.Open: - case VsCommands.OpenWith: - result |= QueryStatusResult.SUPPORTED | QueryStatusResult.ENABLED; - return VSConstants.S_OK; - } - } else if (cmdGroup == VsMenus.guidStandardCommandSet2K) { - if ((VsCommands2K)cmd == VsCommands2K.EXCLUDEFROMPROJECT) { - result |= QueryStatusResult.NOTSUPPORTED; - return VSConstants.S_OK; - } - } else { - return (int)OleConstants.OLECMDERR_E_UNKNOWNGROUP; - } - return base.QueryStatusOnNode(cmdGroup, cmd, pCmdText, ref result); - } - - /// - /// DependentFileNodes node cannot be dragged. - /// - /// null - protected internal override string PrepareSelectedNodesForClipBoard() { - return null; - } - - protected override NodeProperties CreatePropertiesObject() { - return new DependentFileNodeProperties(this); - } - - /// - /// Redraws the state icon if the node is not excluded from source control. - /// - protected internal override void UpdateSccStateIcons() { - if (!this.ExcludeNodeFromScc) { - ProjectMgr.ReDrawNode(this.Parent, UIHierarchyElement.SccState); - } - } - - public override int QueryService(ref Guid guidService, out object result) { - // - // If you have a code dom provider you'd provide it here. - // if (guidService == typeof(SVSMDCodeDomProvider).GUID) { - // } - - return base.QueryService(ref guidService, out result); - } - - internal override FileNode RenameFileNode(string oldFileName, string newFileName) { - return this.RenameFileNode(oldFileName, newFileName, Parent); - } - - #endregion - - } -} diff --git a/Microsoft.VisualStudio.Project/DesignPropertyDescriptor.cs b/Microsoft.VisualStudio.Project/DesignPropertyDescriptor.cs deleted file mode 100644 index a399fada..00000000 --- a/Microsoft.VisualStudio.Project/DesignPropertyDescriptor.cs +++ /dev/null @@ -1,180 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Collections; -using System.ComponentModel; -using System.Reflection; - -namespace Microsoft.VisualStudioTools.Project { - /// - /// The purpose of DesignPropertyDescriptor is to allow us to customize the - /// display name of the property in the property grid. None of the CLR - /// implementations of PropertyDescriptor allow you to change the DisplayName. - /// - public class DesignPropertyDescriptor : PropertyDescriptor { - private string displayName; // Custom display name - private PropertyDescriptor property; // Base property descriptor - private Hashtable editors = new Hashtable(); // Type -> editor instance - private TypeConverter converter; - - /// - /// Delegates to base. - /// - public override string DisplayName { - get { - return this.displayName; - } - } - - /// - /// Delegates to base. - /// - public override Type ComponentType { - get { - return this.property.ComponentType; - } - } - - /// - /// Delegates to base. - /// - public override bool IsReadOnly { - get { - return this.property.IsReadOnly; - } - } - - /// - /// Delegates to base. - /// - public override Type PropertyType { - get { - return this.property.PropertyType; - } - } - - - /// - /// Delegates to base. - /// - public override object GetEditor(Type editorBaseType) { - object editor = this.editors[editorBaseType]; - if (editor == null) { - for (int i = 0; i < this.Attributes.Count; i++) { - EditorAttribute attr = Attributes[i] as EditorAttribute; - if (attr == null) { - continue; - } - Type editorType = Type.GetType(attr.EditorBaseTypeName); - if (editorBaseType == editorType) { - Type type = GetTypeFromNameProperty(attr.EditorTypeName); - if (type != null) { - editor = CreateInstance(type); - this.editors[type] = editor; // cache it - break; - } - } - } - } - return editor; - } - - - /// - /// Return type converter for property - /// - public override TypeConverter Converter { - get { - if (converter == null) { - if (converter == null) { - converter = property.Converter; - } - } - return converter; - } - } - - /// - /// Convert name to a Type object. - /// - public virtual Type GetTypeFromNameProperty(string typeName) { - return Type.GetType(typeName); - } - - /// - /// Delegates to base. - /// - public override bool CanResetValue(object component) { - bool result = this.property.CanResetValue(component); - return result; - } - - /// - /// Delegates to base. - /// - public override object GetValue(object component) { - object value = this.property.GetValue(component); - return value; - } - - /// - /// Delegates to base. - /// - public override void ResetValue(object component) { - this.property.ResetValue(component); - } - - /// - /// Delegates to base. - /// - public override void SetValue(object component, object value) { - this.property.SetValue(component, value); - } - - /// - /// Delegates to base. - /// - public override bool ShouldSerializeValue(object component) { - // If the user has set the AlwaysSerializedAttribute, do not attempt to bold. - if (property.ComponentType.GetProperty(property.Name).IsDefined(typeof(AlwaysSerializedAttribute))) { - return false; - } else { - bool result = property.ShouldSerializeValue(component); - return result; - } - } - - /// - /// Constructor. Copy the base property descriptor and also hold a pointer - /// to it for calling its overridden abstract methods. - /// - public DesignPropertyDescriptor(PropertyDescriptor prop) - : base(prop) { - Utilities.ArgumentNotNull("prop", prop); - - this.property = prop; - - DisplayNameAttribute attr = prop.Attributes[typeof(DisplayNameAttribute)] as DisplayNameAttribute; - - if (attr != null) { - this.displayName = attr.DisplayName; - } else { - this.displayName = prop.Name; - } - } - } -} diff --git a/Microsoft.VisualStudio.Project/DeveloperActivityAttribute.cs b/Microsoft.VisualStudio.Project/DeveloperActivityAttribute.cs deleted file mode 100644 index 312a07f4..00000000 --- a/Microsoft.VisualStudio.Project/DeveloperActivityAttribute.cs +++ /dev/null @@ -1,46 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using Microsoft.VisualStudio.Shell; - -namespace Microsoft.VisualStudioTools { - class DeveloperActivityAttribute : RegistrationAttribute { - private readonly Type _projectType; - private readonly int _templateSet; - private readonly string _developerActivity; - - public DeveloperActivityAttribute(string developerActivity, Type projectPackageType) { - _developerActivity = developerActivity; - _projectType = projectPackageType; - _templateSet = 1; - } - - public DeveloperActivityAttribute(string developerActivity, Type projectPackageType, int templateSet) { - _developerActivity = developerActivity; - _projectType = projectPackageType; - _templateSet = templateSet; - } - - public override void Register(RegistrationAttribute.RegistrationContext context) { - var key = context.CreateKey("NewProjectTemplates\\TemplateDirs\\" + _projectType.GUID.ToString("B") + "\\/" + _templateSet); - key.SetValue("DeveloperActivity", _developerActivity); - } - - public override void Unregister(RegistrationAttribute.RegistrationContext context) { - } - } -} diff --git a/Microsoft.VisualStudio.Project/DialogWindowVersioningWorkaround.cs b/Microsoft.VisualStudio.Project/DialogWindowVersioningWorkaround.cs deleted file mode 100644 index f226be50..00000000 --- a/Microsoft.VisualStudio.Project/DialogWindowVersioningWorkaround.cs +++ /dev/null @@ -1,29 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using Microsoft.VisualStudio.PlatformUI; - -namespace Microsoft.VisualStudioTools { - /// - /// Works around an issue w/ DialogWindow and targetting multiple versions of VS. - /// - /// Because the Microsoft.VisualStudio.Shell.version.0 assembly changes names - /// we cannot refer to both v10 and v11 versions from within the same XAML file. - /// Instead we use this subclass defined in our assembly. - /// - class DialogWindowVersioningWorkaround : DialogWindow { - } -} diff --git a/Microsoft.VisualStudio.Project/DirtyChangedEventArgs.cs b/Microsoft.VisualStudio.Project/DirtyChangedEventArgs.cs deleted file mode 100644 index 42d6f2e2..00000000 --- a/Microsoft.VisualStudio.Project/DirtyChangedEventArgs.cs +++ /dev/null @@ -1,35 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; - -namespace Microsoft.VisualStudioTools.Project { - public sealed class DirtyChangedEventArgs : EventArgs { - private readonly bool _isDirty; - public static readonly DirtyChangedEventArgs DirtyValue = new DirtyChangedEventArgs(true); - public static readonly DirtyChangedEventArgs SavedValue = new DirtyChangedEventArgs(false); - - public DirtyChangedEventArgs(bool isDirty) { - _isDirty = isDirty; - } - - public bool IsDirty { - get { - return _isDirty; - } - } - } -} diff --git a/Microsoft.VisualStudio.Project/DocumentManager.cs b/Microsoft.VisualStudio.Project/DocumentManager.cs deleted file mode 100644 index f9cc5ed4..00000000 --- a/Microsoft.VisualStudio.Project/DocumentManager.cs +++ /dev/null @@ -1,413 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Diagnostics; -using System.Globalization; -using System.Runtime.InteropServices; -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.Shell; -using Microsoft.VisualStudio.Shell.Interop; -using IServiceProvider = System.IServiceProvider; -using ShellConstants = Microsoft.VisualStudio.Shell.Interop.Constants; - -namespace Microsoft.VisualStudioTools.Project { - /// - /// This abstract class handles opening, saving of items in the hierarchy. - /// - - internal abstract class DocumentManager { - #region fields - private readonly HierarchyNode node = null; - #endregion - - #region properties - protected HierarchyNode Node { - get { - return this.node; - } - } - #endregion - - #region ctors - protected DocumentManager(HierarchyNode node) { - Utilities.ArgumentNotNull("node", node); - this.node = node; - } - #endregion - - #region virtual methods - - /// - /// Open a document using the standard editor. This method has no implementation since a document is abstract in this context - /// - /// In MultiView case determines view to be activated by IVsMultiViewDocumentView. For a list of logical view GUIDS, see constants starting with LOGVIEWID_ defined in NativeMethods class - /// IntPtr to the IUnknown interface of the existing document data object - /// A reference to the window frame that is mapped to the document - /// Determine the UI action on the document window - /// NotImplementedException - /// See FileDocumentManager class for an implementation of this method - public virtual int Open(ref Guid logicalView, IntPtr docDataExisting, out IVsWindowFrame windowFrame, WindowFrameShowAction windowFrameAction) { - throw new NotImplementedException(); - } - - /// - /// Open a document using a specific editor. This method has no implementation. - /// - /// Specifies actions to take when opening a specific editor. Possible editor flags are defined in the enumeration Microsoft.VisualStudio.Shell.Interop.__VSOSPEFLAGS - /// Unique identifier of the editor type - /// Name of the physical view. If null, the environment calls MapLogicalView on the editor factory to determine the physical view that corresponds to the logical view. In this case, null does not specify the primary view, but rather indicates that you do not know which view corresponds to the logical view - /// In MultiView case determines view to be activated by IVsMultiViewDocumentView. For a list of logical view GUIDS, see constants starting with LOGVIEWID_ defined in NativeMethods class - /// IntPtr to the IUnknown interface of the existing document data object - /// A reference to the window frame that is mapped to the document - /// Determine the UI action on the document window - /// NotImplementedException - /// See FileDocumentManager for an implementation of this method - public virtual int OpenWithSpecific(uint editorFlags, ref Guid editorType, string physicalView, ref Guid logicalView, IntPtr docDataExisting, out IVsWindowFrame frame, WindowFrameShowAction windowFrameAction) { - throw new NotImplementedException(); - } - - /// - /// Open a document using a specific editor. This method has no implementation. - /// - /// Specifies actions to take when opening a specific editor. Possible editor flags are defined in the enumeration Microsoft.VisualStudio.Shell.Interop.__VSOSPEFLAGS - /// Unique identifier of the editor type - /// Name of the physical view. If null, the environment calls MapLogicalView on the editor factory to determine the physical view that corresponds to the logical view. In this case, null does not specify the primary view, but rather indicates that you do not know which view corresponds to the logical view - /// In MultiView case determines view to be activated by IVsMultiViewDocumentView. For a list of logical view GUIDS, see constants starting with LOGVIEWID_ defined in NativeMethods class - /// IntPtr to the IUnknown interface of the existing document data object - /// A reference to the window frame that is mapped to the document - /// Determine the UI action on the document window - /// NotImplementedException - /// See FileDocumentManager for an implementation of this method - public virtual int ReOpenWithSpecific(uint editorFlags, ref Guid editorType, string physicalView, ref Guid logicalView, IntPtr docDataExisting, out IVsWindowFrame frame, WindowFrameShowAction windowFrameAction) { - return OpenWithSpecific(editorFlags, ref editorType, physicalView, ref logicalView, docDataExisting, out frame, windowFrameAction); - } - - /// - /// Close an open document window - /// - /// Decides how to close the document - /// S_OK if successful, otherwise an error is returned - public virtual int Close(__FRAMECLOSE closeFlag) { - if (this.node == null || this.node.ProjectMgr == null || this.node.ProjectMgr.IsClosed || this.node.ProjectMgr.IsClosing) { - return VSConstants.E_FAIL; - } - - if (IsOpenedByUs) { - IVsUIShellOpenDocument shell = this.Node.ProjectMgr.Site.GetService(typeof(IVsUIShellOpenDocument)) as IVsUIShellOpenDocument; - Guid logicalView = Guid.Empty; - uint grfIDO = 0; - IVsUIHierarchy pHierOpen; - uint[] itemIdOpen = new uint[1]; - IVsWindowFrame windowFrame; - int fOpen; - ErrorHandler.ThrowOnFailure(shell.IsDocumentOpen(this.Node.ProjectMgr, this.Node.ID, this.Node.Url, ref logicalView, grfIDO, out pHierOpen, itemIdOpen, out windowFrame, out fOpen)); - - if (windowFrame != null) { - return windowFrame.CloseFrame((uint)closeFlag); - } - } - - return VSConstants.S_OK; - } - - /// - /// Silently saves an open document - /// - /// Save the open document only if it is dirty - /// The call to SaveDocData may return Microsoft.VisualStudio.Shell.Interop.PFF_RESULTS.STG_S_DATALOSS to indicate some characters could not be represented in the current codepage - public virtual void Save(bool saveIfDirty) { - if (saveIfDirty && IsDirty) { - IVsPersistDocData persistDocData = DocData; - if (persistDocData != null) { - string name; - int cancelled; - ErrorHandler.ThrowOnFailure(persistDocData.SaveDocData(VSSAVEFLAGS.VSSAVE_SilentSave, out name, out cancelled)); - } - } - } - - #endregion - - /// - /// Queries the RDT to see if the document is currently edited and not saved. - /// - public bool IsDirty { - get { -#if DEV12_OR_LATER - var docTable = (IVsRunningDocumentTable4)node.ProjectMgr.GetService(typeof(SVsRunningDocumentTable)); - if (!docTable.IsMonikerValid(node.GetMkDocument())) { - return false; - } - - return docTable.IsDocumentDirty(docTable.GetDocumentCookie(node.GetMkDocument())); -#else - bool isOpen, isDirty, isOpenedByUs; - uint docCookie; - IVsPersistDocData persistDocData; - GetDocInfo(out isOpen, out isDirty, out isOpenedByUs, out docCookie, out persistDocData); - return isDirty; -#endif - } - } - - /// - /// Queries the RDT to see if the document was opened by our project. - /// - public bool IsOpenedByUs { - get { -#if DEV12_OR_LATER - var docTable = (IVsRunningDocumentTable4)node.ProjectMgr.GetService(typeof(SVsRunningDocumentTable)); - if (!docTable.IsMonikerValid(node.GetMkDocument())) { - return false; - } - - IVsHierarchy hierarchy; - uint itemId; - docTable.GetDocumentHierarchyItem( - docTable.GetDocumentCookie(node.GetMkDocument()), - out hierarchy, - out itemId - ); - return Utilities.IsSameComObject(node.ProjectMgr, hierarchy); -#else - bool isOpen, isDirty, isOpenedByUs; - uint docCookie; - IVsPersistDocData persistDocData; - GetDocInfo(out isOpen, out isDirty, out isOpenedByUs, out docCookie, out persistDocData); - return isOpenedByUs; -#endif - - } - } - - /// - /// Returns the doc cookie in the RDT for the associated file. - /// - public uint DocCookie { - get { -#if DEV12_OR_LATER - var docTable = (IVsRunningDocumentTable4)node.ProjectMgr.GetService(typeof(SVsRunningDocumentTable)); - if (!docTable.IsMonikerValid(node.GetMkDocument())) { - return (uint)ShellConstants.VSDOCCOOKIE_NIL; - } - - return docTable.GetDocumentCookie(node.GetMkDocument()); -#else - bool isOpen, isDirty, isOpenedByUs; - uint docCookie; - IVsPersistDocData persistDocData; - GetDocInfo(out isOpen, out isDirty, out isOpenedByUs, out docCookie, out persistDocData); - return docCookie; -#endif - } - } - - /// - /// Returns the IVsPersistDocData associated with the document, or null if there isn't one. - /// - public IVsPersistDocData DocData { - get { -#if DEV12_OR_LATER - var docTable = (IVsRunningDocumentTable4)node.ProjectMgr.GetService(typeof(SVsRunningDocumentTable)); - if (!docTable.IsMonikerValid(node.GetMkDocument())) { - return null; - } - - return docTable.GetDocumentData(docTable.GetDocumentCookie(node.GetMkDocument())) as IVsPersistDocData; -#else - bool isOpen, isDirty, isOpenedByUs; - uint docCookie; - IVsPersistDocData persistDocData; - GetDocInfo(out isOpen, out isDirty, out isOpenedByUs, out docCookie, out persistDocData); - return persistDocData; -#endif - } - } - - #region helper methods - -#if !DEV12_OR_LATER - /// - /// Get document properties from RDT - /// - private void GetDocInfo( - out bool isOpen, // true if the doc is opened - out bool isDirty, // true if the doc is dirty - out bool isOpenedByUs, // true if opened by our project - out uint docCookie, // VSDOCCOOKIE if open - out IVsPersistDocData persistDocData) - { - isOpen = isDirty = isOpenedByUs = false; - docCookie = (uint)ShellConstants.VSDOCCOOKIE_NIL; - persistDocData = null; - - if (this.node == null || this.node.ProjectMgr == null || this.node.ProjectMgr.IsClosed) - { - return; - } - - IVsHierarchy hierarchy; - uint vsitemid = VSConstants.VSITEMID_NIL; - - VsShellUtilities.GetRDTDocumentInfo(this.node.ProjectMgr.Site, this.node.Url, out hierarchy, out vsitemid, out persistDocData, out docCookie); - - if (hierarchy == null || docCookie == (uint)ShellConstants.VSDOCCOOKIE_NIL) - { - return; - } - - isOpen = true; - // check if the doc is opened by another project - if (Utilities.IsSameComObject(this.node.ProjectMgr, hierarchy)) - { - isOpenedByUs = true; - } - - if (persistDocData != null) - { - int isDocDataDirty; - ErrorHandler.ThrowOnFailure(persistDocData.IsDocDataDirty(out isDocDataDirty)); - isDirty = (isDocDataDirty != 0); - } - } -#endif - - protected string GetOwnerCaption() { - Debug.Assert(this.node != null, "No node has been initialized for the document manager"); - - object pvar; - ErrorHandler.ThrowOnFailure(node.ProjectMgr.GetProperty(node.ID, (int)__VSHPROPID.VSHPROPID_Caption, out pvar)); - - return (pvar as string); - } - - protected static void CloseWindowFrame(ref IVsWindowFrame windowFrame) { - if (windowFrame != null) { - try { - ErrorHandler.ThrowOnFailure(windowFrame.CloseFrame(0)); - } finally { - windowFrame = null; - } - } - } - - protected string GetFullPathForDocument() { - string fullPath = String.Empty; - - // Get the URL representing the item - fullPath = this.node.GetMkDocument(); - - Debug.Assert(!String.IsNullOrEmpty(fullPath), "Could not retrive the fullpath for the node" + this.Node.ID.ToString(CultureInfo.CurrentCulture)); - return fullPath; - } - - #endregion - - #region static methods - /// - /// Updates the caption for all windows associated to the document. - /// - /// The service provider. - /// The new caption. - /// The IUnknown interface to a document data object associated with a registered document. - public static void UpdateCaption(IServiceProvider site, string caption, IntPtr docData) { - Utilities.ArgumentNotNull("site", site); - - if (String.IsNullOrEmpty(caption)) { - throw new ArgumentException(SR.GetString(SR.ParameterCannotBeNullOrEmpty), "caption"); - } - - IVsUIShell uiShell = site.GetService(typeof(SVsUIShell)) as IVsUIShell; - - // We need to tell the windows to update their captions. - IEnumWindowFrames windowFramesEnum; - ErrorHandler.ThrowOnFailure(uiShell.GetDocumentWindowEnum(out windowFramesEnum)); - IVsWindowFrame[] windowFrames = new IVsWindowFrame[1]; - uint fetched; - while (windowFramesEnum.Next(1, windowFrames, out fetched) == VSConstants.S_OK && fetched == 1) { - IVsWindowFrame windowFrame = windowFrames[0]; - object data; - ErrorHandler.ThrowOnFailure(windowFrame.GetProperty((int)__VSFPROPID.VSFPROPID_DocData, out data)); - IntPtr ptr = Marshal.GetIUnknownForObject(data); - try { - if (ptr == docData) { - ErrorHandler.ThrowOnFailure(windowFrame.SetProperty((int)__VSFPROPID.VSFPROPID_OwnerCaption, caption)); - } - } finally { - if (ptr != IntPtr.Zero) { - Marshal.Release(ptr); - } - } - } - } - - /// - /// Rename document in the running document table from oldName to newName. - /// - /// The service provider. - /// Full path to the old name of the document. - /// Full path to the new name of the document. - /// The new item id of the document - public static void RenameDocument(IServiceProvider site, string oldName, string newName, uint newItemId) { - Utilities.ArgumentNotNull("site", site); - - if (String.IsNullOrEmpty(oldName)) { - throw new ArgumentException(SR.GetString(SR.ParameterCannotBeNullOrEmpty), "oldName"); - } - - if (String.IsNullOrEmpty(newName)) { - throw new ArgumentException(SR.GetString(SR.ParameterCannotBeNullOrEmpty), "newName"); - } - - if (newItemId == VSConstants.VSITEMID_NIL) { - throw new ArgumentNullException("newItemId"); - } - - IVsRunningDocumentTable pRDT = site.GetService(typeof(SVsRunningDocumentTable)) as IVsRunningDocumentTable; - IVsUIShellOpenDocument doc = site.GetService(typeof(SVsUIShellOpenDocument)) as IVsUIShellOpenDocument; - - if (pRDT == null || doc == null) - return; - - IVsHierarchy pIVsHierarchy; - uint itemId; - IntPtr docData; - uint uiVsDocCookie; - ErrorHandler.ThrowOnFailure(pRDT.FindAndLockDocument((uint)_VSRDTFLAGS.RDT_NoLock, oldName, out pIVsHierarchy, out itemId, out docData, out uiVsDocCookie)); - - if (docData != IntPtr.Zero && pIVsHierarchy != null) { - try { - IntPtr pUnk = Marshal.GetIUnknownForObject(pIVsHierarchy); - Guid iid = typeof(IVsHierarchy).GUID; - IntPtr pHier; - Marshal.QueryInterface(pUnk, ref iid, out pHier); - try { - ErrorHandler.ThrowOnFailure(pRDT.RenameDocument(oldName, newName, pHier, newItemId)); - } finally { - if (pHier != IntPtr.Zero) - Marshal.Release(pHier); - if (pUnk != IntPtr.Zero) - Marshal.Release(pUnk); - } - } finally { - Marshal.Release(docData); - } - } - } - #endregion - } -} diff --git a/Microsoft.VisualStudio.Project/EnumDependencies.cs b/Microsoft.VisualStudio.Project/EnumDependencies.cs deleted file mode 100644 index 95fc9b08..00000000 --- a/Microsoft.VisualStudio.Project/EnumDependencies.cs +++ /dev/null @@ -1,88 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System.Collections.Generic; -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.Shell.Interop; - -namespace Microsoft.VisualStudioTools.Project { - - public class EnumDependencies : IVsEnumDependencies { - private List dependencyList = new List(); - - private uint nextIndex; - - public EnumDependencies(IList dependencyList) { - Utilities.ArgumentNotNull("dependencyList", dependencyList); - - foreach (IVsDependency dependency in dependencyList) { - this.dependencyList.Add(dependency); - } - } - - public EnumDependencies(IList dependencyList) { - Utilities.ArgumentNotNull("dependencyList", dependencyList); - - foreach (IVsBuildDependency dependency in dependencyList) { - this.dependencyList.Add(dependency); - } - } - - public int Clone(out IVsEnumDependencies enumDependencies) { - enumDependencies = new EnumDependencies(this.dependencyList); - ErrorHandler.ThrowOnFailure(enumDependencies.Skip(this.nextIndex)); - return VSConstants.S_OK; - } - - public int Next(uint elements, IVsDependency[] dependencies, out uint elementsFetched) { - elementsFetched = 0; - Utilities.ArgumentNotNull("dependencies", dependencies); - - uint fetched = 0; - int count = this.dependencyList.Count; - - while (this.nextIndex < count && elements > 0 && fetched < count) { - dependencies[fetched] = this.dependencyList[(int)this.nextIndex]; - this.nextIndex++; - fetched++; - elements--; - - } - - elementsFetched = fetched; - - // Did we get 'em all? - return (elements == 0 ? VSConstants.S_OK : VSConstants.S_FALSE); - } - - public int Reset() { - this.nextIndex = 0; - return VSConstants.S_OK; - } - - public int Skip(uint elements) { - this.nextIndex += elements; - uint count = (uint)this.dependencyList.Count; - - if (this.nextIndex > count) { - this.nextIndex = count; - return VSConstants.S_FALSE; - } - - return VSConstants.S_OK; - } - } -} diff --git a/Microsoft.VisualStudio.Project/ExceptionExtensions.cs b/Microsoft.VisualStudio.Project/ExceptionExtensions.cs deleted file mode 100644 index 7ee0fcf3..00000000 --- a/Microsoft.VisualStudio.Project/ExceptionExtensions.cs +++ /dev/null @@ -1,47 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Threading; - -namespace Microsoft.VisualStudioTools { - static class ExceptionExtensions { - /// - /// Returns true if an exception should not be handled by logging code. - /// - public static bool IsCriticalException(this Exception ex) { - return ex is StackOverflowException || - ex is OutOfMemoryException || - ex is ThreadAbortException || - ex is AccessViolationException || - ex is CriticalException; - } - } - - /// - /// An exception that should not be silently handled and logged. - /// - [Serializable] - class CriticalException : Exception { - public CriticalException() { } - public CriticalException(string message) : base(message) { } - public CriticalException(string message, Exception inner) : base(message, inner) { } - protected CriticalException( - System.Runtime.Serialization.SerializationInfo info, - System.Runtime.Serialization.StreamingContext context) - : base(info, context) { } - } -} \ No newline at end of file diff --git a/Microsoft.VisualStudio.Project/ExtensibilityEventsDispatcher.cs b/Microsoft.VisualStudio.Project/ExtensibilityEventsDispatcher.cs deleted file mode 100644 index ef66de97..00000000 --- a/Microsoft.VisualStudio.Project/ExtensibilityEventsDispatcher.cs +++ /dev/null @@ -1,101 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using EnvDTE; -using Microsoft.VisualStudio.Shell.Interop; - -namespace Microsoft.VisualStudioTools.Project { - /// - /// This is a helper class which fires IVsExtensibility3 events if not in suspended state. - /// - internal sealed class ExtensibilityEventsDispatcher { - private class SuspendLock : IDisposable { - private readonly bool _previousState; - private readonly ExtensibilityEventsDispatcher _owner; - - public SuspendLock(ExtensibilityEventsDispatcher owner) { - this._owner = owner; - this._previousState = this._owner._suspended; - this._owner._suspended = true; - } - - void IDisposable.Dispose() { - this._owner._suspended = this._previousState; - } - } - - private readonly ProjectNode _project; - private bool _suspended; - - public ExtensibilityEventsDispatcher(ProjectNode/*!*/ project) { - Utilities.ArgumentNotNull("project", project); - - this._project = project; - } - - /// - /// Creates a lock which suspends firing of the events until it gets disposed. - /// - public IDisposable Suspend() { - return new SuspendLock(this); - } - - public void FireItemAdded(HierarchyNode node) { - this.Fire(node, (IVsExtensibility3 vsExtensibility, ProjectItem item) => { - vsExtensibility.FireProjectItemsEvent_ItemAdded(item); - }); - } - - public void FireItemRemoved(HierarchyNode node) { - this.Fire(node, (IVsExtensibility3 vsExtensibility, ProjectItem item) => { - vsExtensibility.FireProjectItemsEvent_ItemRemoved(item); - }); - } - - public void FireItemRenamed(HierarchyNode node, string oldName) { - this.Fire(node, (IVsExtensibility3 vsExtensibility, ProjectItem item) => { - vsExtensibility.FireProjectItemsEvent_ItemRenamed(item, oldName); - }); - } - - private void Fire(HierarchyNode node, Action fire) { - // When we are in suspended mode. Do not fire anything - if (this._suspended) { - return; - } - - // Project has to be opened - if (!this._project.IsProjectOpened) { - return; - } - - // We don't want to fire events for references here. OAReferences should do the job - if (node is ReferenceNode) { - return; - } - - IVsExtensibility3 vsExtensibility = this._project.GetService(typeof(IVsExtensibility)) as IVsExtensibility3; - if (vsExtensibility != null) { - object obj = node.GetAutomationObject(); - ProjectItem item = obj as ProjectItem; - if (item != null) { - fire(vsExtensibility, item); - } - } - } - } -} diff --git a/Microsoft.VisualStudio.Project/FileChangeManager.cs b/Microsoft.VisualStudio.Project/FileChangeManager.cs deleted file mode 100644 index f95caed3..00000000 --- a/Microsoft.VisualStudio.Project/FileChangeManager.cs +++ /dev/null @@ -1,261 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Collections.Generic; -using System.Globalization; -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.Shell.Interop; -using IServiceProvider = System.IServiceProvider; - -namespace Microsoft.VisualStudioTools.Project { - /// - /// This object is in charge of reloading nodes that have file monikers that can be listened to changes - /// - internal class FileChangeManager : IVsFileChangeEvents { - #region nested objects - /// - /// Defines a data structure that can link a item moniker to the item and its file change cookie. - /// - private struct ObservedItemInfo { - /// - /// Defines the id of the item that is to be reloaded. - /// - private uint itemID; - - /// - /// Defines the file change cookie that is returned when listening on file changes on the nested project item. - /// - private uint fileChangeCookie; - - /// - /// Defines the nested project item that is to be reloaded. - /// - internal uint ItemID { - get { - return this.itemID; - } - - set { - this.itemID = value; - } - } - - /// - /// Defines the file change cookie that is returned when listenning on file changes on the nested project item. - /// - internal uint FileChangeCookie { - get { - return this.fileChangeCookie; - } - - set { - this.fileChangeCookie = value; - } - } - } - #endregion - - #region Fields - /// - /// Event that is raised when one of the observed file names have changed on disk. - /// - internal event EventHandler FileChangedOnDisk; - - /// - /// Reference to the FileChange service. - /// - private IVsFileChangeEx fileChangeService; - - /// - /// Maps between the observed item identified by its filename (in canonicalized form) and the cookie used for subscribing - /// to the events. - /// - private Dictionary observedItems = new Dictionary(); - - /// - /// Has Disposed already been called? - /// - private bool disposed; - #endregion - - #region Constructor - /// - /// Overloaded ctor. - /// - /// An instance of a project item. - internal FileChangeManager(IServiceProvider serviceProvider) { - #region input validation - if (serviceProvider == null) { - throw new ArgumentNullException("serviceProvider"); - } - #endregion - - this.fileChangeService = (IVsFileChangeEx)serviceProvider.GetService(typeof(SVsFileChangeEx)); - - if (this.fileChangeService == null) { - // VS is in bad state, since the SVsFileChangeEx could not be proffered. - throw new InvalidOperationException(); - } - } - #endregion - - #region IDisposable Members - /// - /// Disposes resources. - /// - public void Dispose() { - // Don't dispose more than once - if (this.disposed) { - return; - } - - this.disposed = true; - - // Unsubscribe from the observed source files. - foreach (ObservedItemInfo info in this.observedItems.Values) { - ErrorHandler.ThrowOnFailure(this.fileChangeService.UnadviseFileChange(info.FileChangeCookie)); - } - - // Clean the observerItems list - this.observedItems.Clear(); - } - #endregion - - #region IVsFileChangeEvents Members - /// - /// Called when one of the file have changed on disk. - /// - /// Number of files changed. - /// Array of file names. - /// Array of flags indicating the type of changes. See _VSFILECHANGEFLAGS. - /// If the method succeeds, it returns S_OK. If it fails, it returns an error code. - int IVsFileChangeEvents.FilesChanged(uint numberOfFilesChanged, string[] filesChanged, uint[] flags) { - if (filesChanged == null) { - throw new ArgumentNullException("filesChanged"); - } - - if (flags == null) { - throw new ArgumentNullException("flags"); - } - - if (this.FileChangedOnDisk != null) { - for (int i = 0; i < numberOfFilesChanged; i++) { - string fullFileName = Utilities.CanonicalizeFileName(filesChanged[i]); - if (this.observedItems.ContainsKey(fullFileName)) { - ObservedItemInfo info = this.observedItems[fullFileName]; - this.FileChangedOnDisk(this, new FileChangedOnDiskEventArgs(fullFileName, info.ItemID, (_VSFILECHANGEFLAGS)flags[i])); - } - } - } - - return VSConstants.S_OK; - } - - /// - /// Notifies clients of changes made to a directory. - /// - /// Name of the directory that had a change. - /// If the method succeeds, it returns S_OK. If it fails, it returns an error code. - int IVsFileChangeEvents.DirectoryChanged(string directory) { - return VSConstants.S_OK; - } - #endregion - - #region helpers - /// - /// Observe when the given file is updated on disk. In this case we do not care about the item id that represents the file in the hierarchy. - /// - /// File to observe. - internal void ObserveItem(string fileName) { - this.ObserveItem(fileName, VSConstants.VSITEMID_NIL); - } - - /// - /// Observe when the given file is updated on disk. - /// - /// File to observe. - /// The item id of the item to observe. - internal void ObserveItem(string fileName, uint id) { - #region Input validation - if (String.IsNullOrEmpty(fileName)) { - throw new ArgumentException(SR.GetString(SR.InvalidParameter), "fileName"); - } - #endregion - - string fullFileName = Utilities.CanonicalizeFileName(fileName); - if (!this.observedItems.ContainsKey(fullFileName)) { - // Observe changes to the file - uint fileChangeCookie; - ErrorHandler.ThrowOnFailure(this.fileChangeService.AdviseFileChange(fullFileName, (uint)(_VSFILECHANGEFLAGS.VSFILECHG_Time | _VSFILECHANGEFLAGS.VSFILECHG_Del), this, out fileChangeCookie)); - - ObservedItemInfo itemInfo = new ObservedItemInfo(); - itemInfo.ItemID = id; - itemInfo.FileChangeCookie = fileChangeCookie; - - // Remember that we're observing this file (used in FilesChanged event handler) - this.observedItems.Add(fullFileName, itemInfo); - } - } - - /// - /// Ignore item file changes for the specified item. - /// - /// File to ignore observing. - /// Flag indicating whether or not to ignore changes (1 to ignore, 0 to stop ignoring). - internal void IgnoreItemChanges(string fileName, bool ignore) { - #region Input validation - if (String.IsNullOrEmpty(fileName)) { - throw new ArgumentException(SR.GetString(SR.InvalidParameter), "fileName"); - } - #endregion - - string fullFileName = Utilities.CanonicalizeFileName(fileName); - if (this.observedItems.ContainsKey(fullFileName)) { - // Call ignore file with the flags specified. - ErrorHandler.ThrowOnFailure(this.fileChangeService.IgnoreFile(0, fileName, ignore ? 1 : 0)); - } - } - - /// - /// Stop observing when the file is updated on disk. - /// - /// File to stop observing. - internal void StopObservingItem(string fileName) { - #region Input validation - if (String.IsNullOrEmpty(fileName)) { - throw new ArgumentException(SR.GetString(SR.InvalidParameter), "fileName"); - } - #endregion - - string fullFileName = Utilities.CanonicalizeFileName(fileName); - - if (this.observedItems.ContainsKey(fullFileName)) { - // Get the cookie that was used for this.observedItems to this file. - ObservedItemInfo itemInfo = this.observedItems[fullFileName]; - - // Remove the file from our observed list. It's important that this is done before the call to - // UnadviseFileChange, because for some reason, the call to UnadviseFileChange can trigger a - // FilesChanged event, and we want to be able to filter that event away. - this.observedItems.Remove(fullFileName); - - // Stop observing the file - ErrorHandler.ThrowOnFailure(this.fileChangeService.UnadviseFileChange(itemInfo.FileChangeCookie)); - } - } - #endregion - } -} diff --git a/Microsoft.VisualStudio.Project/FileDocumentManager.cs b/Microsoft.VisualStudio.Project/FileDocumentManager.cs deleted file mode 100644 index 5a659f40..00000000 --- a/Microsoft.VisualStudio.Project/FileDocumentManager.cs +++ /dev/null @@ -1,267 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Diagnostics; -using System.Runtime.InteropServices; -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.Shell.Interop; -using IOleServiceProvider = Microsoft.VisualStudio.OLE.Interop.IServiceProvider; - -namespace Microsoft.VisualStudioTools.Project { - /// - /// This class handles opening, saving of file items in the hierarchy. - /// - - internal class FileDocumentManager : DocumentManager { - #region ctors - - public FileDocumentManager(FileNode node) - : base(node) { - } - #endregion - - #region overriden methods - - /// - /// Open a file using the standard editor - /// - /// In MultiView case determines view to be activated by IVsMultiViewDocumentView. For a list of logical view GUIDS, see constants starting with LOGVIEWID_ defined in NativeMethods class - /// IntPtr to the IUnknown interface of the existing document data object - /// A reference to the window frame that is mapped to the file - /// Determine the UI action on the document window - /// If the method succeeds, it returns S_OK. If it fails, it returns an error code. - public override int Open(ref Guid logicalView, IntPtr docDataExisting, out IVsWindowFrame windowFrame, WindowFrameShowAction windowFrameAction) { - bool newFile = false; - bool openWith = false; - return this.Open(newFile, openWith, ref logicalView, docDataExisting, out windowFrame, windowFrameAction); - } - - /// - /// Open a file with a specific editor - /// - /// Specifies actions to take when opening a specific editor. Possible editor flags are defined in the enumeration Microsoft.VisualStudio.Shell.Interop.__VSOSPEFLAGS - /// Unique identifier of the editor type - /// Name of the physical view. If null, the environment calls MapLogicalView on the editor factory to determine the physical view that corresponds to the logical view. In this case, null does not specify the primary view, but rather indicates that you do not know which view corresponds to the logical view - /// In MultiView case determines view to be activated by IVsMultiViewDocumentView. For a list of logical view GUIDS, see constants starting with LOGVIEWID_ defined in NativeMethods class - /// IntPtr to the IUnknown interface of the existing document data object - /// A reference to the window frame that is mapped to the file - /// Determine the UI action on the document window - /// If the method succeeds, it returns S_OK. If it fails, it returns an error code. - public override int OpenWithSpecific(uint editorFlags, ref Guid editorType, string physicalView, ref Guid logicalView, IntPtr docDataExisting, out IVsWindowFrame windowFrame, WindowFrameShowAction windowFrameAction) { - windowFrame = null; - bool newFile = false; - bool openWith = false; - return Open(newFile, openWith, editorFlags, ref editorType, physicalView, ref logicalView, docDataExisting, out windowFrame, windowFrameAction); - } - - /// - /// Open a file with a specific editor - /// - /// Specifies actions to take when opening a specific editor. Possible editor flags are defined in the enumeration Microsoft.VisualStudio.Shell.Interop.__VSOSPEFLAGS - /// Unique identifier of the editor type - /// Name of the physical view. If null, the environment calls MapLogicalView on the editor factory to determine the physical view that corresponds to the logical view. In this case, null does not specify the primary view, but rather indicates that you do not know which view corresponds to the logical view - /// In MultiView case determines view to be activated by IVsMultiViewDocumentView. For a list of logical view GUIDS, see constants starting with LOGVIEWID_ defined in NativeMethods class - /// IntPtr to the IUnknown interface of the existing document data object - /// A reference to the window frame that is mapped to the file - /// Determine the UI action on the document window - /// If the method succeeds, it returns S_OK. If it fails, it returns an error code. - public override int ReOpenWithSpecific(uint editorFlags, ref Guid editorType, string physicalView, ref Guid logicalView, IntPtr docDataExisting, out IVsWindowFrame windowFrame, WindowFrameShowAction windowFrameAction) { - windowFrame = null; - bool newFile = false; - bool openWith = false; - return Open(newFile, openWith, editorFlags, ref editorType, physicalView, ref logicalView, docDataExisting, out windowFrame, windowFrameAction, reopen: true); - } - - #endregion - - #region public methods - /// - /// Open a file in a document window with a std editor - /// - /// Open the file as a new file - /// Use a dialog box to determine which editor to use - /// Determine the UI action on the document window - /// If the method succeeds, it returns S_OK. If it fails, it returns an error code. - public int Open(bool newFile, bool openWith, WindowFrameShowAction windowFrameAction) { - Guid logicalView = Guid.Empty; - IVsWindowFrame windowFrame = null; - return this.Open(newFile, openWith, logicalView, out windowFrame, windowFrameAction); - } - - /// - /// Open a file in a document window with a std editor - /// - /// Open the file as a new file - /// Use a dialog box to determine which editor to use - /// In MultiView case determines view to be activated by IVsMultiViewDocumentView. For a list of logical view GUIDS, see constants starting with LOGVIEWID_ defined in NativeMethods class - /// A reference to the window frame that is mapped to the file - /// Determine the UI action on the document window - /// If the method succeeds, it returns S_OK. If it fails, it returns an error code. - public int Open(bool newFile, bool openWith, Guid logicalView, out IVsWindowFrame frame, WindowFrameShowAction windowFrameAction) { - frame = null; - IVsRunningDocumentTable rdt = this.Node.ProjectMgr.Site.GetService(typeof(SVsRunningDocumentTable)) as IVsRunningDocumentTable; - Debug.Assert(rdt != null, " Could not get running document table from the services exposed by this project"); - if (rdt == null) { - return VSConstants.E_FAIL; - } - - // First we see if someone else has opened the requested view of the file. - _VSRDTFLAGS flags = _VSRDTFLAGS.RDT_NoLock; - uint itemid; - IntPtr docData = IntPtr.Zero; - IVsHierarchy ivsHierarchy; - uint docCookie; - string path = this.GetFullPathForDocument(); - int returnValue = VSConstants.S_OK; - - try { - ErrorHandler.ThrowOnFailure(rdt.FindAndLockDocument((uint)flags, path, out ivsHierarchy, out itemid, out docData, out docCookie)); - ErrorHandler.ThrowOnFailure(this.Open(newFile, openWith, ref logicalView, docData, out frame, windowFrameAction)); - } catch (COMException e) { - Trace.WriteLine("Exception :" + e.Message); - returnValue = e.ErrorCode; - } finally { - if (docData != IntPtr.Zero) { - Marshal.Release(docData); - } - } - - return returnValue; - } - - #endregion - - #region virtual methods - /// - /// Open a file in a document window - /// - /// Open the file as a new file - /// Use a dialog box to determine which editor to use - /// In MultiView case determines view to be activated by IVsMultiViewDocumentView. For a list of logical view GUIDS, see constants starting with LOGVIEWID_ defined in NativeMethods class - /// IntPtr to the IUnknown interface of the existing document data object - /// A reference to the window frame that is mapped to the file - /// Determine the UI action on the document window - /// If the method succeeds, it returns S_OK. If it fails, it returns an error code. - public virtual int Open(bool newFile, bool openWith, ref Guid logicalView, IntPtr docDataExisting, out IVsWindowFrame windowFrame, WindowFrameShowAction windowFrameAction) { - windowFrame = null; - Guid editorType = Guid.Empty; - return this.Open(newFile, openWith, 0, ref editorType, null, ref logicalView, docDataExisting, out windowFrame, windowFrameAction); - } - - #endregion - - #region helper methods - - private int Open(bool newFile, bool openWith, uint editorFlags, ref Guid editorType, string physicalView, ref Guid logicalView, IntPtr docDataExisting, out IVsWindowFrame windowFrame, WindowFrameShowAction windowFrameAction, bool reopen = false) { - windowFrame = null; - Debug.Assert(this.Node != null, "No node has been initialized for the document manager"); - Debug.Assert(this.Node.ProjectMgr != null, "No project manager has been initialized for the document manager"); - Debug.Assert(this.Node is FileNode, "Node is not FileNode object"); - - if (this.Node == null || this.Node.ProjectMgr == null || this.Node.ProjectMgr.IsClosed) { - return VSConstants.E_FAIL; - } - - int returnValue = VSConstants.S_OK; - string caption = this.GetOwnerCaption(); - string fullPath = this.GetFullPathForDocument(); - - IVsUIShellOpenDocument uiShellOpenDocument = this.Node.ProjectMgr.Site.GetService(typeof(SVsUIShellOpenDocument)) as IVsUIShellOpenDocument; - IOleServiceProvider serviceProvider = this.Node.ProjectMgr.Site.GetService(typeof(IOleServiceProvider)) as IOleServiceProvider; - -#if DEV11_OR_LATER - var openState = uiShellOpenDocument as IVsUIShellOpenDocument3; - bool showDialog = !reopen && (openState == null || !((__VSNEWDOCUMENTSTATE)openState.NewDocumentState).HasFlag(__VSNEWDOCUMENTSTATE.NDS_Provisional)); -#else - bool showDialog = !reopen; -#endif - - // Make sure that the file is on disk before we open the editor and display message if not found - if (!((FileNode)this.Node).IsFileOnDisk(showDialog)) { - // Bail since we are not able to open the item - // Do not return an error code otherwise an internal error message is shown. The scenario for this operation - // normally is already a reaction to a dialog box telling that the item has been removed. - return VSConstants.S_FALSE; - } - - try { - this.Node.ProjectMgr.OnOpenItem(fullPath); - int result = VSConstants.E_FAIL; - - if (openWith) { - result = uiShellOpenDocument.OpenStandardEditor((uint)__VSOSEFLAGS.OSE_UseOpenWithDialog, fullPath, ref logicalView, caption, this.Node.ProjectMgr, this.Node.ID, docDataExisting, serviceProvider, out windowFrame); - } else { - __VSOSEFLAGS openFlags = 0; - if (newFile) { - openFlags |= __VSOSEFLAGS.OSE_OpenAsNewFile; - } - - //NOTE: we MUST pass the IVsProject in pVsUIHierarchy and the itemid - // of the node being opened, otherwise the debugger doesn't work. - if (editorType != Guid.Empty) { - result = uiShellOpenDocument.OpenSpecificEditor(editorFlags, fullPath, ref editorType, physicalView, ref logicalView, caption, this.Node.ProjectMgr.GetOuterInterface(), this.Node.ID, docDataExisting, serviceProvider, out windowFrame); - } else { - openFlags |= __VSOSEFLAGS.OSE_ChooseBestStdEditor; - result = uiShellOpenDocument.OpenStandardEditor((uint)openFlags, fullPath, ref logicalView, caption, this.Node.ProjectMgr, this.Node.ID, docDataExisting, serviceProvider, out windowFrame); - } - } - - if (result != VSConstants.S_OK && result != VSConstants.S_FALSE && result != VSConstants.OLE_E_PROMPTSAVECANCELLED) { - return result; - } - - if (windowFrame != null) { - object var; - - if (newFile) { - ErrorHandler.ThrowOnFailure(windowFrame.GetProperty((int)__VSFPROPID.VSFPROPID_DocData, out var)); - IVsPersistDocData persistDocData = (IVsPersistDocData)var; - ErrorHandler.ThrowOnFailure(persistDocData.SetUntitledDocPath(fullPath)); - } - - var = null; - ErrorHandler.ThrowOnFailure(windowFrame.GetProperty((int)__VSFPROPID.VSFPROPID_DocCookie, out var)); - this.Node.DocCookie = (uint)(int)var; - - if (windowFrameAction == WindowFrameShowAction.Show) { - ErrorHandler.ThrowOnFailure(windowFrame.Show()); - } else if (windowFrameAction == WindowFrameShowAction.ShowNoActivate) { - ErrorHandler.ThrowOnFailure(windowFrame.ShowNoActivate()); - } else if (windowFrameAction == WindowFrameShowAction.Hide) { - ErrorHandler.ThrowOnFailure(windowFrame.Hide()); - } - } - } catch (COMException e) { - Trace.WriteLine("Exception e:" + e.Message); - returnValue = e.ErrorCode; - CloseWindowFrame(ref windowFrame); - } - - return returnValue; - } - - - #endregion - - private new FileNode Node { - get { - return (FileNode)base.Node; - } - } - - } -} diff --git a/Microsoft.VisualStudio.Project/FileNode.cs b/Microsoft.VisualStudio.Project/FileNode.cs deleted file mode 100644 index 6efc5fba..00000000 --- a/Microsoft.VisualStudio.Project/FileNode.cs +++ /dev/null @@ -1,972 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Runtime.InteropServices; -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.Shell; -using Microsoft.VisualStudio.Shell.Interop; -using OleConstants = Microsoft.VisualStudio.OLE.Interop.Constants; -using VsCommands = Microsoft.VisualStudio.VSConstants.VSStd97CmdID; -using VsCommands2K = Microsoft.VisualStudio.VSConstants.VSStd2KCmdID; - -namespace Microsoft.VisualStudioTools.Project { - - internal class FileNode : HierarchyNode, IDiskBasedNode { - private bool _isLinkFile; - private uint _docCookie; - private static readonly string[] _defaultOpensWithDesignViewExtensions = new[] { ".aspx", ".ascx", ".asax", ".asmx", ".xsd", ".resource", ".xaml" }; - private static readonly string[] _supportsDesignViewExtensions = new[] { ".aspx", ".ascx", ".asax", ".asmx" }; - private static readonly string[] _supportsDesignViewSubTypes = new[] { ProjectFileAttributeValue.Code, ProjectFileAttributeValue.Form, ProjectFileAttributeValue.UserControl, ProjectFileAttributeValue.Component, ProjectFileAttributeValue.Designer }; - private string _caption; - - #region static fields - private static Dictionary extensionIcons; - #endregion - - #region overriden Properties - - public override bool DefaultOpensWithDesignView { - get { - // ASPX\ASCX files support design view but should be opened by default with - // LOGVIEWID_Primary - this is because they support design and html view which - // is a tools option setting for them. If we force designview this option - // gets bypassed. We do a similar thing for asax/asmx/xsd. By doing so, we don't force - // the designer to be invoked when double-clicking on the - it will now go through the - // shell's standard open mechanism. - string extension = Path.GetExtension(Url); - return !_defaultOpensWithDesignViewExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase) && - !IsCodeBehindFile && - SupportsDesignView; - } - } - - public override bool SupportsDesignView { - get { - if (ItemNode != null && !ItemNode.IsExcluded) { - string extension = Path.GetExtension(Url); - if (_supportsDesignViewExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase) || - IsCodeBehindFile) { - return true; - } else { - var subType = ItemNode.GetMetadata("SubType"); - if (subType != null && _supportsDesignViewExtensions.Contains(subType, StringComparer.OrdinalIgnoreCase)) { - return true; - } - } - } - return false; - } - } - - public override bool IsNonMemberItem { - get { - return ItemNode is AllFilesProjectElement; - } - } - - /// - /// overwrites of the generic hierarchyitem. - /// - [System.ComponentModel.BrowsableAttribute(false)] - public override string Caption { - get { - return _caption; - } - } - - private void UpdateCaption() { - // Use LinkedIntoProjectAt property if available - string caption = this.ItemNode.GetMetadata(ProjectFileConstants.LinkedIntoProjectAt); - if (caption == null || caption.Length == 0) { - // Otherwise use filename - caption = this.ItemNode.GetMetadata(ProjectFileConstants.Include); - caption = Path.GetFileName(caption); - } - _caption = caption; - } - - public override string GetEditLabel() { - if (IsLinkFile) { - // cannot rename link files - return null; - } - return Caption; - } - - public override int ImageIndex { - get { - // Check if the file is there. - if (!this.CanShowDefaultIcon()) { - return (int)ProjectNode.ImageName.MissingFile; - } - - //Check for known extensions - int imageIndex; - string extension = Path.GetExtension(this.FileName); - if ((string.IsNullOrEmpty(extension)) || (!extensionIcons.TryGetValue(extension, out imageIndex))) { - // Missing or unknown extension; let the base class handle this case. - return base.ImageIndex; - } - - // The file type is known and there is an image for it in the image list. - return imageIndex; - } - } - - public uint DocCookie { - get { - return this._docCookie; - } - set { - this._docCookie = value; - } - } - - public override bool IsLinkFile { - get { - return _isLinkFile; - } - } - - internal void SetIsLinkFile(bool value) { - _isLinkFile = value; - } - - protected override VSOVERLAYICON OverlayIconIndex { - get { - if (IsLinkFile) { - return VSOVERLAYICON.OVERLAYICON_SHORTCUT; - } - return VSOVERLAYICON.OVERLAYICON_NONE; - } - } - - public override Guid ItemTypeGuid { - get { return VSConstants.GUID_ItemType_PhysicalFile; } - } - - public override int MenuCommandId { - get { return VsMenus.IDM_VS_CTXT_ITEMNODE; } - } - - public override string Url { - get { - return ItemNode.Url; - } - } - - #endregion - - #region ctor - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline")] - static FileNode() { - // Build the dictionary with the mapping between some well known extensions - // and the index of the icons inside the standard image list. - extensionIcons = new Dictionary(StringComparer.OrdinalIgnoreCase); - extensionIcons.Add(".aspx", (int)ProjectNode.ImageName.WebForm); - extensionIcons.Add(".asax", (int)ProjectNode.ImageName.GlobalApplicationClass); - extensionIcons.Add(".asmx", (int)ProjectNode.ImageName.WebService); - extensionIcons.Add(".ascx", (int)ProjectNode.ImageName.WebUserControl); - extensionIcons.Add(".asp", (int)ProjectNode.ImageName.ASPPage); - extensionIcons.Add(".config", (int)ProjectNode.ImageName.WebConfig); - extensionIcons.Add(".htm", (int)ProjectNode.ImageName.HTMLPage); - extensionIcons.Add(".html", (int)ProjectNode.ImageName.HTMLPage); - extensionIcons.Add(".css", (int)ProjectNode.ImageName.StyleSheet); - extensionIcons.Add(".xsl", (int)ProjectNode.ImageName.StyleSheet); - extensionIcons.Add(".vbs", (int)ProjectNode.ImageName.ScriptFile); - extensionIcons.Add(".js", (int)ProjectNode.ImageName.ScriptFile); - extensionIcons.Add(".wsf", (int)ProjectNode.ImageName.ScriptFile); - extensionIcons.Add(".txt", (int)ProjectNode.ImageName.TextFile); - extensionIcons.Add(".resx", (int)ProjectNode.ImageName.Resources); - extensionIcons.Add(".rc", (int)ProjectNode.ImageName.Resources); - extensionIcons.Add(".bmp", (int)ProjectNode.ImageName.Bitmap); - extensionIcons.Add(".ico", (int)ProjectNode.ImageName.Icon); - extensionIcons.Add(".gif", (int)ProjectNode.ImageName.Image); - extensionIcons.Add(".jpg", (int)ProjectNode.ImageName.Image); - extensionIcons.Add(".png", (int)ProjectNode.ImageName.Image); - extensionIcons.Add(".map", (int)ProjectNode.ImageName.ImageMap); - extensionIcons.Add(".wav", (int)ProjectNode.ImageName.Audio); - extensionIcons.Add(".mid", (int)ProjectNode.ImageName.Audio); - extensionIcons.Add(".midi", (int)ProjectNode.ImageName.Audio); - extensionIcons.Add(".avi", (int)ProjectNode.ImageName.Video); - extensionIcons.Add(".mov", (int)ProjectNode.ImageName.Video); - extensionIcons.Add(".mpg", (int)ProjectNode.ImageName.Video); - extensionIcons.Add(".mpeg", (int)ProjectNode.ImageName.Video); - extensionIcons.Add(".cab", (int)ProjectNode.ImageName.CAB); - extensionIcons.Add(".jar", (int)ProjectNode.ImageName.JAR); - extensionIcons.Add(".xslt", (int)ProjectNode.ImageName.XSLTFile); - extensionIcons.Add(".xsd", (int)ProjectNode.ImageName.XMLSchema); - extensionIcons.Add(".xml", (int)ProjectNode.ImageName.XMLFile); - extensionIcons.Add(".pfx", (int)ProjectNode.ImageName.PFX); - extensionIcons.Add(".snk", (int)ProjectNode.ImageName.SNK); - } - - /// - /// Constructor for the FileNode - /// - /// Root of the hierarchy - /// Associated project element - public FileNode(ProjectNode root, ProjectElement element) - : base(root, element) { - UpdateCaption(); - } - #endregion - - #region overridden methods - protected override NodeProperties CreatePropertiesObject() { - if (IsLinkFile) { - return new LinkFileNodeProperties(this); - } else if (IsNonMemberItem) { - return new ExcludedFileNodeProperties(this); - } - - return new IncludedFileNodeProperties(this); - } - - public override object GetIconHandle(bool open) { - int index = this.ImageIndex; - if (NoImage == index) { - // There is no image for this file; let the base class handle this case. - return base.GetIconHandle(open); - } - // Return the handle for the image. - return this.ProjectMgr.ImageHandler.GetIconHandle(index); - } - - /// - /// Get an instance of the automation object for a FileNode - /// - /// An instance of the Automation.OAFileNode if succeeded - public override object GetAutomationObject() { - if (this.ProjectMgr == null || this.ProjectMgr.IsClosed) { - return null; - } - - return new Automation.OAFileItem(this.ProjectMgr.GetAutomationObject() as Automation.OAProject, this); - } - - /// - /// Renames a file node. - /// - /// The new name. - /// An errorcode for failure or S_OK. - /// - /// - /// We are going to throw instead of showing messageboxes, since this method is called from various places where a dialog box does not make sense. - /// For example the FileNodeProperties are also calling this method. That should not show directly a messagebox. - /// Also the automation methods are also calling SetEditLabel - /// - - public override int SetEditLabel(string label) { - // IMPORTANT NOTE: This code will be called when a parent folder is renamed. As such, it is - // expected that we can be called with a label which is the same as the current - // label and this should not be considered a NO-OP. - if (this.ProjectMgr == null || this.ProjectMgr.IsClosed) { - return VSConstants.E_FAIL; - } - - // Validate the filename. - if (String.IsNullOrEmpty(label)) { - throw new InvalidOperationException(SR.GetString(SR.ErrorInvalidFileName, label)); - } else if (label.Length > NativeMethods.MAX_PATH) { - throw new InvalidOperationException(SR.GetString(SR.PathTooLong, label)); - } else if (Utilities.IsFileNameInvalid(label)) { - throw new InvalidOperationException(SR.GetString(SR.ErrorInvalidFileName, label)); - } - - for (HierarchyNode n = this.Parent.FirstChild; n != null; n = n.NextSibling) { - // TODO: Distinguish between real Urls and fake ones (eg. "References") - if (n != this && String.Equals(n.Caption, label, StringComparison.OrdinalIgnoreCase)) { - //A file or folder with the name '{0}' already exists on disk at this location. Please choose another name. - //If this file or folder does not appear in the Solution Explorer, then it is not currently part of your project. To view files which exist on disk, but are not in the project, select Show All Files from the Project menu. - throw new InvalidOperationException(SR.GetString(SR.FileOrFolderAlreadyExists, label)); - } - } - - string fileName = Path.GetFileNameWithoutExtension(label); - - // Verify that the file extension is unchanged - string strRelPath = Path.GetFileName(this.ItemNode.GetMetadata(ProjectFileConstants.Include)); - if (!Utilities.IsInAutomationFunction(this.ProjectMgr.Site) && - !String.Equals(Path.GetExtension(strRelPath), Path.GetExtension(label), StringComparison.OrdinalIgnoreCase)) { - // Prompt to confirm that they really want to change the extension of the file - string message = SR.GetString(SR.ConfirmExtensionChange, label); - IVsUIShell shell = this.ProjectMgr.Site.GetService(typeof(SVsUIShell)) as IVsUIShell; - - Utilities.CheckNotNull(shell, "Could not get the UI shell from the project"); - - if (!VsShellUtilities.PromptYesNo(message, null, OLEMSGICON.OLEMSGICON_INFO, shell)) { - // The user cancelled the confirmation for changing the extension. - // Return S_OK in order not to show any extra dialog box - return VSConstants.S_OK; - } - } - - - // Build the relative path by looking at folder names above us as one scenarios - // where we get called is when a folder above us gets renamed (in which case our path is invalid) - HierarchyNode parent = this.Parent; - while (parent != null && (parent is FolderNode)) { - strRelPath = Path.Combine(parent.Caption, strRelPath); - parent = parent.Parent; - } - - return SetEditLabel(label, strRelPath); - } - - public override string GetMkDocument() { - Debug.Assert(!string.IsNullOrEmpty(this.Url), "No url specified for this node"); - Debug.Assert(Path.IsPathRooted(this.Url), "Url should not be a relative path"); - - return this.Url; - } - - /// - /// Delete the item corresponding to the specified path from storage. - /// - /// - protected internal override void DeleteFromStorage(string path) { - if (File.Exists(path)) { - File.SetAttributes(path, FileAttributes.Normal); // make sure it's not readonly. - File.Delete(path); - } - } - - /// - /// Rename the underlying document based on the change the user just made to the edit label. - /// - protected internal override int SetEditLabel(string label, string relativePath) { - int returnValue = VSConstants.S_OK; - uint oldId = this.ID; - string strSavePath = Path.GetDirectoryName(relativePath); - - strSavePath = CommonUtils.GetAbsoluteDirectoryPath(this.ProjectMgr.ProjectHome, strSavePath); - string newName = Path.Combine(strSavePath, label); - - if (String.Equals(newName, this.Url, StringComparison.Ordinal)) { - // This is really a no-op (including changing case), so there is nothing to do - return VSConstants.S_FALSE; - } else if (String.Equals(newName, this.Url, StringComparison.OrdinalIgnoreCase)) { - // This is a change of file casing only. - } else { - // If the renamed file already exists then quit (unless it is the result of the parent having done the move). - if (IsFileOnDisk(newName) - && (IsFileOnDisk(this.Url) - || !String.Equals(Path.GetFileName(newName), Path.GetFileName(this.Url), StringComparison.OrdinalIgnoreCase))) { - throw new InvalidOperationException(SR.GetString(SR.FileCannotBeRenamedToAnExistingFile, label)); - } else if (newName.Length > NativeMethods.MAX_PATH) { - throw new InvalidOperationException(SR.GetString(SR.PathTooLong, label)); - } - } - - string oldName = this.Url; - // must update the caption prior to calling RenameDocument, since it may - // cause queries of that property (such as from open editors). - string oldrelPath = this.ItemNode.GetMetadata(ProjectFileConstants.Include); - - try { - if (!RenameDocument(oldName, newName)) { - this.ItemNode.Rename(oldrelPath); - } - - if (this is DependentFileNode) { - ProjectMgr.OnInvalidateItems(this.Parent); - } - } catch (Exception e) { - // Just re-throw the exception so we don't get duplicate message boxes. - Trace.WriteLine("Exception : " + e.Message); - this.RecoverFromRenameFailure(newName, oldrelPath); - returnValue = Marshal.GetHRForException(e); - throw; - } - // Return S_FALSE if the hierarchy item id has changed. This forces VS to flush the stale - // hierarchy item id. - if (returnValue == (int)VSConstants.S_OK || returnValue == (int)VSConstants.S_FALSE || returnValue == VSConstants.OLE_E_PROMPTSAVECANCELLED) { - return (oldId == this.ID) ? VSConstants.S_OK : (int)VSConstants.S_FALSE; - } - - return returnValue; - } - - /// - /// Returns a specific Document manager to handle files - /// - /// Document manager object - protected internal override DocumentManager GetDocumentManager() { - return new FileDocumentManager(this); - } - - public override int QueryService(ref Guid guidService, out object result) { - if (guidService == typeof(EnvDTE.Project).GUID) { - result = ProjectMgr.GetAutomationObject(); - return VSConstants.S_OK; - } else if (guidService == typeof(EnvDTE.ProjectItem).GUID) { - result = GetAutomationObject(); - return VSConstants.S_OK; - } - - return base.QueryService(ref guidService, out result); - } - - /// - /// Called by the drag&drop implementation to ask the node - /// which is being dragged/droped over which nodes should - /// process the operation. - /// This allows for dragging to a node that cannot contain - /// items to let its parent accept the drop, while a reference - /// node delegate to the project and a folder/project node to itself. - /// - /// - protected internal override HierarchyNode GetDragTargetHandlerNode() { - Debug.Assert(this.ProjectMgr != null, " The project manager is null for the filenode"); - HierarchyNode handlerNode = this; - while (handlerNode != null && !(handlerNode is ProjectNode || handlerNode is FolderNode)) - handlerNode = handlerNode.Parent; - if (handlerNode == null) - handlerNode = this.ProjectMgr; - return handlerNode; - } - - internal override int ExecCommandOnNode(Guid cmdGroup, uint cmd, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) { - if (this.ProjectMgr == null || this.ProjectMgr.IsClosed) { - return (int)OleConstants.OLECMDERR_E_NOTSUPPORTED; - } - - // Exec on special filenode commands - if (cmdGroup == VsMenus.guidStandardCommandSet97) { - IVsWindowFrame windowFrame = null; - - switch ((VsCommands)cmd) { - case VsCommands.ViewCode: - return ((FileDocumentManager)this.GetDocumentManager()).Open(false, false, VSConstants.LOGVIEWID_Code, out windowFrame, WindowFrameShowAction.Show); - - case VsCommands.ViewForm: - return ((FileDocumentManager)this.GetDocumentManager()).Open(false, false, VSConstants.LOGVIEWID_Designer, out windowFrame, WindowFrameShowAction.Show); - - case VsCommands.Open: - return ((FileDocumentManager)this.GetDocumentManager()).Open(false, false, WindowFrameShowAction.Show); - - case VsCommands.OpenWith: - return ((FileDocumentManager)this.GetDocumentManager()).Open(false, true, VSConstants.LOGVIEWID_UserChooseView, out windowFrame, WindowFrameShowAction.Show); - } - } - - return base.ExecCommandOnNode(cmdGroup, cmd, nCmdexecopt, pvaIn, pvaOut); - } - - - internal override int QueryStatusOnNode(Guid cmdGroup, uint cmd, IntPtr pCmdText, ref QueryStatusResult result) { - if (cmdGroup == VsMenus.guidStandardCommandSet97) { - switch ((VsCommands)cmd) { - case VsCommands.Copy: - case VsCommands.Paste: - case VsCommands.Cut: - case VsCommands.Rename: - result |= QueryStatusResult.SUPPORTED | QueryStatusResult.ENABLED; - return VSConstants.S_OK; - - case VsCommands.ViewCode: - //case VsCommands.Delete: goto case VsCommands.OpenWith; - case VsCommands.Open: - case VsCommands.OpenWith: - result |= QueryStatusResult.SUPPORTED | QueryStatusResult.ENABLED; - return VSConstants.S_OK; - } - } else if (cmdGroup == VsMenus.guidStandardCommandSet2K) { - if ((VsCommands2K)cmd == VsCommands2K.EXCLUDEFROMPROJECT) { - result |= QueryStatusResult.SUPPORTED | QueryStatusResult.ENABLED; - return VSConstants.S_OK; - } - } - return base.QueryStatusOnNode(cmdGroup, cmd, pCmdText, ref result); - } - - - protected override void DoDefaultAction() { - FileDocumentManager manager = this.GetDocumentManager() as FileDocumentManager; - Utilities.CheckNotNull(manager, "Could not get the FileDocumentManager"); - manager.Open(false, false, WindowFrameShowAction.Show); - } - - /// - /// Performs a SaveAs operation of an open document. Called from SaveItem after the running document table has been updated with the new doc data. - /// - /// A pointer to the document in the rdt - /// The new file path to the document - /// - internal override int AfterSaveItemAs(IntPtr docData, string newFilePath) { - Utilities.ArgumentNotNullOrEmpty("newFilePath", newFilePath); - - int returnCode = VSConstants.S_OK; - newFilePath = newFilePath.Trim(); - - //Identify if Path or FileName are the same for old and new file - string newDirectoryName = CommonUtils.NormalizeDirectoryPath(Path.GetDirectoryName(newFilePath)); - string oldDirectoryName = CommonUtils.NormalizeDirectoryPath(Path.GetDirectoryName(this.GetMkDocument())); - bool isSamePath = CommonUtils.IsSameDirectory(newDirectoryName, oldDirectoryName); - bool isSameFile = CommonUtils.IsSamePath(newFilePath, this.Url); - - //Get target container - HierarchyNode targetContainer = null; - bool isLink = false; - if (isSamePath) { - targetContainer = this.Parent; - } else if (!CommonUtils.IsSubpathOf(this.ProjectMgr.ProjectHome, newDirectoryName)) { - targetContainer = this.Parent; - isLink = true; - } else if (CommonUtils.IsSameDirectory(this.ProjectMgr.ProjectHome, newDirectoryName)) { - //the projectnode is the target container - targetContainer = this.ProjectMgr; - } else { - //search for the target container among existing child nodes - targetContainer = this.ProjectMgr.FindNodeByFullPath(newDirectoryName); - if (targetContainer != null && (targetContainer is FileNode)) { - // We already have a file node with this name in the hierarchy. - throw new InvalidOperationException(SR.GetString(SR.FileAlreadyExistsAndCannotBeRenamed, Path.GetFileName(newFilePath))); - } - } - - if (targetContainer == null) { - // Add a chain of subdirectories to the project. - string relativeUri = CommonUtils.GetRelativeDirectoryPath(this.ProjectMgr.ProjectHome, newDirectoryName); - targetContainer = this.ProjectMgr.CreateFolderNodes(relativeUri); - } - Utilities.CheckNotNull(targetContainer, "Could not find a target container"); - - //Suspend file changes while we rename the document - string oldrelPath = this.ItemNode.GetMetadata(ProjectFileConstants.Include); - string oldName = CommonUtils.GetAbsoluteFilePath(this.ProjectMgr.ProjectHome, oldrelPath); - SuspendFileChanges sfc = new SuspendFileChanges(this.ProjectMgr.Site, oldName); - sfc.Suspend(); - - try { - // Rename the node. - DocumentManager.UpdateCaption(this.ProjectMgr.Site, Path.GetFileName(newFilePath), docData); - // Check if the file name was actually changed. - // In same cases (e.g. if the item is a file and the user has changed its encoding) this function - // is called even if there is no real rename. - if (!isSameFile || (this.Parent.ID != targetContainer.ID)) { - // The path of the file is changed or its parent is changed; in both cases we have - // to rename the item. - if (isLink != IsLinkFile) { - if (isLink) { - var newPath = CommonUtils.GetRelativeFilePath( - this.ProjectMgr.ProjectHome, - Path.Combine(Path.GetDirectoryName(Url), Path.GetFileName(newFilePath)) - ); - - ItemNode.SetMetadata(ProjectFileConstants.Link, newPath); - } else { - ItemNode.SetMetadata(ProjectFileConstants.Link, null); - } - SetIsLinkFile(isLink); - } - - RenameFileNode(oldName, newFilePath, targetContainer); - ProjectMgr.OnInvalidateItems(this.Parent); - } - } catch (Exception e) { - Trace.WriteLine("Exception : " + e.Message); - this.RecoverFromRenameFailure(newFilePath, oldrelPath); - throw; - } finally { - sfc.Resume(); - } - - return returnCode; - } - - /// - /// Determines if this is node a valid node for painting the default file icon. - /// - /// - protected override bool CanShowDefaultIcon() { - string moniker = this.GetMkDocument(); - - return File.Exists(moniker); - } - - #endregion - - #region virtual methods - - public override object GetProperty(int propId) { - switch ((__VSHPROPID)propId) { - case __VSHPROPID.VSHPROPID_ItemDocCookie: - if (this.DocCookie != 0) - return (IntPtr)this.DocCookie; //cast to IntPtr as some callers expect VT_INT - break; - - } - return base.GetProperty(propId); - } - - public virtual string FileName { - get { - return this.Caption; - } - set { - this.SetEditLabel(value); - } - } - - /// - /// Determine if this item is represented physical on disk and shows a messagebox in case that the file is not present and a UI is to be presented. - /// - /// true if user should be presented for UI in case the file is not present - /// true if file is on disk - internal protected virtual bool IsFileOnDisk(bool showMessage) { - bool fileExist = IsFileOnDisk(this.Url); - - if (!fileExist && showMessage && !Utilities.IsInAutomationFunction(this.ProjectMgr.Site)) { - string message = SR.GetString(SR.ItemDoesNotExistInProjectDirectory, Caption); - string title = string.Empty; - OLEMSGICON icon = OLEMSGICON.OLEMSGICON_CRITICAL; - OLEMSGBUTTON buttons = OLEMSGBUTTON.OLEMSGBUTTON_OK; - OLEMSGDEFBUTTON defaultButton = OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST; - VsShellUtilities.ShowMessageBox(this.ProjectMgr.Site, title, message, icon, buttons, defaultButton); - } - - return fileExist; - } - - /// - /// Determine if the file represented by "path" exist in storage. - /// Override this method if your files are not persisted on disk. - /// - /// Url representing the file - /// True if the file exist - internal protected virtual bool IsFileOnDisk(string path) { - return File.Exists(path); - } - - /// - /// Renames the file in the hierarchy by removing old node and adding a new node in the hierarchy. - /// - /// The old file name. - /// The new file name - /// The new parent id of the item. - /// The newly added FileNode. - /// While a new node will be used to represent the item, the underlying MSBuild item will be the same and as a result file properties saved in the project file will not be lost. - internal FileNode RenameFileNode(string oldFileName, string newFileName, HierarchyNode newParent) { - if (CommonUtils.IsSamePath(oldFileName, newFileName)) { - // We do not want to rename the same file - return null; - } - - //If we are included in the project and our parent isn't then - //we need to bring our parent into the project - if (!this.IsNonMemberItem && newParent.IsNonMemberItem) { - ErrorHandler.ThrowOnFailure(newParent.IncludeInProject(false)); - } - - // Retrieve child nodes to add later. - List childNodes = this.GetChildNodes(); - - FileNode renamedNode; - using (this.ProjectMgr.ExtensibilityEventsDispatcher.Suspend()) { - - // Remove this from its parent. - ProjectMgr.OnItemDeleted(this); - this.Parent.RemoveChild(this); - - // Update name in MSBuild - this.ItemNode.Rename(CommonUtils.GetRelativeFilePath(ProjectMgr.ProjectHome, newFileName)); - - // Request a new file node be made. This is used to replace the old file node. This way custom - // derived FileNode types will be used and correctly associated on rename. This is useful for things - // like .txt -> .js where the file would now be able to be a startup project/file. - renamedNode = this.ProjectMgr.CreateFileNode(this.ItemNode); - - renamedNode.ItemNode.RefreshProperties(); - renamedNode.UpdateCaption(); - newParent.AddChild(renamedNode); - renamedNode.Parent = newParent; - } - - UpdateCaption(); - ProjectMgr.ReDrawNode(renamedNode, UIHierarchyElement.Caption); - - renamedNode.ProjectMgr.ExtensibilityEventsDispatcher.FireItemRenamed(this, oldFileName); - - //Update the new document in the RDT. - DocumentManager.RenameDocument(renamedNode.ProjectMgr.Site, oldFileName, newFileName, renamedNode.ID); - - //Select the new node in the hierarchy - renamedNode.ExpandItem(EXPANDFLAGS.EXPF_SelectItem); - - // Add children to new node and rename them appropriately. - childNodes.ForEach(x => renamedNode.AddChild(x)); - RenameChildNodes(renamedNode); - - return renamedNode; - } - - /// - /// Rename all childnodes - /// - /// The newly added Parent node. - protected virtual void RenameChildNodes(FileNode parentNode) { - foreach (var childNode in GetChildNodes().OfType()) { - string newfilename; - if (childNode.HasParentNodeNameRelation) { - string relationalName = childNode.Parent.GetRelationalName(); - string extension = childNode.GetRelationNameExtension(); - newfilename = relationalName + extension; - newfilename = CommonUtils.GetAbsoluteFilePath(Path.GetDirectoryName(childNode.Parent.GetMkDocument()), newfilename); - } else { - newfilename = CommonUtils.GetAbsoluteFilePath(Path.GetDirectoryName(childNode.Parent.GetMkDocument()), childNode.Caption); - } - - childNode.RenameDocument(childNode.GetMkDocument(), newfilename); - - //We must update the DependsUpon property since the rename operation will not do it if the childNode is not renamed - //which happens if the is no name relation between the parent and the child - string dependentOf = childNode.ItemNode.GetMetadata(ProjectFileConstants.DependentUpon); - if (!string.IsNullOrEmpty(dependentOf)) { - childNode.ItemNode.SetMetadata(ProjectFileConstants.DependentUpon, childNode.Parent.ItemNode.GetMetadata(ProjectFileConstants.Include)); - } - } - } - - - /// - /// Tries recovering from a rename failure. - /// - /// The file that failed to be renamed. - /// The original filenamee - protected virtual void RecoverFromRenameFailure(string fileThatFailed, string originalFileName) { - if (this.ItemNode != null && !String.IsNullOrEmpty(originalFileName)) { - this.ItemNode.Rename(originalFileName); - } - } - - internal override bool CanDeleteItem(__VSDELETEITEMOPERATION deleteOperation) { - if (deleteOperation == __VSDELETEITEMOPERATION.DELITEMOP_DeleteFromStorage) { - return this.ProjectMgr.CanProjectDeleteItems; - } - return false; - } - - /// - /// This should be overriden for node that are not saved on disk - /// - /// Previous name in storage - /// New name in storage - internal virtual void RenameInStorage(string oldName, string newName) { - // Make a few attempts over a short time period - for (int retries = 4; retries > 0; --retries) { - try { - File.Move(oldName, newName); - return; - } catch (IOException) { - System.Threading.Thread.Sleep(50); - } - } - - // Final attempt has no handling so exception propagates - File.Move(oldName, newName); - } - - /// - /// This method should be overridden to provide the list of special files and associated flags for source control. - /// - /// One of the file associated to the node. - /// The list of files to be placed under source control. - /// The flags that are associated to the files. - protected internal override void GetSccSpecialFiles(string sccFile, IList files, IList flags) { - if (this.ExcludeNodeFromScc) { - return; - } - - Utilities.ArgumentNotNull("files", files); - Utilities.ArgumentNotNull("flags", flags); - - foreach (HierarchyNode node in this.GetChildNodes()) { - files.Add(node.GetMkDocument()); - } - } - - #endregion - - #region Helper methods - /// - /// Gets called to rename the eventually running document this hierarchyitem points to - /// - /// returns FALSE if the doc can not be renamed - internal bool RenameDocument(string oldName, string newName) { - IVsRunningDocumentTable pRDT = this.GetService(typeof(IVsRunningDocumentTable)) as IVsRunningDocumentTable; - if (pRDT == null) - return false; - IntPtr docData = IntPtr.Zero; - IVsHierarchy pIVsHierarchy; - uint itemId; - uint uiVsDocCookie; - - SuspendFileChanges sfc = null; - - if (File.Exists(oldName)) { - sfc = new SuspendFileChanges(this.ProjectMgr.Site, oldName); - sfc.Suspend(); - } - - try { - // Suspend ms build since during a rename operation no msbuild re-evaluation should be performed until we have finished. - // Scenario that could fail if we do not suspend. - // We have a project system relying on MPF that triggers a Compile target build (re-evaluates itself) whenever the project changes. (example: a file is added, property changed.) - // 1. User renames a file in the above project sytem relying on MPF - // 2. Our rename funstionality implemented in this method removes and readds the file and as a post step copies all msbuild entries from the removed file to the added file. - // 3. The project system mentioned will trigger an msbuild re-evaluate with the new item, because it was listening to OnItemAdded. - // The problem is that the item at the "add" time is only partly added to the project, since the msbuild part has not yet been copied over as mentioned in part 2 of the last step of the rename process. - // The result is that the project re-evaluates itself wrongly. - VSRENAMEFILEFLAGS renameflag = VSRENAMEFILEFLAGS.VSRENAMEFILEFLAGS_NoFlags; - ErrorHandler.ThrowOnFailure(pRDT.FindAndLockDocument((uint)_VSRDTFLAGS.RDT_NoLock, oldName, out pIVsHierarchy, out itemId, out docData, out uiVsDocCookie)); - - if (pIVsHierarchy != null && !Utilities.IsSameComObject(pIVsHierarchy, this.ProjectMgr)) { - // Don't rename it if it wasn't opened by us. - return false; - } - - // ask other potentially running packages - if (!this.ProjectMgr.Tracker.CanRenameItem(oldName, newName, renameflag)) { - return false; - } - - if (IsFileOnDisk(oldName)) { - RenameInStorage(oldName, newName); - } - - // For some reason when ignoreFileChanges is called in Resume, we get an ArgumentException because - // Somewhere a required fileWatcher is null. This issue only occurs when you copy and rename a typescript file, - // Calling Resume here prevents said fileWatcher from being null. Don't know why it works, but it does. - // Also fun! This is the only location it can go (between RenameInStorage and RenameFileNode) - // So presumably there is some condition that is no longer met once both of these methods are called with a ts file. - // https://nodejstools.codeplex.com/workitem/1510 - if (sfc != null) { - sfc.Resume(); - sfc.Suspend(); - } - - if (!CommonUtils.IsSamePath(oldName, newName)) { - // Check out the project file if necessary. - if (!this.ProjectMgr.QueryEditProjectFile(false)) { - throw Marshal.GetExceptionForHR(VSConstants.OLE_E_PROMPTSAVECANCELLED); - } - - this.RenameFileNode(oldName, newName); - } else { - this.RenameCaseOnlyChange(oldName, newName); - } - - DocumentManager.UpdateCaption(this.ProjectMgr.Site, Caption, docData); - - // changed from MPFProj: - // http://mpfproj10.codeplex.com/WorkItem/View.aspx?WorkItemId=8231 - this.ProjectMgr.Tracker.OnItemRenamed(oldName, newName, renameflag); - } finally { - if (sfc != null) { - sfc.Resume(); - } - if (docData != IntPtr.Zero) { - Marshal.Release(docData); - } - } - - return true; - } - - internal virtual FileNode RenameFileNode(string oldFileName, string newFileName) { - string newFolder = Path.GetDirectoryName(newFileName) + Path.DirectorySeparatorChar; - var parentFolder = ProjectMgr.FindNodeByFullPath(newFolder); - if (parentFolder == null) { - Debug.Assert(newFolder == ProjectMgr.ProjectHome); - parentFolder = ProjectMgr; - } - - return this.RenameFileNode(oldFileName, newFileName, parentFolder); - } - - /// - /// Renames the file node for a case only change. - /// - /// The new file name. - private void RenameCaseOnlyChange(string oldName, string newName) { - //Update the include for this item. - string relName = CommonUtils.GetRelativeFilePath(this.ProjectMgr.ProjectHome, newName); - Debug.Assert(String.Equals(this.ItemNode.GetMetadata(ProjectFileConstants.Include), relName, StringComparison.OrdinalIgnoreCase), - "Not just changing the filename case"); - - this.ItemNode.Rename(relName); - this.ItemNode.RefreshProperties(); - - UpdateCaption(); - ProjectMgr.ReDrawNode(this, UIHierarchyElement.Caption); - this.RenameChildNodes(this); - - // Refresh the property browser. - IVsUIShell shell = this.ProjectMgr.Site.GetService(typeof(SVsUIShell)) as IVsUIShell; - Utilities.CheckNotNull(shell, "Could not get the UI shell from the project"); - - ErrorHandler.ThrowOnFailure(shell.RefreshPropertyBrowser(0)); - - //Select the new node in the hierarchy - ExpandItem(EXPANDFLAGS.EXPF_SelectItem); - } - - #endregion - - #region helpers - - - /// - /// Update the ChildNodes after the parent node has been renamed - /// - /// The new FileNode created as part of the rename of this node - private void SetNewParentOnChildNodes(FileNode newFileNode) { - foreach (HierarchyNode childNode in GetChildNodes()) { - childNode.Parent = newFileNode; - } - } - - private List GetChildNodes() { - List childNodes = new List(); - HierarchyNode childNode = this.FirstChild; - while (childNode != null) { - childNodes.Add(childNode); - childNode = childNode.NextSibling; - } - return childNodes; - } - #endregion - - void IDiskBasedNode.RenameForDeferredSave(string basePath, string baseNewPath) { - string oldLoc = CommonUtils.GetAbsoluteFilePath(basePath, ItemNode.GetMetadata(ProjectFileConstants.Include)); - string newLoc = CommonUtils.GetAbsoluteFilePath(baseNewPath, ItemNode.GetMetadata(ProjectFileConstants.Include)); - - ProjectMgr.UpdatePathForDeferredSave(oldLoc, newLoc); - // make sure the directory is there - Directory.CreateDirectory(Path.GetDirectoryName(newLoc)); - if (File.Exists(oldLoc)) { - File.Move(oldLoc, newLoc); - } - } - } -} diff --git a/Microsoft.VisualStudio.Project/FileWatcher.cs b/Microsoft.VisualStudio.Project/FileWatcher.cs deleted file mode 100644 index eb5168cc..00000000 --- a/Microsoft.VisualStudio.Project/FileWatcher.cs +++ /dev/null @@ -1,129 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace Microsoft.VisualStudioTools { - /// - /// Listens to the file system change notifications and raises events when a directory, - /// or file in a directory, changes. This replaces using FileSystemWatcher as this - /// implementation/wrapper uses a guard to make sure we don't try to operate during disposal. - /// - internal sealed class FileWatcher : IDisposable { - private FileSystemWatcher _fsw; - - public FileWatcher(string path = "", string filter = "*.*") { - _fsw = new FileSystemWatcher(path, filter); - } - - public bool IsDisposing { get; private set; } - - public bool EnableRaisingEvents { - get { return !IsDisposing ? _fsw.EnableRaisingEvents : false; } - set { if (!IsDisposing) { _fsw.EnableRaisingEvents = value; } } - } - - public bool IncludeSubdirectories { - get { return !IsDisposing ? _fsw.IncludeSubdirectories : false; } - set { if (!IsDisposing) { _fsw.IncludeSubdirectories = value; } } - } - - /// - /// The internal buffer size in bytes. The default is 8192 (8 KB). - /// - public int InternalBufferSize { - get { return !IsDisposing ? _fsw.InternalBufferSize : 0; } - set { if (!IsDisposing) { _fsw.InternalBufferSize = value; } } - } - - public NotifyFilters NotifyFilter { - get { return !IsDisposing ? _fsw.NotifyFilter : new NotifyFilters(); } - set { if (!IsDisposing) { _fsw.NotifyFilter = value; } } - } - - public event FileSystemEventHandler Changed { - add { - _fsw.Changed += value; - } - remove { - _fsw.Changed -= value; - } - } - - public event FileSystemEventHandler Created { - add { - _fsw.Created += value; - } - remove { - _fsw.Created -= value; - } - } - - public event FileSystemEventHandler Deleted { - add { - _fsw.Deleted += value; - } - remove { - _fsw.Deleted -= value; - } - } - - public event ErrorEventHandler Error { - add { - _fsw.Error += value; - } - remove { - _fsw.Error -= value; - } - } - - public event RenamedEventHandler Renamed { - add { - _fsw.Renamed += value; - } - remove { - _fsw.Renamed -= value; - } - } - - public void Dispose() { - if (!IsDisposing) { - IsDisposing = true; - - // Call the _fsw dispose method from the background so it doesn't block anything else. - var backgroundDispose = new Thread(BackgroundDispose); - backgroundDispose.IsBackground = true; - backgroundDispose.Start(); - } - } - - private void BackgroundDispose() - { - try{ - _fsw.Dispose(); - } - catch(Exception){} - } - } -} - diff --git a/Microsoft.VisualStudio.Project/FolderNode.cs b/Microsoft.VisualStudio.Project/FolderNode.cs deleted file mode 100644 index 5a9d646f..00000000 --- a/Microsoft.VisualStudio.Project/FolderNode.cs +++ /dev/null @@ -1,528 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Globalization; -using System.IO; -using System.Runtime.InteropServices; -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.Shell; -using Microsoft.VisualStudio.Shell.Interop; -using OleConstants = Microsoft.VisualStudio.OLE.Interop.Constants; -using VsCommands = Microsoft.VisualStudio.VSConstants.VSStd97CmdID; -using VsCommands2K = Microsoft.VisualStudio.VSConstants.VSStd2KCmdID; - -namespace Microsoft.VisualStudioTools.Project { - - internal class FolderNode : HierarchyNode, IDiskBasedNode { - #region ctors - /// - /// Constructor for the FolderNode - /// - /// Root node of the hierarchy - /// relative path from root i.e.: "NewFolder1\\NewFolder2\\NewFolder3 - /// Associated project element - public FolderNode(ProjectNode root, ProjectElement element) - : base(root, element) { - } - #endregion - - #region overridden properties - public override bool CanOpenCommandPrompt { - get { - return true; - } - } - - internal override string FullPathToChildren { - get { - return Url; - } - } - - public override int SortPriority { - get { return DefaultSortOrderNode.FolderNode; } - } - - /// - /// This relates to the SCC glyph - /// - public override VsStateIcon StateIconIndex { - get { - // The SCC manager does not support being asked for the state icon of a folder (result of the operation is undefined) - return VsStateIcon.STATEICON_NOSTATEICON; - } - } - - public override bool CanAddFiles { - get { - return true; - } - } - - #endregion - - #region overridden methods - protected override NodeProperties CreatePropertiesObject() { - return new FolderNodeProperties(this); - } - - protected internal override void DeleteFromStorage(string path) { - this.DeleteFolder(path); - } - - /// - /// Get the automation object for the FolderNode - /// - /// An instance of the Automation.OAFolderNode type if succeeded - public override object GetAutomationObject() { - if (this.ProjectMgr == null || this.ProjectMgr.IsClosed) { - return null; - } - - return new Automation.OAFolderItem(this.ProjectMgr.GetAutomationObject() as Automation.OAProject, this); - } - - public override object GetIconHandle(bool open) { - return ProjectMgr.GetIconHandleByName(open ? - ProjectNode.ImageName.OpenFolder : - ProjectNode.ImageName.Folder - ); - } - - /// - /// Rename Folder - /// - /// new Name of Folder - /// VSConstants.S_OK, if succeeded - public override int SetEditLabel(string label) { - if (IsBeingCreated) { - return FinishFolderAdd(label, false); - } else { - if (String.Equals(CommonUtils.GetFileOrDirectoryName(Url), label, StringComparison.Ordinal)) { - // Label matches current Name - return VSConstants.S_OK; - } - - string newPath = CommonUtils.GetAbsoluteDirectoryPath(CommonUtils.GetParent(Url), label); - - // Verify that No Directory/file already exists with the new name among current children - var existingChild = Parent.FindImmediateChildByName(label); - if (existingChild != null && existingChild != this) { - return ShowFileOrFolderAlreadyExistsErrorMessage(newPath); - } - - // Verify that No Directory/file already exists with the new name on disk. - // Unless the path exists because it is the path to the source file also. - if ((Directory.Exists(newPath) || File.Exists(newPath)) && !CommonUtils.IsSamePath(Url, newPath)) { - return ShowFileOrFolderAlreadyExistsErrorMessage(newPath); - } - - if (!ProjectMgr.Tracker.CanRenameItem(Url, newPath, VSRENAMEFILEFLAGS.VSRENAMEFILEFLAGS_Directory)) { - return VSConstants.S_OK; - } - } - - try { - var oldTriggerFlag = this.ProjectMgr.EventTriggeringFlag; - ProjectMgr.EventTriggeringFlag |= ProjectNode.EventTriggering.DoNotTriggerTrackerQueryEvents; - try { - RenameFolder(label); - } finally { - ProjectMgr.EventTriggeringFlag = oldTriggerFlag; - } - - - //Refresh the properties in the properties window - IVsUIShell shell = this.ProjectMgr.GetService(typeof(SVsUIShell)) as IVsUIShell; - Utilities.CheckNotNull(shell, "Could not get the UI shell from the project"); - ErrorHandler.ThrowOnFailure(shell.RefreshPropertyBrowser(0)); - - // Notify the listeners that the name of this folder is changed. This will - // also force a refresh of the SolutionExplorer's node. - ProjectMgr.OnPropertyChanged(this, (int)__VSHPROPID.VSHPROPID_Caption, 0); - } catch (Exception e) { - if (e.IsCriticalException()) { - throw; - } - throw new InvalidOperationException(SR.GetString(SR.RenameFolder, e.Message)); - } - return VSConstants.S_OK; - } - - internal static string PathTooLongMessage { - get { - return SR.GetString(SR.PathTooLongShortMessage); - } - } - - private int FinishFolderAdd(string label, bool wasCancelled) { - // finish creation - string filename = label.Trim(); - if (filename == "." || filename == "..") { - Debug.Assert(!wasCancelled); // cancelling leaves us with a valid label - NativeMethods.SetErrorDescription("{0} is an invalid filename.", filename); - return VSConstants.E_FAIL; - } - - var path = Path.Combine(Parent.FullPathToChildren, label); - if (path.Length >= NativeMethods.MAX_FOLDER_PATH) { - if (wasCancelled) { - // cancelling an edit label doesn't result in the error - // being displayed, so we'll display one for the user. - VsShellUtilities.ShowMessageBox( - ProjectMgr.Site, - null, - PathTooLongMessage, - OLEMSGICON.OLEMSGICON_CRITICAL, - OLEMSGBUTTON.OLEMSGBUTTON_OK, - OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST - ); - } else { - NativeMethods.SetErrorDescription(PathTooLongMessage); - } - return VSConstants.E_FAIL; - } - - if (filename == Caption || Parent.FindImmediateChildByName(filename) == null) { - if (ProjectMgr.QueryFolderAdd(Parent, path)) { - Directory.CreateDirectory(path); - IsBeingCreated = false; - var relativePath = CommonUtils.GetRelativeDirectoryPath( - ProjectMgr.ProjectHome, - CommonUtils.GetAbsoluteDirectoryPath(CommonUtils.GetParent(Url), label) - ); - this.ItemNode.Rename(relativePath); - - ProjectMgr.OnItemDeleted(this); - this.Parent.RemoveChild(this); - this.ID = ProjectMgr.ItemIdMap.Add(this); - this.Parent.AddChild(this); - - ExpandItem(EXPANDFLAGS.EXPF_SelectItem); - - ProjectMgr.Tracker.OnFolderAdded( - path, - VSADDDIRECTORYFLAGS.VSADDDIRECTORYFLAGS_NoFlags - ); - } - } else { - Debug.Assert(!wasCancelled); // we choose a label which didn't exist when we started the edit - // Set error: folder already exists - NativeMethods.SetErrorDescription("The folder {0} already exists.", filename); - return VSConstants.E_FAIL; - } - return VSConstants.S_OK; - } - - public override int MenuCommandId { - get { return VsMenus.IDM_VS_CTXT_FOLDERNODE; } - } - - public override Guid ItemTypeGuid { - get { - return VSConstants.GUID_ItemType_PhysicalFolder; - } - } - - public override string Url { - get { - return CommonUtils.EnsureEndSeparator(ItemNode.Url); - } - } - - public override string Caption { - get { - // it might have a backslash at the end... - // and it might consist of Grandparent\parent\this\ - return CommonUtils.GetFileOrDirectoryName(Url); - } - } - - public override string GetMkDocument() { - Debug.Assert(!string.IsNullOrEmpty(this.Url), "No url specified for this node"); - Debug.Assert(Path.IsPathRooted(this.Url), "Url should not be a relative path"); - - return this.Url; - } - - /// - /// Recursively walks the folder nodes and redraws the state icons - /// - protected internal override void UpdateSccStateIcons() { - for (HierarchyNode child = this.FirstChild; child != null; child = child.NextSibling) { - child.UpdateSccStateIcons(); - } - } - - internal override int QueryStatusOnNode(Guid cmdGroup, uint cmd, IntPtr pCmdText, ref QueryStatusResult result) { - if (cmdGroup == VsMenus.guidStandardCommandSet97) { - switch ((VsCommands)cmd) { - case VsCommands.Copy: - case VsCommands.Paste: - case VsCommands.Cut: - case VsCommands.Rename: - result |= QueryStatusResult.SUPPORTED | QueryStatusResult.ENABLED; - return VSConstants.S_OK; - - case VsCommands.NewFolder: - if (!IsNonMemberItem) { - result |= QueryStatusResult.SUPPORTED | QueryStatusResult.ENABLED; - return VSConstants.S_OK; - } - break; - } - } else if (cmdGroup == VsMenus.guidStandardCommandSet2K) { - if ((VsCommands2K)cmd == VsCommands2K.EXCLUDEFROMPROJECT) { - result |= QueryStatusResult.SUPPORTED | QueryStatusResult.ENABLED; - return VSConstants.S_OK; - } - } else if (cmdGroup != ProjectMgr.SharedCommandGuid) { - return (int)OleConstants.OLECMDERR_E_UNKNOWNGROUP; - } - return base.QueryStatusOnNode(cmdGroup, cmd, pCmdText, ref result); - } - - internal override bool CanDeleteItem(__VSDELETEITEMOPERATION deleteOperation) { - if (deleteOperation == __VSDELETEITEMOPERATION.DELITEMOP_DeleteFromStorage) { - return this.ProjectMgr.CanProjectDeleteItems; - } - return false; - } - - protected internal override void GetSccFiles(IList files, IList flags) { - for (HierarchyNode n = this.FirstChild; n != null; n = n.NextSibling) { - n.GetSccFiles(files, flags); - } - } - - protected internal override void GetSccSpecialFiles(string sccFile, IList files, IList flags) { - for (HierarchyNode n = this.FirstChild; n != null; n = n.NextSibling) { - n.GetSccSpecialFiles(sccFile, files, flags); - } - } - - #endregion - - #region virtual methods - /// - /// Override if your node is not a file system folder so that - /// it does nothing or it deletes it from your storage location. - /// - /// Path to the folder to delete - public virtual void DeleteFolder(string path) { - if (Directory.Exists(path)) { - try { - try { - Directory.Delete(path, true); - } catch (UnauthorizedAccessException) { - // probably one or more files are read only - foreach (var file in Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories)) { - // We will ignore all exceptions here and rethrow when - // we retry the Directory.Delete. - try { - File.SetAttributes(file, FileAttributes.Normal); - } catch (UnauthorizedAccessException) { - } catch (IOException) { - } - } - Directory.Delete(path, true); - } - } catch (IOException ioEx) { - // re-throw with a friendly path - throw new IOException(ioEx.Message.Replace(path, Caption)); - } - } - } - - /// - /// creates the physical directory for a folder node - /// Override if your node does not use file system folder - /// - public virtual void CreateDirectory() { - if (Directory.Exists(this.Url) == false) { - Directory.CreateDirectory(this.Url); - } - } - /// - /// Creates a folder nodes physical directory - /// Override if your node does not use file system folder - /// - /// - /// - public virtual void CreateDirectory(string newName) { - if (String.IsNullOrEmpty(newName)) { - throw new ArgumentException(SR.GetString(SR.ParameterCannotBeNullOrEmpty), "newName"); - } - - // on a new dir && enter, we get called with the same name (so do nothing if name is the same - string strNewDir = CommonUtils.GetAbsoluteDirectoryPath(CommonUtils.GetParent(Url), newName); - - if (!CommonUtils.IsSameDirectory(Url, strNewDir)) { - if (Directory.Exists(strNewDir)) { - throw new InvalidOperationException(SR.GetString(SR.DirectoryExistsShortMessage)); - } - Directory.CreateDirectory(strNewDir); - } - } - - /// - /// Rename the physical directory for a folder node - /// Override if your node does not use file system folder - /// - /// - public virtual void RenameDirectory(string newPath) { - if (Directory.Exists(this.Url)) { - if (CommonUtils.IsSamePath(this.Url, newPath)) { - // This is a rename to the same location with (possible) capitilization changes. - // Directory.Move does not allow renaming to the same name so P/Invoke MoveFile to bypass this. - if (!NativeMethods.MoveFile(this.Url, newPath)) { - // Rather than perform error handling, Call Directory.Move and let it handle the error handling. - // If this succeeds, then we didn't really have errors that needed handling. - Directory.Move(this.Url, newPath); - } - } else if (Directory.Exists(newPath)) { - // Directory exists and it wasn't the source. Item cannot be moved as name exists. - ShowFileOrFolderAlreadyExistsErrorMessage(newPath); - } else { - Directory.Move(this.Url, newPath); - } - } - } - - void IDiskBasedNode.RenameForDeferredSave(string basePath, string baseNewPath) { - string oldPath = Path.Combine(basePath, ItemNode.GetMetadata(ProjectFileConstants.Include)); - string newPath = Path.Combine(baseNewPath, ItemNode.GetMetadata(ProjectFileConstants.Include)); - Directory.CreateDirectory(newPath); - - ProjectMgr.UpdatePathForDeferredSave(oldPath, newPath); - } - - #endregion - - #region helper methods - - /// - /// Renames the folder to the new name. - /// - public virtual void RenameFolder(string newName) { - // Do the rename (note that we only do the physical rename if the leaf name changed) - string newPath = Path.Combine(Parent.FullPathToChildren, newName); - string oldPath = Url; - if (!String.Equals(Path.GetFileName(Url), newName, StringComparison.Ordinal)) { - RenameDirectory(CommonUtils.GetAbsoluteDirectoryPath(ProjectMgr.ProjectHome, newPath)); - } - - bool wasExpanded = GetIsExpanded(); - - ReparentFolder(newPath); - - var oldTriggerFlag = ProjectMgr.EventTriggeringFlag; - ProjectMgr.EventTriggeringFlag |= ProjectNode.EventTriggering.DoNotTriggerTrackerEvents; - try { - // Let all children know of the new path - for (HierarchyNode child = this.FirstChild; child != null; child = child.NextSibling) { - FolderNode node = child as FolderNode; - - if (node == null) { - child.SetEditLabel(child.GetEditLabel()); - } else { - node.RenameFolder(node.Caption); - } - } - } finally { - ProjectMgr.EventTriggeringFlag = oldTriggerFlag; - } - - ProjectMgr.Tracker.OnItemRenamed(oldPath, newPath, VSRENAMEFILEFLAGS.VSRENAMEFILEFLAGS_Directory); - - // Some of the previous operation may have changed the selection so set it back to us - ExpandItem(wasExpanded ? EXPANDFLAGS.EXPF_ExpandFolder : EXPANDFLAGS.EXPF_CollapseFolder); - ExpandItem(EXPANDFLAGS.EXPF_SelectItem); - } - - /// - /// Moves the HierarchyNode from the old path to be a child of the - /// newly specified node. - /// - /// This is a low-level operation that only updates the hierarchy and our MSBuild - /// state. The parents of the node must already be created. - /// - /// To do a general rename, call RenameFolder instead. - /// - internal void ReparentFolder(string newPath) { - // Reparent the folder - ProjectMgr.OnItemDeleted(this); - Parent.RemoveChild(this); - ID = ProjectMgr.ItemIdMap.Add(this); - - ItemNode.Rename(CommonUtils.GetRelativeDirectoryPath(ProjectMgr.ProjectHome, newPath)); - var parent = ProjectMgr.GetParentFolderForPath(newPath); - Debug.Assert(parent != null, "ReparentFolder called without full path to parent being created"); - parent.AddChild(this); - } - - /// - /// Show error message if not in automation mode, otherwise throw exception - /// - /// path of file or folder already existing on disk - /// S_OK - private int ShowFileOrFolderAlreadyExistsErrorMessage(string newPath) { - //A file or folder with the name '{0}' already exists on disk at this location. Please choose another name. - //If this file or folder does not appear in the Solution Explorer, then it is not currently part of your project. To view files which exist on disk, but are not in the project, select Show All Files from the Project menu. - string errorMessage = SR.GetString(SR.FileOrFolderAlreadyExists, newPath); - if (!Utilities.IsInAutomationFunction(this.ProjectMgr.Site)) { - string title = null; - OLEMSGICON icon = OLEMSGICON.OLEMSGICON_CRITICAL; - OLEMSGBUTTON buttons = OLEMSGBUTTON.OLEMSGBUTTON_OK; - OLEMSGDEFBUTTON defaultButton = OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST; - VsShellUtilities.ShowMessageBox(this.ProjectMgr.Site, title, errorMessage, icon, buttons, defaultButton); - return VSConstants.S_OK; - } else { - throw new InvalidOperationException(errorMessage); - } - } - - protected override void OnCancelLabelEdit() { - if (IsBeingCreated) { - // finish the creation - FinishFolderAdd(Caption, true); - } - } - - internal bool IsBeingCreated { - get { - return ProjectMgr.FolderBeingCreated == this; - } - set { - if (value) { - ProjectMgr.FolderBeingCreated = this; - } else { - ProjectMgr.FolderBeingCreated = null; - } - } - } - - #endregion - - protected override void RaiseOnItemRemoved(string documentToRemove, string[] filesToBeDeleted) { - VSREMOVEDIRECTORYFLAGS[] removeFlags = new VSREMOVEDIRECTORYFLAGS[1]; - this.ProjectMgr.Tracker.OnFolderRemoved(documentToRemove, removeFlags[0]); - } - } -} diff --git a/Microsoft.VisualStudio.Project/HierarchyIdMap.cs b/Microsoft.VisualStudio.Project/HierarchyIdMap.cs deleted file mode 100644 index dfbe8386..00000000 --- a/Microsoft.VisualStudio.Project/HierarchyIdMap.cs +++ /dev/null @@ -1,71 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Collections.Generic; -using System.Diagnostics; - -namespace Microsoft.VisualStudioTools.Project { - sealed class HierarchyIdMap { - private readonly List _ids = new List(); - private readonly Stack _freedIds = new Stack(); - - public uint Add(HierarchyNode node) { - UIThread.MustBeCalledFromUIThread(); - -#if DEBUG - foreach (var item in _ids) { - Debug.Assert(node != item); - } -#endif - if (_freedIds.Count > 0) { - var i = _freedIds.Pop(); - _ids[i] = node; - return (uint)i + 1; - } else { - _ids.Add(node); - // ids are 1 based - return (uint)_ids.Count; - } - } - - public void Remove(HierarchyNode node) { - UIThread.MustBeCalledFromUIThread(); - - int i = (int)node.ID - 1; - if(i < 0 || - i >= _ids.Count || - !object.ReferenceEquals(node, _ids[i])) { - throw new InvalidOperationException("Removing node with invalid ID or map is corrupted"); - } - - _ids[i] = null; - _freedIds.Push(i); - } - - public HierarchyNode this[uint itemId] { - get { - UIThread.MustBeCalledFromUIThread(); - - int i = (int)itemId - 1; - if (0 <= i && i < _ids.Count) { - return _ids[i]; - } - return null; - } - } - } -} diff --git a/Microsoft.VisualStudio.Project/HierarchyNode.cs b/Microsoft.VisualStudio.Project/HierarchyNode.cs deleted file mode 100644 index ded0fdfb..00000000 --- a/Microsoft.VisualStudio.Project/HierarchyNode.cs +++ /dev/null @@ -1,1877 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Globalization; -using System.IO; -using System.Runtime.InteropServices; -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.OLE.Interop; -//#define CCI_TRACING -using Microsoft.VisualStudio.Shell.Interop; -using OleConstants = Microsoft.VisualStudio.OLE.Interop.Constants; -using VsCommands = Microsoft.VisualStudio.VSConstants.VSStd97CmdID; -using VsCommands2K = Microsoft.VisualStudio.VSConstants.VSStd2KCmdID; -using IOleServiceProvider = Microsoft.VisualStudio.OLE.Interop.IServiceProvider; - -namespace Microsoft.VisualStudioTools.Project { - /// - /// An object that deals with user interaction via a GUI in the form a hierarchy: a parent node with zero or more child nodes, each of which - /// can itself be a hierarchy. - /// - internal abstract class HierarchyNode : - IDisposable, - IOleServiceProvider { - public static readonly Guid SolutionExplorer = new Guid(EnvDTE.Constants.vsWindowKindSolutionExplorer); - public const int NoImage = -1; -#if DEBUG - internal static int LastTracedProperty; -#endif - - private ProjectElement itemNode; - private ProjectNode projectMgr; - private HierarchyNode parentNode; - private HierarchyNode nextSibling; - private HierarchyNode firstChild; - - /// - /// Remember the last child in the list, - /// so we can add new nodes quickly during project load. - /// - private HierarchyNode lastChild; - - private uint hierarchyId; - private HierarchyNodeFlags flags; - - private NodeProperties nodeProperties; - - #region abstract properties - /// - /// The URL of the node. - /// - /// - public abstract string Url { - get; - } - - /// - /// The Caption of the node. - /// - /// - public abstract string Caption { - get; - } - - /// - /// The item type guid associated to a node. - /// - /// - public abstract Guid ItemTypeGuid { - get; - } - #endregion - - #region virtual properties - - public virtual bool CanOpenCommandPrompt { - get { - return false; - } - } - - public virtual bool IsNonMemberItem { - get { - return false; - } - } - - /// - /// Returns true if the item should be included in search results - /// - /// By default all items in the project are searchable. - /// - public virtual bool IsSearchable { - get { - return !IsNonMemberItem; - } - } - - /// - /// Gets the full path to where children of this node live on disk. - /// - /// This should only be called on nodes which actually can have children, such - /// as folders and project nodes. For all other nodes this will raise an - /// InvalidOperationException. - /// - /// For a project node, this returns the project home folder. For folder - /// nodes this returns the folder's path. - /// - internal virtual string FullPathToChildren { - get { - Debug.Fail("This node cannot have children"); - throw new InvalidOperationException(); - } - } - - /// - /// Defines a string that is used to separate the name relation from the extension - /// - public virtual string NameRelationSeparator { - get { - return "."; - } - } - - - public virtual int MenuCommandId { - get { return VsMenus.IDM_VS_CTXT_NOCOMMANDS; } - } - - public virtual Guid MenuGroupId { - get { return VsMenus.guidSHLMainMenu; } - } - - - /// - /// Return an imageindex - /// - /// - public virtual int ImageIndex { - get { return NoImage; } - } - - /// - /// Return an state icon index - /// - /// - /// - /// Sets the state icon for a file. - /// - public virtual VsStateIcon StateIconIndex { - get { - if (!this.ExcludeNodeFromScc) { - IVsSccManager2 sccManager = this.ProjectMgr.Site.GetService(typeof(SVsSccManager)) as IVsSccManager2; - if (sccManager != null) { - string mkDocument = this.GetMkDocument(); - if (!string.IsNullOrEmpty(mkDocument)) { - VsStateIcon[] statIcons = new VsStateIcon[1] { VsStateIcon.STATEICON_NOSTATEICON }; - uint[] sccStatus = new uint[1] { 0 }; - // Get the glyph from the scc manager. Note that it will fail in command line - // scenarios. - if (ErrorHandler.Succeeded(sccManager.GetSccGlyph(1, new string[] { mkDocument }, statIcons, sccStatus))) { - return statIcons[0]; - } - } - } - } - - return VsStateIcon.STATEICON_NOSTATEICON; - } - } - - public virtual bool IsLinkFile { - get { - return false; - } - } - - protected virtual VSOVERLAYICON OverlayIconIndex { - get { - return VSOVERLAYICON.OVERLAYICON_NONE; - } - } - - /// - /// Defines whether a node can execute a command if in selection. - /// - public virtual bool CanExecuteCommand { - get { - return true; - } - } - - /// - /// Used to determine the sort order of different node types - /// in the solution explorer window. - /// Nodes with the same priorities are sorted based on their captions. - /// - public virtual int SortPriority { - get { return DefaultSortOrderNode.HierarchyNode; } - } - - /// - /// Returns an object that is a special view over this object; this is the value - /// returned by the Object property of the automation objects. - /// - internal virtual object Object { - get { return this; } - } - #endregion - - #region properties - - /// - /// Defines the properties attached to this node. - /// - public NodeProperties NodeProperties { - get { - if (null == nodeProperties) { - nodeProperties = CreatePropertiesObject(); - } - return this.nodeProperties; - } - } - - [System.ComponentModel.BrowsableAttribute(false)] - public ProjectNode ProjectMgr { - get { - return this.projectMgr; - } - set { - this.projectMgr = value; - } - } - - - [System.ComponentModel.BrowsableAttribute(false)] - public HierarchyNode NextSibling { - get { - return this.nextSibling; - } - set { - this.nextSibling = value; - } - } - - public HierarchyNode FirstChild { - get { - return this.firstChild; - } - set { - this.firstChild = value; - } - } - - /// - /// Returns a sequence containing all of this node's children. - /// - public IEnumerable AllChildren { - get { - for (HierarchyNode node = this.firstChild; node != null; node = node.nextSibling) { - yield return node; - } - } - } - - /// - /// Gets or sets whether the node is currently visible in the hierarchy. - /// - /// Enables subsetting or supersetting the hierarchy view. - /// - public bool IsVisible { - get { - return flags.HasFlag(HierarchyNodeFlags.IsVisible); - } - set { - if (value) { - flags |= HierarchyNodeFlags.IsVisible; - } else { - flags &= ~HierarchyNodeFlags.IsVisible; - } - } - } - - public HierarchyNode PreviousVisibleSibling { - get { - HierarchyNode prev = null; - - if (parentNode != null) { - for (HierarchyNode child = parentNode.firstChild; child != null; child = child.nextSibling) { - if (child == this) { - break; - } - - if (child.IsVisible) { - prev = child; - } - } - } - - return prev; - } - } - - public HierarchyNode NextVisibleSibling { - get { - var next = nextSibling; - while (next != null && !next.IsVisible) { - next = next.NextSibling; - } - return next; - } - } - - public HierarchyNode FirstVisibleChild { - get { - var next = FirstChild; - while (next != null && !next.IsVisible) { - next = next.NextSibling; - } - return next; - } - } - - [System.ComponentModel.BrowsableAttribute(false)] - public HierarchyNode Parent { - get { - return this.parentNode; - } - set { - this.parentNode = value; - } - } - - - [System.ComponentModel.BrowsableAttribute(false)] - public uint ID { - get { - return this.hierarchyId; - } - internal set { - this.hierarchyId = value; - } - } - - [System.ComponentModel.BrowsableAttribute(false)] - public ProjectElement ItemNode { - get { - return itemNode; - } - set { - itemNode = value; - } - } - - [System.ComponentModel.BrowsableAttribute(false)] - public bool IsExpanded { - get { - return flags.HasFlag(HierarchyNodeFlags.IsExpanded); - } - set { - if (value) { - flags |= HierarchyNodeFlags.IsExpanded; - } else { - flags &= ~HierarchyNodeFlags.IsExpanded; - } - } - } - - public HierarchyNode PreviousSibling { - get { - if (this.parentNode == null) - return null; - HierarchyNode prev = null; - for (HierarchyNode child = this.parentNode.firstChild; child != null; child = child.nextSibling) { - if (child == this) - break; - prev = child; - } - return prev; - } - } - - /// - /// Specifies if a Node is under source control. - /// - public bool ExcludeNodeFromScc { - get { - return flags.HasFlag(HierarchyNodeFlags.ExcludeFromScc); - } - set { - if (value) { - flags |= HierarchyNodeFlags.ExcludeFromScc; - } else { - flags &= ~HierarchyNodeFlags.ExcludeFromScc; - } - } - } - - /// - /// Defines if a node a name relation to its parent node - /// - /// - public bool HasParentNodeNameRelation { - get { - return flags.HasFlag(HierarchyNodeFlags.HasParentNodeNameRelation); - } - set { - if (value) { - flags |= HierarchyNodeFlags.HasParentNodeNameRelation; - } else { - flags &= ~HierarchyNodeFlags.HasParentNodeNameRelation; - } - } - } - - #endregion - - #region ctors - - protected HierarchyNode() { - IsExpanded = true; - IsVisible = true; - } - - protected HierarchyNode(ProjectNode root, ProjectElement element) { - Utilities.ArgumentNotNull("root", root); - - this.projectMgr = root; - this.itemNode = element; - this.hierarchyId = this.projectMgr.ItemIdMap.Add(this); - IsVisible = true; - } - - /// - /// Overloaded ctor. - /// - /// - protected HierarchyNode(ProjectNode root) { - Utilities.ArgumentNotNull("root", root); - - this.projectMgr = root; - this.itemNode = new VirtualProjectElement(this.projectMgr); - this.hierarchyId = this.projectMgr.ItemIdMap.Add(this); - IsVisible = true; - } - #endregion - - #region virtual methods - /// - /// Creates an object derived from NodeProperties that will be used to expose properties - /// spacific for this object to the property browser. - /// - /// - protected virtual NodeProperties CreatePropertiesObject() { - return null; - } - - /// - /// Return an iconhandle - /// - /// - /// - public virtual object GetIconHandle(bool open) { - return null; - } - - /// - /// Removes a node from the hierarchy. - /// - /// The node to remove. - public virtual void RemoveChild(HierarchyNode node) { - Utilities.ArgumentNotNull("node", node); - - this.projectMgr.ItemIdMap.Remove(node); - - HierarchyNode last = null; - for (HierarchyNode n = this.firstChild; n != null; n = n.nextSibling) { - if (n == node) { - if (last != null) { - last.nextSibling = n.nextSibling; - } - if (n == this.firstChild) { - this.firstChild = n.nextSibling; - } - if (object.ReferenceEquals(node, this.lastChild)) { - this.lastChild = last; - } - return; - } - last = n; - } - throw new InvalidOperationException("Node not found"); - } - - /// - /// Returns an automation object representing this node - /// - /// The automation object - public virtual object GetAutomationObject() { - return new Automation.OAProjectItem(this.projectMgr.GetAutomationObject() as Automation.OAProject, this); - } - - /// - /// Returns a property object based on a property id - /// - /// the property id of the property requested - /// the property object requested - public virtual object GetProperty(int propId) { - object result = null; - switch ((__VSHPROPID)propId) { - case __VSHPROPID.VSHPROPID_Expandable: - result = (this.firstChild != null); - break; - - case __VSHPROPID.VSHPROPID_Caption: - result = this.Caption; - break; - - case __VSHPROPID.VSHPROPID_Name: - result = this.Caption; - break; - - case __VSHPROPID.VSHPROPID_ExpandByDefault: - result = false; - break; - - case __VSHPROPID.VSHPROPID_IconImgList: - result = this.ProjectMgr.ImageHandler.ImageList.Handle; - break; - - case __VSHPROPID.VSHPROPID_OpenFolderIconIndex: - case __VSHPROPID.VSHPROPID_IconIndex: - int index = this.ImageIndex; - if (index != NoImage) { - result = index; - } - break; - - case __VSHPROPID.VSHPROPID_StateIconIndex: - result = (int)this.StateIconIndex; - break; - - case __VSHPROPID.VSHPROPID_OverlayIconIndex: - result = (int)this.OverlayIconIndex; - break; - - case __VSHPROPID.VSHPROPID_IconHandle: - result = GetIconHandle(false); - break; - - case __VSHPROPID.VSHPROPID_OpenFolderIconHandle: - result = GetIconHandle(true); - break; - - case __VSHPROPID.VSHPROPID_NextVisibleSibling: - var nextVisible = NextVisibleSibling; - result = (int)((nextVisible != null) ? nextVisible.ID : VSConstants.VSITEMID_NIL); - break; - - case __VSHPROPID.VSHPROPID_NextSibling: - result = (int)((this.nextSibling != null) ? this.nextSibling.hierarchyId : VSConstants.VSITEMID_NIL); - break; - - case __VSHPROPID.VSHPROPID_IsNonMemberItem: - result = IsNonMemberItem; - break; - - case __VSHPROPID.VSHPROPID_IsHiddenItem: - result = !IsVisible; - break; - - case __VSHPROPID.VSHPROPID_IsNonSearchable: - result = !IsSearchable; - break; - - case __VSHPROPID.VSHPROPID_FirstChild: - result = (int)((this.firstChild != null) ? this.firstChild.hierarchyId : VSConstants.VSITEMID_NIL); - break; - - case __VSHPROPID.VSHPROPID_FirstVisibleChild: - var firstVisible = FirstVisibleChild; - result = (int)((firstVisible != null) ? firstVisible.hierarchyId : VSConstants.VSITEMID_NIL); - break; - - case __VSHPROPID.VSHPROPID_Parent: - if (null == this.parentNode) { - unchecked { result = new IntPtr((int)VSConstants.VSITEMID_NIL); } - } else { - result = new IntPtr((int)this.parentNode.hierarchyId); // see bug 176470 - } - break; - - case __VSHPROPID.VSHPROPID_Root: - result = Marshal.GetIUnknownForObject(this.projectMgr); - break; - - case __VSHPROPID.VSHPROPID_Expanded: - result = this.IsExpanded; - break; - - case __VSHPROPID.VSHPROPID_BrowseObject: - result = this.NodeProperties; - if (result != null) - result = new DispatchWrapper(result); - break; - - case __VSHPROPID.VSHPROPID_EditLabel: - if (this.ProjectMgr != null && !this.ProjectMgr.IsClosed && !this.ProjectMgr.IsCurrentStateASuppressCommandsMode()) { - result = GetEditLabel(); - } - break; - - case __VSHPROPID.VSHPROPID_SaveName: - //SaveName is the name shown in the Save and the Save Changes dialog boxes. - result = this.Caption; - break; - - case __VSHPROPID.VSHPROPID_ExtObject: -#if DEBUG - try { -#endif - result = GetAutomationObject(); -#if DEBUG - } catch (Exception e) { - Debug.WriteLine(String.Format("Failed to get automation object for node {1}: {0}", e, this)); - throw; - } -#endif - break; - } - - __VSHPROPID2 id2 = (__VSHPROPID2)propId; - switch (id2) { - case __VSHPROPID2.VSHPROPID_IsLinkFile: - result = IsLinkFile; - break; - - case __VSHPROPID2.VSHPROPID_NoDefaultNestedHierSorting: - return true; // We are doing the sorting ourselves through VSHPROPID_FirstChild and VSHPROPID_NextSibling - case __VSHPROPID2.VSHPROPID_CfgBrowseObjectCATID: - case __VSHPROPID2.VSHPROPID_BrowseObjectCATID: { - // If there is a browse object and it is a NodeProperties, then get it's CATID - object browseObject = this.GetProperty((int)__VSHPROPID.VSHPROPID_BrowseObject); - if (browseObject != null) { - if (browseObject is DispatchWrapper) - browseObject = ((DispatchWrapper)browseObject).WrappedObject; - result = this.ProjectMgr.GetCATIDForType(browseObject.GetType()).ToString("B"); - if (String.Equals(result as string, Guid.Empty.ToString("B"), StringComparison.Ordinal)) - result = null; - } - break; - } - case __VSHPROPID2.VSHPROPID_ExtObjectCATID: { - // If there is a extensibility object and it is a NodeProperties, then get it's CATID - object extObject = this.GetProperty((int)__VSHPROPID.VSHPROPID_ExtObject); - if (extObject != null) { - if (extObject is DispatchWrapper) - extObject = ((DispatchWrapper)extObject).WrappedObject; - result = this.ProjectMgr.GetCATIDForType(extObject.GetType()).ToString("B"); - if (String.Equals(result as string, Guid.Empty.ToString("B"), StringComparison.Ordinal)) - result = null; - } - break; - } - - } - -#if DEV11_OR_LATER - __VSHPROPID5 id5 = (__VSHPROPID5)propId; - switch (id5) { - case __VSHPROPID5.VSHPROPID_ProvisionalViewingStatus: - result = ProvisionalViewingStatus; - break; - } -#endif -#if DEBUG - if (propId != LastTracedProperty) { - string trailer = (result == null) ? "null" : result.ToString(); - LastTracedProperty = propId; // some basic filtering here... - } -#endif - return result; - } - -#if DEV11_OR_LATER - public virtual __VSPROVISIONALVIEWINGSTATUS ProvisionalViewingStatus { - get { - return __VSPROVISIONALVIEWINGSTATUS.PVS_Disabled; - } - } -#endif - - /// - /// Sets the value of a property for a given property id - /// - /// the property id of the property to be set - /// value of the property - /// S_OK if succeeded - public virtual int SetProperty(int propid, object value) { - __VSHPROPID id = (__VSHPROPID)propid; - - switch (id) { - case __VSHPROPID.VSHPROPID_Expanded: - this.IsExpanded = (bool)value; - break; - - case __VSHPROPID.VSHPROPID_EditLabel: - return SetEditLabel((string)value); - - default: - break; - } - return VSConstants.S_OK; - } - - /// - /// Get a guid property - /// - /// property id for the guid property requested - /// the requested guid - /// S_OK if succeded - public virtual int GetGuidProperty(int propid, out Guid guid) { - guid = Guid.Empty; - if (propid == (int)__VSHPROPID.VSHPROPID_TypeGuid) { - guid = this.ItemTypeGuid; - } - - if (guid.Equals(Guid.Empty)) { - return VSConstants.DISP_E_MEMBERNOTFOUND; - } - - return VSConstants.S_OK; - } - - public virtual bool CanAddFiles { - get { - return false; - } - } - - /// - /// Set a guid property. - /// - /// property id of the guid property to be set - /// the guid to be set - /// E_NOTIMPL - public virtual int SetGuidProperty(int propid, ref Guid guid) { - return VSConstants.E_NOTIMPL; - } - - /// - /// Called by the shell when a node has been renamed from the GUI - /// - /// - /// E_NOTIMPL - public virtual int SetEditLabel(string label) { - return VSConstants.E_NOTIMPL; - } - - /// - /// Called by the shell to get the node caption when the user tries to rename from the GUI - /// - /// the node cation - public virtual string GetEditLabel() { - return this.Caption; - } - - /// - /// This method is called by the interface method GetMkDocument to specify the item moniker. - /// - /// The moniker for this item - public virtual string GetMkDocument() { - return String.Empty; - } - - /// - /// Removes items from the hierarchy. Project overwrites this - /// - /// - public virtual void Remove(bool removeFromStorage) { - string documentToRemove = this.GetMkDocument(); - - // Ask Document tracker listeners if we can remove the item. - string[] filesToBeDeleted = new string[1] { documentToRemove }; - if (!String.IsNullOrWhiteSpace(documentToRemove)) { - VSQUERYREMOVEFILEFLAGS[] queryRemoveFlags = this.GetQueryRemoveFileFlags(filesToBeDeleted); - if (!this.ProjectMgr.Tracker.CanRemoveItems(filesToBeDeleted, queryRemoveFlags)) { - return; - } - } - - // Close the document if it has a manager. - DocumentManager manager = this.GetDocumentManager(); - if (manager != null) { - if (manager.Close(!removeFromStorage ? __FRAMECLOSE.FRAMECLOSE_PromptSave : __FRAMECLOSE.FRAMECLOSE_NoSave) == VSConstants.E_ABORT) { - // User cancelled operation in message box. - return; - } - } - - if (removeFromStorage) { - this.DeleteFromStorage(documentToRemove); - } - - RemoveNonDocument(removeFromStorage); - - // Close the document window if opened. - CloseDocumentWindow(this); - - RaiseOnItemRemoved(documentToRemove, filesToBeDeleted); - - // When we don't call this it behaves properly also in Solution Explorer search result set - // Notify hierarchy event listeners that items have been invalidated - //ProjectMgr.OnInvalidateItems(this); - - // Dispose the node now that is deleted. - this.Dispose(true); - } - - /// - /// Determines if the node should open with the designer by default, or if we should - /// just open with the default editor. - /// - public virtual bool DefaultOpensWithDesignView { - get { - // ASPX\ASCX files support design view but should be opened by default with - // LOGVIEWID_Primary - this is because they support design and html view which - // is a tools option setting for them. If we force designview this option - // gets bypassed. We do a similar thing for asax/asmx/xsd. By doing so, we don't force - // the designer to be invoked when double-clicking on the node - it will now go through the - // shell's standard open mechanism. - return false; - } - } - - /// - /// Returns true if the node supports a design view. - /// - public virtual bool SupportsDesignView { - get { - return false; - } - } - - /// - /// Returns true if the node represents a code behind file. - /// - public virtual bool IsCodeBehindFile { - get { - return false; - } - } - - protected virtual void RaiseOnItemRemoved(string documentToRemove, string[] filesToBeDeleted) { - if (!String.IsNullOrWhiteSpace(documentToRemove)) { - // Notify document tracker listeners that we have removed the item. - VSREMOVEFILEFLAGS[] removeFlags = this.GetRemoveFileFlags(filesToBeDeleted); - Debug.Assert(removeFlags != null, "At least an empty array should be returned for the GetRemoveFileFlags"); - this.ProjectMgr.Tracker.OnItemRemoved(documentToRemove, removeFlags[0]); - } - } - - internal void RemoveNonDocument(bool removeFromStorage) { - // Check out the project file. - if (!this.ProjectMgr.QueryEditProjectFile(false)) { - throw Marshal.GetExceptionForHR(VSConstants.OLE_E_PROMPTSAVECANCELLED); - } - - // Notify hierarchy event listeners that the file is going to be removed. - ProjectMgr.OnItemDeleted(this); - - // Remove child if any before removing from the hierarchy - for (HierarchyNode child = this.FirstChild; child != null; child = child.NextSibling) { - child.Remove(removeFromStorage); - } - - // the project node has no parentNode - if (this.parentNode != null) { - // Remove from the Hierarchy - this.parentNode.RemoveChild(this); - } - - this.itemNode.RemoveFromProjectFile(); - } - - /// - /// Returns the relational name which is defined as the first part of the caption until indexof NameRelationSeparator - /// - public virtual string GetRelationalName() { - //Get the first part of the caption - string[] partsOfParent = this.Caption.Split(new string[] { this.NameRelationSeparator }, StringSplitOptions.None); - return partsOfParent[0]; - } - - /// - /// Returns the 'extension' of the relational name - /// e.g. form1.resx returns .resx, form1.designer.cs returns .designer.cs - /// - /// The extension - public virtual string GetRelationNameExtension() { - return this.Caption.Substring(this.Caption.IndexOf(this.NameRelationSeparator, StringComparison.Ordinal)); - } - - /// - /// Close open document frame for a specific node. - /// - protected void CloseDocumentWindow(HierarchyNode node) { - Utilities.ArgumentNotNull("node", node); - - // We walk the RDT looking for all running documents attached to this hierarchy and itemid. There - // are cases where there may be two different editors (not views) open on the same document. - IEnumRunningDocuments pEnumRdt; - IVsRunningDocumentTable pRdt = this.GetService(typeof(SVsRunningDocumentTable)) as IVsRunningDocumentTable; - Utilities.CheckNotNull(pRdt); - - if (ErrorHandler.Succeeded(pRdt.GetRunningDocumentsEnum(out pEnumRdt))) { - uint[] cookie = new uint[1]; - uint fetched; - uint saveOptions = (uint)__VSSLNSAVEOPTIONS.SLNSAVEOPT_NoSave; - IVsHierarchy srpOurHier = node.projectMgr as IVsHierarchy; - - ErrorHandler.ThrowOnFailure(pEnumRdt.Reset()); - while (VSConstants.S_OK == pEnumRdt.Next(1, cookie, out fetched)) { - // Note we can pass NULL for all parameters we don't care about - uint empty; - string emptyStr; - IntPtr ppunkDocData; - IVsHierarchy srpHier; - uint itemid = VSConstants.VSITEMID_NIL; - - ErrorHandler.ThrowOnFailure(pRdt.GetDocumentInfo( - cookie[0], - out empty, - out empty, - out empty, - out emptyStr, - out srpHier, - out itemid, - out ppunkDocData)); - - // Is this one of our documents? - if (Utilities.IsSameComObject(srpOurHier, srpHier) && itemid == node.ID) { - IVsSolution soln = GetService(typeof(SVsSolution)) as IVsSolution; - ErrorHandler.ThrowOnFailure(soln.CloseSolutionElement(saveOptions, srpOurHier, cookie[0])); - } - if (ppunkDocData != IntPtr.Zero) - Marshal.Release(ppunkDocData); - - } - } - } - - /// - /// Redraws the state icon if the node is not excluded from source control. - /// - protected internal virtual void UpdateSccStateIcons() { - if (!this.ExcludeNodeFromScc) { - ProjectMgr.ReDrawNode(this, UIHierarchyElement.SccState); - } - } - - /// - /// To be overwritten by descendants. - /// - protected internal virtual int SetEditLabel(string label, string relativePath) { - throw new NotImplementedException(); - } - - /// - /// Called by the drag and drop implementation to ask the node - /// which is being dragged/droped over which nodes should - /// process the operation. - /// This allows for dragging to a node that cannot contain - /// items to let its parent accept the drop - /// - /// HierarchyNode that accept the drop handling - protected internal virtual HierarchyNode GetDragTargetHandlerNode() { - return this; - } - - /// - /// Add a new Folder to the project hierarchy. - /// - /// S_OK if succeeded, otherwise an error - protected virtual int AddNewFolder() { - // Check out the project file. - if (!this.ProjectMgr.QueryEditProjectFile(false)) { - throw Marshal.GetExceptionForHR(VSConstants.OLE_E_PROMPTSAVECANCELLED); - } - - try { - // Generate a new folder name - string newFolderName; - ErrorHandler.ThrowOnFailure(this.projectMgr.GenerateUniqueItemName(this.hierarchyId, String.Empty, String.Empty, out newFolderName)); - - // create the folder node, this will add it to MS build but we won't have the directory created yet. - var folderNode = ProjectMgr.CreateFolderNode(Path.Combine(FullPathToChildren, newFolderName)); - folderNode.IsBeingCreated = true; - AddChild(folderNode); - - folderNode.ExpandItem(EXPANDFLAGS.EXPF_SelectItem); - IVsUIShell shell = this.projectMgr.Site.GetService(typeof(SVsUIShell)) as IVsUIShell; - - // let the user rename the folder which will create the directory when finished - int hr; - object dummy = null; - Guid cmdGroup = VsMenus.guidStandardCommandSet97; - if (ErrorHandler.Failed(hr = shell.PostExecCommand(ref cmdGroup, (uint)VsCommands.Rename, 0, ref dummy))) { - // make sure the directory is created... - folderNode.OnCancelLabelEdit(); - } - } catch (COMException e) { - Trace.WriteLine("Exception : " + e.Message); - return e.ErrorCode; - } - - return VSConstants.S_OK; - } - - protected virtual int AddItemToHierarchy(HierarchyAddType addType) { - IVsAddProjectItemDlg addItemDialog; - - string strFilter = String.Empty; - int iDontShowAgain; - uint uiFlags; - IVsProject3 project = (IVsProject3)this.projectMgr; - - string strBrowseLocations = this.projectMgr.ProjectHome; - - System.Guid projectGuid = this.projectMgr.ProjectGuid; - - addItemDialog = this.GetService(typeof(IVsAddProjectItemDlg)) as IVsAddProjectItemDlg; - - if (addType == HierarchyAddType.AddNewItem) - uiFlags = (uint)(__VSADDITEMFLAGS.VSADDITEM_AddNewItems | __VSADDITEMFLAGS.VSADDITEM_SuggestTemplateName | __VSADDITEMFLAGS.VSADDITEM_AllowHiddenTreeView); - else - uiFlags = (uint)(__VSADDITEMFLAGS.VSADDITEM_AddExistingItems | __VSADDITEMFLAGS.VSADDITEM_ProjectHandlesLinks | __VSADDITEMFLAGS.VSADDITEM_AllowMultiSelect | __VSADDITEMFLAGS.VSADDITEM_AllowStickyFilter); - - return addItemDialog.AddProjectItemDlg(this.hierarchyId, ref projectGuid, project, uiFlags, null, null, ref strBrowseLocations, ref strFilter, out iDontShowAgain); /*&fDontShowAgain*/ - } - - /// - /// Overwritten in subclasses - /// - protected virtual void DoDefaultAction() { - } - - /// - /// Handles the exclude from project command. - /// - /// - internal virtual int ExcludeFromProject() { - Debug.Assert(this.ProjectMgr != null, "The project item " + this.ToString() + " has not been initialised correctly. It has a null ProjectMgr"); - this.Remove(false); - return VSConstants.S_OK; - } - - /// - /// Handles the exclude from project command potentially displaying - /// a progress bar if the operation can take a long time. - /// - /// - internal virtual int ExcludeFromProjectWithProgress() { - - int hr = ExcludeFromProject(); - if (ErrorHandler.Succeeded(hr)) { - // https://pytools.codeplex.com/workitem/1996 - // Mark the previous sibling or direct parent as the active item - IVsUIHierarchyWindow2 windows = UIHierarchyUtilities.GetUIHierarchyWindow( - ProjectMgr.Site, - new Guid(ToolWindowGuids80.SolutionExplorer)) as IVsUIHierarchyWindow2; - windows.ExpandItem( - ProjectMgr, - PreviousVisibleSibling != null ? - PreviousVisibleSibling.ID : - Parent.ID, - EXPANDFLAGS.EXPF_SelectItem - ); - } - return hr; - } - - /// - /// Handles the include in project command. - /// - /// - internal virtual int IncludeInProject(bool includeChildren) { - return VSConstants.E_FAIL; - } - - /// - /// Handles the include in project command showing a progress bar - /// if the operation can potentially take a long time. - /// - internal virtual int IncludeInProjectWithProgress(bool includeChildren) { - return IncludeInProject(includeChildren); - } - - /// - /// Handles the Show in Designer command. - /// - /// - protected virtual int ShowInDesigner(IList selectedNodes) { - return (int)OleConstants.OLECMDERR_E_NOTSUPPORTED; - } - - /// - /// Prepares a selected node for clipboard. - /// It takes the the project reference string of this item and adds it to a stringbuilder. - /// - /// A stringbuilder. - /// This method has to be public since seleceted nodes will call it. - protected internal virtual string PrepareSelectedNodesForClipBoard() { - Debug.Assert(this.ProjectMgr != null, " No project mananager available for this node " + ToString()); - Debug.Assert(this.ProjectMgr.ItemsDraggedOrCutOrCopied != null, " The itemsdragged list should have been initialized prior calling this method"); - if (this.ProjectMgr == null || this.ProjectMgr.ItemsDraggedOrCutOrCopied == null) { - return null; - } - - if (this.hierarchyId == VSConstants.VSITEMID_ROOT) { - if (this.ProjectMgr.ItemsDraggedOrCutOrCopied != null) { - this.ProjectMgr.ItemsDraggedOrCutOrCopied.Clear();// abort - } - return null; - } - - if (this.ProjectMgr.ItemsDraggedOrCutOrCopied != null) { - this.ProjectMgr.ItemsDraggedOrCutOrCopied.Add(this); - } - - string projref = String.Empty; - IVsSolution solution = this.GetService(typeof(IVsSolution)) as IVsSolution; - if (solution != null) { - ErrorHandler.ThrowOnFailure(solution.GetProjrefOfItem(this.ProjectMgr, this.hierarchyId, out projref)); - if (String.IsNullOrEmpty(projref)) { - if (this.ProjectMgr.ItemsDraggedOrCutOrCopied != null) { - this.ProjectMgr.ItemsDraggedOrCutOrCopied.Clear();// abort - } - return null; - } - } - - // Append the projectref and a null terminator to the string builder - - return projref + '\0'; - } - - /// - /// Returns the Cannonical Name - /// - /// Cannonical Name - internal virtual string GetCanonicalName() { - return this.GetMkDocument(); - } - - /// - /// Factory method for the Document Manager object - /// - /// null object, since a hierarchy node does not know its kind of document - /// Must be overriden by derived node classes if a document manager is needed - protected internal virtual DocumentManager GetDocumentManager() { - return null; - } - - /// - /// Displays the context menu. - /// - /// list of selected nodes. - /// contains the location (x,y) at which to show the menu. - protected virtual int DisplayContextMenu(IList selectedNodes, IntPtr pointerToVariant) { - if (selectedNodes == null || selectedNodes.Count == 0 || pointerToVariant == IntPtr.Zero) { - return NativeMethods.OLECMDERR_E_NOTSUPPORTED; - } - - int projectsSelected = 0; - int menuId = 0; - Guid menuGroup = Guid.Empty; - - bool groupIsConsistent = false; - bool cmdidIsConsistent = false; - - foreach (HierarchyNode node in selectedNodes) { - var cmdId = node.MenuCommandId; - var grpId = node.MenuGroupId; - if (cmdId == VsMenus.IDM_VS_CTXT_PROJNODE) { - projectsSelected += 1; - } - - // We check here whether we have a multiple selection of - // nodes of differing type. - if (menuId == 0) { - // First time through or single node case - menuId = cmdId; - cmdidIsConsistent = true; - menuGroup = grpId; - groupIsConsistent = true; - } else { - if (menuGroup != grpId) { - // We have very different node types. If a project is in - // the selection, we will eventually display its context - // menu. More likely, we will display nothing. - groupIsConsistent = false; - } else if (menuId != node.MenuCommandId) { - // We have different node types. - cmdidIsConsistent = false; - } - } - } - - if (groupIsConsistent && !cmdidIsConsistent) { - // The selected items agree on a menu group, but not the ID. - if (projectsSelected == 0) { - // We will use IDM_VS_CTXT_XPROJ_MULTIITEM (0x0419) with - // whatever group they agreed on. This allows people to create - // multi-selection context menus in custom groups. - menuId = VsMenus.IDM_VS_CTXT_XPROJ_MULTIITEM; - cmdidIsConsistent = true; - } else { - // One or more projects were selected, so we will use - // IDM_VS_CTXT_XPROJ_PROJITEM (0x0417) with whatever group - // they agreed on. - menuId = VsMenus.IDM_VS_CTXT_XPROJ_PROJITEM; - cmdidIsConsistent = true; - } - } - - if (!groupIsConsistent) { - // The selected items could not agree on a group. If projects - // are selected, display the project context menu. Otherwise, - // show nothing. - if (projectsSelected > 0) { - menuId = projectsSelected == 1 ? - VsMenus.IDM_VS_CTXT_PROJNODE : - VsMenus.IDM_VS_CTXT_XPROJ_PROJITEM; - menuGroup = VsMenus.guidSHLMainMenu; - groupIsConsistent = true; - cmdidIsConsistent = true; - } - } - - if (groupIsConsistent && cmdidIsConsistent) { - object variant = Marshal.GetObjectForNativeVariant(pointerToVariant); - UInt32 pointsAsUint = (UInt32)variant; - short x = (short)(pointsAsUint & 0x0000ffff); - short y = (short)((pointsAsUint & 0xffff0000) / 0x10000); - - POINTS points = new POINTS(); - points.x = x; - points.y = y; - return ShowContextMenu(menuId, menuGroup, points); - } else { - return VSConstants.S_OK; - } - } - - /// - /// Shows the specified context menu at a specified location. - /// - /// The context menu ID. - /// The GUID of the menu group. - /// The location at which to show the menu. - protected virtual int ShowContextMenu(int menuId, Guid menuGroup, POINTS points) { - IVsUIShell shell = this.projectMgr.Site.GetService(typeof(SVsUIShell)) as IVsUIShell; - - Debug.Assert(shell != null, "Could not get the UI shell from the project"); - if (shell == null) { - return VSConstants.E_FAIL; - } - POINTS[] pnts = new POINTS[1]; - pnts[0].x = points.x; - pnts[0].y = points.y; - return shell.ShowContextMenu(0, ref menuGroup, menuId, pnts, (Microsoft.VisualStudio.OLE.Interop.IOleCommandTarget)ProjectMgr); - } - - #region initiation of command execution - /// - /// Handles command execution. - /// - /// Unique identifier of the command group - /// The command to be executed. - /// Values describe how the object should execute the command. - /// Pointer to a VARIANTARG structure containing input arguments. Can be NULL - /// VARIANTARG structure to receive command output. Can be NULL. - /// If the method succeeds, it returns S_OK. If it fails, it returns an error code. - internal virtual int ExecCommandOnNode(Guid cmdGroup, uint cmd, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) { - if (InvalidProject()) { - return (int)OleConstants.OLECMDERR_E_NOTSUPPORTED; - } - - if (cmdGroup == Guid.Empty) { - return (int)OleConstants.OLECMDERR_E_NOTSUPPORTED; - } else if (cmdGroup == VsMenus.guidVsUIHierarchyWindowCmds) { - switch (cmd) { - case (uint)VSConstants.VsUIHierarchyWindowCmdIds.UIHWCMDID_DoubleClick: - case (uint)VSConstants.VsUIHierarchyWindowCmdIds.UIHWCMDID_EnterKey: - this.DoDefaultAction(); - return VSConstants.S_OK; - case (uint)VSConstants.VsUIHierarchyWindowCmdIds.UIHWCMDID_CancelLabelEdit: - this.OnCancelLabelEdit(); - return VSConstants.S_OK; - } - return (int)OleConstants.OLECMDERR_E_NOTSUPPORTED; - } else if (cmdGroup == VsMenus.guidStandardCommandSet97) { - HierarchyNode nodeToAddTo = this.GetDragTargetHandlerNode(); - switch ((VsCommands)cmd) { - case VsCommands.AddNewItem: - return nodeToAddTo.AddItemToHierarchy(HierarchyAddType.AddNewItem); - - case VsCommands.AddExistingItem: - return nodeToAddTo.AddItemToHierarchy(HierarchyAddType.AddExistingItem); - - case VsCommands.NewFolder: - return nodeToAddTo.AddNewFolder(); - - case VsCommands.Paste: - return this.ProjectMgr.PasteFromClipboard(this); - } - - } else if (cmdGroup == VsMenus.guidStandardCommandSet2K) { - switch ((VsCommands2K)cmd) { - case VsCommands2K.EXCLUDEFROMPROJECT: - return this.ExcludeFromProjectWithProgress(); - case VsCommands2K.INCLUDEINPROJECT: - return this.IncludeInProjectWithProgress(true); - } - } else if (cmdGroup == ProjectMgr.SharedCommandGuid) { - switch ((SharedCommands)cmd) { - case SharedCommands.OpenCommandPromptHere: - var psi = new ProcessStartInfo( - Path.Combine( - Environment.SystemDirectory, - "cmd.exe" - ) - ); - psi.WorkingDirectory = FullPathToChildren; - Process.Start(psi); - return VSConstants.S_OK; - case SharedCommands.CopyFullPath: - System.Windows.Clipboard.SetText(Url); - return VSConstants.S_OK; - } - } - - return (int)OleConstants.OLECMDERR_E_NOTSUPPORTED; - } - - #endregion - - #region query command handling - - - /// - /// Handles command status on a node. Should be overridden by descendant nodes. If a command cannot be handled then the base should be called. - /// - /// A unique identifier of the command group. The pguidCmdGroup parameter can be NULL to specify the standard group. - /// The command to query status for. - /// Pointer to an OLECMDTEXT structure in which to return the name and/or status information of a single command. Can be NULL to indicate that the caller does not require this information. - /// An out parameter specifying the QueryStatusResult of the command. - /// If the method succeeds, it returns S_OK. If it fails, it returns an error code. - internal virtual int QueryStatusOnNode(Guid cmdGroup, uint cmd, IntPtr pCmdText, ref QueryStatusResult result) { - if (cmdGroup == VsMenus.guidStandardCommandSet97) { - switch ((VsCommands)cmd) { - case VsCommands.AddNewItem: - case VsCommands.AddExistingItem: - if (!IsNonMemberItem) { - result |= QueryStatusResult.SUPPORTED | QueryStatusResult.ENABLED; - return VSConstants.S_OK; - } - break; - } - } else if (cmdGroup == VsMenus.guidStandardCommandSet2K) { - // http://social.msdn.microsoft.com/Forums/en/vsx/thread/f348aaed-cdcc-4709-9118-c0fd8b9e154d - switch ((VsCommands2K)cmd) { - case VsCommands2K.SHOWALLFILES: - if (ProjectMgr.CanShowAllFiles) { - if (ProjectMgr.IsShowingAllFiles) { - result |= QueryStatusResult.SUPPORTED | QueryStatusResult.ENABLED | QueryStatusResult.LATCHED; - } else { - result |= QueryStatusResult.SUPPORTED | QueryStatusResult.ENABLED; - } - } else { - result |= QueryStatusResult.NOTSUPPORTED | QueryStatusResult.INVISIBLE; - } - return VSConstants.S_OK; - } - } else if (cmdGroup == ProjectMgr.SharedCommandGuid) { - switch ((SharedCommands)cmd) { - case SharedCommands.OpenCommandPromptHere: - if (CanOpenCommandPrompt) { - result |= QueryStatusResult.SUPPORTED | QueryStatusResult.ENABLED; - return VSConstants.S_OK; - } - break; - case SharedCommands.CopyFullPath: - if (this is IDiskBasedNode || this is ProjectNode) { - result |= QueryStatusResult.SUPPORTED | QueryStatusResult.ENABLED; - return VSConstants.S_OK; - } - break; - } - } - - return (int)OleConstants.OLECMDERR_E_NOTSUPPORTED; - } - - #endregion - internal virtual bool CanDeleteItem(__VSDELETEITEMOPERATION deleteOperation) { - return this.ProjectMgr.CanProjectDeleteItems; - } - - /// - /// Overwrite this method to tell that you support the default icon for this node. - /// - /// - protected virtual bool CanShowDefaultIcon() { - return false; - } - - /// - /// Performs save as operation for an item after the save as dialog has been processed. - /// - /// A pointer to the rdt - /// The newName of the item - /// - internal virtual int AfterSaveItemAs(IntPtr docData, string newName) { - throw new NotImplementedException(); - } - - /// - /// Invoked when the node receives UIHWCMDID_CancelLabelEdit hierarchy window command, which occurs - /// when user cancels the label editing operation. - /// - protected virtual void OnCancelLabelEdit() { - } - - /// - /// The method that does the cleanup. - /// - /// Is the Dispose called by some internal member, or it is called by from GC. - protected virtual void Dispose(bool disposing) { - } - - /// - /// Sets the VSQUERYADDFILEFLAGS that will be used to call the IVsTrackProjectDocumentsEvents2 OnQueryAddFiles - /// - /// The files to which an array of VSADDFILEFLAGS has to be specified. - /// - protected internal virtual VSQUERYADDFILEFLAGS[] GetQueryAddFileFlags(string[] files) { - if (files == null || files.Length == 0) { - return new VSQUERYADDFILEFLAGS[1] { VSQUERYADDFILEFLAGS.VSQUERYADDFILEFLAGS_NoFlags }; - } - - VSQUERYADDFILEFLAGS[] queryAddFileFlags = new VSQUERYADDFILEFLAGS[files.Length]; - - for (int i = 0; i < files.Length; i++) { - queryAddFileFlags[i] = VSQUERYADDFILEFLAGS.VSQUERYADDFILEFLAGS_NoFlags; - } - - return queryAddFileFlags; - } - - /// - /// Sets the VSREMOVEFILEFLAGS that will be used to call the IVsTrackProjectDocumentsEvents2 OnRemoveFiles - /// - /// The files to which an array of VSREMOVEFILEFLAGS has to be specified. - /// - protected internal virtual VSREMOVEFILEFLAGS[] GetRemoveFileFlags(string[] files) { - if (files == null || files.Length == 0) { - return new VSREMOVEFILEFLAGS[1] { VSREMOVEFILEFLAGS.VSREMOVEFILEFLAGS_NoFlags }; - } - - VSREMOVEFILEFLAGS[] removeFileFlags = new VSREMOVEFILEFLAGS[files.Length]; - - for (int i = 0; i < files.Length; i++) { - removeFileFlags[i] = VSREMOVEFILEFLAGS.VSREMOVEFILEFLAGS_NoFlags; - } - - return removeFileFlags; - } - - /// - /// Sets the VSQUERYREMOVEFILEFLAGS that will be used to call the IVsTrackProjectDocumentsEvents2 OnQueryRemoveFiles - /// - /// The files to which an array of VSQUERYREMOVEFILEFLAGS has to be specified. - /// - protected internal virtual VSQUERYREMOVEFILEFLAGS[] GetQueryRemoveFileFlags(string[] files) { - if (files == null || files.Length == 0) { - return new VSQUERYREMOVEFILEFLAGS[1] { VSQUERYREMOVEFILEFLAGS.VSQUERYREMOVEFILEFLAGS_NoFlags }; - } - - VSQUERYREMOVEFILEFLAGS[] queryRemoveFileFlags = new VSQUERYREMOVEFILEFLAGS[files.Length]; - - for (int i = 0; i < files.Length; i++) { - queryRemoveFileFlags[i] = VSQUERYREMOVEFILEFLAGS.VSQUERYREMOVEFILEFLAGS_NoFlags; - } - - return queryRemoveFileFlags; - } - - /// - /// This method should be overridden to provide the list of files and associated flags for source control. - /// - /// The list of files to be placed under source control. - /// The flags that are associated to the files. - protected internal virtual void GetSccFiles(IList files, IList flags) { - if (this.ExcludeNodeFromScc || this.IsNonMemberItem) { - return; - } - Utilities.ArgumentNotNull("files", files); - Utilities.ArgumentNotNull("flags", flags); - - files.Add(this.GetMkDocument()); - - tagVsSccFilesFlags flagsToAdd = (this.firstChild != null && (this.firstChild is DependentFileNode)) ? tagVsSccFilesFlags.SFF_HasSpecialFiles : tagVsSccFilesFlags.SFF_NoFlags; - - flags.Add(flagsToAdd); - } - - /// - /// This method should be overridden to provide the list of special files and associated flags for source control. - /// - /// One of the file associated to the node. - /// The list of files to be placed under source control. - /// The flags that are associated to the files. - protected internal virtual void GetSccSpecialFiles(string sccFile, IList files, IList flags) { - if (this.ExcludeNodeFromScc) { - return; - } - - Utilities.ArgumentNotNull("files", files); - Utilities.ArgumentNotNull("flags", flags); - } - - /// - /// Delete the item corresponding to the specified path from storage. - /// - /// Url of the item to delete - internal protected virtual void DeleteFromStorage(string path) { - } - - /// - /// Determines whether a file change should be ignored or not. - /// - /// Flag indicating whether or not to ignore changes (true to ignore changes). - protected internal virtual void IgnoreItemFileChanges(bool ignoreFlag) { - } - - /// - /// Called to determine whether a project item is reloadable. - /// - /// True if the project item is reloadable. - protected internal virtual bool IsItemReloadable() { - return true; - } - - /// - /// Reloads an item. - /// - /// Reserved parameter defined at the IVsPersistHierarchyItem2::ReloadItem parameter. - protected internal virtual void ReloadItem(uint reserved) { - - } - - protected internal virtual void ShowDeleteMessage(IList nodes, __VSDELETEITEMOPERATION action, out bool cancel, out bool useStandardDialog) { - useStandardDialog = true; - cancel = true; - } - - #endregion - - #region public methods - - /// - /// Clears the cached node properties so that it will be recreated on the next request. - /// - public void ResetNodeProperties() { - nodeProperties = null; - } - - public void ExpandItem(EXPANDFLAGS flags) { - if (ProjectMgr == null || ProjectMgr.Site == null) { - return; - } - ProjectMgr.AssertHasParentHierarchy(); - IVsUIHierarchyWindow2 windows = UIHierarchyUtilities.GetUIHierarchyWindow( - ProjectMgr.Site, - new Guid(ToolWindowGuids80.SolutionExplorer)) as IVsUIHierarchyWindow2; - - if (windows == null) { - return; - } - - ErrorHandler.ThrowOnFailure(windows.ExpandItem(ProjectMgr.GetOuterInterface(), ID, flags)); - } - - public __VSHIERARCHYITEMSTATE GetItemState(__VSHIERARCHYITEMSTATE mask) { - if (ProjectMgr == null || ProjectMgr.Site == null || ProjectMgr.ParentHierarchy == null) { - return 0; - } - - IVsUIHierarchyWindow2 windows = UIHierarchyUtilities.GetUIHierarchyWindow( - ProjectMgr.Site, - new Guid(ToolWindowGuids80.SolutionExplorer)) as IVsUIHierarchyWindow2; - - if (windows == null) { - return 0; - } - - uint state; - if (ErrorHandler.Succeeded(windows.GetItemState(ProjectMgr.GetOuterInterface(), - ID, - (uint)mask, - out state))) { - return (__VSHIERARCHYITEMSTATE)state; - } - return 0; - } - - public bool GetIsExpanded() { - return (uint)GetItemState(__VSHIERARCHYITEMSTATE.HIS_Expanded) != 0; - } - - /// - /// AddChild - add a node, sorted in the right location. - /// - /// The node to add. - public virtual void AddChild(HierarchyNode node) { - Utilities.ArgumentNotNull("node", node); - - Debug.Assert(ProjectMgr.ItemIdMap[node.hierarchyId] == null || ProjectMgr.ItemIdMap[node.hierarchyId] == node); - - HierarchyNode previous = null; - HierarchyNode previousVisible = null; - if (this.lastChild != null && this.ProjectMgr.CompareNodes(node, this.lastChild) < 0) { - // we can add the node at the end of the list quickly: - previous = this.lastChild; - previous.nextSibling = node; - if (previous.IsVisible) { - previousVisible = previous; - } - - this.lastChild = node; - node.nextSibling = null; - } else { - // merge node into the list: - for (HierarchyNode n = this.firstChild; n != null; n = n.nextSibling) { - if (this.ProjectMgr.CompareNodes(node, n) > 0) - break; - previous = n; - if (previous.IsVisible) { - previousVisible = previous; - } - } - // insert "node" after "previous". - if (previous != null) { - node.nextSibling = previous.nextSibling; - previous.nextSibling = node; - } else { - node.nextSibling = this.firstChild; - this.firstChild = node; - } - if (node.nextSibling == null) { - this.lastChild = node; - } - } - - node.parentNode = this; - ProjectMgr.OnItemAdded(this, node, previousVisible); -#if DEV10 - // Dev10 won't check the IsHiddenItem flag when we add an item, and it'll just - // make it visible no matter what. So we turn around and invalidate our parent - // so it'll rescan the children items and see that we're not visible. - if (!node.IsVisible) - { - if (previous != null) - { - ProjectMgr.OnPropertyChanged(previous, (int)__VSHPROPID.VSHPROPID_NextVisibleSibling, 0); - } - else - { - ProjectMgr.OnPropertyChanged(this, (int)__VSHPROPID.VSHPROPID_FirstVisibleChild, 0); - } - } -#endif - } - - public object GetService(Type type) { - Utilities.ArgumentNotNull("type", type); - - if (this.projectMgr == null || this.projectMgr.Site == null) - return null; - return this.projectMgr.Site.GetService(type); - } - - - #endregion - - #region IDisposable - /// - /// The IDispose interface Dispose method for disposing the object determinastically. - /// - public void Dispose() { - this.Dispose(true); - GC.SuppressFinalize(this); - } - - #endregion - - public virtual void Close() { - DocumentManager manager = this.GetDocumentManager(); - try { - if (manager != null) { - manager.Close(__FRAMECLOSE.FRAMECLOSE_PromptSave); - } - } catch { - } finally { - this.Dispose(true); - } - } - - internal uint HierarchyId { - get { - return hierarchyId; - } - } - - #region helper methods - - /// - /// Searches the immediate children of this node for a node which matches the specified predicate. - /// - internal HierarchyNode FindImmediateChild(Func predicate) { - for (HierarchyNode child = this.firstChild; child != null; child = child.NextSibling) { - if (predicate(child)) { - return child; - } - } - return null; - } - - /// - /// Searches the immediate children of this node for a file who's filename (w/o path) matches - /// the requested name. - /// - internal HierarchyNode FindImmediateChildByName(string name) { - Debug.Assert(!String.IsNullOrEmpty(GetMkDocument())); - - for (HierarchyNode child = this.firstChild; child != null; child = child.NextSibling) { - string filename = CommonUtils.GetFileOrDirectoryName(child.ItemNode.GetMetadata(ProjectFileConstants.Include)); - - if (String.Equals(filename, name, StringComparison.OrdinalIgnoreCase)) { - return child; - } - } - return null; - } - - /// - /// Recursively find all nodes of type T - /// - /// The type of hierachy node being serched for - /// A list of nodes of type T - internal void FindNodesOfType(List nodes) - where T : HierarchyNode { - for (HierarchyNode n = this.FirstChild; n != null; n = n.NextSibling) { - T nodeAsT = n as T; - if (nodeAsT != null) { - nodes.Add(nodeAsT); - } - - n.FindNodesOfType(nodes); - } - } - - /// - /// Recursively find all nodes of type T - /// - /// The type of hierachy node being serched for - /// A list of nodes of type T - internal IEnumerable EnumNodesOfType() - where T : HierarchyNode { - for (HierarchyNode n = this.FirstChild; n != null; n = n.NextSibling) { - T nodeAsT = n as T; - if (nodeAsT != null) { - yield return nodeAsT; - } - - foreach (var node in n.EnumNodesOfType()) { - yield return node; - } - } - } - - #endregion - - private bool InvalidProject() { - return this.projectMgr == null || this.projectMgr.IsClosed; - } - - #region nested types - /// - /// DropEffect as defined in oleidl.h - /// - internal enum DropEffect { - None, - Copy = 1, - Move = 2, - Link = 4 - }; - #endregion - - #region IOleServiceProvider - - int IOleServiceProvider.QueryService(ref Guid guidService, ref Guid riid, out IntPtr ppvObject) { - object obj; - int hr = QueryService(ref guidService, out obj); - if (ErrorHandler.Succeeded(hr)) { - if (riid.Equals(NativeMethods.IID_IUnknown)) { - ppvObject = Marshal.GetIUnknownForObject(obj); - return VSConstants.S_OK; - } - - IntPtr pUnk = IntPtr.Zero; - try { - pUnk = Marshal.GetIUnknownForObject(obj); - return Marshal.QueryInterface(pUnk, ref riid, out ppvObject); - } finally { - if (pUnk != IntPtr.Zero) { - Marshal.Release(pUnk); - } - } - } - - ppvObject = IntPtr.Zero; - return hr; - } - - /// - /// Provides services for this hierarchy node. These services are proffered to consumers - /// via IVsProject.GetItemContext. When a service provider is requested we hand out - /// the hierarchy node which implements IServiceProvider directly. Nodes can override - /// this function to provide the underlying object which implements the service. - /// - /// By default we support handing out the parent project when IVsHierarchy is requested. - /// Project nodes support handing their own automation object out, and other services - /// such as the Xaml designer context type can also be provided. - /// - public virtual int QueryService(ref Guid guidService, out object result) { - if (guidService == typeof(IVsHierarchy).GUID) { - result = ProjectMgr; - return VSConstants.S_OK; - } - - result = null; - return VSConstants.E_FAIL; - } - - #endregion - } -} diff --git a/Microsoft.VisualStudio.Project/HierarchyNodeFlags.cs b/Microsoft.VisualStudio.Project/HierarchyNodeFlags.cs deleted file mode 100644 index 856284f7..00000000 --- a/Microsoft.VisualStudio.Project/HierarchyNodeFlags.cs +++ /dev/null @@ -1,31 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; - -namespace Microsoft.VisualStudioTools.Project { - /// - /// Represents various boolean states for the HiearchyNode - /// - [Flags] - enum HierarchyNodeFlags { - None, - ExcludeFromScc = 0x01, - IsExpanded = 0x02, - HasParentNodeNameRelation = 0x04, - IsVisible = 0x08 - } -} diff --git a/Microsoft.VisualStudio.Project/IDEBuildLogger.cs b/Microsoft.VisualStudio.Project/IDEBuildLogger.cs deleted file mode 100644 index 303c32f4..00000000 --- a/Microsoft.VisualStudio.Project/IDEBuildLogger.cs +++ /dev/null @@ -1,680 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Collections.Concurrent; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Globalization; -using System.Text; -using System.Threading; -using System.Windows.Forms.Design; -using System.Windows.Threading; -using Microsoft.Build.Framework; -using Microsoft.Build.Utilities; -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.Settings; -using Microsoft.VisualStudio.Shell; -using Microsoft.VisualStudio.Shell.Interop; -using Microsoft.VisualStudio.Shell.Settings; -using Microsoft.Win32; -using IOleServiceProvider = Microsoft.VisualStudio.OLE.Interop.IServiceProvider; -using Microsoft.VisualStudio.Package; -using Microsoft.VisualStudio.TextManager.Interop; -using System.IO; - -namespace Microsoft.VisualStudioTools.Project { - /// - /// This class implements an MSBuild logger that output events to VS outputwindow and tasklist. - /// - internal class IDEBuildLogger : Logger, IDisposable { - #region fields - - private const string GeneralCollection = @"General"; - private const string BuildVerbosityProperty = "MSBuildLoggerVerbosity"; - - private int currentIndent; - private IVsOutputWindowPane outputWindowPane; - private string errorString = SR.GetString(SR.Error); - private string warningString = SR.GetString(SR.Warning); - private TaskProvider taskProvider; - private IVsHierarchy hierarchy; - private IServiceProvider serviceProvider; - private Dispatcher dispatcher; - private bool haveCachedVerbosity = false; - - // Queues to manage Tasks and Error output plus message logging - private ConcurrentQueue> taskQueue; - private ConcurrentQueue outputQueue; - - #endregion - - #region properties - - public IServiceProvider ServiceProvider { - get { return this.serviceProvider; } - } - - public string WarningString { - get { return this.warningString; } - set { this.warningString = value; } - } - - public string ErrorString { - get { return this.errorString; } - set { this.errorString = value; } - } - - /// - /// When the build is not a "design time" (background or secondary) build this is True - /// - /// - /// The only known way to detect an interactive build is to check this.outputWindowPane for null. - /// - protected bool InteractiveBuild { - get { return this.outputWindowPane != null; } - } - - /// - /// Set to null to avoid writing to the output window - /// - internal IVsOutputWindowPane OutputWindowPane { - get { return this.outputWindowPane; } - set { this.outputWindowPane = value; } - } - - #endregion - - #region ctors - - /// - /// Constructor. Inititialize member data. - /// - public IDEBuildLogger(IVsOutputWindowPane output, TaskProvider taskProvider, IVsHierarchy hierarchy) { - UIThread.MustBeCalledFromUIThread(); - - Utilities.ArgumentNotNull("taskProvider", taskProvider); - Utilities.ArgumentNotNull("hierarchy", hierarchy); - - Trace.WriteLineIf(Thread.CurrentThread.GetApartmentState() != ApartmentState.STA, "WARNING: IDEBuildLogger constructor running on the wrong thread."); - - IOleServiceProvider site; - Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(hierarchy.GetSite(out site)); - - this.taskProvider = taskProvider; - this.outputWindowPane = output; - this.hierarchy = hierarchy; - this.serviceProvider = new ServiceProvider(site); - this.dispatcher = Dispatcher.CurrentDispatcher; - } - - #endregion - - #region IDisposable - - public void Dispose() { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected virtual void Dispose(bool disposing) { - if (disposing) { - var sp = this.serviceProvider as ServiceProvider; - this.serviceProvider = null; - if (sp != null) { - sp.Dispose(); - } - } - } - - #endregion - - #region overridden methods - - /// - /// Overridden from the Logger class. - /// - public override void Initialize(IEventSource eventSource) { - Utilities.ArgumentNotNull("eventSource", eventSource); - - this.taskQueue = new ConcurrentQueue>(); - this.outputQueue = new ConcurrentQueue(); - - eventSource.BuildStarted += new BuildStartedEventHandler(BuildStartedHandler); - eventSource.BuildFinished += new BuildFinishedEventHandler(BuildFinishedHandler); - eventSource.ProjectStarted += new ProjectStartedEventHandler(ProjectStartedHandler); - eventSource.ProjectFinished += new ProjectFinishedEventHandler(ProjectFinishedHandler); - eventSource.TargetStarted += new TargetStartedEventHandler(TargetStartedHandler); - eventSource.TargetFinished += new TargetFinishedEventHandler(TargetFinishedHandler); - eventSource.TaskStarted += new TaskStartedEventHandler(TaskStartedHandler); - eventSource.TaskFinished += new TaskFinishedEventHandler(TaskFinishedHandler); - eventSource.CustomEventRaised += new CustomBuildEventHandler(CustomHandler); - eventSource.ErrorRaised += new BuildErrorEventHandler(ErrorRaisedHandler); - eventSource.WarningRaised += new BuildWarningEventHandler(WarningHandler); - eventSource.MessageRaised += new BuildMessageEventHandler(MessageHandler); - } - - #endregion - - #region event delegates - - /// - /// This is the delegate for BuildStartedHandler events. - /// - protected virtual void BuildStartedHandler(object sender, BuildStartedEventArgs buildEvent) { - // NOTE: This may run on a background thread! - ClearCachedVerbosity(); - ClearQueuedOutput(); - ClearQueuedTasks(); - - QueueOutputEvent(MessageImportance.Low, buildEvent); - } - - /// - /// This is the delegate for BuildFinishedHandler events. - /// - /// - /// - protected virtual void BuildFinishedHandler(object sender, BuildFinishedEventArgs buildEvent) { - // NOTE: This may run on a background thread! - MessageImportance importance = buildEvent.Succeeded ? MessageImportance.Low : MessageImportance.High; - QueueOutputText(importance, Environment.NewLine); - QueueOutputEvent(importance, buildEvent); - - // flush output and error queues - ReportQueuedOutput(); - ReportQueuedTasks(); - } - - /// - /// This is the delegate for ProjectStartedHandler events. - /// - protected virtual void ProjectStartedHandler(object sender, ProjectStartedEventArgs buildEvent) { - // NOTE: This may run on a background thread! - QueueOutputEvent(MessageImportance.Low, buildEvent); - } - - /// - /// This is the delegate for ProjectFinishedHandler events. - /// - protected virtual void ProjectFinishedHandler(object sender, ProjectFinishedEventArgs buildEvent) { - // NOTE: This may run on a background thread! - QueueOutputEvent(buildEvent.Succeeded ? MessageImportance.Low : MessageImportance.High, buildEvent); - } - - /// - /// This is the delegate for TargetStartedHandler events. - /// - protected virtual void TargetStartedHandler(object sender, TargetStartedEventArgs buildEvent) { - // NOTE: This may run on a background thread! - QueueOutputEvent(MessageImportance.Low, buildEvent); - IndentOutput(); - } - - /// - /// This is the delegate for TargetFinishedHandler events. - /// - protected virtual void TargetFinishedHandler(object sender, TargetFinishedEventArgs buildEvent) { - // NOTE: This may run on a background thread! - UnindentOutput(); - QueueOutputEvent(MessageImportance.Low, buildEvent); - } - - /// - /// This is the delegate for TaskStartedHandler events. - /// - protected virtual void TaskStartedHandler(object sender, TaskStartedEventArgs buildEvent) { - // NOTE: This may run on a background thread! - QueueOutputEvent(MessageImportance.Low, buildEvent); - IndentOutput(); - } - - /// - /// This is the delegate for TaskFinishedHandler events. - /// - protected virtual void TaskFinishedHandler(object sender, TaskFinishedEventArgs buildEvent) { - // NOTE: This may run on a background thread! - UnindentOutput(); - QueueOutputEvent(MessageImportance.Low, buildEvent); - } - - /// - /// This is the delegate for CustomHandler events. - /// - /// - /// - protected virtual void CustomHandler(object sender, CustomBuildEventArgs buildEvent) { - // NOTE: This may run on a background thread! - QueueOutputEvent(MessageImportance.High, buildEvent); - } - - /// - /// This is the delegate for error events. - /// - protected virtual void ErrorRaisedHandler(object sender, BuildErrorEventArgs errorEvent) { - // NOTE: This may run on a background thread! - QueueOutputText(GetFormattedErrorMessage(errorEvent.File, errorEvent.LineNumber, errorEvent.ColumnNumber, false, errorEvent.Code, errorEvent.Message)); - QueueTaskEvent(errorEvent); - } - - /// - /// This is the delegate for warning events. - /// - protected virtual void WarningHandler(object sender, BuildWarningEventArgs warningEvent) { - // NOTE: This may run on a background thread! - QueueOutputText(MessageImportance.High, GetFormattedErrorMessage(warningEvent.File, warningEvent.LineNumber, warningEvent.ColumnNumber, true, warningEvent.Code, warningEvent.Message)); - QueueTaskEvent(warningEvent); - } - - /// - /// This is the delegate for Message event types - /// - protected virtual void MessageHandler(object sender, BuildMessageEventArgs messageEvent) { - // NOTE: This may run on a background thread! - - // Special-case this event type. It's reported by tasks derived from ToolTask, and prints out the command line used - // to invoke the tool. It has high priority for some unclear reason, but we really don't want to be showing it for - // verbosity below normal (https://nodejstools.codeplex.com/workitem/693). The check here is taken directly from the - // standard MSBuild console logger, which does the same thing. - if (messageEvent is TaskCommandLineEventArgs && !IsVerbosityAtLeast(LoggerVerbosity.Normal)) { - return; - } - - QueueOutputEvent(messageEvent.Importance, messageEvent); - } - - #endregion - - #region output queue - - protected void QueueOutputEvent(MessageImportance importance, BuildEventArgs buildEvent) { - // NOTE: This may run on a background thread! - if (LogAtImportance(importance) && !string.IsNullOrEmpty(buildEvent.Message)) { - StringBuilder message = new StringBuilder(this.currentIndent + buildEvent.Message.Length); - if (this.currentIndent > 0) { - message.Append('\t', this.currentIndent); - } - message.AppendLine(buildEvent.Message); - - QueueOutputText(message.ToString()); - } - } - - protected void QueueOutputText(MessageImportance importance, string text) { - // NOTE: This may run on a background thread! - if (LogAtImportance(importance)) { - QueueOutputText(text); - } - } - - protected void QueueOutputText(string text) { - // NOTE: This may run on a background thread! - if (this.OutputWindowPane != null) { - // Enqueue the output text - this.outputQueue.Enqueue(new OutputQueueEntry(text, OutputWindowPane)); - - // We want to interactively report the output. But we dont want to dispatch - // more than one at a time, otherwise we might overflow the main thread's - // message queue. So, we only report the output if the queue was empty. - if (this.outputQueue.Count == 1) { - ReportQueuedOutput(); - } - } - } - - private void IndentOutput() { - // NOTE: This may run on a background thread! - this.currentIndent++; - } - - private void UnindentOutput() { - // NOTE: This may run on a background thread! - this.currentIndent--; - } - - private void ReportQueuedOutput() { - // NOTE: This may run on a background thread! - // We need to output this on the main thread. We must use BeginInvoke because the main thread may not be pumping events yet. - BeginInvokeWithErrorMessage(this.serviceProvider, this.dispatcher, FlushBuildOutput); - } - - internal void FlushBuildOutput() { - OutputQueueEntry output; - - while (this.outputQueue.TryDequeue(out output)) { - ErrorHandler.ThrowOnFailure(output.Pane.OutputString(output.Message)); - } - } - - private void ClearQueuedOutput() { - // NOTE: This may run on a background thread! - this.outputQueue = new ConcurrentQueue(); - } - - #endregion output queue - - #region task queue - - class NavigableErrorTask : ErrorTask { - private readonly IServiceProvider _serviceProvider; - - public NavigableErrorTask(IServiceProvider serviceProvider) { - _serviceProvider = serviceProvider; - } - - protected override void OnNavigate(EventArgs e) { - VsUtilities.NavigateTo( - _serviceProvider, - Document, - Guid.Empty, - Line, - Column - 1 - ); - base.OnNavigate(e); - } - } - - protected void QueueTaskEvent(BuildEventArgs errorEvent) { - // This enqueues a function that will later be run on the main (UI) thread - this.taskQueue.Enqueue(() => - { - TextSpan span; - string file; - MARKERTYPE marker; - TaskErrorCategory category; - - if (errorEvent is BuildErrorEventArgs) - { - BuildErrorEventArgs errorArgs = (BuildErrorEventArgs)errorEvent; - span = new TextSpan(); - // spans require zero-based indices - span.iStartLine = errorArgs.LineNumber - 1; - span.iEndLine = errorArgs.EndLineNumber - 1; - span.iStartIndex = errorArgs.ColumnNumber - 1; - span.iEndIndex = errorArgs.EndColumnNumber - 1; - file = GetRelativeOrProjectPath(errorArgs.ProjectFile, errorArgs.File); - marker = MARKERTYPE.MARKER_CODESENSE_ERROR; // red squiggles - category = TaskErrorCategory.Error; - } - else if (errorEvent is BuildWarningEventArgs) - { - BuildWarningEventArgs warningArgs = (BuildWarningEventArgs)errorEvent; - span = new TextSpan(); - // spans require zero-based indices - span.iStartLine = warningArgs.LineNumber - 1; - span.iEndLine = warningArgs.EndLineNumber - 1; - span.iStartIndex = warningArgs.ColumnNumber - 1; - span.iEndIndex = warningArgs.EndColumnNumber - 1; - file = GetRelativeOrProjectPath(warningArgs.ProjectFile, warningArgs.File); - marker = MARKERTYPE.MARKER_COMPILE_ERROR; // red squiggles - category = TaskErrorCategory.Warning; - } - else - { - throw new NotImplementedException(); - } - - if (span.iEndLine == -1) span.iEndLine = span.iStartLine; - if (span.iEndIndex == -1) span.iEndIndex = span.iStartIndex; - - IVsUIShellOpenDocument openDoc = serviceProvider.GetService(typeof(IVsUIShellOpenDocument)) as IVsUIShellOpenDocument; - if (openDoc == null) - throw new NotImplementedException(); // TODO - - IVsWindowFrame frame; - IOleServiceProvider sp; - IVsUIHierarchy hier; - uint itemid; - Guid logicalView = VSConstants.LOGVIEWID_Code; - - IVsTextLines buffer = null; - - // Notes about acquiring the buffer: - // If the file physically exists then this will open the document in the current project. It doesn't matter if the file is a member of the project. - // Also, it doesn't matter if this is a Rust file. For example, an error in Microsoft.Common.targets will cause a file to be opened here. - // However, opening the document does not mean it will be shown in VS. - if (!Microsoft.VisualStudio.ErrorHandler.Failed(openDoc.OpenDocumentViaProject(file, ref logicalView, out sp, out hier, out itemid, out frame)) && frame != null) - { - object docData; - frame.GetProperty((int)__VSFPROPID.VSFPROPID_DocData, out docData); - - // Get the text lines - buffer = docData as IVsTextLines; - - if (buffer == null) - { - IVsTextBufferProvider bufferProvider = docData as IVsTextBufferProvider; - if (bufferProvider != null) - { - bufferProvider.GetTextBuffer(out buffer); - } - } - } - - ErrorTask task = CreateErrorTask(errorEvent, span, file, marker, category, buffer); - task.ErrorCategory = category; - task.Document = file; - task.Line = span.iStartLine; - task.Column = span.iStartIndex; - task.Priority = category == TaskErrorCategory.Error ? TaskPriority.High : TaskPriority.Normal; - task.Text = errorEvent.Message; - task.Category = TaskCategory.BuildCompile; - task.HierarchyItem = hierarchy; - return task; - }); - - // NOTE: Unlike output we dont want to interactively report the tasks. So we never queue - // call ReportQueuedTasks here. We do this when the build finishes. - } - - static string GetRelativeOrProjectPath(string projectFile, string file) - { - bool isInvalidFileName = file.IndexOfAny(Path.GetInvalidPathChars()) != -1; - if(isInvalidFileName) - return projectFile; - return Path.Combine(Path.GetDirectoryName(projectFile), file); - - } - - ErrorTask CreateErrorTask(BuildEventArgs errorEvent, TextSpan span, string file, MARKERTYPE marker, TaskErrorCategory category, IVsTextLines buffer) - { - if(buffer != null) - return new DocumentTask(serviceProvider, buffer, marker, span, file); - else - return new ErrorTask(); - } - - private void ReportQueuedTasks() { - // NOTE: This may run on a background thread! - // We need to output this on the main thread. We must use BeginInvoke because the main thread may not be pumping events yet. - BeginInvokeWithErrorMessage(this.serviceProvider, this.dispatcher, () => { - this.taskProvider.SuspendRefresh(); - try { - Func taskFunc; - - while (this.taskQueue.TryDequeue(out taskFunc)) { - // Create the error task - ErrorTask task = taskFunc(); - - // Log the task - this.taskProvider.Tasks.Add(task); - } - } finally { - this.taskProvider.ResumeRefresh(); - } - }); - } - - private void ClearQueuedTasks() { - // NOTE: This may run on a background thread! - this.taskQueue = new ConcurrentQueue>(); - - if (this.InteractiveBuild) { - // We need to clear this on the main thread. We must use BeginInvoke because the main thread may not be pumping events yet. - BeginInvokeWithErrorMessage(this.serviceProvider, this.dispatcher, () => { - this.taskProvider.Tasks.Clear(); - }); - } - } - - #endregion task queue - - #region helpers - - /// - /// This method takes a MessageImportance and returns true if messages - /// at importance i should be loggeed. Otherwise return false. - /// - private bool LogAtImportance(MessageImportance importance) { - // If importance is too low for current settings, ignore the event - bool logIt = false; - - this.SetVerbosity(); - - switch (this.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 nothing to be logged"); - break; - } - - return logIt; - } - - /// - /// Format error messages for the task list - /// - private string GetFormattedErrorMessage( - string fileName, - int line, - int column, - bool isWarning, - string errorNumber, - string errorText) { - string errorCode = isWarning ? this.WarningString : this.ErrorString; - - StringBuilder message = new StringBuilder(); - if (!string.IsNullOrEmpty(fileName)) { - message.AppendFormat(CultureInfo.CurrentCulture, "{0}({1},{2}):", fileName, line, column); - } - message.AppendFormat(CultureInfo.CurrentCulture, " {0} {1}: {2}", errorCode, errorNumber, errorText); - message.AppendLine(); - - return message.ToString(); - } - - /// - /// Sets the verbosity level. - /// - private void SetVerbosity() { - if (!this.haveCachedVerbosity) { - this.Verbosity = LoggerVerbosity.Normal; - - try { - var settings = new ShellSettingsManager(serviceProvider); - var store = settings.GetReadOnlySettingsStore(SettingsScope.UserSettings); - if (store.CollectionExists(GeneralCollection) && store.PropertyExists(GeneralCollection, BuildVerbosityProperty)) { - this.Verbosity = (LoggerVerbosity)store.GetInt32(GeneralCollection, BuildVerbosityProperty, (int)LoggerVerbosity.Normal); - } - } catch (Exception ex) { - var message = string.Format( - "Unable to read verbosity option from the registry.{0}{1}", - Environment.NewLine, - ex.ToString() - ); - this.QueueOutputText(MessageImportance.High, message); - } - - this.haveCachedVerbosity = true; - } - } - - /// - /// Clear the cached verbosity, so that it will be re-evaluated from the build verbosity registry key. - /// - private void ClearCachedVerbosity() { - this.haveCachedVerbosity = false; - } - - #endregion helpers - - #region exception handling helpers - - /// - /// Call Dispatcher.BeginInvoke, showing an error message if there was a non-critical exception. - /// - /// service provider - /// dispatcher - /// action to invoke - private static void BeginInvokeWithErrorMessage(IServiceProvider serviceProvider, Dispatcher dispatcher, Action action) { - dispatcher.BeginInvoke(new Action(() => CallWithErrorMessage(serviceProvider, action))); - } - - /// - /// Show error message if exception is caught when invoking a method - /// - /// service provider - /// action to invoke - private static void CallWithErrorMessage(IServiceProvider serviceProvider, Action action) { - try { - action(); - } catch (Exception ex) { - if (ex.IsCriticalException()) { - throw; - } - - ShowErrorMessage(serviceProvider, ex); - } - } - - /// - /// Show error window about the exception - /// - /// service provider - /// exception - private static void ShowErrorMessage(IServiceProvider serviceProvider, Exception exception) { - IUIService UIservice = (IUIService)serviceProvider.GetService(typeof(IUIService)); - if (UIservice != null && exception != null) { - UIservice.ShowError(exception); - } - } - - #endregion exception handling helpers - - class OutputQueueEntry { - public readonly string Message; - public readonly IVsOutputWindowPane Pane; - - public OutputQueueEntry(string message, IVsOutputWindowPane pane) { - Message = message; - Pane = pane; - } - } - } -} \ No newline at end of file diff --git a/Microsoft.VisualStudio.Project/IDiskBasedNode.cs b/Microsoft.VisualStudio.Project/IDiskBasedNode.cs deleted file mode 100644 index 0fa1d66e..00000000 --- a/Microsoft.VisualStudio.Project/IDiskBasedNode.cs +++ /dev/null @@ -1,28 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -namespace Microsoft.VisualStudioTools.Project { - /// - /// Represents a node which has a filename on disk, implemented by folder and file nodes. - /// - interface IDiskBasedNode { - string Url { - get; - } - - void RenameForDeferredSave(string basePath, string baseNewPath); - } -} diff --git a/Microsoft.VisualStudio.Project/IProjectLauncher.cs b/Microsoft.VisualStudio.Project/IProjectLauncher.cs deleted file mode 100644 index 4b0a4787..00000000 --- a/Microsoft.VisualStudio.Project/IProjectLauncher.cs +++ /dev/null @@ -1,36 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -namespace Microsoft.VisualStudioTools.Project { - /// - /// Defines an interface for launching a project or a file with or without debugging. - /// - public interface IProjectLauncher { - /// - /// Starts a project with or without debugging. - /// - /// Returns an HRESULT indicating success or failure. - /// - int LaunchProject(bool debug); - - /// - /// Starts a file in a project with or without debugging. - /// - /// Returns an HRESULT indicating success or failure. - /// - int LaunchFile(string file, bool debug); - } -} diff --git a/Microsoft.VisualStudio.Project/IProjectPublisher.cs b/Microsoft.VisualStudio.Project/IProjectPublisher.cs deleted file mode 100644 index 994d9cfe..00000000 --- a/Microsoft.VisualStudio.Project/IProjectPublisher.cs +++ /dev/null @@ -1,48 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; - -namespace Microsoft.VisualStudioTools.Project { - /// - /// Implements a publisher which handles publishing the list of files to a destination. - /// - public interface IProjectPublisher { - /// - /// Publishes the files listed in the given project to the provided URI. - /// - /// This function should return when publishing is complete or throw an exception if publishing fails. - /// - /// The project to be published. - /// The destination URI for the project. - void PublishFiles(IPublishProject project, Uri destination); - - /// - /// Gets a localized description of the destination type (web site, file share, etc...) - /// - string DestinationDescription { - get; - } - - /// - /// Gets the schema supported by this publisher - used to select which publisher will - /// be used based upon the schema of the Uri provided by the user. - /// - string Schema { - get; - } - } -} diff --git a/Microsoft.VisualStudio.Project/IPublishFile.cs b/Microsoft.VisualStudio.Project/IPublishFile.cs deleted file mode 100644 index 4bc11504..00000000 --- a/Microsoft.VisualStudio.Project/IPublishFile.cs +++ /dev/null @@ -1,33 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -namespace Microsoft.VisualStudioTools.Project { - public interface IPublishFile { - /// - /// Returns the source file that should be copied from. - /// - string SourceFile { - get; - } - - /// - /// Returns the relative path for the destination file. - /// - string DestinationFile { - get; - } - } -} diff --git a/Microsoft.VisualStudio.Project/IPublishProject.cs b/Microsoft.VisualStudio.Project/IPublishProject.cs deleted file mode 100644 index 19d4f1ac..00000000 --- a/Microsoft.VisualStudio.Project/IPublishProject.cs +++ /dev/null @@ -1,43 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System.Collections.Generic; - -namespace Microsoft.VisualStudioTools.Project { - public interface IPublishProject { - /// - /// Gets the list of files which need to be published. - /// - IList Files { - get; - } - - /// - /// Gets the root directory of the project. - /// - string ProjectDir { - get; - } - - /// - /// Gets or sets the progress of the publishing. - /// - int Progress { - get; - set; - } - } -} diff --git a/Microsoft.VisualStudio.Project/ImageHandler.cs b/Microsoft.VisualStudio.Project/ImageHandler.cs deleted file mode 100644 index d4f1faa7..00000000 --- a/Microsoft.VisualStudio.Project/ImageHandler.cs +++ /dev/null @@ -1,177 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Collections.Generic; -using System.Drawing; -using System.IO; -using System.Windows.Forms; - -namespace Microsoft.VisualStudioTools.Project { - public class ImageHandler : IDisposable { - private ImageList imageList; - private List iconHandles; - private static volatile object Mutex; - private bool isDisposed; - - /// - /// Initializes the class. - /// - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline")] - static ImageHandler() { - Mutex = new object(); - } - - /// - /// Builds an empty ImageHandler object. - /// - public ImageHandler() { - } - - /// - /// Builds an ImageHandler object from a Stream providing the bitmap that - /// stores the images for the image list. - /// - public ImageHandler(Stream resourceStream) { - Utilities.ArgumentNotNull("resourceStream", resourceStream); - imageList = Utilities.GetImageList(new Bitmap(resourceStream)); - } - - /// - /// Builds an ImageHandler object from an ImageList object. - /// - public ImageHandler(ImageList list) { - Utilities.ArgumentNotNull("list", list); - - imageList = list; - } - - public ImageHandler(Bitmap bitmap) - { - if (null == bitmap) - { - throw new ArgumentNullException("bitmap"); - } - imageList = Utilities.GetImageList(bitmap); - } - - /// - /// Closes the ImageHandler object freeing its resources. - /// - public void Close() { - if (null != iconHandles) { - foreach (IntPtr hnd in iconHandles) { - if (hnd != IntPtr.Zero) { - NativeMethods.DestroyIcon(hnd); - } - } - iconHandles = null; - } - - if (null != imageList) { - imageList.Dispose(); - imageList = null; - } - } - - /// - /// Add an image to the ImageHandler. - /// - /// the image object to be added. - public void AddImage(Image image) { - Utilities.ArgumentNotNull("image", image); - if (null == imageList) { - imageList = new ImageList(); - } - imageList.Images.Add(image); - if (null != iconHandles) { - iconHandles.Add(IntPtr.Zero); - } - } - - /// - /// Get or set the ImageList object for this ImageHandler. - /// - public ImageList ImageList { - get { return imageList; } - set { - Close(); - imageList = value; - } - } - - /// - /// Returns the handle to an icon build from the image of index - /// iconIndex in the image list. - /// - public IntPtr GetIconHandle(int iconIndex) { - Utilities.CheckNotNull(imageList); - // Make sure that the list of handles is initialized. - if (null == iconHandles) { - InitHandlesList(); - } - - // Verify that the index is inside the expected range. - if ((iconIndex < 0) || (iconIndex >= iconHandles.Count)) { - throw new ArgumentOutOfRangeException("iconIndex"); - } - - // Check if the icon is in the cache. - if (IntPtr.Zero == iconHandles[iconIndex]) { - Bitmap bitmap = imageList.Images[iconIndex] as Bitmap; - // If the image is not a bitmap, then we can not build the icon, - // so we have to return a null handle. - if (null == bitmap) { - return IntPtr.Zero; - } - - iconHandles[iconIndex] = bitmap.GetHicon(); - } - - return iconHandles[iconIndex]; - } - - private void InitHandlesList() { - iconHandles = new List(imageList.Images.Count); - for (int i = 0; i < imageList.Images.Count; ++i) { - iconHandles.Add(IntPtr.Zero); - } - } - - #region IDisposable Members - - /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// - public void Dispose() { - this.Dispose(true); - GC.SuppressFinalize(this); - } - #endregion - - private void Dispose(bool disposing) { - if (!this.isDisposed) { - lock (Mutex) { - if (disposing) { - this.imageList.Dispose(); - } - - this.isDisposed = true; - } - } - } - } -} diff --git a/Microsoft.VisualStudio.Project/Interfaces.cs b/Microsoft.VisualStudio.Project/Interfaces.cs deleted file mode 100644 index 362ad123..00000000 --- a/Microsoft.VisualStudio.Project/Interfaces.cs +++ /dev/null @@ -1,81 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.InteropServices; -using Microsoft.VisualStudio.Shell.Interop; -using MSBuild = Microsoft.Build.Evaluation; - -namespace Microsoft.VisualStudioTools.Project { - - /// - /// Interface for manipulating build dependency - /// - /// Normally this should be an internal interface but since it shouldbe available for the aggregator it must be made public. - [ComVisible(true)] - public interface IBuildDependencyUpdate { - /// - /// Defines a container for storing BuildDependencies - /// - - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] - IVsBuildDependency[] BuildDependencies { - get; - } - - /// - /// Adds a BuildDependency to the container - /// - /// The dependency to add - void AddBuildDependency(IVsBuildDependency dependency); - - /// - /// Removes the builddependency from teh container. - /// - /// The dependency to add - void RemoveBuildDependency(IVsBuildDependency dependency); - - } - - /// - /// Provides access to the reference data container. - /// - internal interface IReferenceContainerProvider { - IReferenceContainer GetReferenceContainer(); - } - - /// - /// Defines a container for manipulating references - /// - internal interface IReferenceContainer { - IList EnumReferences(); - ReferenceNode AddReferenceFromSelectorData(VSCOMPONENTSELECTORDATA selectorData); - void LoadReferencesFromBuildProject(MSBuild.Project buildProject); - } - - /// - /// Defines support for single file generator - /// - public interface ISingleFileGenerator { - /// - /// Runs the generator on the item represented by the document moniker. - /// - /// - void RunGenerator(string document); - } -} \ No newline at end of file diff --git a/Microsoft.VisualStudio.Project/LocalizableProperties.cs b/Microsoft.VisualStudio.Project/LocalizableProperties.cs deleted file mode 100644 index fac587af..00000000 --- a/Microsoft.VisualStudio.Project/LocalizableProperties.cs +++ /dev/null @@ -1,99 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Collections; -using System.ComponentModel; -using System.Runtime.InteropServices; - -namespace Microsoft.VisualStudioTools.Project { - /// - /// Enables a managed object to expose properties and attributes for COM objects. - /// - [ComVisible(true)] - public class LocalizableProperties : ICustomTypeDescriptor { - #region ICustomTypeDescriptor - public virtual AttributeCollection GetAttributes() { - AttributeCollection col = TypeDescriptor.GetAttributes(this, true); - return col; - } - - public virtual EventDescriptor GetDefaultEvent() { - EventDescriptor ed = TypeDescriptor.GetDefaultEvent(this, true); - return ed; - } - - public virtual PropertyDescriptor GetDefaultProperty() { - PropertyDescriptor pd = TypeDescriptor.GetDefaultProperty(this, true); - return pd; - } - - public virtual object GetEditor(Type editorBaseType) { - object o = TypeDescriptor.GetEditor(this, editorBaseType, true); - return o; - } - - public virtual EventDescriptorCollection GetEvents() { - EventDescriptorCollection edc = TypeDescriptor.GetEvents(this, true); - return edc; - } - - public virtual EventDescriptorCollection GetEvents(System.Attribute[] attributes) { - EventDescriptorCollection edc = TypeDescriptor.GetEvents(this, attributes, true); - return edc; - } - - public virtual object GetPropertyOwner(PropertyDescriptor pd) { - return this; - } - - public virtual PropertyDescriptorCollection GetProperties() { - PropertyDescriptorCollection pcol = GetProperties(null); - return pcol; - } - - public virtual PropertyDescriptorCollection GetProperties(System.Attribute[] attributes) { - ArrayList newList = new ArrayList(); - PropertyDescriptorCollection props = TypeDescriptor.GetProperties(this, attributes, true); - - for (int i = 0; i < props.Count; i++) - newList.Add(CreateDesignPropertyDescriptor(props[i])); - - return new PropertyDescriptorCollection((PropertyDescriptor[])newList.ToArray(typeof(PropertyDescriptor))); - ; - } - - public virtual DesignPropertyDescriptor CreateDesignPropertyDescriptor(PropertyDescriptor propertyDescriptor) { - return new DesignPropertyDescriptor(propertyDescriptor); - } - - public virtual string GetComponentName() { - string name = TypeDescriptor.GetComponentName(this, true); - return name; - } - - public virtual TypeConverter GetConverter() { - TypeConverter tc = TypeDescriptor.GetConverter(this, true); - return tc; - } - - public virtual string GetClassName() { - return this.GetType().FullName; - } - - #endregion ICustomTypeDescriptor - } -} diff --git a/Microsoft.VisualStudio.Project/Microsoft.VisualStudio.Project.csproj b/Microsoft.VisualStudio.Project/Microsoft.VisualStudio.Project.csproj deleted file mode 100644 index 371405e4..00000000 --- a/Microsoft.VisualStudio.Project/Microsoft.VisualStudio.Project.csproj +++ /dev/null @@ -1,459 +0,0 @@ - - - - Debug - AnyCPU - 10.0.20506 - 2.0 - {CACB60A9-1E76-4F92-8831-B134A658C695} - Library - Properties - Microsoft.VisualStudio.Project - Microsoft.VisualStudio.Project - v4.5 - 512 - true - ..\VisualRust\Key.snk - $(AllowedAssemblyPrefix);Microsoft.Internal - - - - true - full - false - bin\Debug\ - TRACE;DEBUG;TEST DEV11_OR_LATER DEV12_OR_LATER - prompt - 4 - false - false - 3021,0649 - - - pdbonly - true - bin\Release\ - TRACE;DEV11_OR_LATER - prompt - 4 - false - - - true - bin\Debug-CI\ - TRACE;DEBUG;TEST DEV11_OR_LATER DEV12_OR_LATER - 3021,0649 - full - AnyCPU - prompt - - - - False - ..\packages\VSSDK.DTE.7.0.4\lib\net20\envdte.dll - False - - - False - ..\packages\VSSDK.DTE.8.8.0.4\lib\net20\envdte80.dll - False - - - 4.0 - - - - 4.0 - - - False - False - - - False - ..\packages\VSSDK.ComponentModelHost.12.0.4\lib\net45\Microsoft.VisualStudio.ComponentModelHost.dll - False - - - False - ..\packages\VSSDK.CoreUtility.12.0.4\lib\net45\Microsoft.VisualStudio.CoreUtility.dll - False - - - False - ..\packages\VSSDK.Debugger.Interop.9.9.0.4\lib\net20\Microsoft.VisualStudio.Debugger.InteropA.dll - False - - - False - False - - - False - ..\packages\VSSDK.Editor.12.0.4\lib\net45\Microsoft.VisualStudio.Editor.dll - False - - - False - ..\packages\VSSDK.GraphModel.12.0.4\lib\net45\Microsoft.VisualStudio.GraphModel.dll - False - - - False - ..\packages\VSSDK.Language.12.0.4\lib\net45\Microsoft.VisualStudio.Language.Intellisense.dll - False - - - False - ..\packages\VSSDK.Language.12.0.4\lib\net45\Microsoft.VisualStudio.Language.StandardClassification.dll - False - - - False - ..\packages\VSSDK.OLE.Interop.7.0.4\lib\net20\Microsoft.VisualStudio.OLE.Interop.dll - False - - - False - ..\packages\VSSDK.LanguageService.12.12.0.4\lib\net45\Microsoft.VisualStudio.Package.LanguageService.12.0.dll - False - - - False - ..\packages\VSSDK.Shell.12.12.0.4\lib\net45\Microsoft.VisualStudio.Shell.12.0.dll - False - - - False - ..\packages\VSSDK.Shell.Immutable.10.10.0.4\lib\net40\Microsoft.VisualStudio.Shell.Immutable.10.0.dll - False - - - False - ..\packages\VSSDK.Shell.Immutable.11.11.0.4\lib\net45\Microsoft.VisualStudio.Shell.Immutable.11.0.dll - False - - - False - ..\packages\VSSDK.Shell.Immutable.12.12.0.4\lib\net45\Microsoft.VisualStudio.Shell.Immutable.12.0.dll - False - - - False - ..\packages\VSSDK.Shell.Interop.7.0.4\lib\net20\Microsoft.VisualStudio.Shell.Interop.dll - False - - - False - ..\packages\VSSDK.Shell.Interop.10.10.0.4\lib\net20\Microsoft.VisualStudio.Shell.Interop.10.0.dll - False - - - False - ..\packages\VSSDK.Shell.Interop.11.11.0.4\lib\net20\Microsoft.VisualStudio.Shell.Interop.11.0.dll - False - - - False - ..\packages\VSSDK.Shell.Interop.12.12.0.4\lib\net20\Microsoft.VisualStudio.Shell.Interop.12.0.dll - False - - - False - ..\packages\VSSDK.Shell.Interop.8.8.0.4\lib\net20\Microsoft.VisualStudio.Shell.Interop.8.0.dll - False - - - False - ..\packages\VSSDK.Shell.Interop.9.9.0.4\lib\net20\Microsoft.VisualStudio.Shell.Interop.9.0.dll - False - - - False - ..\packages\VSSDK.Text.12.0.4\lib\net45\Microsoft.VisualStudio.Text.Data.dll - False - - - False - ..\packages\VSSDK.Text.12.0.4\lib\net45\Microsoft.VisualStudio.Text.Logic.dll - False - - - False - ..\packages\VSSDK.Text.12.0.4\lib\net45\Microsoft.VisualStudio.Text.UI.dll - False - - - False - ..\packages\VSSDK.Text.12.0.4\lib\net45\Microsoft.VisualStudio.Text.UI.Wpf.dll - False - - - False - ..\packages\VSSDK.TextManager.Interop.7.0.4\lib\net20\Microsoft.VisualStudio.TextManager.Interop.dll - False - - - False - ..\packages\VSSDK.TextManager.Interop.8.8.0.4\lib\net20\Microsoft.VisualStudio.TextManager.Interop.8.0.dll - False - - - False - ..\packages\VSSDK.Threading.12.0.4\lib\net45\Microsoft.VisualStudio.Threading.dll - False - - - - - False - ..\packages\VSSDK.DTE.7.0.4\lib\net20\stdole.dll - False - - - - - 3.5 - - - - - - - - - - - False - ..\packages\VSSDK.VSLangProj.7.0.4\lib\net20\VSLangProj.dll - False - - - False - C:\Users\vosen\Source\Repos\VisualRust\packages\VSSDK.VSLangProj.7.0.4\lib\net20\VSLangProj2.dll - False - False - - - False - ..\packages\VSSDK.VSLangProj.8.8.0.4\lib\net20\VSLangProj80.dll - False - - - - - - - - - - - - - OverwriteFileDialog.xaml - true - - - Designer - MSBuild:Compile - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TaskProgressBar.xaml - true - - - - - - MSBuild:Compile - Designer - MSBuild:Compile - Designer - true - - - - - - - - - - - - true - UserControl - - - WebPiComponentPickerControl.cs - true - - - - - - - - - - - - - - - - - - - - - true - MSBuild:Compile - Designer - - - - - Microsoft.VisualStudio.Project.resources - - - WebPiComponentPickerControl.cs - Designer - true - - - - - - - - - - - - Designer - - - - - \ No newline at end of file diff --git a/Microsoft.VisualStudio.Project/Misc/ConnectionPointContainer.cs b/Microsoft.VisualStudio.Project/Misc/ConnectionPointContainer.cs deleted file mode 100644 index 6d9ceb02..00000000 --- a/Microsoft.VisualStudio.Project/Misc/ConnectionPointContainer.cs +++ /dev/null @@ -1,112 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Collections.Generic; -using System.Runtime.InteropServices; -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.OLE.Interop; - -namespace Microsoft.VisualStudioTools.Project { - /// - /// Class used to identify a source of events of type SinkType. - /// - [ComVisible(false)] - internal interface IEventSource - where SinkType : class { - void OnSinkAdded(SinkType sink); - void OnSinkRemoved(SinkType sink); - } - - [ComVisible(true)] - public class ConnectionPointContainer : IConnectionPointContainer { - private Dictionary connectionPoints; - internal ConnectionPointContainer() { - connectionPoints = new Dictionary(); - } - internal void AddEventSource(IEventSource source) - where SinkType : class { - if (null == source) { - throw new ArgumentNullException("source"); - } - if (connectionPoints.ContainsKey(typeof(SinkType).GUID)) { - throw new ArgumentException("EventSource guid already added to the list of connection points", "source"); - } - connectionPoints.Add(typeof(SinkType).GUID, new ConnectionPoint(this, source)); - } - - #region IConnectionPointContainer Members - void IConnectionPointContainer.EnumConnectionPoints(out IEnumConnectionPoints ppEnum) { - throw new NotImplementedException(); - } - void IConnectionPointContainer.FindConnectionPoint(ref Guid riid, out IConnectionPoint ppCP) { - ppCP = connectionPoints[riid]; - } - #endregion - } - - internal class ConnectionPoint : IConnectionPoint - where SinkType : class { - Dictionary sinks; - private uint nextCookie; - private ConnectionPointContainer container; - private IEventSource source; - internal ConnectionPoint(ConnectionPointContainer container, IEventSource source) { - if (null == container) { - throw new ArgumentNullException("container"); - } - if (null == source) { - throw new ArgumentNullException("source"); - } - this.container = container; - this.source = source; - sinks = new Dictionary(); - nextCookie = 1; - } - #region IConnectionPoint Members - public void Advise(object pUnkSink, out uint pdwCookie) { - SinkType sink = pUnkSink as SinkType; - if (null == sink) { - Marshal.ThrowExceptionForHR(VSConstants.E_NOINTERFACE); - } - sinks.Add(nextCookie, sink); - pdwCookie = nextCookie; - source.OnSinkAdded(sink); - nextCookie += 1; - } - - public void EnumConnections(out IEnumConnections ppEnum) { - throw new NotImplementedException(); - ; - } - - public void GetConnectionInterface(out Guid pIID) { - pIID = typeof(SinkType).GUID; - } - - public void GetConnectionPointContainer(out IConnectionPointContainer ppCPC) { - ppCPC = this.container; - } - - public void Unadvise(uint dwCookie) { - // This will throw if the cookie is not in the list. - SinkType sink = sinks[dwCookie]; - sinks.Remove(dwCookie); - source.OnSinkRemoved(sink); - } - #endregion - } -} diff --git a/Microsoft.VisualStudio.Project/Misc/ExternDll.cs b/Microsoft.VisualStudio.Project/Misc/ExternDll.cs deleted file mode 100644 index 98cc5187..00000000 --- a/Microsoft.VisualStudio.Project/Misc/ExternDll.cs +++ /dev/null @@ -1,88 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -namespace Microsoft.VisualStudioTools.Project { - internal static class ExternDll { - -#if FEATURE_PAL - -#if !PLATFORM_UNIX - internal const String DLLPREFIX = ""; - internal const String DLLSUFFIX = ".dll"; -#else // !PLATFORM_UNIX -#if __APPLE__ - internal const String DLLPREFIX = "lib"; - internal const String DLLSUFFIX = ".dylib"; -#elif _AIX - internal const String DLLPREFIX = "lib"; - internal const String DLLSUFFIX = ".a"; -#elif __hppa__ || IA64 - internal const String DLLPREFIX = "lib"; - internal const String DLLSUFFIX = ".sl"; -#else - internal const String DLLPREFIX = "lib"; - internal const String DLLSUFFIX = ".so"; -#endif -#endif // !PLATFORM_UNIX - - public const string Kernel32 = DLLPREFIX + "rotor_pal" + DLLSUFFIX; - public const string User32 = DLLPREFIX + "rotor_pal" + DLLSUFFIX; - public const string Mscoree = DLLPREFIX + "sscoree" + DLLSUFFIX; -#else - public const string Activeds = "activeds.dll"; - public const string Advapi32 = "advapi32.dll"; - public const string Comctl32 = "comctl32.dll"; - public const string Comdlg32 = "comdlg32.dll"; - public const string Gdi32 = "gdi32.dll"; - public const string Gdiplus = "gdiplus.dll"; - public const string Hhctrl = "hhctrl.ocx"; - public const string Imm32 = "imm32.dll"; - public const string Kernel32 = "kernel32.dll"; - public const string Loadperf = "Loadperf.dll"; - public const string Mscoree = "mscoree.dll"; - public const string Mscorwks = "mscorwks.dll"; - public const string Msi = "msi.dll"; - public const string Mqrt = "mqrt.dll"; - public const string Ntdll = "ntdll.dll"; - public const string Ole32 = "ole32.dll"; - public const string Oleacc = "oleacc.dll"; - public const string Oleaut32 = "oleaut32.dll"; - public const string Olepro32 = "olepro32.dll"; - public const string PerfCounter = "perfcounter.dll"; - public const string Powrprof = "Powrprof.dll"; - public const string Psapi = "psapi.dll"; - public const string Shell32 = "shell32.dll"; - public const string Shfolder = "shfolder.dll"; - public const string User32 = "user32.dll"; - public const string Uxtheme = "uxtheme.dll"; - public const string WinMM = "winmm.dll"; - public const string Winspool = "winspool.drv"; - public const string Wtsapi32 = "wtsapi32.dll"; - public const string Version = "version.dll"; - public const string Vsassert = "vsassert.dll"; - public const string Shlwapi = "shlwapi.dll"; - public const string Crypt32 = "crypt32.dll"; - - // system.data specific - internal const string Odbc32 = "odbc32.dll"; - internal const string SNI = "System.Data.dll"; - - // system.data.oracleclient specific - internal const string OciDll = "oci.dll"; - internal const string OraMtsDll = "oramts.dll"; -#endif //!FEATURE_PAL - } -} diff --git a/Microsoft.VisualStudio.Project/Misc/NativeMethods.cs b/Microsoft.VisualStudio.Project/Misc/NativeMethods.cs deleted file mode 100644 index 2a042580..00000000 --- a/Microsoft.VisualStudio.Project/Misc/NativeMethods.cs +++ /dev/null @@ -1,1195 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.ComponentModel; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.IO; -using System.Reflection; -using System.Runtime.InteropServices; -using System.Text; -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.OLE.Interop; -using Microsoft.VisualStudio.Shell.Interop; -using Microsoft.VisualStudio.TextManager.Interop; -using Microsoft.Win32.SafeHandles; - -namespace Microsoft.VisualStudioTools.Project { - internal static class NativeMethods { - // IIDS - public static readonly Guid IID_IUnknown = new Guid("{00000000-0000-0000-C000-000000000046}"); - - public const int ERROR_FILE_NOT_FOUND = 2; - - public const int - CLSCTX_INPROC_SERVER = 0x1; - - public const int - S_FALSE = 0x00000001, - S_OK = 0x00000000, - - IDOK = 1, - IDCANCEL = 2, - IDABORT = 3, - IDRETRY = 4, - IDIGNORE = 5, - IDYES = 6, - IDNO = 7, - IDCLOSE = 8, - IDHELP = 9, - IDTRYAGAIN = 10, - IDCONTINUE = 11, - - OLECMDERR_E_NOTSUPPORTED = unchecked((int)0x80040100), - OLECMDERR_E_UNKNOWNGROUP = unchecked((int)0x80040104), - - UNDO_E_CLIENTABORT = unchecked((int)0x80044001), - E_OUTOFMEMORY = unchecked((int)0x8007000E), - E_INVALIDARG = unchecked((int)0x80070057), - E_FAIL = unchecked((int)0x80004005), - E_NOINTERFACE = unchecked((int)0x80004002), - E_POINTER = unchecked((int)0x80004003), - E_NOTIMPL = unchecked((int)0x80004001), - E_UNEXPECTED = unchecked((int)0x8000FFFF), - E_HANDLE = unchecked((int)0x80070006), - E_ABORT = unchecked((int)0x80004004), - E_ACCESSDENIED = unchecked((int)0x80070005), - E_PENDING = unchecked((int)0x8000000A); - - public const int - OLECLOSE_SAVEIFDIRTY = 0, - OLECLOSE_NOSAVE = 1, - OLECLOSE_PROMPTSAVE = 2; - - public const int - OLEIVERB_PRIMARY = 0, - OLEIVERB_SHOW = -1, - OLEIVERB_OPEN = -2, - OLEIVERB_HIDE = -3, - OLEIVERB_UIACTIVATE = -4, - OLEIVERB_INPLACEACTIVATE = -5, - OLEIVERB_DISCARDUNDOSTATE = -6, - OLEIVERB_PROPERTIES = -7; - - public const int - OFN_READONLY = unchecked((int)0x00000001), - OFN_OVERWRITEPROMPT = unchecked((int)0x00000002), - OFN_HIDEREADONLY = unchecked((int)0x00000004), - OFN_NOCHANGEDIR = unchecked((int)0x00000008), - OFN_SHOWHELP = unchecked((int)0x00000010), - OFN_ENABLEHOOK = unchecked((int)0x00000020), - OFN_ENABLETEMPLATE = unchecked((int)0x00000040), - OFN_ENABLETEMPLATEHANDLE = unchecked((int)0x00000080), - OFN_NOVALIDATE = unchecked((int)0x00000100), - OFN_ALLOWMULTISELECT = unchecked((int)0x00000200), - OFN_EXTENSIONDIFFERENT = unchecked((int)0x00000400), - OFN_PATHMUSTEXIST = unchecked((int)0x00000800), - OFN_FILEMUSTEXIST = unchecked((int)0x00001000), - OFN_CREATEPROMPT = unchecked((int)0x00002000), - OFN_SHAREAWARE = unchecked((int)0x00004000), - OFN_NOREADONLYRETURN = unchecked((int)0x00008000), - OFN_NOTESTFILECREATE = unchecked((int)0x00010000), - OFN_NONETWORKBUTTON = unchecked((int)0x00020000), - OFN_NOLONGNAMES = unchecked((int)0x00040000), - OFN_EXPLORER = unchecked((int)0x00080000), - OFN_NODEREFERENCELINKS = unchecked((int)0x00100000), - OFN_LONGNAMES = unchecked((int)0x00200000), - OFN_ENABLEINCLUDENOTIFY = unchecked((int)0x00400000), - OFN_ENABLESIZING = unchecked((int)0x00800000), - OFN_USESHELLITEM = unchecked((int)0x01000000), - OFN_DONTADDTORECENT = unchecked((int)0x02000000), - OFN_FORCESHOWHIDDEN = unchecked((int)0x10000000); - - // for READONLYSTATUS - public const int - ROSTATUS_NotReadOnly = 0x0, - ROSTATUS_ReadOnly = 0x1, - ROSTATUS_Unknown = unchecked((int)0xFFFFFFFF); - - public const int - IEI_DoNotLoadDocData = 0x10000000; - - public const int - CB_SETDROPPEDWIDTH = 0x0160, - - GWL_STYLE = (-16), - GWL_EXSTYLE = (-20), - - DWL_MSGRESULT = 0, - - SW_HIDE = 0, - SW_SHOW = 5, - SW_SHOWNORMAL = 1, - - HTMENU = 5, - - WS_POPUP = unchecked((int)0x80000000), - WS_CHILD = 0x40000000, - WS_MINIMIZE = 0x20000000, - WS_VISIBLE = 0x10000000, - WS_DISABLED = 0x08000000, - WS_CLIPSIBLINGS = 0x04000000, - WS_CLIPCHILDREN = 0x02000000, - WS_MAXIMIZE = 0x01000000, - WS_CAPTION = 0x00C00000, - WS_BORDER = 0x00800000, - WS_DLGFRAME = 0x00400000, - WS_VSCROLL = 0x00200000, - WS_HSCROLL = 0x00100000, - WS_SYSMENU = 0x00080000, - WS_THICKFRAME = 0x00040000, - WS_TABSTOP = 0x00010000, - WS_MINIMIZEBOX = 0x00020000, - WS_MAXIMIZEBOX = 0x00010000, - WS_EX_DLGMODALFRAME = 0x00000001, - WS_EX_MDICHILD = 0x00000040, - WS_EX_TOOLWINDOW = 0x00000080, - WS_EX_CLIENTEDGE = 0x00000200, - WS_EX_CONTEXTHELP = 0x00000400, - WS_EX_RIGHT = 0x00001000, - WS_EX_LEFT = 0x00000000, - WS_EX_RTLREADING = 0x00002000, - WS_EX_LEFTSCROLLBAR = 0x00004000, - WS_EX_CONTROLPARENT = 0x00010000, - WS_EX_STATICEDGE = 0x00020000, - WS_EX_APPWINDOW = 0x00040000, - WS_EX_LAYERED = 0x00080000, - WS_EX_TOPMOST = 0x00000008, - WS_EX_NOPARENTNOTIFY = 0x00000004, - - LVM_SETEXTENDEDLISTVIEWSTYLE = (0x1000 + 54), - - LVS_EX_LABELTIP = 0x00004000, - - // winuser.h - WH_JOURNALPLAYBACK = 1, - WH_GETMESSAGE = 3, - WH_MOUSE = 7, - WSF_VISIBLE = 0x0001, - WM_NULL = 0x0000, - WM_CREATE = 0x0001, - WM_DELETEITEM = 0x002D, - WM_DESTROY = 0x0002, - WM_MOVE = 0x0003, - WM_SIZE = 0x0005, - WM_ACTIVATE = 0x0006, - WA_INACTIVE = 0, - WA_ACTIVE = 1, - WA_CLICKACTIVE = 2, - WM_SETFOCUS = 0x0007, - WM_KILLFOCUS = 0x0008, - WM_ENABLE = 0x000A, - WM_SETREDRAW = 0x000B, - WM_SETTEXT = 0x000C, - WM_GETTEXT = 0x000D, - WM_GETTEXTLENGTH = 0x000E, - WM_PAINT = 0x000F, - WM_CLOSE = 0x0010, - WM_QUERYENDSESSION = 0x0011, - WM_QUIT = 0x0012, - WM_QUERYOPEN = 0x0013, - WM_ERASEBKGND = 0x0014, - WM_SYSCOLORCHANGE = 0x0015, - WM_ENDSESSION = 0x0016, - WM_SHOWWINDOW = 0x0018, - WM_WININICHANGE = 0x001A, - WM_SETTINGCHANGE = 0x001A, - WM_DEVMODECHANGE = 0x001B, - WM_ACTIVATEAPP = 0x001C, - WM_FONTCHANGE = 0x001D, - WM_TIMECHANGE = 0x001E, - WM_CANCELMODE = 0x001F, - WM_SETCURSOR = 0x0020, - WM_MOUSEACTIVATE = 0x0021, - WM_CHILDACTIVATE = 0x0022, - WM_QUEUESYNC = 0x0023, - WM_GETMINMAXINFO = 0x0024, - WM_PAINTICON = 0x0026, - WM_ICONERASEBKGND = 0x0027, - WM_NEXTDLGCTL = 0x0028, - WM_SPOOLERSTATUS = 0x002A, - WM_DRAWITEM = 0x002B, - WM_MEASUREITEM = 0x002C, - WM_VKEYTOITEM = 0x002E, - WM_CHARTOITEM = 0x002F, - WM_SETFONT = 0x0030, - WM_GETFONT = 0x0031, - WM_SETHOTKEY = 0x0032, - WM_GETHOTKEY = 0x0033, - WM_QUERYDRAGICON = 0x0037, - WM_COMPAREITEM = 0x0039, - WM_GETOBJECT = 0x003D, - WM_COMPACTING = 0x0041, - WM_COMMNOTIFY = 0x0044, - WM_WINDOWPOSCHANGING = 0x0046, - WM_WINDOWPOSCHANGED = 0x0047, - WM_POWER = 0x0048, - WM_COPYDATA = 0x004A, - WM_CANCELJOURNAL = 0x004B, - WM_NOTIFY = 0x004E, - WM_INPUTLANGCHANGEREQUEST = 0x0050, - WM_INPUTLANGCHANGE = 0x0051, - WM_TCARD = 0x0052, - WM_HELP = 0x0053, - WM_USERCHANGED = 0x0054, - WM_NOTIFYFORMAT = 0x0055, - WM_CONTEXTMENU = 0x007B, - WM_STYLECHANGING = 0x007C, - WM_STYLECHANGED = 0x007D, - WM_DISPLAYCHANGE = 0x007E, - WM_GETICON = 0x007F, - WM_SETICON = 0x0080, - WM_NCCREATE = 0x0081, - WM_NCDESTROY = 0x0082, - WM_NCCALCSIZE = 0x0083, - WM_NCHITTEST = 0x0084, - WM_NCPAINT = 0x0085, - WM_NCACTIVATE = 0x0086, - WM_GETDLGCODE = 0x0087, - WM_NCMOUSEMOVE = 0x00A0, - WM_NCLBUTTONDOWN = 0x00A1, - WM_NCLBUTTONUP = 0x00A2, - WM_NCLBUTTONDBLCLK = 0x00A3, - WM_NCRBUTTONDOWN = 0x00A4, - WM_NCRBUTTONUP = 0x00A5, - WM_NCRBUTTONDBLCLK = 0x00A6, - WM_NCMBUTTONDOWN = 0x00A7, - WM_NCMBUTTONUP = 0x00A8, - WM_NCMBUTTONDBLCLK = 0x00A9, - WM_NCXBUTTONDOWN = 0x00AB, - WM_NCXBUTTONUP = 0x00AC, - WM_NCXBUTTONDBLCLK = 0x00AD, - WM_KEYFIRST = 0x0100, - WM_KEYDOWN = 0x0100, - WM_KEYUP = 0x0101, - WM_CHAR = 0x0102, - WM_DEADCHAR = 0x0103, - WM_CTLCOLOR = 0x0019, - WM_SYSKEYDOWN = 0x0104, - WM_SYSKEYUP = 0x0105, - WM_SYSCHAR = 0x0106, - WM_SYSDEADCHAR = 0x0107, - WM_KEYLAST = 0x0108, - WM_IME_STARTCOMPOSITION = 0x010D, - WM_IME_ENDCOMPOSITION = 0x010E, - WM_IME_COMPOSITION = 0x010F, - WM_IME_KEYLAST = 0x010F, - WM_INITDIALOG = 0x0110, - WM_COMMAND = 0x0111, - WM_SYSCOMMAND = 0x0112, - WM_TIMER = 0x0113, - WM_HSCROLL = 0x0114, - WM_VSCROLL = 0x0115, - WM_INITMENU = 0x0116, - WM_INITMENUPOPUP = 0x0117, - WM_MENUSELECT = 0x011F, - WM_MENUCHAR = 0x0120, - WM_ENTERIDLE = 0x0121, - WM_CHANGEUISTATE = 0x0127, - WM_UPDATEUISTATE = 0x0128, - WM_QUERYUISTATE = 0x0129, - WM_CTLCOLORMSGBOX = 0x0132, - WM_CTLCOLOREDIT = 0x0133, - WM_CTLCOLORLISTBOX = 0x0134, - WM_CTLCOLORBTN = 0x0135, - WM_CTLCOLORDLG = 0x0136, - WM_CTLCOLORSCROLLBAR = 0x0137, - WM_CTLCOLORSTATIC = 0x0138, - WM_MOUSEFIRST = 0x0200, - WM_MOUSEMOVE = 0x0200, - WM_LBUTTONDOWN = 0x0201, - WM_LBUTTONUP = 0x0202, - WM_LBUTTONDBLCLK = 0x0203, - WM_RBUTTONDOWN = 0x0204, - WM_RBUTTONUP = 0x0205, - WM_RBUTTONDBLCLK = 0x0206, - WM_MBUTTONDOWN = 0x0207, - WM_MBUTTONUP = 0x0208, - WM_MBUTTONDBLCLK = 0x0209, - WM_XBUTTONDOWN = 0x020B, - WM_XBUTTONUP = 0x020C, - WM_XBUTTONDBLCLK = 0x020D, - WM_MOUSEWHEEL = 0x020A, - WM_MOUSELAST = 0x020A, - WM_PARENTNOTIFY = 0x0210, - WM_ENTERMENULOOP = 0x0211, - WM_EXITMENULOOP = 0x0212, - WM_NEXTMENU = 0x0213, - WM_SIZING = 0x0214, - WM_CAPTURECHANGED = 0x0215, - WM_MOVING = 0x0216, - WM_POWERBROADCAST = 0x0218, - WM_DEVICECHANGE = 0x0219, - WM_IME_SETCONTEXT = 0x0281, - WM_IME_NOTIFY = 0x0282, - WM_IME_CONTROL = 0x0283, - WM_IME_COMPOSITIONFULL = 0x0284, - WM_IME_SELECT = 0x0285, - WM_IME_CHAR = 0x0286, - WM_IME_KEYDOWN = 0x0290, - WM_IME_KEYUP = 0x0291, - WM_MDICREATE = 0x0220, - WM_MDIDESTROY = 0x0221, - WM_MDIACTIVATE = 0x0222, - WM_MDIRESTORE = 0x0223, - WM_MDINEXT = 0x0224, - WM_MDIMAXIMIZE = 0x0225, - WM_MDITILE = 0x0226, - WM_MDICASCADE = 0x0227, - WM_MDIICONARRANGE = 0x0228, - WM_MDIGETACTIVE = 0x0229, - WM_MDISETMENU = 0x0230, - WM_ENTERSIZEMOVE = 0x0231, - WM_EXITSIZEMOVE = 0x0232, - WM_DROPFILES = 0x0233, - WM_MDIREFRESHMENU = 0x0234, - WM_MOUSEHOVER = 0x02A1, - WM_MOUSELEAVE = 0x02A3, - WM_CUT = 0x0300, - WM_COPY = 0x0301, - WM_PASTE = 0x0302, - WM_CLEAR = 0x0303, - WM_UNDO = 0x0304, - WM_RENDERFORMAT = 0x0305, - WM_RENDERALLFORMATS = 0x0306, - WM_DESTROYCLIPBOARD = 0x0307, - WM_DRAWCLIPBOARD = 0x0308, - WM_PAINTCLIPBOARD = 0x0309, - WM_VSCROLLCLIPBOARD = 0x030A, - WM_SIZECLIPBOARD = 0x030B, - WM_ASKCBFORMATNAME = 0x030C, - WM_CHANGECBCHAIN = 0x030D, - WM_HSCROLLCLIPBOARD = 0x030E, - WM_QUERYNEWPALETTE = 0x030F, - WM_PALETTEISCHANGING = 0x0310, - WM_PALETTECHANGED = 0x0311, - WM_HOTKEY = 0x0312, - WM_PRINT = 0x0317, - WM_PRINTCLIENT = 0x0318, - WM_HANDHELDFIRST = 0x0358, - WM_HANDHELDLAST = 0x035F, - WM_AFXFIRST = 0x0360, - WM_AFXLAST = 0x037F, - WM_PENWINFIRST = 0x0380, - WM_PENWINLAST = 0x038F, - WM_APP = unchecked((int)0x8000), - WM_USER = 0x0400, - WM_REFLECT = - WM_USER + 0x1C00, - WS_OVERLAPPED = 0x00000000, - WPF_SETMINPOSITION = 0x0001, - WM_CHOOSEFONT_GETLOGFONT = (0x0400 + 1), - - WHEEL_DELTA = 120, - DWLP_MSGRESULT = 0, - PSNRET_NOERROR = 0, - PSNRET_INVALID = 1, - PSNRET_INVALID_NOCHANGEPAGE = 2, - EM_SETCUEBANNER = 0x1501; - - public const int - PSN_APPLY = ((0 - 200) - 2), - PSN_KILLACTIVE = ((0 - 200) - 1), - PSN_RESET = ((0 - 200) - 3), - PSN_SETACTIVE = ((0 - 200) - 0); - - public const int - GMEM_MOVEABLE = 0x0002, - GMEM_ZEROINIT = 0x0040, - GMEM_DDESHARE = 0x2000; - - public const int - SWP_NOACTIVATE = 0x0010, - SWP_NOZORDER = 0x0004, - SWP_NOSIZE = 0x0001, - SWP_NOMOVE = 0x0002, - SWP_FRAMECHANGED = 0x0020; - - public const int - TVM_SETINSERTMARK = (0x1100 + 26), - TVM_GETEDITCONTROL = (0x1100 + 15); - - public const int - FILE_ATTRIBUTE_READONLY = 0x00000001, - FILE_ATTRIBUTE_DIRECTORY = 0x00000010; - - public const int - PSP_DEFAULT = 0x00000000, - PSP_DLGINDIRECT = 0x00000001, - PSP_USEHICON = 0x00000002, - PSP_USEICONID = 0x00000004, - PSP_USETITLE = 0x00000008, - PSP_RTLREADING = 0x00000010, - PSP_HASHELP = 0x00000020, - PSP_USEREFPARENT = 0x00000040, - PSP_USECALLBACK = 0x00000080, - PSP_PREMATURE = 0x00000400, - PSP_HIDEHEADER = 0x00000800, - PSP_USEHEADERTITLE = 0x00001000, - PSP_USEHEADERSUBTITLE = 0x00002000; - - public const int - PSH_DEFAULT = 0x00000000, - PSH_PROPTITLE = 0x00000001, - PSH_USEHICON = 0x00000002, - PSH_USEICONID = 0x00000004, - PSH_PROPSHEETPAGE = 0x00000008, - PSH_WIZARDHASFINISH = 0x00000010, - PSH_WIZARD = 0x00000020, - PSH_USEPSTARTPAGE = 0x00000040, - PSH_NOAPPLYNOW = 0x00000080, - PSH_USECALLBACK = 0x00000100, - PSH_HASHELP = 0x00000200, - PSH_MODELESS = 0x00000400, - PSH_RTLREADING = 0x00000800, - PSH_WIZARDCONTEXTHELP = 0x00001000, - PSH_WATERMARK = 0x00008000, - PSH_USEHBMWATERMARK = 0x00010000, // user pass in a hbmWatermark instead of pszbmWatermark - PSH_USEHPLWATERMARK = 0x00020000, // - PSH_STRETCHWATERMARK = 0x00040000, // stretchwatermark also applies for the header - PSH_HEADER = 0x00080000, - PSH_USEHBMHEADER = 0x00100000, - PSH_USEPAGELANG = 0x00200000, // use frame dialog template matched to page - PSH_WIZARD_LITE = 0x00400000, - PSH_NOCONTEXTHELP = 0x02000000; - - public const int - PSBTN_BACK = 0, - PSBTN_NEXT = 1, - PSBTN_FINISH = 2, - PSBTN_OK = 3, - PSBTN_APPLYNOW = 4, - PSBTN_CANCEL = 5, - PSBTN_HELP = 6, - PSBTN_MAX = 6; - - public const int - TRANSPARENT = 1, - OPAQUE = 2, - FW_BOLD = 700; - - [StructLayout(LayoutKind.Sequential)] - public struct NMHDR { - public IntPtr hwndFrom; - public int idFrom; - public int code; - } - - /// - /// Helper class for setting the text parameters to OLECMDTEXT structures. - /// - public static class OLECMDTEXT { - public static void SetText(IntPtr pCmdTextInt, string text) { - Microsoft.VisualStudio.OLE.Interop.OLECMDTEXT pCmdText = (Microsoft.VisualStudio.OLE.Interop.OLECMDTEXT)Marshal.PtrToStructure(pCmdTextInt, typeof(Microsoft.VisualStudio.OLE.Interop.OLECMDTEXT)); - char[] menuText = text.ToCharArray(); - - // Get the offset to the rgsz param. This is where we will stuff our text - // - IntPtr offset = Marshal.OffsetOf(typeof(Microsoft.VisualStudio.OLE.Interop.OLECMDTEXT), "rgwz"); - IntPtr offsetToCwActual = Marshal.OffsetOf(typeof(Microsoft.VisualStudio.OLE.Interop.OLECMDTEXT), "cwActual"); - - // The max chars we copy is our string, or one less than the buffer size, - // since we need a null at the end. - // - int maxChars = Math.Min((int)pCmdText.cwBuf - 1, menuText.Length); - - Marshal.Copy(menuText, 0, (IntPtr)((long)pCmdTextInt + (long)offset), maxChars); - - // append a null character - Marshal.WriteInt16((IntPtr)((long)pCmdTextInt + (long)offset + maxChars * 2), 0); - - // write out the length - // +1 for the null char - Marshal.WriteInt32((IntPtr)((long)pCmdTextInt + (long)offsetToCwActual), maxChars + 1); - } - - /// - /// Gets the flags of the OLECMDTEXT structure - /// - /// The structure to read. - /// The value of the flags. - public static OLECMDTEXTF GetFlags(IntPtr pCmdTextInt) { - Microsoft.VisualStudio.OLE.Interop.OLECMDTEXT pCmdText = (Microsoft.VisualStudio.OLE.Interop.OLECMDTEXT)Marshal.PtrToStructure(pCmdTextInt, typeof(Microsoft.VisualStudio.OLE.Interop.OLECMDTEXT)); - - if ((pCmdText.cmdtextf & (int)OLECMDTEXTF.OLECMDTEXTF_NAME) != 0) - return OLECMDTEXTF.OLECMDTEXTF_NAME; - - if ((pCmdText.cmdtextf & (int)OLECMDTEXTF.OLECMDTEXTF_STATUS) != 0) - return OLECMDTEXTF.OLECMDTEXTF_STATUS; - - return OLECMDTEXTF.OLECMDTEXTF_NONE; - } - - - /// - /// Flags for the OLE command text - /// - public enum OLECMDTEXTF { - /// No flag - OLECMDTEXTF_NONE = 0, - /// The name of the command is required. - OLECMDTEXTF_NAME = 1, - /// A description of the status is required. - OLECMDTEXTF_STATUS = 2 - } - } - - /// - /// OLECMDF enums for IOleCommandTarget - /// - public enum tagOLECMDF { - OLECMDF_SUPPORTED = 1, - OLECMDF_ENABLED = 2, - OLECMDF_LATCHED = 4, - OLECMDF_NINCHED = 8, - OLECMDF_INVISIBLE = 16 - } - - [DllImport("user32", CallingConvention = CallingConvention.Winapi)] - public static extern IntPtr GetParent(IntPtr hWnd); - - [DllImport("user32", CallingConvention = CallingConvention.Winapi)] - public static extern bool GetClientRect(IntPtr hWnd, out User32RECT lpRect); - - [DllImport("user32", CallingConvention = CallingConvention.Winapi)] - public static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint); - - [DllImport("user32", CallingConvention = CallingConvention.Winapi)] - public static extern IntPtr SendMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam); - - [DllImport("user32", CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Unicode)] - public static extern IntPtr SendMessageW(IntPtr hWnd, uint msg, IntPtr wParam, string lParam); - - [DllImport("user32", CallingConvention = CallingConvention.Winapi)] - public static extern int GetWindowLong(IntPtr hWnd, int nIndex); - - [DllImport("user32", CallingConvention = CallingConvention.Winapi)] - public static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong); - - [DllImport("user32", CallingConvention = CallingConvention.Winapi)] - public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, int flags); - - [DllImport("user32", CallingConvention = CallingConvention.Winapi)] - public static extern bool GetWindowRect(IntPtr hWnd, out RECT[] rect); - - public static void SetErrorDescription(string description, params object[] args) { - ICreateErrorInfo errInfo; - ErrorHandler.ThrowOnFailure(CreateErrorInfo(out errInfo)); - - errInfo.SetDescription(String.Format(description, args)); - var guidNull = Guid.Empty; - errInfo.SetGUID(ref guidNull); - errInfo.SetHelpFile(null); - errInfo.SetHelpContext(0); - errInfo.SetSource(""); - IErrorInfo errorInfo = errInfo as IErrorInfo; - SetErrorInfo(0, errorInfo); - } - - [DllImport("oleaut32")] - static extern int CreateErrorInfo(out ICreateErrorInfo errInfo); - - [DllImport("oleaut32")] - static extern int SetErrorInfo(uint dwReserved, IErrorInfo perrinfo); - - [ComImport(), Guid("9BDA66AE-CA28-4e22-AA27-8A7218A0E3FA"), InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] - public interface IEventHandler { - - // converts the underlying codefunction into an event handler for the given event - // if the given event is NULL, then the function will handle no events - [PreserveSig] - int AddHandler(string bstrEventName); - - [PreserveSig] - int RemoveHandler(string bstrEventName); - - IVsEnumBSTR GetHandledEvents(); - - bool HandlesEvent(string bstrEventName); - } - - [ComImport(), Guid("A55CCBCC-7031-432d-B30A-A68DE7BDAD75"), InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] - public interface IParameterKind { - - void SetParameterPassingMode(PARAMETER_PASSING_MODE ParamPassingMode); - void SetParameterArrayDimensions(int uDimensions); - int GetParameterArrayCount(); - int GetParameterArrayDimensions(int uIndex); - int GetParameterPassingMode(); - } - - public enum PARAMETER_PASSING_MODE { - cmParameterTypeIn = 1, - cmParameterTypeOut = 2, - cmParameterTypeInOut = 3 - } - - [ - ComImport, ComVisible(true), Guid("3E596484-D2E4-461a-A876-254C4F097EBB"), - InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown) - ] - public interface IMethodXML { - // Generate XML describing the contents of this function's body. - void GetXML(ref string pbstrXML); - - // Parse the incoming XML with respect to the CodeModel XML schema and - // use the result to regenerate the body of the function. - /// - [PreserveSig] - int SetXML(string pszXML); - - // This is really a textpoint - [PreserveSig] - int GetBodyPoint([MarshalAs(UnmanagedType.Interface)]out object bodyPoint); - } - - [ComImport(), Guid("EA1A87AD-7BC5-4349-B3BE-CADC301F17A3"), InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] - public interface IVBFileCodeModelEvents { - - [PreserveSig] - int StartEdit(); - - [PreserveSig] - int EndEdit(); - } - - ///-------------------------------------------------------------------------- - /// ICodeClassBase: - ///-------------------------------------------------------------------------- - [GuidAttribute("23BBD58A-7C59-449b-A93C-43E59EFC080C")] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - [ComImport()] - public interface ICodeClassBase { - [PreserveSig()] - int GetBaseName(out string pBaseName); - } - - public const ushort CF_HDROP = 15; // winuser.h - public const uint MK_CONTROL = 0x0008; //winuser.h - public const uint MK_SHIFT = 0x0004; - public const int MAX_PATH = 260; // windef.h - public const int MAX_FOLDER_PATH = MAX_PATH - 12; // folders need to allow 8.3 filenames, so MAX_PATH - 12 - - /// - /// Specifies options for a bitmap image associated with a task item. - /// - public enum VSTASKBITMAP { - BMP_COMPILE = -1, - BMP_SQUIGGLE = -2, - BMP_COMMENT = -3, - BMP_SHORTCUT = -4, - BMP_USER = -5 - }; - - public const int ILD_NORMAL = 0x0000, - ILD_TRANSPARENT = 0x0001, - ILD_MASK = 0x0010, - ILD_ROP = 0x0040; - - /// - /// Defines the values that are not supported by the System.Environment.SpecialFolder enumeration - /// - [ComVisible(true)] - public enum ExtendedSpecialFolder { - /// - /// Identical to CSIDL_COMMON_STARTUP - /// - CommonStartup = 0x0018, - - /// - /// Identical to CSIDL_WINDOWS - /// - Windows = 0x0024, - } - - - // APIS - - /// - /// Changes the parent window of the specified child window. - /// - /// Handle to the child window. - /// Handle to the new parent window. If this parameter is NULL, the desktop window becomes the new parent window. - /// A handle to the previous parent window indicates success. NULL indicates failure. - [DllImport("User32", ExactSpelling = true, CharSet = CharSet.Auto)] - public static extern IntPtr SetParent(IntPtr hWnd, IntPtr hWndParent); - - [DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)] - public static extern bool DestroyIcon(IntPtr handle); - - [DllImport("user32.dll", EntryPoint = "IsDialogMessageA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)] - public static extern bool IsDialogMessageA(IntPtr hDlg, ref MSG msg); - - [DllImport("kernel32", EntryPoint = "GetBinaryTypeW", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Winapi)] - private static extern bool _GetBinaryType(string lpApplicationName, out GetBinaryTypeResult lpBinaryType); - - private enum GetBinaryTypeResult : uint { - SCS_32BIT_BINARY = 0, - SCS_DOS_BINARY = 1, - SCS_WOW_BINARY = 2, - SCS_PIF_BINARY = 3, - SCS_POSIX_BINARY = 4, - SCS_OS216_BINARY = 5, - SCS_64BIT_BINARY = 6 - } - - public static ProcessorArchitecture GetBinaryType(string path) { - GetBinaryTypeResult result; - - if (_GetBinaryType(path, out result)) { - switch (result) { - case GetBinaryTypeResult.SCS_32BIT_BINARY: - return ProcessorArchitecture.X86; - case GetBinaryTypeResult.SCS_64BIT_BINARY: - return ProcessorArchitecture.Amd64; - case GetBinaryTypeResult.SCS_DOS_BINARY: - case GetBinaryTypeResult.SCS_WOW_BINARY: - case GetBinaryTypeResult.SCS_PIF_BINARY: - case GetBinaryTypeResult.SCS_POSIX_BINARY: - case GetBinaryTypeResult.SCS_OS216_BINARY: - default: - break; - } - } - - return ProcessorArchitecture.None; - } - - - [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] - public extern static bool DuplicateToken(IntPtr ExistingTokenHandle, - int SECURITY_IMPERSONATION_LEVEL, ref IntPtr DuplicateTokenHandle); - - [DllImport("ADVAPI32.dll", SetLastError = true, CharSet = CharSet.Unicode)] - internal static extern bool LogonUser( - [In] string lpszUsername, - [In] string lpszDomain, - [In] string lpszPassword, - [In] LogonType dwLogonType, - [In] LogonProvider dwLogonProvider, - [In, Out] ref IntPtr hToken - ); - - [DllImport("kernel32.dll", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool CloseHandle(IntPtr handle); - - [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] - public static extern uint GetFinalPathNameByHandle( - SafeHandle hFile, - [Out]StringBuilder lpszFilePath, - uint cchFilePath, - uint dwFlags - ); - - [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] - public static extern SafeFileHandle CreateFile( - string lpFileName, - FileDesiredAccess dwDesiredAccess, - FileShareFlags dwShareMode, - IntPtr lpSecurityAttributes, - FileCreationDisposition dwCreationDisposition, - FileFlagsAndAttributes dwFlagsAndAttributes, - IntPtr hTemplateFile - ); - - [Flags] - public enum FileDesiredAccess : uint { - FILE_LIST_DIRECTORY = 1 - } - - [Flags] - public enum FileShareFlags : uint { - FILE_SHARE_READ = 0x00000001, - FILE_SHARE_WRITE = 0x00000002, - FILE_SHARE_DELETE = 0x00000004 - } - - [Flags] - public enum FileCreationDisposition : uint { - OPEN_EXISTING = 3 - } - - [Flags] - public enum FileFlagsAndAttributes : uint { - FILE_FLAG_BACKUP_SEMANTICS = 0x02000000 - } - - public static IntPtr INVALID_FILE_HANDLE = new IntPtr(-1); - public static IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1); - - public enum LogonType { - LOGON32_LOGON_INTERACTIVE = 2, - LOGON32_LOGON_NETWORK, - LOGON32_LOGON_BATCH, - LOGON32_LOGON_SERVICE = 5, - LOGON32_LOGON_UNLOCK = 7, - LOGON32_LOGON_NETWORK_CLEARTEXT, - LOGON32_LOGON_NEW_CREDENTIALS - } - - public enum LogonProvider { - LOGON32_PROVIDER_DEFAULT = 0, - LOGON32_PROVIDER_WINNT35, - LOGON32_PROVIDER_WINNT40, - LOGON32_PROVIDER_WINNT50 - } - - [DllImport("msi.dll", CharSet = CharSet.Unicode)] - internal static extern MsiInstallState MsiGetComponentPath(string szProduct, string szComponent, [Out]StringBuilder lpPathBuf, ref uint pcchBuf); - - /// - /// Buffer for lpProductBuf must be 39 characters long. - /// - /// - /// - /// - [DllImport("msi.dll", CharSet = CharSet.Unicode)] - internal static extern uint MsiGetProductCode(string szComponent, [Out]StringBuilder lpProductBuf); - - - internal enum MsiInstallState { - NotUsed = -7, // component disabled - BadConfig = -6, // configuration data corrupt - Incomplete = -5, // installation suspended or in progress - SourceAbsent = -4, // run from source, source is unavailable - MoreData = -3, // return buffer overflow - InvalidArg = -2, // invalid function argument - Unknown = -1, // unrecognized product or feature - Broken = 0, // broken - Advertised = 1, // advertised feature - Removed = 1, // component being removed (action state, not settable) - Absent = 2, // uninstalled (or action state absent but clients remain) - Local = 3, // installed on local drive - Source = 4, // run from source, CD or net - Default = 5 // use default, local or source - } - - [DllImport("user32", CallingConvention = CallingConvention.Winapi)] - public static extern bool AllowSetForegroundWindow(int dwProcessId); - - [DllImport("mpr", CharSet = CharSet.Unicode)] - public static extern uint WNetAddConnection3(IntPtr handle, ref _NETRESOURCE lpNetResource, string lpPassword, string lpUsername, uint dwFlags); - - public const int CONNECT_INTERACTIVE = 0x08; - public const int CONNECT_PROMPT = 0x10; - public const int RESOURCETYPE_DISK = 1; - - public struct _NETRESOURCE { - public uint dwScope; - public uint dwType; - public uint dwDisplayType; - public uint dwUsage; - public string lpLocalName; - public string lpRemoteName; - public string lpComment; - public string lpProvider; - } - - [DllImport(ExternDll.Kernel32, EntryPoint = "GetFinalPathNameByHandleW", CharSet = CharSet.Unicode, SetLastError = true)] - public static extern int GetFinalPathNameByHandle(SafeFileHandle handle, [In, Out] StringBuilder path, int bufLen, int flags); - - [DllImport(ExternDll.Kernel32, EntryPoint = "CreateFileW", CharSet = CharSet.Unicode, SetLastError = true)] - public static extern SafeFileHandle CreateFile( - string lpFileName, - int dwDesiredAccess, - [MarshalAs(UnmanagedType.U4)] FileShare dwShareMode, - IntPtr SecurityAttributes, - [MarshalAs(UnmanagedType.U4)] FileMode dwCreationDisposition, - int dwFlagsAndAttributes, - IntPtr hTemplateFile); - - /// - /// Given a directory, actual or symbolic, return the actual directory path. - /// - /// DirectoryInfo object for the suspected symlink. - /// A string of the actual path. - internal static string GetAbsolutePathToDirectory(string symlink) { - const int FILE_FLAG_BACKUP_SEMANTICS = 0x02000000; - const int DEVICE_QUERY_ACCESS = 0; - - using (SafeFileHandle directoryHandle = CreateFile( - symlink, - DEVICE_QUERY_ACCESS, - FileShare.Write, - System.IntPtr.Zero, - FileMode.Open, - FILE_FLAG_BACKUP_SEMANTICS, - System.IntPtr.Zero)) { - if (directoryHandle.IsInvalid) { - Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); - } - - StringBuilder path = new StringBuilder(512); - int pathSize = GetFinalPathNameByHandle(directoryHandle, path, path.Capacity, 0); - if (pathSize < 0) { - Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); - } - - // UNC Paths will start with \\?\. Remove this if present as this isn't really expected on a path. - var pathString = path.ToString(); - return pathString.StartsWith(@"\\?\") ? pathString.Substring(4) : pathString; - } - } - - [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] - public static extern IntPtr FindFirstFile(string lpFileName, out WIN32_FIND_DATA lpFindFileData); - - [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] - public static extern bool FindNextFile(IntPtr hFindFile, out WIN32_FIND_DATA lpFindFileData); - - [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] - public static extern bool FindClose(IntPtr hFindFile); - - [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] - public static extern bool DeleteFile(string lpFileName); - - [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] - public static extern bool RemoveDirectory(string lpPathName); - - [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] - internal static extern bool MoveFile(String src, String dst); - } - - internal class CredUI { - private const string advapi32Dll = "advapi32.dll"; - private const string credUIDll = "credui.dll"; - - public const int - ERROR_INVALID_FLAGS = 1004, // Invalid flags. - ERROR_NOT_FOUND = 1168, // Element not found. - ERROR_NO_SUCH_LOGON_SESSION = 1312, // A specified logon session does not exist. It may already have been terminated. - ERROR_LOGON_FAILURE = 1326; // Logon failure: unknown user name or bad password. - - [Flags] - public enum CREDUI_FLAGS : uint { - INCORRECT_PASSWORD = 0x1, - DO_NOT_PERSIST = 0x2, - REQUEST_ADMINISTRATOR = 0x4, - EXCLUDE_CERTIFICATES = 0x8, - REQUIRE_CERTIFICATE = 0x10, - SHOW_SAVE_CHECK_BOX = 0x40, - ALWAYS_SHOW_UI = 0x80, - REQUIRE_SMARTCARD = 0x100, - PASSWORD_ONLY_OK = 0x200, - VALIDATE_USERNAME = 0x400, - COMPLETE_USERNAME = 0x800, - PERSIST = 0x1000, - SERVER_CREDENTIAL = 0x4000, - EXPECT_CONFIRMATION = 0x20000, - GENERIC_CREDENTIALS = 0x40000, - USERNAME_TARGET_CREDENTIALS = 0x80000, - KEEP_USERNAME = 0x100000, - } - - [StructLayout(LayoutKind.Sequential)] - public class CREDUI_INFO { - public int cbSize; - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] - public IntPtr hwndParentCERParent; - [MarshalAs(UnmanagedType.LPWStr)] - public string pszMessageText; - [MarshalAs(UnmanagedType.LPWStr)] - public string pszCaptionText; - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] - public IntPtr hbmBannerCERHandle; - } - - public enum CredUIReturnCodes : uint { - NO_ERROR = 0, - ERROR_CANCELLED = 1223, - ERROR_NO_SUCH_LOGON_SESSION = 1312, - ERROR_NOT_FOUND = 1168, - ERROR_INVALID_ACCOUNT_NAME = 1315, - ERROR_INSUFFICIENT_BUFFER = 122, - ERROR_INVALID_PARAMETER = 87, - ERROR_INVALID_FLAGS = 1004, - } - - // Copied from wincred.h - public const uint - // Values of the Credential Type field. - CRED_TYPE_GENERIC = 1, - CRED_TYPE_DOMAIN_PASSWORD = 2, - CRED_TYPE_DOMAIN_CERTIFICATE = 3, - CRED_TYPE_DOMAIN_VISIBLE_PASSWORD = 4, - CRED_TYPE_MAXIMUM = 5, // Maximum supported cred type - CRED_TYPE_MAXIMUM_EX = (CRED_TYPE_MAXIMUM + 1000), // Allow new applications to run on old OSes - - // String limits - CRED_MAX_CREDENTIAL_BLOB_SIZE = 512, // Maximum size of the CredBlob field (in bytes) - CRED_MAX_STRING_LENGTH = 256, // Maximum length of the various credential string fields (in characters) - CRED_MAX_USERNAME_LENGTH = (256 + 1 + 256), // Maximum length of the UserName field. The worst case is @ - CRED_MAX_GENERIC_TARGET_NAME_LENGTH = 32767, // Maximum length of the TargetName field for CRED_TYPE_GENERIC (in characters) - CRED_MAX_DOMAIN_TARGET_NAME_LENGTH = (256 + 1 + 80), // Maximum length of the TargetName field for CRED_TYPE_DOMAIN_* (in characters). Largest one is \ - CRED_MAX_VALUE_SIZE = 256, // Maximum size of the Credential Attribute Value field (in bytes) - CRED_MAX_ATTRIBUTES = 64, // Maximum number of attributes per credential - CREDUI_MAX_MESSAGE_LENGTH = 32767, - CREDUI_MAX_CAPTION_LENGTH = 128, - CREDUI_MAX_GENERIC_TARGET_LENGTH = CRED_MAX_GENERIC_TARGET_NAME_LENGTH, - CREDUI_MAX_DOMAIN_TARGET_LENGTH = CRED_MAX_DOMAIN_TARGET_NAME_LENGTH, - CREDUI_MAX_USERNAME_LENGTH = CRED_MAX_USERNAME_LENGTH, - CREDUI_MAX_PASSWORD_LENGTH = (CRED_MAX_CREDENTIAL_BLOB_SIZE / 2); - - internal enum CRED_PERSIST : uint { - NONE = 0, - SESSION = 1, - LOCAL_MACHINE = 2, - ENTERPRISE = 3, - } - - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] - public struct NativeCredential { - public uint flags; - public uint type; - public string targetName; - public string comment; - public int lastWritten_lowDateTime; - public int lastWritten_highDateTime; - public uint credentialBlobSize; - public IntPtr credentialBlob; - public uint persist; - public uint attributeCount; - public IntPtr attributes; - public string targetAlias; - public string userName; - }; - - [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass")] - [DllImport(advapi32Dll, CharSet = CharSet.Unicode, SetLastError = true, EntryPoint = "CredReadW")] - public static extern bool - CredRead( - [MarshalAs(UnmanagedType.LPWStr)] - string targetName, - [MarshalAs(UnmanagedType.U4)] - uint type, - [MarshalAs(UnmanagedType.U4)] - uint flags, - out IntPtr credential - ); - - [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass")] - [DllImport(advapi32Dll, CharSet = CharSet.Unicode, SetLastError = true, EntryPoint = "CredWriteW")] - public static extern bool - CredWrite( - ref NativeCredential Credential, - [MarshalAs(UnmanagedType.U4)] - uint flags - ); - - [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass")] - [DllImport(advapi32Dll, SetLastError = true)] - public static extern bool - CredFree( - IntPtr buffer - ); - - [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass")] - [DllImport(credUIDll, EntryPoint = "CredUIPromptForCredentialsW", CharSet = CharSet.Unicode)] - public static extern CredUIReturnCodes CredUIPromptForCredentials( - CREDUI_INFO pUiInfo, // Optional (one can pass null here) - [MarshalAs(UnmanagedType.LPWStr)] - string targetName, - IntPtr Reserved, // Must be 0 (IntPtr.Zero) - int iError, - [MarshalAs(UnmanagedType.LPWStr)] - StringBuilder pszUserName, - [MarshalAs(UnmanagedType.U4)] - uint ulUserNameMaxChars, - [MarshalAs(UnmanagedType.LPWStr)] - StringBuilder pszPassword, - [MarshalAs(UnmanagedType.U4)] - uint ulPasswordMaxChars, - ref int pfSave, - CREDUI_FLAGS dwFlags); - - /// - /// Win32 system errors: - /// NO_ERROR - /// ERROR_INVALID_ACCOUNT_NAME - /// ERROR_INSUFFICIENT_BUFFER - /// ERROR_INVALID_PARAMETER - /// - [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass")] - [DllImport(credUIDll, CharSet = CharSet.Unicode, SetLastError = true, EntryPoint = "CredUIParseUserNameW")] - public static extern CredUIReturnCodes CredUIParseUserName( - [MarshalAs(UnmanagedType.LPWStr)] - string strUserName, - [MarshalAs(UnmanagedType.LPWStr)] - StringBuilder strUser, - [MarshalAs(UnmanagedType.U4)] - uint iUserMaxChars, - [MarshalAs(UnmanagedType.LPWStr)] - StringBuilder strDomain, - [MarshalAs(UnmanagedType.U4)] - uint iDomainMaxChars - ); - } - - struct User32RECT { - public int left; - public int top; - public int right; - public int bottom; - - public int Width { - get { - return right - left; - } - } - - public int Height { - get { - return bottom - top; - } - } - } - - [Guid("22F03340-547D-101B-8E65-08002B2BD119")] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - interface ICreateErrorInfo { - int SetGUID( - ref Guid rguid - ); - - int SetSource(string szSource); - - int SetDescription(string szDescription); - - int SetHelpFile(string szHelpFile); - - int SetHelpContext(uint dwHelpContext); - } - - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] - struct WIN32_FIND_DATA { - public uint dwFileAttributes; - public System.Runtime.InteropServices.ComTypes.FILETIME ftCreationTime; - public System.Runtime.InteropServices.ComTypes.FILETIME ftLastAccessTime; - public System.Runtime.InteropServices.ComTypes.FILETIME ftLastWriteTime; - public uint nFileSizeHigh; - public uint nFileSizeLow; - public uint dwReserved0; - public uint dwReserved1; - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] - public string cFileName; - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)] - public string cAlternateFileName; - } - -} - diff --git a/Microsoft.VisualStudio.Project/Misc/UnsafeNativeMethods.cs b/Microsoft.VisualStudio.Project/Misc/UnsafeNativeMethods.cs deleted file mode 100644 index 0b2670c8..00000000 --- a/Microsoft.VisualStudio.Project/Misc/UnsafeNativeMethods.cs +++ /dev/null @@ -1,62 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Runtime.InteropServices; - -namespace Microsoft.VisualStudioTools.Project { - internal static class UnsafeNativeMethods { - [DllImport(ExternDll.Kernel32, EntryPoint = "GlobalLock", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)] - internal static extern IntPtr GlobalLock(IntPtr h); - - [DllImport(ExternDll.Kernel32, EntryPoint = "GlobalUnlock", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)] - internal static extern bool GlobalUnLock(IntPtr h); - - [DllImport(ExternDll.Kernel32, EntryPoint = "GlobalSize", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)] - internal static extern IntPtr GlobalSize(IntPtr h); - - [DllImport(ExternDll.Ole32, ExactSpelling = true, CharSet = CharSet.Unicode)] - internal static extern int OleSetClipboard(Microsoft.VisualStudio.OLE.Interop.IDataObject dataObject); - - [DllImport(ExternDll.Ole32, ExactSpelling = true, CharSet = CharSet.Unicode)] - internal static extern int OleGetClipboard(out Microsoft.VisualStudio.OLE.Interop.IDataObject dataObject); - - [DllImport(ExternDll.Ole32, ExactSpelling = true, CharSet = CharSet.Unicode)] - internal static extern int OleFlushClipboard(); - - [DllImport(ExternDll.User32, ExactSpelling = true, CharSet = CharSet.Unicode)] - internal static extern int OpenClipboard(IntPtr newOwner); - - [DllImport(ExternDll.User32, ExactSpelling = true, CharSet = CharSet.Unicode)] - internal static extern int EmptyClipboard(); - - [DllImport(ExternDll.User32, ExactSpelling = true, CharSet = CharSet.Unicode)] - internal static extern int CloseClipboard(); - - [DllImport(ExternDll.Comctl32, CharSet = CharSet.Auto)] - internal static extern int ImageList_GetImageCount(HandleRef himl); - - [DllImport(ExternDll.Comctl32, CharSet = CharSet.Auto)] - internal static extern bool ImageList_Draw(HandleRef himl, int i, HandleRef hdcDst, int x, int y, int fStyle); - - [DllImport(ExternDll.Shell32, EntryPoint = "DragQueryFileW", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)] - internal static extern uint DragQueryFile(IntPtr hDrop, uint iFile, char[] lpszFile, uint cch); - - [DllImport(ExternDll.User32, SetLastError = true, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)] - internal static extern uint RegisterClipboardFormat(string format); - } -} - diff --git a/Microsoft.VisualStudio.Project/MsBuildProjectElement.cs b/Microsoft.VisualStudio.Project/MsBuildProjectElement.cs deleted file mode 100644 index 455b34a3..00000000 --- a/Microsoft.VisualStudio.Project/MsBuildProjectElement.cs +++ /dev/null @@ -1,197 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Runtime.InteropServices; -using Microsoft.Build.Evaluation; -using Microsoft.VisualStudio; -using MSBuild = Microsoft.Build.Evaluation; - -namespace Microsoft.VisualStudioTools.Project { - internal class MsBuildProjectElement : ProjectElement { - private MSBuild.ProjectItem _item; - private string _url; // cached Url - - /// - /// Constructor to create a new MSBuild.ProjectItem and add it to the project - /// Only have internal constructors as the only one who should be creating - /// such object is the project itself (see Project.CreateFileNode()). - /// - internal MsBuildProjectElement(ProjectNode project, string itemPath, string itemType) - : base(project) { - Utilities.ArgumentNotNullOrEmpty("itemPath", itemPath); - Utilities.ArgumentNotNullOrEmpty("itemType", itemType); - - // create and add the item to the project - - _item = project.BuildProject.AddItem(itemType, Microsoft.Build.Evaluation.ProjectCollection.Escape(itemPath))[0]; - _url = base.Url; - } - - /// - /// Constructor to Wrap an existing MSBuild.ProjectItem - /// Only have internal constructors as the only one who should be creating - /// such object is the project itself (see Project.CreateFileNode()). - /// - /// Project that owns this item - /// an MSBuild.ProjectItem; can be null if virtualFolder is true - /// Is this item virtual (such as reference folder) - internal MsBuildProjectElement(ProjectNode project, MSBuild.ProjectItem existingItem) - : base(project) { - Utilities.ArgumentNotNull("existingItem", existingItem); - - // Keep a reference to project and item - _item = existingItem; - _url = base.Url; - } - - protected override string ItemType { - get { - return _item.ItemType; - } - set { - _item.ItemType = value; - OnItemTypeChanged(); - } - } - - /// - /// Set an attribute on the project element - /// - /// Name of the attribute to set - /// Value to give to the attribute - public override void SetMetadata(string attributeName, string attributeValue) { - Debug.Assert(String.Compare(attributeName, ProjectFileConstants.Include, StringComparison.OrdinalIgnoreCase) != 0, "Use rename as this won't work"); - - // Build Action is the type, not a property, so intercept - if (String.Compare(attributeName, ProjectFileConstants.BuildAction, StringComparison.OrdinalIgnoreCase) == 0) { - _item.ItemType = attributeValue; - return; - } - - // Check out the project file. - if (!ItemProject.QueryEditProjectFile(false)) { - throw Marshal.GetExceptionForHR(VSConstants.OLE_E_PROMPTSAVECANCELLED); - } - - if (attributeValue == null) { - _item.RemoveMetadata(attributeName); - } else { - _item.SetMetadataValue(attributeName, attributeValue); - } - } - - /// - /// Get the value of an attribute on a project element - /// - /// Name of the attribute to get the value for - /// Value of the attribute - public override string GetMetadata(string attributeName) { - // cannot ask MSBuild for Include, so intercept it and return the corresponding property - if (String.Compare(attributeName, ProjectFileConstants.Include, StringComparison.OrdinalIgnoreCase) == 0) { - return _item.EvaluatedInclude; - } - - // Build Action is the type, not a property, so intercept this one as well - if (String.Compare(attributeName, ProjectFileConstants.BuildAction, StringComparison.OrdinalIgnoreCase) == 0) { - return _item.ItemType; - } - - return _item.GetMetadataValue(attributeName); - } - - public override void Rename(string newPath) { - string escapedPath = Microsoft.Build.Evaluation.ProjectCollection.Escape(newPath); - - _item.Rename(escapedPath); - this.RefreshProperties(); - } - - public override void RefreshProperties() { - ItemProject.BuildProject.ReevaluateIfNecessary(); - - _url = base.Url; - - IEnumerable items = ItemProject.BuildProject.GetItems(_item.ItemType); - foreach (ProjectItem projectItem in items) { - if (projectItem != null && projectItem.UnevaluatedInclude.Equals(_item.UnevaluatedInclude)) { - _item = projectItem; - return; - } - } - } - - /// - /// Calling this method remove this item from the project file. - /// Once the item is delete, you should not longer be using it. - /// Note that the item should be removed from the hierarchy prior to this call. - /// - public override void RemoveFromProjectFile() { - if (!Deleted) { - ItemProject.BuildProject.RemoveItem(_item); - } - - base.RemoveFromProjectFile(); - } - - internal MSBuild.ProjectItem Item { - get { - return _item; - } - } - - public override string Url { - get { - return _url; - } - } - - public override bool Equals(object obj) { - // Do they reference the same element? - if (Object.ReferenceEquals(this, obj)) { - return true; - } - - MsBuildProjectElement msBuildProjElem = obj as MsBuildProjectElement; - if (Object.ReferenceEquals(msBuildProjElem, null)) { - return false; - } - - // Do they reference the same project? - if (!ItemProject.Equals(msBuildProjElem.ItemProject)) - return false; - - // Do they have the same include? - string include1 = GetMetadata(ProjectFileConstants.Include); - string include2 = msBuildProjElem.GetMetadata(ProjectFileConstants.Include); - - // Unfortunately the checking for nulls have to be done again, since neither String.Equals nor String.Compare can handle nulls. - // Virtual folders should not be handled here. - if (include1 == null || include2 == null) { - return false; - } - - return String.Equals(include1, include2, StringComparison.OrdinalIgnoreCase); - } - - public override int GetHashCode() { - return StringComparer.OrdinalIgnoreCase.GetHashCode(GetMetadata(ProjectFileConstants.Include)); - } - } -} diff --git a/Microsoft.VisualStudio.Project/Navigation/CommonLibraryNode.cs b/Microsoft.VisualStudio.Project/Navigation/CommonLibraryNode.cs deleted file mode 100644 index b7abac97..00000000 --- a/Microsoft.VisualStudio.Project/Navigation/CommonLibraryNode.cs +++ /dev/null @@ -1,224 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Globalization; -using System.Runtime.InteropServices; -using Microsoft.VisualStudio.Shell; -using Microsoft.VisualStudio.Shell.Interop; -using Microsoft.VisualStudio.TextManager.Interop; -using Microsoft.VisualStudioTools.Parsing; -using ErrorHandler = Microsoft.VisualStudio.ErrorHandler; -using VSConstants = Microsoft.VisualStudio.VSConstants; - -namespace Microsoft.VisualStudioTools.Navigation { - - /// - /// This is a specialized version of the LibraryNode that handles the dynamic languages - /// items. The main difference from the generic one is that it supports navigation - /// to the location inside the source code where the element is defined. - /// - internal abstract class CommonLibraryNode : LibraryNode { - private readonly IVsHierarchy _ownerHierarchy; - private readonly uint _fileId; - private readonly TextSpan _sourceSpan; - private readonly IScopeNode _scope; - private string _fileMoniker; - - protected CommonLibraryNode(LibraryNode parent, IScopeNode scope, string namePrefix, IVsHierarchy hierarchy, uint itemId) : - base(parent, GetLibraryNodeName(scope, namePrefix), namePrefix + scope.Name, scope.NodeType) { - _ownerHierarchy = hierarchy; - _fileId = itemId; - - // Now check if we have all the information to navigate to the source location. - if ((null != _ownerHierarchy) && (VSConstants.VSITEMID_NIL != _fileId)) { - if ((SourceLocation.Invalid != scope.Start) && (SourceLocation.Invalid != scope.End)) { - _sourceSpan = new TextSpan(); - _sourceSpan.iStartIndex = scope.Start.Column - 1; - if (scope.Start.Line > 0) { - _sourceSpan.iStartLine = scope.Start.Line - 1; - } - _sourceSpan.iEndIndex = scope.End.Column; - if (scope.End.Line > 0) { - _sourceSpan.iEndLine = scope.End.Line - 1; - } - CanGoToSource = true; - } - } - _scope = scope; - } - - internal IScopeNode ScopeNode { - get { - return _scope; - } - } - - public TextSpan SourceSpan { - get { - return _sourceSpan; - } - } - - private static string GetLibraryNodeName(IScopeNode node, string namePrefix) { - namePrefix = namePrefix.Substring(namePrefix.LastIndexOf(':') + 1); // remove filename prefix - return node.NodeType == LibraryNodeType.Members ? node.Name : string.Format(CultureInfo.InvariantCulture, "{0}{1}", namePrefix, node.Name); - } - - protected CommonLibraryNode(CommonLibraryNode node) : - base(node) { - _fileId = node._fileId; - _ownerHierarchy = node._ownerHierarchy; - _fileMoniker = node._fileMoniker; - _sourceSpan = node._sourceSpan; - } - - protected CommonLibraryNode(CommonLibraryNode node, string newFullName) : - base(node, newFullName) { - _scope = node._scope; - _fileId = node._fileId; - _ownerHierarchy = node._ownerHierarchy; - _fileMoniker = node._fileMoniker; - _sourceSpan = node._sourceSpan; - } - - public override uint CategoryField(LIB_CATEGORY category) { - switch (category) { - case (LIB_CATEGORY)_LIB_CATEGORY2.LC_MEMBERINHERITANCE: - if (NodeType == LibraryNodeType.Members || NodeType == LibraryNodeType.Definitions) { - return (uint)_LIBCAT_MEMBERINHERITANCE.LCMI_IMMEDIATE; - } - break; - } - return base.CategoryField(category); - } - - public override void GotoSource(VSOBJGOTOSRCTYPE gotoType) { - // We do not support the "Goto Reference" - if (VSOBJGOTOSRCTYPE.GS_REFERENCE == gotoType) { - return; - } - - // There is no difference between definition and declaration, so here we - // don't check for the other flags. - - IVsWindowFrame frame = null; - IntPtr documentData = FindDocDataFromRDT(); - try { - // Now we can try to open the editor. We assume that the owner hierarchy is - // a project and we want to use its OpenItem method. - IVsProject3 project = _ownerHierarchy as IVsProject3; - if (null == project) { - return; - } - Guid viewGuid = VSConstants.LOGVIEWID_Code; - ErrorHandler.ThrowOnFailure(project.OpenItem(_fileId, ref viewGuid, documentData, out frame)); - } finally { - if (IntPtr.Zero != documentData) { - Marshal.Release(documentData); - documentData = IntPtr.Zero; - } - } - - // Make sure that the document window is visible. - ErrorHandler.ThrowOnFailure(frame.Show()); - - // Get the code window from the window frame. - object docView; - ErrorHandler.ThrowOnFailure(frame.GetProperty((int)__VSFPROPID.VSFPROPID_DocView, out docView)); - IVsCodeWindow codeWindow = docView as IVsCodeWindow; - if (null == codeWindow) { - object docData; - ErrorHandler.ThrowOnFailure(frame.GetProperty((int)__VSFPROPID.VSFPROPID_DocData, out docData)); - codeWindow = docData as IVsCodeWindow; - if (null == codeWindow) { - return; - } - } - - // Get the primary view from the code window. - IVsTextView textView; - ErrorHandler.ThrowOnFailure(codeWindow.GetPrimaryView(out textView)); - - // Set the cursor at the beginning of the declaration. - ErrorHandler.ThrowOnFailure(textView.SetCaretPos(_sourceSpan.iStartLine, _sourceSpan.iStartIndex)); - // Make sure that the text is visible. - TextSpan visibleSpan = new TextSpan(); - visibleSpan.iStartLine = _sourceSpan.iStartLine; - visibleSpan.iStartIndex = _sourceSpan.iStartIndex; - visibleSpan.iEndLine = _sourceSpan.iStartLine; - visibleSpan.iEndIndex = _sourceSpan.iStartIndex + 1; - ErrorHandler.ThrowOnFailure(textView.EnsureSpanVisible(visibleSpan)); - - } - - public override void SourceItems(out IVsHierarchy hierarchy, out uint itemId, out uint itemsCount) { - hierarchy = _ownerHierarchy; - itemId = _fileId; - itemsCount = 1; - } - - public override string UniqueName { - get { - if (string.IsNullOrEmpty(_fileMoniker)) { - ErrorHandler.ThrowOnFailure(_ownerHierarchy.GetCanonicalName(_fileId, out _fileMoniker)); - } - return string.Format(CultureInfo.InvariantCulture, "{0}/{1}", _fileMoniker, Name); - } - } - - private IntPtr FindDocDataFromRDT() { - // Get a reference to the RDT. - IVsRunningDocumentTable rdt = Package.GetGlobalService(typeof(SVsRunningDocumentTable)) as IVsRunningDocumentTable; - if (null == rdt) { - return IntPtr.Zero; - } - - // Get the enumeration of the running documents. - IEnumRunningDocuments documents; - ErrorHandler.ThrowOnFailure(rdt.GetRunningDocumentsEnum(out documents)); - - IntPtr documentData = IntPtr.Zero; - uint[] docCookie = new uint[1]; - uint fetched; - while ((VSConstants.S_OK == documents.Next(1, docCookie, out fetched)) && (1 == fetched)) { - uint flags; - uint editLocks; - uint readLocks; - string moniker; - IVsHierarchy docHierarchy; - uint docId; - IntPtr docData = IntPtr.Zero; - try { - ErrorHandler.ThrowOnFailure( - rdt.GetDocumentInfo(docCookie[0], out flags, out readLocks, out editLocks, out moniker, out docHierarchy, out docId, out docData)); - // Check if this document is the one we are looking for. - if ((docId == _fileId) && (_ownerHierarchy.Equals(docHierarchy))) { - documentData = docData; - docData = IntPtr.Zero; - break; - } - } finally { - if (IntPtr.Zero != docData) { - Marshal.Release(docData); - } - } - } - - return documentData; - } - } -} diff --git a/Microsoft.VisualStudio.Project/Navigation/HierarchyListener.cs b/Microsoft.VisualStudio.Project/Navigation/HierarchyListener.cs deleted file mode 100644 index 08f803f4..00000000 --- a/Microsoft.VisualStudio.Project/Navigation/HierarchyListener.cs +++ /dev/null @@ -1,252 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.Shell.Interop; -using Microsoft.VisualStudio.TextManager.Interop; -using Microsoft.VisualStudioTools.Project; -using VSConstants = Microsoft.VisualStudio.VSConstants; - -namespace Microsoft.VisualStudioTools.Navigation { - class HierarchyEventArgs : EventArgs { - private uint _itemId; - private string _fileName; - private IVsTextLines _buffer; - - public HierarchyEventArgs(uint itemId, string canonicalName) { - _itemId = itemId; - _fileName = canonicalName; - } - public string CanonicalName { - get { return _fileName; } - } - public uint ItemID { - get { return _itemId; } - } - public IVsTextLines TextBuffer { - get { return _buffer; } - set { _buffer = value; } - } - } - - internal abstract partial class LibraryManager : IDisposable, IVsRunningDocTableEvents { - internal class HierarchyListener : IVsHierarchyEvents, IDisposable { - private IVsHierarchy _hierarchy; - private uint _cookie; - private LibraryManager _manager; - - public HierarchyListener(IVsHierarchy hierarchy, LibraryManager manager) { - Utilities.ArgumentNotNull("hierarchy", hierarchy); - Utilities.ArgumentNotNull("manager", manager); - - _hierarchy = hierarchy; - _manager = manager; - } - - protected IVsHierarchy Hierarchy { - get { return _hierarchy; } - } - - #region Public Methods - public bool IsListening { - get { return (0 != _cookie); } - } - public void StartListening(bool doInitialScan) { - if (0 != _cookie) { - return; - } - ErrorHandler.ThrowOnFailure( - _hierarchy.AdviseHierarchyEvents(this, out _cookie)); - if (doInitialScan) { - InternalScanHierarchy(VSConstants.VSITEMID_ROOT); - } - } - public void StopListening() { - InternalStopListening(true); - } - #endregion - - #region IDisposable Members - - public void Dispose() { - InternalStopListening(false); - _cookie = 0; - _hierarchy = null; - } - - #endregion - #region IVsHierarchyEvents Members - - public int OnInvalidateIcon(IntPtr hicon) { - // Do Nothing. - return VSConstants.S_OK; - } - - public int OnInvalidateItems(uint itemidParent) { - // TODO: Find out if this event is needed. - return VSConstants.S_OK; - } - - public int OnItemAdded(uint itemidParent, uint itemidSiblingPrev, uint itemidAdded) { - // Check if the item is my language file. - string name; - if (!IsAnalyzableSource(itemidAdded, out name)) { - return VSConstants.S_OK; - } - - // This item is a my language file, so we can notify that it is added to the hierarchy. - HierarchyEventArgs args = new HierarchyEventArgs(itemidAdded, name); - _manager.OnNewFile(_hierarchy, args); - return VSConstants.S_OK; - } - - public int OnItemDeleted(uint itemid) { - // Notify that the item is deleted only if it is my language file. - string name; - if (!IsAnalyzableSource(itemid, out name)) { - return VSConstants.S_OK; - } - HierarchyEventArgs args = new HierarchyEventArgs(itemid, name); - _manager.OnDeleteFile(_hierarchy, args); - return VSConstants.S_OK; - } - - public int OnItemsAppended(uint itemidParent) { - // TODO: Find out what this event is about. - return VSConstants.S_OK; - } - - public int OnPropertyChanged(uint itemid, int propid, uint flags) { - if ((null == _hierarchy) || (0 == _cookie)) { - return VSConstants.S_OK; - } - string name; - if (!IsAnalyzableSource(itemid, out name)) { - return VSConstants.S_OK; - } - if (propid == (int)__VSHPROPID.VSHPROPID_IsNonMemberItem) { - _manager.IsNonMemberItemChanged(_hierarchy, new HierarchyEventArgs(itemid, name)); - } - return VSConstants.S_OK; - } - #endregion - - private bool InternalStopListening(bool throwOnError) { - if ((null == _hierarchy) || (0 == _cookie)) { - return false; - } - int hr = _hierarchy.UnadviseHierarchyEvents(_cookie); - if (throwOnError) { - ErrorHandler.ThrowOnFailure(hr); - } - _cookie = 0; - return ErrorHandler.Succeeded(hr); - } - - /// - /// Do a recursive walk on the hierarchy to find all this language files in it. - /// It will generate an event for every file found. - /// - private void InternalScanHierarchy(uint itemId) { - uint currentItem = itemId; - while (VSConstants.VSITEMID_NIL != currentItem) { - // If this item is a my language file, then send the add item event. - string itemName; - if (IsAnalyzableSource(currentItem, out itemName)) { - HierarchyEventArgs args = new HierarchyEventArgs(currentItem, itemName); - _manager.OnNewFile(_hierarchy, args); - } - - // NOTE: At the moment we skip the nested hierarchies, so here we look for the - // children of this node. - // Before looking at the children we have to make sure that the enumeration has not - // side effects to avoid unexpected behavior. - object propertyValue; - bool canScanSubitems = true; - int hr = _hierarchy.GetProperty(currentItem, (int)__VSHPROPID.VSHPROPID_HasEnumerationSideEffects, out propertyValue); - if ((VSConstants.S_OK == hr) && (propertyValue is bool)) { - canScanSubitems = !(bool)propertyValue; - } - // If it is allow to look at the sub-items of the current one, lets do it. - if (canScanSubitems) { - object child; - hr = _hierarchy.GetProperty(currentItem, (int)__VSHPROPID.VSHPROPID_FirstChild, out child); - if (VSConstants.S_OK == hr) { - // There is a sub-item, call this same function on it. - InternalScanHierarchy(GetItemId(child)); - } - } - - // Move the current item to its first visible sibling. - object sibling; - hr = _hierarchy.GetProperty(currentItem, (int)__VSHPROPID.VSHPROPID_NextSibling, out sibling); - if (VSConstants.S_OK != hr) { - currentItem = VSConstants.VSITEMID_NIL; - } else { - currentItem = GetItemId(sibling); - } - } - } - - private bool IsAnalyzableSource(uint itemId, out string canonicalName) { - // Find out if this item is a physical file. - Guid typeGuid; - canonicalName = null; - int hr; - try { - hr = Hierarchy.GetGuidProperty(itemId, (int)__VSHPROPID.VSHPROPID_TypeGuid, out typeGuid); - } catch (System.Runtime.InteropServices.COMException) { - return false; - } - if (Microsoft.VisualStudio.ErrorHandler.Failed(hr) || - VSConstants.GUID_ItemType_PhysicalFile != typeGuid) { - // It is not a file, we can exit now. - return false; - } - - // This item is a file; find if current language can recognize it. - hr = Hierarchy.GetCanonicalName(itemId, out canonicalName); - if (ErrorHandler.Failed(hr)) { - return false; - } - return (System.IO.Path.GetExtension(canonicalName).Equals(".xaml", StringComparison.OrdinalIgnoreCase)) || - _manager._package.IsRecognizedFile(canonicalName); - } - - /// - /// Gets the item id. - /// - /// VARIANT holding an itemid. - /// Item Id of the concerned node - private static uint GetItemId(object variantValue) { - if (variantValue == null) - return VSConstants.VSITEMID_NIL; - if (variantValue is int) - return (uint)(int)variantValue; - if (variantValue is uint) - return (uint)variantValue; - if (variantValue is short) - return (uint)(short)variantValue; - if (variantValue is ushort) - return (uint)(ushort)variantValue; - if (variantValue is long) - return (uint)(long)variantValue; - return VSConstants.VSITEMID_NIL; - } - } - } -} diff --git a/Microsoft.VisualStudio.Project/Navigation/ICustomSearchListProvider.cs b/Microsoft.VisualStudio.Project/Navigation/ICustomSearchListProvider.cs deleted file mode 100644 index ac803972..00000000 --- a/Microsoft.VisualStudio.Project/Navigation/ICustomSearchListProvider.cs +++ /dev/null @@ -1,23 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using Microsoft.VisualStudio.Shell.Interop; - -namespace Microsoft.VisualStudioTools.Navigation { - interface ICustomSearchListProvider { - IVsSimpleObjectList2 GetSearchList(); - } -} diff --git a/Microsoft.VisualStudio.Project/Navigation/ILibraryManager.cs b/Microsoft.VisualStudio.Project/Navigation/ILibraryManager.cs deleted file mode 100644 index 8c636829..00000000 --- a/Microsoft.VisualStudio.Project/Navigation/ILibraryManager.cs +++ /dev/null @@ -1,32 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using Microsoft.VisualStudio.Shell.Interop; -using Microsoft.VisualStudio.TextManager.Interop; - -namespace Microsoft.VisualStudioTools.Navigation { - /// - /// This interface defines the service that finds current language files inside a hierarchy - /// and builds information to expose to the class view or object browser. - /// - internal interface ILibraryManager { - void RegisterHierarchy(IVsHierarchy hierarchy); - void UnregisterHierarchy(IVsHierarchy hierarchy); - void RegisterLineChangeHandler(uint document, TextLineChangeEvent lineChanged, Action onIdle); - } - internal delegate void TextLineChangeEvent(object sender, TextLineChange[] changes, int last); -} diff --git a/Microsoft.VisualStudio.Project/Navigation/IScopeNode.cs b/Microsoft.VisualStudio.Project/Navigation/IScopeNode.cs deleted file mode 100644 index 8b691d24..00000000 --- a/Microsoft.VisualStudio.Project/Navigation/IScopeNode.cs +++ /dev/null @@ -1,45 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System.Collections.Generic; -using Microsoft.VisualStudioTools.Parsing; - -namespace Microsoft.VisualStudioTools.Navigation { - interface IScopeNode { - LibraryNodeType NodeType { - get; - } - - string Name { - get; - } - - string Description { - get; - } - - SourceLocation Start { - get; - } - SourceLocation End { - get; - } - - IEnumerable NestedScopes { - get; - } - } -} diff --git a/Microsoft.VisualStudio.Project/Navigation/ISimpleObject.cs b/Microsoft.VisualStudio.Project/Navigation/ISimpleObject.cs deleted file mode 100644 index 09141b2f..00000000 --- a/Microsoft.VisualStudio.Project/Navigation/ISimpleObject.cs +++ /dev/null @@ -1,49 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System.ComponentModel.Design; -using Microsoft.VisualStudio.Shell; -using Microsoft.VisualStudio.Shell.Interop; - -namespace Microsoft.VisualStudioTools.Navigation { - public interface ISimpleObject { - bool CanDelete { get; } - bool CanGoToSource { get; } - bool CanRename { get; } - string Name { get; } - string UniqueName { get; } - string FullName { get; } - string GetTextRepresentation(VSTREETEXTOPTIONS options); - string TooltipText { get; } - object BrowseObject { get; } - CommandID ContextMenuID { get; } - VSTREEDISPLAYDATA DisplayData { get; } - - uint CategoryField(LIB_CATEGORY lIB_CATEGORY); - - void Delete(); - void DoDragDrop(OleDataObject dataObject, uint grfKeyState, uint pdwEffect); - void Rename(string pszNewName, uint grfFlags); - void GotoSource(VSOBJGOTOSRCTYPE SrcType); - - void SourceItems(out IVsHierarchy ppHier, out uint pItemid, out uint pcItems); - uint EnumClipboardFormats(_VSOBJCFFLAGS _VSOBJCFFLAGS, VSOBJCLIPFORMAT[] rgcfFormats); - void FillDescription(_VSOBJDESCOPTIONS _VSOBJDESCOPTIONS, IVsObjectBrowserDescription3 pobDesc); - - IVsSimpleObjectList2 FilterView(uint ListType); - } - -} diff --git a/Microsoft.VisualStudio.Project/Navigation/Library.cs b/Microsoft.VisualStudio.Project/Navigation/Library.cs deleted file mode 100644 index 1fd8733a..00000000 --- a/Microsoft.VisualStudio.Project/Navigation/Library.cs +++ /dev/null @@ -1,193 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Threading; -using Microsoft.VisualStudio.OLE.Interop; -using Microsoft.VisualStudio.Shell.Interop; -using VSConstants = Microsoft.VisualStudio.VSConstants; - -namespace Microsoft.VisualStudioTools.Navigation { - - /// - /// Implements a simple library that tracks project symbols, objects etc. - /// - class Library : IVsSimpleLibrary2 { - private Guid _guid; - private _LIB_FLAGS2 _capabilities; - private LibraryNode _root; - private uint _updateCount; - - public Library(Guid libraryGuid) { - _guid = libraryGuid; - _root = new LibraryNode(null, String.Empty, String.Empty, LibraryNodeType.Package); - } - - public _LIB_FLAGS2 LibraryCapabilities { - get { return _capabilities; } - set { _capabilities = value; } - } - - internal void AddNode(LibraryNode node) { - lock (this) { - // re-create root node here because we may have handed out the node before and don't want to mutate it's list. - _root = _root.Clone(); - _root.AddNode(node); - _updateCount++; - } - } - - internal void RemoveNode(LibraryNode node) { - lock (this) { - _root = _root.Clone(); - _root.RemoveNode(node); - _updateCount++; - } - } - - #region IVsSimpleLibrary2 Members - - public int AddBrowseContainer(VSCOMPONENTSELECTORDATA[] pcdComponent, ref uint pgrfOptions, out string pbstrComponentAdded) { - pbstrComponentAdded = null; - return VSConstants.E_NOTIMPL; - } - - public int CreateNavInfo(SYMBOL_DESCRIPTION_NODE[] rgSymbolNodes, uint ulcNodes, out IVsNavInfo ppNavInfo) { - ppNavInfo = null; - return VSConstants.E_NOTIMPL; - } - - public int GetBrowseContainersForHierarchy(IVsHierarchy pHierarchy, uint celt, VSBROWSECONTAINER[] rgBrowseContainers, uint[] pcActual) { - return VSConstants.E_NOTIMPL; - } - - public int GetGuid(out Guid pguidLib) { - pguidLib = _guid; - return VSConstants.S_OK; - } - - public int GetLibFlags2(out uint pgrfFlags) { - pgrfFlags = (uint)LibraryCapabilities; - return VSConstants.S_OK; - } - - public int GetList2(uint ListType, uint flags, VSOBSEARCHCRITERIA2[] pobSrch, out IVsSimpleObjectList2 ppIVsSimpleObjectList2) { - if ((flags & (uint)_LIB_LISTFLAGS.LLF_RESOURCEVIEW) != 0) { - ppIVsSimpleObjectList2 = null; - return VSConstants.E_NOTIMPL; - } - - ICustomSearchListProvider listProvider; - if (pobSrch != null && - pobSrch.Length > 0) { - if ((listProvider = pobSrch[0].pIVsNavInfo as ICustomSearchListProvider) != null) { - switch ((_LIB_LISTTYPE)ListType) { - case _LIB_LISTTYPE.LLT_NAMESPACES: - ppIVsSimpleObjectList2 = listProvider.GetSearchList(); - break; - default: - ppIVsSimpleObjectList2 = null; - return VSConstants.E_FAIL; - } - } else { - if (pobSrch[0].eSrchType == VSOBSEARCHTYPE.SO_ENTIREWORD && ListType == (uint)_LIB_LISTTYPE.LLT_MEMBERS) { - string srchText = pobSrch[0].szName; - int colonIndex; - if ((colonIndex = srchText.LastIndexOf(':')) != -1) { - string filename = srchText.Substring(0, srchText.LastIndexOf(':')); - foreach (ProjectLibraryNode project in _root.Children) { - foreach (var item in project.Children) { - if (item.FullName == filename) { - ppIVsSimpleObjectList2 = item.DoSearch(pobSrch[0]); - if (ppIVsSimpleObjectList2 != null) { - return VSConstants.S_OK; - } - } - } - } - } - - ppIVsSimpleObjectList2 = null; - return VSConstants.E_FAIL; - } else if (pobSrch[0].eSrchType == VSOBSEARCHTYPE.SO_SUBSTRING && ListType == (uint)_LIB_LISTTYPE.LLT_NAMESPACES) { - var lib = new LibraryNode(null, "Search results " + pobSrch[0].szName, "Search results " + pobSrch[0].szName, LibraryNodeType.Package); - foreach (var item in SearchNodes(pobSrch[0], new SimpleObjectList(), _root).Children) { - lib.Children.Add(item); - } - ppIVsSimpleObjectList2 = lib; - return VSConstants.S_OK; - } else { - ppIVsSimpleObjectList2 = null; - return VSConstants.E_FAIL; - } - } - } else { - ppIVsSimpleObjectList2 = _root as IVsSimpleObjectList2; - } - return VSConstants.S_OK; - } - - private static SimpleObjectList SearchNodes(VSOBSEARCHCRITERIA2 srch, SimpleObjectList list, LibraryNode curNode) { - foreach (var child in curNode.Children) { - if (child.Name.IndexOf(srch.szName, StringComparison.OrdinalIgnoreCase) != -1) { - list.Children.Add(child.Clone(child.Name)); - } - - SearchNodes(srch, list, child); - } - return list; - } - - public void VisitNodes(ILibraryNodeVisitor visitor, CancellationToken ct = default(CancellationToken)) { - lock (this) { - _root.Visit(visitor, ct); - } - } - - public int GetSeparatorStringWithOwnership(out string pbstrSeparator) { - pbstrSeparator = "."; - return VSConstants.S_OK; - } - - public int GetSupportedCategoryFields2(int Category, out uint pgrfCatField) { - pgrfCatField = (uint)_LIB_CATEGORY2.LC_HIERARCHYTYPE | (uint)_LIB_CATEGORY2.LC_PHYSICALCONTAINERTYPE; - return VSConstants.S_OK; - } - - public int LoadState(IStream pIStream, LIB_PERSISTTYPE lptType) { - return VSConstants.S_OK; - } - - public int RemoveBrowseContainer(uint dwReserved, string pszLibName) { - return VSConstants.E_NOTIMPL; - } - - public int SaveState(IStream pIStream, LIB_PERSISTTYPE lptType) { - return VSConstants.S_OK; - } - - public int UpdateCounter(out uint pCurUpdate) { - pCurUpdate = _updateCount; - return VSConstants.S_OK; - } - - public void Update() { - _updateCount++; - _root.Update(); - } - #endregion - } -} diff --git a/Microsoft.VisualStudio.Project/Navigation/LibraryManager.cs b/Microsoft.VisualStudio.Project/Navigation/LibraryManager.cs deleted file mode 100644 index 02188fea..00000000 --- a/Microsoft.VisualStudio.Project/Navigation/LibraryManager.cs +++ /dev/null @@ -1,502 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Collections.Generic; -using System.ComponentModel.Design; -using System.Diagnostics.Contracts; -using System.Runtime.InteropServices; -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.ComponentModelHost; -using Microsoft.VisualStudio.Editor; -using Microsoft.VisualStudio.OLE.Interop; -using Microsoft.VisualStudio.Shell.Interop; -using Microsoft.VisualStudio.Text; -using Microsoft.VisualStudio.TextManager.Interop; -using Microsoft.VisualStudioTools.Project; - -namespace Microsoft.VisualStudioTools.Navigation { - - /// - /// Inplementation of the service that builds the information to expose to the symbols - /// navigation tools (class view or object browser) from the source files inside a - /// hierarchy. - /// - internal abstract partial class LibraryManager : IDisposable, IVsRunningDocTableEvents { - private readonly CommonPackage/*!*/ _package; - private readonly Dictionary _documents; - private readonly Dictionary _hierarchies = new Dictionary(); - private readonly Dictionary _files; - private readonly Library _library; - private readonly IVsEditorAdaptersFactoryService _adapterFactory; - private uint _objectManagerCookie; - private uint _runningDocTableCookie; - - public LibraryManager(CommonPackage/*!*/ package) { - Contract.Assert(package != null); - _package = package; - _documents = new Dictionary(); - _library = new Library(new Guid(CommonConstants.LibraryGuid)); - _library.LibraryCapabilities = (_LIB_FLAGS2)_LIB_FLAGS.LF_PROJECT; - _files = new Dictionary(); - - var model = ((IServiceContainer)package).GetService(typeof(SComponentModel)) as IComponentModel; - _adapterFactory = model.GetService(); - - // Register our library now so it'll be available for find all references - RegisterLibrary(); - } - - public Library Library { - get { return _library; } - } - - protected abstract LibraryNode CreateLibraryNode(LibraryNode parent, IScopeNode subItem, string namePrefix, IVsHierarchy hierarchy, uint itemid); - - public virtual LibraryNode CreateFileLibraryNode(LibraryNode parent, HierarchyNode hierarchy, string name, string filename, LibraryNodeType libraryNodeType) { - return new LibraryNode(null, name, filename, libraryNodeType); - } - - private object GetPackageService(Type/*!*/ type) { - return ((System.IServiceProvider)_package).GetService(type); - } - - private void RegisterForRDTEvents() { - if (0 != _runningDocTableCookie) { - return; - } - IVsRunningDocumentTable rdt = GetPackageService(typeof(SVsRunningDocumentTable)) as IVsRunningDocumentTable; - if (null != rdt) { - // Do not throw here in case of error, simply skip the registration. - rdt.AdviseRunningDocTableEvents(this, out _runningDocTableCookie); - } - } - - private void UnregisterRDTEvents() { - if (0 == _runningDocTableCookie) { - return; - } - IVsRunningDocumentTable rdt = GetPackageService(typeof(SVsRunningDocumentTable)) as IVsRunningDocumentTable; - if (null != rdt) { - // Do not throw in case of error. - rdt.UnadviseRunningDocTableEvents(_runningDocTableCookie); - } - _runningDocTableCookie = 0; - } - - #region ILibraryManager Members - - public void RegisterHierarchy(IVsHierarchy hierarchy) { - if ((null == hierarchy) || _hierarchies.ContainsKey(hierarchy)) { - return; - } - - RegisterLibrary(); - var commonProject = hierarchy.GetProject().GetCommonProject(); - HierarchyListener listener = new HierarchyListener(hierarchy, this); - var node = _hierarchies[hierarchy] = new HierarchyInfo( - listener, - new ProjectLibraryNode(commonProject) - ); - _library.AddNode(node.ProjectLibraryNode); - listener.StartListening(true); - RegisterForRDTEvents(); - } - - private void RegisterLibrary() { - if (0 == _objectManagerCookie) { - IVsObjectManager2 objManager = GetPackageService(typeof(SVsObjectManager)) as IVsObjectManager2; - if (null == objManager) { - return; - } - Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure( - objManager.RegisterSimpleLibrary(_library, out _objectManagerCookie)); - } - } - - public void UnregisterHierarchy(IVsHierarchy hierarchy) { - if ((null == hierarchy) || !_hierarchies.ContainsKey(hierarchy)) { - return; - } - HierarchyInfo info = _hierarchies[hierarchy]; - if (null != info) { - info.Listener.Dispose(); - } - _hierarchies.Remove(hierarchy); - _library.RemoveNode(info.ProjectLibraryNode); - if (0 == _hierarchies.Count) { - UnregisterRDTEvents(); - } - lock (_files) { - ModuleId[] keys = new ModuleId[_files.Keys.Count]; - _files.Keys.CopyTo(keys, 0); - foreach (ModuleId id in keys) { - if (hierarchy.Equals(id.Hierarchy)) { - _library.RemoveNode(_files[id]); - _files.Remove(id); - } - } - } - // Remove the document listeners. - uint[] docKeys = new uint[_documents.Keys.Count]; - _documents.Keys.CopyTo(docKeys, 0); - foreach (uint id in docKeys) { - TextLineEventListener docListener = _documents[id]; - if (hierarchy.Equals(docListener.FileID.Hierarchy)) { - _documents.Remove(id); - docListener.Dispose(); - } - } - } - - public void RegisterLineChangeHandler(uint document, - TextLineChangeEvent lineChanged, Action onIdle) { - _documents[document].OnFileChangedImmediate += delegate(object sender, TextLineChange[] changes, int fLast) { - lineChanged(sender, changes, fLast); - }; - _documents[document].OnFileChanged += (sender, args) => onIdle(args.TextBuffer); - } - - #endregion - - #region Library Member Production - - /// - /// Overridden in the base class to receive notifications of when a file should - /// be analyzed for inclusion in the library. The derived class should queue - /// the parsing of the file and when it's complete it should call FileParsed - /// with the provided LibraryTask and an IScopeNode which provides information - /// about the members of the file. - /// - protected virtual void OnNewFile(LibraryTask task) { - } - - /// - /// Called by derived class when a file has been parsed. The caller should - /// provide the LibraryTask received from the OnNewFile call and an IScopeNode - /// which represents the contents of the library. - /// - /// It is safe to call this method from any thread. - /// - protected void FileParsed(LibraryTask task, IScopeNode scope) { - try { - var project = task.ModuleID.Hierarchy.GetProject().GetCommonProject(); - - HierarchyNode fileNode = fileNode = project.NodeFromItemId(task.ModuleID.ItemID); - HierarchyInfo parent; - if (fileNode == null || !_hierarchies.TryGetValue(task.ModuleID.Hierarchy, out parent)) { - return; - } - - LibraryNode module = CreateFileLibraryNode( - parent.ProjectLibraryNode, - fileNode, - System.IO.Path.GetFileName(task.FileName), - task.FileName, - LibraryNodeType.Package | LibraryNodeType.Classes - ); - - // TODO: Creating the module tree should be done lazily as needed - // Currently we replace the entire tree and rely upon the libraries - // update count to invalidate the whole thing. We could do this - // finer grained and only update the changed nodes. But then we - // need to make sure we're not mutating lists which are handed out. - - CreateModuleTree(module, scope, task.FileName + ":", task.ModuleID); - if (null != task.ModuleID) { - LibraryNode previousItem = null; - lock (_files) { - if (_files.TryGetValue(task.ModuleID, out previousItem)) { - _files.Remove(task.ModuleID); - parent.ProjectLibraryNode.RemoveNode(previousItem); - } - } - } - parent.ProjectLibraryNode.AddNode(module); - _library.Update(); - if (null != task.ModuleID) { - lock (_files) { - _files.Add(task.ModuleID, module); - } - } - } catch (COMException) { - // we're shutting down and can't get the project - } - } - - private void CreateModuleTree(LibraryNode current, IScopeNode scope, string namePrefix, ModuleId moduleId) { - if ((null == scope) || (null == scope.NestedScopes)) { - return; - } - - foreach (IScopeNode subItem in scope.NestedScopes) { - LibraryNode newNode = CreateLibraryNode(current, subItem, namePrefix, moduleId.Hierarchy, moduleId.ItemID); - string newNamePrefix = namePrefix; - - current.AddNode(newNode); - if ((newNode.NodeType & LibraryNodeType.Classes) != LibraryNodeType.None) { - newNamePrefix = namePrefix + newNode.Name + "."; - } - - // Now use recursion to get the other types. - CreateModuleTree(newNode, subItem, newNamePrefix, moduleId); - } - } - #endregion - - #region Hierarchy Events - - private void OnNewFile(object sender, HierarchyEventArgs args) { - IVsHierarchy hierarchy = sender as IVsHierarchy; - if (null == hierarchy || IsNonMemberItem(hierarchy, args.ItemID)) { - return; - } - - ITextBuffer buffer = null; - if (null != args.TextBuffer) { - buffer = _adapterFactory.GetDocumentBuffer(args.TextBuffer); - } - - var id = new ModuleId(hierarchy, args.ItemID); - OnNewFile(new LibraryTask(args.CanonicalName, buffer, new ModuleId(hierarchy, args.ItemID))); - } - - /// - /// Handles the delete event, checking to see if this is a project item. - /// - /// - /// - private void OnDeleteFile(object sender, HierarchyEventArgs args) { - IVsHierarchy hierarchy = sender as IVsHierarchy; - if (null == hierarchy || IsNonMemberItem(hierarchy, args.ItemID)) { - return; - } - - OnDeleteFile(hierarchy, args); - } - - /// - /// Does a delete w/o checking if it's a non-meber item, for handling the - /// transition from member item to non-member item. - /// - private void OnDeleteFile(IVsHierarchy hierarchy, HierarchyEventArgs args) { - ModuleId id = new ModuleId(hierarchy, args.ItemID); - LibraryNode node = null; - lock (_files) { - if (_files.TryGetValue(id, out node)) { - _files.Remove(id); - HierarchyInfo parent; - if (_hierarchies.TryGetValue(hierarchy, out parent)) { - parent.ProjectLibraryNode.RemoveNode(node); - } - } - } - if (null != node) { - _library.RemoveNode(node); - } - } - - private void IsNonMemberItemChanged(object sender, HierarchyEventArgs args) { - IVsHierarchy hierarchy = sender as IVsHierarchy; - if (null == hierarchy) { - return; - } - - if (!IsNonMemberItem(hierarchy, args.ItemID)) { - OnNewFile(hierarchy, args); - } else { - OnDeleteFile(hierarchy, args); - } - } - - /// - /// Checks whether this hierarchy item is a project member (on disk items from show all - /// files aren't considered project members). - /// - protected bool IsNonMemberItem(IVsHierarchy hierarchy, uint itemId) { - object val; - int hr = hierarchy.GetProperty(itemId, (int)__VSHPROPID.VSHPROPID_IsNonMemberItem, out val); - return ErrorHandler.Succeeded(hr) && (bool)val; - } - - #endregion - - #region IVsRunningDocTableEvents Members - - public int OnAfterAttributeChange(uint docCookie, uint grfAttribs) { - if ((grfAttribs & (uint)(__VSRDTATTRIB.RDTA_MkDocument)) == (uint)__VSRDTATTRIB.RDTA_MkDocument) { - IVsRunningDocumentTable rdt = GetPackageService(typeof(SVsRunningDocumentTable)) as IVsRunningDocumentTable; - if (rdt != null) { - uint flags, readLocks, editLocks, itemid; - IVsHierarchy hier; - IntPtr docData = IntPtr.Zero; - string moniker; - int hr; - try { - hr = rdt.GetDocumentInfo(docCookie, out flags, out readLocks, out editLocks, out moniker, out hier, out itemid, out docData); - TextLineEventListener listner; - if (_documents.TryGetValue(docCookie, out listner)) { - listner.FileName = moniker; - } - } finally { - if (IntPtr.Zero != docData) { - Marshal.Release(docData); - } - } - } - } - return VSConstants.S_OK; - } - - public int OnAfterDocumentWindowHide(uint docCookie, IVsWindowFrame pFrame) { - return VSConstants.S_OK; - } - - public int OnAfterFirstDocumentLock(uint docCookie, uint dwRDTLockType, uint dwReadLocksRemaining, uint dwEditLocksRemaining) { - return VSConstants.S_OK; - } - - public int OnAfterSave(uint docCookie) { - return VSConstants.S_OK; - } - - public int OnBeforeDocumentWindowShow(uint docCookie, int fFirstShow, IVsWindowFrame pFrame) { - // Check if this document is in the list of the documents. - if (_documents.ContainsKey(docCookie)) { - return VSConstants.S_OK; - } - // Get the information about this document from the RDT. - IVsRunningDocumentTable rdt = GetPackageService(typeof(SVsRunningDocumentTable)) as IVsRunningDocumentTable; - if (null != rdt) { - // Note that here we don't want to throw in case of error. - uint flags; - uint readLocks; - uint writeLoks; - string documentMoniker; - IVsHierarchy hierarchy; - uint itemId; - IntPtr unkDocData; - int hr = rdt.GetDocumentInfo(docCookie, out flags, out readLocks, out writeLoks, - out documentMoniker, out hierarchy, out itemId, out unkDocData); - try { - if (Microsoft.VisualStudio.ErrorHandler.Failed(hr) || (IntPtr.Zero == unkDocData)) { - return VSConstants.S_OK; - } - // Check if the herarchy is one of the hierarchies this service is monitoring. - if (!_hierarchies.ContainsKey(hierarchy)) { - // This hierarchy is not monitored, we can exit now. - return VSConstants.S_OK; - } - - // Check the file to see if a listener is required. - if (_package.IsRecognizedFile(documentMoniker)) { - return VSConstants.S_OK; - } - - // Create the module id for this document. - ModuleId docId = new ModuleId(hierarchy, itemId); - - // Try to get the text buffer. - IVsTextLines buffer = Marshal.GetObjectForIUnknown(unkDocData) as IVsTextLines; - - // Create the listener. - TextLineEventListener listener = new TextLineEventListener(buffer, documentMoniker, docId); - // Set the event handler for the change event. Note that there is no difference - // between the AddFile and FileChanged operation, so we can use the same handler. - listener.OnFileChanged += new EventHandler(OnNewFile); - // Add the listener to the dictionary, so we will not create it anymore. - _documents.Add(docCookie, listener); - } finally { - if (IntPtr.Zero != unkDocData) { - Marshal.Release(unkDocData); - } - } - } - // Always return success. - return VSConstants.S_OK; - } - - public int OnBeforeLastDocumentUnlock(uint docCookie, uint dwRDTLockType, uint dwReadLocksRemaining, uint dwEditLocksRemaining) { - if ((0 != dwEditLocksRemaining) || (0 != dwReadLocksRemaining)) { - return VSConstants.S_OK; - } - TextLineEventListener listener; - if (!_documents.TryGetValue(docCookie, out listener) || (null == listener)) { - return VSConstants.S_OK; - } - using (listener) { - _documents.Remove(docCookie); - // Now make sure that the information about this file are up to date (e.g. it is - // possible that Class View shows something strange if the file was closed without - // saving the changes). - HierarchyEventArgs args = new HierarchyEventArgs(listener.FileID.ItemID, listener.FileName); - OnNewFile(listener.FileID.Hierarchy, args); - } - return VSConstants.S_OK; - } - - #endregion - - public void OnIdle(IOleComponentManager compMgr) { - foreach (TextLineEventListener listener in _documents.Values) { - if (compMgr.FContinueIdle() == 0) { - break; - } - - listener.OnIdle(); - } - } - - #region IDisposable Members - - public void Dispose() { - // Dispose all the listeners. - foreach (var info in _hierarchies.Values) { - info.Listener.Dispose(); - } - _hierarchies.Clear(); - - foreach (TextLineEventListener textListener in _documents.Values) { - textListener.Dispose(); - } - _documents.Clear(); - - // Remove this library from the object manager. - if (0 != _objectManagerCookie) { - IVsObjectManager2 mgr = GetPackageService(typeof(SVsObjectManager)) as IVsObjectManager2; - if (null != mgr) { - mgr.UnregisterLibrary(_objectManagerCookie); - } - _objectManagerCookie = 0; - } - - // Unregister this object from the RDT events. - UnregisterRDTEvents(); - } - - #endregion - - class HierarchyInfo { - public readonly HierarchyListener Listener; - public readonly ProjectLibraryNode ProjectLibraryNode; - - public HierarchyInfo(HierarchyListener listener, ProjectLibraryNode projectLibNode) { - Listener = listener; - ProjectLibraryNode = projectLibNode; - } - } - } -} diff --git a/Microsoft.VisualStudio.Project/Navigation/LibraryNode.cs b/Microsoft.VisualStudio.Project/Navigation/LibraryNode.cs deleted file mode 100644 index 8a432781..00000000 --- a/Microsoft.VisualStudio.Project/Navigation/LibraryNode.cs +++ /dev/null @@ -1,494 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Collections.Generic; -using System.ComponentModel.Design; -using System.Diagnostics; -using System.Threading; -using Microsoft.VisualStudio.Language.Intellisense; -using Microsoft.VisualStudio.Shell; -using Microsoft.VisualStudio.Shell.Interop; -using VSConstants = Microsoft.VisualStudio.VSConstants; - -namespace Microsoft.VisualStudioTools.Navigation { - - /// - /// Single node inside the tree of the libraries in the object browser or class view. - /// - class LibraryNode : SimpleObjectList, IVsNavInfo, IVsNavInfoNode, ISimpleObject { - private string _name, _fullname; - private readonly LibraryNode _parent; - private LibraryNodeCapabilities _capabilities; - private readonly LibraryNodeType _type; - private readonly CommandID _contextMenuID; - private readonly string _tooltip; - private readonly Dictionary _filteredView; - private readonly Dictionary _childrenByName; - private bool _duplicatedByName; - - public LibraryNode(LibraryNode parent, string name, string fullname, LibraryNodeType type) - : this(parent, name, fullname, type, LibraryNodeCapabilities.None, null) { } - - public LibraryNode(LibraryNode parent, string name, string fullname, LibraryNodeType type, LibraryNodeCapabilities capabilities, CommandID contextMenuID) { - Debug.Assert(name != null); - - _parent = parent; - _capabilities = capabilities; - _contextMenuID = contextMenuID; - _name = name; - _fullname = fullname; - _tooltip = name; - _type = type; - _filteredView = new Dictionary(); - _childrenByName = new Dictionary(); - } - - protected LibraryNode(LibraryNode node) - : this(node, node.FullName) { - } - - protected LibraryNode(LibraryNode node, string newFullName) { - _parent = node._parent; - _capabilities = node._capabilities; - _contextMenuID = node._contextMenuID; - _name = node._name; - _tooltip = node._tooltip; - _type = node._type; - _fullname = newFullName; - Children.AddRange(node.Children); - _childrenByName = new Dictionary(node._childrenByName); - _filteredView = new Dictionary(); - } - - protected void SetCapabilityFlag(LibraryNodeCapabilities flag, bool value) { - if (value) { - _capabilities |= flag; - } else { - _capabilities &= ~flag; - } - } - - public LibraryNode Parent { - get { return _parent; } - } - - /// - /// Get or Set if the node can be deleted. - /// - public bool CanDelete { - get { return (0 != (_capabilities & LibraryNodeCapabilities.AllowDelete)); } - set { SetCapabilityFlag(LibraryNodeCapabilities.AllowDelete, value); } - } - - /// - /// Get or Set if the node can be associated with some source code. - /// - public bool CanGoToSource { - get { return (0 != (_capabilities & LibraryNodeCapabilities.HasSourceContext)); } - set { SetCapabilityFlag(LibraryNodeCapabilities.HasSourceContext, value); } - } - - /// - /// Get or Set if the node can be renamed. - /// - public bool CanRename { - get { return (0 != (_capabilities & LibraryNodeCapabilities.AllowRename)); } - set { SetCapabilityFlag(LibraryNodeCapabilities.AllowRename, value); } - } - - /// - /// - /// - - public override uint Capabilities { get { return (uint)_capabilities; } } - - public string TooltipText { - get { return _tooltip; } - } - - internal void AddNode(LibraryNode node) { - lock (Children) { - Children.Add(node); - LibraryNode[] nodes; - if (!_childrenByName.TryGetValue(node.Name, out nodes)) { - // common case, no duplicates by name - _childrenByName[node.Name] = new[] { node }; - } else { - // uncommon case, duplicated by name - _childrenByName[node.Name] = nodes = nodes.Append(node); - foreach (var dupNode in nodes) { - dupNode.DuplicatedByName = true; - } - } - } - Update(); - } - - internal void RemoveNode(LibraryNode node) { - if (node != null) { - lock (Children) { - Children.Remove(node); - - LibraryNode[] items; - if (_childrenByName.TryGetValue(node.Name, out items)) { - if (items.Length == 1) { - System.Diagnostics.Debug.Assert(items[0] == node); - _childrenByName.Remove(node.Name); - } else { - var newItems = new LibraryNode[items.Length - 1]; - for (int i = 0, write = 0; i < items.Length; i++) { - if (items[i] != node) { - newItems[write++] = items[i]; - } - } - _childrenByName[node.Name] = newItems; - } - } - } - Update(); - } - } - - public virtual object BrowseObject { - get { return null; } - } - - public override uint CategoryField(LIB_CATEGORY category) { - uint fieldValue = 0; - - switch (category) { - case (LIB_CATEGORY)_LIB_CATEGORY2.LC_PHYSICALCONTAINERTYPE: - fieldValue = (uint)_LIBCAT_PHYSICALCONTAINERTYPE.LCPT_PROJECT; - break; - case LIB_CATEGORY.LC_NODETYPE: - fieldValue = (uint)_LIBCAT_NODETYPE.LCNT_SYMBOL; - break; - case LIB_CATEGORY.LC_LISTTYPE: { - LibraryNodeType subTypes = LibraryNodeType.None; - foreach (LibraryNode node in Children) { - subTypes |= node._type; - } - fieldValue = (uint)subTypes; - } - break; - case (LIB_CATEGORY)_LIB_CATEGORY2.LC_HIERARCHYTYPE: - fieldValue = (uint)_LIBCAT_HIERARCHYTYPE.LCHT_UNKNOWN; - break; - case LIB_CATEGORY.LC_VISIBILITY: - fieldValue = (uint)_LIBCAT_VISIBILITY.LCV_VISIBLE; - break; - case LIB_CATEGORY.LC_MEMBERTYPE: - fieldValue = (uint)_LIBCAT_MEMBERTYPE.LCMT_METHOD; - break; - case LIB_CATEGORY.LC_MEMBERACCESS: - fieldValue = (uint)_LIBCAT_MEMBERACCESS.LCMA_PUBLIC; - break; - default: - throw new NotImplementedException(); - } - return fieldValue; - } - - public virtual LibraryNode Clone() { - return new LibraryNode(this); - } - - public virtual LibraryNode Clone(string newFullName) { - return new LibraryNode(this, newFullName); - } - - /// - /// Performs the operations needed to delete this node. - /// - public virtual void Delete() { - } - - /// - /// Perform a Drag and Drop operation on this node. - /// - public virtual void DoDragDrop(OleDataObject dataObject, uint keyState, uint effect) { - } - - public virtual uint EnumClipboardFormats(_VSOBJCFFLAGS flags, VSOBJCLIPFORMAT[] formats) { - return 0; - } - - public virtual void FillDescription(_VSOBJDESCOPTIONS flags, IVsObjectBrowserDescription3 description) { - description.ClearDescriptionText(); - description.AddDescriptionText3(_name, VSOBDESCRIPTIONSECTION.OBDS_NAME, null); - } - - public IVsSimpleObjectList2 FilterView(uint filterType) { - var libraryNodeType = (LibraryNodeType)filterType; - LibraryNode filtered = null; - if (_filteredView.TryGetValue(libraryNodeType, out filtered)) { - return filtered as IVsSimpleObjectList2; - } - filtered = this.Clone(); - for (int i = 0; i < filtered.Children.Count; ) { - if (0 == (filtered.Children[i]._type & libraryNodeType)) { - filtered.Children.RemoveAt(i); - } else { - i += 1; - } - } - _filteredView.Add(libraryNodeType, filtered); - return filtered as IVsSimpleObjectList2; - } - - public virtual void GotoSource(VSOBJGOTOSRCTYPE gotoType) { - // Do nothing. - } - - public virtual string Name { - get { - return _name; - } - } - - public virtual string GetTextRepresentation(VSTREETEXTOPTIONS options) { - return Name; - } - - public LibraryNodeType NodeType { - get { return _type; } - } - - /// - /// Finds the source files associated with this node. - /// - /// The hierarchy containing the items. - /// The item id of the item. - /// Number of items. - public virtual void SourceItems(out IVsHierarchy hierarchy, out uint itemId, out uint itemsCount) { - hierarchy = null; - itemId = 0; - itemsCount = 0; - } - - public virtual void Rename(string newName, uint flags) { - this._name = newName; - } - - public virtual string UniqueName { - get { return Name; } - } - - public string FullName { - get { - return _fullname; - } - } - - public CommandID ContextMenuID { - get { - return _contextMenuID; - } - } - - public virtual StandardGlyphGroup GlyphType { - get { - return StandardGlyphGroup.GlyphGroupModule; - } - } - - public virtual VSTREEDISPLAYDATA DisplayData { - get { - var res = new VSTREEDISPLAYDATA(); - res.Image = res.SelectedImage = (ushort)GlyphType; - return res; - } - } - - public virtual IVsSimpleObjectList2 DoSearch(VSOBSEARCHCRITERIA2 criteria) { - return null; - } - - public override void Update() { - base.Update(); - _filteredView.Clear(); - } - - /// - /// Visit this node and its children. - /// - /// Visitor to invoke methods on when visiting the nodes. - public void Visit(ILibraryNodeVisitor visitor, CancellationToken ct = default(CancellationToken)) { - if (ct.IsCancellationRequested) { - visitor.LeaveNode(this, ct); - return; - } - - if (visitor.EnterNode(this, ct)) { - lock (Children) { - foreach (var child in Children) { - if (ct.IsCancellationRequested) { - visitor.LeaveNode(this, ct); - return; - } - child.Visit(visitor, ct); - } - } - } - - visitor.LeaveNode(this, ct); - } - - #region IVsNavInfoNode Members - - int IVsNavInfoNode.get_Name(out string pbstrName) { - pbstrName = UniqueName; - return VSConstants.S_OK; - } - - int IVsNavInfoNode.get_Type(out uint pllt) { - pllt = (uint)_type; - return VSConstants.S_OK; - } - - #endregion - - /// - /// Enumeration of the capabilities of a node. It is possible to combine different values - /// to support more capabilities. - /// This enumeration is a copy of _LIB_LISTCAPABILITIES with the Flags attribute set. - /// - [Flags()] - public enum LibraryNodeCapabilities { - None = _LIB_LISTCAPABILITIES.LLC_NONE, - HasBrowseObject = _LIB_LISTCAPABILITIES.LLC_HASBROWSEOBJ, - HasDescriptionPane = _LIB_LISTCAPABILITIES.LLC_HASDESCPANE, - HasSourceContext = _LIB_LISTCAPABILITIES.LLC_HASSOURCECONTEXT, - HasCommands = _LIB_LISTCAPABILITIES.LLC_HASCOMMANDS, - AllowDragDrop = _LIB_LISTCAPABILITIES.LLC_ALLOWDRAGDROP, - AllowRename = _LIB_LISTCAPABILITIES.LLC_ALLOWRENAME, - AllowDelete = _LIB_LISTCAPABILITIES.LLC_ALLOWDELETE, - AllowSourceControl = _LIB_LISTCAPABILITIES.LLC_ALLOWSCCOPS, - } - - public bool DuplicatedByName { get { return _duplicatedByName; } private set { _duplicatedByName = value; } } - - #region IVsNavInfo - - private class VsEnumNavInfoNodes : IVsEnumNavInfoNodes { - private readonly IEnumerator _nodeEnum; - - public VsEnumNavInfoNodes(IEnumerator nodeEnum) { - _nodeEnum = nodeEnum; - } - - public int Clone(out IVsEnumNavInfoNodes ppEnum) { - ppEnum = new VsEnumNavInfoNodes(_nodeEnum); - return VSConstants.S_OK; - } - - public int Next(uint celt, IVsNavInfoNode[] rgelt, out uint pceltFetched) { - for (pceltFetched = 0; pceltFetched < celt; ++pceltFetched) { - if (!_nodeEnum.MoveNext()) { - return VSConstants.S_FALSE; - } - rgelt[pceltFetched] = _nodeEnum.Current; - } - return VSConstants.S_OK; - } - - public int Reset() { - throw new NotImplementedException(); - } - - public int Skip(uint celt) { - while (celt-- > 0) { - if (!_nodeEnum.MoveNext()) { - return VSConstants.S_FALSE; - } - } - return VSConstants.S_OK; - } - } - - public virtual int GetLibGuid(out Guid pGuid) { - pGuid = Guid.Empty; - return VSConstants.E_NOTIMPL; - } - - public int EnumCanonicalNodes(out IVsEnumNavInfoNodes ppEnum) { - return EnumPresentationNodes(0, out ppEnum); - } - - public int EnumPresentationNodes(uint dwFlags, out IVsEnumNavInfoNodes ppEnum) { - var path = new Stack(); - for (LibraryNode node = this; node != null; node = node.Parent) { - path.Push(node); - } - - ppEnum = new VsEnumNavInfoNodes(path.GetEnumerator()); - return VSConstants.S_OK; - } - - public int GetSymbolType(out uint pdwType) { - pdwType = (uint)_type; - return VSConstants.S_OK; - } - - #endregion - } - - /// - /// Enumeration of the possible types of node. The type of a node can be the combination - /// of one of more of these values. - /// This is actually a copy of the _LIB_LISTTYPE enumeration with the difference that the - /// Flags attribute is set so that it is possible to specify more than one value. - /// - [Flags()] - enum LibraryNodeType { - None = 0, - Hierarchy = _LIB_LISTTYPE.LLT_HIERARCHY, - Namespaces = _LIB_LISTTYPE.LLT_NAMESPACES, - Classes = _LIB_LISTTYPE.LLT_CLASSES, - Members = _LIB_LISTTYPE.LLT_MEMBERS, - Package = _LIB_LISTTYPE.LLT_PACKAGE, - PhysicalContainer = _LIB_LISTTYPE.LLT_PHYSICALCONTAINERS, - Containment = _LIB_LISTTYPE.LLT_CONTAINMENT, - ContainedBy = _LIB_LISTTYPE.LLT_CONTAINEDBY, - UsesClasses = _LIB_LISTTYPE.LLT_USESCLASSES, - UsedByClasses = _LIB_LISTTYPE.LLT_USEDBYCLASSES, - NestedClasses = _LIB_LISTTYPE.LLT_NESTEDCLASSES, - InheritedInterface = _LIB_LISTTYPE.LLT_INHERITEDINTERFACES, - InterfaceUsedByClasses = _LIB_LISTTYPE.LLT_INTERFACEUSEDBYCLASSES, - Definitions = _LIB_LISTTYPE.LLT_DEFINITIONS, - References = _LIB_LISTTYPE.LLT_REFERENCES, - DeferExpansion = _LIB_LISTTYPE.LLT_DEFEREXPANSION, - } - - /// - /// Visitor interface used to enumerate all s in the library. - /// - interface ILibraryNodeVisitor { - /// - /// Called on each node before any of its child nodes are visited. - /// - /// The node that is being visited. - /// true if children of this node should be visited, otherwise false. - bool EnterNode(LibraryNode node, CancellationToken ct); - - /// - /// Called on each node after all its child nodes were visited. - /// - /// The node that was being visited. - void LeaveNode(LibraryNode node, CancellationToken ct); - } -} diff --git a/Microsoft.VisualStudio.Project/Navigation/LibraryTask.cs b/Microsoft.VisualStudio.Project/Navigation/LibraryTask.cs deleted file mode 100644 index 09f4d420..00000000 --- a/Microsoft.VisualStudio.Project/Navigation/LibraryTask.cs +++ /dev/null @@ -1,50 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using Microsoft.VisualStudio.Text; - -namespace Microsoft.VisualStudioTools.Navigation { - /// - /// Class storing the data about a parsing task on a language module. - /// A module in dynamic languages is a source file, so here we use the file name to - /// identify it. - /// - public class LibraryTask { - private string _fileName; - private ITextBuffer _textBuffer; - private ModuleId _moduleId; - - public LibraryTask(string fileName, ITextBuffer textBuffer, ModuleId moduleId) { - _fileName = fileName; - _textBuffer = textBuffer; - _moduleId = moduleId; - } - - public string FileName { - get { return _fileName; } - } - - public ModuleId ModuleID { - get { return _moduleId; } - set { _moduleId = value; } - } - - public ITextBuffer TextBuffer { - get { return _textBuffer; } - } - } - -} diff --git a/Microsoft.VisualStudio.Project/Navigation/ModuleId.cs b/Microsoft.VisualStudio.Project/Navigation/ModuleId.cs deleted file mode 100644 index 31ce0eaa..00000000 --- a/Microsoft.VisualStudio.Project/Navigation/ModuleId.cs +++ /dev/null @@ -1,61 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using Microsoft.VisualStudio.Shell.Interop; - -namespace Microsoft.VisualStudioTools.Navigation { - /// - /// Class used to identify a module. The module is identified using the hierarchy that - /// contains it and its item id inside the hierarchy. - /// - public sealed class ModuleId { - private IVsHierarchy _ownerHierarchy; - private uint _itemId; - - public ModuleId(IVsHierarchy owner, uint id) { - _ownerHierarchy = owner; - _itemId = id; - } - - public IVsHierarchy Hierarchy { - get { return _ownerHierarchy; } - } - - public uint ItemID { - get { return _itemId; } - } - - public override int GetHashCode() { - int hash = 0; - if (null != _ownerHierarchy) { - hash = _ownerHierarchy.GetHashCode(); - } - hash = hash ^ (int)_itemId; - return hash; - } - - public override bool Equals(object obj) { - ModuleId other = obj as ModuleId; - if (null == other) { - return false; - } - if (!_ownerHierarchy.Equals(other._ownerHierarchy)) { - return false; - } - return (_itemId == other._itemId); - } - } -} \ No newline at end of file diff --git a/Microsoft.VisualStudio.Project/Navigation/ProjectLibraryNode.cs b/Microsoft.VisualStudio.Project/Navigation/ProjectLibraryNode.cs deleted file mode 100644 index 369f8686..00000000 --- a/Microsoft.VisualStudio.Project/Navigation/ProjectLibraryNode.cs +++ /dev/null @@ -1,53 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using Microsoft.VisualStudio.Language.Intellisense; -using Microsoft.VisualStudio.Shell.Interop; -using Microsoft.VisualStudioTools.Project; - -namespace Microsoft.VisualStudioTools.Navigation { - class ProjectLibraryNode : LibraryNode { - private readonly CommonProjectNode _project; - - public ProjectLibraryNode(CommonProjectNode project) - : base(null, project.Caption, project.Caption, LibraryNodeType.PhysicalContainer) { - _project = project; - } - - public override uint CategoryField(LIB_CATEGORY category) { - switch (category) { - case LIB_CATEGORY.LC_NODETYPE: - return (uint)_LIBCAT_NODETYPE.LCNT_PROJECT; - } - return base.CategoryField(category); - } - - public override VSTREEDISPLAYDATA DisplayData { - get { - var res = new VSTREEDISPLAYDATA(); - res.hImageList = _project.ImageHandler.ImageList.Handle; - res.Image = res.SelectedImage = (ushort)_project.ImageIndex; - return res; - } - } - - public override StandardGlyphGroup GlyphType { - get { - return StandardGlyphGroup.GlyphCoolProject; - } - } - } -} diff --git a/Microsoft.VisualStudio.Project/Navigation/SimpleObject.cs b/Microsoft.VisualStudio.Project/Navigation/SimpleObject.cs deleted file mode 100644 index 75fe0345..00000000 --- a/Microsoft.VisualStudio.Project/Navigation/SimpleObject.cs +++ /dev/null @@ -1,106 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using Microsoft.VisualStudio.Shell; -using Microsoft.VisualStudio.Shell.Interop; - -namespace Microsoft.VisualStudioTools.Navigation { - class SimpleObject : ISimpleObject { - #region ISimpleObject Members - - public virtual bool CanDelete { - get { return false; } - } - - public virtual bool CanGoToSource { - get { return false; } - } - - public virtual bool CanRename { - get { return false; } - } - - public virtual string Name { - get { return String.Empty; } - } - - public virtual string UniqueName { - get { return String.Empty; } - } - - public virtual string FullName { - get { - return Name; - } - } - - public virtual string GetTextRepresentation(VSTREETEXTOPTIONS options) { - return Name; - } - - public virtual string TooltipText { - get { return String.Empty; } - } - - public virtual object BrowseObject { - get { return null; } - } - - public virtual System.ComponentModel.Design.CommandID ContextMenuID { - get { return null; } - } - - public virtual VSTREEDISPLAYDATA DisplayData { - get { return new VSTREEDISPLAYDATA(); } - } - - public virtual uint CategoryField(LIB_CATEGORY lIB_CATEGORY) { - return 0; - } - - public virtual void Delete() { - } - - public virtual void DoDragDrop(OleDataObject dataObject, uint grfKeyState, uint pdwEffect) { - } - - public virtual void Rename(string pszNewName, uint grfFlags) { - } - - public virtual void GotoSource(VSOBJGOTOSRCTYPE SrcType) { - } - - public virtual void SourceItems(out IVsHierarchy ppHier, out uint pItemid, out uint pcItems) { - ppHier = null; - pItemid = 0; - pcItems = 0; - } - - public virtual uint EnumClipboardFormats(_VSOBJCFFLAGS _VSOBJCFFLAGS, VSOBJCLIPFORMAT[] rgcfFormats) { - return 0; - } - - public virtual void FillDescription(_VSOBJDESCOPTIONS _VSOBJDESCOPTIONS, IVsObjectBrowserDescription3 pobDesc) { - } - - public virtual IVsSimpleObjectList2 FilterView(uint ListType) { - return null; - } - - #endregion - } -} diff --git a/Microsoft.VisualStudio.Project/Navigation/SimpleObjectList.cs b/Microsoft.VisualStudio.Project/Navigation/SimpleObjectList.cs deleted file mode 100644 index a9fda31d..00000000 --- a/Microsoft.VisualStudio.Project/Navigation/SimpleObjectList.cs +++ /dev/null @@ -1,330 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Collections.Generic; -using System.ComponentModel.Design; -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.OLE.Interop; -using Microsoft.VisualStudio.Shell; -using Microsoft.VisualStudio.Shell.Interop; -using Microsoft.VisualStudioTools.Project; - -namespace Microsoft.VisualStudioTools.Navigation { - /// - /// Represents a simple list which the VS UI can query for items. - /// - /// VS assumes that these lists do not change once VS has gotten ahold of them. Therefore if the - /// list is changing over time it should be thrown away and a new list should be placed in the parent. - /// - class SimpleObjectList : IVsSimpleObjectList2 where T : ISimpleObject { - private readonly List _children; - private uint _updateCount; - - public SimpleObjectList() { - _children = new List(); - } - - public List Children { - get { - return _children; - } - } - - public virtual void Update() { - _updateCount++; - } - - public uint UpdateCount { - get { return _updateCount; } - set { _updateCount = value; } - } - - public const uint NullIndex = (uint)0xFFFFFFFF; - - int IVsSimpleObjectList2.CanDelete(uint index, out int pfOK) { - if (index >= (uint)_children.Count) { - throw new ArgumentOutOfRangeException("index"); - } - pfOK = _children[(int)index].CanDelete ? 1 : 0; - return VSConstants.S_OK; - } - - int IVsSimpleObjectList2.CanGoToSource(uint index, VSOBJGOTOSRCTYPE SrcType, out int pfOK) { - if (index >= (uint)_children.Count) { - throw new ArgumentOutOfRangeException("index"); - } - pfOK = _children[(int)index].CanGoToSource ? 1 : 0; - return VSConstants.S_OK; - } - - int IVsSimpleObjectList2.CanRename(uint index, string pszNewName, out int pfOK) { - if (index >= (uint)_children.Count) { - throw new ArgumentOutOfRangeException("index"); - } - pfOK = _children[(int)index].CanRename ? 1 : 0; - return VSConstants.S_OK; - } - - int IVsSimpleObjectList2.CountSourceItems(uint index, out IVsHierarchy ppHier, out uint pItemid, out uint pcItems) { - if (index >= (uint)_children.Count) { - throw new ArgumentOutOfRangeException("index"); - } - _children[(int)index].SourceItems(out ppHier, out pItemid, out pcItems); - return VSConstants.S_OK; - } - - int IVsSimpleObjectList2.DoDelete(uint index, uint grfFlags) { - if (index >= (uint)_children.Count) { - throw new ArgumentOutOfRangeException("index"); - } - _children[(int)index].Delete(); - _children.RemoveAt((int)index); - return VSConstants.S_OK; - } - - int IVsSimpleObjectList2.DoDragDrop(uint index, IDataObject pDataObject, uint grfKeyState, ref uint pdwEffect) { - if (index >= (uint)_children.Count) { - throw new ArgumentOutOfRangeException("index"); - } - OleDataObject dataObject = new OleDataObject(pDataObject); - _children[(int)index].DoDragDrop(dataObject, grfKeyState, pdwEffect); - return VSConstants.S_OK; - } - - int IVsSimpleObjectList2.DoRename(uint index, string pszNewName, uint grfFlags) { - if (index >= (uint)_children.Count) { - throw new ArgumentOutOfRangeException("index"); - } - _children[(int)index].Rename(pszNewName, grfFlags); - return VSConstants.S_OK; - } - - int IVsSimpleObjectList2.EnumClipboardFormats(uint index, uint grfFlags, uint celt, VSOBJCLIPFORMAT[] rgcfFormats, uint[] pcActual) { - if (index >= (uint)_children.Count) { - throw new ArgumentOutOfRangeException("index"); - } - uint copied = _children[(int)index].EnumClipboardFormats((_VSOBJCFFLAGS)grfFlags, rgcfFormats); - if ((null != pcActual) && (pcActual.Length > 0)) { - pcActual[0] = copied; - } - return VSConstants.S_OK; - } - - int IVsSimpleObjectList2.FillDescription2(uint index, uint grfOptions, IVsObjectBrowserDescription3 pobDesc) { - if (index >= (uint)_children.Count) { - throw new ArgumentOutOfRangeException("index"); - } - _children[(int)index].FillDescription((_VSOBJDESCOPTIONS)grfOptions, pobDesc); - return VSConstants.S_OK; - } - - int IVsSimpleObjectList2.GetBrowseObject(uint index, out object ppdispBrowseObj) { - if (index >= (uint)_children.Count) { - throw new ArgumentOutOfRangeException("index"); - } - ppdispBrowseObj = _children[(int)index].BrowseObject; - if (null == ppdispBrowseObj) { - return VSConstants.E_NOTIMPL; - } - return VSConstants.S_OK; - } - - int IVsSimpleObjectList2.GetCapabilities2(out uint pgrfCapabilities) { - pgrfCapabilities = (uint)Capabilities; - return VSConstants.S_OK; - } - - int IVsSimpleObjectList2.GetCategoryField2(uint index, int Category, out uint pfCatField) { - if (NullIndex == index) { - pfCatField = CategoryField((LIB_CATEGORY)Category); - } else if (index < (uint)_children.Count) { - pfCatField = _children[(int)index].CategoryField((LIB_CATEGORY)Category); - } else { - throw new ArgumentOutOfRangeException("index"); - } - return VSConstants.S_OK; - } - - int IVsSimpleObjectList2.GetClipboardFormat(uint index, uint grfFlags, FORMATETC[] pFormatetc, STGMEDIUM[] pMedium) { - return VSConstants.E_NOTIMPL; - } - - int IVsSimpleObjectList2.GetContextMenu(uint index, out Guid pclsidActive, out int pnMenuId, out IOleCommandTarget ppCmdTrgtActive) { - if (index >= (uint)_children.Count) { - throw new ArgumentOutOfRangeException("index"); - } - CommandID commandId = _children[(int)index].ContextMenuID; - if (null == commandId) { - pclsidActive = Guid.Empty; - pnMenuId = 0; - ppCmdTrgtActive = null; - return VSConstants.E_NOTIMPL; - } - pclsidActive = commandId.Guid; - pnMenuId = commandId.ID; - ppCmdTrgtActive = _children[(int)index] as IOleCommandTarget; - return VSConstants.S_OK; - } - - int IVsSimpleObjectList2.GetDisplayData(uint index, VSTREEDISPLAYDATA[] pData) { - if (index >= (uint)_children.Count) { - throw new ArgumentOutOfRangeException("index"); - } - pData[0] = _children[(int)index].DisplayData; - return VSConstants.S_OK; - } - - int IVsSimpleObjectList2.GetExpandable3(uint index, uint ListTypeExcluded, out int pfExpandable) { - // There is a not empty implementation of GetCategoryField2, so this method should - // return E_NOTIMPL. - pfExpandable = 0; - return VSConstants.E_NOTIMPL; - } - - int IVsSimpleObjectList2.GetExtendedClipboardVariant(uint index, uint grfFlags, VSOBJCLIPFORMAT[] pcfFormat, out object pvarFormat) { - pvarFormat = null; - return VSConstants.E_NOTIMPL; - } - - int IVsSimpleObjectList2.GetFlags(out uint pFlags) { - pFlags = (uint)Flags; - return VSConstants.S_OK; - } - - int IVsSimpleObjectList2.GetItemCount(out uint pCount) { - pCount = (uint)_children.Count; - return VSConstants.S_OK; - } - - int IVsSimpleObjectList2.GetList2(uint index, uint ListType, uint flags, VSOBSEARCHCRITERIA2[] pobSrch, out IVsSimpleObjectList2 ppIVsSimpleObjectList2) { - // TODO: Use the flags and list type to actually filter the result. - if (index >= (uint)_children.Count) { - throw new ArgumentOutOfRangeException("index"); - } - ppIVsSimpleObjectList2 = _children[(int)index].FilterView(ListType); - return VSConstants.S_OK; - } - - int IVsSimpleObjectList2.GetMultipleSourceItems(uint index, uint grfGSI, uint cItems, VSITEMSELECTION[] rgItemSel) { - return VSConstants.E_NOTIMPL; - } - - int IVsSimpleObjectList2.GetNavInfo(uint index, out IVsNavInfo ppNavInfo) { - if (index >= (uint)_children.Count) { - throw new ArgumentOutOfRangeException("index"); - } - ppNavInfo = _children[(int)index] as IVsNavInfo; - return ppNavInfo == null ? VSConstants.E_NOTIMPL : VSConstants.S_OK; - } - - int IVsSimpleObjectList2.GetNavInfoNode(uint index, out IVsNavInfoNode ppNavInfoNode) { - if (index >= (uint)_children.Count) { - throw new ArgumentOutOfRangeException("index"); - } - ppNavInfoNode = _children[(int)index] as IVsNavInfoNode; - return VSConstants.S_OK; - } - - int IVsSimpleObjectList2.GetProperty(uint index, int propid, out object pvar) { - if (propid == (int)_VSOBJLISTELEMPROPID.VSOBJLISTELEMPROPID_FULLNAME) { - pvar = _children[(int)index].FullName; - return VSConstants.S_OK; - } - - pvar = null; - return VSConstants.E_NOTIMPL; - } - - int IVsSimpleObjectList2.GetSourceContextWithOwnership(uint index, out string pbstrFilename, out uint pulLineNum) { - pbstrFilename = null; - pulLineNum = (uint)0; - return VSConstants.E_NOTIMPL; - } - - int IVsSimpleObjectList2.GetTextWithOwnership(uint index, VSTREETEXTOPTIONS tto, out string pbstrText) { - // TODO: make use of the text option. - if (index >= (uint)_children.Count) { - throw new ArgumentOutOfRangeException("index"); - } - pbstrText = _children[(int)index].GetTextRepresentation(tto); - return VSConstants.S_OK; - } - - int IVsSimpleObjectList2.GetTipTextWithOwnership(uint index, VSTREETOOLTIPTYPE eTipType, out string pbstrText) { - // TODO: Make use of the tooltip type. - if (index >= (uint)_children.Count) { - throw new ArgumentOutOfRangeException("index"); - } - pbstrText = _children[(int)index].TooltipText; - return VSConstants.S_OK; - } - - int IVsSimpleObjectList2.GetUserContext(uint index, out object ppunkUserCtx) { - ppunkUserCtx = null; - return VSConstants.E_NOTIMPL; - } - - int IVsSimpleObjectList2.GoToSource(uint index, VSOBJGOTOSRCTYPE SrcType) { - if (index >= (uint)_children.Count) { - throw new ArgumentOutOfRangeException("index"); - } - _children[(int)index].GotoSource(SrcType); - return VSConstants.S_OK; - } - - int IVsSimpleObjectList2.LocateNavInfoNode(IVsNavInfoNode pNavInfoNode, out uint pulIndex) { - Utilities.ArgumentNotNull("pNavInfoNode", pNavInfoNode); - - pulIndex = NullIndex; - string nodeName; - ErrorHandler.ThrowOnFailure(pNavInfoNode.get_Name(out nodeName)); - for (int i = 0; i < _children.Count; i++) { - if (0 == string.Compare(_children[i].UniqueName, nodeName, StringComparison.OrdinalIgnoreCase)) { - pulIndex = (uint)i; - return VSConstants.S_OK; - } - } - return VSConstants.S_FALSE; - } - - int IVsSimpleObjectList2.OnClose(VSTREECLOSEACTIONS[] ptca) { - // Do Nothing. - return VSConstants.S_OK; - } - - int IVsSimpleObjectList2.QueryDragDrop(uint index, IDataObject pDataObject, uint grfKeyState, ref uint pdwEffect) { - return VSConstants.E_NOTIMPL; - } - - int IVsSimpleObjectList2.ShowHelp(uint index) { - return VSConstants.E_NOTIMPL; - } - - int IVsSimpleObjectList2.UpdateCounter(out uint pCurUpdate) { - pCurUpdate = _updateCount; - return VSConstants.S_OK; - } - - public virtual uint Capabilities { get { return 0; } } - - public virtual _VSTREEFLAGS Flags { get { return 0; } } - - public virtual uint CategoryField(LIB_CATEGORY lIB_CATEGORY) { - return 0; - } - } -} diff --git a/Microsoft.VisualStudio.Project/Navigation/SourceLocation.cs b/Microsoft.VisualStudio.Project/Navigation/SourceLocation.cs deleted file mode 100644 index fc45a9c4..00000000 --- a/Microsoft.VisualStudio.Project/Navigation/SourceLocation.cs +++ /dev/null @@ -1,210 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Globalization; - -namespace Microsoft.VisualStudioTools.Parsing { - /// - /// Represents a location in source code. - /// - [Serializable] - public struct SourceLocation { - // TODO: remove index - private readonly int _index; - - private readonly int _line; - private readonly int _column; - - /// - /// Creates a new source location. - /// - /// The index in the source stream the location represents (0-based). - /// The line in the source stream the location represents (1-based). - /// The column in the source stream the location represents (1-based). - public SourceLocation(int index, int line, int column) { - ValidateLocation(index, line, column); - - _index = index; - _line = line; - _column = column; - } - - private static void ValidateLocation(int index, int line, int column) { - if (index < 0) { - throw ErrorOutOfRange("index", 0); - } - if (line < 1) { - throw ErrorOutOfRange("line", 1); - } - if (column < 1) { - throw ErrorOutOfRange("column", 1); - } - } - - private static Exception ErrorOutOfRange(object p0, object p1) { - return new ArgumentOutOfRangeException(string.Format("{0} must be greater than or equal to {1}", p0, p1)); - } - - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters")] - private SourceLocation(int index, int line, int column, bool noChecks) { - _index = index; - _line = line; - _column = column; - } - - /// - /// The index in the source stream the location represents (0-based). - /// - public int Index { - get { return _index; } - } - - /// - /// The line in the source stream the location represents (1-based). - /// - public int Line { - get { return _line; } - } - - /// - /// The column in the source stream the location represents (1-based). - /// - public int Column { - get { return _column; } - } - - /// - /// Compares two specified location values to see if they are equal. - /// - /// One location to compare. - /// The other location to compare. - /// True if the locations are the same, False otherwise. - public static bool operator ==(SourceLocation left, SourceLocation right) { - return left._index == right._index && left._line == right._line && left._column == right._column; - } - - /// - /// Compares two specified location values to see if they are not equal. - /// - /// One location to compare. - /// The other location to compare. - /// True if the locations are not the same, False otherwise. - public static bool operator !=(SourceLocation left, SourceLocation right) { - return left._index != right._index || left._line != right._line || left._column != right._column; - } - - /// - /// Compares two specified location values to see if one is before the other. - /// - /// One location to compare. - /// The other location to compare. - /// True if the first location is before the other location, False otherwise. - public static bool operator <(SourceLocation left, SourceLocation right) { - return left._index < right._index; - } - - /// - /// Compares two specified location values to see if one is after the other. - /// - /// One location to compare. - /// The other location to compare. - /// True if the first location is after the other location, False otherwise. - public static bool operator >(SourceLocation left, SourceLocation right) { - return left._index > right._index; - } - - /// - /// Compares two specified location values to see if one is before or the same as the other. - /// - /// One location to compare. - /// The other location to compare. - /// True if the first location is before or the same as the other location, False otherwise. - public static bool operator <=(SourceLocation left, SourceLocation right) { - return left._index <= right._index; - } - - /// - /// Compares two specified location values to see if one is after or the same as the other. - /// - /// One location to compare. - /// The other location to compare. - /// True if the first location is after or the same as the other location, False otherwise. - public static bool operator >=(SourceLocation left, SourceLocation right) { - return left._index >= right._index; - } - - /// - /// Compares two specified location values. - /// - /// One location to compare. - /// The other location to compare. - /// 0 if the locations are equal, -1 if the left one is less than the right one, 1 otherwise. - public static int Compare(SourceLocation left, SourceLocation right) { - if (left < right) - return -1; - if (right < left) - return 1; - - return 0; - } - - /// - /// A location that is valid but represents no location at all. - /// - public static readonly SourceLocation None = new SourceLocation(0, 0xfeefee, 0, true); - - /// - /// An invalid location. - /// - public static readonly SourceLocation Invalid = new SourceLocation(0, 0, 0, true); - - /// - /// A minimal valid location. - /// - public static readonly SourceLocation MinValue = new SourceLocation(0, 1, 1); - - /// - /// Whether the location is a valid location. - /// - /// True if the location is valid, False otherwise. - public bool IsValid { - get { - return this._line != 0 && this._column != 0; - } - } - - public override bool Equals(object obj) { - if (!(obj is SourceLocation)) - return false; - - SourceLocation other = (SourceLocation)obj; - return other._index == _index && other._line == _line && other._column == _column; - } - - public override int GetHashCode() { - return (_line << 16) ^ _column; - } - - public override string ToString() { - return "(" + _line + "," + _column + ")"; - } - - internal string ToDebugString() { - return String.Format(CultureInfo.CurrentCulture, "({0},{1},{2})", _index, _line, _column); - } - } -} \ No newline at end of file diff --git a/Microsoft.VisualStudio.Project/Navigation/TextLineEventListener.cs b/Microsoft.VisualStudio.Project/Navigation/TextLineEventListener.cs deleted file mode 100644 index 680a748c..00000000 --- a/Microsoft.VisualStudio.Project/Navigation/TextLineEventListener.cs +++ /dev/null @@ -1,104 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using Microsoft.VisualStudio.OLE.Interop; -using Microsoft.VisualStudio.TextManager.Interop; - -namespace Microsoft.VisualStudioTools.Navigation { - internal class TextLineEventListener : IVsTextLinesEvents, IDisposable { - private const int _defaultDelay = 2000; - private string _fileName; - private ModuleId _fileId; - private IVsTextLines _buffer; - private bool _isDirty; - private IConnectionPoint _connectionPoint; - private uint _connectionCookie; - - public TextLineEventListener(IVsTextLines buffer, string fileName, ModuleId id) { - _buffer = buffer; - _fileId = id; - _fileName = fileName; - IConnectionPointContainer container = buffer as IConnectionPointContainer; - if (null != container) { - Guid eventsGuid = typeof(IVsTextLinesEvents).GUID; - container.FindConnectionPoint(ref eventsGuid, out _connectionPoint); - _connectionPoint.Advise(this as IVsTextLinesEvents, out _connectionCookie); - } - } - - #region Properties - public ModuleId FileID { - get { return _fileId; } - } - public string FileName { - get { return _fileName; } - set { _fileName = value; } - } - #endregion - - #region Events - public event EventHandler OnFileChanged; - - public event TextLineChangeEvent OnFileChangedImmediate; - - #endregion - - #region IVsTextLinesEvents Members - void IVsTextLinesEvents.OnChangeLineAttributes(int iFirstLine, int iLastLine) { - // Do Nothing - } - - void IVsTextLinesEvents.OnChangeLineText(TextLineChange[] pTextLineChange, int fLast) { - TextLineChangeEvent eh = OnFileChangedImmediate; - if (null != eh) { - eh(this, pTextLineChange, fLast); - } - - _isDirty = true; - } - #endregion - - #region IDisposable Members - public void Dispose() { - if ((null != _connectionPoint) && (0 != _connectionCookie)) { - _connectionPoint.Unadvise(_connectionCookie); - } - _connectionCookie = 0; - _connectionPoint = null; - - _buffer = null; - _fileId = null; - } - #endregion - - #region Idle time processing - public void OnIdle() { - if (!_isDirty) { - return; - } - var onFileChanged = OnFileChanged; - if (null != onFileChanged) { - HierarchyEventArgs args = new HierarchyEventArgs(_fileId.ItemID, _fileName); - args.TextBuffer = _buffer; - onFileChanged(_fileId.Hierarchy, args); - } - - _isDirty = false; - } - #endregion - } -} diff --git a/Microsoft.VisualStudio.Project/NodeProperties.cs b/Microsoft.VisualStudio.Project/NodeProperties.cs deleted file mode 100644 index f98b4a24..00000000 --- a/Microsoft.VisualStudio.Project/NodeProperties.cs +++ /dev/null @@ -1,834 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Runtime.InteropServices; -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.OLE.Interop; -using Microsoft.VisualStudio.Shell; -using Microsoft.VisualStudio.Shell.Interop; -using VSLangProj; -using IOleServiceProvider = Microsoft.VisualStudio.OLE.Interop.IServiceProvider; - -namespace Microsoft.VisualStudioTools.Project { - - /// - /// All public properties on Nodeproperties or derived classes are assumed to be used by Automation by default. - /// Set this attribute to false on Properties that should not be visible for Automation. - /// - [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)] - public sealed class AutomationBrowsableAttribute : System.Attribute { - public AutomationBrowsableAttribute(bool browsable) { - this.browsable = browsable; - } - - public bool Browsable { - get { - return this.browsable; - } - } - - private bool browsable; - } - - /// - /// This attribute is used to mark properties that shouldn't be serialized. Marking properties with this will - /// result in them not being serialized and not being bold in the properties pane. - /// - [AttributeUsage(AttributeTargets.Property)] - internal sealed class AlwaysSerializedAttribute : Attribute { - public AlwaysSerializedAttribute() { } - } - - /// - /// To create your own localizable node properties, subclass this and add public properties - /// decorated with your own localized display name, category and description attributes. - /// - [ComVisible(true)] - public class NodeProperties : LocalizableProperties, - ISpecifyPropertyPages, - IVsGetCfgProvider, - IVsSpecifyProjectDesignerPages, - IVsBrowseObject { - #region fields - private HierarchyNode node; - #endregion - - #region properties - [Browsable(false)] - [AutomationBrowsable(true)] - public object Node { - get { return this.node; } - } - - internal HierarchyNode HierarchyNode { - get { return this.node; } - } - - - /// - /// Used by Property Pages Frame to set it's title bar. The Caption of the Hierarchy Node is returned. - /// - [Browsable(false)] - [AutomationBrowsable(false)] - public virtual string Name { - get { return this.node.Caption; } - } - - #endregion - - #region ctors - internal NodeProperties(HierarchyNode node) { - Utilities.ArgumentNotNull("node", node); - this.node = node; - } - #endregion - - #region ISpecifyPropertyPages methods - public virtual void GetPages(CAUUID[] pages) { - this.GetCommonPropertyPages(pages); - } - #endregion - - #region IVsSpecifyProjectDesignerPages - /// - /// Implementation of the IVsSpecifyProjectDesignerPages. It will retun the pages that are configuration independent. - /// - /// The pages to return. - /// - public virtual int GetProjectDesignerPages(CAUUID[] pages) { - this.GetCommonPropertyPages(pages); - return VSConstants.S_OK; - } - #endregion - - #region IVsGetCfgProvider methods - public virtual int GetCfgProvider(out IVsCfgProvider p) { - p = null; - return VSConstants.E_NOTIMPL; - } - #endregion - - #region IVsBrowseObject methods - /// - /// Maps back to the hierarchy or project item object corresponding to the browse object. - /// - /// Reference to the hierarchy object. - /// Reference to the project item. - /// If the method succeeds, it returns S_OK. If it fails, it returns an error code. - public virtual int GetProjectItem(out IVsHierarchy hier, out uint itemid) { - Utilities.CheckNotNull(node); - - hier = node.ProjectMgr.GetOuterInterface(); - itemid = this.node.ID; - return VSConstants.S_OK; - } - #endregion - - #region overridden methods - /// - /// Get the Caption of the Hierarchy Node instance. If Caption is null or empty we delegate to base - /// - /// Caption of Hierarchy node instance - public override string GetComponentName() { - string caption = this.HierarchyNode.Caption; - if (string.IsNullOrEmpty(caption)) { - return base.GetComponentName(); - } else { - return caption; - } - } - #endregion - - #region helper methods - protected string GetProperty(string name, string def) { - string a = this.HierarchyNode.ItemNode.GetMetadata(name); - return (a == null) ? def : a; - } - - protected void SetProperty(string name, string value) { - this.HierarchyNode.ItemNode.SetMetadata(name, value); - } - - /// - /// Retrieves the common property pages. The NodeProperties is the BrowseObject and that will be called to support - /// configuration independent properties. - /// - /// The pages to return. - private void GetCommonPropertyPages(CAUUID[] pages) { - // We do not check whether the supportsProjectDesigner is set to false on the ProjectNode. - // We rely that the caller knows what to call on us. - Utilities.ArgumentNotNull("pages", pages); - - if (pages.Length == 0) { - throw new ArgumentException(SR.GetString(SR.InvalidParameter), "pages"); - } - - // Only the project should show the property page the rest should show the project properties. - if (this.node != null && (this.node is ProjectNode)) { - // Retrieve the list of guids from hierarchy properties. - // Because a flavor could modify that list we must make sure we are calling the outer most implementation of IVsHierarchy - string guidsList = String.Empty; - IVsHierarchy hierarchy = HierarchyNode.ProjectMgr.GetOuterInterface(); - object variant = null; - ErrorHandler.ThrowOnFailure(hierarchy.GetProperty(VSConstants.VSITEMID_ROOT, (int)__VSHPROPID2.VSHPROPID_PropertyPagesCLSIDList, out variant)); - guidsList = (string)variant; - - Guid[] guids = Utilities.GuidsArrayFromSemicolonDelimitedStringOfGuids(guidsList); - if (guids == null || guids.Length == 0) { - pages[0] = new CAUUID(); - pages[0].cElems = 0; - } else { - pages[0] = PackageUtilities.CreateCAUUIDFromGuidArray(guids); - } - } else { - pages[0] = new CAUUID(); - pages[0].cElems = 0; - } - } - #endregion - - #region ExtenderSupport - [Browsable(false)] - public virtual string ExtenderCATID { - get { - Guid catid = this.HierarchyNode.ProjectMgr.GetCATIDForType(this.GetType()); - if (Guid.Empty.CompareTo(catid) == 0) { - return null; - } - return catid.ToString("B"); - } - } - - [Browsable(false)] - public object ExtenderNames() { - EnvDTE.ObjectExtenders extenderService = (EnvDTE.ObjectExtenders)this.HierarchyNode.GetService(typeof(EnvDTE.ObjectExtenders)); - Utilities.CheckNotNull(extenderService, "Could not get the ObjectExtenders object from the services exposed by this property object"); - - return extenderService.GetExtenderNames(this.ExtenderCATID, this); - } - - public object Extender(string extenderName) { - EnvDTE.ObjectExtenders extenderService = (EnvDTE.ObjectExtenders)this.HierarchyNode.GetService(typeof(EnvDTE.ObjectExtenders)); - Utilities.CheckNotNull(extenderService, "Could not get the ObjectExtenders object from the services exposed by this property object"); - return extenderService.GetExtender(this.ExtenderCATID, extenderName, this); - } - - #endregion - } - - [ComVisible(true)] - public class FileNodeProperties : NodeProperties { - #region properties - - [SRCategoryAttribute(SR.Misc)] - [SRDisplayName(SR.FileName)] - [SRDescriptionAttribute(SR.FileNameDescription)] - [AlwaysSerialized] - public virtual string FileName { - get { - return this.HierarchyNode.Caption; - } - set { - this.HierarchyNode.SetEditLabel(value); - } - } - - [SRCategoryAttribute(SR.Misc)] - [SRDisplayName(SR.FullPath)] - [SRDescriptionAttribute(SR.FullPathDescription)] - public string FullPath { - get { - return this.HierarchyNode.Url; - } - } - - #region non-browsable properties - used for automation only - - [Browsable(false)] - public string URL { - get { - return this.HierarchyNode.Url; - } - } - - [Browsable(false)] - public string Extension { - get { - return Path.GetExtension(this.HierarchyNode.Caption); - } - } - - [Browsable(false)] - public bool IsLinkFile { - get { - return HierarchyNode.IsLinkFile; - } - } - - #endregion - - #endregion - - #region ctors - internal FileNodeProperties(HierarchyNode node) - : base(node) { - } - #endregion - - public override string GetClassName() { - return SR.GetString(SR.FileProperties); - } - } - - [ComVisible(true)] - public class ExcludedFileNodeProperties : FileNodeProperties { - internal ExcludedFileNodeProperties(HierarchyNode node) - : base(node) { - } - - [SRCategoryAttribute(SR.Advanced)] - [SRDisplayName(SR.BuildAction)] - [SRDescriptionAttribute(SR.BuildActionDescription)] - [TypeConverter(typeof(BuildActionTypeConverter))] - public prjBuildAction BuildAction { - get { - return prjBuildAction.prjBuildActionNone; - } - } - } - - [ComVisible(true)] - public class IncludedFileNodeProperties : FileNodeProperties { - internal IncludedFileNodeProperties(HierarchyNode node) - : base(node) { - } - - /// - /// Specifies the build action as a string so the user can configure it to any value. - /// - [SRCategoryAttribute(SR.Advanced)] - [SRDisplayName(SR.BuildAction)] - [SRDescriptionAttribute(SR.BuildActionDescription)] - [AlwaysSerialized] - [TypeConverter(typeof(BuildActionStringConverter))] - public string ItemType { - get { - return HierarchyNode.ItemNode.ItemTypeName; - } - set { - HierarchyNode.ItemNode.ItemTypeName = value; - } - } - - /// - /// Specifies the build action as a projBuildAction so that automation can get the - /// expected enum value. - /// - [Browsable(false)] - public prjBuildAction BuildAction { - get { - var res = BuildActionTypeConverter.Instance.ConvertFromString(HierarchyNode.ItemNode.ItemTypeName); - if (res is prjBuildAction) { - return (prjBuildAction)res; - } - return prjBuildAction.prjBuildActionContent; - } - set { - this.HierarchyNode.ItemNode.ItemTypeName = BuildActionTypeConverter.Instance.ConvertToString(value); - } - } - - [SRCategoryAttribute(SR.Advanced)] - [SRDisplayName(SR.Publish)] - [SRDescriptionAttribute(SR.PublishDescription)] - public bool Publish { - get { - var publish = this.HierarchyNode.ItemNode.GetMetadata("Publish"); - if (String.IsNullOrEmpty(publish)) { - if (this.HierarchyNode.ItemNode.ItemTypeName == ProjectFileConstants.Compile) { - return true; - } - return false; - } - return Convert.ToBoolean(publish); - } - set { - this.HierarchyNode.ItemNode.SetMetadata("Publish", value.ToString()); - } - } - - [Browsable(false)] - public bool ShouldSerializePublish() { - // If compile, default should be true, else the default is false. - if (HierarchyNode.ItemNode.ItemTypeName == ProjectFileConstants.Compile) { - return !Publish; - } - return Publish; - } - - [Browsable(false)] - public void ResetPublish() { - // If compile, default should be true, else the default is false. - if (HierarchyNode.ItemNode.ItemTypeName == ProjectFileConstants.Compile) { - Publish = true; - } - Publish = false; - } - - [Browsable(false)] - public string SourceControlStatus { - get { - // remove STATEICON_ and return rest of enum - return HierarchyNode.StateIconIndex.ToString().Substring(10); - } - } - - [Browsable(false)] - public string SubType { - get { - return this.HierarchyNode.ItemNode.GetMetadata("SubType"); - } - set { - this.HierarchyNode.ItemNode.SetMetadata("SubType", value.ToString()); - } - } - } - - [ComVisible(true)] - public class LinkFileNodeProperties : FileNodeProperties { - internal LinkFileNodeProperties(HierarchyNode node) - : base(node) { - - } - - [SRCategoryAttribute(SR.Misc)] - [SRDisplayName(SR.FileName)] - [SRDescriptionAttribute(SR.FileNameDescription)] - [ReadOnly(true)] - public override string FileName { - get { - return this.HierarchyNode.Caption; - } - set { - throw new InvalidOperationException(); - } - } - } - - [ComVisible(true)] - public class DependentFileNodeProperties : NodeProperties { - #region properties - - [SRCategoryAttribute(SR.Misc)] - [SRDisplayName(SR.FileName)] - [SRDescriptionAttribute(SR.FileNameDescription)] - public virtual string FileName { - get { - return this.HierarchyNode.Caption; - } - } - - [SRCategoryAttribute(SR.Misc)] - [SRDisplayName(SR.FullPath)] - [SRDescriptionAttribute(SR.FullPathDescription)] - public string FullPath { - get { - return this.HierarchyNode.Url; - } - } - #endregion - - #region ctors - internal DependentFileNodeProperties(HierarchyNode node) - : base(node) { - } - - #endregion - - public override string GetClassName() { - return SR.GetString(SR.FileProperties); - } - } - - class BuildActionTypeConverter : StringConverter { - internal static readonly BuildActionTypeConverter Instance = new BuildActionTypeConverter(); - - public BuildActionTypeConverter() { - } - - public override bool GetStandardValuesSupported(ITypeDescriptorContext context) { - return true; - } - - public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) { - if (sourceType == typeof(string)) { - return true; - } - return base.CanConvertFrom(context, sourceType); - } - - public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) { - return base.CanConvertTo(context, destinationType); - } - - public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) { - if (destinationType == typeof(string)) { - switch ((prjBuildAction)value) { - case prjBuildAction.prjBuildActionCompile: - return ProjectFileConstants.Compile; - case prjBuildAction.prjBuildActionContent: - return ProjectFileConstants.Content; - case prjBuildAction.prjBuildActionNone: - return ProjectFileConstants.None; - } - } - return base.ConvertTo(context, culture, value, destinationType); - } - - public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { - if (value is string) { - string strVal = (string)value; - if (strVal.Equals(ProjectFileConstants.Compile, StringComparison.OrdinalIgnoreCase)) { - return prjBuildAction.prjBuildActionCompile; - } else if (strVal.Equals(ProjectFileConstants.Content, StringComparison.OrdinalIgnoreCase)) { - return prjBuildAction.prjBuildActionContent; - } else if (strVal.Equals(ProjectFileConstants.None, StringComparison.OrdinalIgnoreCase)) { - return prjBuildAction.prjBuildActionNone; - } - } - return base.ConvertFrom(context, culture, value); - } - - public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context) { - return new StandardValuesCollection(new[] { prjBuildAction.prjBuildActionNone, prjBuildAction.prjBuildActionCompile, prjBuildAction.prjBuildActionContent }); - } - } - - /// - /// This type converter doesn't really do any conversions, but allows us to provide - /// a list of standard values for the build action. - /// - class BuildActionStringConverter : StringConverter { - internal static readonly BuildActionStringConverter Instance = new BuildActionStringConverter(); - - public BuildActionStringConverter() { - } - - public override bool GetStandardValuesSupported(ITypeDescriptorContext context) { - return true; - } - - public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) { - if (sourceType == typeof(string)) { - return true; - } - return base.CanConvertFrom(context, sourceType); - } - - public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) { - return base.CanConvertTo(context, destinationType); - } - - public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) { - return value; - } - - public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { - return value; - } - - public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context) { - FileNodeProperties nodeProps = context.Instance as FileNodeProperties; - IEnumerable itemNames; - if (nodeProps != null) { - itemNames = nodeProps.HierarchyNode.ProjectMgr.GetAvailableItemNames(); - } else { - itemNames = new[] { ProjectFileConstants.None, ProjectFileConstants.Compile, ProjectFileConstants.Content }; - } - return new StandardValuesCollection(itemNames.ToArray()); - } - } - - [ComVisible(true)] - public class ProjectNodeProperties : NodeProperties, EnvDTE80.IInternalExtenderProvider { - #region properties - [SRCategoryAttribute(SR.Misc)] - [SRDisplayName(SR.ProjectFolder)] - [SRDescriptionAttribute(SR.ProjectFolderDescription)] - [AutomationBrowsable(false)] - public string ProjectFolder { - get { - return this.Node.ProjectMgr.ProjectFolder; - } - } - - [SRCategoryAttribute(SR.Misc)] - [SRDisplayName(SR.ProjectFile)] - [SRDescriptionAttribute(SR.ProjectFileDescription)] - [AutomationBrowsable(false)] - public string ProjectFile { - get { - return this.Node.ProjectMgr.ProjectFile; - } - set { - this.Node.ProjectMgr.ProjectFile = value; - } - } - - #region non-browsable properties - used for automation only - [Browsable(false)] - public string Guid { - get { - return this.Node.ProjectMgr.ProjectIDGuid.ToString(); - } - } - - [Browsable(false)] - public string FileName { - get { - return this.Node.ProjectMgr.ProjectFile; - } - set { - this.Node.ProjectMgr.ProjectFile = value; - } - } - - - [Browsable(false)] - public string FullPath { - get { - return CommonUtils.NormalizeDirectoryPath(this.Node.ProjectMgr.ProjectFolder); - } - } - #endregion - - #endregion - - #region ctors - internal ProjectNodeProperties(ProjectNode node) - : base(node) { - } - - internal new ProjectNode Node { - get { - return (ProjectNode)base.Node; - } - } - - #endregion - - #region overridden methods - - /// - /// ICustomTypeDescriptor.GetEditor - /// To enable the "Property Pages" button on the properties browser - /// the browse object (project properties) need to be unmanaged - /// or it needs to provide an editor of type ComponentEditor. - /// - /// Type of the editor - /// Editor - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", - Justification = "The service provider is used by the PropertiesEditorLauncher")] - public override object GetEditor(Type editorBaseType) { - // Override the scenario where we are asked for a ComponentEditor - // as this is how the Properties Browser calls us - if (editorBaseType == typeof(ComponentEditor)) { - IOleServiceProvider sp; - ErrorHandler.ThrowOnFailure(Node.ProjectMgr.GetSite(out sp)); - return new PropertiesEditorLauncher(new ServiceProvider(sp)); - } - - return base.GetEditor(editorBaseType); - } - - public override int GetCfgProvider(out IVsCfgProvider p) { - if (this.Node != null && this.Node.ProjectMgr != null) { - return this.Node.ProjectMgr.GetCfgProvider(out p); - } - - return base.GetCfgProvider(out p); - } - - public override string GetClassName() { - return SR.GetString(SR.ProjectProperties); - } - - #endregion - - #region IInternalExtenderProvider Members - - bool EnvDTE80.IInternalExtenderProvider.CanExtend(string extenderCATID, string extenderName, object extendeeObject) { - EnvDTE80.IInternalExtenderProvider outerHierarchy = Node.GetOuterInterface(); - - if (outerHierarchy != null) { - return outerHierarchy.CanExtend(extenderCATID, extenderName, extendeeObject); - } - return false; - } - - object EnvDTE80.IInternalExtenderProvider.GetExtender(string extenderCATID, string extenderName, object extendeeObject, EnvDTE.IExtenderSite extenderSite, int cookie) { - EnvDTE80.IInternalExtenderProvider outerHierarchy = Node.GetOuterInterface(); - - if (outerHierarchy != null) { - return outerHierarchy.GetExtender(extenderCATID, extenderName, extendeeObject, extenderSite, cookie); - } - - return null; - } - - object EnvDTE80.IInternalExtenderProvider.GetExtenderNames(string extenderCATID, object extendeeObject) { - return null; - } - - #endregion - } - - [ComVisible(true)] - public class FolderNodeProperties : NodeProperties { - #region properties - [SRCategoryAttribute(SR.Misc)] - [SRDisplayName(SR.FolderName)] - [SRDescriptionAttribute(SR.FolderNameDescription)] - public string FolderName { - get { - return this.HierarchyNode.Caption; - } - set { - UIThread.Invoke(() => { - this.HierarchyNode.SetEditLabel(value); - this.HierarchyNode.ProjectMgr.ReDrawNode(HierarchyNode, UIHierarchyElement.Caption); - }); - } - } - - #region properties - used for automation only - [Browsable(false)] - [AutomationBrowsable(true)] - public string FileName { - get { - return this.HierarchyNode.Caption; - } - set { - UIThread.Invoke(() => { - this.HierarchyNode.SetEditLabel(value); - this.HierarchyNode.ProjectMgr.ReDrawNode(HierarchyNode, UIHierarchyElement.Caption); - }); - } - } - - [Browsable(true)] - [AutomationBrowsable(true)] - [SRCategoryAttribute(SR.Misc)] - [SRDisplayName(SR.FullPath)] - [SRDescriptionAttribute(SR.FullPathDescription)] - public string FullPath { - get { - return CommonUtils.NormalizeDirectoryPath(this.HierarchyNode.GetMkDocument()); - } - } - #endregion - - #endregion - - #region ctors - internal FolderNodeProperties(HierarchyNode node) - : base(node) { - } - #endregion - - public override string GetClassName() { - return SR.GetString(SR.FolderProperties); - } - } - - [CLSCompliant(false), ComVisible(true)] - public class ReferenceNodeProperties : NodeProperties { - #region properties - [SRCategoryAttribute(SR.Misc)] - [SRDisplayName(SR.RefName)] - [SRDescriptionAttribute(SR.RefNameDescription)] - [Browsable(true)] - [AutomationBrowsable(true)] - public override string Name { - get { - return this.HierarchyNode.Caption; - } - } - - [SRCategoryAttribute(SR.Misc)] - [SRDisplayName(SR.CopyToLocal)] - [SRDescriptionAttribute(SR.CopyToLocalDescription)] - public bool CopyToLocal { - get { - string copyLocal = this.GetProperty(ProjectFileConstants.Private, "False"); - if (copyLocal == null || copyLocal.Length == 0) - return true; - return bool.Parse(copyLocal); - } - set { - this.SetProperty(ProjectFileConstants.Private, value.ToString()); - } - } - - [SRCategoryAttribute(SR.Misc)] - [SRDisplayName(SR.FullPath)] - [SRDescriptionAttribute(SR.FullPathDescription)] - public virtual string FullPath { - get { - return this.HierarchyNode.Url; - } - } - #endregion - - #region ctors - internal ReferenceNodeProperties(HierarchyNode node) - : base(node) { - } - #endregion - - #region overridden methods - public override string GetClassName() { - return SR.GetString(SR.ReferenceProperties); - } - #endregion - } - - [ComVisible(true)] - public class ProjectReferencesProperties : ReferenceNodeProperties { - #region ctors - internal ProjectReferencesProperties(ProjectReferenceNode node) - : base(node) { - } - #endregion - - #region overriden methods - public override string FullPath { - get { - return ((ProjectReferenceNode)Node).ReferencedProjectOutputPath; - } - } - #endregion - } -} diff --git a/Microsoft.VisualStudio.Project/OleServiceProvider.cs b/Microsoft.VisualStudio.Project/OleServiceProvider.cs deleted file mode 100644 index fa0d2807..00000000 --- a/Microsoft.VisualStudio.Project/OleServiceProvider.cs +++ /dev/null @@ -1,232 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Runtime.InteropServices; -using Microsoft.VisualStudio; -using IOleServiceProvider = Microsoft.VisualStudio.OLE.Interop.IServiceProvider; - -namespace Microsoft.VisualStudioTools.Project { - // This class is No longer used by project system, retained for backwards for languages - // which have already shipped this public type. -#if SHAREDPROJECT_OLESERVICEPROVIDER - public class OleServiceProvider : IOleServiceProvider, IDisposable { - #region Public Types - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")] - public delegate object ServiceCreatorCallback(Type serviceType); - #endregion - - #region Private Types - private class ServiceData : IDisposable { - private Type serviceType; - private object instance; - private ServiceCreatorCallback creator; - private bool shouldDispose; - public ServiceData(Type serviceType, object instance, ServiceCreatorCallback callback, bool shouldDispose) { - Utilities.ArgumentNotNull("serviceType", serviceType); - - if ((null == instance) && (null == callback)) { - throw new ArgumentNullException("instance"); - } - - this.serviceType = serviceType; - this.instance = instance; - this.creator = callback; - this.shouldDispose = shouldDispose; - } - - public object ServiceInstance { - get { - if (null == instance) { - Debug.Assert(serviceType != null); - instance = creator(serviceType); - } - return instance; - } - } - - public Guid Guid { - get { return serviceType.GUID; } - } - - public void Dispose() { - if ((shouldDispose) && (null != instance)) { - IDisposable disp = instance as IDisposable; - if (null != disp) { - disp.Dispose(); - } - instance = null; - } - creator = null; - GC.SuppressFinalize(this); - } - } - #endregion - - #region fields - - private Dictionary services = new Dictionary(); - private bool isDisposed; - /// - /// Defines an object that will be a mutex for this object for synchronizing thread calls. - /// - private static volatile object Mutex = new object(); - #endregion - - #region ctors - public OleServiceProvider() { - } - #endregion - - #region IOleServiceProvider Members - - public int QueryService(ref Guid guidService, ref Guid riid, out IntPtr ppvObject) { - ppvObject = (IntPtr)0; - int hr = VSConstants.S_OK; - - ServiceData serviceInstance = null; - - if (services != null && services.ContainsKey(guidService)) { - serviceInstance = services[guidService]; - } - - if (serviceInstance == null) { - return VSConstants.E_NOINTERFACE; - } - - // Now check to see if the user asked for an IID other than - // IUnknown. If so, we must do another QI. - // - if (riid.Equals(NativeMethods.IID_IUnknown)) { - object inst = serviceInstance.ServiceInstance; - if (inst == null) { - return VSConstants.E_NOINTERFACE; - } - ppvObject = Marshal.GetIUnknownForObject(serviceInstance.ServiceInstance); - } else { - IntPtr pUnk = IntPtr.Zero; - try { - pUnk = Marshal.GetIUnknownForObject(serviceInstance.ServiceInstance); - hr = Marshal.QueryInterface(pUnk, ref riid, out ppvObject); - } finally { - if (pUnk != IntPtr.Zero) { - Marshal.Release(pUnk); - } - } - } - - return hr; - } - - #endregion - - #region Dispose - - /// - /// The IDispose interface Dispose method for disposing the object determinastically. - /// - public void Dispose() { - Dispose(true); - GC.SuppressFinalize(this); - } - - #endregion - - /// - /// Adds the given service to the service container. - /// - /// The type of the service to add. - /// An instance of the service. - /// true if the Dipose of the service provider is allowed to dispose the sevice instance. - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", - Justification = "The services created here will be disposed in the Dispose method of this type.")] - public void AddService(Type serviceType, object serviceInstance, bool shouldDisposeServiceInstance) { - // Create the description of this service. Note that we don't do any validation - // of the parameter here because the constructor of ServiceData will do it for us. - ServiceData service = new ServiceData(serviceType, serviceInstance, null, shouldDisposeServiceInstance); - - // Now add the service desctription to the dictionary. - AddService(service); - } - - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", - Justification = "The services created here will be disposed in the Dispose method of this type.")] - public void AddService(Type serviceType, ServiceCreatorCallback callback, bool shouldDisposeServiceInstance) { - // Create the description of this service. Note that we don't do any validation - // of the parameter here because the constructor of ServiceData will do it for us. - ServiceData service = new ServiceData(serviceType, null, callback, shouldDisposeServiceInstance); - - // Now add the service desctription to the dictionary. - AddService(service); - } - - private void AddService(ServiceData data) { - // Make sure that the collection of services is created. - if (null == services) { - services = new Dictionary(); - } - - // Disallow the addition of duplicate services. - if (services.ContainsKey(data.Guid)) { - throw new InvalidOperationException(); - } - - services.Add(data.Guid, data); - } - - /// - /// Removes the given service type from the service container. - /// - public void RemoveService(Type serviceType) { - Utilities.ArgumentNotNull("serviceType", serviceType); - - if (services.ContainsKey(serviceType.GUID)) { - services.Remove(serviceType.GUID); - } - } - - #region helper methods - /// - /// The method that does the cleanup. - /// - /// - protected virtual void Dispose(bool disposing) { - // Everybody can go here. - if (!this.isDisposed) { - // Synchronize calls to the Dispose simulteniously. - lock (Mutex) { - if (disposing) { - // Remove all our services - if (services != null) { - foreach (ServiceData data in services.Values) { - data.Dispose(); - } - services.Clear(); - services = null; - } - } - - this.isDisposed = true; - } - } - } - #endregion - - } -#endif -} diff --git a/Microsoft.VisualStudio.Project/Output.cs b/Microsoft.VisualStudio.Project/Output.cs deleted file mode 100644 index 7f4e28f0..00000000 --- a/Microsoft.VisualStudio.Project/Output.cs +++ /dev/null @@ -1,150 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Diagnostics; -using System.IO; -using Microsoft.Build.Execution; -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.Shell; -using Microsoft.VisualStudio.Shell.Interop; - -namespace Microsoft.VisualStudioTools.Project { - class Output : IVsOutput2 { - private ProjectNode project; - private ProjectItemInstance output; - - /// - /// Constructor for IVSOutput2 implementation - /// - /// Project that produce this output - /// MSBuild generated item corresponding to the output assembly (by default, these would be of type MainAssembly - public Output(ProjectNode projectManager, ProjectItemInstance outputAssembly) { - Utilities.ArgumentNotNull("projectManager", projectManager); - - project = projectManager; - output = outputAssembly; - } - - internal string CanonicalName { - get { - string canonicalName; - return ErrorHandler.Succeeded(get_CanonicalName(out canonicalName)) ? canonicalName : null; - } - } - - internal string GetMetadata(string name) { - object value; - return ErrorHandler.Succeeded(get_Property(name, out value)) ? value as string : null; - } - - #region IVsOutput2 Members - - public int get_CanonicalName(out string pbstrCanonicalName) { - if (output == null) { - pbstrCanonicalName = project.Url; - return VSConstants.S_OK; - } - - // Get the output assembly path (including the name) - pbstrCanonicalName = output.GetMetadataValue("FullPath"); - Debug.Assert(!String.IsNullOrEmpty(pbstrCanonicalName), "Output Assembly not defined"); - - // Make sure we have a full path - pbstrCanonicalName = CommonUtils.GetAbsoluteFilePath(project.ProjectHome, pbstrCanonicalName); - return VSConstants.S_OK; - } - - /// - /// This path must start with file:/// if it wants other project - /// to be able to reference the output on disk. - /// If the output is not on disk, then this requirement does not - /// apply as other projects probably don't know how to access it. - /// - public virtual int get_DeploySourceURL(out string pbstrDeploySourceURL) { - if (output == null) { - // we're lying here to keep callers happy who expect a path... See also OutputGroup.get_KeyOutputObject - pbstrDeploySourceURL = GetType().Assembly.CodeBase; - return VSConstants.S_OK; - } - - string path = output.GetMetadataValue(ProjectFileConstants.FinalOutputPath); - if (string.IsNullOrEmpty(path)) { - pbstrDeploySourceURL = new Url(output.GetMetadataValue("FullPath")).Uri.AbsoluteUri; - return VSConstants.S_OK; - } - if (path.Length < 9 || String.Compare(path.Substring(0, 8), "file:///", StringComparison.OrdinalIgnoreCase) != 0) - path = "file:///" + path; - pbstrDeploySourceURL = path; - return VSConstants.S_OK; - } - - public int get_DisplayName(out string pbstrDisplayName) { - return this.get_CanonicalName(out pbstrDisplayName); - } - - public virtual int get_Property(string szProperty, out object pvar) { - if (output == null) { - switch (szProperty) { - case "FinalOutputPath": - pvar = typeof(string).Assembly.CodeBase; - return VSConstants.S_OK; - } - pvar = null; - return VSConstants.E_NOTIMPL; - } - String value = output.GetMetadataValue(szProperty); - pvar = value; - - // If we don't have a value, we are expected to return unimplemented - return String.IsNullOrEmpty(value) ? VSConstants.E_NOTIMPL : VSConstants.S_OK; - } - - public int get_RootRelativeURL(out string pbstrRelativePath) { - if (output == null) { - pbstrRelativePath = project.ProjectHome; - return VSConstants.E_FAIL; - } - - pbstrRelativePath = String.Empty; - object variant; - // get the corresponding property - - if (ErrorHandler.Succeeded(this.get_Property("TargetPath", out variant))) { - string var = variant as String; - - if (var != null) { - pbstrRelativePath = var; - } - } else { - string baseDir = project.ProjectHome; - string fullPath = output.GetMetadataValue("FullPath"); - if (CommonUtils.IsSubpathOf(baseDir, fullPath)) { - pbstrRelativePath = CommonUtils.GetRelativeFilePath(baseDir, fullPath); - } - } - - return VSConstants.S_OK; - } - - public virtual int get_Type(out Guid pguidType) { - pguidType = Guid.Empty; - throw new NotImplementedException(); - } - - #endregion - } -} diff --git a/Microsoft.VisualStudio.Project/OutputGroup.cs b/Microsoft.VisualStudio.Project/OutputGroup.cs deleted file mode 100644 index 71dfb34a..00000000 --- a/Microsoft.VisualStudio.Project/OutputGroup.cs +++ /dev/null @@ -1,264 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.InteropServices; -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.Shell.Interop; -using MSBuildExecution = Microsoft.Build.Execution; - -namespace Microsoft.VisualStudioTools.Project { - /// - /// Allows projects to group outputs according to usage. - /// - [ComVisible(true)] - internal class OutputGroup : IVsOutputGroup2 { - private readonly ProjectConfig _projectCfg; - private readonly ProjectNode _project; - private readonly List _outputs = new List(); - private readonly string _name; - private readonly string _targetName; - private Output _keyOutput; - - - /// - /// Constructor for IVSOutputGroup2 implementation - /// - /// Name of the output group. See VS_OUTPUTGROUP_CNAME_Build in vsshell.idl for the list of standard values - /// MSBuild target name - /// Project that produce this output - /// Configuration that produce this output - public OutputGroup(string outputName, string msBuildTargetName, ProjectNode projectManager, ProjectConfig configuration) { - Utilities.ArgumentNotNull("outputName", outputName); - Utilities.ArgumentNotNull("msBuildTargetName", msBuildTargetName); - Utilities.ArgumentNotNull("projectManager", projectManager); - Utilities.ArgumentNotNull("configuration", configuration); - - _name = outputName; - _targetName = msBuildTargetName; - _project = projectManager; - _projectCfg = configuration; - } - - /// - /// Get the project configuration object associated with this output group - /// - protected ProjectConfig ProjectCfg { - get { return _projectCfg; } - } - - /// - /// Get the project object that produces this output group. - /// - internal ProjectNode Project { - get { return _project; } - } - - /// - /// Gets the msbuild target name which is assciated to the outputgroup. - /// ProjectNode defines a static collection of output group names and their associated MsBuild target - /// - protected string TargetName { - get { return _targetName; } - } - - /// - /// Easy access to the canonical name of the group. - /// - internal string Name { - get { - string canonicalName; - ErrorHandler.ThrowOnFailure(get_CanonicalName(out canonicalName)); - return canonicalName; - } - } - - #region virtual methods - - protected virtual void Refresh() { - // Let MSBuild know which configuration we are working with - _project.SetConfiguration(_projectCfg.ConfigName); - - // Generate dependencies if such a task exist - if (_project.BuildProject.Targets.ContainsKey(_targetName)) { - bool succeeded = false; - _project.BuildTarget(_targetName, out succeeded); - if (!succeeded) { - Debug.WriteLine("Failed to build target {0}", _targetName); - this._outputs.Clear(); - return; - } - } - - // Rebuild the content of our list of output - string outputType = _targetName + "Output"; - this._outputs.Clear(); - - if (_project.CurrentConfig != null) { - foreach (MSBuildExecution.ProjectItemInstance assembly in _project.CurrentConfig.GetItems(outputType)) { - Output output = new Output(_project, assembly); - _outputs.Add(output); - - // See if it is our key output - if (_keyOutput == null || - String.Compare(assembly.GetMetadataValue("IsKeyOutput"), true.ToString(), StringComparison.OrdinalIgnoreCase) == 0) { - _keyOutput = output; - } - } - } - - _project.SetCurrentConfiguration(); - - // Now that the group is built we have to check if it is invalidated by a property - // change on the project. - _project.OnProjectPropertyChanged += new EventHandler(OnProjectPropertyChanged); - } - - public virtual IList EnumerateOutputs() { - UIThread.Invoke(Refresh); - return _outputs; - } - - public virtual void InvalidateGroup() { - // Set keyOutput to null so that a refresh will be performed the next time - // a property getter is called. - if (null != _keyOutput) { - // Once the group is invalidated there is no more reason to listen for events. - _project.OnProjectPropertyChanged -= new EventHandler(OnProjectPropertyChanged); - } - _keyOutput = null; - } - #endregion - - #region event handlers - private void OnProjectPropertyChanged(object sender, ProjectPropertyChangedArgs args) { - // In theory here we should decide if we have to invalidate the group according with the kind of property - // that is changed. - InvalidateGroup(); - } - #endregion - - #region IVsOutputGroup2 Members - - public virtual int get_CanonicalName(out string pbstrCanonicalName) { - pbstrCanonicalName = this._name; - return VSConstants.S_OK; - } - - public virtual int get_DeployDependencies(uint celt, IVsDeployDependency[] rgpdpd, uint[] pcActual) { - return VSConstants.E_NOTIMPL; - } - - public virtual int get_Description(out string pbstrDescription) { - pbstrDescription = null; - - string description; - int hr = this.get_CanonicalName(out description); - if (ErrorHandler.Succeeded(hr)) - pbstrDescription = this.Project.GetOutputGroupDescription(description); - return hr; - } - - public virtual int get_DisplayName(out string pbstrDisplayName) { - pbstrDisplayName = null; - - string displayName; - int hr = this.get_CanonicalName(out displayName); - if (ErrorHandler.Succeeded(hr)) - pbstrDisplayName = this.Project.GetOutputGroupDisplayName(displayName); - return hr; - } - - public virtual int get_KeyOutput(out string pbstrCanonicalName) { - pbstrCanonicalName = null; - if (_keyOutput == null) - Refresh(); - if (_keyOutput == null) { - pbstrCanonicalName = String.Empty; - return VSConstants.S_FALSE; - } - return _keyOutput.get_CanonicalName(out pbstrCanonicalName); - } - - public virtual int get_KeyOutputObject(out IVsOutput2 ppKeyOutput) { - if (_keyOutput == null) { - Refresh(); - if (_keyOutput == null) { - // horrible hack: we don't really have outputs but the Cider designer insists - // that we have an output so it can figure out our output assembly name. So we - // lie here, and then lie again to give a path in Output.get_Property - _keyOutput = new Output(_project, null); - } - } - ppKeyOutput = _keyOutput; - if (ppKeyOutput == null) - return VSConstants.S_FALSE; - return VSConstants.S_OK; - } - - public virtual int get_Outputs(uint celt, IVsOutput2[] rgpcfg, uint[] pcActual) { - // Ensure that we are refreshed. This is somewhat of a hack that enables project to - // project reference scenarios to work. Normally, output groups are populated as part - // of build. However, in the project to project reference case, what ends up happening - // is that the referencing projects requests the referenced project's output group - // before a build is done on the referenced project. - // - // Furthermore, the project auto toolbox manager requires output groups to be populated - // on project reopen as well... - // - // In the end, this is probably the right thing to do, though -- as it keeps the output - // groups always up to date. - Refresh(); - - // See if only the caller only wants to know the count - if (celt == 0 || rgpcfg == null) { - if (pcActual != null && pcActual.Length > 0) - pcActual[0] = (uint)_outputs.Count; - return VSConstants.S_OK; - } - - // Fill the array with our outputs - uint count = 0; - foreach (Output output in _outputs) { - if (rgpcfg.Length > count && celt > count && output != null) { - rgpcfg[count] = output; - ++count; - } - } - - if (pcActual != null && pcActual.Length > 0) - pcActual[0] = count; - - // If the number asked for does not match the number returned, return S_FALSE - return (count == celt) ? VSConstants.S_OK : VSConstants.S_FALSE; - } - - public virtual int get_ProjectCfg(out IVsProjectCfg2 ppIVsProjectCfg2) { - ppIVsProjectCfg2 = (IVsProjectCfg2)this._projectCfg; - return VSConstants.S_OK; - } - - public virtual int get_Property(string pszProperty, out object pvar) { - pvar = _project.GetProjectProperty(pszProperty); - return VSConstants.S_OK; - } - - #endregion - } -} diff --git a/Microsoft.VisualStudio.Project/OutputWindowRedirector.cs b/Microsoft.VisualStudio.Project/OutputWindowRedirector.cs deleted file mode 100644 index 31b4ffc1..00000000 --- a/Microsoft.VisualStudio.Project/OutputWindowRedirector.cs +++ /dev/null @@ -1,136 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Diagnostics; -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.Shell.Interop; - -namespace Microsoft.VisualStudioTools.Project { - class OutputWindowRedirector : Redirector { - private static readonly Guid OutputWindowGuid = new Guid("{34E76E81-EE4A-11D0-AE2E-00A0C90FFFC3}"); - static OutputWindowRedirector _generalPane; - - /// - /// Gets or creates the specified output pane. - /// - /// The output pane could - /// not be found or created. - public static OutputWindowRedirector Get(IServiceProvider provider, Guid id, string title) { - var outputWindow = provider.GetService(typeof(SVsOutputWindow)) as IVsOutputWindow; - if (outputWindow == null) { - throw new InvalidOperationException("Unable to get output window service"); - } - - IVsOutputWindowPane pane; - if (ErrorHandler.Failed(outputWindow.GetPane(id, out pane)) || pane == null) { - if (ErrorHandler.Failed(UIThread.Invoke(() => outputWindow.CreatePane(id, title, 1, 0)))) { - throw new InvalidOperationException("Unable to create output pane"); - } - } - return new OutputWindowRedirector(provider, id); - } - - /// - /// Gets or creates the "General" output pane. - /// - /// The "General" pane could - /// not be found or created. - public static OutputWindowRedirector GetGeneral(IServiceProvider provider) { - if (_generalPane == null) { - _generalPane = Get(provider, VSConstants.OutputWindowPaneGuid.GeneralPane_guid, "General"); - } - return _generalPane; - } - - readonly IVsWindowFrame _window; - readonly IVsOutputWindowPane _pane; - - public IVsOutputWindowPane Pane { get { return _pane; } } - - /// - /// Creates a redirector to the specified output pane. - /// - /// - /// An active service provider. - /// - /// - /// The ID of the pane to direct output to. - /// - /// - /// The pane could not be found or the Output Window service is not - /// available. - /// - public OutputWindowRedirector(IServiceProvider provider, Guid paneGuid) { - var shell = provider.GetService(typeof(SVsUIShell)) as IVsUIShell; - if (shell != null) { - // Ignore errors - we just won't support opening the window if - // we don't find it. - var windowGuid = OutputWindowGuid; - shell.FindToolWindow(0, ref windowGuid, out _window); - } - var outputWindow = provider.GetService(typeof(SVsOutputWindow)) as IVsOutputWindow; - if (outputWindow == null) { - throw new InvalidOperationException("Unable to get output window service"); - } - if (ErrorHandler.Failed(outputWindow.GetPane(paneGuid, out _pane))) { - throw new InvalidOperationException("Unable to get output pane"); - } - } - - /// - /// Creates a redirector to the specified output pane. - /// - /// - /// The window containing the pane. Optional, but if omitted then the - /// and methods become - /// no-ops. - /// - /// - /// The pane to direct output to. - /// - public OutputWindowRedirector(IVsWindowFrame window, IVsOutputWindowPane pane) { - _window = window; - if (pane == null) { - throw new ArgumentNullException("pane"); - } - _pane = pane; - } - - public override void Show() { - UIThread.Invoke(() => ErrorHandler.ThrowOnFailure(_pane.Activate())); - } - - public override void ShowAndActivate() { - UIThread.Invoke(() => { - ErrorHandler.ThrowOnFailure(_pane.Activate()); - if (_window != null) { - ErrorHandler.ThrowOnFailure(_window.ShowNoActivate()); - } - }); - } - - public override void WriteLine(string line) { - _pane.OutputStringThreadSafe(line + Environment.NewLine); - Debug.WriteLine(line, "Output Window"); - } - - public override void WriteErrorLine(string line) { - _pane.OutputStringThreadSafe(line + Environment.NewLine); - Debug.WriteLine(line, "Output Window"); - } - } -} diff --git a/Microsoft.VisualStudio.Project/OverwriteFileDialog.xaml b/Microsoft.VisualStudio.Project/OverwriteFileDialog.xaml deleted file mode 100644 index 029e8215..00000000 --- a/Microsoft.VisualStudio.Project/OverwriteFileDialog.xaml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - public event EventHandler AfterProjectFileOpened; - - /// - /// Event raised before the project file closed. - /// - public event EventHandler BeforeProjectFileClosed; - #endregion - - #region ctor - internal SolutionListenerForProjectEvents(IServiceProvider serviceProvider) - : base(serviceProvider) - { - } - #endregion - - #region overridden methods - public override int OnAfterOpenProject(IVsHierarchy hierarchy, int added) - { - return VSConstants.S_OK; - } - - public override int OnBeforeCloseProject(IVsHierarchy hierarchy, int removed) - { - return VSConstants.S_OK; - } - #endregion - - #region helpers - /// - /// Raises after project file opened event. - /// - /// True if the project is added to the solution after the solution is opened. false if the project is added to the solution while the solution is being opened. - private void RaiseAfterProjectFileOpened(bool added) - { - // Save event in temporary variable to avoid race condition. - EventHandler tempEvent = this.AfterProjectFileOpened; - if (tempEvent != null) - { - tempEvent(this, new AfterProjectFileOpenedEventArgs()); - } - } - - - - - /// - /// Raises the before project file closed event. - /// - /// true if the project was removed from the solution before the solution was closed. false if the project was removed from the solution while the solution was being closed. - private void RaiseBeforeProjectFileClosed(IVsHierarchy hierarchy, bool removed) - { - // Save event in temporary variable to avoid race condition. - EventHandler tempEvent = this.BeforeProjectFileClosed; - if (tempEvent != null) - { - tempEvent(this, new BeforeProjectFileClosedEventArgs(hierarchy, removed)); - } - } - } - #endregion -} diff --git a/Microsoft.VisualStudio.Project/SolutionListenerForProjectOpen.cs b/Microsoft.VisualStudio.Project/SolutionListenerForProjectOpen.cs deleted file mode 100644 index 047dec7f..00000000 --- a/Microsoft.VisualStudio.Project/SolutionListenerForProjectOpen.cs +++ /dev/null @@ -1,71 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System.Diagnostics; -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.Shell.Interop; -using Microsoft.VisualStudioTools.Project.Automation; -using IServiceProvider = System.IServiceProvider; - -namespace Microsoft.VisualStudioTools.Project { - - - internal class SolutionListenerForProjectOpen : SolutionListener { - public SolutionListenerForProjectOpen(IServiceProvider serviceProvider) - : base(serviceProvider) { - } - - public override int OnAfterOpenProject(IVsHierarchy hierarchy, int added) { - // If this is our project, notify it that it has been opened. - if (hierarchy.GetProject() != null) { - var oaProject = hierarchy.GetProject() as OAProject; - if (oaProject != null && oaProject.Project is ProjectNode) { - ((ProjectNode)oaProject.Project).OnAfterProjectOpen(); - } - } - - // If this is a new project and our project. We use here that it is only our project that will implemnet the "internal" IBuildDependencyOnProjectContainer. - if (added != 0 && hierarchy is IBuildDependencyUpdate) { - IVsUIHierarchy uiHierarchy = hierarchy as IVsUIHierarchy; - Debug.Assert(uiHierarchy != null, "The ProjectNode should implement IVsUIHierarchy"); - if (uiHierarchy == null) { - return VSConstants.E_FAIL; - } - // Expand and select project node - IVsUIHierarchyWindow uiWindow = UIHierarchyUtilities.GetUIHierarchyWindow(this.ServiceProvider, HierarchyNode.SolutionExplorer); - if (uiWindow != null) { - __VSHIERARCHYITEMSTATE state; - uint stateAsInt; - if (uiWindow.GetItemState(uiHierarchy, VSConstants.VSITEMID_ROOT, (uint)__VSHIERARCHYITEMSTATE.HIS_Expanded, out stateAsInt) == VSConstants.S_OK) { - state = (__VSHIERARCHYITEMSTATE)stateAsInt; - if (state != __VSHIERARCHYITEMSTATE.HIS_Expanded) { - int hr; - hr = uiWindow.ExpandItem(uiHierarchy, VSConstants.VSITEMID_ROOT, EXPANDFLAGS.EXPF_ExpandParentsToShowItem); - if (ErrorHandler.Failed(hr)) - Trace.WriteLine("Failed to expand project node"); - hr = uiWindow.ExpandItem(uiHierarchy, VSConstants.VSITEMID_ROOT, EXPANDFLAGS.EXPF_SelectItem); - if (ErrorHandler.Failed(hr)) - Trace.WriteLine("Failed to select project node"); - - return hr; - } - } - } - } - return VSConstants.S_OK; - } - } -} diff --git a/Microsoft.VisualStudio.Project/StructuresEnums.cs b/Microsoft.VisualStudio.Project/StructuresEnums.cs deleted file mode 100644 index 4c67998a..00000000 --- a/Microsoft.VisualStudio.Project/StructuresEnums.cs +++ /dev/null @@ -1,384 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.InteropServices; -using Microsoft.VisualStudio.Shell.Interop; - -namespace Microsoft.VisualStudioTools.Project { - #region structures - [StructLayoutAttribute(LayoutKind.Sequential)] - internal struct _DROPFILES { - public Int32 pFiles; - public Int32 X; - public Int32 Y; - public Int32 fNC; - public Int32 fWide; - } - #endregion - - #region enums - - - /// - /// Defines the currect state of a property page. - /// - [Flags] - public enum PropPageStatus { - - Dirty = 0x1, - - Validate = 0x2, - - Clean = 0x4 - } - - /// - /// Defines the status of the command being queried - /// - [Flags] - public enum QueryStatusResult { - /// - /// The command is not supported. - /// - NOTSUPPORTED = 0, - - /// - /// The command is supported - /// - SUPPORTED = 1, - - /// - /// The command is enabled - /// - ENABLED = 2, - - /// - /// The command is toggled on - /// - LATCHED = 4, - - /// - /// The command is toggled off (the opposite of LATCHED). - /// - NINCHED = 8, - - /// - /// The command is invisible. - /// - INVISIBLE = 16 - } - - /// - /// Defines the type of item to be added to the hierarchy. - /// - public enum HierarchyAddType { - AddNewItem, - AddExistingItem - } - - /// - /// Defines the component from which a command was issued. - /// - public enum CommandOrigin { - UiHierarchy, - OleCommandTarget - } - - /// - /// Defines the current status of the build process. - /// - public enum MSBuildResult { - /// - /// The build is currently suspended. - /// - Suspended, - - /// - /// The build has been restarted. - /// - Resumed, - - /// - /// The build failed. - /// - Failed, - - /// - /// The build was successful. - /// - Successful, - } - - /// - /// Defines the type of action to be taken in showing the window frame. - /// - public enum WindowFrameShowAction { - DoNotShow, - Show, - ShowNoActivate, - Hide, - } - - /// - /// Defines drop types - /// - internal enum DropDataType { - None, - Shell, - VsStg, - VsRef - } - - /// - /// Used by the hierarchy node to decide which element to redraw. - /// - [Flags] - public enum UIHierarchyElement { - None = 0, - - /// - /// This will be translated to VSHPROPID_IconIndex - /// - Icon = 1, - - /// - /// This will be translated to VSHPROPID_StateIconIndex - /// - SccState = 2, - - /// - /// This will be translated to VSHPROPID_Caption - /// - Caption = 4, - - /// - /// This will be translated to VSHPROPID_OverlayIconIndex - /// - OverlayIcon = 8 - } - - /// - /// Defines the global propeties used by the msbuild project. - /// - public enum GlobalProperty { - /// - /// Property specifying that we are building inside VS. - /// - BuildingInsideVisualStudio, - - /// - /// The VS installation directory. This is the same as the $(DevEnvDir) macro. - /// - DevEnvDir, - - /// - /// The name of the solution the project is created. This is the same as the $(SolutionName) macro. - /// - SolutionName, - - /// - /// The file name of the solution. This is the same as $(SolutionFileName) macro. - /// - SolutionFileName, - - /// - /// The full path of the solution. This is the same as the $(SolutionPath) macro. - /// - SolutionPath, - - /// - /// The directory of the solution. This is the same as the $(SolutionDir) macro. - /// - SolutionDir, - - /// - /// The extension of teh directory. This is the same as the $(SolutionExt) macro. - /// - SolutionExt, - - /// - /// The fxcop installation directory. - /// - FxCopDir, - - /// - /// The ResolvedNonMSBuildProjectOutputs msbuild property - /// - VSIDEResolvedNonMSBuildProjectOutputs, - - /// - /// The Configuartion property. - /// - Configuration, - - /// - /// The platform property. - /// - Platform, - - /// - /// The RunCodeAnalysisOnce property - /// - RunCodeAnalysisOnce, - - /// - /// The VisualStudioStyleErrors property - /// - VisualStudioStyleErrors, - } - #endregion - - public class AfterProjectFileOpenedEventArgs : EventArgs { - - } - - public class BeforeProjectFileClosedEventArgs : EventArgs { - #region fields - private bool _removed; - private IVsHierarchy _hierarchy; - #endregion - - #region properties - /// - /// true if the project was removed from the solution before the solution was closed. false if the project was removed from the solution while the solution was being closed. - /// - internal bool Removed { - get { return _removed; } - } - - internal IVsHierarchy Hierarchy { - get { - return _hierarchy; - } - } - - #endregion - - #region ctor - internal BeforeProjectFileClosedEventArgs(IVsHierarchy hierarchy, bool removed) { - this._removed = removed; - _hierarchy = hierarchy; - } - #endregion - } - - /// - /// Argument of the event raised when a project property is changed. - /// - public class ProjectPropertyChangedArgs : EventArgs { - private string propertyName; - private string oldValue; - private string newValue; - - internal ProjectPropertyChangedArgs(string propertyName, string oldValue, string newValue) { - this.propertyName = propertyName; - this.oldValue = oldValue; - this.newValue = newValue; - } - - public string NewValue { - get { return newValue; } - } - - public string OldValue { - get { return oldValue; } - } - - public string PropertyName { - get { return propertyName; } - } - } - - /// - /// This class is used for the events raised by a HierarchyNode object. - /// - internal class HierarchyNodeEventArgs : EventArgs { - private HierarchyNode child; - - internal HierarchyNodeEventArgs(HierarchyNode child) { - this.child = child; - } - - public HierarchyNode Child { - get { return this.child; } - } - } - - /// - /// Event args class for triggering file change event arguments. - /// - public class FileChangedOnDiskEventArgs : EventArgs { - #region Private fields - /// - /// File name that was changed on disk. - /// - private string fileName; - - /// - /// The item ide of the file that has changed. - /// - private uint itemID; - - /// - /// The reason the file has changed on disk. - /// - private _VSFILECHANGEFLAGS fileChangeFlag; - #endregion - - /// - /// Constructs a new event args. - /// - /// File name that was changed on disk. - /// The item id of the file that was changed on disk. - internal FileChangedOnDiskEventArgs(string fileName, uint id, _VSFILECHANGEFLAGS flag) { - this.fileName = fileName; - this.itemID = id; - this.fileChangeFlag = flag; - } - - /// - /// Gets the file name that was changed on disk. - /// - /// The file that was changed on disk. - public string FileName { - get { - return this.fileName; - } - } - - /// - /// Gets item id of the file that has changed - /// - /// The file that was changed on disk. - internal uint ItemID { - get { - return this.itemID; - } - } - - /// - /// The reason while the file has chnaged on disk. - /// - /// The reason while the file has chnaged on disk. - public _VSFILECHANGEFLAGS FileChangeFlag { - get { - return this.fileChangeFlag; - } - } - } -} diff --git a/Microsoft.VisualStudio.Project/SuspendFileChanges.cs b/Microsoft.VisualStudio.Project/SuspendFileChanges.cs deleted file mode 100644 index 4bfa3c9e..00000000 --- a/Microsoft.VisualStudio.Project/SuspendFileChanges.cs +++ /dev/null @@ -1,111 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Diagnostics; -using System.Runtime.InteropServices; -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.Shell.Interop; -using IServiceProvider = System.IServiceProvider; -using ShellConstants = Microsoft.VisualStudio.Shell.Interop.Constants; - -namespace Microsoft.VisualStudioTools.Project { - /// - /// helper to make the editor ignore external changes - /// - internal class SuspendFileChanges { - private string documentFileName; - - private bool isSuspending; - - private IServiceProvider site; - - private IVsDocDataFileChangeControl fileChangeControl; - - public SuspendFileChanges(IServiceProvider site, string document) { - this.site = site; - this.documentFileName = document; - } - - - public void Suspend() { - if (this.isSuspending) - return; - - IntPtr docData = IntPtr.Zero; - try { - IVsRunningDocumentTable rdt = this.site.GetService(typeof(SVsRunningDocumentTable)) as IVsRunningDocumentTable; - - IVsHierarchy hierarchy; - uint itemId; - uint docCookie; - IVsFileChangeEx fileChange; - - - if (rdt == null) - return; - - ErrorHandler.ThrowOnFailure(rdt.FindAndLockDocument((uint)_VSRDTFLAGS.RDT_NoLock, this.documentFileName, out hierarchy, out itemId, out docData, out docCookie)); - - if ((docCookie == (uint)ShellConstants.VSDOCCOOKIE_NIL) || docData == IntPtr.Zero) - return; - - fileChange = this.site.GetService(typeof(SVsFileChangeEx)) as IVsFileChangeEx; - - if (fileChange != null) { - this.isSuspending = true; - ErrorHandler.ThrowOnFailure(fileChange.IgnoreFile(0, this.documentFileName, 1)); - if (docData != IntPtr.Zero) { - IVsPersistDocData persistDocData = null; - - // if interface is not supported, return null - object unknown = Marshal.GetObjectForIUnknown(docData); - if (unknown is IVsPersistDocData) { - persistDocData = (IVsPersistDocData)unknown; - if (persistDocData is IVsDocDataFileChangeControl) { - this.fileChangeControl = (IVsDocDataFileChangeControl)persistDocData; - if (this.fileChangeControl != null) { - ErrorHandler.ThrowOnFailure(this.fileChangeControl.IgnoreFileChanges(1)); - } - } - } - } - } - } catch (InvalidCastException e) { - Trace.WriteLine("Exception" + e.Message); - } finally { - if (docData != IntPtr.Zero) { - Marshal.Release(docData); - } - } - return; - } - - public void Resume() { - if (!this.isSuspending) - return; - IVsFileChangeEx fileChange; - fileChange = this.site.GetService(typeof(SVsFileChangeEx)) as IVsFileChangeEx; - if (fileChange != null) { - this.isSuspending = false; - ErrorHandler.ThrowOnFailure(fileChange.IgnoreFile(0, this.documentFileName, 0)); - if (this.fileChangeControl != null) { - ErrorHandler.ThrowOnFailure(this.fileChangeControl.IgnoreFileChanges(0)); - } - } - } - } -} diff --git a/Microsoft.VisualStudio.Project/TaskDialog.cs b/Microsoft.VisualStudio.Project/TaskDialog.cs deleted file mode 100644 index c7330795..00000000 --- a/Microsoft.VisualStudio.Project/TaskDialog.cs +++ /dev/null @@ -1,684 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Runtime.InteropServices; -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.Shell.Interop; - -namespace Microsoft.VisualStudioTools { - sealed class TaskDialog { - private readonly IServiceProvider _provider; - private readonly List _buttons; - private readonly List _radioButtons; - - public TaskDialog(IServiceProvider provider) { - _provider = provider; - _buttons = new List(); - _radioButtons = new List(); - UseCommandLinks = true; - } - - public static TaskDialog ForException( - IServiceProvider provider, - Exception exception, - string message = null, - string issueTrackerUrl = null - ) { - string suffix = string.IsNullOrEmpty(issueTrackerUrl) ? - "Please press Ctrl+C to copy the contents of this dialog and report this error." : - "Please press Ctrl+C to copy the contents of this dialog and report this error to our issue tracker."; - - if (string.IsNullOrEmpty(message)) { - message = suffix; - } else { - message += Environment.NewLine + Environment.NewLine + suffix; - } - - var td = new TaskDialog(provider) { - MainInstruction = "An unexpected error occurred", - Content = message, - EnableHyperlinks = true, - CollapsedControlText = "Show &details", - ExpandedControlText = "Hide &details", - ExpandedInformation = exception.ToString() - }; - td.Buttons.Add(TaskDialogButton.Close); - if (!string.IsNullOrEmpty(issueTrackerUrl)) { - td.HyperlinkClicked += (s, e) => { - if (e.Url == "issuetracker") { - Process.Start(issueTrackerUrl); - } - }; - } - return td; - } - - public static void CallWithRetry( - Action action, - IServiceProvider provider, - string title, - string failedText, - string expandControlText, - string retryButtonText, - string cancelButtonText, - Func canRetry = null - ) { - for (int retryCount = 1; ; ++retryCount) { - try { - action(retryCount); - return; - } catch (Exception ex) { - if (ex.IsCriticalException()) { - throw; - } - if (canRetry != null && !canRetry(ex)) { - throw; - } - - var td = new TaskDialog(provider) { - Title = title, - MainInstruction = failedText, - Content = ex.Message, - CollapsedControlText = expandControlText, - ExpandedControlText = expandControlText, - ExpandedInformation = ex.ToString() - }; - var retry = new TaskDialogButton(retryButtonText); - td.Buttons.Add(retry); - td.Buttons.Add(new TaskDialogButton(cancelButtonText)); - var button = td.ShowModal(); - if (button != retry) { - throw new OperationCanceledException(); - } - } - } - } - - public static T CallWithRetry( - Func func, - IServiceProvider provider, - string title, - string failedText, - string expandControlText, - string retryButtonText, - string cancelButtonText, - Func canRetry = null - ) { - for (int retryCount = 1; ; ++retryCount) { - try { - return func(retryCount); - } catch (Exception ex) { - if (ex.IsCriticalException()) { - throw; - } - if (canRetry != null && !canRetry(ex)) { - throw; - } - - var td = new TaskDialog(provider) { - Title = title, - MainInstruction = failedText, - Content = ex.Message, - CollapsedControlText = expandControlText, - ExpandedControlText = expandControlText, - ExpandedInformation = ex.ToString() - }; - var retry = new TaskDialogButton(retryButtonText); - var cancel = new TaskDialogButton(cancelButtonText); - td.Buttons.Add(retry); - td.Buttons.Add(cancel); - var button = td.ShowModal(); - if (button == cancel) { - throw new OperationCanceledException(); - } - } - } - } - - public TaskDialogButton ShowModal() { - var config = new NativeMethods.TASKDIALOGCONFIG(); - config.cbSize = (uint)Marshal.SizeOf(typeof(NativeMethods.TASKDIALOGCONFIG)); - config.pButtons = IntPtr.Zero; - config.pRadioButtons = IntPtr.Zero; - - var uiShell = (IVsUIShell)_provider.GetService(typeof(SVsUIShell)); - uiShell.GetDialogOwnerHwnd(out config.hwndParent); - uiShell.EnableModeless(0); - - var customButtons = new List(); - config.dwCommonButtons = 0; - - foreach (var button in Buttons) { - var flag = GetButtonFlag(button); - if (flag != 0) { - config.dwCommonButtons |= flag; - } else { - customButtons.Add(button); - } - } - - try { - if (customButtons.Any()) { - config.cButtons = (uint)customButtons.Count; - var ptr = config.pButtons = Marshal.AllocHGlobal(customButtons.Count * Marshal.SizeOf(typeof(NativeMethods.TASKDIALOG_BUTTON))); - for (int i = 0; i < customButtons.Count; ++i) { - NativeMethods.TASKDIALOG_BUTTON data; - data.nButtonID = GetButtonId(null, null, i); - if (string.IsNullOrEmpty(customButtons[i].Subtext)) { - data.pszButtonText = customButtons[i].Text; - } else { - data.pszButtonText = string.Format("{0}\n{1}", customButtons[i].Text, customButtons[i].Subtext); - } - Marshal.StructureToPtr(data, ptr + i * Marshal.SizeOf(typeof(NativeMethods.TASKDIALOG_BUTTON)), false); - } - } else { - config.cButtons = 0; - config.pButtons = IntPtr.Zero; - } - - if (_buttons.Any() && SelectedButton != null) { - config.nDefaultButton = GetButtonId(SelectedButton, customButtons); - } else { - config.nDefaultButton = 0; - } - - if (_radioButtons.Any()) { - config.cRadioButtons = (uint)_radioButtons.Count; - var ptr = config.pRadioButtons = Marshal.AllocHGlobal(_radioButtons.Count * Marshal.SizeOf(typeof(NativeMethods.TASKDIALOG_BUTTON))); - for (int i = 0; i < _radioButtons.Count; ++i) { - NativeMethods.TASKDIALOG_BUTTON data; - data.nButtonID = GetRadioId(null, null, i); - data.pszButtonText = _radioButtons[i].Text; - Marshal.StructureToPtr(data, ptr + i * Marshal.SizeOf(typeof(NativeMethods.TASKDIALOG_BUTTON)), false); - } - - if (SelectedRadioButton != null) { - config.nDefaultRadioButton = GetRadioId(SelectedRadioButton, _radioButtons); - } else { - config.nDefaultRadioButton = 0; - } - } - - config.pszWindowTitle = Title; - config.pszMainInstruction = MainInstruction; - config.pszContent = Content; - config.pszExpandedInformation = ExpandedInformation; - config.pszExpandedControlText = ExpandedControlText; - config.pszCollapsedControlText = CollapsedControlText; - config.pszFooter = Footer; - config.pszVerificationText = VerificationText; - config.pfCallback = Callback; - config.hMainIcon = (IntPtr)GetIconResource(MainIcon); - config.hFooterIcon = (IntPtr)GetIconResource(FooterIcon); - - if (Width.HasValue) { - config.cxWidth = (uint)Width.Value; - } else { - config.dwFlags |= NativeMethods.TASKDIALOG_FLAGS.TDF_SIZE_TO_CONTENT; - } - if (EnableHyperlinks) { - config.dwFlags |= NativeMethods.TASKDIALOG_FLAGS.TDF_ENABLE_HYPERLINKS; - } - if (AllowCancellation) { - config.dwFlags |= NativeMethods.TASKDIALOG_FLAGS.TDF_ALLOW_DIALOG_CANCELLATION; - } - if (UseCommandLinks && config.cButtons > 0) { - config.dwFlags |= NativeMethods.TASKDIALOG_FLAGS.TDF_USE_COMMAND_LINKS; - } - if (!ShowExpandedInformationInContent) { - config.dwFlags |= NativeMethods.TASKDIALOG_FLAGS.TDF_EXPAND_FOOTER_AREA; - } - if (ExpandedByDefault) { - config.dwFlags |= NativeMethods.TASKDIALOG_FLAGS.TDF_EXPANDED_BY_DEFAULT; - } - if (SelectedVerified) { - config.dwFlags |= NativeMethods.TASKDIALOG_FLAGS.TDF_VERIFICATION_FLAG_CHECKED; - } - if (CanMinimize) { - config.dwFlags |= NativeMethods.TASKDIALOG_FLAGS.TDF_CAN_BE_MINIMIZED; - } - - config.dwFlags |= NativeMethods.TASKDIALOG_FLAGS.TDF_POSITION_RELATIVE_TO_WINDOW; - - int selectedButton, selectedRadioButton; - bool verified; - ErrorHandler.ThrowOnFailure(NativeMethods.TaskDialogIndirect( - ref config, - out selectedButton, - out selectedRadioButton, - out verified - )); - - SelectedButton = GetButton(selectedButton, customButtons); - SelectedRadioButton = GetRadio(selectedRadioButton, _radioButtons); - SelectedVerified = verified; - } finally { - uiShell.EnableModeless(1); - - if (config.pButtons != IntPtr.Zero) { - for (int i = 0; i < customButtons.Count; ++i) { - Marshal.DestroyStructure(config.pButtons + i * Marshal.SizeOf(typeof(NativeMethods.TASKDIALOG_BUTTON)), typeof(NativeMethods.TASKDIALOG_BUTTON)); - } - Marshal.FreeHGlobal(config.pButtons); - } - if (config.pRadioButtons != IntPtr.Zero) { - for (int i = 0; i < _radioButtons.Count; ++i) { - Marshal.DestroyStructure(config.pRadioButtons + i * Marshal.SizeOf(typeof(NativeMethods.TASKDIALOG_BUTTON)), typeof(NativeMethods.TASKDIALOG_BUTTON)); - } - Marshal.FreeHGlobal(config.pRadioButtons); - } - } - - return SelectedButton; - } - - private int Callback(IntPtr hwnd, uint uNotification, UIntPtr wParam, IntPtr lParam, IntPtr lpRefData) { - try { - switch ((NativeMethods.TASKDIALOG_NOTIFICATION)uNotification) { - case NativeMethods.TASKDIALOG_NOTIFICATION.TDN_CREATED: - foreach (var btn in _buttons.Where(b => b.ElevationRequired)) { - NativeMethods.SendMessage( - hwnd, - (int)NativeMethods.TASKDIALOG_MESSAGE.TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE, - new IntPtr(GetButtonId(btn, _buttons)), - new IntPtr(1) - ); - } - break; - case NativeMethods.TASKDIALOG_NOTIFICATION.TDN_NAVIGATED: - break; - case NativeMethods.TASKDIALOG_NOTIFICATION.TDN_BUTTON_CLICKED: - break; - case NativeMethods.TASKDIALOG_NOTIFICATION.TDN_HYPERLINK_CLICKED: - var url = Marshal.PtrToStringUni(lParam); - var hevt = HyperlinkClicked; - if (hevt != null) { - hevt(this, new TaskDialogHyperlinkClickedEventArgs(url)); - } else { - Process.Start(new ProcessStartInfo { FileName = url, UseShellExecute = true }); - } - break; - case NativeMethods.TASKDIALOG_NOTIFICATION.TDN_TIMER: - break; - case NativeMethods.TASKDIALOG_NOTIFICATION.TDN_DESTROYED: - break; - case NativeMethods.TASKDIALOG_NOTIFICATION.TDN_RADIO_BUTTON_CLICKED: - break; - case NativeMethods.TASKDIALOG_NOTIFICATION.TDN_DIALOG_CONSTRUCTED: - break; - case NativeMethods.TASKDIALOG_NOTIFICATION.TDN_VERIFICATION_CLICKED: - break; - case NativeMethods.TASKDIALOG_NOTIFICATION.TDN_HELP: - break; - case NativeMethods.TASKDIALOG_NOTIFICATION.TDN_EXPANDO_BUTTON_CLICKED: - break; - default: - break; - } - return VSConstants.S_OK; - } catch (Exception ex) { - if (ex.IsCriticalException()) { - throw; - } - return Marshal.GetHRForException(ex); - } - } - - public string Title { get; set; } - public string MainInstruction { get; set; } - public string Content { get; set; } - public string VerificationText { get; set; } - public string ExpandedInformation { get; set; } - public string Footer { get; set; } - - public bool ExpandedByDefault { get; set; } - public bool ShowExpandedInformationInContent { get; set; } - public string ExpandedControlText { get; set; } - public string CollapsedControlText { get; set; } - - public int? Width { get; set; } - public bool EnableHyperlinks { get; set; } - public bool AllowCancellation { get; set; } - public bool UseCommandLinks { get; set; } - public bool CanMinimize { get; set; } - - public TaskDialogIcon MainIcon { get; set; } - public TaskDialogIcon FooterIcon { get; set; } - - /// - /// Raised when a hyperlink in the dialog is clicked. If no event - /// handlers are added, the default behavior is to open an external - /// browser. - /// - public event EventHandler HyperlinkClicked; - - public List Buttons { - get { - return _buttons; - } - } - - public List RadioButtons { - get { - return _radioButtons; - } - } - - public TaskDialogButton SelectedButton { get; set; } - public TaskDialogButton SelectedRadioButton { get; set; } - public bool SelectedVerified { get; set; } - - - private static NativeMethods.TASKDIALOG_COMMON_BUTTON_FLAGS GetButtonFlag(TaskDialogButton button) { - if (button == TaskDialogButton.OK) { - return NativeMethods.TASKDIALOG_COMMON_BUTTON_FLAGS.TDCBF_OK_BUTTON; - } else if (button == TaskDialogButton.Cancel) { - return NativeMethods.TASKDIALOG_COMMON_BUTTON_FLAGS.TDCBF_CANCEL_BUTTON; - } else if (button == TaskDialogButton.Yes) { - return NativeMethods.TASKDIALOG_COMMON_BUTTON_FLAGS.TDCBF_YES_BUTTON; - } else if (button == TaskDialogButton.No) { - return NativeMethods.TASKDIALOG_COMMON_BUTTON_FLAGS.TDCBF_NO_BUTTON; - } else if (button == TaskDialogButton.Retry) { - return NativeMethods.TASKDIALOG_COMMON_BUTTON_FLAGS.TDCBF_RETRY_BUTTON; - } else if (button == TaskDialogButton.Close) { - return NativeMethods.TASKDIALOG_COMMON_BUTTON_FLAGS.TDCBF_CLOSE_BUTTON; - } else { - return 0; - } - } - - private static NativeMethods.TASKDIALOG_ICON GetIconResource(TaskDialogIcon icon) { - switch (icon) { - case TaskDialogIcon.None: - return 0; - case TaskDialogIcon.Error: - return NativeMethods.TASKDIALOG_ICON.TD_ERROR_ICON; - case TaskDialogIcon.Warning: - return NativeMethods.TASKDIALOG_ICON.TD_WARNING_ICON; - case TaskDialogIcon.Information: - return NativeMethods.TASKDIALOG_ICON.TD_INFORMATION_ICON; - case TaskDialogIcon.Shield: - return NativeMethods.TASKDIALOG_ICON.TD_SHIELD_ICON; - default: - throw new ArgumentException("Invalid TaskDialogIcon value", "icon"); - } - } - - private static int GetButtonId( - TaskDialogButton button, - IList customButtons = null, - int indexHint = -1 - ) { - if (indexHint >= 0) { - return indexHint + 1000; - } - - if (button == TaskDialogButton.OK) { - return NativeMethods.IDOK; - } else if (button == TaskDialogButton.Cancel) { - return NativeMethods.IDCANCEL; - } else if (button == TaskDialogButton.Yes) { - return NativeMethods.IDYES; - } else if (button == TaskDialogButton.No) { - return NativeMethods.IDNO; - } else if (button == TaskDialogButton.Retry) { - return NativeMethods.IDRETRY; - } else if (button == TaskDialogButton.Close) { - return NativeMethods.IDCLOSE; - } else if (customButtons != null) { - int i = customButtons.IndexOf(button); - if (i >= 0) { - return i + 1000; - } - } - - return -1; - } - - private static TaskDialogButton GetButton(int id, IList customButtons = null) { - switch (id) { - case NativeMethods.IDOK: - return TaskDialogButton.OK; - case NativeMethods.IDCANCEL: - return TaskDialogButton.Cancel; - case NativeMethods.IDYES: - return TaskDialogButton.Yes; - case NativeMethods.IDNO: - return TaskDialogButton.No; - case NativeMethods.IDRETRY: - return TaskDialogButton.Retry; - case NativeMethods.IDCLOSE: - return TaskDialogButton.Close; - } - - if (customButtons != null && id >= 1000 && id - 1000 < customButtons.Count) { - return customButtons[id - 1000]; - } - - return null; - } - - private static int GetRadioId( - TaskDialogButton button, - IList buttons, - int indexHint = -1 - ) { - if (indexHint >= 0) { - return indexHint + 2000; - } - - return buttons.IndexOf(button) + 2000; - } - - private static TaskDialogButton GetRadio(int id, IList buttons) { - if (id >= 2000 && id - 2000 < buttons.Count) { - return buttons[id - 2000]; - } - - return null; - } - - private static class NativeMethods { - internal const int IDOK = 1; - internal const int IDCANCEL = 2; - internal const int IDABORT = 3; - internal const int IDRETRY = 4; - internal const int IDIGNORE = 5; - internal const int IDYES = 6; - internal const int IDNO = 7; - internal const int IDCLOSE = 8; - - internal enum TASKDIALOG_FLAGS { - TDF_ENABLE_HYPERLINKS = 0x0001, - TDF_USE_HICON_MAIN = 0x0002, - TDF_USE_HICON_FOOTER = 0x0004, - TDF_ALLOW_DIALOG_CANCELLATION = 0x0008, - TDF_USE_COMMAND_LINKS = 0x0010, - TDF_USE_COMMAND_LINKS_NO_ICON = 0x0020, - TDF_EXPAND_FOOTER_AREA = 0x0040, - TDF_EXPANDED_BY_DEFAULT = 0x0080, - TDF_VERIFICATION_FLAG_CHECKED = 0x0100, - TDF_SHOW_PROGRESS_BAR = 0x0200, - TDF_SHOW_MARQUEE_PROGRESS_BAR = 0x0400, - TDF_CALLBACK_TIMER = 0x0800, - TDF_POSITION_RELATIVE_TO_WINDOW = 0x1000, - TDF_RTL_LAYOUT = 0x2000, - TDF_NO_DEFAULT_RADIO_BUTTON = 0x4000, - TDF_CAN_BE_MINIMIZED = 0x8000, - TDF_SIZE_TO_CONTENT = 0x01000000 - } - - internal enum TASKDIALOG_COMMON_BUTTON_FLAGS { - TDCBF_OK_BUTTON = 0x0001, - TDCBF_YES_BUTTON = 0x0002, - TDCBF_NO_BUTTON = 0x0004, - TDCBF_CANCEL_BUTTON = 0x0008, - TDCBF_RETRY_BUTTON = 0x0010, - TDCBF_CLOSE_BUTTON = 0x0020 - } - - internal enum TASKDIALOG_NOTIFICATION : uint { - TDN_CREATED = 0, - TDN_NAVIGATED = 1, - TDN_BUTTON_CLICKED = 2, // wParam = Button ID - TDN_HYPERLINK_CLICKED = 3, // lParam = (LPCWSTR)pszHREF - TDN_TIMER = 4, // wParam = Milliseconds since dialog created or timer reset - TDN_DESTROYED = 5, - TDN_RADIO_BUTTON_CLICKED = 6, // wParam = Radio Button ID - TDN_DIALOG_CONSTRUCTED = 7, - TDN_VERIFICATION_CLICKED = 8, // wParam = 1 if checkbox checked, 0 if not, lParam is unused and always 0 - TDN_HELP = 9, - TDN_EXPANDO_BUTTON_CLICKED = 10 // wParam = 0 (dialog is now collapsed), wParam != 0 (dialog is now expanded) - }; - - internal enum TASKDIALOG_ICON : ushort { - TD_WARNING_ICON = unchecked((ushort)-1), - TD_ERROR_ICON = unchecked((ushort)-2), - TD_INFORMATION_ICON = unchecked((ushort)-3), - TD_SHIELD_ICON = unchecked((ushort)-4) - } - - const int WM_USER = 0x0400; - - internal enum TASKDIALOG_MESSAGE : int { - TDM_NAVIGATE_PAGE = WM_USER + 101, - TDM_CLICK_BUTTON = WM_USER + 102, // wParam = Button ID - TDM_SET_MARQUEE_PROGRESS_BAR = WM_USER + 103, // wParam = 0 (nonMarque) wParam != 0 (Marquee) - TDM_SET_PROGRESS_BAR_STATE = WM_USER + 104, // wParam = new progress state - TDM_SET_PROGRESS_BAR_RANGE = WM_USER + 105, // lParam = MAKELPARAM(nMinRange, nMaxRange) - TDM_SET_PROGRESS_BAR_POS = WM_USER + 106, // wParam = new position - TDM_SET_PROGRESS_BAR_MARQUEE = WM_USER + 107, // wParam = 0 (stop marquee), wParam != 0 (start marquee), lparam = speed (milliseconds between repaints) - TDM_SET_ELEMENT_TEXT = WM_USER + 108, // wParam = element (TASKDIALOG_ELEMENTS), lParam = new element text (LPCWSTR) - TDM_CLICK_RADIO_BUTTON = WM_USER + 110, // wParam = Radio Button ID - TDM_ENABLE_BUTTON = WM_USER + 111, // lParam = 0 (disable), lParam != 0 (enable), wParam = Button ID - TDM_ENABLE_RADIO_BUTTON = WM_USER + 112, // lParam = 0 (disable), lParam != 0 (enable), wParam = Radio Button ID - TDM_CLICK_VERIFICATION = WM_USER + 113, // wParam = 0 (unchecked), 1 (checked), lParam = 1 (set key focus) - TDM_UPDATE_ELEMENT_TEXT = WM_USER + 114, // wParam = element (TASKDIALOG_ELEMENTS), lParam = new element text (LPCWSTR) - TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE = WM_USER + 115, // wParam = Button ID, lParam = 0 (elevation not required), lParam != 0 (elevation required) - TDM_UPDATE_ICON = WM_USER + 116 // wParam = icon element (TASKDIALOG_ICON_ELEMENTS), lParam = new icon (hIcon if TDF_USE_HICON_* was set, PCWSTR otherwise) - } - - [SuppressMessage("Microsoft.Interoperability", "CA1400:PInvokeEntryPointsShouldExist", - Justification = "Entry point exists but CA can't find it")] - [DllImport("comctl32.dll", SetLastError = true)] - internal static extern int TaskDialogIndirect( - ref TASKDIALOGCONFIG pTaskConfig, - out int pnButton, - out int pnRadioButton, - [MarshalAs(UnmanagedType.Bool)] out bool pfverificationFlagChecked); - - internal delegate int PFTASKDIALOGCALLBACK(IntPtr hwnd, uint uNotification, UIntPtr wParam, IntPtr lParam, IntPtr lpRefData); - - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] - internal struct TASKDIALOG_BUTTON { - public int nButtonID; - [MarshalAs(UnmanagedType.LPWStr)] - public string pszButtonText; - } - - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] - internal struct TASKDIALOGCONFIG { - public uint cbSize; - public IntPtr hwndParent; - public IntPtr hInstance; - public TASKDIALOG_FLAGS dwFlags; - public TASKDIALOG_COMMON_BUTTON_FLAGS dwCommonButtons; - [MarshalAs(UnmanagedType.LPWStr)] - public string pszWindowTitle; - public IntPtr hMainIcon; - [MarshalAs(UnmanagedType.LPWStr)] - public string pszMainInstruction; - [MarshalAs(UnmanagedType.LPWStr)] - public string pszContent; - public uint cButtons; - public IntPtr pButtons; - public int nDefaultButton; - public uint cRadioButtons; - public IntPtr pRadioButtons; - public int nDefaultRadioButton; - [MarshalAs(UnmanagedType.LPWStr)] - public string pszVerificationText; - [MarshalAs(UnmanagedType.LPWStr)] - public string pszExpandedInformation; - [MarshalAs(UnmanagedType.LPWStr)] - public string pszExpandedControlText; - [MarshalAs(UnmanagedType.LPWStr)] - public string pszCollapsedControlText; - public IntPtr hFooterIcon; - [MarshalAs(UnmanagedType.LPWStr)] - public string pszFooter; - public PFTASKDIALOGCALLBACK pfCallback; - public IntPtr lpCallbackData; - public uint cxWidth; - } - - [DllImport("user32.dll")] - internal static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam); - } - } - - class TaskDialogButton { - public TaskDialogButton(string text) { - int i = text.IndexOfAny(Environment.NewLine.ToCharArray()); - if (i < 0) { - Text = text; - } else { - Text = text.Remove(i); - Subtext = text.Substring(i).TrimStart(); - } - } - - public TaskDialogButton(string text, string subtext) { - Text = text; - Subtext = subtext; - } - - public string Text { get; set; } - public string Subtext { get; set; } - public bool ElevationRequired { get; set; } - - private TaskDialogButton() { } - public static readonly TaskDialogButton OK = new TaskDialogButton(); - public static readonly TaskDialogButton Cancel = new TaskDialogButton(); - public static readonly TaskDialogButton Yes = new TaskDialogButton(); - public static readonly TaskDialogButton No = new TaskDialogButton(); - public static readonly TaskDialogButton Retry = new TaskDialogButton(); - public static readonly TaskDialogButton Close = new TaskDialogButton(); - } - - sealed class TaskDialogHyperlinkClickedEventArgs : EventArgs { - private readonly string _url; - - public TaskDialogHyperlinkClickedEventArgs(string url) { - _url = url; - } - - public string Url { get { return _url; } } - } - - enum TaskDialogIcon { - None, - Error, - Warning, - Information, - Shield - } -} \ No newline at end of file diff --git a/Microsoft.VisualStudio.Project/TaskExtensions.cs b/Microsoft.VisualStudio.Project/TaskExtensions.cs deleted file mode 100644 index a712ce78..00000000 --- a/Microsoft.VisualStudio.Project/TaskExtensions.cs +++ /dev/null @@ -1,156 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Diagnostics; -using System.Runtime.CompilerServices; -using System.Threading.Tasks; -using Microsoft.VisualStudio.Shell; -using Microsoft.VisualStudioTools.Project; -using Task = System.Threading.Tasks.Task; - -namespace Microsoft.VisualStudioTools { - static class TaskExtensions { - /// - /// Suppresses warnings about unawaited tasks and ensures that unhandled - /// errors will cause the process to terminate. - /// - public static async void DoNotWait(this Task task) { - await task; - } - - /// - /// Waits for a task to complete. If an exception occurs, the exception - /// will be raised without being wrapped in a - /// . - /// - public static void WaitAndUnwrapExceptions(this Task task) { - task.GetAwaiter().GetResult(); - } - - /// - /// Waits for a task to complete. If an exception occurs, the exception - /// will be raised without being wrapped in a - /// . - /// - public static T WaitAndUnwrapExceptions(this Task task) { - return task.GetAwaiter().GetResult(); - } - - /// - /// Waits for a task to complete and logs all exceptions except those - /// that return true from , which are - /// rethrown. - /// - public static T WaitAndHandleAllExceptions( - this Task task, - string productTitle, - Type callerType = null, - [CallerFilePath] string callerFile = null, - [CallerLineNumber] int callerLineNumber = 0, - [CallerMemberName] string callerName = null - ) { - return task.HandleAllExceptions(productTitle, callerType, callerFile, callerLineNumber, callerName) - .WaitAndUnwrapExceptions(); - } - - - /// - /// Logs all exceptions from a task except those that return true from - /// , which are rethrown. - /// If an exception is thrown, default(T) is returned. - /// - public static async Task HandleAllExceptions( - this Task task, - string productTitle, - Type callerType = null, - [CallerFilePath] string callerFile = null, - [CallerLineNumber] int callerLineNumber = 0, - [CallerMemberName] string callerName = null - ) { - var result = default(T); - try { - result = await task; - } catch (Exception ex) { - if (ex.IsCriticalException()) { - throw; - } - - var message = SR.GetUnhandledExceptionString(ex, callerType, callerFile, callerLineNumber, callerName); - // Send the message to the trace listener in case there is - // somebody out there listening. - Trace.TraceError(message); - - try { - ActivityLog.LogError(productTitle, message); - } catch (InvalidOperationException) { - // Activity Log is unavailable. - } - } - return result; - } - - /// - /// Waits for a task to complete and logs all exceptions except those - /// that return true from , which are - /// rethrown. - /// - public static void WaitAndHandleAllExceptions( - this Task task, - string productTitle, - Type callerType = null, - [CallerFilePath] string callerFile = null, - [CallerLineNumber] int callerLineNumber = 0, - [CallerMemberName] string callerName = null - ) { - task.HandleAllExceptions(productTitle, callerType, callerFile, callerLineNumber, callerName) - .WaitAndUnwrapExceptions(); - } - - - /// - /// Logs all exceptions from a task except those that return true from - /// , which are rethrown. - /// - public static async Task HandleAllExceptions( - this Task task, - string productTitle, - Type callerType = null, - [CallerFilePath] string callerFile = null, - [CallerLineNumber] int callerLineNumber = 0, - [CallerMemberName] string callerName = null - ) { - try { - await task; - } catch (Exception ex) { - if (ex.IsCriticalException()) { - throw; - } - - var message = SR.GetUnhandledExceptionString(ex, callerType, callerFile, callerLineNumber, callerName); - // Send the message to the trace listener in case there is - // somebody out there listening. - Trace.TraceError(message); - - try { - ActivityLog.LogError(productTitle, message); - } catch (InvalidOperationException) { - // Activity Log is unavailable. - } - } - } - } -} \ No newline at end of file diff --git a/Microsoft.VisualStudio.Project/TaskProgressBar.xaml b/Microsoft.VisualStudio.Project/TaskProgressBar.xaml deleted file mode 100644 index f4fc240d..00000000 --- a/Microsoft.VisualStudio.Project/TaskProgressBar.xaml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - diff --git a/Microsoft.VisualStudio.Project/TaskProgressBar.xaml.cs b/Microsoft.VisualStudio.Project/TaskProgressBar.xaml.cs deleted file mode 100644 index 8502330e..00000000 --- a/Microsoft.VisualStudio.Project/TaskProgressBar.xaml.cs +++ /dev/null @@ -1,84 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Threading; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Threading; -using Microsoft.VisualStudio.PlatformUI; - -namespace Microsoft.VisualStudioTools.Project { - /// - /// Interaction logic for WaitForCompleteAnalysisDialog.xaml - /// - partial class TaskProgressBar : DialogWindowVersioningWorkaround { - private readonly Task _task; - private readonly DispatcherTimer _timer; - private readonly CancellationTokenSource _cancelSource; - - public TaskProgressBar(Task task, CancellationTokenSource cancelSource, string message) { - _task = task; - InitializeComponent(); - _waitLabel.Text = message; - _timer = new DispatcherTimer(); - _timer.Interval = new TimeSpan(0, 0, 1); - _timer.Start(); - _timer.Tick += TimerTick; - _cancelSource = cancelSource; - } - - void TimerTick(object sender, EventArgs e) { - _progress.Value = (_progress.Value + 1) % 100; - } - - protected override void OnInitialized(System.EventArgs e) { - // when the task completes we post back onto our UI thread to close the dialog box. - // Capture the UI scheduler, and setup a continuation to do the close. - var curScheduler = TaskScheduler.FromCurrentSynchronizationContext(); - _task.ContinueWith(new CloseDialog(curScheduler, this).Close); - - base.OnInitialized(e); - } - - class CloseDialog { - private readonly TaskScheduler _ui; - private readonly TaskProgressBar _progressBar; - - public CloseDialog(TaskScheduler uiScheduler, TaskProgressBar progressBar) { - _ui = uiScheduler; - _progressBar = progressBar; - } - - public void Close(Task task) { - var newTask = new Task(CloseWorker); - newTask.Start(_ui); - newTask.Wait(); - } - - private void CloseWorker() { - _progressBar.DialogResult = true; - _progressBar.Close(); - } - } - - private void _cancelButton_Click(object sender, RoutedEventArgs e) { - _cancelSource.Cancel(); - this.DialogResult = false; - this.Close(); - } - } -} diff --git a/Microsoft.VisualStudio.Project/TrackDocumentsHelper.cs b/Microsoft.VisualStudio.Project/TrackDocumentsHelper.cs deleted file mode 100644 index 4b44c1a9..00000000 --- a/Microsoft.VisualStudio.Project/TrackDocumentsHelper.cs +++ /dev/null @@ -1,179 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System.Diagnostics; -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.Shell.Interop; - -namespace Microsoft.VisualStudioTools.Project { - /// - /// Used by a project to query the environment for permission to add, remove, or rename a file or directory in a solution - /// - internal class TrackDocumentsHelper { - #region fields - private ProjectNode projectMgr; - #endregion - - #region properties - - #endregion - - #region ctors - internal TrackDocumentsHelper(ProjectNode project) { - this.projectMgr = project; - } - #endregion - - #region helper methods - /// - /// Gets the IVsTrackProjectDocuments2 object by asking the service provider for it. - /// - /// the IVsTrackProjectDocuments2 object - private IVsTrackProjectDocuments2 GetIVsTrackProjectDocuments2() { - Debug.Assert(this.projectMgr != null && !this.projectMgr.IsClosed && this.projectMgr.Site != null); - - IVsTrackProjectDocuments2 documentTracker = this.projectMgr.Site.GetService(typeof(SVsTrackProjectDocuments)) as IVsTrackProjectDocuments2; - Utilities.CheckNotNull(documentTracker); - - return documentTracker; - } - - /// - /// Asks the environment for permission to add files. - /// - /// The files to add. - /// The VSQUERYADDFILEFLAGS flags associated to the files added - /// true if the file can be added, false if not. - internal bool CanAddItems(string[] files, VSQUERYADDFILEFLAGS[] flags) { - // If we are silent then we assume that the file can be added, since we do not want to trigger this event. - if ((this.projectMgr.EventTriggeringFlag & ProjectNode.EventTriggering.DoNotTriggerTrackerEvents) != 0) { - return true; - } - - if (files == null || files.Length == 0) { - return false; - } - - int len = files.Length; - VSQUERYADDFILERESULTS[] summary = new VSQUERYADDFILERESULTS[1]; - ErrorHandler.ThrowOnFailure(this.GetIVsTrackProjectDocuments2().OnQueryAddFiles(projectMgr.GetOuterInterface(), len, files, flags, summary, null)); - if (summary[0] == VSQUERYADDFILERESULTS.VSQUERYADDFILERESULTS_AddNotOK) { - return false; - } - - return true; - } - - /// - /// Notify the environment about a file just added - /// - internal void OnItemAdded(string file, VSADDFILEFLAGS flag) { - if ((this.projectMgr.EventTriggeringFlag & ProjectNode.EventTriggering.DoNotTriggerTrackerEvents) == 0) { - ErrorHandler.ThrowOnFailure(this.GetIVsTrackProjectDocuments2().OnAfterAddFilesEx(projectMgr.GetOuterInterface(), 1, new string[1] { file }, new VSADDFILEFLAGS[1] { flag })); - } - } - - /// - /// Notify the environment about a folder just added - /// - internal void OnFolderAdded(string folder, VSADDDIRECTORYFLAGS flag) { - if ((this.projectMgr.EventTriggeringFlag & ProjectNode.EventTriggering.DoNotTriggerTrackerEvents) == 0) { - ErrorHandler.ThrowOnFailure(this.GetIVsTrackProjectDocuments2().OnAfterAddDirectoriesEx( - projectMgr.GetOuterInterface(), 1, new string[1] { folder }, new VSADDDIRECTORYFLAGS[1] { flag })); - } - } - - /// - /// Asks the environment for permission to remove files. - /// - /// an array of files to remove - /// The VSQUERYREMOVEFILEFLAGS associated to the files to be removed. - /// true if the files can be removed, false if not. - internal bool CanRemoveItems(string[] files, VSQUERYREMOVEFILEFLAGS[] flags) { - // If we are silent then we assume that the file can be removed, since we do not want to trigger this event. - if ((this.projectMgr.EventTriggeringFlag & ProjectNode.EventTriggering.DoNotTriggerTrackerEvents) != 0) { - return true; - } - - if (files == null || files.Length == 0) { - return false; - } - int length = files.Length; - - VSQUERYREMOVEFILERESULTS[] summary = new VSQUERYREMOVEFILERESULTS[1]; - - ErrorHandler.ThrowOnFailure(this.GetIVsTrackProjectDocuments2().OnQueryRemoveFiles(projectMgr.GetOuterInterface(), length, files, flags, summary, null)); - if (summary[0] == VSQUERYREMOVEFILERESULTS.VSQUERYREMOVEFILERESULTS_RemoveNotOK) { - return false; - } - - return true; - } - - /// - /// Notify the environment about a file just removed - /// - internal void OnItemRemoved(string file, VSREMOVEFILEFLAGS flag) { - if ((this.projectMgr.EventTriggeringFlag & ProjectNode.EventTriggering.DoNotTriggerTrackerEvents) == 0) { - ErrorHandler.ThrowOnFailure(this.GetIVsTrackProjectDocuments2().OnAfterRemoveFiles(projectMgr.GetOuterInterface(), 1, new string[1] { file }, new VSREMOVEFILEFLAGS[1] { flag })); - } - } - - /// - /// Notify the environment about a file just removed - /// - internal void OnFolderRemoved(string folder, VSREMOVEDIRECTORYFLAGS flag) { - if ((this.projectMgr.EventTriggeringFlag & ProjectNode.EventTriggering.DoNotTriggerTrackerEvents) == 0) { - ErrorHandler.ThrowOnFailure(this.GetIVsTrackProjectDocuments2().OnAfterRemoveDirectories( - projectMgr.GetOuterInterface(), - 1, - new string[1] { folder }, - new VSREMOVEDIRECTORYFLAGS[1] { flag })); - } - } - - - /// - /// Asks the environment for permission to rename files. - /// - /// Path to the file to be renamed. - /// Path to the new file. - /// The VSRENAMEFILEFLAGS associated with the file to be renamed. - /// true if the file can be renamed. Otherwise false. - internal bool CanRenameItem(string oldFileName, string newFileName, VSRENAMEFILEFLAGS flag) { - // If we are silent then we assume that the file can be renamed, since we do not want to trigger this event. - if ((this.projectMgr.EventTriggeringFlag & (ProjectNode.EventTriggering.DoNotTriggerTrackerEvents | ProjectNode.EventTriggering.DoNotTriggerTrackerQueryEvents)) != 0) { - return true; - } - - int iCanContinue = 0; - ErrorHandler.ThrowOnFailure(this.GetIVsTrackProjectDocuments2().OnQueryRenameFile(projectMgr.GetOuterInterface(), oldFileName, newFileName, flag, out iCanContinue)); - return (iCanContinue != 0); - } - - /// - /// Get's called to tell the env that a file was renamed - /// - /// - internal void OnItemRenamed(string strOldName, string strNewName, VSRENAMEFILEFLAGS flag) { - if ((this.projectMgr.EventTriggeringFlag & ProjectNode.EventTriggering.DoNotTriggerTrackerEvents) == 0) { - ErrorHandler.ThrowOnFailure(this.GetIVsTrackProjectDocuments2().OnAfterRenameFile(projectMgr.GetOuterInterface(), strOldName, strNewName, flag)); - } - } - #endregion - } -} - diff --git a/Microsoft.VisualStudio.Project/UIThread.cs b/Microsoft.VisualStudio.Project/UIThread.cs deleted file mode 100644 index f081614a..00000000 --- a/Microsoft.VisualStudio.Project/UIThread.cs +++ /dev/null @@ -1,384 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Diagnostics; -using System.Runtime.InteropServices; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.Shell; -using IOleServiceProvider = Microsoft.VisualStudio.OLE.Interop.IServiceProvider; -using Task = System.Threading.Tasks.Task; - -namespace Microsoft.VisualStudioTools { - /// - /// Provides helper functions to execute code on the UI thread. - /// - /// - /// Because the UI thread is determined from the global service provider, - /// in non-VS tests, all invocations will occur on the current thread. - /// To specify a UI thread, call . - /// - internal static class UIThread { - private static ThreadHelper _invoker; -#if DEV10 - private static Thread _uiThread; -#endif - - private static bool? _tryToInvoke; - - /// - /// This function is called from the UI thread as early as possible. It - /// will mark this class as active and future calls to the invoke - /// methods will attempt to marshal to the UI thread. - /// - /// - /// If has already been called, - /// this method has no effect. - /// - /// If neither Initialize method is called, attempting to call any other - /// method on this class will terminate the process immediately. - /// - public static void InitializeAndAlwaysInvokeToCurrentThread() { - if (!_tryToInvoke.HasValue) { - _invoker = ThreadHelper.Generic; - _tryToInvoke = true; -#if DEV10 - Debug.Assert(_uiThread == null); - _uiThread = Thread.CurrentThread; -#endif - } - } - - /// - /// This function may be called from any thread and will prevent future - /// calls to methods on this class from trying to marshal to another - /// thread. - /// - /// - /// If neither Initialize method is called, attempting to call any other - /// method on this class will terminate the process immediately. - /// - public static void InitializeAndNeverInvoke() { - _tryToInvoke = false; - } - - internal static bool InvokeRequired { - get { - if (!_tryToInvoke.HasValue) { - // One of the initialize methods needs to be called before - // attempting to marshal to the UI thread. - Debug.Fail("Neither UIThread.Initialize method has been called"); - throw new CriticalException("Neither UIThread.Initialize method has been called"); - } - - if (_tryToInvoke == false) { - return false; - } -#if DEV10 - return Thread.CurrentThread != _uiThread; -#else - return !ThreadHelper.CheckAccess(); -#endif - } - } - - public static void MustBeCalledFromUIThreadOrThrow() { - if (InvokeRequired) { - const int RPC_E_WRONG_THREAD = unchecked((int)0x8001010E); - throw new COMException("Invalid cross-thread call", RPC_E_WRONG_THREAD); - } - } - - [Conditional("DEBUG")] - public static void MustBeCalledFromUIThread(string message = "Invalid cross-thread call") { - Debug.Assert(!InvokeRequired, message); - } - - [Conditional("DEBUG")] - public static void MustNotBeCalledFromUIThread(string message = "Invalid cross-thread call") { - if (_tryToInvoke != false) { - Debug.Assert(InvokeRequired, message); - } - } - - /// - /// Executes the specified action on the UI thread. Returns once the - /// action has been completed. - /// - /// - /// If called from the UI thread, the action is executed synchronously. - /// - public static void Invoke(Action action) { - if (InvokeRequired) { - _invoker.Invoke(action); - } else { - action(); - } - } - - /// - /// Evaluates the specified function on the UI thread. Returns once the - /// function has completed. - /// - /// - /// If called from the UI thread, the function is evaluated - /// synchronously. - /// - public static T Invoke(Func func) { - if (InvokeRequired) { - return _invoker.Invoke(func); - } else { - return func(); - } - } - - /// - /// Executes the specified action on the UI thread. The task is - /// completed once the action completes. - /// - /// - /// If called from the UI thread, the action is executed synchronously. - /// - public static Task InvokeAsync(Action action) { - var tcs = new TaskCompletionSource(); - if (InvokeRequired) { -#if DEV10 - // VS 2010 does not have BeginInvoke, so use the thread pool - // to run it asynchronously. - ThreadPool.QueueUserWorkItem(_ => { - _invoker.Invoke(() => InvokeAsyncHelper(action, tcs)); - }); -#elif DEV11 - _invoker.BeginInvoke(() => InvokeAsyncHelper(action, tcs)); -#else - _invoker.InvokeAsync(() => InvokeAsyncHelper(action, tcs)); -#endif - } else { - // Action is run synchronously, but we still return the task. - InvokeAsyncHelper(action, tcs); - } - return tcs.Task; - } - - /// - /// Evaluates the specified function on the UI thread. The task is - /// completed once the result is available. - /// - /// - /// If called from the UI thread, the function is evaluated - /// synchronously. - /// - public static Task InvokeAsync(Func func) { - var tcs = new TaskCompletionSource(); - if (InvokeRequired) { -#if DEV10 - // VS 2010 does not have BeginInvoke, so use the thread pool - // to run it asynchronously. - ThreadPool.QueueUserWorkItem(_ => { - _invoker.Invoke(() => InvokeAsyncHelper(func, tcs)); - }); -#elif DEV11 - _invoker.BeginInvoke(() => InvokeAsyncHelper(func, tcs)); -#else - _invoker.InvokeAsync(() => InvokeAsyncHelper(func, tcs)); -#endif - } else { - // Function is run synchronously, but we still return the task. - InvokeAsyncHelper(func, tcs); - } - return tcs.Task; - } - - /// - /// Awaits the provided task on the UI thread. The function will be - /// invoked on the UI thread to ensure the correct context is captured - /// for any await statements within the task. - /// - /// - /// If called from the UI thread, the function is evaluated - /// synchronously. - /// - public static Task InvokeTask(Func func) { - var tcs = new TaskCompletionSource(); - if (InvokeRequired) { -#if DEV10 - // VS 2010 does not have BeginInvoke, so use the thread pool - // to run it asynchronously. - ThreadPool.QueueUserWorkItem(_ => { - _invoker.Invoke(() => InvokeTaskHelper(func, tcs)); - }); -#elif DEV11 - _invoker.BeginInvoke(() => InvokeTaskHelper(func, tcs)); -#else - _invoker.InvokeAsync(() => InvokeTaskHelper(func, tcs)); -#endif - } else { - // Function is run synchronously, but we still return the task. - InvokeTaskHelper(func, tcs); - } - return tcs.Task; - } - - /// - /// Awaits the provided task on the UI thread. The function will be - /// invoked on the UI thread to ensure the correct context is captured - /// for any await statements within the task. - /// - /// - /// If called from the UI thread, the function is evaluated - /// synchronously. - /// - public static Task InvokeTask(Func> func) { - var tcs = new TaskCompletionSource(); - if (InvokeRequired) { -#if DEV10 - // VS 2010 does not have BeginInvoke, so use the thread pool - // to run it asynchronously. - ThreadPool.QueueUserWorkItem(_ => { - _invoker.Invoke(() => InvokeTaskHelper(func, tcs)); - }); -#elif DEV11 - _invoker.BeginInvoke(() => InvokeTaskHelper(func, tcs)); -#else - _invoker.InvokeAsync(() => InvokeTaskHelper(func, tcs)); -#endif - } else { - // Function is run synchronously, but we still return the task. - InvokeTaskHelper(func, tcs); - } - return tcs.Task; - } - - #region Helper Functions - - private static void InvokeAsyncHelper(Action action, TaskCompletionSource tcs) { - try { - action(); - tcs.TrySetResult(null); - } catch (OperationCanceledException) { - tcs.TrySetCanceled(); - } catch (Exception ex) { - if (ex.IsCriticalException()) { - throw; - } - tcs.TrySetException(ex); - } - } - - private static void InvokeAsyncHelper(Func func, TaskCompletionSource tcs) { - try { - tcs.TrySetResult(func()); - } catch (OperationCanceledException) { - tcs.TrySetCanceled(); - } catch (Exception ex) { - if (ex.IsCriticalException()) { - throw; - } - tcs.TrySetException(ex); - } - } - - private static async void InvokeTaskHelper(Func func, TaskCompletionSource tcs) { - try { - await func(); - tcs.TrySetResult(null); - } catch (OperationCanceledException) { - tcs.TrySetCanceled(); - } catch (Exception ex) { - if (ex.IsCriticalException()) { - throw; - } - tcs.TrySetException(ex); - } - } - - private static async void InvokeTaskHelper(Func> func, TaskCompletionSource tcs) { - try { - tcs.TrySetResult(await func()); - } catch (OperationCanceledException) { - tcs.TrySetCanceled(); - } catch (Exception ex) { - if (ex.IsCriticalException()) { - throw; - } - tcs.TrySetException(ex); - } - } - - #endregion - - #region Test Helpers - - /// - /// Makes the current thread the UI thread. This is done by setting - /// . - /// - /// - /// A service provider that may be used to fulfil queries made through - /// the global provider. - /// - /// - /// This function is intended solely for testing purposes and should - /// only be called from outside Visual Studio. - /// - /// - /// A UI thread already exists. This may indicate that the function - /// has been called within Visual Studio. - /// - internal static void MakeCurrentThreadUIThread(ServiceProvider provider = null) { - if (ServiceProvider.GlobalProvider != null) { - throw new InvalidOperationException("UI thread already exists"); - } - ServiceProvider.CreateFromSetSite(new DummyOleServiceProvider(provider)); - } - - class DummyOleServiceProvider : IOleServiceProvider { - private readonly ServiceProvider _provider; - - public DummyOleServiceProvider(ServiceProvider provider) { - _provider = provider; - } - - public int QueryService(ref Guid guidService, ref Guid riid, out IntPtr ppvObject) { - if (_provider == null) { - ppvObject = IntPtr.Zero; - return VSConstants.E_FAIL; - } - - object service = _provider.GetService(guidService); - if (service == null) { - ppvObject = IntPtr.Zero; - return VSConstants.E_FAIL; - } - - ppvObject = Marshal.GetIUnknownForObject(service); - if (riid != VSConstants.IID_IUnknown) { - var punk = ppvObject; - try { - Marshal.QueryInterface(punk, ref riid, out ppvObject); - } finally { - Marshal.Release(punk); - } - } - return VSConstants.S_OK; - } - } - - #endregion - } -} \ No newline at end of file diff --git a/Microsoft.VisualStudio.Project/UIThreadSynchronizer.cs b/Microsoft.VisualStudio.Project/UIThreadSynchronizer.cs deleted file mode 100644 index 1d690415..00000000 --- a/Microsoft.VisualStudio.Project/UIThreadSynchronizer.cs +++ /dev/null @@ -1,68 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.ComponentModel; -using System.Threading; -using System.Threading.Tasks; - -namespace Microsoft.VisualStudioTools.Project { - - /// - /// Implements ISynchronizeInvoke in terms of System.Threading.Tasks.Task. - /// - /// This class will handle marshalling calls back onto the UI thread for us. - /// - class UIThreadSynchronizer : ISynchronizeInvoke { - private readonly TaskScheduler _scheduler; - private readonly Thread _thread; - - /// - /// Creates a new UIThreadSynchronizer which will invoke callbacks within the - /// current synchronization context. - /// - public UIThreadSynchronizer() - : this(TaskScheduler.FromCurrentSynchronizationContext(), Thread.CurrentThread) { - } - - public UIThreadSynchronizer(TaskScheduler scheduler, Thread target) { - _scheduler = scheduler; - _thread = target; - } - - #region ISynchronizeInvoke Members - - public IAsyncResult BeginInvoke(Delegate method, params object[] args) { - return Task.Factory.StartNew(() => method.DynamicInvoke(args), default(System.Threading.CancellationToken), TaskCreationOptions.None, _scheduler); - } - - public object EndInvoke(IAsyncResult result) { - return ((Task)result).Result; - } - - public object Invoke(Delegate method, params object[] args) { - var task = Task.Factory.StartNew(() => method.DynamicInvoke(args), default(System.Threading.CancellationToken), TaskCreationOptions.None, _scheduler); - task.Wait(); - return task.Result; - } - - public bool InvokeRequired { - get { return Thread.CurrentThread != _thread; } - } - - #endregion - } -} diff --git a/Microsoft.VisualStudio.Project/UpdateSolutionEventsListener.cs b/Microsoft.VisualStudio.Project/UpdateSolutionEventsListener.cs deleted file mode 100644 index fee3031d..00000000 --- a/Microsoft.VisualStudio.Project/UpdateSolutionEventsListener.cs +++ /dev/null @@ -1,266 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Diagnostics; -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.Shell.Interop; -using IServiceProvider = System.IServiceProvider; -using ShellConstants = Microsoft.VisualStudio.Shell.Interop.Constants; - -namespace Microsoft.VisualStudioTools.Project { - /// - /// Defines an abstract class implementing IVsUpdateSolutionEvents interfaces. - /// - class UpdateSolutionEventsListener : IVsUpdateSolutionEvents3, IVsUpdateSolutionEvents2, IDisposable { - #region fields - /// - /// The cookie associated to the the events based IVsUpdateSolutionEvents2. - /// - private uint solutionEvents2Cookie; - - /// - /// The cookie associated to the theIVsUpdateSolutionEvents3 events. - /// - private uint solutionEvents3Cookie; - - /// - /// The IVsSolutionBuildManager2 object controlling the update solution events. - /// - private IVsSolutionBuildManager2 solutionBuildManager; - - - /// - /// The associated service provider. - /// - private IServiceProvider serviceProvider; - - /// - /// Flag determining if the object has been disposed. - /// - private bool isDisposed; - - /// - /// Defines an object that will be a mutex for this object for synchronizing thread calls. - /// - private static volatile object Mutex = new object(); - #endregion - - #region ctors - /// - /// Overloaded constructor. - /// - /// A service provider. - public UpdateSolutionEventsListener(IServiceProvider serviceProvider) { - if (serviceProvider == null) { - throw new ArgumentNullException("serviceProvider"); - } - - this.serviceProvider = serviceProvider; - - this.solutionBuildManager = this.serviceProvider.GetService(typeof(SVsSolutionBuildManager)) as IVsSolutionBuildManager2; - - if (this.solutionBuildManager == null) { - throw new InvalidOperationException(); - } - - ErrorHandler.ThrowOnFailure(this.solutionBuildManager.AdviseUpdateSolutionEvents(this, out this.solutionEvents2Cookie)); - - Debug.Assert(this.solutionBuildManager is IVsSolutionBuildManager3, "The solution build manager object implementing IVsSolutionBuildManager2 does not implement IVsSolutionBuildManager3"); - ErrorHandler.ThrowOnFailure(this.SolutionBuildManager3.AdviseUpdateSolutionEvents3(this, out this.solutionEvents3Cookie)); - } - #endregion - - #region properties - - /// - /// The associated service provider. - /// - protected IServiceProvider ServiceProvider { - get { - return this.serviceProvider; - } - } - - /// - /// The solution build manager object controlling the solution events. - /// - protected IVsSolutionBuildManager2 SolutionBuildManager2 { - get { - return this.solutionBuildManager; - } - } - - /// - /// The solution build manager object controlling the solution events. - /// - protected IVsSolutionBuildManager3 SolutionBuildManager3 { - get { - return (IVsSolutionBuildManager3)this.solutionBuildManager; - } - - } - #endregion - - #region IVsUpdateSolutionEvents3 Members - - /// - /// Fired after the active solution config is changed (pOldActiveSlnCfg can be NULL). - /// - /// Old configuration. - /// New configuration. - /// If the method succeeds, it returns S_OK. If it fails, it returns an error code. - public virtual int OnAfterActiveSolutionCfgChange(IVsCfg oldActiveSlnCfg, IVsCfg newActiveSlnCfg) { - var handlers = AfterActiveSolutionConfigurationChange; - if (handlers != null) { - handlers(this, EventArgs.Empty); - } - return VSConstants.S_OK; - } - - public event EventHandler AfterActiveSolutionConfigurationChange; - - /// - /// Fired before the active solution config is changed (pOldActiveSlnCfg can be NULL - /// - /// Old configuration. - /// New configuration. - /// If the method succeeds, it returns S_OK. If it fails, it returns an error code. - public virtual int OnBeforeActiveSolutionCfgChange(IVsCfg oldActiveSlnCfg, IVsCfg newActiveSlnCfg) { - return VSConstants.E_NOTIMPL; - } - - #endregion - - #region IVsUpdateSolutionEvents2 Members - - /// - /// Called when the active project configuration for a project in the solution has changed. - /// - /// The project whose configuration has changed. - /// If the method succeeds, it returns S_OK. If it fails, it returns an error code. - public virtual int OnActiveProjectCfgChange(IVsHierarchy hierarchy) { - return VSConstants.E_NOTIMPL; - } - - /// - /// Called right before a project configuration begins to build. - /// - /// The project that is to be build. - /// A configuration project object. - /// A configuration solution object. - /// The action taken. - /// A flag indicating cancel. - /// If the method succeeds, it returns S_OK. If it fails, it returns an error code. - /// The values for the action are defined in the enum _SLNUPDACTION env\msenv\core\slnupd2.h - public int UpdateProjectCfg_Begin(IVsHierarchy hierarchy, IVsCfg configProject, IVsCfg configSolution, uint action, ref int cancel) { - return VSConstants.E_NOTIMPL; - } - - /// - /// Called right after a project configuration is finished building. - /// - /// The project that has finished building. - /// A configuration project object. - /// A configuration solution object. - /// The action taken. - /// Flag indicating success. - /// Flag indicating cancel. - /// If the method succeeds, it returns S_OK. If it fails, it returns an error code. - /// The values for the action are defined in the enum _SLNUPDACTION env\msenv\core\slnupd2.h - public virtual int UpdateProjectCfg_Done(IVsHierarchy hierarchy, IVsCfg configProject, IVsCfg configSolution, uint action, int success, int cancel) { - return VSConstants.E_NOTIMPL; - } - - /// - /// Called before any build actions have begun. This is the last chance to cancel the build before any building begins. - /// - /// Flag indicating cancel update. - /// If the method succeeds, it returns S_OK. If it fails, it returns an error code. - public virtual int UpdateSolution_Begin(ref int cancelUpdate) { - return VSConstants.E_NOTIMPL; - } - - /// - /// Called when a build is being cancelled. - /// - /// If the method succeeds, it returns S_OK. If it fails, it returns an error code. - public virtual int UpdateSolution_Cancel() { - return VSConstants.E_NOTIMPL; - } - - /// - /// Called when a build is completed. - /// - /// true if no update actions failed. - /// true if any update action succeeded. - /// true if update actions were canceled. - /// If the method succeeds, it returns S_OK. If it fails, it returns an error code. - public virtual int UpdateSolution_Done(int fSucceeded, int fModified, int fCancelCommand) { - return VSConstants.E_NOTIMPL; - } - - /// - /// Called before the first project configuration is about to be built. - /// - /// A flag indicating cancel update. - /// If the method succeeds, it returns S_OK. If it fails, it returns an error code. - public virtual int UpdateSolution_StartUpdate(ref int cancelUpdate) { - return VSConstants.E_NOTIMPL; - } - - #endregion - - - #region IDisposable Members - - /// - /// The IDispose interface Dispose method for disposing the object determinastically. - /// - public void Dispose() { - this.Dispose(true); - GC.SuppressFinalize(this); - } - - #endregion - - #region methods - /// - /// The method that does the cleanup. - /// - /// true if called from IDispose.Dispose; false if called from Finalizer. - protected virtual void Dispose(bool disposing) { - // Everybody can go here. - if (!this.isDisposed) { - // Synchronize calls to the Dispose simultaniously. - lock (Mutex) { - if (this.solutionEvents2Cookie != (uint)ShellConstants.VSCOOKIE_NIL) { - ErrorHandler.ThrowOnFailure(this.solutionBuildManager.UnadviseUpdateSolutionEvents(this.solutionEvents2Cookie)); - this.solutionEvents2Cookie = (uint)ShellConstants.VSCOOKIE_NIL; - } - - if (this.solutionEvents3Cookie != (uint)ShellConstants.VSCOOKIE_NIL) { - ErrorHandler.ThrowOnFailure(this.SolutionBuildManager3.UnadviseUpdateSolutionEvents3(this.solutionEvents3Cookie)); - this.solutionEvents3Cookie = (uint)ShellConstants.VSCOOKIE_NIL; - } - - this.isDisposed = true; - } - } - } - #endregion - } -} diff --git a/Microsoft.VisualStudio.Project/Utilities.cs b/Microsoft.VisualStudio.Project/Utilities.cs deleted file mode 100644 index 3f179b04..00000000 --- a/Microsoft.VisualStudio.Project/Utilities.cs +++ /dev/null @@ -1,634 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Drawing; -using System.Globalization; -using System.IO; -using System.Runtime.InteropServices; -using System.Security.Permissions; -using System.Text; -using System.Text.RegularExpressions; -using System.Windows.Forms; -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.OLE.Interop; -using Microsoft.VisualStudio.Shell; -using Microsoft.VisualStudio.Shell.Interop; -using IServiceProvider = System.IServiceProvider; -using MSBuild = Microsoft.Build.Evaluation; - -namespace Microsoft.VisualStudioTools.Project { - public static class Utilities { - private const string defaultMSBuildVersion = "4.0"; - - /// - /// Look in the registry under the current hive for the path - /// of MSBuild - /// - /// - - /// - /// Is Visual Studio in design mode. - /// - /// The service provider. - /// true if visual studio is in design mode - public static bool IsVisualStudioInDesignMode(IServiceProvider site) { - Utilities.ArgumentNotNull("site", site); - - IVsMonitorSelection selectionMonitor = site.GetService(typeof(IVsMonitorSelection)) as IVsMonitorSelection; - uint cookie = 0; - int active = 0; - Guid designContext = VSConstants.UICONTEXT_DesignMode; - ErrorHandler.ThrowOnFailure(selectionMonitor.GetCmdUIContextCookie(ref designContext, out cookie)); - ErrorHandler.ThrowOnFailure(selectionMonitor.IsCmdUIContextActive(cookie, out active)); - return active != 0; - } - - /// - /// - /// Is an extensibility object executing an automation function. - /// - /// The service provider. - /// true if the extensiblity object is executing an automation function. - public static bool IsInAutomationFunction(IServiceProvider serviceProvider) { - Utilities.ArgumentNotNull("serviceProvider", serviceProvider); - - IVsExtensibility3 extensibility = serviceProvider.GetService(typeof(EnvDTE.IVsExtensibility)) as IVsExtensibility3; - - if (extensibility == null) { - throw new InvalidOperationException(); - } - int inAutomation = 0; - ErrorHandler.ThrowOnFailure(extensibility.IsInAutomationFunction(out inAutomation)); - return inAutomation != 0; - } - - /// - /// Creates a semicolon delinited list of strings. This can be used to provide the properties for VSHPROPID_CfgPropertyPagesCLSIDList, VSHPROPID_PropertyPagesCLSIDList, VSHPROPID_PriorityPropertyPagesCLSIDList - /// - /// An array of Guids. - /// A semicolon delimited string, or null - - public static string CreateSemicolonDelimitedListOfStringFromGuids(Guid[] guids) { - if (guids == null || guids.Length == 0) { - return String.Empty; - } - - // Create a StringBuilder with a pre-allocated buffer big enough for the - // final string. 39 is the length of a GUID in the "B" form plus the final ';' - StringBuilder stringList = new StringBuilder(39 * guids.Length); - for (int i = 0; i < guids.Length; i++) { - stringList.Append(guids[i].ToString("B")); - stringList.Append(";"); - } - - return stringList.ToString().TrimEnd(';'); - } - - private static char[] curlyBraces = new char[] { '{', '}' }; - /// - /// Take list of guids as a single string and generate an array of Guids from it - /// - /// Semi-colon separated list of Guids - /// Array of Guids - - public static Guid[] GuidsArrayFromSemicolonDelimitedStringOfGuids(string guidList) { - if (guidList == null) { - return null; - } - - List guids = new List(); - string[] guidsStrings = guidList.Split(';'); - foreach (string guid in guidsStrings) { - if (!String.IsNullOrEmpty(guid)) - guids.Add(new Guid(guid.Trim(curlyBraces))); - } - - return guids.ToArray(); - } - - internal static bool GuidEquals(string x, string y) { - Guid gx, gy; - return Guid.TryParse(x, out gx) && Guid.TryParse(y, out gy) && gx == gy; - } - - internal static bool GuidEquals(Guid x, string y) { - Guid gy; - return Guid.TryParse(y, out gy) && x == gy; - } - - internal static void CheckNotNull(object value, string message = null) { - if (value == null) { - throw new InvalidOperationException(message); - } - } - - internal static void ArgumentNotNull(string name, object value) { - if (value == null) { - throw new ArgumentNullException(name); - } - } - internal static void ArgumentNotNullOrEmpty(string name, string value) { - if (String.IsNullOrEmpty(value)) { - throw new ArgumentNullException(name); - } - } - /// - /// Validates a file path by validating all file parts. If the - /// the file name is invalid it throws an exception if the project is in automation. Otherwise it shows a dialog box with the error message. - /// - /// The service provider - /// A full path to a file name - /// In case of failure an InvalidOperationException is thrown. - public static void ValidateFileName(IServiceProvider serviceProvider, string filePath) { - string errorMessage = String.Empty; - if (String.IsNullOrEmpty(filePath)) { - errorMessage = SR.GetString(SR.ErrorInvalidFileName, filePath); - } else if (filePath.Length > NativeMethods.MAX_PATH) { - errorMessage = SR.GetString(SR.PathTooLong, filePath); - } else if (ContainsInvalidFileNameChars(filePath)) { - errorMessage = SR.GetString(SR.ErrorInvalidFileName, filePath); - } - - if (errorMessage.Length == 0) { - string fileName = Path.GetFileName(filePath); - if (String.IsNullOrEmpty(fileName) || IsFileNameInvalid(fileName)) { - errorMessage = SR.GetString(SR.ErrorInvalidFileName, filePath); - } - } - - if (errorMessage.Length > 0) { - // If it is not called from an automation method show a dialog box. - if (!Utilities.IsInAutomationFunction(serviceProvider)) { - string title = null; - OLEMSGICON icon = OLEMSGICON.OLEMSGICON_CRITICAL; - OLEMSGBUTTON buttons = OLEMSGBUTTON.OLEMSGBUTTON_OK; - OLEMSGDEFBUTTON defaultButton = OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST; - VsShellUtilities.ShowMessageBox(serviceProvider, title, errorMessage, icon, buttons, defaultButton); - } else { - throw new InvalidOperationException(errorMessage); - } - } - - } - - /// - /// Creates a CALPOLESTR from a list of strings - /// It is the responsability of the caller to release this memory. - /// - /// - /// A CALPOLESTR that was created from the the list of strings. - public static CALPOLESTR CreateCALPOLESTR(IList strings) { - CALPOLESTR calpolStr = new CALPOLESTR(); - - if (strings != null) { - // Demand unmanaged permissions in order to access unmanaged memory. - new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Demand(); - - calpolStr.cElems = (uint)strings.Count; - - int size = Marshal.SizeOf(typeof(IntPtr)); - - calpolStr.pElems = Marshal.AllocCoTaskMem(strings.Count * size); - - IntPtr ptr = calpolStr.pElems; - - foreach (string aString in strings) { - IntPtr tempPtr = Marshal.StringToCoTaskMemUni(aString); - Marshal.WriteIntPtr(ptr, tempPtr); - ptr = new IntPtr(ptr.ToInt64() + size); - } - } - - return calpolStr; - } - - /// - /// Creates a CADWORD from a list of tagVsSccFilesFlags. Memory is allocated for the elems. - /// It is the responsability of the caller to release this memory. - /// - /// - /// A CADWORD created from the list of tagVsSccFilesFlags. - public static CADWORD CreateCADWORD(IList flags) { - CADWORD cadWord = new CADWORD(); - - if (flags != null) { - // Demand unmanaged permissions in order to access unmanaged memory. - new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Demand(); - - cadWord.cElems = (uint)flags.Count; - - int size = Marshal.SizeOf(typeof(UInt32)); - - cadWord.pElems = Marshal.AllocCoTaskMem(flags.Count * size); - - IntPtr ptr = cadWord.pElems; - - foreach (tagVsSccFilesFlags flag in flags) { - Marshal.WriteInt32(ptr, (int)flag); - ptr = new IntPtr(ptr.ToInt64() + size); - } - } - - return cadWord; - } - - /// - /// Splits a bitmap from a Stream into an ImageList - /// - /// A Stream representing a Bitmap - /// An ImageList object representing the images from the given stream - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")] - public static ImageList GetImageList(Bitmap bitmap) { - ImageList ilist = new ImageList(); - - if (bitmap == null) { - Debug.Fail("ImageStream was null."); - return ilist; - } - ilist.ColorDepth = ColorDepth.Depth24Bit; - ilist.ImageSize = new Size(16, 16); - ilist.Images.AddStrip(bitmap); - ilist.TransparentColor = Color.Magenta; - return ilist; - } - - /// - /// Gets the active configuration name. - /// - /// The automation object. - /// The name of the active configuartion. - internal static string GetActiveConfigurationName(EnvDTE.Project automationObject) { - Utilities.ArgumentNotNull("automationObject", automationObject); - - string currentConfigName = string.Empty; - if (automationObject.ConfigurationManager != null) { - try { - EnvDTE.Configuration activeConfig = automationObject.ConfigurationManager.ActiveConfiguration; - if (activeConfig != null) { - currentConfigName = activeConfig.ConfigurationName; - } - } catch (COMException ex) { - Debug.WriteLine("Failed to get active configuration because of {0}", ex); - } - } - return currentConfigName; - - } - - - /// - /// Verifies that two objects represent the same instance of a COM object. - /// This essentially compares the IUnkown pointers of the 2 objects. - /// This is needed in scenario where aggregation is involved. - /// - /// Can be an object, interface or IntPtr - /// Can be an object, interface or IntPtr - /// True if the 2 items represent the same thing - public static bool IsSameComObject(object obj1, object obj2) { - bool isSame = false; - IntPtr unknown1 = IntPtr.Zero; - IntPtr unknown2 = IntPtr.Zero; - try { - // If we have 2 null, then they are not COM objects and as such "it's not the same COM object" - if (obj1 != null && obj2 != null) { - unknown1 = QueryInterfaceIUnknown(obj1); - unknown2 = QueryInterfaceIUnknown(obj2); - - isSame = IntPtr.Equals(unknown1, unknown2); - } - } finally { - if (unknown1 != IntPtr.Zero) { - Marshal.Release(unknown1); - } - - if (unknown2 != IntPtr.Zero) { - Marshal.Release(unknown2); - } - - } - - return isSame; - } - - /// - /// Retrieve the IUnknown for the managed or COM object passed in. - /// - /// Managed or COM object. - /// Pointer to the IUnknown interface of the object. - internal static IntPtr QueryInterfaceIUnknown(object objToQuery) { - bool releaseIt = false; - IntPtr unknown = IntPtr.Zero; - IntPtr result; - try { - if (objToQuery is IntPtr) { - unknown = (IntPtr)objToQuery; - } else { - // This is a managed object (or RCW) - unknown = Marshal.GetIUnknownForObject(objToQuery); - releaseIt = true; - } - - // We might already have an IUnknown, but if this is an aggregated - // object, it may not be THE IUnknown until we QI for it. - Guid IID_IUnknown = VSConstants.IID_IUnknown; - ErrorHandler.ThrowOnFailure(Marshal.QueryInterface(unknown, ref IID_IUnknown, out result)); - } finally { - if (releaseIt && unknown != IntPtr.Zero) { - Marshal.Release(unknown); - } - - } - - return result; - } - - /// - /// Returns true if thename that can represent a path, absolut or relative, or a file name contains invalid filename characters. - /// - /// File name - /// true if file name is invalid - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", - Justification = "The name is validated.")] - public static bool ContainsInvalidFileNameChars(string name) { - if (String.IsNullOrEmpty(name)) { - return true; - } - - try { - if (Path.IsPathRooted(name) && !name.StartsWith(@"\\", StringComparison.Ordinal)) { - string root = Path.GetPathRoot(name); - name = name.Substring(root.Length); - } - } - // The Path methods used by ContainsInvalidFileNameChars return argument exception if the filePath contains invalid characters. - catch (ArgumentException) { - return true; - } - - Microsoft.VisualStudio.Shell.Url uri = new Microsoft.VisualStudio.Shell.Url(name); - - // This might be confusing bur Url.IsFile means that the uri represented by the name is either absolut or relative. - if (uri.IsFile) { - string[] segments = uri.Segments; - if (segments != null && segments.Length > 0) { - foreach (string segment in segments) { - if (IsFilePartInValid(segment)) { - return true; - } - } - - // Now the last segment should be specially taken care, since that cannot be all dots or spaces. - string lastSegment = segments[segments.Length - 1]; - string filePart = Path.GetFileNameWithoutExtension(lastSegment); - // if the file is only an extension (.fob) then it's ok, otherwise we need to do the special checks. - if (filePart.Length != 0 && (IsFileNameAllGivenCharacter('.', filePart) || IsFileNameAllGivenCharacter(' ', filePart))) { - return true; - } - } - } else { - // The assumption here is that we got a file name. - string filePart = Path.GetFileNameWithoutExtension(name); - if (IsFileNameAllGivenCharacter('.', filePart) || IsFileNameAllGivenCharacter(' ', filePart)) { - return true; - } - - - return IsFilePartInValid(name); - } - - return false; - } - - /// Cehcks if a file name is valid. - /// - /// The name of the file - /// True if the file is valid. - public static bool IsFileNameInvalid(string fileName) { - if (String.IsNullOrEmpty(fileName)) { - return true; - } - - if (IsFileNameAllGivenCharacter('.', fileName) || IsFileNameAllGivenCharacter(' ', fileName)) { - return true; - } - - - return IsFilePartInValid(fileName); - - } - - /// - /// Initializes the in memory project. Sets BuildEnabled on the project to true. - /// - /// The build engine to use to create a build project. - /// The full path of the project. - /// A loaded msbuild project. - internal static MSBuild.Project InitializeMsBuildProject(MSBuild.ProjectCollection buildEngine, string fullProjectPath) { - Utilities.ArgumentNotNullOrEmpty("fullProjectPath", fullProjectPath); - - // Call GetFullPath to expand any relative path passed into this method. - fullProjectPath = CommonUtils.NormalizePath(fullProjectPath); - - - // Check if the project already has been loaded with the fullProjectPath. If yes return the build project associated to it. - List loadedProject = new List(buildEngine.GetLoadedProjects(fullProjectPath)); - MSBuild.Project buildProject = loadedProject != null && loadedProject.Count > 0 && loadedProject[0] != null ? loadedProject[0] : null; - - if (buildProject == null) { - buildProject = buildEngine.LoadProject(fullProjectPath); - } - - return buildProject; - } - - /// - /// Loads a project file for the file. If the build project exists and it was loaded with a different file then it is unloaded first. - /// - /// The build engine to use to create a build project. - /// The full path of the project. - /// An Existing build project that will be reloaded. - /// A loaded msbuild project. - internal static MSBuild.Project ReinitializeMsBuildProject(MSBuild.ProjectCollection buildEngine, string fullProjectPath, MSBuild.Project exitingBuildProject) { - // If we have a build project that has been loaded with another file unload it. - try { - if (exitingBuildProject != null && exitingBuildProject.ProjectCollection != null && !CommonUtils.IsSamePath(exitingBuildProject.FullPath, fullProjectPath)) { - buildEngine.UnloadProject(exitingBuildProject); - } - } - // We catch Invalid operation exception because if the project was unloaded while we touch the ParentEngine the msbuild API throws. - // Is there a way to figure out that a project was unloaded? - catch (InvalidOperationException) { - } - - return Utilities.InitializeMsBuildProject(buildEngine, fullProjectPath); - } - - /// > - /// Checks if the file name is all the given character. - /// - private static bool IsFileNameAllGivenCharacter(char c, string fileName) { - // A valid file name cannot be all "c" . - int charFound = 0; - for (charFound = 0; charFound < fileName.Length && fileName[charFound] == c; ++charFound) - ; - if (charFound >= fileName.Length) { - return true; - } - - return false; - } - - private const string _reservedName = "(\\b(nul|con|aux|prn)\\b)|(\\b((com|lpt)[0-9])\\b)"; - private const string _invalidChars = "([\\/:*?\"<>|#%])"; - private const string _regexToUseForFileName = _reservedName + "|" + _invalidChars; - private static Regex _unsafeFileNameCharactersRegex = new Regex(_regexToUseForFileName, RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); - private static Regex _unsafeCharactersRegex = new Regex(_invalidChars, RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); - - /// - /// Checks whether a file part contains valid characters. The file part can be any part of a non rooted path. - /// - /// - /// - private static bool IsFilePartInValid(string filePart) { - if (String.IsNullOrEmpty(filePart)) { - return true; - } - String fileNameToVerify = filePart; - - // Define a regular expression that covers all characters that are not in the safe character sets. - // It is compiled for performance. - - // The filePart might still be a file and extension. If it is like that then we must check them separately, since different rules apply - string extension = String.Empty; - try { - extension = Path.GetExtension(filePart); - } - // We catch the ArgumentException because we want this method to return true if the filename is not valid. FilePart could be for example #¤&%"¤&"% and that would throw ArgumentException on GetExtension - catch (ArgumentException) { - return true; - } - - if (!String.IsNullOrEmpty(extension)) { - // Check the extension first - bool isMatch = _unsafeCharactersRegex.IsMatch(extension); - if (isMatch) { - return isMatch; - } - - // We want to verify here everything but the extension. - // We cannot use GetFileNameWithoutExtension because it might be that for example (..\\filename.txt) is passed in and that should fail, since that is not a valid filename. - fileNameToVerify = filePart.Substring(0, filePart.Length - extension.Length); - - if (String.IsNullOrEmpty(fileNameToVerify)) { - // http://pytools.codeplex.com/workitem/497 - // .fob is ok - return false; - } - } - - // We verify CLOCK$ outside the regex since for some reason the regex is not matching the clock\\$ added. - if (String.Equals(fileNameToVerify, "CLOCK$", StringComparison.OrdinalIgnoreCase)) { - return true; - } - - return _unsafeFileNameCharactersRegex.IsMatch(fileNameToVerify); - } - - /// - /// Copy a directory recursively to the specified non-existing directory - /// - /// Directory to copy from - /// Directory to copy to - public static void RecursivelyCopyDirectory(string source, string target) { - // Make sure it doesn't already exist - if (Directory.Exists(target)) - throw new ArgumentException(SR.GetString(SR.FileOrFolderAlreadyExists, target)); - - Directory.CreateDirectory(target); - DirectoryInfo directory = new DirectoryInfo(source); - - // Copy files - foreach (FileInfo file in directory.GetFiles()) { - file.CopyTo(Path.Combine(target, file.Name)); - } - - // Now recurse to child directories - foreach (DirectoryInfo child in directory.GetDirectories()) { - RecursivelyCopyDirectory(child.FullName, Path.Combine(target, child.Name)); - } - } - - /// - /// Canonicalizes a file name, including: - /// - determines the full path to the file - /// - casts to upper case - /// Canonicalizing a file name makes it possible to compare file names using simple simple string comparison. - /// - /// Note: this method does not handle shared drives and UNC drives. - /// - /// A file name, which can be relative/absolute and contain lower-case/upper-case characters. - /// Canonicalized file name. - internal static string CanonicalizeFileName(string anyFileName) { - // Get absolute path - // Note: this will not handle UNC paths - FileInfo fileInfo = new FileInfo(anyFileName); - string fullPath = fileInfo.FullName; - - // Cast to upper-case - fullPath = fullPath.ToUpperInvariant(); - - return fullPath; - } - - /// - /// Determines if a file is a template. - /// - /// The file to check whether it is a template file - /// true if the file is a template file - internal static bool IsTemplateFile(string fileName) { - if (String.IsNullOrEmpty(fileName)) { - return false; - } - - string extension = Path.GetExtension(fileName); - return (String.Equals(extension, ".vstemplate", StringComparison.OrdinalIgnoreCase) || string.Equals(extension, ".vsz", StringComparison.OrdinalIgnoreCase)); - } - - /// - /// Save dirty files - /// - /// Whether succeeded - public static bool SaveDirtyFiles() { - var rdt = ServiceProvider.GlobalProvider.GetService(typeof(SVsRunningDocumentTable)) as IVsRunningDocumentTable; - if (rdt != null) { - // Consider using (uint)(__VSRDTSAVEOPTIONS.RDTSAVEOPT_SaveIfDirty | __VSRDTSAVEOPTIONS.RDTSAVEOPT_PromptSave) - // when VS settings include prompt for save on build - var saveOpt = (uint)__VSRDTSAVEOPTIONS.RDTSAVEOPT_SaveIfDirty; - var hr = rdt.SaveDocuments(saveOpt, null, VSConstants.VSITEMID_NIL, VSConstants.VSCOOKIE_NIL); - if (hr == VSConstants.E_ABORT) { - return false; - } - } - - return true; - } - } -} diff --git a/Microsoft.VisualStudio.Project/VirtualProjectElement.cs b/Microsoft.VisualStudio.Project/VirtualProjectElement.cs deleted file mode 100644 index 74654cc9..00000000 --- a/Microsoft.VisualStudio.Project/VirtualProjectElement.cs +++ /dev/null @@ -1,88 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Runtime.CompilerServices; - -namespace Microsoft.VisualStudioTools.Project { - class VirtualProjectElement : ProjectElement { - private readonly Dictionary _virtualProperties; - - /// - /// Constructor to Wrap an existing MSBuild.ProjectItem - /// Only have internal constructors as the only one who should be creating - /// such object is the project itself (see Project.CreateFileNode()). - /// - /// Project that owns this item - /// an MSBuild.ProjectItem; can be null if virtualFolder is true - /// Is this item virtual (such as reference folder) - internal VirtualProjectElement(ProjectNode project, string path = null) - : base(project) - { - _virtualProperties = new Dictionary(); - if(path != null) - Rename(path); - } - - protected override string ItemType { - get { - return ""; - } - set { - } - } - - /// - /// Set an attribute on the project element - /// - /// Name of the attribute to set - /// Value to give to the attribute - public override void SetMetadata(string attributeName, string attributeValue) { - Debug.Assert(String.Compare(attributeName, ProjectFileConstants.Include, StringComparison.OrdinalIgnoreCase) != 0, "Use rename as this won't work"); - - // For virtual node, use our virtual property collection - _virtualProperties[attributeName] = attributeValue; - } - - /// - /// Get the value of an attribute on a project element - /// - /// Name of the attribute to get the value for - /// Value of the attribute - public override string GetMetadata(string attributeName) { - // For virtual items, use our virtual property collection - if (!_virtualProperties.ContainsKey(attributeName)) { - return String.Empty; - } - - return _virtualProperties[attributeName]; - } - - public override void Rename(string newPath) { - _virtualProperties[ProjectFileConstants.Include] = newPath; - } - - public override bool Equals(object obj) { - return Object.ReferenceEquals(this, obj); - } - - public override int GetHashCode() { - return RuntimeHelpers.GetHashCode(this); - } - } -} diff --git a/Microsoft.VisualStudio.Project/VisualStudio.Project.resx b/Microsoft.VisualStudio.Project/VisualStudio.Project.resx deleted file mode 100644 index 45d977a7..00000000 --- a/Microsoft.VisualStudio.Project/VisualStudio.Project.resx +++ /dev/null @@ -1,665 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Failed to add file '{0}' to project as project is null. - - - Advanced - Project Property Page Caption - - - A reference to component '{0}' cannot be added. A reference to the component already exists in the project. - ReferenceAlreadyExists error message - - - Could not load attribute '{0}' from project file '{1}'. - - - Build Action - Project Build Property Name - - - How the file relates to the build and deployment process - Project Build Property Description - - - Verbosity - - - Specify how much information is included in the build output - - - ECMA-335 CLI compatible framework (location must be provided) - Target platform drop down option - - - Compile - Build Action - drop down option - - - If you change a file name extension, the file may become unusable. Are you sure you want to change it? - - - A file with name '{0}' already exists and is open in an editor. Please give a unique name to the item you are adding, or delete the existing item first. - - - Cannot save '{0}' as it is not open in the editor. - - - Content - Build Action - drop down option - - - Copy Local - File property - - - Indicates whether the reference will be copied to the output directory. - - - Detailed - - - Diagnostic - - - Directory already exists - - - Error opening specified view '{0}' using editor '{1}' - - - Embedded Resource - Build Action - drop down option - - - error - - - Invalid filename: {0} - -Files and folders cannot be: -- Empty strings -- System reserved names, including 'CON', 'AUX', PRN', 'COM1' or 'LPT2' -- contain only '.' -- have any of the following characters: / ? : & \ * " < > | # % - - - The name you provided is not a valid project name. - - - MSBuild path not found in registry. Please reinstall to fix the problem. - - - Error Saving File - - - Console Application - - - Expecting object of type {0}. - - - Failed to retrieve MSBuild property {0} from the project file. - The exception message thrown when getting a property from msbuild fails. - - - A file with the same name '{0}' already exists. Do you want to overwrite it? - - - A file with the same name '{0}' already exists. - - - Destination File Exists - - - A file named '{0}' is already part of the project. Do you want to overwrite it? - - - Destination File Exists - - - A file or folder with the name '{0}' already exists on disk at this location. Please choose another name. - - - Error Copying File - - - File Name - - - File and folder names cannot contain a leading period. - - - The name of the file or folder - - - Folder Name - - - Name of this folder - - - Full Path - - - Location of the file - - - General - - - The item '{0}' does not exist in the project directory. It may have been moved, renamed or deleted. - - - Launch URL - - - The URL which should be opened in the browser when launching the project - - - Cannot save '{0}' outside the project directory. Linked items are not supported. - - - Class Library - - - Minimal - - - Misc - - - None - - - Normal - - - Item is not available or corrupted and thus cannot be pasted. - - - Program - - - Project - - - A reference to library '{0}' cannot be added. Adding this project as a reference would cause a circular dependency. - - - Project File - - - The name of the file containing build, configuration, and other information about the project. - - - Project Folder - - - The absolute location of the project. - - - Quiet - - - (Name) - - - References - - - Display name of the reference - - - Rename directory failed. {0} - - - RTL_False - - - Save? - - - Do you want to save modified documents? - - - The project file can only be saved into the project location '{0}'. - - - Script arguments - - - Arguments passed to the script on launch - - - Error opening specified view '{0}' using standard editor. - - - Startup file - - - The startup file which is launched when running or debugging - - - Start web browser - - - True to start the web browser when launching - - - URL - - - You are trying to use an item that has already been deleted or that does not exist. - - - Microsoft .NET Framework v1.0 - - - Microsoft .NET Framework v1.1 - - - Microsoft .NET Framework v2.0 - - - warning - - - Windows Application - - - Working directory - - - The working directory when launching - - - Add Reference - - - Automation object invalid. - - - The command you are attempting cannot be completed because the file '{0}' that must be modified cannot be changed. If the file is under source control, you may want to check it out; if the file is read-only on disk, you may want to change its attributes. - MsgBox - - - Parameter must be a valid guid. - Error message in the ArgumentException for a parameter that is not a valid guid. - - - Invalid logger type\nExpected: {0}\nReceived: {1} - Error message thrown for when an invalid logger type is set. - - - InvalidParameter - Generic error message for invalid parameters. - - - ParameterCannotBeNullOEmpty - Error message for string parameters that cannot be null or empty. - - - Parameter must be a valid item identifier. - Error message thrown when an invalid item id is retrieved. - - - File Properties - - - Folder Properties - - - Project Properties - - - Reference Properties - - - A file or folder with the name '{0}' already exists on disk at this location. Please choose another name. - - - Build - - - Output Path - - - The path to the primary output - - - The complete path to '{0}' exceeds the maximum number of characters permitted by the file system. - - - Custom Tool - - - Specifies the tool that transforms a file at design time and places the output of that transformation into another file. For example, a dataset (.xsd) file comes with a default custom tool. - - - Custom Tool Namespace - - - The namespace into which the output of the custom tool is placed. - - - Primary Output - - - Content Files - - - Documentation Files - - - Localized Resources - - - Source Files - - - Debug Symbols - - - XML Serialization Assemblies - - - Contains the DLL or EXE built by the project. - - - Contains all content files in the project. - - - Contains the XML Documentation files for the project. - - - Contains the satellite assemblies for each culture's resources. - - - Contains all source files in the project. - - - Contains the debugging files for the project. - - - Contains the XML serialization assemblies for the project. - - - The project file '{0}' has been modified outside of Visual Studio. Do you want to reload the project? - - - The nested project has failed to reload. - - - The item '{0}' cannot be found on disk, either because it has been renamed, deleted, or moved to a new location. - - - A reference to {0} could not be added. Please make sure that the file is accessible, and that it is a valid assembly or COM component. - - - An 'Import' of the file '{1}' was found in the project file '{0}'. This file is not registered as a safe file to import, and could contain targets and tasks that are harmful. If this imported file is indeed considered safe, then it can be registered by writing to the registry key {2}. - - - An 'Import' of the file '{1}' was found in the user project file '{0}'. All imports in user project files are considered unsafe. - - - One or more items named '{1}' were found in the project file '{0}'. These items normally should not be specified in the project file. They can change the way targets and tasks are executed during project load, and this could have harmful effects. - - - A property named '{1}' was found in the project file '{0}'. This property normally should not be specified in the project file. Its value can change the way targets and tasks are executed during project load, and this could have harmful effects. - - - A 'UsingTask' tag which registers the '{1}' task was found in the project file '{0}'. 'UsingTask' tags in the project file take precedence over those in the imported .TARGETS files, and therefore could be used to execute arbitrary code during an otherwise unmodified build process. - - - A 'Target' named '{1}' was found in the project file '{0}'. The tasks within this target could contain arbitrary code and may get executed as soon as the project is loaded in the IDE. - - - An item referring to the file '{1}' was found in the project file '{0}'. Since this file is located within a system directory, root directory, or network share, it could be harmful to write to this file. - - - The project location is not trusted:{0}{0}{1}{0}{0}Running the application may result in security exceptions when it {0}attempts to perform actions which require full trust.{0}{0}Click OK to ignore and continue. - - - Exception was thrown during BuildBegin event\n{0} - - - Settings - - - Microsoft .NET Framework v3.0 - - - Microsoft .NET Framework v3.5 - - - Microsoft .NET Framework v4.0 - - - Publish - - - If the file should be included in the files which are published. - - - Feed - - - The WebPI Feed that contains this reference - - - Product ID - - - The product ID that for this web reference - - - WebPI Reference Properties - - - The filename or extension is too long. - - - Project Home - - - The base location for all files in the project - - - (Unknown) - - - Project is configured to launch to invalid URL: "{0}" - -Your web browser will not be opened. - - - An unexpected error occurred while attempting to upgrade a project: {0} -Run Visual Studio with the /Log option and check ActivityLog.xml for more detail. - - - The project could not be upgraded because it could not be checked out from source control. - - - The project could not be loaded. - - - No upgrade required for project. - - - Unhandled exception in {3} ({1}:{2}) -{0} - - - Dynamic Link Libraries (*.dll)|*.dll|All Files (*.*)|*.* - - - Unable to get feed "{0}". - -{1} - - - &Cancel - - - The command you are attempting cannot be completed because the files that must be modified cannot be changed. If these files are under source control, you may want to check them out; if the files are read-only on disk, you may want to change their attributes. - MsgBox - - - Error &details - - - T&ry again - - - Unable to add '{0}'. A file with that name already exists. - - - Cannot add folder '{0}' as a child or decedent of self. - - - Cannot move the folder '{0}'. A folder with that name already exists in the destination directory. - - - Cannot move '{0}'. The destination folder is the same as the source folder. - - - Cannot move '{0}'. The destination folder is a subfolder of the source folder. - - - A directory with the name '{0}' already exists. - - - The folder '{0}' does not exist on disk and could not be created. - - - The folder name is too long. - - - This folder already contains a folder called '{0}' - -If the files in the existing folder have the same names as files in the -folder you are copying, do you want to replace the existing files? - - - The source URL '{0}' could not be found. - - \ No newline at end of file diff --git a/Microsoft.VisualStudio.Project/VsCommands.cs b/Microsoft.VisualStudio.Project/VsCommands.cs deleted file mode 100644 index 886d6fa5..00000000 --- a/Microsoft.VisualStudio.Project/VsCommands.cs +++ /dev/null @@ -1,52 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Diagnostics.CodeAnalysis; - -namespace Microsoft.VisualStudioTools.Project { - /// - /// Defines menu commands guids and menu command id's - /// - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1053:StaticHolderTypesShouldNotHaveConstructors"), SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Vs")] - public class VsMenus { - // menu command guids. - public static Guid guidStandardCommandSet97 = new Guid("5efc7975-14bc-11cf-9b2b-00aa00573819"); - - public static Guid guidStandardCommandSet2K = new Guid("1496A755-94DE-11D0-8C3F-00C04FC2AAE2"); - - public static Guid guidVsVbaPkg = new Guid(0xa659f1b3, 0xad34, 0x11d1, 0xab, 0xad, 0x0, 0x80, 0xc7, 0xb8, 0x9c, 0x95); - - public static Guid guidSHLMainMenu = new Guid(0xd309f791, 0x903f, 0x11d0, 0x9e, 0xfc, 0x00, 0xa0, 0xc9, 0x11, 0x00, 0x4f); - - public static Guid guidVSUISet = new Guid("60481700-078b-11d1-aaf8-00a0c9055a90"); - - public static Guid guidVsUIHierarchyWindowCmds = new Guid("60481700-078B-11D1-AAF8-00A0C9055A90"); - - // Special Menus. - public const int IDM_VS_CTXT_CODEWIN = 0x040D; - public const int IDM_VS_CTXT_ITEMNODE = 0x0430; - public const int IDM_VS_CTXT_PROJNODE = 0x0402; - public const int IDM_VS_CTXT_REFERENCEROOT = 0x0450; - public const int IDM_VS_CTXT_REFERENCE = 0x0451; - public const int IDM_VS_CTXT_FOLDERNODE = 0x0431; - public const int IDM_VS_CTXT_NOCOMMANDS = 0x041A; - - public const int VSCmdOptQueryParameterList = 1; - public const int IDM_VS_CTXT_XPROJ_MULTIITEM = 0x0419; - public const int IDM_VS_CTXT_XPROJ_PROJITEM = 0x0417; - } -} diff --git a/Microsoft.VisualStudio.Project/VsExtensions.cs b/Microsoft.VisualStudio.Project/VsExtensions.cs deleted file mode 100644 index 2cd8c71d..00000000 --- a/Microsoft.VisualStudio.Project/VsExtensions.cs +++ /dev/null @@ -1,94 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - - -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.Shell.Interop; -using Microsoft.VisualStudio.Text; -using Microsoft.VisualStudio.Text.Editor; -using Microsoft.VisualStudioTools.Project; -using Microsoft.VisualStudioTools.Project.Automation; - -namespace Microsoft.VisualStudioTools { - static class VsExtensions { - public static string GetFilePath(this ITextView textView) { - return textView.TextBuffer.GetFilePath(); - } -#if FALSE - internal static ITrackingSpan CreateTrackingSpan(this IIntellisenseSession session, ITextBuffer buffer) { - var triggerPoint = session.GetTriggerPoint(buffer); - var position = session.GetTriggerPoint(buffer).GetPosition(session.TextView.TextSnapshot); - - var snapshot = buffer.CurrentSnapshot; - if (position == snapshot.Length) { - return snapshot.CreateTrackingSpan(position, 0, SpanTrackingMode.EdgeInclusive); - } else { - return snapshot.CreateTrackingSpan(position, 1, SpanTrackingMode.EdgeInclusive); - } - } -#endif - internal static EnvDTE.Project GetProject(this IVsHierarchy hierarchy) { - object project; - - ErrorHandler.ThrowOnFailure( - hierarchy.GetProperty( - VSConstants.VSITEMID_ROOT, - (int)__VSHPROPID.VSHPROPID_ExtObject, - out project - ) - ); - - return (project as EnvDTE.Project); - } - - public static CommonProjectNode GetCommonProject(this EnvDTE.Project project) { - OAProject oaProj = project as OAProject; - if (oaProj != null) { - var common = oaProj.Project as CommonProjectNode; - if (common != null) { - return common; - } - } - return null; - } - - public static string GetRootCanonicalName(this IVsProject project) { - return ((IVsHierarchy)project).GetRootCanonicalName(); - } - - public static string GetRootCanonicalName(this IVsHierarchy heirarchy) { - string path; - ErrorHandler.ThrowOnFailure(heirarchy.GetCanonicalName(VSConstants.VSITEMID_ROOT, out path)); - return path; - } - - internal static T[] Append(this T[] list, T item) { - T[] res = new T[list.Length + 1]; - list.CopyTo(res, 0); - res[res.Length - 1] = item; - return res; - } - - internal static string GetFilePath(this ITextBuffer textBuffer) { - ITextDocument textDocument; - if (textBuffer.Properties.TryGetProperty(typeof(ITextDocument), out textDocument)) { - return textDocument.FilePath; - } else { - return null; - } - } - } -} diff --git a/Microsoft.VisualStudio.Project/WaitDialog.cs b/Microsoft.VisualStudio.Project/WaitDialog.cs deleted file mode 100644 index 18d14fca..00000000 --- a/Microsoft.VisualStudio.Project/WaitDialog.cs +++ /dev/null @@ -1,73 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.Shell.Interop; - -namespace Microsoft.VisualStudioTools.Project { - sealed class WaitDialog : IDisposable { - private readonly int _waitResult; - private readonly IVsThreadedWaitDialog2 _waitDialog; - - public WaitDialog(string waitCaption, string waitMessage, IServiceProvider serviceProvider, int displayDelay = 1, bool isCancelable = false, bool showProgress = false) { - _waitDialog = (IVsThreadedWaitDialog2)serviceProvider.GetService(typeof(SVsThreadedWaitDialog)); - _waitResult = _waitDialog.StartWaitDialog( - waitCaption, - waitMessage, - null, - null, - null, - displayDelay, - isCancelable, - showProgress - ); - } - - public void UpdateProgress(int currentSteps, int totalSteps) { - bool canceled; - _waitDialog.UpdateProgress( - null, - null, - null, - currentSteps, - totalSteps, - false, - out canceled - ); - - } - - public bool Canceled { - get { - bool canceled; - ErrorHandler.ThrowOnFailure(_waitDialog.HasCanceled(out canceled)); - return canceled; - } - } - - #region IDisposable Members - - public void Dispose() { - if (ErrorHandler.Succeeded(_waitResult)) { - int cancelled = 0; - _waitDialog.EndWaitDialog(out cancelled); - } - } - - #endregion - } -} \ No newline at end of file diff --git a/Microsoft.VisualStudio.Project/WebPiComponentPickerControl.Designer.cs b/Microsoft.VisualStudio.Project/WebPiComponentPickerControl.Designer.cs deleted file mode 100644 index d06a71ba..00000000 --- a/Microsoft.VisualStudio.Project/WebPiComponentPickerControl.Designer.cs +++ /dev/null @@ -1,141 +0,0 @@ -namespace Microsoft.VisualStudioTools.Project { - partial class WebPiComponentPickerControl { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) { - if (disposing && (components != null)) { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Component Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() { - this.backgroundWorker5 = new System.ComponentModel.BackgroundWorker(); - this.tableLayout = new System.Windows.Forms.TableLayoutPanel(); - this._addNewFeed = new System.Windows.Forms.Button(); - this._productsList = new System.Windows.Forms.ListView(); - this._name = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this._released = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this._feed = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this._newFeedUrl = new System.Windows.Forms.TextBox(); - this._addNewFeedLabel = new System.Windows.Forms.Label(); - this.tableLayout.SuspendLayout(); - this.SuspendLayout(); - // - // tableLayout - // - this.tableLayout.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); - this.tableLayout.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); - this.tableLayout.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); - this.tableLayout.Controls.Add(this._addNewFeed, 2, 1); - this.tableLayout.Controls.Add(this._productsList, 0, 0); - this.tableLayout.Controls.Add(this._newFeedUrl, 1, 1); - this.tableLayout.Controls.Add(this._addNewFeedLabel, 0, 1); - this.tableLayout.Dock = System.Windows.Forms.DockStyle.Fill; - this.tableLayout.Location = new System.Drawing.Point(0, 0); - this.tableLayout.Name = "tableLayout"; - this.tableLayout.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); - this.tableLayout.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayout.Size = new System.Drawing.Size(501, 433); - this.tableLayout.TabIndex = 0; - // - // _addNewFeed - // - this._addNewFeed.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this._addNewFeed.AutoSize = true; - this._addNewFeed.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; - this._addNewFeed.Location = new System.Drawing.Point(364, 397); - this._addNewFeed.Name = "_addNewFeed"; - this._addNewFeed.Padding = new System.Windows.Forms.Padding(6, 3, 6, 3); - this._addNewFeed.Size = new System.Drawing.Size(134, 33); - this._addNewFeed.TabIndex = 4; - this._addNewFeed.Text = "Add New Feed..."; - this._addNewFeed.UseVisualStyleBackColor = true; - this._addNewFeed.Click += new System.EventHandler(this.AddNewFeedClick); - // - // _productsList - // - this._productsList.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { - this._name, - this._released, - this._feed}); - this.tableLayout.SetColumnSpan(this._productsList, 3); - this._productsList.Dock = System.Windows.Forms.DockStyle.Fill; - this._productsList.Location = new System.Drawing.Point(3, 3); - this._productsList.Name = "_productsList"; - this._productsList.Size = new System.Drawing.Size(495, 388); - this._productsList.TabIndex = 0; - this._productsList.UseCompatibleStateImageBehavior = false; - this._productsList.View = System.Windows.Forms.View.Details; - // - // _name - // - this._name.Text = "Name"; - this._name.Width = 154; - // - // _released - // - this._released.Text = "Released"; - this._released.Width = 110; - // - // _feed - // - this._feed.Text = "Feed"; - this._feed.Width = 283; - // - // _newFeedUrl - // - this._newFeedUrl.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); - this._newFeedUrl.Location = new System.Drawing.Point(84, 402); - this._newFeedUrl.Name = "_newFeedUrl"; - this._newFeedUrl.Size = new System.Drawing.Size(274, 22); - this._newFeedUrl.TabIndex = 5; - this._newFeedUrl.TextChanged += new System.EventHandler(this.NewFeedUrlTextChanged); - // - // _addNewFeedLabel - // - this._addNewFeedLabel.Anchor = System.Windows.Forms.AnchorStyles.Left; - this._addNewFeedLabel.AutoSize = true; - this._addNewFeedLabel.Location = new System.Drawing.Point(3, 405); - this._addNewFeedLabel.Name = "_addNewFeedLabel"; - this._addNewFeedLabel.Size = new System.Drawing.Size(75, 17); - this._addNewFeedLabel.TabIndex = 6; - this._addNewFeedLabel.Text = "New Feed:"; - // - // WebPiComponentPickerControl - // - this.Controls.Add(this.tableLayout); - this.Name = "WebPiComponentPickerControl"; - this.Size = new System.Drawing.Size(501, 433); - this.tableLayout.ResumeLayout(false); - this.tableLayout.PerformLayout(); - this.ResumeLayout(false); - - } - - #endregion - - private System.ComponentModel.BackgroundWorker backgroundWorker5; - private System.Windows.Forms.Button _addNewFeed; - private System.Windows.Forms.ListView _productsList; - private System.Windows.Forms.ColumnHeader _name; - private System.Windows.Forms.ColumnHeader _released; - private System.Windows.Forms.ColumnHeader _feed; - private System.Windows.Forms.TextBox _newFeedUrl; - private System.Windows.Forms.Label _addNewFeedLabel; - private System.Windows.Forms.TableLayoutPanel tableLayout; - } -} diff --git a/Microsoft.VisualStudio.Project/WebPiComponentPickerControl.cs b/Microsoft.VisualStudio.Project/WebPiComponentPickerControl.cs deleted file mode 100644 index 26d0188f..00000000 --- a/Microsoft.VisualStudio.Project/WebPiComponentPickerControl.cs +++ /dev/null @@ -1,323 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; -using System.Runtime.InteropServices; -using System.Windows.Forms; -using System.Xml; -using System.Xml.XPath; -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.Shell; -using Microsoft.VisualStudio.Shell.Interop; -using Task = System.Threading.Tasks.Task; - -namespace Microsoft.VisualStudioTools.Project { - [Guid("B7773A32-2EE5-4844-9630-F14768A5D03C")] - partial class WebPiComponentPickerControl : UserControl { - private readonly List _packages = new List(); - private const string _defaultFeeds = "https://www.microsoft.com/web/webpi/5.0/webproductlist.xml"; - private ListViewSorter _sorter = new ListViewSorter(); - - public WebPiComponentPickerControl() { - InitializeComponent(); - - AutoSize = true; - AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; - _productsList.ItemSelectionChanged += new ListViewItemSelectionChangedEventHandler(ProductsListItemSelectionChanged); - _productsList.ListViewItemSorter = _sorter; - _productsList.DoubleClick += new EventHandler(ProductsListDoubleClick); - _productsList.ColumnClick += new ColumnClickEventHandler(ProductsListColumnClick); - } - - private void ProductsListColumnClick(object sender, ColumnClickEventArgs e) { - if (e.Column == _sorter.Column) { - if (_sorter.Order == SortOrder.Ascending) { - _sorter.Order = SortOrder.Descending; - } else { - _sorter.Order = SortOrder.Ascending; - } - } else { - _sorter.Column = e.Column; - _sorter.Order = SortOrder.Ascending; - } - _productsList.Sort(); - } - - private void ProductsListDoubleClick(object sender, EventArgs e) { - NativeMethods.SendMessage( - NativeMethods.GetParent(NativeMethods.GetParent(NativeMethods.GetParent(Handle))), - (uint)VSConstants.CPDN_SELDBLCLICK, - IntPtr.Zero, - Handle - ); - } - - private void ProductsListItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e) { - NativeMethods.SendMessage( - NativeMethods.GetParent(NativeMethods.GetParent(NativeMethods.GetParent(Handle))), - (uint)VSConstants.CPDN_SELCHANGED, - IntPtr.Zero, - Handle - ); - } - - private async Task RequestFeeds(string feedSource) { - try { - await Task.Run(() => GetFeeds(feedSource)); - } catch (Exception ex) { - if (ex.IsCriticalException()) { - throw; - } - - MessageBox.Show(SR.GetString(SR.WebPiFeedError, feedSource, ex.Message)); - - var fullMessage = SR.GetString(SR.WebPiFeedError, feedSource, ex); - Trace.WriteLine(fullMessage); - try { - ActivityLog.LogError("WebPiComponentPickerControl", fullMessage); - } catch (InvalidOperationException) { - } - } - } - - private void GetFeeds(string feed) { - var doc = new XPathDocument(feed); - XmlNamespaceManager mngr = new XmlNamespaceManager(new NameTable()); - mngr.AddNamespace("x", "http://www.w3.org/2005/Atom"); - - var nav = doc.CreateNavigator(); - - var nodes = nav.Select("/x:feed/x:entry", mngr); - foreach (XPathNavigator node in nodes) { - var title = node.Select("x:title", mngr); - var updated = node.Select("x:updated", mngr); - var productId = node.Select("x:productId", mngr); - - string titleVal = null; - foreach (XPathNavigator titleNode in title) { - titleVal = titleNode.Value; - break; - } - - string updatedVal = null; - foreach (XPathNavigator updatedNode in updated) { - updatedVal = updatedNode.Value; - } - - - string productIdVal = null; - foreach (XPathNavigator productIdNode in productId) { - productIdVal = productIdNode.Value; - } - - if (titleVal != null && updatedVal != null && productIdVal != null) { - var newPackage = new PackageInfo( - titleVal, - updatedVal, - productIdVal, - feed - ); - - _packages.Add(newPackage); - - try { - BeginInvoke(new Action(AddPackage), newPackage); - } catch (InvalidOperationException) { - break; - } - } - } - } - - private void AddPackage(object package) { - var pkgInfo = (PackageInfo)package; - var item = new ListViewItem( - new[] { - pkgInfo.Title, - pkgInfo.Updated, - pkgInfo.ProductId, - pkgInfo.Feed - } - ); - - item.Tag = pkgInfo; - _productsList.Items.Add(item); - } - - class PackageInfo { - public readonly string Title; - public readonly string Updated; - public readonly string ProductId; - public readonly string Feed; - - public PackageInfo(string title, string updated, string productId, string feed) { - Title = title; - Updated = updated; - ProductId = productId; - Feed = feed; - } - } - - class ListViewSorter : IComparer { - public SortOrder Order; - public int Column; - - #region IComparer Members - - public int Compare(object x, object y) { - ListViewItem itemX = (ListViewItem)x; - ListViewItem itemY = (ListViewItem)y; - - int? res = null; - if (Column == 1) { - DateTime dtX, dtY; - if (DateTime.TryParse(itemX.SubItems[1].Text, out dtX) && - DateTime.TryParse(itemY.SubItems[1].Text, out dtY)) { - res = dtX.CompareTo(dtY); - } - } - - if (res == null) { - res = String.Compare( - itemX.SubItems[0].Text, - itemY.SubItems[0].Text, - true - ); - } - - if (Order == SortOrder.Descending) { - return -res.Value; - } - return res.Value; - } - - #endregion - } - private void AddNewFeedClick(object sender, EventArgs e) { - RequestFeeds(_newFeedUrl.Text).DoNotWait(); - } - - protected override void DefWndProc(ref Message m) { - switch (m.Msg) { - case NativeMethods.WM_INITDIALOG: - SetWindowStyleOnStaticHostControl(); - goto default; - case VSConstants.CPPM_INITIALIZELIST: - RequestFeeds(_defaultFeeds).DoNotWait(); - break; - case VSConstants.CPPM_SETMULTISELECT: - _productsList.MultiSelect = (m.WParam != IntPtr.Zero); - break; - case VSConstants.CPPM_CLEARSELECTION: - _productsList.SelectedItems.Clear(); - break; - case VSConstants.CPPM_QUERYCANSELECT: - Marshal.WriteInt32( - m.LParam, - (_productsList.SelectedItems.Count > 0) ? 1 : 0 - ); - break; - case VSConstants.CPPM_GETSELECTION: - var items = new PackageInfo[this._productsList.SelectedItems.Count]; - for (int i = 0; i < items.Length; i++) { - items[i] = (PackageInfo)_productsList.SelectedItems[0].Tag; - } - int count = items != null ? items.Length : 0; - Marshal.WriteByte(m.WParam, Convert.ToByte(count)); - if (count > 0) { - IntPtr ppItems = Marshal.AllocCoTaskMem( - count * Marshal.SizeOf(typeof(IntPtr))); - for (int i = 0; i < count; i++) { - IntPtr pItem = Marshal.AllocCoTaskMem( - Marshal.SizeOf(typeof(VSCOMPONENTSELECTORDATA))); - Marshal.WriteIntPtr( - ppItems + i * Marshal.SizeOf(typeof(IntPtr)), - pItem); - VSCOMPONENTSELECTORDATA data = new VSCOMPONENTSELECTORDATA() { - dwSize = (uint)Marshal.SizeOf(typeof(VSCOMPONENTSELECTORDATA)), - bstrFile = items[i].Feed, - bstrTitle = items[i].ProductId, - bstrProjRef = items[i].Title, - type = VSCOMPONENTTYPE.VSCOMPONENTTYPE_Custom - }; - Marshal.StructureToPtr(data, pItem, false); - } - Marshal.WriteIntPtr(m.LParam, ppItems); - } - break; - case NativeMethods.WM_SIZE: - IntPtr parentHwnd = NativeMethods.GetParent(Handle); - - if (parentHwnd != IntPtr.Zero) { - IntPtr grandParentHwnd = NativeMethods.GetParent(parentHwnd); - - User32RECT parentClientRect, grandParentClientRect; - if (grandParentHwnd != IntPtr.Zero && - NativeMethods.GetClientRect(parentHwnd, out parentClientRect) && - NativeMethods.GetClientRect(grandParentHwnd, out grandParentClientRect)) { - - int width = grandParentClientRect.Width; - int height = grandParentClientRect.Height; - - if ((parentClientRect.Width != width) || (parentClientRect.Height != height)) { - NativeMethods.MoveWindow(parentHwnd, 0, 0, width, height, true); - this.Width = width; - this.Height = height; - } - this.Refresh(); - } - } - break; - default: - base.DefWndProc(ref m); - break; - } - } - - private void NewFeedUrlTextChanged(object sender, EventArgs e) { - try { - new Uri(_newFeedUrl.Text); - _addNewFeed.Enabled = true; - } catch (UriFormatException) { - _addNewFeed.Enabled = false; - } - } - - /// - /// VS hosts us in a static control ("This is a static!") but that control doesn't - /// have the WS_EX_CONTROLPARENT style like it should (and like our UserControl properly - /// gets because it's a ContainerControl). This causes an infinite loop when we start - /// trying to loop through the controls if the user navigates away from the control. - /// - /// http://support.microsoft.com/kb/149501 - /// - /// So we go in and muck about with the This is a static! control's window style so that - /// we don't hang VS if the user alt-tabs away. - /// - private void SetWindowStyleOnStaticHostControl() { - var target = (NativeMethods.GetParent(Handle)); - NativeMethods.SetWindowLong( - target, - NativeMethods.GWL_EXSTYLE, - NativeMethods.WS_EX_CONTROLPARENT | NativeMethods.GetWindowLong(target, NativeMethods.GWL_EXSTYLE) - ); - } - } -} - diff --git a/Microsoft.VisualStudio.Project/WebPiComponentPickerControl.resx b/Microsoft.VisualStudio.Project/WebPiComponentPickerControl.resx deleted file mode 100644 index 86f37162..00000000 --- a/Microsoft.VisualStudio.Project/WebPiComponentPickerControl.resx +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - 673, 17 - - - 300 - - \ No newline at end of file diff --git a/Microsoft.VisualStudio.Project/WebSocketStream.cs b/Microsoft.VisualStudio.Project/WebSocketStream.cs deleted file mode 100644 index ecee566f..00000000 --- a/Microsoft.VisualStudio.Project/WebSocketStream.cs +++ /dev/null @@ -1,103 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.IO; -using System.Net.WebSockets; -using System.Threading; -using System.Threading.Tasks; - -namespace Microsoft.VisualStudioTools { - /// - /// Wraps a instance and exposes its interface as a generic . - /// - internal class WebSocketStream : Stream { - private readonly WebSocket _webSocket; - private bool _ownsSocket; - - public WebSocketStream(WebSocket webSocket, bool ownsSocket = false) { - _webSocket = webSocket; - _ownsSocket = ownsSocket; - } - - protected override void Dispose(bool disposing) { - base.Dispose(disposing); - if (disposing && _ownsSocket) { - _webSocket.Dispose(); - } - } - - public override bool CanRead { - get { return true; } - } - - public override bool CanWrite { - get { return true; } - } - - public override bool CanSeek { - get { return false; } - } - - public override void Flush() { - } - - public override Task FlushAsync(CancellationToken cancellationToken) { - return Task.FromResult(true); - } - - public override int Read(byte[] buffer, int offset, int count) { - return ReadAsync(buffer, offset, count).GetAwaiter().GetResult(); - } - - public override async Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { - try { - return (await _webSocket.ReceiveAsync(new ArraySegment(buffer, offset, count), cancellationToken).ConfigureAwait(false)).Count; - } catch (WebSocketException ex) { - throw new IOException(ex.Message, ex); - } - } - - public override void Write(byte[] buffer, int offset, int count) { - WriteAsync(buffer, offset, count).GetAwaiter().GetResult(); - } - - public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { - try { - await _webSocket.SendAsync(new ArraySegment(buffer, offset, count), WebSocketMessageType.Binary, true, cancellationToken).ConfigureAwait(false); - } catch (WebSocketException ex) { - throw new IOException(ex.Message, ex); - } - } - - public override long Length { - get { throw new NotSupportedException(); } - } - - public override long Position { - get { throw new NotSupportedException(); } - set { throw new NotSupportedException(); } - } - - public override void SetLength(long value) { - throw new NotSupportedException(); - } - - public override long Seek(long offset, SeekOrigin origin) { - throw new NotSupportedException(); - } - } -} diff --git a/Microsoft.VisualStudio.Project/Wpf/Commands.cs b/Microsoft.VisualStudio.Project/Wpf/Commands.cs deleted file mode 100644 index ccdf96d5..00000000 --- a/Microsoft.VisualStudio.Project/Wpf/Commands.cs +++ /dev/null @@ -1,141 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.IO; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Input; -using System.Windows.Interop; - -namespace Microsoft.VisualStudioTools.Wpf { - /// - /// Infrastructure class. - /// - public static class Commands { - private static readonly RoutedCommand _browseFolder = new RoutedCommand(); - private static readonly RoutedCommand _browseOpenFile = new RoutedCommand(); - private static readonly RoutedCommand _browseSaveFile = new RoutedCommand(); - - /// - /// Displays UI to browse for a single folder and sets the TextBox that - /// is specified as the CommandTarget to the selected path. - /// - public static RoutedCommand BrowseFolder { get { return _browseFolder; } } - /// - /// Displays UI to open a single file using the filter in - /// CommandParameter and sets the TextBox that is specified as the - /// CommandTarget to the selected path. - /// - public static RoutedCommand BrowseOpenFile { get { return _browseOpenFile; } } - /// - /// Displays UI to save a single file using the filter in - /// CommandParameter and sets the TextBox that is specified as the - /// CommandTarget to the selected path. - /// - public static RoutedCommand BrowseSaveFile { get { return _browseSaveFile; } } - - /// - /// Handles the CanExecute event for all commands defined in this class. - /// - public static void CanExecute(Window window, object sender, CanExecuteRoutedEventArgs e) { - if (e.Command == BrowseFolder || e.Command == BrowseOpenFile || e.Command == BrowseSaveFile) { - e.CanExecute = e.OriginalSource is TextBox; - } - } - - /// - /// Handles the Executed event for all commands defined in this class. - /// - public static void Executed(Window window, object sender, ExecutedRoutedEventArgs e) { - if (e.Command == BrowseFolder) { - BrowseFolderExecute(window, e); - } else if (e.Command == BrowseOpenFile) { - BrowseOpenFileExecute(window, e); - } else if (e.Command == BrowseSaveFile) { - BrowseSaveFileExecute(window, e); - } - } - - private static void BrowseFolderExecute(Window window, ExecutedRoutedEventArgs e) { - var tb = (TextBox)e.OriginalSource; - if (!tb.AcceptsReturn) { - var path = e.Parameter as string ?? tb.GetValue(TextBox.TextProperty) as string; - while (!string.IsNullOrEmpty(path) && !Directory.Exists(path)) { - path = Path.GetDirectoryName(path); - } - path = Dialogs.BrowseForDirectory(new WindowInteropHelper(window).Handle, path); - if (path != null) { - tb.SetCurrentValue(TextBox.TextProperty, path); - var binding = BindingOperations.GetBindingExpressionBase(tb, TextBox.TextProperty); - if (binding != null) { - binding.UpdateSource(); - } - } - } else { - var existing = tb.GetValue(TextBox.TextProperty) as string; - var path = e.Parameter as string; - while (!string.IsNullOrEmpty(path) && !Directory.Exists(path)) { - path = Path.GetDirectoryName(path); - } - path = Dialogs.BrowseForDirectory(new WindowInteropHelper(window).Handle, path); - if (path != null) { - if (string.IsNullOrEmpty(existing)) { - tb.SetCurrentValue(TextBox.TextProperty, path); - } else { - tb.SetCurrentValue(TextBox.TextProperty, existing.TrimEnd(new[] { '\r', '\n' }) + Environment.NewLine + path); - } - var binding = BindingOperations.GetBindingExpressionBase(tb, TextBox.TextProperty); - if (binding != null) { - binding.UpdateSource(); - } - } - } - } - - private static void BrowseOpenFileExecute(Window window, ExecutedRoutedEventArgs e) { - var tb = (TextBox)e.OriginalSource; - var filter = (e.Parameter as string) ?? "All Files (*.*)|*.*"; - - var path = tb.GetValue(TextBox.TextProperty) as string; - path = Dialogs.BrowseForFileOpen(new WindowInteropHelper(window).Handle, filter, path); - if (path != null) { - tb.SetCurrentValue(TextBox.TextProperty, path); - var binding = BindingOperations.GetBindingExpressionBase(tb, TextBox.TextProperty); - if (binding != null) { - binding.UpdateSource(); - } - } - } - - private static void BrowseSaveFileExecute(Window window, ExecutedRoutedEventArgs e) { - var tb = (TextBox)e.OriginalSource; - var filter = (e.Parameter as string) ?? "All Files (*.*)|*.*"; - - var path = tb.GetValue(TextBox.TextProperty) as string; - path = Dialogs.BrowseForFileSave(new WindowInteropHelper(window).Handle, filter, path); - if (path != null) { - tb.SetCurrentValue(TextBox.TextProperty, path); - var binding = BindingOperations.GetBindingExpressionBase(tb, TextBox.TextProperty); - if (binding != null) { - binding.UpdateSource(); - } - } - } - - } -} diff --git a/Microsoft.VisualStudio.Project/Wpf/Controls.cs b/Microsoft.VisualStudio.Project/Wpf/Controls.cs deleted file mode 100644 index 80c74eb6..00000000 --- a/Microsoft.VisualStudio.Project/Wpf/Controls.cs +++ /dev/null @@ -1,214 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Drawing; -using System.Linq; -using System.Runtime.InteropServices; -using System.Windows; -using System.Windows.Data; -using System.Windows.Interop; -using System.Windows.Media.Imaging; -using Microsoft.VisualStudio.PlatformUI; -using Microsoft.VisualStudio.Shell; - -namespace Microsoft.VisualStudioTools.Wpf { - public static class Controls { - public static readonly object BackgroundKey = VsBrushes.WindowKey; - public static readonly object BackgroundAccentKey = VsBrushes.ButtonFaceKey; - public static readonly object ForegroundKey = VsBrushes.WindowTextKey; - public static readonly object GrayTextKey = VsBrushes.GrayTextKey; - public static readonly object HighlightKey = VsBrushes.HighlightKey; - public static readonly object HighlightTextKey = VsBrushes.HighlightTextKey; - public static readonly object HotTrackKey = VsBrushes.CommandBarMouseOverBackgroundGradientKey; - - public static readonly object TooltipBackgroundKey = VsBrushes.InfoBackgroundKey; - public static readonly object TooltipTextKey = VsBrushes.InfoTextKey; - - public static readonly object HyperlinkKey = VsBrushes.ControlLinkTextKey; - public static readonly object HyperlinkHoverKey = VsBrushes.ControlLinkTextHoverKey; - - public static readonly object ControlBackgroundKey = VsBrushes.ComboBoxBackgroundKey; - public static readonly object ControlForegroundKey = VsBrushes.WindowTextKey; - public static readonly object ControlBorderKey = VsBrushes.ComboBoxBorderKey; - public static readonly object ControlBackgroundHoverKey = VsBrushes.ComboBoxMouseOverBackgroundGradientKey; - public static readonly object ControlBorderHoverKey = VsBrushes.ComboBoxMouseOverGlyphKey; - public static readonly object ControlBackgroundPressedKey = VsBrushes.ComboBoxMouseDownBackgroundKey; - public static readonly object ControlForegroundPressedKey = VsBrushes.ComboBoxGlyphKey; - public static readonly object ControlBorderPressedKey = VsBrushes.ComboBoxMouseDownBorderKey; - public static readonly object ControlBackgroundSelectedKey = VsBrushes.ComboBoxMouseDownBackgroundKey; - public static readonly object ControlForegroundSelectedKey = VsBrushes.ComboBoxGlyphKey; - public static readonly object ControlBorderSelectedKey = VsBrushes.ComboBoxMouseOverBorderKey; - public static readonly object ControlBackgroundDisabledKey = VsBrushes.ComboBoxDisabledBackgroundKey; - public static readonly object ControlForegroundDisabledKey = VsBrushes.ComboBoxDisabledGlyphKey; - public static readonly object ControlBorderDisabledKey = VsBrushes.ComboBoxDisabledBorderKey; - - public static readonly object ComboBoxPopupBackgroundKey = VsBrushes.ComboBoxPopupBackgroundGradientKey; - public static readonly object ComboBoxPopupBorderKey = VsBrushes.ComboBoxPopupBorderKey; - public static readonly object ComboBoxPopupForegroundKey = VsBrushes.WindowTextKey; - - public static readonly object ButtonForegroundPressedKey = VsBrushes.ToolWindowButtonDownActiveGlyphKey; - public static readonly object ButtonBackgroundPressedKey = VsBrushes.ComboBoxMouseOverBorderKey; - public static readonly object ButtonBackgroundHoverKey = VsBrushes.CommandBarHoverOverSelectedKey; - public static readonly object ButtonBorderHoverKey = VsBrushes.ComboBoxMouseOverGlyphKey; - - public static readonly object ScrollBarBackgroundKey = VsBrushes.ScrollBarBackgroundKey; - public static readonly object ScrollBarThumbBackgroundKey = VsBrushes.ScrollBarThumbBackgroundKey; - public static readonly object ScrollBarThumbBackgroundHoverKey = VsBrushes.ScrollBarThumbMouseOverBackgroundKey; - public static readonly object ScrollBarThumbBackgroundPressedKey = VsBrushes.ScrollBarThumbPressedBackgroundKey; - public static readonly object ScrollBarArrowKey = VsBrushes.ScrollBarThumbGlyphKey; - public static readonly object ScrollBarArrowHoverKey = VsBrushes.GrayTextKey; - public static readonly object ScrollBarArrowPressedKey = VsBrushes.WindowTextKey; - public static readonly object ScrollBarArrowDisabledKey = VsBrushes.ScrollBarThumbGlyphKey; - public static readonly object ScrollBarArrowBackgroundKey = VsBrushes.ScrollBarArrowBackgroundKey; - public static readonly object ScrollBarArrowBackgroundHoverKey = VsBrushes.ScrollBarArrowMouseOverBackgroundKey; - public static readonly object ScrollBarArrowBackgroundPressedKey = VsBrushes.ScrollBarArrowPressedBackgroundKey; - public static readonly object ScrollBarArrowBackgroundDisabledKey = VsBrushes.ScrollBarArrowDisabledBackgroundKey; - -#if DEV11_OR_LATER - public static readonly object SearchGlyphBrushKey = SearchControlColors.SearchGlyphBrushKey; -#else - public static readonly object SearchGlyphBrushKey = VsBrushes.WindowTextKey; -#endif - - public static readonly BitmapSource UacShield = CreateUacShield(); - - private static BitmapSource CreateUacShield() { - if (Environment.OSVersion.Version.Major >= 6) { - var sii = new NativeMethods.SHSTOCKICONINFO(); - sii.cbSize = (UInt32)Marshal.SizeOf(typeof(NativeMethods.SHSTOCKICONINFO)); - - Marshal.ThrowExceptionForHR(NativeMethods.SHGetStockIconInfo(77, 0x0101, ref sii)); - try { - return Imaging.CreateBitmapSourceFromHIcon( - sii.hIcon, - Int32Rect.Empty, - BitmapSizeOptions.FromEmptyOptions()); - } finally { - NativeMethods.DestroyIcon(sii.hIcon); - } - } else { - return Imaging.CreateBitmapSourceFromHIcon( - SystemIcons.Shield.Handle, - Int32Rect.Empty, - BitmapSizeOptions.FromEmptyOptions()); - } - } - } - - [ValueConversion(typeof(bool), typeof(object))] - public sealed class IfElseConverter : IValueConverter, IMultiValueConverter { - public object IfTrue { - get; - set; - } - - public object IfFalse { - get; - set; - } - - public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { - return (value as bool? == true) ? IfTrue : IfFalse; - } - - public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { - return (value == IfTrue); - } - - public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture) { - return values.All(b => b as bool? == true) ? IfTrue : IfFalse; - } - - public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture) { - throw new NotImplementedException(); - } - } - - [ValueConversion(typeof(object), typeof(object))] - public sealed class ComparisonConverter : IValueConverter { - public object IfTrue { - get; - set; - } - - public object IfFalse { - get; - set; - } - - public ComparisonOperator Operator { - get; - set; - } - - public object SecondOperand { - get; - set; - } - - public enum ComparisonOperator { - LessThan, - LessThanOrEqualTo, - EqualTo, - NotEqualTo, - GreaterThan, - GreaterThanOrEqualTo - } - - public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { - return (Compare(value, Operator, SecondOperand)) ? IfTrue : IfFalse; - } - - public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { - throw new NotImplementedException(); - } - - private bool Compare(object firstOperand, ComparisonOperator comparisonOperator, object secondOperand) { - // There may be loss of precision if firstOperand and secondOperand are not of the same type. - // This is unfortunately unavoidable unless we want to use type-specific converters. - - var firstComparable = firstOperand as IComparable; - if (firstComparable == null) { - return false; - } - - var secondComparable = System.Convert.ChangeType(secondOperand, firstComparable.GetType()); - if (secondComparable == null) { - return false; - } - - int result = firstComparable.CompareTo(secondComparable); - - switch (comparisonOperator) { - case ComparisonOperator.LessThan: - return result < 0; - case ComparisonOperator.LessThanOrEqualTo: - return result <= 0; - case ComparisonOperator.EqualTo: - return result == 0; - case ComparisonOperator.NotEqualTo: - return result != 0; - case ComparisonOperator.GreaterThanOrEqualTo: - return result >= 0; - case ComparisonOperator.GreaterThan: - return result > 0; - } - - throw new ArgumentException(String.Format("Comparison operator {0} not handled", comparisonOperator)); - } - } -} diff --git a/Microsoft.VisualStudio.Project/Wpf/Controls.xaml b/Microsoft.VisualStudio.Project/Wpf/Controls.xaml deleted file mode 100644 index 993673c7..00000000 --- a/Microsoft.VisualStudio.Project/Wpf/Controls.xaml +++ /dev/null @@ -1,953 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cargo manifest could not be loaded due to errors: - - - - Do you want to pick a different path or reload from the existing one? - - - - diff --git a/VisualRust.Project/Controls/OpenManifestErrorWindow.xaml.cs b/VisualRust.Project/Controls/OpenManifestErrorWindow.xaml.cs deleted file mode 100644 index de03cbe1..00000000 --- a/VisualRust.Project/Controls/OpenManifestErrorWindow.xaml.cs +++ /dev/null @@ -1,68 +0,0 @@ -using Microsoft.Win32; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Navigation; -using System.Windows.Shapes; - -namespace VisualRust.Project.Controls -{ - partial class OpenManifestErrorWindow : ChildWindow - { - public OpenManifestErrorWindow() - { - InitializeComponent(); - } - - public string FileName { get; private set; } - public string Errors { get; private set; } - public string NewManifest { get; private set; } - public bool Reload { get; private set; } - - public OpenManifestErrorWindow(Window owner, string fileName, string[] errors) : base(owner) - { - InitializeComponent(); - FileName = fileName; - Errors = String.Join(Environment.NewLine, errors); - DataContext = this; - } - - private void OnBrowse(object sender, RoutedEventArgs e) - { - OpenFileDialog openFile = new OpenFileDialog() - { - Filter = "TOML files|*.toml|All files|*.*", - InitialDirectory = System.IO.Path.GetDirectoryName(FileName), - }; - bool? result = openFile.ShowDialog(); - if (result == true) - { - NewManifest = openFile.FileName; - DialogResult = true; - this.Close(); - } - } - - private void OnReload(object sender, RoutedEventArgs e) - { - DialogResult = false; - Reload = true; - this.Close(); - } - - private void OnCancel(object sender, RoutedEventArgs e) - { - DialogResult = false; - this.Close(); - } - } -} diff --git a/VisualRust.Project/Controls/OutputPage.xaml b/VisualRust.Project/Controls/OutputPage.xaml deleted file mode 100644 index da8d70f6..00000000 --- a/VisualRust.Project/Controls/OutputPage.xaml +++ /dev/null @@ -1,281 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Enable unit tests - Enable documentation tests - Enable benchmarks - Enable documentation - Compiler plugin - Build test harness - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/VisualRust.Project/Controls/OutputPage.xaml.cs b/VisualRust.Project/Controls/OutputPage.xaml.cs deleted file mode 100644 index 3f381cdf..00000000 --- a/VisualRust.Project/Controls/OutputPage.xaml.cs +++ /dev/null @@ -1,211 +0,0 @@ -using Microsoft.VisualStudioTools; -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Globalization; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Interop; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Navigation; -using System.Windows.Shapes; -using VisualRust.Cargo; - -namespace VisualRust.Project.Controls -{ - public partial class OutputPage : DockPanel - { - object lastSelectedTarget; - - public OutputPage() - { - InitializeComponent(); - TargetsList.SelectionChanged += DisableUnselect; - } - - void DisableUnselect(object sender, SelectionChangedEventArgs e) - { - if (e.AddedItems.Count == 0 && e.RemovedItems.Count == 1) - { - e.Handled = true; - TargetsList.SelectedItem = lastSelectedTarget; - } - else if (e.AddedItems.Count > 0) - { - lastSelectedTarget = e.AddedItems[0]; - } - } - - void BrowseOpenFileExecuted(object sender, ExecutedRoutedEventArgs args) - { - var tb = (TextBox)args.OriginalSource; - var filter = (args.Parameter as string) ?? "All Files (*.*)|*.*"; - - var manifestPath = ((OutputTargetSectionViewModel)DataContext).ManifestPath; - string chosenPath = Dialogs.BrowseForFileOpen(new WindowInteropHelper(Application.Current.MainWindow).Handle, filter, manifestPath); - if (chosenPath != null) { - string manifestDir = System.IO.Path.GetDirectoryName(manifestPath); - string normalizedPath = CommonUtils.GetRelativeFilePath(manifestDir, chosenPath).Replace("\\", "/"); - tb.SetCurrentValue(TextBox.TextProperty, normalizedPath); - var binding = BindingOperations.GetBindingExpressionBase(tb, TextBox.TextProperty); - if (binding != null) { - binding.UpdateSource(); - } - } - } - } - - public class OutputTargetGroupDescription : GroupDescription - { - public override object GroupNameFromItem(object item, int level, CultureInfo culture) - { - IOutputTargetViewModel vm = item as IOutputTargetViewModel; - if (vm == null) - return null; - if (item is CommandOutputTargetViewModel) - return "Custom targets"; - if (vm.IsAutoGenerated) - return "Default targets"; - else - return "Custom targets"; - } - } - - public class ItemTemplateSelector : DataTemplateSelector - { - public DataTemplate Benchmark { get; set; } - public DataTemplate Binary { get; set; } - public DataTemplate Example { get; set; } - public DataTemplate Library { get; set; } - public DataTemplate Test { get; set; } - public DataTemplate Add { get; set; } - - public override DataTemplate SelectTemplate(object item, DependencyObject container) - { - IOutputTargetViewModel vm = item as IOutputTargetViewModel; - if (vm == null) - return base.SelectTemplate(item, container); - if (item is CommandOutputTargetViewModel) - return Add; - switch (vm.Type) - { - case OutputTargetType.Benchmark: - return Benchmark; - case OutputTargetType.Binary: - return Binary; - case OutputTargetType.Example: - return Example; - case OutputTargetType.Library: - return Library; - case OutputTargetType.Test: - return Test; - } - return base.SelectTemplate(item, container); - } - } - - public class ContentTemplateSelector : DataTemplateSelector - { - public DataTemplate Custom { get; set; } - public DataTemplate Auto { get; set; } - - public override DataTemplate SelectTemplate(object item, DependencyObject container) - { - IOutputTargetViewModel vm = item as IOutputTargetViewModel; - if (vm == null) - return base.SelectTemplate(item, container); - if (vm.IsAutoGenerated) - return Auto; - return Custom; - } - } - - class ItemContainerStyleSelector : StyleSelector - { - public Style Default { get; set; } - public Style Button { get; set; } - - public override Style SelectStyle(object item, DependencyObject container) - { - IOutputTargetViewModel vm = item as IOutputTargetViewModel; - if (item == null) - return base.SelectStyle(item, container); - if (item is CommandOutputTargetViewModel) - return Button; - return Default; - } - } - - class InvisibilityConverter : IValueConverter - { - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - bool invisible = false; - if (value is bool) - invisible = (bool)value; - return invisible ? Visibility.Collapsed : Visibility.Visible; - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - if (value is Visibility) - return (Visibility)value == Visibility.Collapsed; - return false; - } - } - - class CollapseNullConverter : IValueConverter - { - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - return value == null ? Visibility.Collapsed : Visibility.Visible; - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - return DependencyProperty.UnsetValue; - } - } - - class TargetIconConverter : IValueConverter - { - public DrawingGroup Benchmark { get; set; } - public DrawingGroup Binary { get; set; } - public DrawingGroup Example { get; set; } - public DrawingGroup Library { get; set; } - public DrawingGroup Test { get; set; } - - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - if (value is OutputTargetType) - { - switch ((OutputTargetType)value) - { - case OutputTargetType.Benchmark: - return Benchmark; - case OutputTargetType.Binary: - return Binary; - case OutputTargetType.Example: - return Example; - case OutputTargetType.Library: - return Library; - case OutputTargetType.Test: - return Test; - } - } - return DependencyProperty.UnsetValue; - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - return DependencyProperty.UnsetValue; - } - } -} diff --git a/VisualRust.Project/Controls/OutputTargetChange.cs b/VisualRust.Project/Controls/OutputTargetChange.cs deleted file mode 100644 index 233a8a0a..00000000 --- a/VisualRust.Project/Controls/OutputTargetChange.cs +++ /dev/null @@ -1,85 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using VisualRust.Cargo; -using TargetPair = System.Collections.Generic.KeyValuePair; - -namespace VisualRust.Project.Controls -{ - public struct OutputTargetRemoval - { - public UIntPtr Handle { get; private set; } - public string Type { get; private set; } - internal OutputTargetRemoval(OutputTarget vm) : this() - { - Handle = vm.Handle.Value; - Type = vm.Type.ToTypeString(); - } - } - - public class OutputTargetChanges - { - public IReadOnlyList TargetsAdded { get; private set; } - public IReadOnlyList TargetsRemoved { get; private set; } - public IReadOnlyList TargetsChanged { get; private set; } - - public OutputTargetChanges(Manifest manifest, IEnumerable models) - { - List added = new List(); - List changed = new List(); - Dictionary existingTargets = manifest.OutputTargets.ToDictionary(t => t.Handle.Value); - foreach (var vm in models) - { - if (!vm.Handle.HasValue) - { - added.Add(new TargetPair(vm, vm.ToOutputTarget())); - } - else - { - OutputTarget diff = Difference(existingTargets[vm.Handle.Value], vm); - if (diff != null) - changed.Add(new TargetPair(vm, diff)); - existingTargets.Remove(vm.Handle.Value); - } - } - TargetsAdded = added; - TargetsRemoved = existingTargets.Select(kvp => new OutputTargetRemoval(kvp.Value)).ToList(); - TargetsChanged = changed; - } - - OutputTarget Difference(OutputTarget before, OutputTargetViewModel after) - { - Debug.Assert(before.Type == after.Type); - OutputTarget result = new OutputTarget(before.Type) { Handle = before.Handle }; - bool changed = false; - result.Name = CompareString(before.Name, after.RawName, ref changed); - result.Path = CompareString(before.Path, after.RawPath, ref changed); - result.Test = Compare(before.Test, after.RawTest, ref changed); - result.Doctest = Compare(before.Doctest, after.RawDoctest, ref changed); - result.Bench = Compare(before.Bench, after.RawBench, ref changed); - result.Doc = Compare(before.Doc, after.RawDoc, ref changed); - result.Plugin = Compare(before.Plugin, after.RawPlugin, ref changed); - result.Harness = Compare(before.Harness, after.RawHarness, ref changed); - if (!changed) - return null; - return result; - } - - static T? Compare(T? before, T? after, ref bool changed) where T : struct, IEquatable - { - if (before.Equals(after)) - return null; - changed = true; - return after; - } - - static string CompareString(string before, string after, ref bool changed) - { - if (String.Equals(before, after, StringComparison.InvariantCulture)) - return null; - changed = true; - return after; - } - } -} \ No newline at end of file diff --git a/VisualRust.Project/Controls/OutputTargetSectionViewModel.cs b/VisualRust.Project/Controls/OutputTargetSectionViewModel.cs deleted file mode 100644 index 6c605500..00000000 --- a/VisualRust.Project/Controls/OutputTargetSectionViewModel.cs +++ /dev/null @@ -1,137 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Data; -using VisualRust.Cargo; - -namespace VisualRust.Project.Controls -{ - public class OutputTargetSectionViewModel: ViewModelBase, IPropertyPageContext - { - readonly ManifestFile manifest; - // We keep all the targets in a one big collection because CompositeCollection doesn't support grouping - readonly int libraries = 1; - int binaries; - int tests; - int benchmarks; - int examples; - - public string ManifestPath { get { return manifest.Path; } } - - ObservableCollection targets; - public ObservableCollection Targets - { - get { return targets; } - set - { - Set(ref targets, value); - } - } - - IOutputTargetViewModel selectedTarget; - public IOutputTargetViewModel SelectedTarget - { - get { return selectedTarget; } - set - { - Set(ref selectedTarget, value); - } - } - - public event EventHandler DirtyChanged; - - private bool isDirty; - public bool IsDirty - { - get { return isDirty; } - set - { - isDirty = value; - var temp = DirtyChanged; - if(temp != null) - temp(null, null); - } - } - - readonly Func addSelector; - - public OutputTargetSectionViewModel(ManifestFile m, Func addSelector) - { - this.addSelector = addSelector; - this.manifest = m; - targets = new ObservableCollection(); - var lookup = manifest.Manifest.OutputTargets.ToLookup(t => t.Type); - OutputTarget rawLibraryTarget = lookup[OutputTargetType.Library].FirstOrDefault(); - targets.Add(CreateLibraryTarget(rawLibraryTarget)); - binaries = LoadTargets(lookup[OutputTargetType.Binary], () => new BinaryAutoOutputTargetViewModel(manifest.Manifest)); - tests = LoadTargets(lookup[OutputTargetType.Test], () => new TestAutoOutputTargetViewModel(manifest.Manifest)); - benchmarks = LoadTargets(lookup[OutputTargetType.Benchmark], () => new BenchmarkAutoOutputTargetViewModel(manifest.Manifest)); - examples = LoadTargets(lookup[OutputTargetType.Example], () => new ExampleAutoOutputTargetViewModel(manifest.Manifest)); - targets.Add(new CommandOutputTargetViewModel(this.Add)); - SelectedTarget = Targets.Where(f => !(f is CommandOutputTargetViewModel)) - .OrderBy(f => f.Type) - .ThenBy(f => f.Name) - .First(); - } - - public void Add() - { - OutputTargetType? type = addSelector(this); - if(!type.HasValue) - return; - var vm = new OutputTargetViewModel(this.manifest.Manifest, this, new OutputTarget(type.Value)); - IOutputTargetViewModel autoTarget = this.Targets.FirstOrDefault(t => t.IsAutoGenerated && t.Type == type.Value); - if(autoTarget != null) - this.Targets.Remove(autoTarget); - this.Targets.Add(vm); - SelectedTarget = vm; - IsDirty = true; - } - - public void Remove(OutputTargetViewModel target) - { - Targets.Remove(target); - IsDirty = true; - } - - public void Apply() - { - OutputTargetChanges changes = PendingChanges(); - manifest.Apply(changes); - IsDirty = false; - } - - IOutputTargetViewModel CreateLibraryTarget(OutputTarget rawLibraryTarget) - { - if(rawLibraryTarget == null) - return new LibraryAutoOutputTargetViewModel(manifest.Manifest); - return new OutputTargetViewModel(manifest.Manifest, this, rawLibraryTarget); - } - - int LoadTargets(IEnumerable rawTargets, Func ctor) - { - List vms = rawTargets.Select(t => new OutputTargetViewModel(manifest.Manifest, this, t)).ToList(); - if(vms.Count == 0) - { - Targets.Add(ctor()); - return 1; - } - else - { - foreach(OutputTargetViewModel vm in vms) - Targets.Add(vm); - return vms.Count; - } - } - - public OutputTargetChanges PendingChanges() - { - return new OutputTargetChanges( - this.manifest.Manifest, - this.Targets.OfType()); - } - } -} diff --git a/VisualRust.Project/Controls/OutputTargetViewModel.cs b/VisualRust.Project/Controls/OutputTargetViewModel.cs deleted file mode 100644 index 9ff06abd..00000000 --- a/VisualRust.Project/Controls/OutputTargetViewModel.cs +++ /dev/null @@ -1,168 +0,0 @@ -using System; -using System.Runtime.CompilerServices; -using VisualRust.Cargo; - -namespace VisualRust.Project.Controls -{ - public class OutputTargetViewModel : ViewModelBase, IOutputTargetViewModel - { - public OutputTargetType Type { get; private set; } - - readonly Manifest manifest; - - public string TabName { get { return this.Name; } } - - public string DefaultName { get { return manifest.Name; } } - private string name; - public string Name - { - get { return name ?? manifest.Name; } - set - { - if(SetInvalidate(ref name, value)) - { - RaisePropertyChanged("IsNameOverriden"); - RaisePropertyChanged("Path"); - RaisePropertyChanged("TabName"); - } - } - } - public string RawName { get { return name; } } - public bool IsNameOverriden - { - get - { - return name != null; - } - set - { - if(value) - Name = DefaultName; - else - Name = null; - } - } - - - public string DefaultPath { get { return Type.DefaultPath(Name ?? DefaultName); } } - private string path; - public string Path - { - get { return path; } - set - { - if(SetInvalidate(ref path, value)) - RaisePropertyChanged("IsPathOverriden"); - } - } - public string RawPath { get { return path; } } - public bool IsPathOverriden - { - get - { - return path != null; - } - set - { - if(value) - Path = DefaultPath; - else - Path = null; - } - } - - private bool? test; - public bool Test - { - get { return test ?? Type.DefaultTest() ; } - set { SetInvalidate(ref test, value); } - } - public bool? RawTest { get { return test; } } - - private bool? doctest; - public bool Doctest - { - get { return doctest ?? Type.DefaultDoctest(); } - set { SetInvalidate(ref doctest, value); } - } - public bool? RawDoctest { get { return doctest; } } - - private bool? bench; - public bool Bench - { - get { return bench ?? Type.DefaultBench(); } - set { SetInvalidate(ref bench, value); } - } - public bool? RawBench { get { return bench; } } - - private bool? doc; - public bool Doc - { - get { return doc ?? Type.DefaultDoc(); } - set { SetInvalidate(ref doc, value); } - } - public bool? RawDoc { get { return doc; } } - - private bool? plugin; - public bool Plugin - { - get { return plugin ?? Type.DefaultPlugin(); } - set { SetInvalidate(ref plugin, value); } - } - public bool? RawPlugin { get { return plugin; } } - - private bool? harness; - public bool Harness - { - get { return harness ?? Type.DefaultHarness(); } - set { SetInvalidate(ref harness, value); } - } - public bool? RawHarness { get { return harness; } } - - public bool IsAutoGenerated { get { return false; } } - public RelayCommand Remove { get; private set; } - public UIntPtr? Handle { get; internal set; } - - private OutputTargetSectionViewModel parent; - - public OutputTargetViewModel(Manifest m, OutputTargetSectionViewModel parent, OutputTarget t) - { - this.manifest = m; - Type = t.Type; - name = t.Name; - path = t.Path; - test = t.Test; - doctest = t.Doctest; - bench = t.Bench; - doc = t.Doc; - plugin = t.Plugin; - harness = t.Harness; - Handle = t.Handle; - this.parent = parent; - Remove = new RelayCommand(() => parent.Remove(this)); - } - - private bool SetInvalidate(ref T field, T value, [CallerMemberName] string property = null) - { - if(!Set(ref field, value, property)) - return false; - parent.IsDirty = true; - return true; - } - - public OutputTarget ToOutputTarget() - { - return new OutputTarget(this.Type) - { - Name = this.name, - Path = this.path, - Test = this.test, - Doctest = this.doctest, - Bench = this.bench, - Doc = this.doc, - Plugin = this.plugin, - Harness = this.harness - }; - } - } -} \ No newline at end of file diff --git a/VisualRust.Project/Controls/PickTargetOutputTypeWindow.xaml b/VisualRust.Project/Controls/PickTargetOutputTypeWindow.xaml deleted file mode 100644 index ba5aea8c..00000000 --- a/VisualRust.Project/Controls/PickTargetOutputTypeWindow.xaml +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/VisualRust.Project/Controls/PickTargetOutputTypeWindow.xaml.cs b/VisualRust.Project/Controls/PickTargetOutputTypeWindow.xaml.cs deleted file mode 100644 index 890238e1..00000000 --- a/VisualRust.Project/Controls/PickTargetOutputTypeWindow.xaml.cs +++ /dev/null @@ -1,81 +0,0 @@ -using Microsoft.Win32; -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Navigation; -using System.Windows.Shapes; -using VisualRust.Cargo; - -namespace VisualRust.Project.Controls -{ - partial class PickTargetOutputTypeWindow : ChildWindow - { - public IList Targets { get; private set; } - public OutputTargetType SelectedTarget { get; private set; } - - public PickTargetOutputTypeWindow() - { - InitializeComponent(); - } - - public PickTargetOutputTypeWindow(Window owner, OutputTargetSectionViewModel viewModel) : base(owner) - { - InitializeComponent(); - Title = "Select type"; - DataContext = this; - IOutputTargetViewModel libraryVm = viewModel.Targets.First(vm => vm.Type == OutputTargetType.Library); - if(libraryVm.IsAutoGenerated) - { - Targets = new OutputTargetType[] - { - OutputTargetType.Library, - OutputTargetType.Binary, - OutputTargetType.Benchmark, - OutputTargetType.Test, - OutputTargetType.Example - }; - } - else - { - Targets = new OutputTargetType[] - { - OutputTargetType.Binary, - OutputTargetType.Benchmark, - OutputTargetType.Test, - OutputTargetType.Example - }; - } - SelectedTarget = Targets[0]; - } - - public static OutputTargetType? Start(OutputTargetSectionViewModel viewModel) - { - var window = new PickTargetOutputTypeWindow(Application.Current.MainWindow, viewModel); - bool? result = window.ShowDialog(); - if(result == true) - return window.SelectedTarget; - else - return null; - } - - void OnOk(object sender, RoutedEventArgs e) - { - DialogResult = true; - } - - void OnCancel(object sender, RoutedEventArgs e) - { - DialogResult = false; - } - } -} diff --git a/VisualRust.Project/Controls/RelayCommand.cs b/VisualRust.Project/Controls/RelayCommand.cs deleted file mode 100644 index e1d81159..00000000 --- a/VisualRust.Project/Controls/RelayCommand.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using System.Windows.Input; - -namespace VisualRust.Project.Controls -{ - public class RelayCommand : ICommand - { - Action action; - - public RelayCommand(Action action) - { - this.action = action; - } - - public event EventHandler CanExecuteChanged - { - add { } - remove { } - } - - public bool CanExecute(object parameter) - { - return true; - } - - public void Execute(object parameter) - { - action(); - } - } -} \ No newline at end of file diff --git a/VisualRust.Project/Controls/Shared.xaml b/VisualRust.Project/Controls/Shared.xaml deleted file mode 100644 index 3e2058d3..00000000 --- a/VisualRust.Project/Controls/Shared.xaml +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/VisualRust.Project/Controls/SideContentGrid.cs b/VisualRust.Project/Controls/SideContentGrid.cs deleted file mode 100644 index e7de5316..00000000 --- a/VisualRust.Project/Controls/SideContentGrid.cs +++ /dev/null @@ -1,137 +0,0 @@ -using System; -using System.Linq; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Media; - -namespace VisualRust.Project.Controls -{ - class SideContentGrid : Panel - { - class LayoutProxy : UIElement - { - public UIElement Element { get; set; } - - public LayoutProxy(UIElement elm) - { - Element = elm; - } - - protected override Size MeasureCore(Size availableSize) - { - Element.Measure(availableSize); - return Element.DesiredSize; - } - - protected override void ArrangeCore(Rect finalRect) - { - Element.Arrange(finalRect); - } - } - - public static readonly DependencyProperty SideContentTemplateProperty = - DependencyProperty.Register("SideContentTemplate", typeof(DataTemplate), typeof(SideContentGrid)); - public DataTemplate SideContentTemplate - { - get { return this.GetValue(SideContentTemplateProperty) as DataTemplate; } - set { this.SetValue(SideContentTemplateProperty, value); } - } - - private Grid innerGrid; - private FrameworkElement[] sideContents = new FrameworkElement[0]; - private bool measuredOnce; - private bool ignoreVisualChange; - - protected override void OnInitialized(EventArgs e) - { - base.OnInitialized(e); - InitializeProxyLayout(); - } - - private void InitializeProxyLayout() - { - foreach (UIElement uie in sideContents) - this.RemoveVisualChild(uie); - innerGrid = new Grid(); - sideContents = new FrameworkElement[InternalChildren.Count]; - innerGrid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Star) }); - innerGrid.ColumnDefinitions.Add(new ColumnDefinition() { Width = GridLength.Auto }); - int i = 0; - foreach (UIElement uie in InternalChildren.Cast().Where(uie => uie != null)) - { - OnVisualChildAdded(i, uie); - i++; - } - } - - private void OnVisualChildAdded(int i, UIElement elm) - { - innerGrid.RowDefinitions.Add(new RowDefinition()); - FrameworkElement sideChild = AddChild(elm, i); - sideContents[i] = sideChild; - } - - protected override Visual GetVisualChild(int index) - { - return ((LayoutProxy)innerGrid.Children[index]).Element; - } - - FrameworkElement AddChild(UIElement elm, int i) - { - var proxy = new LayoutProxy(elm); - Grid.SetColumnSpan(proxy, Grid.GetColumnSpan(elm)); - Grid.SetRow(proxy, i); - Grid.SetColumn(proxy, 0); - var sideContentPresenter = new ContentControl { ContentTemplate = SideContentTemplate }; - var binding = new Binding("DataContext") { Source = elm }; - sideContentPresenter.SetBinding(ContentControl.ContentProperty, binding); - var sideContentWrapper = new LayoutProxy(sideContentPresenter); - Grid.SetRow(sideContentWrapper, i); - Grid.SetColumn(sideContentWrapper, 1); - this.AddVisualChild(sideContentPresenter); - innerGrid.Children.Add(proxy); - innerGrid.Children.Add(sideContentWrapper); - return sideContentPresenter; - } - - protected override Size MeasureOverride(Size availableSize) - { - innerGrid.InvalidateMeasure(); - innerGrid.Measure(availableSize); - this.measuredOnce = true; - return innerGrid.DesiredSize; - } - - protected override Size ArrangeOverride(Size finalSize) - { - innerGrid.InvalidateArrange(); - innerGrid.Arrange(new Rect(finalSize)); - return finalSize; - } - - protected override int VisualChildrenCount - { - get - { - // Otherwise UIElements from this.Children get instantiated, which really confuses WPF - if (!measuredOnce) - return 0; - return innerGrid.Children.Count; - } - } - - protected override void OnVisualChildrenChanged(DependencyObject visualAdded, DependencyObject visualRemoved) - { - base.OnVisualChildrenChanged(visualAdded, visualRemoved); - if (measuredOnce && !ignoreVisualChange) - { - ignoreVisualChange = true; - // This could be smarter but nobody is going to have more then a dozen of target outputs - InitializeProxyLayout(); - ignoreVisualChange = false; - } - } - } - -} diff --git a/VisualRust.Project/Controls/TestAutoOutputTargetViewModel.cs b/VisualRust.Project/Controls/TestAutoOutputTargetViewModel.cs deleted file mode 100644 index 08ab0a71..00000000 --- a/VisualRust.Project/Controls/TestAutoOutputTargetViewModel.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using VisualRust.Cargo; - -namespace VisualRust.Project.Controls -{ - internal class TestAutoOutputTargetViewModel : AutoOutputTargetViewModel - { - public TestAutoOutputTargetViewModel(Manifest m) : base(m) - { - } - - public override OutputTargetType Type { get { return OutputTargetType.Test; } } - public override string TabName { get { return "Autodetect tests"; } } - public override string Name { get { return AutoDetect; } } - public override string Path { get { return @"tests\*.rs"; } } - public override bool Bench { get { return false; } } - } -} \ No newline at end of file diff --git a/VisualRust.Project/Controls/ViewModelBase.cs b/VisualRust.Project/Controls/ViewModelBase.cs deleted file mode 100644 index 81a87bc0..00000000 --- a/VisualRust.Project/Controls/ViewModelBase.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System.Collections.Generic; -using System.ComponentModel; -using System.Runtime.CompilerServices; - -namespace VisualRust -{ - public class ViewModelBase : INotifyPropertyChanged - { - public event PropertyChangedEventHandler PropertyChanged; - - protected bool Set(ref T field, T value, [CallerMemberName] string property = null) - { - if (EqualityComparer.Default.Equals(field, value)) - { - return false; - } - var oldValue = field; - field = value; - RaisePropertyChanged(property); - return true; - } - - protected void RaisePropertyChanged(string property) - { - var handler = PropertyChanged; - if (handler != null) - { - handler(this, new PropertyChangedEventArgs(property)); - } - } - } -} \ No newline at end of file diff --git a/VisualRust.Project/EnvironmentPath.cs b/VisualRust.Project/EnvironmentPath.cs deleted file mode 100644 index 8ee3cd78..00000000 --- a/VisualRust.Project/EnvironmentPath.cs +++ /dev/null @@ -1,120 +0,0 @@ -using NUnit.Framework; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace VisualRust.Project -{ - static class EnvironmentPath - { - public static string FindExePath(string name) - { - string extensionsVariable = Environment.GetEnvironmentVariable("PATHEXT") ?? ".COM;.EXE"; - string[] extensions = extensionsVariable.Split(new [] {";"}, StringSplitOptions.RemoveEmptyEntries); - string[] fileNames = extensions.Where(s => s.StartsWith(".")).Select(e => name + e).ToArray(); - foreach(string path in SplitPaths(Environment.GetEnvironmentVariable("PATH") ?? "")) - { - foreach(string file in fileNames) - { - string fullPath = Path.Combine(path, file); - if(File.Exists(fullPath)) - return fullPath; - } - } - return null; - } - - private static List SplitPaths(string path) - { - int i = 0; - List result = new List(); - while(i < path.Length) - { - int start = i; - int end; - if(path[start] == '"') - { - start++; - end = path.IndexOf('"', start); - if (end == -1) - { - end = path.Length; - i = path.Length; - } - else - { - int semi = path.IndexOf(';', end); - if(semi == -1) - i = path.Length; - else - i = semi + 1; - } - } - else - { - end = path.IndexOf(';', start); - if (end == -1) - { - end = path.Length; - i = path.Length; - } - else - { - i = end + 1; - } - } - result.Add(path.Substring(start, end - start)); - } - return result; - } - - #if TEST - [TestFixture] - private class Test - { - [Test] - public void SplitPathsPlain() - { - CollectionAssert.AreEquivalent( - new String[] { @"D:\dev\Rust\bin", @"D:\dev\LLVM\bin" }, - SplitPaths(@"D:\dev\LLVM\bin;D:\dev\Rust\bin")); - } - - [Test] - public void SplitPathsSingleChars() - { - CollectionAssert.AreEquivalent( - new String[] { "C", "D" }, - SplitPaths("C;D")); - } - - [Test] - public void SplitPathsExtraSemicolon() - { - CollectionAssert.AreEquivalent( - new String[] { @"D:\dev\Rust\bin", @"D:\dev\LLVM\bin" }, - SplitPaths(@"D:\dev\LLVM\bin;D:\dev\Rust\bin;")); - } - - [Test] - public void SplitPathsQuoted() - { - CollectionAssert.AreEquivalent( - new String[] { @"D:\dev\LLVM\bin", @"C:\main() {printf('%d', 42);}" }, - SplitPaths(@"D:\dev\LLVM\bin;""C:\main() {printf('%d', 42);}""")); - } - - [Test] - public void SplitPathsQuotedExtraSemicolon() - { - CollectionAssert.AreEquivalent( - new String[] { @"D:\dev\LLVM\bin", @"C:\main() {printf('%d', 42);}" }, - SplitPaths(@"D:\dev\LLVM\bin;""C:\main() {printf('%d', 42);}"";")); - } - } - #endif - } -} diff --git a/VisualRust.Project/FileNodeProperties.cs b/VisualRust.Project/FileNodeProperties.cs deleted file mode 100644 index f79369e0..00000000 --- a/VisualRust.Project/FileNodeProperties.cs +++ /dev/null @@ -1,128 +0,0 @@ -using Microsoft.VisualStudioTools.Project; -using System; -using System.ComponentModel; -using System.Globalization; -using System.IO; -using System.Runtime.InteropServices; - -namespace VisualRust.Project -{ - [ComVisible(true)] - abstract public class FileNodePropertiesBase : NodeProperties - { - [SRCategoryAttribute(SR.Misc)] - [SRDisplayName(SR.FileName)] - [SRDescriptionAttribute(SR.FileNameDescription)] - public string FileName - { - get - { - return this.HierarchyNode.Caption; - } - set - { - this.HierarchyNode.SetEditLabel(value); - } - } - - [SRCategoryAttribute(SR.Misc)] - [SRDisplayName(SR.FullPath)] - [SRDescriptionAttribute(SR.FullPathDescription)] - public string FullPath - { - get - { - return this.HierarchyNode.Url; - } - } - - [Browsable(false)] - public string URL - { - get { return this.HierarchyNode.Url; } - } - - [Browsable(false)] - public string Extension - { - get - { - return Path.GetExtension(this.HierarchyNode.Caption); - } - } - - internal FileNodePropertiesBase(HierarchyNode node) - : base(node) - { } - - public override string GetClassName() - { - return SR.GetString(SR.FileProperties, CultureInfo.CurrentUICulture); - } - } - - [ComVisible(true)] - public class FileNodeProperties : FileNodePropertiesBase - { - [CategoryAttribute("Advanced")] - [ResourceDisplayName("TrackModules")] - [ResourceDescription("TrackModulesDescription")] - [DefaultValue(true)] - public bool TrackModules - { - get { return ((TrackedFileNode)this.Node).GetModuleTracking(); } - set { ((TrackedFileNode)this.Node).SetModuleTracking(value); } - } - - internal FileNodeProperties(TrackedFileNode node) - : base(node) - { } - - public override string GetClassName() - { - return "File Properties"; - } - } - - [ComVisible(true)] - public class ReferencedFileNodeProperties : FileNodePropertiesBase - { - [CategoryAttribute("Advanced")] - [ResourceDisplayName("TrackModules")] - [ResourceDescription("TrackModulesReferencedDescription")] - public bool TrackModules - { - get { return true; } - } - - internal ReferencedFileNodeProperties(UntrackedFileNode node) - : base(node) - { } - - public override string GetClassName() - { - return "File Properties"; - } - } - - [ComVisible(true)] - public class ExcludedFileNodeProperties : FileNodePropertiesBase - { - [CategoryAttribute("Advanced")] - [ResourceDisplayName("TrackModules")] - [ResourceDescription("TrackModulesReferencedDescription")] - public bool TrackModules - { - get { return false; } - } - - internal ExcludedFileNodeProperties(TrackedFileNode node) - : base(node) - { } - - public override string GetClassName() - { - return "File Properties"; - } - } -} diff --git a/VisualRust.Project/FolderNode.cs b/VisualRust.Project/FolderNode.cs deleted file mode 100644 index f5d23afa..00000000 --- a/VisualRust.Project/FolderNode.cs +++ /dev/null @@ -1,77 +0,0 @@ -using Microsoft.VisualStudioTools.Project; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using OleConstants = Microsoft.VisualStudio.OLE.Interop.Constants; -using VsCommands = Microsoft.VisualStudio.VSConstants.VSStd97CmdID; -using VsCommands2K = Microsoft.VisualStudio.VSConstants.VSStd2KCmdID; - -namespace VisualRust.Project -{ - class RustFolderNode : CommonFolderNode - { - private RustProjectNode rustProjectNode; - private ProjectElement element; - - public RustFolderNode(RustProjectNode rustProjectNode, ProjectElement element) - : base(rustProjectNode, element) - { } - public bool IsEntryPoint { get; set; } - - // Disable rename - public override string GetEditLabel() - { - if (IsEntryPoint) - return null; - else - return base.GetEditLabel(); - } - - public override int SetEditLabel(string label) - { - if (IsEntryPoint) - throw new InvalidOperationException(Properties.Resources.ErrorRenameEntrypoint); - else - return base.SetEditLabel(label); - } - - // Disable deletion - internal override bool CanDeleteItem(Microsoft.VisualStudio.Shell.Interop.__VSDELETEITEMOPERATION deleteOperation) - { - if (IsEntryPoint) - return false; - else - return base.CanDeleteItem(deleteOperation); - } - - internal override int QueryStatusOnNode(Guid cmdGroup, uint cmd, IntPtr pCmdText, ref QueryStatusResult result) - { - if (IsEntryPoint) - { - if (cmdGroup == Microsoft.VisualStudioTools.Project.VsMenus.guidStandardCommandSet97 - && (VsCommands)cmd == VsCommands.Rename - || (VsCommands)cmd == VsCommands.Cut) - { - result |= QueryStatusResult.NOTSUPPORTED; - return (int)OleConstants.OLECMDERR_E_NOTSUPPORTED; - } - if (cmdGroup == Microsoft.VisualStudioTools.Project.VsMenus.guidStandardCommandSet2K - && (VsCommands2K)cmd == VsCommands2K.EXCLUDEFROMPROJECT) - { - result |= QueryStatusResult.NOTSUPPORTED; - return (int)OleConstants.OLECMDERR_E_NOTSUPPORTED; - } - } - if (cmdGroup == Microsoft.VisualStudioTools.Project.VsMenus.guidStandardCommandSet2K - && (VsCommands2K)cmd == VsCommands2K.INCLUDEINPROJECT - && ItemNode.ItemTypeName == null) - { - result |= QueryStatusResult.NOTSUPPORTED; - return (int)OleConstants.OLECMDERR_E_NOTSUPPORTED; - } - return base.QueryStatusOnNode(cmdGroup, cmd, pCmdText, ref result); - } - } -} diff --git a/VisualRust.Project/Forms/ApplicationPropertyControl.cs b/VisualRust.Project/Forms/ApplicationPropertyControl.cs deleted file mode 100644 index 3cb740f0..00000000 --- a/VisualRust.Project/Forms/ApplicationPropertyControl.cs +++ /dev/null @@ -1,127 +0,0 @@ -using Microsoft.VisualStudioTools.Project; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows.Forms; -using VisualRust.Shared; - -namespace VisualRust.Project.Forms -{ - class ApplicationPropertyControl : UserControl - { - private Action isDirty; - private Configuration.Application config; - private Configuration.Application originalConfig; - private TableLayoutPanel mainPanel; - TextBox crateBox; - ComboBox typeComboBox; - GroupBox libraryGroup; - CheckBox buildRlib; - CheckBox buildStaticlib; - CheckBox buildDylib; - - public ApplicationPropertyControl(Action isDirtyAction) - { - isDirty = isDirtyAction; - this.Font = System.Drawing.SystemFonts.MessageBoxFont; - mainPanel = new TableLayoutPanel - { - AutoSize = true, - Width = 0, - Height = 0, - ColumnCount = 1, - }; - mainPanel.Controls.Add(Utils.CreateLabel("Crate name:", Utils.Paddding())); - crateBox = Utils.CreateTextBox("", Utils.Paddding()); - crateBox.Width = 294; - mainPanel.Controls.Add(crateBox); - mainPanel.Controls.Add(Utils.CreateLabel("Output type:", Utils.Paddding())); - typeComboBox = Utils.CreateComboBox( - new[] - { - BuildOutputType.Application.ToDisplayString(), - BuildOutputType.Library.ToDisplayString() - }, - Utils.Paddding()); - typeComboBox.Anchor = AnchorStyles.Left | AnchorStyles.Right; - mainPanel.Controls.Add(typeComboBox); - AddLibraryTypeBox(); - this.Controls.Add(mainPanel); - } - - private void AddLibraryTypeBox() - { - libraryGroup = new GroupBox() - { - Anchor = AnchorStyles.Left | AnchorStyles.Right, - AutoSize = true, - Margin = Utils.Paddding(), - Text = "Library Type" - }; - TableLayoutPanel panel = new TableLayoutPanel() - { - Dock = DockStyle.Fill, - AutoSize = true, - Margin = new Padding(), - RowCount = 3, - ColumnCount = 1, - }; - panel.RowStyles.Add(new RowStyle(SizeType.AutoSize)); - panel.RowStyles.Add(new RowStyle(SizeType.AutoSize)); - panel.RowStyles.Add(new RowStyle(SizeType.AutoSize)); - Padding topMargin = Utils.Paddding(); - topMargin.Top +=7; - topMargin.Left +=7; - buildDylib = Utils.CreateCheckBox("Build dynamic library", topMargin); - panel.Controls.Add(buildDylib); - Padding midMargin = Utils.Paddding(); - midMargin.Left +=7; - buildStaticlib = Utils.CreateCheckBox("Build static library", midMargin); - panel.Controls.Add(buildStaticlib); - Padding botMargin = Utils.Paddding(); - botMargin.Left +=7; - botMargin.Bottom +=7; - buildRlib = Utils.CreateCheckBox("Build Rust library", botMargin); - panel.Controls.Add(buildRlib); - libraryGroup.Controls.Add(panel); - mainPanel.Controls.Add(libraryGroup); - } - - public void LoadSettings(CommonProjectNode node) - { - originalConfig = Configuration.Application.LoadFrom(node); - config = originalConfig.Clone(); - crateBox.Text = config.CrateName; - crateBox.TextChanged += (src, arg) => config.CrateName = crateBox.Text; - typeComboBox.SelectedIndex = (int)config.OutputType; - libraryGroup.Enabled = config.OutputType == BuildOutputType.Library; - typeComboBox.SelectedIndexChanged += (src, arg) => - { - config.OutputType = (BuildOutputType)typeComboBox.SelectedIndex; - libraryGroup.Enabled = config.OutputType == BuildOutputType.Library; - }; - buildDylib.Checked = config.BuildDylib; - buildDylib.CheckedChanged += (src, arg) => config.BuildDylib = buildDylib.Checked; - buildStaticlib.Checked = config.BuildStaticlib; - buildStaticlib.CheckedChanged += (src, arg) => config.BuildStaticlib = buildStaticlib.Checked; - buildRlib.Checked = config.BuildRlib; - buildRlib.CheckedChanged += (src, arg) => config.BuildRlib = buildRlib.Checked; - MakeSureAtLeastOneLibraryTypeIsSelected(); - config.Changed += (src, arg) => isDirty(config.HasChangedFrom(originalConfig)); - } - - private void MakeSureAtLeastOneLibraryTypeIsSelected() - { - if (config.OutputType == BuildOutputType.Library && !config.BuildDylib && !config.BuildRlib && !config.BuildStaticlib) - buildRlib.Checked = true; - } - - public void ApplyConfig(CommonProjectNode node) - { - MakeSureAtLeastOneLibraryTypeIsSelected(); - config.SaveTo(node); - originalConfig = config.Clone(); - } - } -} diff --git a/VisualRust.Project/Forms/BuildPropertyControl.cs b/VisualRust.Project/Forms/BuildPropertyControl.cs deleted file mode 100644 index 63c7db6b..00000000 --- a/VisualRust.Project/Forms/BuildPropertyControl.cs +++ /dev/null @@ -1,114 +0,0 @@ -using Microsoft.VisualStudioTools.Project; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Forms; -using VisualRust.Shared; - -namespace VisualRust.Project.Forms -{ - class BuildPropertyControl : UserControl - { - private Action isDirty; - private Configuration.Build originalConfig; - private Configuration.Build config; - private string[] knownTargets; - private TableLayoutPanel mainPanel; - private ComboBox customTargetBox; - private ComboBox optimizationBox; - private CheckBox lto; - private CheckBox emitDebug; - - public BuildPropertyControl(Action isDirtyAction) - { - isDirty = isDirtyAction; - knownTargets = new string[] { Shared.Environment.DefaultTarget } - .Union(Shared.Environment.FindInstalledTargets().Select(tt => tt.ToString())) - .ToArray(); - // This looks nonsensical but is required to avoid getting "Microsoft Sans Serif, 8.25pt" - // http://stackoverflow.com/questions/297701/default-font-for-windows-forms-application - this.Font = System.Drawing.SystemFonts.MessageBoxFont; - mainPanel = new TableLayoutPanel - { - AutoSize = true, - Width = 500, - Height = 0, - ColumnCount = 2, - }; - int generalSectionRows = AddPlatformTargetSection(mainPanel, 0); - AddOutputSection(mainPanel, generalSectionRows); - this.Controls.Add(mainPanel); - } - - private int AddPlatformTargetSection(TableLayoutPanel mainPanel, int startingRow) - { - TableLayoutPanel platformHeader = Utils.CreateHeaderLabel("Target"); - mainPanel.Controls.Add(platformHeader); - mainPanel.SetColumnSpan(platformHeader, 2); - mainPanel.Controls.Add(Utils.CreateLabel("Platform target:", Utils.Paddding().Left().Top().Bottom())); - customTargetBox = Utils.CreateComboBox(knownTargets, Utils.Paddding().Top().Bottom()); - customTargetBox.DropDownStyle = ComboBoxStyle.DropDown; - customTargetBox.Width =(int)(customTargetBox.Width * 1.5); - mainPanel.Controls.Add(customTargetBox); - return startingRow + 2; - } - - private int AddOutputSection(TableLayoutPanel mainPanel, int startingRow) - { - TableLayoutPanel outputHeader = Utils.CreateHeaderLabel("Compilation"); - mainPanel.Controls.Add(outputHeader); - mainPanel.SetColumnSpan(outputHeader, 2); - mainPanel.Controls.Add(Utils.CreateLabel("Optimization level:", Utils.Paddding().Left().Top())); - optimizationBox = Utils.CreateComboBox( - new string[] - { - OptimizationLevel.O0.ToDisplayString(), - OptimizationLevel.O1.ToDisplayString(), - OptimizationLevel.O2.ToDisplayString(), - OptimizationLevel.O3.ToDisplayString(), - }, - Utils.Paddding().Top()); - mainPanel.Controls.Add(optimizationBox); - lto = Utils.CreateCheckBox("Apply link-time optimization", Utils.Paddding().Left()); - mainPanel.Controls.Add(lto); - mainPanel.SetColumnSpan(lto, 2); - emitDebug = Utils.CreateCheckBox("Emit debug info", Utils.Paddding().Left().Bottom()); - mainPanel.Controls.Add(emitDebug); - mainPanel.SetColumnSpan(emitDebug, 2); - return startingRow + 4; - } - - public void LoadSettings(ProjectConfig[] configs) - { - originalConfig = Configuration.Build.LoadFrom(configs); - config = originalConfig.Clone(); - customTargetBox.Text = config.PlatformTarget; - customTargetBox.TextChanged += (src,arg) => config.PlatformTarget = customTargetBox.Text; - if(config.OptimizationLevel.HasValue) - optimizationBox.SelectedIndex = (int)config.OptimizationLevel.Value; - else - optimizationBox.SelectedItem = null; - optimizationBox.SelectedIndexChanged += (src,arg) => config.OptimizationLevel = (OptimizationLevel)optimizationBox.SelectedIndex; - lto.CheckState = ToCheckState(config.LTO); - lto.CheckedChanged += (src,arg) => config.LTO = lto.Checked; - emitDebug.CheckState = ToCheckState(config.EmitDebug); - emitDebug.CheckedChanged += (src,arg) => config.EmitDebug = emitDebug.Checked; - config.Changed += (src, arg) => isDirty(config.HasChangedFrom(originalConfig)); - } - - private static CheckState ToCheckState(bool? v) - { - if(!v.HasValue) - return CheckState.Indeterminate; - return v.Value ? CheckState.Checked : CheckState.Unchecked; - } - - public void ApplyConfig(ProjectConfig[] configs) - { - config.SaveTo(configs); - originalConfig = config.Clone(); - } - } -} diff --git a/VisualRust.Project/Forms/DebugPropertyControl.Designer.cs b/VisualRust.Project/Forms/DebugPropertyControl.Designer.cs deleted file mode 100644 index 0dfaef96..00000000 --- a/VisualRust.Project/Forms/DebugPropertyControl.Designer.cs +++ /dev/null @@ -1,249 +0,0 @@ -namespace VisualRust.Project.Forms -{ - partial class DebugPropertyControl - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Component Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - this.components = new System.ComponentModel.Container(); - this.label1 = new System.Windows.Forms.Label(); - this.commandLineArgs = new System.Windows.Forms.TextBox(); - this.label2 = new System.Windows.Forms.Label(); - this.workDir = new System.Windows.Forms.TextBox(); - this.browseWorkDir = new System.Windows.Forms.Button(); - this.radioButton1 = new System.Windows.Forms.RadioButton(); - this.radioButton2 = new System.Windows.Forms.RadioButton(); - this.externalProg = new System.Windows.Forms.TextBox(); - this.browseProg = new System.Windows.Forms.Button(); - this.startActionGrp = new System.Windows.Forms.Panel(); - this.label4 = new System.Windows.Forms.Label(); - this.debuggerScript = new System.Windows.Forms.TextBox(); - this.label3 = new System.Windows.Forms.Label(); - this.gdbReference = new System.Windows.Forms.LinkLabel(); - this.toolTip = new System.Windows.Forms.ToolTip(this.components); - this.startActionGrp.SuspendLayout(); - this.SuspendLayout(); - // - // label1 - // - this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(3, 91); - this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(149, 15); - this.label1.TabIndex = 1; - this.label1.Text = "Command line arguments:"; - // - // commandLineArgs - // - this.commandLineArgs.AllowDrop = true; - this.commandLineArgs.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.commandLineArgs.Location = new System.Drawing.Point(161, 91); - this.commandLineArgs.Multiline = true; - this.commandLineArgs.Name = "commandLineArgs"; - this.commandLineArgs.Size = new System.Drawing.Size(458, 41); - this.commandLineArgs.TabIndex = 2; - this.commandLineArgs.KeyDown += new System.Windows.Forms.KeyEventHandler(this.commandLineArgs_KeyDown); - // - // label2 - // - this.label2.AutoSize = true; - this.label2.Location = new System.Drawing.Point(3, 146); - this.label2.Name = "label2"; - this.label2.Size = new System.Drawing.Size(105, 15); - this.label2.TabIndex = 3; - this.label2.Text = "Working directory:"; - // - // workDir - // - this.workDir.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.workDir.AutoCompleteMode = System.Windows.Forms.AutoCompleteMode.Suggest; - this.workDir.AutoCompleteSource = System.Windows.Forms.AutoCompleteSource.FileSystemDirectories; - this.workDir.Location = new System.Drawing.Point(161, 143); - this.workDir.Name = "workDir"; - this.workDir.Size = new System.Drawing.Size(458, 23); - this.workDir.TabIndex = 4; - // - // browseWorkDir - // - this.browseWorkDir.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.browseWorkDir.Location = new System.Drawing.Point(625, 144); - this.browseWorkDir.Margin = new System.Windows.Forms.Padding(3, 2, 3, 4); - this.browseWorkDir.Name = "browseWorkDir"; - this.browseWorkDir.Size = new System.Drawing.Size(26, 22); - this.browseWorkDir.TabIndex = 5; - this.browseWorkDir.Text = "..."; - this.browseWorkDir.UseVisualStyleBackColor = true; - this.browseWorkDir.Click += new System.EventHandler(this.browseWorkDir_Click); - // - // radioButton1 - // - this.radioButton1.AutoSize = true; - this.radioButton1.Checked = true; - this.radioButton1.Location = new System.Drawing.Point(6, 22); - this.radioButton1.Name = "radioButton1"; - this.radioButton1.Size = new System.Drawing.Size(111, 19); - this.radioButton1.TabIndex = 1; - this.radioButton1.TabStop = true; - this.radioButton1.Text = "Start this project"; - this.radioButton1.UseVisualStyleBackColor = true; - // - // radioButton2 - // - this.radioButton2.AutoSize = true; - this.radioButton2.Location = new System.Drawing.Point(6, 48); - this.radioButton2.Name = "radioButton2"; - this.radioButton2.Size = new System.Drawing.Size(145, 19); - this.radioButton2.TabIndex = 2; - this.radioButton2.Text = "Start external program:"; - this.radioButton2.UseVisualStyleBackColor = true; - // - // externalProg - // - this.externalProg.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.externalProg.AutoCompleteMode = System.Windows.Forms.AutoCompleteMode.Suggest; - this.externalProg.AutoCompleteSource = System.Windows.Forms.AutoCompleteSource.FileSystem; - this.externalProg.Enabled = false; - this.externalProg.Location = new System.Drawing.Point(158, 48); - this.externalProg.Name = "externalProg"; - this.externalProg.Size = new System.Drawing.Size(458, 23); - this.externalProg.TabIndex = 3; - // - // browseProg - // - this.browseProg.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.browseProg.Enabled = false; - this.browseProg.Location = new System.Drawing.Point(621, 49); - this.browseProg.Margin = new System.Windows.Forms.Padding(3, 2, 3, 4); - this.browseProg.Name = "browseProg"; - this.browseProg.Size = new System.Drawing.Size(26, 22); - this.browseProg.TabIndex = 4; - this.browseProg.Text = "..."; - this.browseProg.UseVisualStyleBackColor = true; - this.browseProg.Click += new System.EventHandler(this.browseProg_Click); - // - // startActionGrp - // - this.startActionGrp.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.startActionGrp.Controls.Add(this.label4); - this.startActionGrp.Controls.Add(this.radioButton1); - this.startActionGrp.Controls.Add(this.externalProg); - this.startActionGrp.Controls.Add(this.browseProg); - this.startActionGrp.Controls.Add(this.radioButton2); - this.startActionGrp.Location = new System.Drawing.Point(3, 3); - this.startActionGrp.Name = "startActionGrp"; - this.startActionGrp.Size = new System.Drawing.Size(666, 80); - this.startActionGrp.TabIndex = 0; - this.startActionGrp.Text = "Start action"; - // - // label4 - // - this.label4.AutoSize = true; - this.label4.Location = new System.Drawing.Point(0, 0); - this.label4.Name = "label4"; - this.label4.Size = new System.Drawing.Size(70, 15); - this.label4.TabIndex = 0; - this.label4.Text = "Start action:"; - // - // debuggerScript - // - this.debuggerScript.AcceptsReturn = true; - this.debuggerScript.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.debuggerScript.Location = new System.Drawing.Point(161, 182); - this.debuggerScript.Multiline = true; - this.debuggerScript.Name = "debuggerScript"; - this.debuggerScript.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; - this.debuggerScript.Size = new System.Drawing.Size(458, 120); - this.debuggerScript.TabIndex = 7; - this.toolTip.SetToolTip(this.debuggerScript, "e.g. \'set env FOO=1\'"); - // - // label3 - // - this.label3.AutoSize = true; - this.label3.Location = new System.Drawing.Point(3, 185); - this.label3.Name = "label3"; - this.label3.Size = new System.Drawing.Size(134, 15); - this.label3.TabIndex = 6; - this.label3.Text = "Debugger startup script:"; - // - // gdbReference - // - this.gdbReference.AutoSize = true; - this.gdbReference.Location = new System.Drawing.Point(6, 210); - this.gdbReference.Name = "gdbReference"; - this.gdbReference.Size = new System.Drawing.Size(82, 15); - this.gdbReference.TabIndex = 8; - this.gdbReference.TabStop = true; - this.gdbReference.Text = "GDB reference"; - this.toolTip.SetToolTip(this.gdbReference, "Hold Ctrl to launch in external browser"); - this.gdbReference.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.gdbReference_LinkClicked); - // - // DebugPropertyControl - // - this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.AutoScroll = true; - this.Controls.Add(this.gdbReference); - this.Controls.Add(this.label3); - this.Controls.Add(this.debuggerScript); - this.Controls.Add(this.startActionGrp); - this.Controls.Add(this.browseWorkDir); - this.Controls.Add(this.workDir); - this.Controls.Add(this.label2); - this.Controls.Add(this.commandLineArgs); - this.Controls.Add(this.label1); - this.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.Name = "DebugPropertyControl"; - this.Size = new System.Drawing.Size(669, 322); - this.startActionGrp.ResumeLayout(false); - this.startActionGrp.PerformLayout(); - this.ResumeLayout(false); - this.PerformLayout(); - - } - - #endregion - private System.Windows.Forms.TextBox commandLineArgs; - private System.Windows.Forms.TextBox workDir; - private System.Windows.Forms.Button browseWorkDir; - private System.Windows.Forms.Label label1; - private System.Windows.Forms.Label label2; - private System.Windows.Forms.RadioButton radioButton1; - private System.Windows.Forms.RadioButton radioButton2; - private System.Windows.Forms.TextBox externalProg; - private System.Windows.Forms.Button browseProg; - private System.Windows.Forms.Panel startActionGrp; - private System.Windows.Forms.Label label4; - private System.Windows.Forms.TextBox debuggerScript; - private System.Windows.Forms.Label label3; - private System.Windows.Forms.LinkLabel gdbReference; - private System.Windows.Forms.ToolTip toolTip; - } -} diff --git a/VisualRust.Project/Forms/DebugPropertyControl.cs b/VisualRust.Project/Forms/DebugPropertyControl.cs deleted file mode 100644 index ea94a8f3..00000000 --- a/VisualRust.Project/Forms/DebugPropertyControl.cs +++ /dev/null @@ -1,115 +0,0 @@ -using System; -using System.Diagnostics; -using System.IO; -using System.Windows.Forms; -using Microsoft.VisualStudio.Shell; -using Microsoft.VisualStudio.Shell.Interop; -using Microsoft.VisualStudioTools.Project; -using VisualRust.Project.Configuration; - -namespace VisualRust.Project.Forms -{ - partial class DebugPropertyControl : UserControl - { - private Action isDirty; - private Configuration.Debug originalConfig; - private Configuration.Debug config; - - public DebugPropertyControl(Action isDirtyAction) - { - isDirty = isDirtyAction; - this.Font = System.Drawing.SystemFonts.MessageBoxFont; - InitializeComponent(); - } - - public void LoadSettings(MsBuildConfiguration[] configs) - { - originalConfig = Configuration.Debug.LoadFrom(configs); - config = originalConfig.Clone(); - - radioButton1.CheckedChanged += (src, arg) => { - if (radioButton1.Checked) - config.StartAction = Configuration.StartAction.Project; - else - config.StartAction = Configuration.StartAction.Program; - externalProg.Enabled = !radioButton1.Checked; - browseProg.Enabled = !radioButton1.Checked; - }; - radioButton1.Checked = config.StartAction == Configuration.StartAction.Project; - radioButton2.Checked = !radioButton1.Checked; - - externalProg.Text = config.ExternalProgram; - externalProg.TextChanged += (src, arg) => config.ExternalProgram = externalProg.Text; - - commandLineArgs.Text = config.CommandLineArgs; - commandLineArgs.TextChanged += (src, arg) => config.CommandLineArgs = commandLineArgs.Text; - - workDir.Text = config.WorkingDir; - workDir.TextChanged += (src, arg) => config.WorkingDir = workDir.Text; - - debuggerScript.Text = config.DebuggerScript; - debuggerScript.TextChanged += (src, erg) => config.DebuggerScript = debuggerScript.Text; - - config.Changed += (src, arg) => isDirty(config.HasChangedFrom(originalConfig)); - } - - public void ApplyConfig(MsBuildConfiguration[] configs) - { - config.SaveTo(configs); - originalConfig = config.Clone(); - } - - private void browseProg_Click(object sender, EventArgs e) - { - var dialog = new OpenFileDialog(); - dialog.Title = "Select program"; - dialog.Filter = "Executable files (*.exe)|*.exe|All files (*.*)|*.*"; - dialog.DefaultExt = ".exe"; - dialog.CheckFileExists = true; - if (!string.IsNullOrEmpty(externalProg.Text)) - { - dialog.InitialDirectory = Path.GetDirectoryName(externalProg.Text); - dialog.FileName = Path.GetFileName(externalProg.Text); - } - - if (dialog.ShowDialog() == DialogResult.OK) - { - externalProg.Text = dialog.FileName; - } - } - - private void browseWorkDir_Click(object sender, EventArgs e) - { - var dialog = new FolderBrowserDialog(); - dialog.SelectedPath = workDir.Text; - if (dialog.ShowDialog() == DialogResult.OK) - { - workDir.Text = dialog.SelectedPath; - } - } - - private void commandLineArgs_KeyDown(object sender, KeyEventArgs e) - { - if (e.KeyCode == Keys.Enter) - { - e.SuppressKeyPress = true; - } - } - - private void gdbReference_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) - { - string url = "https://sourceware.org/gdb/onlinedocs/gdb/Command-and-Variable-Index.html"; - - if ((Control.ModifierKeys & Keys.Control) == Keys.Control || e.Button == MouseButtons.Middle) - { - Process.Start(url); - } - else - { - var service = (IVsWebBrowsingService)Package.GetGlobalService(typeof(IVsWebBrowsingService)); - IVsWindowFrame frame; - service.Navigate(url, 0, out frame); - } - } - } -} diff --git a/VisualRust.Project/Forms/DebugPropertyControl.resx b/VisualRust.Project/Forms/DebugPropertyControl.resx deleted file mode 100644 index 8766f298..00000000 --- a/VisualRust.Project/Forms/DebugPropertyControl.resx +++ /dev/null @@ -1,123 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - 17, 17 - - \ No newline at end of file diff --git a/VisualRust.Project/Forms/Utils.cs b/VisualRust.Project/Forms/Utils.cs deleted file mode 100644 index 89238f72..00000000 --- a/VisualRust.Project/Forms/Utils.cs +++ /dev/null @@ -1,120 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Forms; - -namespace VisualRust.Project.Forms -{ - public static class Utils - { - public static TableLayoutPanel CreateHeaderLabel(string text) - { - var panel = new TableLayoutPanel - { - RowCount = 1, - ColumnCount = 2, - AutoSize = true, - Anchor = AnchorStyles.Left | AnchorStyles.Right - }; - panel.Controls.Add( - new Label - { - Anchor = AnchorStyles.Left, - AutoSize = true, - Margin = new Padding(0, 0, 3, 0), - Text = text - }); - panel.Controls.Add( - new Label - { - AccessibleRole = System.Windows.Forms.AccessibleRole.Separator, - Anchor = AnchorStyles.Left | AnchorStyles.Right, - BackColor = System.Drawing.SystemColors.ControlDark, - Margin = new Padding(3, 0, 0, 0), - Height = 1 - }); - return panel; - } - - public static RadioButton CreateRadioButton(string text, Padding margin) - { - return new RadioButton - { - AutoSize = true, - Anchor = AnchorStyles.Left, - Text = text, - Margin = margin - }; - } - - public static Label CreateLabel(string text, Padding margin) - { - return new Label - { - Anchor = AnchorStyles.Left, - AutoSize = true, - Margin = margin, - Text = text - }; - } - - public static CheckBox CreateCheckBox(string text, Padding margin) - { - return new CheckBox - { - Anchor = AnchorStyles.Left, - AutoSize = true, - Margin = margin, - Text = text - }; - } - - public static ComboBox CreateComboBox(string[] text, Padding margin) - { - var box = new ComboBox - { - Anchor = AnchorStyles.Left, - AutoSize = true, - Margin = margin, - DropDownStyle = ComboBoxStyle.DropDownList - }; - box.Items.AddRange(text); - return box; - } - - public static TextBox CreateTextBox(string text, Padding margin) - { - return new TextBox - { - Anchor = AnchorStyles.Left | AnchorStyles.Right, - AutoSize = true, - Margin = margin - }; - } - - public static Padding Paddding() - { - return new Padding(3,4,3,4); - } - - public static Padding Left(this Padding pad) - { - pad.Left += 22; - return pad; - } - - public static Padding Top(this Padding pad) - { - pad.Top += 10; - return pad; - } - - public static Padding Bottom(this Padding pad) - { - pad.Bottom += 10; - return pad; - } - } -} diff --git a/VisualRust.Project/Iconindex.cs b/VisualRust.Project/Iconindex.cs deleted file mode 100644 index 82676de7..00000000 --- a/VisualRust.Project/Iconindex.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace VisualRust.Project -{ - // Strong typing for indexes of images in Resources/IconList.bmp - enum IconIndex - { - NoIcon = -1, - RustProject = 0, - RustFile, - UntrackedRustFile, - UntrackedFolder, - UntrackedFolderOpen, - ZombieUntrackedRustFile, - ZombieUntrackedFolder, - ZombieUntrackedFolderOpen, - } -} diff --git a/VisualRust.Project/Launcher/GnuDebugLauncher.cs b/VisualRust.Project/Launcher/GnuDebugLauncher.cs deleted file mode 100644 index 9c5c738b..00000000 --- a/VisualRust.Project/Launcher/GnuDebugLauncher.cs +++ /dev/null @@ -1,153 +0,0 @@ -using MICore.Xml.LaunchOptions; -using Microsoft.MIDebugEngine; -using Microsoft.VisualStudio.Shell.Interop; -using Microsoft.VisualStudioTools.Project; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; -using System.Xml; -using System.Xml.Serialization; -using VisualRust.Shared; - -namespace VisualRust.Project.Launcher -{ - class GnuDebugLauncher : IRustProjectLauncher - { - readonly LauncherEnvironment env; - readonly TargetTriple triple; - - public GnuDebugLauncher(LauncherEnvironment env, TargetTriple triple) - { - this.env = env; - this.triple = triple; - } - - public void Launch(string path, string args, string workingDir) - { - PipeLaunchOptions options = BuildLaunchOptions(path, args, workingDir); - VsDebugTargetInfo4 target = new VsDebugTargetInfo4 - { - dlo = (uint)DEBUG_LAUNCH_OPERATION.DLO_CreateProcess, - bstrExe = path, - guidLaunchDebugEngine = new Guid(EngineConstants.EngineId), - bstrOptions = ToXmlString(options) - }; - env.LaunchVsDebugger(target); - IVsCommandWindow commandWnd = env.GetService(); - commandWnd.ExecuteCommand("Tools.Alias gdb Debug.VRDebugExec"); - } - - private PipeLaunchOptions BuildLaunchOptions(string path, string args, string workingDir) - { - // We could go through LocalLaunchOptions, but this way we can pass additional args - PipeLaunchOptions options = new PipeLaunchOptions(); - options.PipePath = GetGdbPath(); - options.PipeArguments = String.Format("-q -interpreter=mi {0}", GetExtraArguments()); - options.ExePath = EscapePath(path); - options.ExeArguments = args; - options.SetupCommands = GetSetupCommands(); - // this affects the number of bytes the engine reads when disassembling commands, - // x64 has the largest maximum command size, so it should be safe to use for x86 as well - options.TargetArchitecture = TargetArchitecture.x64; - SetWorkingDirectory(options, path, workingDir); - return options; - } - - private void SetWorkingDirectory(PipeLaunchOptions options, string path, string workingDir) - { - string rustInstallPath = env.GetRustInstallPath(); - if (String.IsNullOrWhiteSpace(workingDir)) - { - options.WorkingDirectory = EscapePath(Path.GetDirectoryName(path)); - if (rustInstallPath != null) - options.AdditionalSOLibSearchPath = rustInstallPath; - } - else - { - options.WorkingDirectory = EscapePath(workingDir); - // GDB won't search working directory by default, but this is expected on Windows. - string additionalPath; - if (rustInstallPath != null) - additionalPath = rustInstallPath + ";" + workingDir; - else - additionalPath = workingDir; - options.AdditionalSOLibSearchPath = additionalPath; - } - } - - private static string EscapePath(string path) - { - if (String.IsNullOrEmpty(path)) - return ""; - return String.Format("\"{0}\"", path); - } - - Command[] GetSetupCommands() - { - return new string[] { "-gdb-set new-console on" } - .Union(GetScriptLines()) - .Select(cmd => new Command { Value = cmd }) - .ToArray(); - } - - string GetGdbPath() - { - string gdbPath = GetCustomPath(); - if (gdbPath != null) - return gdbPath; - return Path.Combine( - Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), - "gdb", - GetArchitectureName(), - "bin\\gdb"); - } - - private string GetArchitectureName() - { - if(triple != null) - { - if(triple.Arch == "i686" || triple.Arch == "x86_64") - return triple.Arch; - } - if (System.Environment.Is64BitOperatingSystem) - return "x86_64"; - return "i686"; - } - - static string ToXmlString(T obj) - { - var builder = new StringBuilder(); - var serializer = new XmlSerializer(typeof(T)); - using (var writer = XmlWriter.Create(builder, new XmlWriterSettings { OmitXmlDeclaration = true })) - { - serializer.Serialize(writer, (object)obj); - } - return builder.ToString(); - } - - string GetCustomPath() - { - bool useCustomPath = env.GetDebugConfigurationProperty("UseCustomGdbPath"); - if(!useCustomPath) - return null; - return env.GetDebugConfigurationProperty("DebuggerLocation"); - } - - string GetExtraArguments() - { - return env.GetDebugConfigurationProperty("ExtraArgs"); - } - - string[] GetScriptLines() - { - string debuggerScript = env.DebugConfig.DebuggerScript; - if(String.IsNullOrEmpty(debuggerScript)) - return new string[0]; - return debuggerScript.Split(new [] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries); - } - } -} \ No newline at end of file diff --git a/VisualRust.Project/Launcher/IRustProjectLauncher.cs b/VisualRust.Project/Launcher/IRustProjectLauncher.cs deleted file mode 100644 index cb92c19e..00000000 --- a/VisualRust.Project/Launcher/IRustProjectLauncher.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using VisualRust.Shared; - -namespace VisualRust.Project.Launcher -{ - public interface IRustProjectLauncher - { - void Launch(string path, string args, string workingDir); - } -} diff --git a/VisualRust.Project/Launcher/LauncherEnviroment.cs b/VisualRust.Project/Launcher/LauncherEnviroment.cs deleted file mode 100644 index 6a8a3967..00000000 --- a/VisualRust.Project/Launcher/LauncherEnviroment.cs +++ /dev/null @@ -1,97 +0,0 @@ -using Microsoft.VisualStudioTools.Project; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Microsoft.VisualStudio.Shell.Interop; -using System.Diagnostics; -using System.Text.RegularExpressions; -using VisualRust.Shared; - -namespace VisualRust.Project.Launcher -{ - class LauncherEnvironment - { - readonly RustProjectNode project; - readonly RustProjectConfig projectConfig; - public Configuration.Debug DebugConfig { get; private set; } - - public LauncherEnvironment(RustProjectNode project, Configuration.Debug debugConfig, RustProjectConfig projConfig) - { - this.project = project; - this.DebugConfig = debugConfig; - this.projectConfig = projConfig; - } - - public string GetRustInstallPath() - { - EnvDTE.Project proj = project.GetAutomationObject() as EnvDTE.Project; - if (proj == null) - return null; - string currentConfigName = Utilities.GetActiveConfigurationName(proj); - if (currentConfigName == null) - return null; - ProjectConfig currentConfig = project.ConfigProvider.GetProjectConfiguration(currentConfigName); - if (currentConfig == null) - return null; - string currentTarget = currentConfig.GetConfigurationProperty("PlatformTarget", true); - if (currentTarget == null) - currentTarget = Shared.Environment.DefaultTarget; - return Shared.Environment.FindInstallPath(currentTarget); - } - - public TInterface GetService() - { - return (TInterface)project.GetService(typeof(TService)); - } - - public void LaunchVsDebugger(VsDebugTargetInfo4 target) - { - var targets = new VsDebugTargetInfo4[1] { target }; - VsDebugTargetProcessInfo[] results = new VsDebugTargetProcessInfo[targets.Length]; - IVsDebugger4 vsDebugger = (IVsDebugger4)project.GetService(typeof(SVsShellDebugger)); - vsDebugger.LaunchDebugTargets4((uint)targets.Length, targets, results); - } - - public T GetDebugConfigurationProperty(string key) - { - var env = (EnvDTE.DTE)project.GetService(typeof(EnvDTE.DTE)); - return (T)env.Properties["Visual Rust", "Debugging"].Item(key).Value; - } - - public string GetProjectProperty(string key) - { - return project.GetProjectProperty(key); - } - - public TargetTriple GetTargetTriple() - { - TargetTriple confTriple = TryGetTripleFromConfiguration(); - if(confTriple != null) - return confTriple; - return TryGetTripleFromRustc(); - } - - public void ForceBuild() - { - project.Build("Build"); - } - - TargetTriple TryGetTripleFromConfiguration() - { - string triple = Configuration.Build.LoadFrom(new ProjectConfig[] { projectConfig }).PlatformTarget; - return TargetTriple.Create(triple); - } - - TargetTriple TryGetTripleFromRustc() - { - string defaultInstallPath = Shared.Environment.FindInstallPath("default"); - if(defaultInstallPath == null) - return null; - string rustcPath = Path.Combine(defaultInstallPath, "rustc.exe"); - return Shared.Environment.GetTarget(rustcPath); - } - } -} diff --git a/VisualRust.Project/Launcher/MsvcDebugLauncher.cs b/VisualRust.Project/Launcher/MsvcDebugLauncher.cs deleted file mode 100644 index 3e3681db..00000000 --- a/VisualRust.Project/Launcher/MsvcDebugLauncher.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Microsoft.VisualStudio.Shell.Interop; -using Microsoft.VisualStudioTools.Project; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace VisualRust.Project.Launcher -{ - class MsvcDebugLauncher : IRustProjectLauncher - { - readonly LauncherEnvironment env; - - public MsvcDebugLauncher(LauncherEnvironment env) - { - this.env = env; - } - - public void Launch(string path, string args, string workingDir) - { - VsDebugTargetInfo4 target = new VsDebugTargetInfo4 - { - dlo = (uint)DEBUG_LAUNCH_OPERATION.DLO_CreateProcess, - guidLaunchDebugEngine = Constants.NativeOnlyEngine, - bstrExe = path, - bstrArg = args, - bstrCurDir = workingDir - }; - env.LaunchVsDebugger(target); - } - } -} diff --git a/VisualRust.Project/Launcher/ReleaseLauncher.cs b/VisualRust.Project/Launcher/ReleaseLauncher.cs deleted file mode 100644 index 13140945..00000000 --- a/VisualRust.Project/Launcher/ReleaseLauncher.cs +++ /dev/null @@ -1,48 +0,0 @@ -using Microsoft.VisualStudioTools.Project; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace VisualRust.Project.Launcher -{ - class ReleaseLauncher : IRustProjectLauncher - { - readonly LauncherEnvironment env; - - public ReleaseLauncher(LauncherEnvironment env) - { - this.env = env; - } - - public void Launch(string path, string args, string workingDir) - { - ProcessStartInfo processStartInfo = CreateProcessStartInfo(path, args, workingDir); - Process.Start(processStartInfo); - } - - ProcessStartInfo CreateProcessStartInfo(string path, string args, string workingDir) - { - string startupFile = Path.Combine(System.Environment.SystemDirectory, "cmd.exe"); - string cmdArgs = String.Format(@"/c """"{0}"" {1} & pause""", path, args); - var startInfo = new ProcessStartInfo(startupFile, cmdArgs); - startInfo.WorkingDirectory = workingDir; - startInfo.UseShellExecute = false; - InjectRustBinPath(startInfo); - return startInfo; - } - - void InjectRustBinPath(ProcessStartInfo startInfo) - { - string installPath = env.GetRustInstallPath(); - if(installPath == null) - return; - string envPath = Environment.GetEnvironmentVariable("PATH"); - string newEnvPath = String.Format("{0};{1}", envPath, installPath); - startInfo.EnvironmentVariables["PATH"] = newEnvPath; - } - } -} diff --git a/VisualRust.Project/ManifestFile.cs b/VisualRust.Project/ManifestFile.cs deleted file mode 100644 index c5f04ae9..00000000 --- a/VisualRust.Project/ManifestFile.cs +++ /dev/null @@ -1,51 +0,0 @@ -using Microsoft.VisualStudioTools.Project; -using System; -using System.Collections.Generic; -using System.IO; -using System.IO.Abstractions; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using VisualRust.Cargo; -using VisualRust.Project.Controls; - -namespace VisualRust.Project -{ - public class ManifestFile - { - private IFileSystem fs; - public string Path { get; private set; } - public Manifest Manifest { get; private set; } - - public static ManifestFile Create(IFileSystem fs, string startingPath, Func fileOpener) - { - var file = new ManifestFile(); - file.fs = fs; - ManifestLoadResult loadResult = fileOpener(startingPath); - file.Path = loadResult.Path; - file.Manifest = loadResult.Manifest; - return file; - } - - public void Apply(OutputTargetChanges changes) - { - foreach(OutputTargetRemoval removed in changes.TargetsRemoved) - { - this.Manifest.Remove(removed.Handle, removed.Type); - } - foreach(KeyValuePair target in changes.TargetsChanged) - { - UIntPtr handle = this.Manifest.Set(target.Value); - if(handle != UIntPtr.Zero) - target.Key.Handle = handle; - } - foreach(KeyValuePair target in changes.TargetsAdded) - { - UIntPtr handle = this.Manifest.Add(target.Value); - if(handle != UIntPtr.Zero) - target.Key.Handle = handle; - } - fs.File.WriteAllText(Path, Manifest.ToString()); - } - } -} diff --git a/VisualRust.Project/ManifestLoadResult.cs b/VisualRust.Project/ManifestLoadResult.cs deleted file mode 100644 index d8a23c1a..00000000 --- a/VisualRust.Project/ManifestLoadResult.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using VisualRust.Cargo; - -namespace VisualRust.Project -{ - public class ManifestLoadResult - { - public bool Cancel { get; private set; } - public string Path { get; private set; } - public Manifest Manifest { get; private set; } - - private ManifestLoadResult() { } - - public static ManifestLoadResult CreateCancel(string path) - { - return new ManifestLoadResult - { - Path = path, - Cancel = true - }; - } - - public static ManifestLoadResult CreateSuccess(string path, Manifest m) - { - return new ManifestLoadResult - { - Path = path, - Manifest = m - }; - } - } -} diff --git a/VisualRust.Project/Module.g4 b/VisualRust.Project/Module.g4 deleted file mode 100644 index 02326e4b..00000000 --- a/VisualRust.Project/Module.g4 +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Very simple module parsing grammar. - * Works like rustc --dep-info, but handles broken files. - */ - -grammar Module; - - -PUB : 'pub'; -MOD : 'mod'; -LBRACE : '{' ; -RBRACE : '}' ; -SEMI : ';' ; -POUND : '#' ; -LBRACKET : '[' ; -RBRACKET : ']' ; -EQ : '=' ; - -fragment -XID_start : [_a-zA-Z] ; -fragment -XID_continue : [_a-zA-Z0-9] ; -IDENT : XID_start XID_continue* ; - -LINE_COMMENT : '//' ~[\n]* { Skip(); }; -BLOCK_COMMENT : '/*' (BLOCK_COMMENT | .)*? '*/' { Skip(); }; - -fragment HEXIT : [0-9a-fA-F] ; -fragment CHAR_ESCAPE: [nrt\\'"0] - | [xX] HEXIT HEXIT - | 'u' HEXIT HEXIT HEXIT HEXIT - | 'U' HEXIT HEXIT HEXIT HEXIT HEXIT HEXIT HEXIT HEXIT ; -LIT_STR : '"' ('\\\n' | '\\\r\n' | '\\' CHAR_ESCAPE | .)*? '"' ; - - -ANY_CHAR: . { Skip(); }; - -mod_block: attrs? PUB? MOD IDENT LBRACE body RBRACE; -mod_import: attrs? PUB? MOD IDENT SEMI; -body: (mod_import | mod_block | item)*?; -item: ( IDENT | SEMI | LBRACE | RBRACE | POUND | LBRACKET | IDENT | EQ | LIT_STR | RBRACKET | PUB); -attrs: attr+; -attr: POUND LBRACKET IDENT EQ LIT_STR RBRACKET; diff --git a/VisualRust.Project/ModuleImport.cs b/VisualRust.Project/ModuleImport.cs deleted file mode 100644 index 748cdad2..00000000 --- a/VisualRust.Project/ModuleImport.cs +++ /dev/null @@ -1,77 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace VisualRust.Project -{ - public class ModuleImport : Dictionary - { - private class SegmentComparer : IEqualityComparer - { - public bool Equals(PathSegment x, PathSegment y) - { - return x.IsAuthorative == y.IsAuthorative - && String.Equals(x.Name, y.Name, StringComparison.InvariantCultureIgnoreCase); - } - - public int GetHashCode(PathSegment obj) - { - return obj.GetHashCode(); - } - } - - private static SegmentComparer moduleComparer = new SegmentComparer(); - - public ModuleImport() - : base(moduleComparer) { } - - public void Merge(Dictionary obj) - { - foreach(var kvp in obj) - { - if (this.ContainsKey(kvp.Key)) - { - this[kvp.Key].Merge(kvp.Value); - } - else if (this.ContainsKey(new PathSegment(kvp.Key.Name, !kvp.Key.IsAuthorative))) - { - this[new PathSegment(kvp.Key.Name, !kvp.Key.IsAuthorative)].Merge(kvp.Value); - } - else - { - this.Add(kvp.Key, kvp.Value); - } - } - } - - public IEnumerable GetTerminalImports() - { - return GetTerminalImports(this, new Queue()); - } - - private IEnumerable GetTerminalImports(ModuleImport current, Queue queue) - { - foreach(var kvp in current) - { - if(kvp.Value.Count == 0) - { - PathSegment[] result = new PathSegment[queue.Count + 1]; - queue.CopyTo(result, 0); - result[result.Length - 1] = kvp.Key; - yield return result; - } - else - { - queue.Enqueue(kvp.Key); - foreach(var value in GetTerminalImports(kvp.Value, queue)) - { - yield return value; - } - queue.Dequeue(); - } - } - } - } -} diff --git a/VisualRust.Project/ModuleLexer.g4.cs b/VisualRust.Project/ModuleLexer.g4.cs deleted file mode 100644 index a0852145..00000000 --- a/VisualRust.Project/ModuleLexer.g4.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Antlr4.Runtime; - -namespace VisualRust.Project -{ - partial class ModuleLexer : Lexer - { - - } -} diff --git a/VisualRust.Project/ModuleParser.g4.cs b/VisualRust.Project/ModuleParser.g4.cs deleted file mode 100644 index 5660913b..00000000 --- a/VisualRust.Project/ModuleParser.g4.cs +++ /dev/null @@ -1,181 +0,0 @@ -using Antlr4.Runtime; -using Antlr4.Runtime.Tree; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Text; - -namespace VisualRust.Project -{ - partial class ModuleParser : Parser - { - /* - * There's one fairly important difference between mod resolution in rustc and what we do. - * Given following code: - * mod bar { mod a; } mod bar { mod b; } - * We will merget this to mod bar { mod a; mod b; }, but rustc will error out. - */ - public static ModuleImport ParseImports(ICharStream stream) - { - var lexer = new ModuleLexer(stream); - var tokens = new CommonTokenStream(lexer); - var parser = new ModuleParser(tokens); - BodyContext root = parser.body(); - var imports = new ModuleImport(); - TraverseForImports(root, imports); - return imports; - } - - /* - * Fairly straightforward traversal, with one gotcha: we return bool indicating - * if the node is contained within exported mod block, it's to deal with the following: - * mod bar { ... } - * We don't know at this point if any of the items inside blocks is a module, - * so decision to add 'bar' ModuleImport has to be delayed. - */ - private static bool TraverseForImports(ITree node, ModuleImport current) - { - bool isContainedInBlock = false; - for(int i = 0; i < node.ChildCount; i++) - { - var child = node.GetChild(i) as IRuleNode; - if (child == null) - continue; - if(child.RuleContext.RuleIndex == ModuleParser.RULE_mod_block) - { - var blockChildren = new ModuleImport(); - var blockImport = new ModuleImport() - { - { GetModIdent(child), blockChildren } - }; - if (TraverseForImports(child, blockChildren)) - { - current.Merge(blockImport); - isContainedInBlock = true; - } - } - else if (child.RuleContext.RuleIndex == ModuleParser.RULE_mod_import) - { - isContainedInBlock = true; - current.Merge(new Dictionary() - { - { GetModIdent(child), new ModuleImport() } - }); - } - else - { - if (TraverseForImports(child, current)) - isContainedInBlock = true; - } - } - return isContainedInBlock; - } - - private static PathSegment GetModIdent(IRuleNode modNode) - { - var firstNode = modNode.GetChild(0) as IRuleNode; - int currentChild = 0; - if (firstNode != null) - { - currentChild = 1; - ITree attrRoot = modNode.GetChild(0); - for(int i = 0; i < attrRoot.ChildCount; i++) - { - IRuleNode attrNode = (IRuleNode)attrRoot.GetChild(i); - if(attrNode.GetChild(2).GetText() == "path") - { - string rawString = EscapeRustString(attrNode.GetChild(4).GetText()); - return new PathSegment(rawString.Substring(1, rawString.Length - 2), true); - } - } - } - var pubOrMod = (ITerminalNode)modNode.GetChild(currentChild); - IParseTree identNode = modNode.GetChild(pubOrMod.Symbol.Type == ModuleParser.PUB ? currentChild + 2 : currentChild + 1); - return new PathSegment(identNode.GetText(), false); - } - - private static string EscapeRustString(string text) - { - StringBuilder b = new StringBuilder(); - bool spottedEscape = false; - for(int i =0; i < text.Length; i++) - { - if(text[i] == '\\') - { - bool unescaped = false; - if(i < text.Length - 1) - { - switch(text[i+1]) - { - case '\\': - AppendSingleChar(text, b, ref spottedEscape, ref i, '\\'); - unescaped = true; - break; - case 'n': - AppendSingleChar(text, b, ref spottedEscape, ref i, '\n'); - unescaped = true; - break; - case 'r': - AppendSingleChar(text, b, ref spottedEscape, ref i, '\r'); - unescaped = true; - break; - case 't': - AppendSingleChar(text, b, ref spottedEscape, ref i, '\t'); - unescaped = true; - break; - case '0': - AppendSingleChar(text, b, ref spottedEscape, ref i, '\0'); - unescaped = true; - break; - case 'x': - if(i < text.Length - 3) - unescaped = AppendHex(text, b, ref spottedEscape, ref i, 2); break; - case 'u': - if (i < text.Length - 5) - unescaped = AppendHex(text, b, ref spottedEscape, ref i, 4); break; - case 'U': - if (i < text.Length - 9) - unescaped = AppendHex(text, b, ref spottedEscape, ref i, 8); break; - } - } - if (!unescaped) - b.Append(text[i]); - } - else if (spottedEscape) - { - b.Append(text[i]); - } - } - if (!spottedEscape) - return text; - return b.ToString(); - } - - private static void AppendSingleChar(string text, StringBuilder b, ref bool spotted, ref int idx, char target) - { - HandleFirstEscape(text, b, ref spotted, idx); - b.Append(target); - idx++; - } - - private static void HandleFirstEscape(string text, StringBuilder b, ref bool spotted, int idx) - { - if (!spotted) - { - spotted = true; - b.Append(text, 0, idx); - } - } - - private static bool AppendHex(string text, StringBuilder b, ref bool spotted, ref int idx, int length) - { - uint value; - if (!uint.TryParse(text.Substring(idx + 2, length), System.Globalization.NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out value)) - return false; - HandleFirstEscape(text, b, ref spotted, idx); - b.Append((char)value); - idx += (length + 1); - return true; - } - } -} diff --git a/VisualRust.Project/ModuleRemovalResult.cs b/VisualRust.Project/ModuleRemovalResult.cs deleted file mode 100644 index 78c9a1a2..00000000 --- a/VisualRust.Project/ModuleRemovalResult.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace VisualRust.Project -{ - public struct ModuleRemovalResult - { - public HashSet Orphans { get; private set; } - public bool IsReferenced { get; private set; } - - public ModuleRemovalResult(HashSet o, bool isRef) : this() - { - Orphans = o; - IsReferenced = isRef; - } - } -} diff --git a/VisualRust.Project/ModuleTracker.cs b/VisualRust.Project/ModuleTracker.cs deleted file mode 100644 index c555b4b1..00000000 --- a/VisualRust.Project/ModuleTracker.cs +++ /dev/null @@ -1,714 +0,0 @@ -using Antlr4.Runtime; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Diagnostics; -using System.Diagnostics.Contracts; - -#if TEST -using NUnit.Framework; -using System.Diagnostics; -#endif - -using ImportsChange = VisualRust.Project.CollectionChange>; -using ImportsDifference = VisualRust.Project.CollectionDifference>; - -namespace VisualRust.Project -{ - struct CollectionChange - { - public T Old { get; private set; } - public T New { get; private set; } - public CollectionChange(T old, T @new) - : this() - { - Old = old; - New = @new; - } - } - - public class ModuleTracker - { - public string EntryPoint { get; private set; } - // Set of tracked files with enabled auto-imports - private HashSet fileRoots = new HashSet(StringComparer.InvariantCultureIgnoreCase); - // Set of modules with disabled auto-imports, this is relevant in some cases - private HashSet blockingRoots = new HashSet(StringComparer.InvariantCultureIgnoreCase); - // We keep track of which modules can reach which modules and which modules are reachable from which modules. - // This saves us from reparsing everything when a file is added/removed. - private Dictionary> moduleImportMap = new Dictionary>(StringComparer.InvariantCultureIgnoreCase); - private Dictionary> reverseModuleImportMap = new Dictionary>(StringComparer.InvariantCultureIgnoreCase); - // I'm not very happy about this but we keep it to avoid molesting disk on every reparse - private Dictionary lastParseResult = new Dictionary(StringComparer.InvariantCultureIgnoreCase); - - public bool IsIncremental { get; private set; } - - public ModuleTracker(string root) - { - EntryPoint = root; - fileRoots.Add(Path.GetFullPath(root)); - } - - public void AddRootModule(string root) - { - if (IsIncremental) - throw new InvalidOperationException(); - if (root == null) - throw new ArgumentNullException("root"); - string normalized = Path.GetFullPath(root); - fileRoots.Add(normalized); - } - - // This function extracts all reachable modules and moves to incremental mode - public HashSet ExtractReachableAndMakeIncremental() - { - if (IsIncremental) - throw new InvalidOperationException(); - IsIncremental = true; - return AddModulesInternal(this.fileRoots); - } - - private HashSet AddModulesInternal(HashSet modulesToParse) - { - HashSet reachedAuthorative = new HashSet(StringComparer.InvariantCultureIgnoreCase); - while (modulesToParse.Count > 0) - { - Dictionary> reached = new Dictionary>(StringComparer.InvariantCultureIgnoreCase); - foreach (string root in modulesToParse) - { - if (this.moduleImportMap.ContainsKey(root)) - continue; - ExtractReachableModules(reached, reachedAuthorative, key => this.fileRoots.Contains(key), root, ReadImports); - } - modulesToParse = FixNonAuthorativeImports(reached, reachedAuthorative); - } - return reachedAuthorative; - } - - /* - * Reached non-authorative module imports are standard stuff like mod foo { mod bar; } - * (as opposed to mod foo { #[path="bar.rs"] bar; }). - * Now, for every terminal module import foo/bar we find out actual backing file in this order: - * Check for authorative entry foo/bar.rs - * Check for authorative entry foo/bar/mod.rs - * Check on the disk for foo/bar.rs - * Check on the disk for foo/bar/mod.rs - * If all of the above fails go with broken foo/bar.rs - */ - private HashSet FixNonAuthorativeImports(Dictionary> nonAuth, - HashSet justParsed) - { - HashSet newlyAuth = new HashSet(StringComparer.InvariantCultureIgnoreCase); - foreach (var kvp in nonAuth) - { - string authPath; - if(!ResolveAuthorativeImport(kvp.Key, justParsed, out authPath)) - { - justParsed.Add(authPath); - newlyAuth.Add(authPath); - } - AddToModuleSets(kvp.Value, authPath); - } - return newlyAuth; - } - - // return value indicates if resolution found module in existing modules - private bool ResolveAuthorativeImport(string nonAuthPath, - HashSet justParsed, - out string path) - { - string filePath = nonAuthPath + ".rs"; - string subfolderPath = Path.Combine(nonAuthPath, "mod.rs"); - if (justParsed.Contains(filePath) || fileRoots.Contains(filePath) || reverseModuleImportMap.ContainsKey(filePath)) - { - path = filePath; - return true; - } - else if (justParsed.Contains(subfolderPath) || fileRoots.Contains(subfolderPath) || reverseModuleImportMap.ContainsKey(subfolderPath)) - { - path = subfolderPath; - return true; - } - else if (File.Exists(filePath)) - { - path = filePath; - return false; - } - else if (File.Exists(subfolderPath)) - { - path = subfolderPath; - return false; - } - else - { - path = filePath; - return false; - } - } - - private void AddToModuleSets(HashSet set, string filePath) - { - foreach (string terminalImportPath in set) - { - if (String.Equals(terminalImportPath, filePath, StringComparison.OrdinalIgnoreCase)) - continue; - AddToSet(moduleImportMap, terminalImportPath, filePath); - AddToSet(reverseModuleImportMap, filePath, terminalImportPath); - } - } - - private ModuleImport ReadImports(string path) - { - ModuleImport imports = ReadImportsRaw(path); - lastParseResult[path] = imports; - return imports; - } - - private ModuleImport ReadImportsRaw(string path) - { - if (blockingRoots.Contains(path)) - return new ModuleImport(); - try - { - using(var stream = File.OpenRead(path)) - { - return ModuleParser.ParseImports(new AntlrInputStream(stream)); - } - } - catch(PathTooLongException) - { - throw; - } - catch(IOException) - { - return new ModuleImport(); - } - catch(UnauthorizedAccessException) - { - return new ModuleImport(); - } - } - - private static void AddToSet(Dictionary> dict, string key, string value) - { - if(!dict.ContainsKey(key)) - dict.Add(key, new HashSet(StringComparer.InvariantCultureIgnoreCase) { value }); - else - dict[key].Add(value); - } - - private static bool DeleteFromSet(Dictionary> dict, string key, string value) - { - HashSet s; - if(dict.TryGetValue(key, out s)) - { - bool wasRemoved = s.Remove(value); - if(wasRemoved && s.Count == 0) - dict.Remove(key); - return wasRemoved; - } - return false; - } - - /* - * General algorithm is: - * # Parse given module (passed as 'importPath') and traverse its imports - * # for every terminal import: - * # if the import [is authorative] and [not a root] and [not in reachables] - * # add it to reachables - * # Recursively call ExtractReachableModules on the import - * # else if the import [is not authorative] - * # add to set of non-authorative imports - * Algorithm returns set of pairs of non-authorative imports - */ - private void ExtractReachableModules(Dictionary> reachable, - HashSet reachableAuthorative, - Func isRoot, - string importPath, - Func importReader) // the last argument is there just to make unit-testing possible - { - ModuleImport imports = importReader(importPath); - foreach(PathSegment[] import in imports.GetTerminalImports()) - { - string terminalImportPath = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(importPath), Path.Combine(import.Select(i => i.Name).ToArray()))); - if (import[import.Length - 1].IsAuthorative) - { - AddToSet(moduleImportMap, importPath, terminalImportPath); - AddToSet(reverseModuleImportMap, terminalImportPath, importPath); - if (!isRoot(terminalImportPath) && reachableAuthorative.Add(terminalImportPath)) - { - ExtractReachableModules(reachable, reachableAuthorative, isRoot, terminalImportPath, importReader); - } - } - else - { - // We can't compare non-authorative paths with roots - // Remember to call ExtractReachableModules(...) again after figuring out authorative paths - AddToSet(reachable, terminalImportPath, importPath); - } - } - } - - private static void Increment(Dictionary dict, string key) - { - int current; - dict.TryGetValue(key, out current); - dict[key] = current + 1; - } - - private static IEnumerable GetSetFromDictionary(Dictionary> dict, string key) - { - HashSet set; - if(dict.TryGetValue(key, out set)) - return set; - else - return new string[0] { }; - } - - private void TraverseForDependants(string current, string root, HashSet nodes, bool delete, ref bool refFromOutside) - { - if (refFromOutside && !delete) - return; - if (String.Equals(current, root, StringComparison.InvariantCultureIgnoreCase)) - { - refFromOutside = true; - return; - } - if(fileRoots.Contains(current) - || !nodes.Remove(current)) - return; - foreach (string mod in GetSetFromDictionary(moduleImportMap, current)) - TraverseForDependants(mod, root, nodes, delete, ref refFromOutside); - } - - // Returns all the module that are reachable only from the given root - private HashSet CalculateDependants(string source, bool delete, out bool refFromOutside) - { - // FIXME: that could use some optimization - // We simply traverse the graph starting from the the other roots, storing all traversed edges. - // All untraversed nodes depend on this root - HashSet nodes = new HashSet(StringComparer.InvariantCultureIgnoreCase); - foreach(var pair in reverseModuleImportMap) - { - if (!fileRoots.Contains(pair.Key)) - nodes.Add(pair.Key); - } - refFromOutside = false; - foreach (string mod in fileRoots.Where(s => !s.Equals(source, StringComparison.InvariantCultureIgnoreCase)).SelectMany(r => GetSetFromDictionary(moduleImportMap, r))) - { - TraverseForDependants(mod, source, nodes, delete, ref refFromOutside); - } - if (delete && refFromOutside) - nodes.Remove(source); - if (!refFromOutside) - nodes.Add(source); - return nodes; - } - - private HashSet CalculateDependantsInner(HashSet seen, - Dictionary degrees, - string currentNode, - string root, - ref int circles) - { - seen.Add(currentNode); - HashSet children = null; - if(this.moduleImportMap.TryGetValue(currentNode, out children)) - { - foreach(string child in children) - { - if (String.Equals(root, child, StringComparison.InvariantCultureIgnoreCase)) - { - circles++; - continue; - } - if (this.fileRoots.Contains(child)) - continue; - Increment(degrees, child); - if(!seen.Contains(child)) - CalculateDependantsInner(seen, degrees, child, root, ref circles); - } - } - return children; - } - - private void DeleteModuleData(string mod) - { - HashSet importSet; - moduleImportMap.TryGetValue(mod, out importSet); - if(importSet != null) - { - foreach(string child in importSet) - { - DeleteFromSet(reverseModuleImportMap, child, mod); - } - } - HashSet reverseImportSet; - reverseModuleImportMap.TryGetValue(mod, out reverseImportSet); - if(reverseImportSet != null) - { - foreach(string parent in reverseImportSet) - { - DeleteFromSet(moduleImportMap, mod, parent); - } - } - moduleImportMap.Remove(mod); - reverseModuleImportMap.Remove(mod); - lastParseResult.Remove(mod); - } - - // Returns set of modules orphaned by this deletion (including the module itself) - // and if the module is still referenced by another non-removed module - public ModuleRemovalResult DeleteModule(string path) - { - if (!IsIncremental) - throw new InvalidOperationException(); - if (path == null) - throw new ArgumentNullException("path"); - bool referencedFromOutside; - HashSet markedForRemoval = CalculateDependants(path, true, out referencedFromOutside); - foreach(string mod in markedForRemoval) - { - DeleteModuleData(mod); - } - moduleImportMap.Remove(path); - if (!referencedFromOutside) - lastParseResult.Remove(path); - else - lastParseResult[path] = new ModuleImport(); - this.fileRoots.Remove(path); - return new ModuleRemovalResult(markedForRemoval, referencedFromOutside); - } - - // Returns set of new modules referenced by this addition (except the module itself) - public HashSet AddRootModuleIncremental(string path) - { - if (!IsIncremental) - throw new InvalidOperationException(); - if (path == null) - throw new ArgumentNullException("path"); - fileRoots.Add(path); - HashSet result = AddModulesInternal(new HashSet(StringComparer.InvariantCultureIgnoreCase) { path }); - return result; - } - - public void UpgradeModule(string path) - { - if (!IsIncremental) - throw new InvalidOperationException(); - if (path == null) - throw new ArgumentNullException("path"); - Contract.Assert(!this.fileRoots.Contains(path)); - fileRoots.Add(path); - } - - // When a module and all its children form a strongly connected component - // downgrading a module can orphan some modules - public ModuleRemovalResult DowngradeModule(string path) - { - if (!IsIncremental) - throw new InvalidOperationException(); - if (path == null) - throw new ArgumentNullException("path"); - Contract.Assert(this.fileRoots.Contains(path)); - bool referencedFromOutside; - HashSet dependingOnRoot = CalculateDependants(path, false, out referencedFromOutside); - fileRoots.Remove(path); - if (referencedFromOutside) - return new ModuleRemovalResult(new HashSet(StringComparer.InvariantCultureIgnoreCase), true); - foreach(string mod in dependingOnRoot) - { - DeleteModuleData(mod); - } - return new ModuleRemovalResult(dependingOnRoot, false); - } - - public HashSet DisableTracking(string path) - { - if (!IsIncremental) - throw new InvalidOperationException(); - if (path == null) - throw new ArgumentNullException("path"); - Contract.Assert(this.fileRoots.Contains(path)); - Contract.Assert(this.blockingRoots.Add(path)); - return Reparse(path).Removed; - } - - public HashSet EnableTracking(string path) - { - if (!IsIncremental) - throw new InvalidOperationException(); - if (path == null) - throw new ArgumentNullException("path"); - Contract.Assert(this.fileRoots.Contains(path)); - Contract.Assert(this.blockingRoots.Remove(path)); - return Reparse(path).Added; - } - - // HACK ALERT: We exploit the fact that passed pair of sets is not used afterwards - private static ImportsDifference DiffReparseSets(string root, ImportsChange change) - { - HashSet removed = new HashSet(StringComparer.InvariantCultureIgnoreCase); - foreach(string path in change.Old) - { - if (!change.New.Remove(path)) - { - removed.Add(path); - } - } - return new ImportsDifference(change.New, removed); - } - - private void NormalizeSingleImport(string rootDir, PathSegment[] segs, HashSet added, bool addResolved) - { - string rootedPath = Path.Combine(rootDir, String.Join(Path.DirectorySeparatorChar.ToString(), segs)); - if (!segs[segs.Length - 1].IsAuthorative) - { - string validImport; - ResolveAuthorativeImport(rootedPath, added, out validImport); - added.Add(validImport); - } - else - { - added.Add(rootedPath); - } - } - - private ImportsChange NormalizeImports(string root, ModuleImport oldI, ModuleImport newI) - { - string rootDir = Path.GetDirectoryName(root); - HashSet added = new HashSet(StringComparer.InvariantCultureIgnoreCase); - foreach(PathSegment[] segs in oldI.GetTerminalImports()) - { - NormalizeSingleImport(rootDir, segs, added, true); - } - HashSet removed = new HashSet(StringComparer.InvariantCultureIgnoreCase); - foreach (PathSegment[] segs in newI.GetTerminalImports()) - { - NormalizeSingleImport(rootDir, segs, removed, false); - } - return new ImportsChange(added, removed); - } - - /* - * This function is called when during reparsing - * a set of module imports is removed. - * We have to check if it's safe to remove those node, - * that is if there is no other path through which this node - * can reach a root. For example: - * [main] ---> (bar) <--- foo <--- (baz) - * â””---------------------^--------^ - * Main is a reparsed file and bar and baz have been "removed". - * We start by removing references main --> bar and main --> baz - * (this is done by an outside function): - * [main] (bar) <--- foo <--- (baz) - * â””---------------------^ - * Then, for every node in the set of removed nodes we backtrack. - * If we can reach the target node or a root, that means the node is not removed. - * For example with bar we go through foo, then reach main, which means that it stays. - * For baz we can't find such path (or in fact any other) which means that baz goes away. - */ - private bool AdditionalImportPathExists(string current, string target, HashSet removed, HashSet seen) - { - if (!seen.Add(current)) - return false; - HashSet children; - if(reverseModuleImportMap.TryGetValue(current, out children)) - { - foreach(string child in children) - { - if (removed.Contains(child)) - continue; - if (String.Equals(child, target, StringComparison.InvariantCultureIgnoreCase) || fileRoots.Contains(child)) - return true; - } - return children.Any(child => AdditionalImportPathExists(child, target, removed, seen)); - } - return false; - } - - public ImportsDifference Reparse(string path) - { - ModuleImport oldImports = lastParseResult[path]; - ModuleImport newImports = ReadImports(path); - if (oldImports.Count == 0 && newImports.Count == 0) - return new ImportsDifference(new HashSet(StringComparer.InvariantCultureIgnoreCase), new HashSet(StringComparer.InvariantCultureIgnoreCase)); - ImportsChange normalized = NormalizeImports(path, oldImports, newImports); - ImportsDifference diff = DiffReparseSets(path, normalized); - HashSet removedFromProject = new HashSet(StringComparer.InvariantCultureIgnoreCase); - if(diff.Removed.Count > 0) - { - HashSet allImports = moduleImportMap[path]; - foreach (string mod in diff.Removed) - { - if (allImports.Remove(mod)) - { - bool removed = DeleteFromSet(reverseModuleImportMap, mod, path); - Debug.Assert(removed); - } - if(allImports.Count == 0) - moduleImportMap.Remove(path); - } - foreach(string mod in diff.Removed) - { - if (!AdditionalImportPathExists(mod, path, diff.Removed, new HashSet(StringComparer.InvariantCultureIgnoreCase))) - removedFromProject.Add(mod); - } - foreach(string mod in removedFromProject.ToArray()) - { - foreach (string removedMod in DeleteModule(mod).Orphans) - removedFromProject.Add(removedMod); - } - } - HashSet addedFromParsing = new HashSet(StringComparer.InvariantCultureIgnoreCase); - foreach(string mod in diff.Added) - { - AddToSet(moduleImportMap, path, mod); - AddToSet(reverseModuleImportMap, mod, path); - if(!lastParseResult.ContainsKey(mod)) - { - addedFromParsing.Add(mod); - } - } - addedFromParsing.UnionWith(AddModulesInternal(diff.Added)); - return new ImportsDifference(addedFromParsing, removedFromProject); - } - -#if TEST - - private static bool AreEqual(Dictionary d1, Dictionary d2) - { - return d1.Count == d2.Count && d1.All(x => AreEqual(x.Value, d2[x.Key])); - } - - private static bool AreEqual(ModuleImport m1, ModuleImport m2) - { - return m1.Count == m2.Count && m1.All(x => AreEqual(x.Value, m2[x.Key])); - } - - private static bool AreEqual(Dictionary> d1, Dictionary> d2) - { - return d1.Count == d2.Count && d1.All(x => AreEqual(x.Value, d2[x.Key])); - } - - private static bool AreEqual(HashSet s1, HashSet s2) - { - return s1.Count == s2.Count && s1.All(x => s2.Contains(x)); - } - - // It's formatted this way to make unit test failures more readable - public bool IsEquivalnet(ModuleTracker other) - { - if (EntryPoint != other.EntryPoint) - return false; - if (!AreEqual(this.fileRoots, other.fileRoots)) - return false; - if (!AreEqual(this.blockingRoots, other.blockingRoots)) - return false; - if (!AreEqual(this.moduleImportMap, other.moduleImportMap)) - return false; - if (!AreEqual(this.reverseModuleImportMap, other.reverseModuleImportMap)) - return false; - if (!AreEqual(this.lastParseResult, other.lastParseResult)) - return false; - return true; - } - - [TestFixture] - private class Test - { - [Test] - public void ExtractSimple() - { - // src\main.rs referenced nothing, we now scan src\foo.rs, which references two empty modules - var reachable = new HashSet(); - var roots = new HashSet() { @"C:\dev\app\src\main.rs", @"C:\dev\app\src\foo.rs" }; - var importPath = @"C:\dev\app\src\foo.rs"; - var imports = new ModuleImport() - { - { new PathSegment("bar.rs", true), new ModuleImport() }, - { new PathSegment("baz.rs", true), new ModuleImport() } - }; - var tracker = new ModuleTracker(@"C:\dev\app\src\main.rs"); - tracker.ExtractReachableModules(new Dictionary>(), reachable, key => roots.Contains(key), importPath, (s) => s.EndsWith("foo.rs") ? imports : new ModuleImport()); - Assert.AreEqual(2, reachable.Count); - Assert.True(reachable.Contains(@"C:\dev\app\src\bar.rs")); - Assert.True(reachable.Contains(@"C:\dev\app\src\baz.rs")); - Assert.AreEqual(1, tracker.moduleImportMap.Count); - Assert.AreEqual(2, tracker.moduleImportMap[@"C:\dev\app\src\foo.rs"].Count); - CollectionAssert.Contains(tracker.moduleImportMap[@"C:\dev\app\src\foo.rs"], @"C:\dev\app\src\bar.rs"); - CollectionAssert.Contains(tracker.moduleImportMap[@"C:\dev\app\src\foo.rs"], @"C:\dev\app\src\baz.rs"); - } - - - [Test] - public void ExtractNested() - { - // src\main.rs referenced nothing, we now scan src\foo.rs, which references three modules - var reachable = new HashSet(); - var roots = new HashSet() { @"C:\dev\app\src\main.rs", @"C:\dev\app\src\foo.rs", @"C:\dev\app\src\bar.rs" }; - var importPath = @"C:\dev\app\src\foo.rs"; - var imports = new ModuleImport() - { - { new PathSegment("bar.rs", true), new ModuleImport() }, - { new PathSegment("baz.rs", true), new ModuleImport() }, - { new PathSegment("frob.rs", true), new ModuleImport() }, - }; - var frobImports = new ModuleImport() - { - { new PathSegment("in1", true), new ModuleImport() { - { new PathSegment("in2.rs", true), new ModuleImport() } - }} - }; - var tracker = new ModuleTracker(@"C:\dev\app\src\main.rs"); - tracker.ExtractReachableModules(new Dictionary>(), reachable, key => roots.Contains(key), importPath, (s) => s.EndsWith("foo.rs") ? imports : s.EndsWith("frob.rs") ? frobImports : new ModuleImport()); - Assert.AreEqual(3, reachable.Count); - Assert.True(reachable.Contains(@"C:\dev\app\src\baz.rs")); - Assert.True(reachable.Contains(@"C:\dev\app\src\frob.rs")); - Assert.True(reachable.Contains(@"C:\dev\app\src\in1\in2.rs")); - Assert.AreEqual(2, tracker.moduleImportMap.Count); - Assert.AreEqual(4, tracker.reverseModuleImportMap.Count); - Assert.AreEqual(3, tracker.moduleImportMap[@"C:\dev\app\src\foo.rs"].Count); - Assert.AreEqual(1, tracker.moduleImportMap[@"C:\dev\app\src\frob.rs"].Count); - CollectionAssert.Contains(tracker.moduleImportMap[@"C:\dev\app\src\foo.rs"], @"C:\dev\app\src\bar.rs"); - CollectionAssert.Contains(tracker.moduleImportMap[@"C:\dev\app\src\foo.rs"], @"C:\dev\app\src\baz.rs"); - CollectionAssert.Contains(tracker.moduleImportMap[@"C:\dev\app\src\foo.rs"], @"C:\dev\app\src\frob.rs"); - CollectionAssert.Contains(tracker.moduleImportMap[@"C:\dev\app\src\frob.rs"], @"C:\dev\app\src\in1\in2.rs"); - } - - [Test] - public void RemoveCircular() - { - var reachable = new HashSet(); - var roots = new HashSet() { @"C:\dev\app\src\main.rs", @"C:\dev\app\src\foo.rs"}; - var imports = new ModuleImport() - { - { new PathSegment("frob.rs", true), new ModuleImport() }, - }; - var frobImports = new ModuleImport() - { - { new PathSegment("in1", true), new ModuleImport() { - { new PathSegment("in2.rs", true), new ModuleImport() } - }} - }; - var in2Imports = new ModuleImport() - { - { new PathSegment("ext1.rs", true), new ModuleImport() }, - { new PathSegment("ext2.rs", true), new ModuleImport() }, - { new PathSegment(@"..\frob.rs", true), new ModuleImport() }, - { new PathSegment(@"..\main.rs", true), new ModuleImport() }, - { new PathSegment(@"..\foo.rs", true), new ModuleImport() }, - }; - var tracker = new ModuleTracker(@"C:\dev\app\src\main.rs"); - foreach(string path in roots) - tracker.AddRootModule(path); - tracker.ExtractReachableAndMakeIncremental(); - var orphanSet = tracker.DeleteModule(@"C:\dev\app\src\in1\in2.rs"); - } - } -#endif - } -} diff --git a/VisualRust.Project/PathSegment.cs b/VisualRust.Project/PathSegment.cs deleted file mode 100644 index cc18159f..00000000 --- a/VisualRust.Project/PathSegment.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace VisualRust.Project -{ - public struct PathSegment - { - public string Name { get; private set; } - // This property is true if the value came from #[path = ...], meaning we - // have actual filename in the Name property - public bool IsAuthorative { get; private set; } - - public PathSegment(string name) - : this(name, false) - { - } - - public PathSegment(string name, bool auth) : this() - { - Name = name; - IsAuthorative = auth; - } - - public override string ToString() - { - return Name; - } - } -} diff --git a/VisualRust.Project/Properties/AssemblyInfo.cs b/VisualRust.Project/Properties/AssemblyInfo.cs deleted file mode 100644 index 2244037b..00000000 --- a/VisualRust.Project/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("VisualRust.Project")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("VisualRust.Project")] -[assembly: AssemblyCopyright("Copyright © 2014")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("0fb99c02-242b-41b0-9ab2-78cb17be3bba")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.1.2.0")] -[assembly: AssemblyFileVersion("0.1.2.0")] - -[assembly: InternalsVisibleTo("VisualRust, PublicKey=00240000048000009400000006020000002400005253413100040000010001007755e184d6da3fe8b941736d1567d465beee5164177fa4517975dc035826e7cb94d733944a9df378cc038429af191f7ca06ddd4a146e6cd5882595030cfcf82b194cec14fe9745368245993236e5059f21a5721c0cad36c71bfa9101f41ac58c39318fdf91b7abf4ae799aa7e3ed5cb79efac57b651eb04c105219cbf1b2b69f")] -#if TEST -[assembly: InternalsVisibleTo("VisualRust.Test.Integration, PublicKey=00240000048000009400000006020000002400005253413100040000010001007755e184d6da3fe8b941736d1567d465beee5164177fa4517975dc035826e7cb94d733944a9df378cc038429af191f7ca06ddd4a146e6cd5882595030cfcf82b194cec14fe9745368245993236e5059f21a5721c0cad36c71bfa9101f41ac58c39318fdf91b7abf4ae799aa7e3ed5cb79efac57b651eb04c105219cbf1b2b69f")] -#endif \ No newline at end of file diff --git a/VisualRust.Project/ResourceDescriptionAttribute.cs b/VisualRust.Project/ResourceDescriptionAttribute.cs deleted file mode 100644 index 3dc3656e..00000000 --- a/VisualRust.Project/ResourceDescriptionAttribute.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace VisualRust.Project -{ - class ResourceDescriptionAttribute : DescriptionAttribute - { - string key; - public ResourceDescriptionAttribute(string key) - { - this.key = key; - } - - public override string Description - { - get - { - return Properties.Resources.ResourceManager.GetString(this.key); - } - } - } -} diff --git a/VisualRust.Project/ResourceDisplayNameAttribute.cs b/VisualRust.Project/ResourceDisplayNameAttribute.cs deleted file mode 100644 index d99116f3..00000000 --- a/VisualRust.Project/ResourceDisplayNameAttribute.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace VisualRust.Project -{ - class ResourceDisplayNameAttribute : DisplayNameAttribute - { - string key; - public ResourceDisplayNameAttribute(string key) - { - this.key = key; - } - - public override string DisplayName - { - get - { - return Properties.Resources.ResourceManager.GetString(this.key); - } - } - } -} diff --git a/VisualRust.Project/Resources/IconList.bmp b/VisualRust.Project/Resources/IconList.bmp deleted file mode 100644 index 51d1ec86..00000000 Binary files a/VisualRust.Project/Resources/IconList.bmp and /dev/null differ diff --git a/VisualRust.Project/Resources/IconList.pdn b/VisualRust.Project/Resources/IconList.pdn deleted file mode 100644 index 76d771e1..00000000 Binary files a/VisualRust.Project/Resources/IconList.pdn and /dev/null differ diff --git a/VisualRust.Project/RustConfigProvider.cs b/VisualRust.Project/RustConfigProvider.cs deleted file mode 100644 index 6f84688a..00000000 --- a/VisualRust.Project/RustConfigProvider.cs +++ /dev/null @@ -1,51 +0,0 @@ -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.Shell.Interop; -using Microsoft.VisualStudioTools.Project; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace VisualRust.Project -{ - class RustConfigProvider : ConfigProvider - { - private CommonProjectNode project; - - public RustConfigProvider(CommonProjectNode proj) - : base(proj) - { - this.project = proj; - } - - public override int GetPlatformNames(uint celt, string[] names, uint[] actual) - { - string[] platforms = GetPropertiesConditionedOn(ProjectFileConstants.Platform); - if (platforms == null || platforms.Length == 0) { - platforms = new string[] { Shared.Environment.DefaultTarget }; - } - return GetPlatforms(celt, names, actual, platforms); - } - - public override int GetSupportedPlatformNames(uint celt, string[] names, uint[] actual) - { - string[] platforms = - new string[] { Shared.Environment.DefaultTarget } - .Union(Shared.Environment.FindInstalledTargets().Select(tt => tt.ToString()) ) - .ToArray(); - return GetPlatforms(celt, names, actual, platforms); - } - - protected override ProjectConfig CreateProjectConfiguration(string configName) - { - return project.MakeConfiguration(configName); - } - - public override int GetCfgProviderProperty(int propid, out object var) - { - var = false; - return VSConstants.S_OK; - } - } -} diff --git a/VisualRust.Project/RustProjectConfig.cs b/VisualRust.Project/RustProjectConfig.cs deleted file mode 100644 index 150bdf2e..00000000 --- a/VisualRust.Project/RustProjectConfig.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using Microsoft.VisualStudio.Shell.Interop; -using Microsoft.VisualStudioTools.Project; -using VisualRust.Project.Configuration; - -namespace VisualRust.Project -{ - class RustProjectConfig : CommonProjectConfig, IVsProjectCfgDebugTypeSelection - { - private MsBuildConfiguration userCfg; - private string debugType; - - public MsBuildConfiguration UserCfg - { - get { return userCfg ?? (userCfg = LoadUserConfiguration()); } - } - - public RustProjectConfig(RustProjectNode project, string configuration) - : base(project, configuration) - { } - - private MsBuildConfiguration LoadUserConfiguration() - { - return new MsBuildConfiguration(((RustProjectNode)this.ProjectMgr).UserConfig, this.ConfigName, "default"); - } - - public void GetDebugTypes(out Array pbstrDebugTypes) - { - pbstrDebugTypes = new[] { Constants.GdbDebugger }; - } - - public void GetDebugTypeName(string bstrDebugType, out string pbstrDebugTypeName) - { - pbstrDebugTypeName = bstrDebugType; - } - - public void GetCurrentDebugType(out string pbstrDebugType) - { - pbstrDebugType = debugType; - } - - public void SetCurrentDebugType(string bstrDebugType) - { - debugType = bstrDebugType; - } - } -} diff --git a/VisualRust.Project/RustProjectFactory.cs b/VisualRust.Project/RustProjectFactory.cs deleted file mode 100644 index c7e9d443..00000000 --- a/VisualRust.Project/RustProjectFactory.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Runtime.InteropServices; -using Microsoft.VisualStudio.Shell; -using Microsoft.VisualStudio.Shell.Interop; -using Microsoft.VisualStudioTools.Project; -using IOleServiceProvider = Microsoft.VisualStudio.OLE.Interop.IServiceProvider; - -namespace VisualRust.Project -{ - [Guid("78C9907C-C22D-4F8D-B13A-49F213FF1631")] - public class RustProjectFactory : ProjectFactory - { - CommonProjectPackage pkg; - public RustProjectFactory(CommonProjectPackage pkg) - : base(pkg) - { - this.pkg = pkg; - } - - internal override ProjectNode CreateProject() - { - RustProjectNode project = new RustProjectNode(this.pkg); - project.SetSite((IOleServiceProvider)((IServiceProvider)this.Package).GetService(typeof(IOleServiceProvider))); - return project; - } - } -} diff --git a/VisualRust.Project/RustProjectLauncher.cs b/VisualRust.Project/RustProjectLauncher.cs deleted file mode 100644 index 37b75d9f..00000000 --- a/VisualRust.Project/RustProjectLauncher.cs +++ /dev/null @@ -1,79 +0,0 @@ -using System; -using System.Diagnostics; -using System.Diagnostics.Eventing.Reader; -using System.IO; -using System.Reflection; -using System.Text; -using System.Text.RegularExpressions; -using System.Xml; -using Microsoft.MIDebugEngine; -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.Shell.Interop; -using Microsoft.VisualStudioTools; -using Microsoft.VisualStudioTools.Project; -using VisualRust.Project.Launcher; -using VisualRust.Shared; - -namespace VisualRust.Project -{ - sealed class RustProjectLauncher : IProjectLauncher - { - private readonly LauncherEnvironment environment; - private readonly Configuration.Debug debugConfig; - - public RustProjectLauncher(RustProjectNode project) - { - Utilities.ArgumentNotNull("project", project); - string currConfig = project.GetProjectProperty(ProjectFileConstants.Configuration); - RustProjectConfig projectConfig = (RustProjectConfig)project.ConfigProvider.GetProjectConfiguration(currConfig); - debugConfig = Configuration.Debug.LoadFrom(new[] { projectConfig.UserCfg }); - if (debugConfig.StartAction == Configuration.StartAction.Project && - project.GetProjectProperty("OutputType") != "exe") - { - throw new InvalidOperationException("A project with an Output Type of Library cannot be started directly."); - } - this.environment = new LauncherEnvironment(project, debugConfig, projectConfig); - } - - public int LaunchProject(bool debug) - { - string startupFilePath; - if (debugConfig.StartAction == Configuration.StartAction.Project) - startupFilePath = GetStartupExecutable(); - else - startupFilePath = debugConfig.ExternalProgram; - return LaunchFile(startupFilePath, debug); - } - - public int LaunchFile(string file, bool debug) - { - if (debugConfig.StartAction == Configuration.StartAction.Project - && !File.Exists(file)) - { - environment.ForceBuild(); - } - IRustProjectLauncher launcher = ChooseLauncher(debug); - launcher.Launch( - file, - debugConfig.CommandLineArgs, - debugConfig.WorkingDir); - return VSConstants.S_OK; - } - - string GetStartupExecutable() - { - return Path.Combine(environment.GetProjectProperty("TargetDir"), environment.GetProjectProperty("TargetFileName")); - } - - private IRustProjectLauncher ChooseLauncher(bool debug) - { - if(!debug) - return new ReleaseLauncher(environment); - TargetTriple triple = environment.GetTargetTriple(); - if(triple != null && triple.Abi == "msvc") - return new MsvcDebugLauncher(environment); - else - return new GnuDebugLauncher(environment, triple); - } - } -} \ No newline at end of file diff --git a/VisualRust.Project/RustProjectNode.cs b/VisualRust.Project/RustProjectNode.cs deleted file mode 100644 index 7dd30e0f..00000000 --- a/VisualRust.Project/RustProjectNode.cs +++ /dev/null @@ -1,546 +0,0 @@ -using Microsoft.VisualStudio; -using Microsoft.VisualStudioTools.Project; -using Microsoft.VisualStudio.Shell.Interop; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Microsoft.VisualStudioTools; -using VisualRust.Project.Configuration.MsBuild; -using OleConstants = Microsoft.VisualStudio.OLE.Interop.Constants; -using VsCommands = Microsoft.VisualStudio.VSConstants.VSStd97CmdID; -using VsCommands2K = Microsoft.VisualStudio.VSConstants.VSStd2KCmdID; -using VisualRust.Shared; -using VisualRust.Cargo; -using System.IO.Abstractions; - -namespace VisualRust.Project -{ - /* - * From the perspective of VisualRust items can be split into five categories: - * # Tracked files (stored in .rsproj) - * ## Module roots with auto-import - * Code files that will automatically include all reference file - * (eg. "mod foo;" inside them adds untracked foo.rs) - * ## Module roots - * Code files with disabled "Automatically track module imports". - * (This distinction is important for module roots with auto-import, - * eg. auto-importing main.rs includes foo.rs with disabled auto-tracking, - * tracking includes of foo.rs should be skipped) - * ## Others - * Other files that have disabled option for auto-tracking. Bitmaps, sql files, docs, etc. - * # Untracked files (not stored in .rsproj, calculated ad-hoc) - * ## Code files that were reached from module roots by automatic tracking - * ## Excluded files - * Nodes that are shown when you press "Show all files" - * Automatically-tracked nodes have priority over excluded files - * Also, items can be in a zombie stated (one way or another item is present in the project - * hierarchy but actual file doesn't exist on disk) - * - * Operations for project items and their behavior: - * # Delete - * ## Module roots with auto-import - * Delete the file, exclude untracked files that depend only on it. - * This might turn the item into a zombified Untracked item. - * ## Module roots, Untracked - * Delete the file. This might turn the item into a zombified Untracked item. - * ## Others - * Simply delete the file and the item - * # Create (new command) - * ## Module roots (with/without auto-tracking), Untracked - * If the file does not exist, create it - * # Include - * ## Untracked - * Convert to a module root with auto-import - * ## Excluded - * Convert to a module root with auto-import - * # Exclude - * ## Module roots with auto-import - * Exclude from the project and exclude all auto-imported references. - * ## Module roots - * Exclude from the project. As a side-effect, this might re-add - * this module as an Untracked item and cascadingly add new Unracked items. - * Surprising, but correct! - * # Disable auto-import - * ## Module roots with auto-import - * Get the list of Untrackd items depending ony on this root, exclude them - * # Enable auto-import - * ## Module roots - * Parse and add newly found Untracked items - */ - class RustProjectNode : CommonProjectNode - { - private ImageHandler handler; - private bool containsEntryPoint; - private FileSystem fs; - - public UserProjectConfig UserConfig { get; private set; } - internal ModuleTracker ModuleTracker { get; private set; } - internal ManifestFile Manifest { get; private set; } - - public RustProjectNode(CommonProjectPackage package) - : base(package, Utilities.GetImageList(new System.Drawing.Bitmap(typeof(RustProjectNode).Assembly.GetManifestResourceStream("VisualRust.Project.Resources.IconList.bmp")))) - { - this.CanFileNodesHaveChilds = false; - this.CanProjectDeleteItems = true; - this.ListenForStartupFileUpdates = false; - this.OnProjectPropertyChanged += ReloadOnOutputChange; - this.fs = new FileSystem(); - } - - void ReloadOnOutputChange(object sender, ProjectPropertyChangedArgs e) - { - if (String.Equals(e.PropertyName, "OutputType", StringComparison.OrdinalIgnoreCase) - && !String.Equals(e.OldValue, e.NewValue, StringComparison.OrdinalIgnoreCase)) - { - TrackedFileNode crateNode = this.GetCrateFileNode(e.OldValue); - if (crateNode != null) - crateNode.IsEntryPoint = false; - int temp; - this.ReloadCore(out temp); - this.GetCrateFileNode(e.NewValue).IsEntryPoint = true; - } - } - - public override System.Guid ProjectGuid - { - get { return typeof(RustProjectFactory).GUID; } - } - - public ImageHandler RustImageHandler - { - get - { - if (null == handler) - { - handler = new ImageHandler(VisualRust.Project.Properties.Resources.IconList); - } - return handler; - } - } - - public override int ImageIndex - { - get { return (int)IconIndex.NoIcon; } - } - - public override object GetIconHandle(bool open) - { - return RustImageHandler.GetIconHandle((int)IconIndex.RustProject); - } - - protected override void Reload(out int canceled) - { - EventTriggeringFlag = ProjectNode.EventTriggering.DoNotTriggerHierarchyEvents | ProjectNode.EventTriggering.DoNotTriggerTrackerEvents; - try - { - ReloadCore(out canceled); - } - finally - { - EventTriggeringFlag = ProjectNode.EventTriggering.TriggerAll; - } - this.SaveMSBuildProjectFile(this.FileName); - EventTriggeringFlag = ProjectNode.EventTriggering.TriggerAll; - } - - public string GetCrateFileNodePath(string outputType) - { - BuildOutputType output = BuildOutputTypeExtension.Parse(outputType); - return fs.Path.Combine(fs.Path.GetDirectoryName(this.FileName), "src", output.ToCrateFile()); - } - - public TrackedFileNode GetCrateFileNode(string outputType) - { - return FindNodeByFullPath(GetCrateFileNodePath(outputType)) as TrackedFileNode; - } - - protected void ReloadCore(out int canceled) - { - string manifestPath = fs.Path.GetFullPath(fs.Path.Combine(this.ProjectFolder, this.BuildProject.GetPropertyValue("ManifestPath"))); - ManifestFile manifestFile = ManifestFile.Create(fs, manifestPath, LoadManifest); - if(manifestFile.Path != null) - this.BuildProject.SetProperty("ManifestPath", CommonUtils.GetRelativeFilePath(this.ProjectFolder, manifestFile.Path)); - if (manifestFile.Manifest == null) - { - canceled = 1; - return; - } - this.Manifest = manifestFile; - this.UserConfig = new UserProjectConfig(this); - string outputType = GetProjectProperty(ProjectFileConstants.OutputType, true); - string entryPoint = GetCrateFileNodePath(outputType); - containsEntryPoint = GetCrateFileNode(outputType) != null; - ModuleTracker = new ModuleTracker(entryPoint); - base.Reload(out canceled); - // This project for some reason doesn't include entrypoint node, add it - if (!containsEntryPoint) - { - HierarchyNode parent = this.CreateFolderNodes(fs.Path.GetDirectoryName(entryPoint), true); - TrackedFileNode node = (TrackedFileNode)this.CreateFileNode(entryPoint); - node.IsEntryPoint = true; - parent.AddChild(node); - } - MarkEntryPointFolders(outputType); - foreach (string file in ModuleTracker.ExtractReachableAndMakeIncremental()) - { - HierarchyNode parent = this.CreateFolderNodes(fs.Path.GetDirectoryName(file), false); - parent.AddChild(CreateUntrackedNode(file)); - } - } - - ManifestLoadResult LoadManifest(string path) - { - string manifestContent; - try - { - manifestContent = fs.File.ReadAllText(path); - } - catch (System.IO.IOException ex) - { - var window = new Controls.OpenManifestErrorWindow(System.Windows.Application.Current.MainWindow, path, new string[] { ex.Message }); - bool? result = window.ShowDialog(); - if (result == false) - { - if(window.Reload) - return LoadManifest(path); - else - return ManifestLoadResult.CreateCancel(path); - } - else - { - return LoadManifest(window.NewManifest); - } - } - ManifestErrors errors; - Manifest manifest = Cargo.Manifest.TryCreate(manifestContent, out errors); - if (manifest == null) - { - var window = new Controls.OpenManifestErrorWindow(System.Windows.Application.Current.MainWindow, path, errors.GetErrors()); - bool? result = window.ShowDialog(); - if (result == false) - { - if(window.Reload) - return LoadManifest(path); - else - return ManifestLoadResult.CreateCancel(path); - } - else - { - return LoadManifest(window.NewManifest); - } - } - return ManifestLoadResult.CreateSuccess(path, manifest); - } - - private void MarkEntryPointFolders(string outputType) - { - HierarchyNode node = GetCrateFileNode(outputType); - while (true) - { - node = node.Parent; - if (!(node is RustFolderNode)) - break; - ((RustFolderNode)node).IsEntryPoint = true; - } - } - - internal void OnNodeDirty(uint id) - { - BaseFileNode dirtyNode = this.NodeFromItemId(id) as BaseFileNode; - if (dirtyNode != null && dirtyNode.GetModuleTracking()) - ReparseFileNode(dirtyNode); - } - - private TrackedFileNode CreateTrackedNode(ProjectElement elm) - { - var node = new TrackedFileNode(this, elm); - if (!ModuleTracker.IsIncremental) - { - ModuleTracker.AddRootModule(node.Url); - } - else - { - HashSet children = ModuleTracker.AddRootModuleIncremental(node.Url); - foreach (string child in children) - { - HierarchyNode parent = this.CreateFolderNodes(fs.Path.GetDirectoryName(child), false); - parent.AddChild(CreateUntrackedNode(child)); - } - } - return node; - } - - private UntrackedFileNode CreateUntrackedNode(string path) - { - var node = new UntrackedFileNode(this, path); - return node; - } - - public override FileNode CreateFileNode(ProjectElement item) - { - if (String.IsNullOrEmpty(item.ItemTypeName)) - return base.CreateFileNode(item); - return CreateTrackedNode(item); - } - - public override FileNode CreateFileNode(string file) - { - ProjectElement item = this.AddFileToMsBuild(file); - return this.CreateFileNode(item); - } - - internal override MsBuildProjectElement AddFileToMsBuild(string file) - { - string itemPath = Microsoft.VisualStudio.Shell.PackageUtilities.MakeRelativeIfRooted(file, this.BaseURI); - System.Diagnostics.Debug.Assert(!fs.Path.IsPathRooted(itemPath), "Cannot add item with full path."); - return this.CreateMsBuildFileItem(itemPath, "File"); - } - - // This functions adds node with data that comes from parsing the .rsproj file - protected override HierarchyNode AddIndependentFileNode(Microsoft.Build.Evaluation.ProjectItem item, HierarchyNode parent) - { - var node = (TrackedFileNode)base.AddIndependentFileNode(item, parent); - if (node.GetModuleTracking()) - { - if (node.Url.Equals(ModuleTracker.EntryPoint, StringComparison.InvariantCultureIgnoreCase)) - { - node.IsEntryPoint = true; - containsEntryPoint = true; - } - } - return node; - } - - protected override NodeProperties CreatePropertiesObject() - { - return new RustProjectNodeProperties(this); - } - - internal void IncludeFileNode(UntrackedFileNode node) - { - string path = node.Url; - ModuleTracker.UpgradeModule(path); - TreeOperations.Replace(this, node, () => CreateFileNode(path)); - } - - internal void ExcludeFileNode(BaseFileNode srcNode) - { - // Ask mod tracker for a professional opinion - string fullPath = srcNode.Url; - ModuleRemovalResult downgradeResult = ModuleTracker.DowngradeModule(fullPath); - if (downgradeResult.IsReferenced) - { - TreeOperations.Replace(this, srcNode, () => CreateUntrackedNode(fullPath)); - } - else - { - foreach (string path in downgradeResult.Orphans) - { - TreeOperations.RemoveSubnodeFromHierarchy(this, path, false); - } - } - } - - internal void DisableAutoImport(BaseFileNode node) - { - var orphans = ModuleTracker.DisableTracking(node.Url); - foreach (string mod in orphans) - { - TreeOperations.RemoveSubnodeFromHierarchy(this, mod, false); - } - } - - internal void EnableAutoImport(BaseFileNode node) - { - var newMods = ModuleTracker.EnableTracking(node.Url); - foreach (string mod in newMods) - { - HierarchyNode parent = this.CreateFolderNodes(fs.Path.GetDirectoryName(mod), false); - parent.AddChild(CreateUntrackedNode(mod)); - } - } - - internal void ReparseFileNode(BaseFileNode n) - { - var diff = ModuleTracker.Reparse(n.Url); - foreach (string mod in diff.Removed) - { - TreeOperations.RemoveSubnodeFromHierarchy(this, mod, false); - } - foreach (string mod in diff.Added) - { - HierarchyNode parent = this.CreateFolderNodes(fs.Path.GetDirectoryName(mod), false); - parent.AddChild(CreateUntrackedNode(mod)); - } - } - - public override int SaveItem(VSSAVEFLAGS saveFlag, string silentSaveAsName, uint itemid, IntPtr docData, out int cancelled) - { - BaseFileNode node = this.NodeFromItemId(itemid) as BaseFileNode; - if (node != null) - { - int result = base.SaveItem(saveFlag, silentSaveAsName, itemid, docData, out cancelled); - if (result == VSConstants.S_OK) - ReparseFileNode(node); - return result; - } - return base.SaveItem(saveFlag, silentSaveAsName, itemid, docData, out cancelled); - } - - protected override ProjectElement AddFolderToMsBuild(string folder, bool createOnDisk = true) - { - if (!createOnDisk) - return new VirtualProjectElement(this, folder); - return base.AddFolderToMsBuild(folder, createOnDisk); - } - - protected internal override FolderNode CreateFolderNode(ProjectElement element) - { - if (element == null) - throw new ArgumentException("element"); - if (element is AllFilesProjectElement || !String.IsNullOrEmpty(element.ItemTypeName)) - return new RustFolderNode(this, element); - else - return new UntrackedFolderNode(this, element); - } - - public override CommonFileNode CreateNonCodeFileNode(ProjectElement item) - { - return new TrackedFileNode(this, item); - } - - public override CommonFileNode CreateCodeFileNode(ProjectElement item) - { - return new TrackedFileNode(this, item); - } - - protected override bool IncludeNonMemberItemInProject(HierarchyNode node) - { - return base.IncludeNonMemberItemInProject(node) - || (node is UntrackedFileNode) - || (node is UntrackedFolderNode); - } - - internal void OnNodeIncluded(TrackedFileNode node) - { - HashSet children = ModuleTracker.AddRootModuleIncremental(node.Url); - foreach (string child in children) - { - HierarchyNode parent = this.CreateFolderNodes(fs.Path.GetDirectoryName(child), false); - parent.AddChild(CreateUntrackedNode(child)); - } - } - - protected override ConfigProvider CreateConfigProvider() - { - return new RustConfigProvider(this); - } - - public override int GetSpecificEditorType(string mkDocument, out Guid guidEditorType) - { - guidEditorType = new Guid(); - return VSConstants.S_OK; - } - - #region Disable "Add references..." - protected override ReferenceContainerNode CreateReferenceContainerNode() - { - return null; - } - - internal override int QueryStatusOnNode(Guid cmdGroup, uint cmd, IntPtr pCmdText, ref QueryStatusResult result) - { - if (cmdGroup == VsMenus.guidStandardCommandSet2K && (VsCommands2K)cmd == VsCommands2K.ADDCOMPONENTS - || cmdGroup == VSConstants.CMDSETID.StandardCommandSet12_guid && (VSConstants.VSStd12CmdID)cmd == VSConstants.VSStd12CmdID.AddReferenceProjectOnly) - { - result |= QueryStatusResult.SUPPORTED | QueryStatusResult.INVISIBLE; - return (int)VSConstants.S_OK; - } - return base.QueryStatusOnNode(cmdGroup, cmd, pCmdText, ref result); - } - - public override int AddProjectReference() - { - return (int)OleConstants.OLECMDERR_E_NOTSUPPORTED; - } - - public override IReferenceContainer GetReferenceContainer() - { - return null; - } - - public override int AddComponent(VSADDCOMPOPERATION dwAddCompOperation, uint cComponents, IntPtr[] rgpcsdComponents, IntPtr hwndDialog, VSADDCOMPRESULT[] pResult) - { - return VSConstants.E_NOTIMPL; - } - #endregion - - // This is OK, because this function is only called by - // ProjectGuid getter, which we override anyway - public override Type GetProjectFactoryType() - { - throw new InvalidOperationException(); - } - - // This is OK, because this function is only called by - // GetSpecificEditorType(...), which we override anyway - public override Type GetEditorFactoryType() - { - throw new InvalidOperationException(); - } - - public override string GetProjectName() - { - return "Rust"; - } - - public override string GetFormatList() - { - return "Rust Project File (*.rsproj)\n*.rsproj"; - } - - public override Type GetGeneralPropertyPageType() - { - return null; - } - - public override Type GetLibraryManagerType() - { - return typeof(object); - } - - public override IProjectLauncher GetLauncher() - { - var defaultLauncher = new RustProjectLauncher(this); - return defaultLauncher; - } - - public override ProjectConfig MakeConfiguration(string activeConfigName) - { - return new RustProjectConfig(this, activeConfigName); - } - - internal override string IssueTrackerUrl - { - get { return "http://github.com/PistonDevelopers/VisualRust/issues"; } - } - - protected override Guid[] GetConfigurationDependentPropertyPages() - { - return new[] { - new Guid(Constants.BuildPropertyPage), - new Guid(Constants.DebugPropertyPage), - }; - } - - protected override Guid[] GetConfigurationIndependentPropertyPages() - { - return new[] { - new Guid(Constants.ApplicationPropertyPage), - new Guid(Constants.TargetOutputsPage), - }; - } - } -} diff --git a/VisualRust.Project/RustProjectNodeProperties.cs b/VisualRust.Project/RustProjectNodeProperties.cs deleted file mode 100644 index 38dec8af..00000000 --- a/VisualRust.Project/RustProjectNodeProperties.cs +++ /dev/null @@ -1,64 +0,0 @@ -using Microsoft.VisualStudio.Shell.Interop; -using Microsoft.VisualStudioTools.Project; -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading.Tasks; -using VisualRust.Cargo; - -namespace VisualRust.Project -{ - [CLSCompliant(false), ComVisible(true)] - public class RustProjectNodeProperties : ProjectNodeProperties - { - public ManifestFile Manifest { get { return ((RustProjectNode)this.Node).Manifest; } } - - internal RustProjectNodeProperties(CommonProjectNode node) - : base(node) - { } - - [Browsable(false)] - public __VSPROJOUTPUTTYPE OutputType - { - get - { - string type = this.Node.ProjectMgr.GetProjectProperty("OutputType"); - if(type.Equals("library", StringComparison.OrdinalIgnoreCase)) - { - return __VSPROJOUTPUTTYPE.VSPROJ_OUTPUTTYPE_LIBRARY; - } - else if (type.Equals("winexe", StringComparison.OrdinalIgnoreCase)) - { - return __VSPROJOUTPUTTYPE.VSPROJ_OUTPUTTYPE_WINEXE; - } - return __VSPROJOUTPUTTYPE.VSPROJ_OUTPUTTYPE_EXE; - } - set - { - string val; - switch (value) - { - case __VSPROJOUTPUTTYPE.VSPROJ_OUTPUTTYPE_WINEXE: - val = "winexe"; - break; - case __VSPROJOUTPUTTYPE.VSPROJ_OUTPUTTYPE_LIBRARY: - val = "library"; - break; - default: - val = "exe"; - break; - } - this.Node.ProjectMgr.SetProjectProperty("OutputType", val); - } - } - - [Browsable(false)] - public string URL - { - get { return Node.ProjectMgr.Url; } - } - } -} diff --git a/VisualRust.Project/TrackedFileNode.cs b/VisualRust.Project/TrackedFileNode.cs deleted file mode 100644 index 9e1cf5ca..00000000 --- a/VisualRust.Project/TrackedFileNode.cs +++ /dev/null @@ -1,120 +0,0 @@ -using Microsoft.VisualStudio; -using Microsoft.VisualStudioTools.Project; -using Microsoft.VisualStudio.OLE.Interop; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using OleConstants = Microsoft.VisualStudio.OLE.Interop.Constants; -using VsCommands = Microsoft.VisualStudio.VSConstants.VSStd97CmdID; -using VsCommands2K = Microsoft.VisualStudio.VSConstants.VSStd2KCmdID; -using System.Diagnostics.Contracts; - -namespace VisualRust.Project -{ - class TrackedFileNode : BaseFileNode - { - private const string ModuleTrackingKey = "AutoImportModules"; - - public bool IsEntryPoint { get; set; } - - public TrackedFileNode(RustProjectNode root, ProjectElement elm) - : base(root, elm, elm.GetMetadata(ProjectFileConstants.Include)) - { - } - - public override int ImageIndex - { - get - { - int baseIdx = base.ImageIndex; - if (baseIdx == (int)ProjectNode.ImageName.MissingFile || baseIdx == (int)ProjectNode.ImageName.ExcludedFile) - return baseIdx; - else if (IsRustFile || GetModuleTracking()) - return (int)IconIndex.NoIcon; - else - return baseIdx; - } - } - - public override object GetIconHandle(bool open) - { - if (IsRustFile || GetModuleTracking()) - return ProjectMgr.RustImageHandler.GetIconHandle((int)IconIndex.RustFile); - return base.GetIconHandle(open); - } - - protected override NodeProperties CreatePropertiesObject() - { - if (this.ItemNode.IsExcluded) - return new ExcludedFileNodeProperties(this); - else - return new FileNodeProperties(this); - } - - private static bool ParseBool(string name) - { - bool retValue; - if (!Boolean.TryParse(name, out retValue)) - return false; - return retValue; - } - - public override bool GetModuleTracking() - { - if (ItemNode.IsExcluded) - return false; - string value = this.ItemNode.GetMetadata(ModuleTrackingKey); - if (String.IsNullOrWhiteSpace(value)) - return true; - bool retValue; - if(!Boolean.TryParse(value, out retValue)) - return true; - return retValue; - } - - public void SetModuleTracking(bool value) - { - if (ItemNode.IsExcluded) - throw new InvalidOperationException(); - this.ItemNode.SetMetadata(ModuleTrackingKey, value.ToString()); - if (value) - this.ProjectMgr.EnableAutoImport(this); - else - this.ProjectMgr.DisableAutoImport(this); - this.ProjectMgr.ReDrawNode(this, UIHierarchyElement.Icon); - } - - internal override int ExcludeFromProject() - { - ((RustProjectNode)this.ProjectMgr).ExcludeFileNode(this); - return VSConstants.S_OK; - } - - protected override bool CanUserMove - { - get { return !IsEntryPoint; } - } - - internal override int IncludeInProject(bool includeChildren) - { - Contract.Assert(this.ItemNode.IsExcluded); - int result = base.IncludeInProject(includeChildren); - ProjectMgr.OnNodeIncluded(this); - return result; - } - - internal override int QueryStatusOnNode(Guid cmdGroup, uint cmd, IntPtr pCmdText, ref QueryStatusResult result) - { - if (cmdGroup == Microsoft.VisualStudioTools.Project.VsMenus.guidStandardCommandSet2K - && (VsCommands2K)cmd == VsCommands2K.INCLUDEINPROJECT - && ItemNode.ItemTypeName == null) - { - result |= QueryStatusResult.NOTSUPPORTED; - return (int)OleConstants.OLECMDERR_E_NOTSUPPORTED; - } - return base.QueryStatusOnNode(cmdGroup, cmd, pCmdText, ref result); - } - } -} diff --git a/VisualRust.Project/TreeOperations.cs b/VisualRust.Project/TreeOperations.cs deleted file mode 100644 index 811dc556..00000000 --- a/VisualRust.Project/TreeOperations.cs +++ /dev/null @@ -1,108 +0,0 @@ -using Microsoft.VisualStudio; -using Microsoft.VisualStudioTools.Project; -using Microsoft.VisualStudio.Shell.Interop; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Diagnostics.Contracts; - -namespace VisualRust.Project -{ - /* - * RustProjectNode was starting to bloat with all kind of - * subnode manipulation functions. - * Most of them has been split here for readability. - */ - static class TreeOperations - { - // Mass delete all sbunodes that were orphaned by the - // removal of a subnode with path `rootPath` - public static void DeleteSubnode(RustProjectNode root, string srcpath) - { - if (root == null) - throw new ArgumentNullException("root"); - if (String.IsNullOrEmpty(srcpath)) - throw new ArgumentException("srcpath"); - - var forRemoval = root.ModuleTracker.DeleteModule(srcpath); - foreach (string path in forRemoval.Orphans) - { - TreeOperations.RemoveSubnodeFromHierarchy(root, path, (!forRemoval.IsReferenced) && path.Equals(srcpath, StringComparison.InvariantCultureIgnoreCase)); - } - } - - private static bool RemoveSubnodeFromHierarchy(RustProjectNode root, HierarchyNode node, bool deleteFromStorage) - { - node.Remove(deleteFromStorage); - return true; - } - - public static bool RemoveSubnodeFromHierarchy(RustProjectNode root, string path, bool deleteFromStorage) - { - if (root == null) - throw new ArgumentNullException("root"); - if (String.IsNullOrEmpty(path)) - throw new ArgumentException("path"); - uint item; - root.ParseCanonicalName(path, out item); - if (item != (uint)VSConstants.VSITEMID.Nil) - { - HierarchyNode node = root.NodeFromItemId(item); - if (node != null) - { - TreeOperations.RemoveSubnodeFromHierarchy(root, node, deleteFromStorage); - return true; - } - } - return false; - } - - private static HierarchyNode ReplaceCore(RustProjectNode root, HierarchyNode old, Func newN, HierarchyNode parent) - { - HierarchyNode newNode = newN(); - while (old.FirstChild != null) - { - HierarchyNode current = old.FirstChild; - root.ProjectMgr.OnItemDeleted(current); - old.RemoveChild(current); - current.ID = root.ProjectMgr.ItemIdMap.Add(current); - newNode.AddChild(current); - } - TreeOperations.RemoveSubnodeFromHierarchy(root, old, false); - parent.AddChild(newNode); - return newNode; - } - - public static void Replace(RustProjectNode root, HierarchyNode old, Func newN) - { - if (root == null) - throw new ArgumentNullException("root"); - if (old == null) - throw new ArgumentNullException("old"); - if (newN == null) - throw new ArgumentNullException("newN"); - __VSHIERARCHYITEMSTATE visualState = old.GetItemState(__VSHIERARCHYITEMSTATE.HIS_Selected | __VSHIERARCHYITEMSTATE.HIS_Expanded); - HierarchyNode parent = old.Parent; - HierarchyNode newNode; - if(parent is UntrackedFolderNode) - { - using(((UntrackedFolderNode)parent).SuspendChildrenTracking()) - { - newNode = ReplaceCore(root, old, newN, parent); - ((UntrackedFolderNode)parent).OnChildReplaced(old, newNode); - } - } - else - { - newNode = ReplaceCore(root, old, newN, parent); - } - if ((visualState & __VSHIERARCHYITEMSTATE.HIS_Expanded) != 0) - newNode.ExpandItem(EXPANDFLAGS.EXPF_ExpandFolder); - if ((visualState & __VSHIERARCHYITEMSTATE.HIS_Selected) != 0) - newNode.ExpandItem(EXPANDFLAGS.EXPF_SelectItem); - } - } -} diff --git a/VisualRust.Project/UntrackedFileNode.cs b/VisualRust.Project/UntrackedFileNode.cs deleted file mode 100644 index 0fab20c8..00000000 --- a/VisualRust.Project/UntrackedFileNode.cs +++ /dev/null @@ -1,68 +0,0 @@ -using Microsoft.VisualStudio; -using Microsoft.VisualStudioTools.Project; -using Microsoft.VisualStudio.Shell; -using Microsoft.VisualStudio.Shell.Interop; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using OleConstants = Microsoft.VisualStudio.OLE.Interop.Constants; -using VsCommands = Microsoft.VisualStudio.VSConstants.VSStd97CmdID; -using VsCommands2K = Microsoft.VisualStudio.VSConstants.VSStd2KCmdID; - -namespace VisualRust.Project -{ - class UntrackedFileNode : BaseFileNode - { - public UntrackedFileNode(RustProjectNode root, string file) - : base(root, new VirtualProjectElement(root, file), file) - { } - - protected override bool CanUserMove - { - get { return false; } - } - - protected override NodeProperties CreatePropertiesObject() - { - return new ReferencedFileNodeProperties(this); - } - - public override int ImageIndex { get { return (int)IconIndex.NoIcon; } } - - public override object GetIconHandle(bool open) - { - if(!System.IO.File.Exists(this.Url)) - return this.ProjectMgr.RustImageHandler.GetIconHandle((int)IconIndex.ZombieUntrackedRustFile); - else - return this.ProjectMgr.RustImageHandler.GetIconHandle((int)IconIndex.UntrackedRustFile); - } - - internal override int ExecCommandOnNode(Guid cmdGroup, uint cmd, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) - { - if (cmdGroup == Microsoft.VisualStudioTools.Project.VsMenus.guidStandardCommandSet2K && (VsCommands2K)cmd == VsCommands2K.INCLUDEINPROJECT) - { - ((RustProjectNode)this.ProjectMgr).IncludeFileNode(this); - return VSConstants.S_OK; - } - return base.ExecCommandOnNode(cmdGroup, cmd, nCmdexecopt, pvaIn, pvaOut); - } - - internal override int QueryStatusOnNode(Guid cmdGroup, uint cmd, IntPtr pCmdText, ref QueryStatusResult result) - { - if (cmdGroup == Microsoft.VisualStudioTools.Project.VsMenus.guidStandardCommandSet2K - && (VsCommands2K)cmd == VsCommands2K.INCLUDEINPROJECT) - { - result |= QueryStatusResult.SUPPORTED | QueryStatusResult.ENABLED; - return (int)VSConstants.S_OK; - } - return base.QueryStatusOnNode(cmdGroup, cmd, pCmdText, ref result); - } - - public override bool GetModuleTracking() - { - return true; - } - } -} diff --git a/VisualRust.Project/UntrackedFolderNode.cs b/VisualRust.Project/UntrackedFolderNode.cs deleted file mode 100644 index 6df9e536..00000000 --- a/VisualRust.Project/UntrackedFolderNode.cs +++ /dev/null @@ -1,104 +0,0 @@ -using Microsoft.VisualStudioTools.Project; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace VisualRust.Project -{ - /* - * Sometimes, untracked nodes (automatically imported code files) will - * materialize in subfolders. - * Eg. main.rs: "mod foo { mod bar; }" will bring file foo\bar.rs into - * the project. This means that we need to add a folder to the project. - * Those temporary folder follow simple logic: - * # They are created first time untracked file is created inside them - * (logic for that is contained inside ProjectNode and RustProjectNode) - * # If any of its subnodes changes from untracked to tracked, it - * changes to tracked (note that the reverse operation, change from - * tracked to untracked, does nothing!) - * # If tracked node is added it gets changes to tracked - * # If all its nodes are removed from the project, it gets removed too - */ - class UntrackedFolderNode : CommonFolderNode - { - - private class SuspendChildrenTrackingCookie : IDisposable - { - private UntrackedFolderNode node; - - public SuspendChildrenTrackingCookie(UntrackedFolderNode node) - { - this.node = node; - this.node.suspendTracking = true; - } - public void Dispose() - { - this.node.suspendTracking = false; - } - } - - private bool suspendTracking = false; - private int untrackedChildren = 0; - public new RustProjectNode ProjectMgr { get; private set; } - - public UntrackedFolderNode(RustProjectNode root, ProjectElement elm) - : base(root, elm) - { - ProjectMgr = root; - } - - public override int ImageIndex { get { return (int)IconIndex.NoIcon; } } - - public override object GetIconHandle(bool open) - { - return ProjectMgr.RustImageHandler.GetIconHandle((int)(open ? IconIndex.UntrackedFolderOpen : IconIndex.UntrackedFolder)); - } - - public override void AddChild(HierarchyNode node) - { - base.AddChild(node); - if (suspendTracking || node.ItemNode.ItemTypeName == null) - return; - if (node is UntrackedFileNode || node is UntrackedFolderNode) - untrackedChildren++; - else - ReplaceWithTracked(); - } - - private void ReplaceWithTracked() - { - TreeOperations.Replace(this.ProjectMgr, this, () => this.ProjectMgr.CreateFolderNode(this.Url)); - } - - private void DecrementTrackedCount() - { - untrackedChildren--; - if (untrackedChildren == 0) - this.Remove(false); - } - - public override void RemoveChild(HierarchyNode node) - { - base.RemoveChild(node); - if (!suspendTracking && (node is UntrackedFileNode || node is UntrackedFolderNode)) - { - DecrementTrackedCount(); - } - } - - public IDisposable SuspendChildrenTracking() - { - return new SuspendChildrenTrackingCookie(this); - } - - internal void OnChildReplaced(HierarchyNode old, HierarchyNode @new) - { - if (old.Parent != @new.Parent) - return; - if(@new is TrackedFileNode || @new is FolderNode) - ReplaceWithTracked(); - } - } -} diff --git a/VisualRust.Project/VisualRust.Project.csproj b/VisualRust.Project/VisualRust.Project.csproj deleted file mode 100644 index e31848ed..00000000 --- a/VisualRust.Project/VisualRust.Project.csproj +++ /dev/null @@ -1,350 +0,0 @@ - - - - - - Debug - AnyCPU - {475C4DF2-4D4B-4F2C-9F27-414148DD6F11} - Library - Properties - VisualRust.Project - VisualRust.Project - True - ..\VisualRust\Key.snk - v4.5 - - - true - full - false - bin\Debug\ - TRACE;DEBUG;TEST - prompt - 4 - 3021 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - 3021 - - - OnBuildSuccess - - - true - bin\Debug-CI\ - TRACE;DEBUG;TEST - 3021 - full - AnyCPU - prompt - - - - ..\packages\Antlr4.Runtime.4.3.0\lib\net45\Antlr4.Runtime.net45.dll - - - False - ..\packages\VSSDK.DTE.7.0.4\lib\net20\envdte.dll - False - - - False - ..\packages\VSSDK.DTE.8.8.0.4\lib\net20\envdte80.dll - False - - - - ..\packages\VSSDK.GraphModel.11.0.4\lib\net45\Microsoft.VisualStudio.GraphModel.dll - False - - - ..\packages\VSSDK.OLE.Interop.7.0.4\lib\net20\Microsoft.VisualStudio.OLE.Interop.dll - False - - - ..\packages\VSSDK.Shell.12.12.0.4\lib\net45\Microsoft.VisualStudio.Shell.12.0.dll - False - - - ..\packages\VSSDK.Shell.Immutable.10.10.0.4\lib\net40\Microsoft.VisualStudio.Shell.Immutable.10.0.dll - False - - - ..\packages\VSSDK.Shell.Immutable.11.11.0.4\lib\net45\Microsoft.VisualStudio.Shell.Immutable.11.0.dll - False - - - ..\packages\VSSDK.Shell.Immutable.12.12.0.4\lib\net45\Microsoft.VisualStudio.Shell.Immutable.12.0.dll - False - - - ..\packages\VSSDK.Shell.Interop.7.0.4\lib\net20\Microsoft.VisualStudio.Shell.Interop.dll - False - - - False - ..\packages\VSSDK.Shell.Interop.10.10.0.4\lib\net20\Microsoft.VisualStudio.Shell.Interop.10.0.dll - False - - - False - ..\packages\VSSDK.Shell.Interop.11.11.0.4\lib\net20\Microsoft.VisualStudio.Shell.Interop.11.0.dll - False - - - ..\packages\VSSDK.Shell.Interop.8.8.0.4\lib\net20\Microsoft.VisualStudio.Shell.Interop.8.0.dll - False - - - ..\packages\VSSDK.Shell.Interop.9.9.0.4\lib\net20\Microsoft.VisualStudio.Shell.Interop.9.0.dll - False - - - ..\packages\VSSDK.TextManager.Interop.7.0.4\lib\net20\Microsoft.VisualStudio.TextManager.Interop.dll - False - - - ..\packages\VSSDK.TextManager.Interop.8.8.0.4\lib\net20\Microsoft.VisualStudio.TextManager.Interop.8.0.dll - False - - - ..\packages\VSSDK.Threading.12.0.4\lib\net45\Microsoft.VisualStudio.Threading.dll - False - - - ..\packages\NUnit.2.6.3\lib\nunit.framework.dll - - - - - False - ..\packages\VSSDK.DTE.7.0.4\lib\net20\stdole.dll - False - - - - - - - - ..\packages\System.IO.Abstractions.2.0.0.124\lib\net40\System.IO.Abstractions.dll - True - - - - - - - - - - - - - Application.tt - True - True - - - - - - True - True - Debug.tt - - - - - - - True - True - Build.tt - - - - - - - - - - - - - - - PickTargetOutputTypeWindow.xaml - - - OpenManifestErrorWindow.xaml - - - OutputPage.xaml - - - - - - - - - - - - - - - - - - - - UserControl - - - UserControl - - - usercontrol - - - DebugPropertyControl.cs - - - - - - - - - - - - PreserveNewest - - - - - - PreserveNewest - - - True - True - Resources.resx - - - - - - - - - - - - - {cacb60a9-1e76-4f92-8831-b134a658c695} - Microsoft.VisualStudio.Project - - - {12cc862d-95b7-4224-8e16-b928c6333677} - MICore - - - {6D2688FE-6FD8-44A8-B96A-6037457F72A7} - MIDebugEngine - - - {2594DB0D-03FF-40EA-8D27-9930E5D3FF83} - VisualRust.Cargo - - - {b99cc9eb-90f2-4040-9e66-418cc7042153} - VisualRust.Shared - - - - - MSBuild:Compile - VisualRust.Project - - - - - - - DebugPropertyControl.cs - - - ResXFileCodeGenerator - Resources.Designer.cs - - - - - - - - - - - - - - TextTemplatingFileGenerator - Application.cs - - - TextTemplatingFileGenerator - Build.cs - - - TextTemplatingFileGenerator - Debug.cs - - - - - MSBuild:Compile - Designer - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - - - \ No newline at end of file diff --git a/VisualRust.Project/app.config b/VisualRust.Project/app.config deleted file mode 100644 index 4a1c0bf1..00000000 --- a/VisualRust.Project/app.config +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/VisualRust.Project/packages.config b/VisualRust.Project/packages.config deleted file mode 100644 index 998b7e98..00000000 --- a/VisualRust.Project/packages.config +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/VisualRust.ProjectSystem.FileSystemMirroring/Extensions/ProjectTreeExtensions.cs b/VisualRust.ProjectSystem.FileSystemMirroring/Extensions/ProjectTreeExtensions.cs new file mode 100644 index 00000000..3ddab69a --- /dev/null +++ b/VisualRust.ProjectSystem.FileSystemMirroring/Extensions/ProjectTreeExtensions.cs @@ -0,0 +1,90 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System.Collections.Generic; +using System.Collections.Immutable; +using System.IO; +using System.Linq; +using Microsoft.VisualStudio.ProjectSystem; +#if VS14 +using Microsoft.VisualStudio.ProjectSystem.Designers; +using Microsoft.VisualStudio.ProjectSystem.Utilities.Designers; +#endif +#if VS15 +using Microsoft.VisualStudio.ProjectSystem; +#endif + +namespace VisualRust.ProjectSystem.FileSystemMirroring { + public static class ProjectTreeExtensions { + public static bool IsProjectSelected(this IImmutableSet nodes) { + return nodes != null && nodes.Count == 1 && nodes.First().Root == nodes.First(); + } + + public static string GetSingleNodePath(this IImmutableSet nodes) { + if (nodes != null && nodes.Count == 1) { + return nodes.First().FilePath; + } + return string.Empty; + } + + public static bool IsSingleNodePath(this IImmutableSet nodes) { + return !string.IsNullOrEmpty(GetSingleNodePath(nodes)); + } + + public static bool IsFolder(this IImmutableSet nodes) { + if (nodes != null && nodes.Count == 1) { + return nodes.First().IsFolder; + } + return false; + } + + public static string GetNodeFolderPath(this IImmutableSet nodes) { + var path = nodes.GetSingleNodePath(); + if (!string.IsNullOrEmpty(path)) { + if (Directory.Exists(path)) { + return path; + } else if (File.Exists(path)) { + return Path.GetDirectoryName(path); + } + } + return string.Empty; + } + + public static IEnumerable GetSelectedNodesPaths(this IImmutableSet nodes) { + if (nodes != null && nodes.Count > 0) { + return nodes.Where(x => !string.IsNullOrEmpty(x?.FilePath)).Select(x => x.FilePath); + } + return Enumerable.Empty(); + } + + public static IEnumerable GetSelectedFilesPaths(this IImmutableSet nodes) { + if (nodes != null && nodes.Count > 0) { + return nodes.Where(x => !x.IsFolder && !string.IsNullOrEmpty(x?.FilePath)).Select(x => x.FilePath); + } + return Enumerable.Empty(); + } + + public static IEnumerable GetAllFilePaths(this IEnumerable nodes) { + List paths = new List(); + foreach (IProjectTree node in nodes) { + if (node.IsFolder || node.Children.Count > 0) { + paths.AddRange(node.Children.GetAllFilePaths()); + } else if (!string.IsNullOrWhiteSpace(node.FilePath)) { + paths.Add(node.FilePath); + } + } + return paths.Distinct(); + } + + public static string GetSelectedFolderPath(this IImmutableSet nodes, UnconfiguredProject unconfiguredProject) { + if (nodes.Count == 1) { + var n = nodes.First(); + if (n.IsRoot()) { + return Path.GetDirectoryName(unconfiguredProject.FullPath); + } + return nodes.GetNodeFolderPath(); + } + return string.Empty; + } + } +} diff --git a/VisualRust.ProjectSystem.FileSystemMirroring/IO/IMsBuildFileSystemFilter.cs b/VisualRust.ProjectSystem.FileSystemMirroring/IO/IMsBuildFileSystemFilter.cs new file mode 100644 index 00000000..6cc8294a --- /dev/null +++ b/VisualRust.ProjectSystem.FileSystemMirroring/IO/IMsBuildFileSystemFilter.cs @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System.IO; + +namespace VisualRust.ProjectSystem.FileSystemMirroring.IO { + public interface IMsBuildFileSystemFilter { + bool IsFileAllowed(string relativePath, FileAttributes attributes); + bool IsDirectoryAllowed(string relativePath, FileAttributes attributes); + void Seal(); + } +} \ No newline at end of file diff --git a/VisualRust.ProjectSystem.FileSystemMirroring/IO/MsBuildFileSystemWatcher.AttributesChanged.cs b/VisualRust.ProjectSystem.FileSystemMirroring/IO/MsBuildFileSystemWatcher.AttributesChanged.cs new file mode 100644 index 00000000..8e11be2d --- /dev/null +++ b/VisualRust.ProjectSystem.FileSystemMirroring/IO/MsBuildFileSystemWatcher.AttributesChanged.cs @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +namespace VisualRust.ProjectSystem.FileSystemMirroring.IO { + public sealed partial class MsBuildFileSystemWatcher { + private class AttributesChanged : IFileSystemChange { + private readonly MsBuildFileSystemWatcherEntries _entries; + private readonly string _name; + private readonly string _fullPath; + + public AttributesChanged(MsBuildFileSystemWatcherEntries entries, string name, string fullPath) { + _entries = entries; + _name = name; + _fullPath = fullPath; + } + + public void Apply() { } + } + } +} \ No newline at end of file diff --git a/VisualRust.ProjectSystem.FileSystemMirroring/IO/MsBuildFileSystemWatcher.DirectoryCreated.cs b/VisualRust.ProjectSystem.FileSystemMirroring/IO/MsBuildFileSystemWatcher.DirectoryCreated.cs new file mode 100644 index 00000000..da8a5d06 --- /dev/null +++ b/VisualRust.ProjectSystem.FileSystemMirroring/IO/MsBuildFileSystemWatcher.DirectoryCreated.cs @@ -0,0 +1,83 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System.IO; +using System.Collections.Generic; +using Microsoft.Common.Core; +using Microsoft.Common.Core.IO; +using VisualRust.ProjectSystem.FileSystemMirroring.Utilities; +#if VS14 +using Microsoft.VisualStudio.ProjectSystem.Utilities; +#endif +using static System.FormattableString; + +namespace VisualRust.ProjectSystem.FileSystemMirroring.IO { + public sealed partial class MsBuildFileSystemWatcher { + private class DirectoryCreated : IFileSystemChange { + private readonly MsBuildFileSystemWatcherEntries _entries; + private readonly string _rootDirectory; + private readonly IFileSystem _fileSystem; + private readonly IMsBuildFileSystemFilter _fileSystemFilter; + private readonly string _directoryFullPath; + + public DirectoryCreated(MsBuildFileSystemWatcherEntries entries, string rootDirectory, IFileSystem fileSystem, IMsBuildFileSystemFilter fileSystemFilter, string directoryFullPath) { + _entries = entries; + _rootDirectory = rootDirectory; + _fileSystem = fileSystem; + _fileSystemFilter = fileSystemFilter; + _directoryFullPath = directoryFullPath; + } + + public void Apply() { + if (!_directoryFullPath.StartsWithIgnoreCase(_rootDirectory)) { + return; + } + + Queue directories = new Queue(); + directories.Enqueue(_directoryFullPath); + + while (directories.Count > 0) { + var directoryPath = directories.Dequeue(); + var directory = _fileSystem.GetDirectoryInfo(directoryPath); + var relativeDirectoryPath = PathHelper.MakeRelative(_rootDirectory, directoryPath); + + if (!directory.Exists) { + continue; + } + + // We don't want to add root directory + if (!string.IsNullOrEmpty(relativeDirectoryPath)) { + relativeDirectoryPath = PathHelper.EnsureTrailingSlash(relativeDirectoryPath); + + // We don't add symlinks + if (directory.Attributes.HasFlag(FileAttributes.ReparsePoint)) { + continue; + } + + if (!_fileSystemFilter.IsDirectoryAllowed(relativeDirectoryPath, directory.Attributes)) { + continue; + } + + _entries.AddDirectory(relativeDirectoryPath, _fileSystem.ToShortRelativePath(directoryPath, _rootDirectory)); + } + + foreach (var entry in directory.EnumerateFileSystemInfos()) { + if (entry is IDirectoryInfo) { + directories.Enqueue(entry.FullName); + } else { + var relativeFilePath = PathHelper.MakeRelative(_rootDirectory, entry.FullName); + + if (_fileSystemFilter.IsFileAllowed(relativeFilePath, entry.Attributes)) { + _entries.AddFile(relativeFilePath, _fileSystem.ToShortRelativePath(entry.FullName, _rootDirectory)); + } + } + } + } + } + + public override string ToString() { + return Invariant($"Directory created: {_directoryFullPath}"); + } + } + } +} \ No newline at end of file diff --git a/VisualRust.ProjectSystem.FileSystemMirroring/IO/MsBuildFileSystemWatcher.DirectoryDeleted.cs b/VisualRust.ProjectSystem.FileSystemMirroring/IO/MsBuildFileSystemWatcher.DirectoryDeleted.cs new file mode 100644 index 00000000..72e406be --- /dev/null +++ b/VisualRust.ProjectSystem.FileSystemMirroring/IO/MsBuildFileSystemWatcher.DirectoryDeleted.cs @@ -0,0 +1,37 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using Microsoft.Common.Core; +#if VS14 +using Microsoft.VisualStudio.ProjectSystem.Utilities; +#endif +using static System.FormattableString; + +namespace VisualRust.ProjectSystem.FileSystemMirroring.IO { + public sealed partial class MsBuildFileSystemWatcher { + private class DirectoryDeleted : IFileSystemChange { + private readonly MsBuildFileSystemWatcherEntries _entries; + private readonly string _rootDirectory; + private readonly string _fullPath; + + public DirectoryDeleted(MsBuildFileSystemWatcherEntries entries, string rootDirectory, string fullPath) { + _entries = entries; + _rootDirectory = rootDirectory; + _fullPath = fullPath; + } + + public void Apply() { + if (!_fullPath.StartsWithIgnoreCase(_rootDirectory)) { + return; + } + + var relativePath = PathHelper.MakeRelative(_rootDirectory, _fullPath); + _entries.DeleteDirectory(relativePath); + } + + public override string ToString() { + return Invariant($"Directory deleted: {_fullPath}"); + } + } + } +} \ No newline at end of file diff --git a/VisualRust.ProjectSystem.FileSystemMirroring/IO/MsBuildFileSystemWatcher.DirectoryRenamed.cs b/VisualRust.ProjectSystem.FileSystemMirroring/IO/MsBuildFileSystemWatcher.DirectoryRenamed.cs new file mode 100644 index 00000000..132a1856 --- /dev/null +++ b/VisualRust.ProjectSystem.FileSystemMirroring/IO/MsBuildFileSystemWatcher.DirectoryRenamed.cs @@ -0,0 +1,60 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using Microsoft.Common.Core; +using Microsoft.Common.Core.IO; +using VisualRust.ProjectSystem.FileSystemMirroring.Utilities; +#if VS14 +using Microsoft.VisualStudio.ProjectSystem.Utilities; +#endif +using static System.FormattableString; + +namespace VisualRust.ProjectSystem.FileSystemMirroring.IO { + public sealed partial class MsBuildFileSystemWatcher { + private class DirectoryRenamed : IFileSystemChange { + private readonly MsBuildFileSystemWatcherEntries _entries; + private readonly string _rootDirectory; + private readonly IFileSystem _fileSystem; + private readonly IMsBuildFileSystemFilter _fileSystemFilter; + private readonly string _oldFullPath; + private readonly string _fullPath; + + public DirectoryRenamed(MsBuildFileSystemWatcherEntries entries, string rootDirectory, IFileSystem fileSystem, IMsBuildFileSystemFilter fileSystemFilter, string oldFullPath, string fullPath) { + _entries = entries; + _rootDirectory = rootDirectory; + _fileSystem = fileSystem; + _fileSystemFilter = fileSystemFilter; + _oldFullPath = oldFullPath; + _fullPath = fullPath; + } + + public void Apply() { + if (!_fullPath.StartsWithIgnoreCase(_rootDirectory)) { + DeleteInsteadOfRename(); + return; + } + + var newDirectoryInfo = _fileSystem.GetDirectoryInfo(_fullPath); + var newRelativePath = PathHelper.EnsureTrailingSlash(PathHelper.MakeRelative(_rootDirectory, _fullPath)); + if (!newDirectoryInfo.Exists || !_fileSystemFilter.IsDirectoryAllowed(newRelativePath, newDirectoryInfo.Attributes)) { + DeleteInsteadOfRename(); + return; + } + + var oldRelativePath = PathHelper.MakeRelative(_rootDirectory, _oldFullPath); + var newRelativePaths = _entries.RenameDirectory(oldRelativePath, newRelativePath, _fileSystem.ToShortRelativePath(_fullPath, _rootDirectory)); + } + + private void DeleteInsteadOfRename() { + if (!_oldFullPath.StartsWithIgnoreCase(_rootDirectory)) { + return; + } + _entries.DeleteDirectory(PathHelper.MakeRelative(_rootDirectory, _fullPath)); + } + + public override string ToString() { + return Invariant($"Directory renamed: {_oldFullPath} -> {_fullPath}"); + } + } + } +} \ No newline at end of file diff --git a/VisualRust.ProjectSystem.FileSystemMirroring/IO/MsBuildFileSystemWatcher.FileCreated.cs b/VisualRust.ProjectSystem.FileSystemMirroring/IO/MsBuildFileSystemWatcher.FileCreated.cs new file mode 100644 index 00000000..aba67c24 --- /dev/null +++ b/VisualRust.ProjectSystem.FileSystemMirroring/IO/MsBuildFileSystemWatcher.FileCreated.cs @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using Microsoft.Common.Core.IO; +using VisualRust.ProjectSystem.FileSystemMirroring.Utilities; +using static System.FormattableString; + +namespace VisualRust.ProjectSystem.FileSystemMirroring.IO { + public sealed partial class MsBuildFileSystemWatcher { + private class FileCreated : IFileSystemChange { + private readonly MsBuildFileSystemWatcherEntries _entries; + private readonly string _rootDirectory; + private readonly IFileSystem _fileSystem; + private readonly IMsBuildFileSystemFilter _fileSystemFilter; + private readonly string _fullPath; + + public FileCreated(MsBuildFileSystemWatcherEntries entries, string rootDirectory, IFileSystem fileSystem, IMsBuildFileSystemFilter fileSystemFilter, string fullPath) { + _entries = entries; + _rootDirectory = rootDirectory; + _fileSystem = fileSystem; + _fileSystemFilter = fileSystemFilter; + _fullPath = fullPath; + } + + public void Apply() { + string relativePath; + string shortRelativePath; + if (IsFileAllowed(_rootDirectory, _fullPath, _fileSystem, _fileSystemFilter, out relativePath, out shortRelativePath)) { + _entries.AddFile(relativePath, shortRelativePath); + } + } + + public override string ToString() { + return Invariant($"File created: {_fullPath}"); + } + } + } +} \ No newline at end of file diff --git a/VisualRust.ProjectSystem.FileSystemMirroring/IO/MsBuildFileSystemWatcher.FileDeleted.cs b/VisualRust.ProjectSystem.FileSystemMirroring/IO/MsBuildFileSystemWatcher.FileDeleted.cs new file mode 100644 index 00000000..1b5fd862 --- /dev/null +++ b/VisualRust.ProjectSystem.FileSystemMirroring/IO/MsBuildFileSystemWatcher.FileDeleted.cs @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using Microsoft.Common.Core; +using VisualRust.ProjectSystem.FileSystemMirroring.Utilities; +#if VS14 +using Microsoft.VisualStudio.ProjectSystem.Utilities; +#endif +using static System.FormattableString; + +namespace VisualRust.ProjectSystem.FileSystemMirroring.IO { + public sealed partial class MsBuildFileSystemWatcher { + private class FileDeleted : IFileSystemChange { + private readonly MsBuildFileSystemWatcherEntries _entries; + private readonly string _rootDirectory; + private readonly string _fullPath; + + public FileDeleted(MsBuildFileSystemWatcherEntries entries, string rootDirectory, string fullPath) { + _entries = entries; + _rootDirectory = rootDirectory; + _fullPath = fullPath; + } + + public void Apply() { + if (!_fullPath.StartsWithIgnoreCase(_rootDirectory)) { + return; + } + + var relativePath = PathHelper.MakeRelative(_rootDirectory, _fullPath); + _entries.DeleteFile(relativePath); + } + + public override string ToString() { + return Invariant($"File deleted: {_fullPath}"); + } + } + } +} \ No newline at end of file diff --git a/VisualRust.ProjectSystem.FileSystemMirroring/IO/MsBuildFileSystemWatcher.FileRenamed.cs b/VisualRust.ProjectSystem.FileSystemMirroring/IO/MsBuildFileSystemWatcher.FileRenamed.cs new file mode 100644 index 00000000..2026fc75 --- /dev/null +++ b/VisualRust.ProjectSystem.FileSystemMirroring/IO/MsBuildFileSystemWatcher.FileRenamed.cs @@ -0,0 +1,55 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using Microsoft.Common.Core; +using Microsoft.Common.Core.IO; +using VisualRust.ProjectSystem.FileSystemMirroring.Utilities; +#if VS14 +using Microsoft.VisualStudio.ProjectSystem.Utilities; +#endif +using static System.FormattableString; + +namespace VisualRust.ProjectSystem.FileSystemMirroring.IO { + public sealed partial class MsBuildFileSystemWatcher { + private class FileRenamed : IFileSystemChange { + private readonly MsBuildFileSystemWatcherEntries _entries; + private readonly string _rootDirectory; + private readonly IFileSystem _fileSystem; + private readonly IMsBuildFileSystemFilter _fileSystemFilter; + private readonly string _oldFullPath; + private readonly string _fullPath; + + public FileRenamed(MsBuildFileSystemWatcherEntries entries, string rootDirectory, IFileSystem fileSystem, IMsBuildFileSystemFilter fileSystemFilter, string oldFullPath, string fullPath) { + _entries = entries; + _rootDirectory = rootDirectory; + _fileSystem = fileSystem; + _fileSystemFilter = fileSystemFilter; + _oldFullPath = oldFullPath; + _fullPath = fullPath; + } + + public void Apply() { + string newRelativePath; + string newShortRelativePath; + if (!_oldFullPath.StartsWithIgnoreCase(_rootDirectory)) { + if (IsFileAllowed(_rootDirectory, _fullPath, _fileSystem, _fileSystemFilter, out newRelativePath, out newShortRelativePath)) { + _entries.AddFile(newRelativePath, newShortRelativePath); + } + + return; + } + + var oldRelativePath = PathHelper.MakeRelative(_rootDirectory, _oldFullPath); + if (IsFileAllowed(_rootDirectory, _fullPath, _fileSystem, _fileSystemFilter, out newRelativePath, out newShortRelativePath)) { + _entries.RenameFile(oldRelativePath, newRelativePath, newShortRelativePath); + } else { + _entries.DeleteFile(oldRelativePath); + } + } + + public override string ToString() { + return Invariant($"File renamed: {_oldFullPath} -> {_fullPath}"); + } + } + } +} \ No newline at end of file diff --git a/VisualRust.ProjectSystem.FileSystemMirroring/IO/MsBuildFileSystemWatcher.cs b/VisualRust.ProjectSystem.FileSystemMirroring/IO/MsBuildFileSystemWatcher.cs new file mode 100644 index 00000000..a499e1f3 --- /dev/null +++ b/VisualRust.ProjectSystem.FileSystemMirroring/IO/MsBuildFileSystemWatcher.cs @@ -0,0 +1,256 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using System.Threading.Tasks.Dataflow; +using Microsoft.Common.Core; +using Microsoft.Common.Core.IO; +using Microsoft.Common.Core.Logging; +using Microsoft; +using VisualRust.ProjectSystem.FileSystemMirroring.Logging; +using VisualRust.ProjectSystem.FileSystemMirroring.Utilities; + +#if VS14 +using Microsoft.VisualStudio.ProjectSystem.Utilities; +#endif +using static System.FormattableString; + +namespace VisualRust.ProjectSystem.FileSystemMirroring.IO { + public sealed partial class MsBuildFileSystemWatcher : IDisposable { + private readonly string _directory; + private readonly string _filter; + private readonly MsBuildFileSystemWatcherEntries _entries; + private readonly ConcurrentQueue _queue; + private readonly int _delayMilliseconds; + private readonly int _recoveryDelayMilliseconds; + private readonly IFileSystem _fileSystem; + private readonly IMsBuildFileSystemFilter _fileSystemFilter; + private readonly TaskScheduler _taskScheduler; + private readonly BroadcastBlock _broadcastBlock; + private readonly IActionLog _log; + private IFileSystemWatcher _fileWatcher; + private IFileSystemWatcher _directoryWatcher; + private IFileSystemWatcher _attributesWatcher; + private int _consumerIsWorking; + private int _hasErrors; + + public IReceivableSourceBlock SourceBlock { get; } + public event EventHandler Error; + + public MsBuildFileSystemWatcher(string directory, string filter, int delayMilliseconds, int recoveryDelayMilliseconds, IFileSystem fileSystem, IMsBuildFileSystemFilter fileSystemFilter, IActionLog log, TaskScheduler taskScheduler = null) { + Requires.NotNullOrWhiteSpace(directory, nameof(directory)); + Requires.NotNullOrWhiteSpace(filter, nameof(filter)); + Requires.Range(delayMilliseconds >= 0, nameof(delayMilliseconds)); + Requires.Range(recoveryDelayMilliseconds >= 0, nameof(recoveryDelayMilliseconds)); + Requires.NotNull(fileSystem, nameof(fileSystem)); + Requires.NotNull(fileSystemFilter, nameof(fileSystemFilter)); + + _directory = directory; + _filter = filter; + _delayMilliseconds = delayMilliseconds; + _recoveryDelayMilliseconds = recoveryDelayMilliseconds; + _fileSystem = fileSystem; + _fileSystemFilter = fileSystemFilter; + _taskScheduler = taskScheduler ?? TaskScheduler.Default; + _log = log; + + _entries = new MsBuildFileSystemWatcherEntries(); + _queue = new ConcurrentQueue(); + _broadcastBlock = new BroadcastBlock(b => b, new DataflowBlockOptions { TaskScheduler = _taskScheduler }); + SourceBlock = _broadcastBlock.SafePublicize(); + _fileSystemFilter.Seal(); + } + + public void Dispose() { + _fileWatcher?.Dispose(); + _directoryWatcher?.Dispose(); + _attributesWatcher?.Dispose(); + } + + public void Start() { + _log.WatcherStarting(); + + Enqueue(new DirectoryCreated(_entries, _directory, _fileSystem, _fileSystemFilter, _directory)); + + _fileWatcher = CreateFileSystemWatcher(NotifyFilters.FileName); + _fileWatcher.Created += (sender, e) => Enqueue(new FileCreated(_entries, _directory, _fileSystem, _fileSystemFilter, e.FullPath)); + _fileWatcher.Deleted += (sender, e) => Enqueue(new FileDeleted(_entries, _directory, e.FullPath)); + _fileWatcher.Renamed += (sender, e) => Enqueue(new FileRenamed(_entries, _directory, _fileSystem, _fileSystemFilter, e.OldFullPath, e.FullPath)); + _fileWatcher.Error += (sender, e) => FileSystemWatcherError("File Watcher", e); + + _directoryWatcher = CreateFileSystemWatcher(NotifyFilters.DirectoryName); + _directoryWatcher.Created += (sender, e) => Enqueue(new DirectoryCreated(_entries, _directory, _fileSystem, _fileSystemFilter, e.FullPath)); + _directoryWatcher.Deleted += (sender, e) => Enqueue(new DirectoryDeleted(_entries, _directory, e.FullPath)); + _directoryWatcher.Renamed += (sender, e) => Enqueue(new DirectoryRenamed(_entries, _directory, _fileSystem, _fileSystemFilter, e.OldFullPath, e.FullPath)); + _directoryWatcher.Error += (sender, e) => FileSystemWatcherError("Directory Watcher", e); + + _attributesWatcher = CreateFileSystemWatcher(NotifyFilters.Attributes); + _attributesWatcher.Changed += (sender, e) => Enqueue(new AttributesChanged(_entries, e.Name, e.FullPath)); + _attributesWatcher.Error += (sender, e) => FileSystemWatcherError("Attributes Watcher", e); + + _log.WatcherStarted(); + } + + private void Enqueue(IFileSystemChange change) { + _queue.Enqueue(change); + StartConsumer(); + } + + private void StartConsumer() { + if (Interlocked.Exchange(ref _consumerIsWorking, 1) == 0) { + Task.Factory + .StartNew(async () => await ConsumeWaitPublish(), CancellationToken.None, Task.Factory.CreationOptions, _taskScheduler) + .Unwrap(); + _log.WatcherConsumeChangesScheduled(); + } + } + + private async Task ConsumeWaitPublish() { + _log.WatcherConsumeChangesStarted(); + + try { + while (!_queue.IsEmpty || _hasErrors != 0) { + Consume(); + await Task.Delay(_delayMilliseconds); + if (Interlocked.Exchange(ref _hasErrors, 0) == 0) { + continue; + } + + var isRecovered = await TryRecover(); + if (!isRecovered) { + return; + } + } + + var changeset = _entries.ProduceChangeset(); + if (!changeset.IsEmpty()) { + _broadcastBlock.Post(changeset); + _log.WatcherChangesetSent(changeset); + } + } finally { + _consumerIsWorking = 0; + _log.WatcherConsumeChangesFinished(); + if (!_queue.IsEmpty) { + StartConsumer(); + } + } + } + + private void Consume() { + IFileSystemChange change; + while (_hasErrors == 0 && _queue.TryDequeue(out change)) { + try { + _log.WatcherApplyChange(change.ToString()); + change.Apply(); + if (_entries.RescanRequired) { + _hasErrors = 1; + } + } catch (Exception e) { + _hasErrors = 1; + _log.WatcherApplyChangeFailed(change.ToString(), e); + System.Diagnostics.Debug.Fail(Invariant($"Failed to apply change {change}:\n{e}")); + } + } + } + + private async Task TryRecover() { + _fileWatcher.EnableRaisingEvents = false; + _directoryWatcher.EnableRaisingEvents = false; + _attributesWatcher.EnableRaisingEvents = false; + + await Task.Delay(_recoveryDelayMilliseconds); + EmptyQueue(); + + var rescanChange = new DirectoryCreated(_entries, _directory, _fileSystem, _fileSystemFilter, _directory); + bool isRecovered; + try { + _entries.MarkAllDeleted(); + _log.WatcherApplyRecoveryChange(rescanChange.ToString()); + rescanChange.Apply(); + isRecovered = !_entries.RescanRequired; + } catch (Exception e) { + _log.WatcherApplyRecoveryChangeFailed(rescanChange.ToString(), e); + isRecovered = false; + } + + if (isRecovered) { + try { + _fileWatcher.EnableRaisingEvents = true; + _directoryWatcher.EnableRaisingEvents = true; + _attributesWatcher.EnableRaisingEvents = true; + } catch (Exception) { + isRecovered = false; + } + } + + if (!isRecovered) { + Error?.Invoke(this, new EventArgs()); + Dispose(); + } + + return isRecovered; + } + + private void EmptyQueue() { + IFileSystemChange change; + while (_queue.TryDequeue(out change)) { } + } + + private IFileSystemWatcher CreateFileSystemWatcher(NotifyFilters notifyFilter) { + var watcher = _fileSystem.CreateFileSystemWatcher(_directory, _filter); + watcher.EnableRaisingEvents = true; + watcher.IncludeSubdirectories = true; + watcher.InternalBufferSize = 65536; + watcher.NotifyFilter = notifyFilter; + return watcher; + } + + private static bool IsFileAllowed(string rootDirectory, string fullPath, + IFileSystem fileSystem, IMsBuildFileSystemFilter filter, + out string relativePath, out string shortRelativePath) { + relativePath = null; + shortRelativePath = null; + if (fullPath.StartsWithIgnoreCase(rootDirectory)) { + relativePath = PathHelper.MakeRelative(rootDirectory, fullPath); + try { + shortRelativePath = fileSystem.ToShortRelativePath(fullPath, rootDirectory); + return !string.IsNullOrEmpty(shortRelativePath) && filter.IsFileAllowed(relativePath, fileSystem.GetFileAttributes(fullPath)); + } catch (IOException) { } catch (UnauthorizedAccessException) { } // File isn't allowed if it isn't accessible + } + return false; + } + + private interface IFileSystemChange { + void Apply(); + } + + private void FileSystemWatcherError(string watcherName, ErrorEventArgs errorEventArgs) { + _log.ErrorInFileSystemWatcher(watcherName, errorEventArgs.GetException()); + Interlocked.Exchange(ref _hasErrors, 1); + StartConsumer(); + } + + public class Changeset { + public HashSet AddedFiles { get; } = new HashSet(StringComparer.Ordinal); + public HashSet AddedDirectories { get; } = new HashSet(StringComparer.Ordinal); + public HashSet RemovedFiles { get; } = new HashSet(StringComparer.Ordinal); + public HashSet RemovedDirectories { get; } = new HashSet(StringComparer.Ordinal); + public Dictionary RenamedFiles { get; } = new Dictionary(StringComparer.Ordinal); + public Dictionary RenamedDirectories { get; } = new Dictionary(StringComparer.Ordinal); + + public bool IsEmpty() { + return AddedFiles.Count == 0 + && AddedDirectories.Count == 0 + && RemovedFiles.Count == 0 + && RemovedDirectories.Count == 0 + && RenamedFiles.Count == 0 + && RenamedDirectories.Count == 0; + } + } + } +} diff --git a/VisualRust.ProjectSystem.FileSystemMirroring/IO/MsBuildFileSystemWatcherEntries.cs b/VisualRust.ProjectSystem.FileSystemMirroring/IO/MsBuildFileSystemWatcherEntries.cs new file mode 100644 index 00000000..407f3129 --- /dev/null +++ b/VisualRust.ProjectSystem.FileSystemMirroring/IO/MsBuildFileSystemWatcherEntries.cs @@ -0,0 +1,338 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using Microsoft.Common.Core; +#if VS14 +using Microsoft.VisualStudio.ProjectSystem.Utilities; +#endif +using static VisualRust.ProjectSystem.FileSystemMirroring.IO.MsBuildFileSystemWatcherEntries.EntryState; +using static VisualRust.ProjectSystem.FileSystemMirroring.IO.MsBuildFileSystemWatcherEntries.EntryType; + +namespace VisualRust.ProjectSystem.FileSystemMirroring.IO { + public class MsBuildFileSystemWatcherEntries { + private readonly Dictionary _entries = new Dictionary(StringComparer.OrdinalIgnoreCase); + + public bool RescanRequired { get; private set; } + + public void AddFile(string relativeFilePath, string shortPath) { + AddEntry(relativeFilePath, shortPath, File); + } + + public void DeleteFile(string relativeFilePath) { + try { + Entry entry; + if (_entries.TryGetValue(relativeFilePath, out entry)) { + DeleteEntry(entry); + } + } catch (InvalidStateException) { + RescanRequired = true; + } + } + + public void RenameFile(string previousRelativePath, string relativeFilePath, string shortPath) { + try { + RenameEntry(previousRelativePath, relativeFilePath, shortPath, File); + } catch (InvalidStateException) { + RescanRequired = true; + } + } + + public void AddDirectory(string relativePath, string shortPath) { + AddEntry(relativePath, shortPath, Directory); + } + + public void DeleteDirectory(string relativePath) { + try { + relativePath = PathHelper.EnsureTrailingSlash(relativePath); + foreach (var entry in _entries.Values.Where(v => v.RelativePath.StartsWithIgnoreCase(relativePath) || + v.ShortPath.StartsWithIgnoreCase(relativePath)).ToList()) { + DeleteEntry(entry); + } + } catch (InvalidStateException) { + RescanRequired = true; + } + } + + public ISet RenameDirectory(string previousRelativePath, string relativePath, string shortPath) { + try { + previousRelativePath = PathHelper.EnsureTrailingSlash(previousRelativePath); + relativePath = PathHelper.EnsureTrailingSlash(relativePath); + shortPath = PathHelper.EnsureTrailingSlash(shortPath); + var newPaths = new HashSet(); + var entriesToRename = _entries.Values + .Where(v => v.State == Unchanged || v.State == Added || v.State == RenamedThenAdded) + .Where(v => v.RelativePath.StartsWithIgnoreCase(previousRelativePath) || + v.ShortPath.StartsWithIgnoreCase(previousRelativePath)).ToList(); + foreach (var entry in entriesToRename) { + var newEntryPath = entry.RelativePath.Replace(previousRelativePath, relativePath, 0, previousRelativePath.Length); + RenameEntry(entry.RelativePath, newEntryPath, shortPath, entry.Type); + newPaths.Add(newEntryPath); + } + return newPaths; + } catch (InvalidStateException) { + RescanRequired = true; + return null; + } + } + + public void MarkAllDeleted() { + foreach (var entry in _entries.Values.ToList()) { + entry.PreviousRelativePath = null; + switch (entry.State) { + case Unchanged: + case Renamed: + case RenamedThenAdded: + entry.State = Deleted; + break; + case Added: + _entries.Remove(entry.RelativePath); + break; + case Deleted: + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + + RescanRequired = false; + } + + private Entry AddEntry(string relativeFilePath, string shortPath, EntryType type) { + if (type == EntryType.Directory) { + relativeFilePath = PathHelper.EnsureTrailingSlash(relativeFilePath); + shortPath = PathHelper.EnsureTrailingSlash(shortPath); + } + + Entry entry; + if (!_entries.TryGetValue(relativeFilePath, out entry)) { + entry = new Entry(relativeFilePath, shortPath, type) { + State = Added + }; + + _entries[relativeFilePath] = entry; + return entry; + } + + switch (entry.State) { + case Unchanged: + case RenamedThenAdded: + case Added: + break; + case Deleted: + entry.State = Unchanged; + break; + case Renamed: + entry.State = RenamedThenAdded; + break; + default: + throw new ArgumentOutOfRangeException(); + } + + return entry; + } + + private void DeleteEntry(Entry entry) { + switch (entry.State) { + case Unchanged: + entry.State = Deleted; + return; + case Added: + _entries.Remove(entry.RelativePath); + UpdateRenamedEntryOnDelete(entry); + return; + case Deleted: + return; + case RenamedThenAdded: + entry.State = Renamed; + UpdateRenamedEntryOnDelete(entry); + return; + case Renamed: + throw new InvalidStateException(); + default: + throw new ArgumentOutOfRangeException(); + } + } + + private void RenameEntry(string previousRelativePath, string relativePath, string shortPath, EntryType type) { + Entry renamedEntry; + if (_entries.TryGetValue(previousRelativePath, out renamedEntry)) { + switch (renamedEntry.State) { + case Unchanged: + renamedEntry.State = Renamed; + var entry = AddEntry(relativePath, shortPath, type); + entry.PreviousRelativePath = previousRelativePath; + return; + case Added: + _entries.Remove(previousRelativePath); + if (renamedEntry.PreviousRelativePath == null) { + AddEntry(relativePath, shortPath, type); + } else { + UpdateRenamingChain(renamedEntry, relativePath, shortPath, type); + } + return; + case RenamedThenAdded: + renamedEntry.State = Renamed; + if (renamedEntry.PreviousRelativePath == null) { + AddEntry(relativePath, shortPath, type); + } else { + UpdateRenamingChain(renamedEntry, relativePath, shortPath, type); + renamedEntry.PreviousRelativePath = null; + } + return; + case Deleted: + case Renamed: + throw new InvalidStateException(); + default: + throw new ArgumentOutOfRangeException(); + } + } + } + + private void UpdateRenamingChain(Entry renamedEntry, string relativePath, string shortPath, EntryType type) { + var previouslyRenamedEntryPath = renamedEntry.PreviousRelativePath; + Entry previouslyRenamedEntry; + if (!_entries.TryGetValue(previouslyRenamedEntryPath, out previouslyRenamedEntry)) { + return; + } + + if (previouslyRenamedEntryPath == relativePath) { + switch (previouslyRenamedEntry.State) { + case Renamed: + previouslyRenamedEntry.State = Unchanged; + return; + case RenamedThenAdded: + case Unchanged: + case Added: + case Deleted: + throw new InvalidStateException(); + default: + throw new ArgumentOutOfRangeException(); + } + } + + var entry = AddEntry(relativePath, shortPath, type); + entry.PreviousRelativePath = previouslyRenamedEntryPath; + } + + private void UpdateRenamedEntryOnDelete(Entry entry) { + if (entry.PreviousRelativePath == null) { + return; + } + + Entry renamedEntry; + if (!_entries.TryGetValue(entry.PreviousRelativePath, out renamedEntry)) { + return; + } + + switch (renamedEntry.State) { + case Renamed: + renamedEntry.State = Deleted; + return; + case RenamedThenAdded: + renamedEntry.State = Added; + return; + case Unchanged: + case Added: + case Deleted: + throw new InvalidStateException(); + default: + throw new ArgumentOutOfRangeException(); + } + } + + public MsBuildFileSystemWatcher.Changeset ProduceChangeset() { + var changeset = new MsBuildFileSystemWatcher.Changeset(); + foreach (var entry in _entries.Values.ToList()) { + switch (entry.State) { + case Added: + case RenamedThenAdded: + if (entry.PreviousRelativePath != null) { + switch (entry.Type) { + case File: + changeset.RenamedFiles.Add(entry.PreviousRelativePath, entry.RelativePath); + break; + case Directory: + changeset.RenamedDirectories.Add(entry.PreviousRelativePath, entry.RelativePath); + break; + default: + throw new ArgumentOutOfRangeException(); + } + } else { + switch (entry.Type) { + case File: + changeset.AddedFiles.Add(entry.RelativePath); + break; + case Directory: + changeset.AddedDirectories.Add(entry.RelativePath); + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + entry.State = Unchanged; + break; + case Deleted: + switch (entry.Type) { + case File: + changeset.RemovedFiles.Add(entry.RelativePath); + break; + case Directory: + changeset.RemovedDirectories.Add(entry.RelativePath); + break; + default: + throw new ArgumentOutOfRangeException(); + } + _entries.Remove(entry.RelativePath); + break; + case Renamed: + _entries.Remove(entry.RelativePath); + break; + default: + entry.State = Unchanged; + break; + } + } + + return changeset; + } + + [DebuggerDisplay("{Type} {PreviousRelativePath == null ? RelativePath : PreviousRelativePath + \" -> \" + RelativePath}, {State}")] + private class Entry { + public Entry(string relativePath, string shortPath, EntryType type) { + RelativePath = relativePath; + ShortPath = shortPath; + Type = type; + } + + public string RelativePath { get; } + public EntryType Type { get; } + + public string PreviousRelativePath { get; set; } + public EntryState State { get; set; } = Unchanged; + + public string ShortPath { get; } + } + + private class InvalidStateException : Exception { + + } + + internal enum EntryState { + Unchanged, + Added, + Deleted, + Renamed, + // This state marks special case when file/directory was first renamed and then another file/directory with the same name was added + RenamedThenAdded + } + + internal enum EntryType { + File, + Directory + } + } +} \ No newline at end of file diff --git a/VisualRust.ProjectSystem.FileSystemMirroring/Interop/NativeMethods.cs b/VisualRust.ProjectSystem.FileSystemMirroring/Interop/NativeMethods.cs new file mode 100644 index 00000000..db6328b6 --- /dev/null +++ b/VisualRust.ProjectSystem.FileSystemMirroring/Interop/NativeMethods.cs @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System.Runtime.InteropServices; +using System.Text; + +namespace VisualRust.ProjectSystem.FileSystemMirroring.Interop { + internal static class NativeMethods { + public const int MAX_PATH = 260; + + [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] + public static extern uint GetLongPathName([MarshalAs(UnmanagedType.LPWStr)] string lpFileName, + [MarshalAs(UnmanagedType.LPWStr)] StringBuilder lpBuffer, + int nBufferLength); + + [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] + public static extern uint GetShortPathName([MarshalAs(UnmanagedType.LPWStr)] string lpFileName, + [MarshalAs(UnmanagedType.LPWStr)] StringBuilder lpBuffer, + int nBufferLength); + } +} diff --git a/VisualRust.ProjectSystem.FileSystemMirroring/Key.snk b/VisualRust.ProjectSystem.FileSystemMirroring/Key.snk new file mode 100644 index 00000000..ec81d588 Binary files /dev/null and b/VisualRust.ProjectSystem.FileSystemMirroring/Key.snk differ diff --git a/VisualRust.ProjectSystem.FileSystemMirroring/Logging/FileSystemMirroringProjectLoggingExtensions.cs b/VisualRust.ProjectSystem.FileSystemMirroring/Logging/FileSystemMirroringProjectLoggingExtensions.cs new file mode 100644 index 00000000..d6a6a2c8 --- /dev/null +++ b/VisualRust.ProjectSystem.FileSystemMirroring/Logging/FileSystemMirroringProjectLoggingExtensions.cs @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using Microsoft.Build.Construction; +using Microsoft.Common.Core.Logging; + +namespace VisualRust.ProjectSystem.FileSystemMirroring.Logging { + internal static class FileSystemMirroringProjectLoggingExtensions { + public static void ApplyProjectChangesStarted(this IActionLog log) { + log.WriteLineAsync(LogVerbosity.Normal, MessageCategory.General, "Starting applying changes to file-mirroring project"); + } + + public static void ApplyProjectChangesFinished(this IActionLog log) { + log.WriteLineAsync(LogVerbosity.Normal, MessageCategory.General, "Finished applying changes to file-mirroring project"); + } + + public static void MsBuildAfterChangesApplied(this IActionLog log, ProjectRootElement rootElement) { + log.WriteLineAsync(LogVerbosity.Normal, MessageCategory.General, "File mirroring project after changes applied:" + Environment.NewLine + rootElement.RawXml); + } + } +} \ No newline at end of file diff --git a/VisualRust.ProjectSystem.FileSystemMirroring/Logging/MsBuildFileSystemWatcherLoggingExtensions.cs b/VisualRust.ProjectSystem.FileSystemMirroring/Logging/MsBuildFileSystemWatcherLoggingExtensions.cs new file mode 100644 index 00000000..b2de549b --- /dev/null +++ b/VisualRust.ProjectSystem.FileSystemMirroring/Logging/MsBuildFileSystemWatcherLoggingExtensions.cs @@ -0,0 +1,89 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.Common.Core.Logging; +using VisualRust.ProjectSystem.FileSystemMirroring.IO; +using static System.FormattableString; + +namespace VisualRust.ProjectSystem.FileSystemMirroring.Logging { + internal static class MsBuildFileSystemWatcherLoggingExtensions { + public static void WatcherStarting(this IActionLog log) { + log.WriteLineAsync(LogVerbosity.Normal, MessageCategory.General, "MsBuildFileSystemWatcher starting"); + } + + public static void WatcherStarted(this IActionLog log) { + log.WriteLineAsync(LogVerbosity.Normal, MessageCategory.General, "MsBuildFileSystemWatcher started"); + } + + public static void WatcherConsumeChangesScheduled(this IActionLog log) { + log.WriteLineAsync(LogVerbosity.Normal, MessageCategory.General, "Consume file system changes scheduled"); + } + + public static void WatcherConsumeChangesStarted(this IActionLog log) { + log.WriteLineAsync(LogVerbosity.Normal, MessageCategory.General, "File system changes consumer started"); + } + + public static void WatcherConsumeChangesFinished(this IActionLog log) { + log.WriteLineAsync(LogVerbosity.Normal, MessageCategory.General, "File system changes consumer finished"); + } + + public static void WatcherApplyChange(this IActionLog log, string change) { + log.WriteLineAsync(LogVerbosity.Normal, MessageCategory.General, Invariant($"Apply change: {change}")); + } + + public static void WatcherApplyChangeFailed(this IActionLog log, string change, Exception exception) { + log.WriteLineAsync(LogVerbosity.Normal, MessageCategory.Error, Invariant($"Failed to apply change '{change}':{exception}")); + } + + public static void WatcherApplyRecoveryChange(this IActionLog log, string change) { + log.WriteLineAsync(LogVerbosity.Normal, MessageCategory.General, Invariant($"Apply recovery change: {change}")); + } + + public static void WatcherApplyRecoveryChangeFailed(this IActionLog log, string change, Exception exception) { + log.WriteLineAsync(LogVerbosity.Normal, MessageCategory.Error, Invariant($"Failed to apply recovery change '{change}', closing watcher:{exception}")); + } + + public static void WatcherChangesetSent(this IActionLog log, MsBuildFileSystemWatcher.Changeset changeset) { + var sb = new StringBuilder(); + sb.AppendLine("MsBuildFileSystemWatcher changeset sent.") + .AppendWatcherChangesetPart(changeset.AddedFiles, "Added Files:") + .AppendWatcherChangesetPart(changeset.RenamedFiles, "Renamed Files:") + .AppendWatcherChangesetPart(changeset.RemovedFiles, "Removed Files:") + .AppendWatcherChangesetPart(changeset.AddedDirectories, "Added Directories:") + .AppendWatcherChangesetPart(changeset.RenamedDirectories, "Renamed Directories:") + .AppendWatcherChangesetPart(changeset.RemovedDirectories, "Removed Directories:"); + + log.WriteAsync(LogVerbosity.Normal, MessageCategory.General, sb.ToString()); + } + + public static void ErrorInFileSystemWatcher(this IActionLog log, string watcherName, Exception e) { + log.WriteAsync(LogVerbosity.Minimal, MessageCategory.Error, Invariant($"{watcherName} failed with exception:{e}")); + } + + private static StringBuilder AppendWatcherChangesetPart(this StringBuilder sb, ISet changesetPart, string name) { + if (changesetPart.Count > 0) { + sb.AppendLine(name); + foreach (var item in changesetPart) { + sb.Append(' ', 4); + sb.AppendLine(item); + } + } + + return sb; + } + + private static StringBuilder AppendWatcherChangesetPart(this StringBuilder sb, IDictionary changesetPart, string name) { + if (changesetPart.Count > 0) { + sb.AppendLine(name); + foreach (var item in changesetPart) { + sb.AppendLine(Invariant($"{item.Key} -> {item.Value}")); + } + } + + return sb; + } + } +} \ No newline at end of file diff --git a/VisualRust.ProjectSystem.FileSystemMirroring/MsBuild/XDefaultValueProperty.cs b/VisualRust.ProjectSystem.FileSystemMirroring/MsBuild/XDefaultValueProperty.cs new file mode 100644 index 00000000..73c02532 --- /dev/null +++ b/VisualRust.ProjectSystem.FileSystemMirroring/MsBuild/XDefaultValueProperty.cs @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using static System.FormattableString; + +namespace VisualRust.ProjectSystem.FileSystemMirroring.MsBuild { + public class XDefaultValueProperty : XProperty { + public XDefaultValueProperty(string name, string defaultValue) + : base(name, Invariant($"'$({name})' == ''"), defaultValue) { } + } +} \ No newline at end of file diff --git a/VisualRust.ProjectSystem.FileSystemMirroring/MsBuild/XImport.cs b/VisualRust.ProjectSystem.FileSystemMirroring/MsBuild/XImport.cs new file mode 100644 index 00000000..41d0b9c2 --- /dev/null +++ b/VisualRust.ProjectSystem.FileSystemMirroring/MsBuild/XImport.cs @@ -0,0 +1,13 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System.Xml.Linq; +using static VisualRust.ProjectSystem.FileSystemMirroring.MsBuild.XProjHelpers; + +namespace VisualRust.ProjectSystem.FileSystemMirroring.MsBuild { + public class XImport : XElement { + public XImport(string project) : base(MsBuildNamespace + "Import", Attr("Project", project)) { } + + public XImport(string project, string condition) : base(MsBuildNamespace + "Import", Attr("Project", project), Attr("Condition", condition)) { } + } +} \ No newline at end of file diff --git a/VisualRust.ProjectSystem.FileSystemMirroring/MsBuild/XImportExisting.cs b/VisualRust.ProjectSystem.FileSystemMirroring/MsBuild/XImportExisting.cs new file mode 100644 index 00000000..b94d46fd --- /dev/null +++ b/VisualRust.ProjectSystem.FileSystemMirroring/MsBuild/XImportExisting.cs @@ -0,0 +1,13 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using static System.FormattableString; + +namespace VisualRust.ProjectSystem.FileSystemMirroring.MsBuild { + public class XImportExisting : XImport { + + public XImportExisting(string project) : base(project, Invariant($"Exists('{project}')")) { } + + public XImportExisting(string project, string additionalCondition) : base(project, Invariant($"Exists('{project}') And {additionalCondition}")) { } + } +} \ No newline at end of file diff --git a/VisualRust.ProjectSystem.FileSystemMirroring/MsBuild/XProjDocument.cs b/VisualRust.ProjectSystem.FileSystemMirroring/MsBuild/XProjDocument.cs new file mode 100644 index 00000000..2a08d70e --- /dev/null +++ b/VisualRust.ProjectSystem.FileSystemMirroring/MsBuild/XProjDocument.cs @@ -0,0 +1,25 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System.Globalization; +using System.IO; +using System.Text; +using System.Xml.Linq; + +namespace VisualRust.ProjectSystem.FileSystemMirroring.MsBuild { + public class XProjDocument : XDocument { + public XProjDocument() + : base(new XDeclaration("1.0", "utf-8", null)) { } + + public XProjDocument(XProject xProject) + : base(new XDeclaration("1.0", "utf-8", null), xProject) { } + + public string GetFullXml() { + var sb = new StringBuilder(); + using (var writer = new StringWriter(sb, CultureInfo.InvariantCulture)) { + Save(writer); + } + return sb.ToString(); + } + } +} diff --git a/VisualRust.ProjectSystem.FileSystemMirroring/MsBuild/XProjElement.cs b/VisualRust.ProjectSystem.FileSystemMirroring/MsBuild/XProjElement.cs new file mode 100644 index 00000000..8d549a74 --- /dev/null +++ b/VisualRust.ProjectSystem.FileSystemMirroring/MsBuild/XProjElement.cs @@ -0,0 +1,15 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System.Xml.Linq; +using static VisualRust.ProjectSystem.FileSystemMirroring.MsBuild.XProjHelpers; + +namespace VisualRust.ProjectSystem.FileSystemMirroring.MsBuild { + public class XProjElement : XElement { + public XProjElement(string name) : base(MsBuildNamespace + name) { } + + public XProjElement(string name, object content) : base(MsBuildNamespace + name, content) { } + + public XProjElement(string name, params object[] content) : base(MsBuildNamespace + name, content) { } + } +} \ No newline at end of file diff --git a/VisualRust.ProjectSystem.FileSystemMirroring/MsBuild/XProjHelpers.cs b/VisualRust.ProjectSystem.FileSystemMirroring/MsBuild/XProjHelpers.cs new file mode 100644 index 00000000..ed06023f --- /dev/null +++ b/VisualRust.ProjectSystem.FileSystemMirroring/MsBuild/XProjHelpers.cs @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System.Linq; +using System.Xml.Linq; + +namespace VisualRust.ProjectSystem.FileSystemMirroring.MsBuild { + internal class XProjHelpers { + public static XNamespace MsBuildNamespace = "http://schemas.microsoft.com/developer/msbuild/2003"; + + public static XAttribute Attr(string name, object value) { + return value != null ? new XAttribute(name, value) : null; + } + + public static object[] Content(object[] elements, params XAttribute[] attributes) { + return attributes + .Where(a => a != null) + .Concat(elements).ToArray(); + } + } +} \ No newline at end of file diff --git a/VisualRust.ProjectSystem.FileSystemMirroring/MsBuild/XProject.cs b/VisualRust.ProjectSystem.FileSystemMirroring/MsBuild/XProject.cs new file mode 100644 index 00000000..73756f58 --- /dev/null +++ b/VisualRust.ProjectSystem.FileSystemMirroring/MsBuild/XProject.cs @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System.Xml.Linq; +using static VisualRust.ProjectSystem.FileSystemMirroring.MsBuild.XProjHelpers; + +namespace VisualRust.ProjectSystem.FileSystemMirroring.MsBuild { + public class XProject : XElement { + public XProject() : base(MsBuildNamespace + "Project") { } + + public XProject(string toolsVersion = null, string defaultTargets = null, params object[] elements) + : base(MsBuildNamespace + "Project", Content(elements, Attr("ToolsVersion", toolsVersion), Attr("DefaultTargets", defaultTargets))) { } + } +} \ No newline at end of file diff --git a/VisualRust.ProjectSystem.FileSystemMirroring/MsBuild/XProperty.cs b/VisualRust.ProjectSystem.FileSystemMirroring/MsBuild/XProperty.cs new file mode 100644 index 00000000..05196952 --- /dev/null +++ b/VisualRust.ProjectSystem.FileSystemMirroring/MsBuild/XProperty.cs @@ -0,0 +1,15 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System.Xml.Linq; +using static VisualRust.ProjectSystem.FileSystemMirroring.MsBuild.XProjHelpers; + +namespace VisualRust.ProjectSystem.FileSystemMirroring.MsBuild { + public class XProperty : XElement { + public XProperty(string name) : base(MsBuildNamespace + name) { } + + public XProperty(string name, string value) : base(MsBuildNamespace + name, new XText(value)) { } + + public XProperty(string name, string condition, string value) : base(MsBuildNamespace + name, Attr("Condition", condition), new XText(value)) { } + } +} \ No newline at end of file diff --git a/VisualRust.ProjectSystem.FileSystemMirroring/MsBuild/XPropertyGroup.cs b/VisualRust.ProjectSystem.FileSystemMirroring/MsBuild/XPropertyGroup.cs new file mode 100644 index 00000000..ec1d4a9b --- /dev/null +++ b/VisualRust.ProjectSystem.FileSystemMirroring/MsBuild/XPropertyGroup.cs @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System.Xml.Linq; +using static VisualRust.ProjectSystem.FileSystemMirroring.MsBuild.XProjHelpers; + +namespace VisualRust.ProjectSystem.FileSystemMirroring.MsBuild { + public class XPropertyGroup : XElement { + public XPropertyGroup(params object[] elements) : base(MsBuildNamespace + "PropertyGroup", elements) { } + + public XPropertyGroup(string condition, params object[] elements) + : base(MsBuildNamespace + "PropertyGroup", Content(elements, Attr("Condition", condition))) { } + + public XPropertyGroup(string label, string condition, params object[] elements) + : base(MsBuildNamespace + "PropertyGroup", Content(elements, Attr("Label", label), Attr("Condition", condition))) { } + } +} \ No newline at end of file diff --git a/VisualRust.ProjectSystem.FileSystemMirroring/Package/Registration/DeveloperActivityAttribute.cs b/VisualRust.ProjectSystem.FileSystemMirroring/Package/Registration/DeveloperActivityAttribute.cs new file mode 100644 index 00000000..3a8c3d12 --- /dev/null +++ b/VisualRust.ProjectSystem.FileSystemMirroring/Package/Registration/DeveloperActivityAttribute.cs @@ -0,0 +1,41 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using Microsoft.VisualStudio.Shell; + +namespace VisualRust.ProjectSystem.FileSystemMirroring.Package.Registration { + public sealed class DeveloperActivityAttribute : RegistrationAttribute { + private readonly string _projectType; + private readonly int _templateSet; + private readonly string _developerActivity; + private readonly int _sortPriority; + + public DeveloperActivityAttribute(string developerActivity, string projectPackageType, int sortPriority, int templateSet = 1) { + _developerActivity = developerActivity; + _projectType = projectPackageType; + _templateSet = templateSet; + _sortPriority = sortPriority; + } + + public override void Register(RegistrationAttribute.RegistrationContext context) { + Build().Register(context); + } + + public override void Unregister(RegistrationAttribute.RegistrationContext context) { + Build().Unregister(context); + } + + private RegistrationAttributeBuilder Build() { + var builder = new RegistrationAttributeBuilder(); + builder.Key("NewProjectTemplates\\TemplateDirs") + .GuidSubKey(_projectType) + .SubKey("/" + _templateSet) + .StringValue("", _developerActivity) + .StringValue("TemplatesDir", "\\.\\NullPath") + .StringValue("DeveloperActivity", _developerActivity) + .IntValue("SortPriority", _sortPriority); + return builder; + } + } +} diff --git a/VisualRust.ProjectSystem.FileSystemMirroring/Package/Registration/ProvideCpsProjectFactoryAttribute.cs b/VisualRust.ProjectSystem.FileSystemMirroring/Package/Registration/ProvideCpsProjectFactoryAttribute.cs new file mode 100644 index 00000000..89365414 --- /dev/null +++ b/VisualRust.ProjectSystem.FileSystemMirroring/Package/Registration/ProvideCpsProjectFactoryAttribute.cs @@ -0,0 +1,44 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using Microsoft.VisualStudio.Shell; + +namespace VisualRust.ProjectSystem.FileSystemMirroring.Package.Registration { + public sealed class ProvideCpsProjectFactoryAttribute : RegistrationAttribute { + public string ProjectTypeGuid { get; } + public string LanguageVsTemplate { get; } + public string PossibleProjectExtensions { get; } + + private bool? _disableAsynchronousSolutionLoadValue; + public bool DisableAsynchronousSolutionLoad { + get { return _disableAsynchronousSolutionLoadValue ?? false; } + set { _disableAsynchronousSolutionLoadValue = value; } + } + + public ProvideCpsProjectFactoryAttribute(string projectTypeGuid, string languageVsTemplate, string possibleProjectExtensions) { + ProjectTypeGuid = projectTypeGuid; + LanguageVsTemplate = languageVsTemplate; + PossibleProjectExtensions = possibleProjectExtensions; + } + + public override void Register(RegistrationContext context) { + Build().Register(context); + } + + public override void Unregister(RegistrationContext context) { + Build().Unregister(context); + } + + private RegistrationAttributeBuilder Build() { + var builder = new RegistrationAttributeBuilder(); + builder.Key("Projects") + .GuidSubKey(ProjectTypeGuid) + .PackageGuidValue("Package") + .StringValue("Language(VsTemplate)", LanguageVsTemplate) + .GuidValue("ProjectFactoryPackage", "3347BEE8-D7A1-4082-95E4-38A439553CC2") + .BoolValue("DisableAsynchronousSolutionLoad", DisableAsynchronousSolutionLoad) + .StringValue("PossibleProjectExtensions", PossibleProjectExtensions); + return builder; + } + } +} \ No newline at end of file diff --git a/VisualRust.ProjectSystem.FileSystemMirroring/Package/Registration/ProvideProjectFileGeneratorAttribute.cs b/VisualRust.ProjectSystem.FileSystemMirroring/Package/Registration/ProvideProjectFileGeneratorAttribute.cs new file mode 100644 index 00000000..2258f973 --- /dev/null +++ b/VisualRust.ProjectSystem.FileSystemMirroring/Package/Registration/ProvideProjectFileGeneratorAttribute.cs @@ -0,0 +1,45 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using Microsoft.VisualStudio.Shell; + +namespace VisualRust.ProjectSystem.FileSystemMirroring.Package.Registration { + public sealed class ProvideProjectFileGeneratorAttribute : RegistrationAttribute { + public Type GeneratorType { get; } + public string FileNames { get; set; } + public string FileExtensions { get; set; } + public string[] PossibleGeneratedProjectTypes { get; } + + private int? _displayGeneratorFilter; + public int DisplayGeneratorFilter { + get { return _displayGeneratorFilter ?? 0; } + set { _displayGeneratorFilter = value; } + } + + public ProvideProjectFileGeneratorAttribute(Type projectFileGeneratorType, params string[] possibleGeneratedProjectTypes) { + GeneratorType = projectFileGeneratorType; + PossibleGeneratedProjectTypes = possibleGeneratedProjectTypes; + } + + public override void Register(RegistrationContext context) { + Build().Register(context); + } + + public override void Unregister(RegistrationContext context) { + Build().Unregister(context); + } + + private RegistrationAttributeBuilder Build() { + var builder = new RegistrationAttributeBuilder(); + builder.Key("ProjectGenerators") + .GuidSubKey(GeneratorType) + .PackageGuidValue("Package") + .StringValue("FileNames", FileNames) + .StringValue("FileExtensions", FileExtensions) + .ResourceIdValue("DisplayGeneratorFilter", DisplayGeneratorFilter) + .GuidArrayValue("PossibleGeneratedProjectTypes", PossibleGeneratedProjectTypes); + return builder; + } + } +} \ No newline at end of file diff --git a/VisualRust.ProjectSystem.FileSystemMirroring/Package/Registration/RegistrationAttributeBuilder.RegKey.cs b/VisualRust.ProjectSystem.FileSystemMirroring/Package/Registration/RegistrationAttributeBuilder.RegKey.cs new file mode 100644 index 00000000..b702a577 --- /dev/null +++ b/VisualRust.ProjectSystem.FileSystemMirroring/Package/Registration/RegistrationAttributeBuilder.RegKey.cs @@ -0,0 +1,81 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using static System.FormattableString; + +namespace VisualRust.ProjectSystem.FileSystemMirroring.Package.Registration { + public sealed partial class RegistrationAttributeBuilder { + public class RegKey { + public string Key { get; } + public string Package { get; private set; } + public List SubKeys { get; } = new List(); + public Dictionary Values = new Dictionary(); + + public RegKey(string key) { + Key = key; + } + + public RegKey GuidSubKey(Type key) { + return SubKey(key?.GUID.ToString("B")); + } + + public RegKey GuidSubKey(string key) { + return SubKey(key != null ? new Guid(key).ToString("B") : null); + } + + public RegKey SubKey(string key) { + var regKey = new RegKey(key); + SubKeys.Add(regKey); + return regKey; + } + + public RegKey PackageGuidValue(string name) { + Package = name; + return this; + } + + public RegKey StringValue(string name, string data) { + if (data != null) { + Values[name] = data; + } + return this; + } + + public RegKey IntValue(string name, int data) { + Values[name] = data; + return this; + } + + public RegKey GuidValue(string name, string data) { + if (data != null) { + Values[name] = new Guid(data).ToString("B"); + } + return this; + } + + public RegKey GuidArrayValue(string name, string[] data, string separator = ";") { + if (data != null && data.Length > 0) { + Values[name] = string.Join(separator, data.Select(d => new Guid(d).ToString("B"))); + } + return this; + } + + public RegKey BoolValue(string name, bool? data) { + if (data.HasValue) { + Values[name] = data.Value ? 1 : 0; + } + return this; + } + + public RegKey ResourceIdValue(string name, int? data) { + if (data.HasValue) { + Values[name] = Invariant($"#{data.Value}"); + } + return this; + } + } + } +} \ No newline at end of file diff --git a/VisualRust.ProjectSystem.FileSystemMirroring/Package/Registration/RegistrationAttributeBuilder.cs b/VisualRust.ProjectSystem.FileSystemMirroring/Package/Registration/RegistrationAttributeBuilder.cs new file mode 100644 index 00000000..a46c581d --- /dev/null +++ b/VisualRust.ProjectSystem.FileSystemMirroring/Package/Registration/RegistrationAttributeBuilder.cs @@ -0,0 +1,63 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System.Collections.Generic; +using Microsoft.VisualStudio.Shell; + +namespace VisualRust.ProjectSystem.FileSystemMirroring.Package.Registration { + public sealed partial class RegistrationAttributeBuilder { + private readonly List _keys = new List(); + + public RegKey Key(string key) { + var regKey = new RegKey(key); + _keys.Add(regKey); + return regKey; + } + + public void Register(RegistrationAttribute.RegistrationContext context) { + foreach (var regKey in _keys) { + using (var key = context.CreateKey(regKey.Key)) { + Register(context, key, regKey); + } + } + } + + public void Unregister(RegistrationAttribute.RegistrationContext context) { + foreach (var regKey in _keys) { + Unregister(context, string.Empty, regKey); + } + } + + private void Register(RegistrationAttribute.RegistrationContext context, RegistrationAttribute.Key key, RegKey regKey) { + foreach (var registrySubKey in regKey.SubKeys) { + using (var subKey = key.CreateSubkey(registrySubKey.Key)) { + Register(context, subKey, registrySubKey); + } + } + + foreach (var value in regKey.Values) { + key.SetValue(value.Key, value.Value); + } + + if (regKey.Package != null) { + key.SetValue(regKey.Package, context.ComponentType.GUID.ToString("B")); + } + } + + private void Unregister(RegistrationAttribute.RegistrationContext context, string prefix, RegKey regKey) { + prefix += "\\" + regKey.Key; + + foreach (var registrySubKey in regKey.SubKeys) { + Unregister(context, prefix, registrySubKey); + } + + foreach (var value in regKey.Values) { + context.RemoveValue(prefix, value.Key); + } + + if (regKey.Package != null) { + context.RemoveValue(prefix, regKey.Package); + } + } + } +} \ No newline at end of file diff --git a/VisualRust.ProjectSystem.FileSystemMirroring/Project/FileSystemMirroringProject.cs b/VisualRust.ProjectSystem.FileSystemMirroring/Project/FileSystemMirroringProject.cs new file mode 100644 index 00000000..a3db0cab --- /dev/null +++ b/VisualRust.ProjectSystem.FileSystemMirroring/Project/FileSystemMirroringProject.cs @@ -0,0 +1,309 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using System.Threading.Tasks.Dataflow; +using System.Xml; +using Microsoft.Build.Construction; +using Microsoft.Build.Evaluation; +using Microsoft.Common.Core; +using Microsoft.Common.Core.Logging; +using Microsoft.VisualStudio.ProjectSystem; +using VisualRust.ProjectSystem.FileSystemMirroring.IO; +using VisualRust.ProjectSystem.FileSystemMirroring.Logging; +using VisualRust.ProjectSystem.FileSystemMirroring.MsBuild; +#if VS14 +using Microsoft.VisualStudio.ProjectSystem.Utilities; +#endif + +namespace VisualRust.ProjectSystem.FileSystemMirroring.Project { + public class FileSystemMirroringProject : IFileSystemMirroringProjectTemporaryItems { + private readonly static XProjDocument EmptyProject; + + private readonly UnconfiguredProject _unconfiguredProject; + private readonly IProjectLockService _projectLockService; + private readonly MsBuildFileSystemWatcher _fileSystemWatcher; + private readonly IActionLog _log; + private readonly CancellationToken _unloadCancellationToken; + private readonly string _projectDirectory; + private readonly string _inMemoryImportFullPath; + private readonly Dictionary _fileItems; + private readonly Dictionary _directoryItems; + private readonly IProjectItemDependencyProvider _dependencyProvider; + + private ProjectRootElement _inMemoryImport; + private ProjectItemGroupElement _filesItemGroup; + private ProjectItemGroupElement _directoriesItemGroup; + private ProjectItemGroupElement _temporaryAddedItemGroup; + + static FileSystemMirroringProject() { + EmptyProject = new XProjDocument(new XProject()); + } + + public FileSystemMirroringProject(UnconfiguredProject unconfiguredProject, IProjectLockService projectLockService, + MsBuildFileSystemWatcher fileSystemWatcher, IProjectItemDependencyProvider dependencyProvider, + IActionLog log) { + _unconfiguredProject = unconfiguredProject; + _projectLockService = projectLockService; + _fileSystemWatcher = fileSystemWatcher; + _dependencyProvider = dependencyProvider; + + _log = log; + _unloadCancellationToken = _unconfiguredProject.Services.ProjectAsynchronousTasks.UnloadCancellationToken; + _projectDirectory = _unconfiguredProject.GetProjectDirectory(); + _inMemoryImportFullPath = _unconfiguredProject.GetInMemoryTargetsFileFullPath(); + _fileItems = new Dictionary(StringComparer.OrdinalIgnoreCase); + _directoryItems = new Dictionary(StringComparer.OrdinalIgnoreCase); + + var changesHandler = new Func(FileSystemChanged); + _fileSystemWatcher.SourceBlock.LinkTo(new ActionBlock(changesHandler)); + } + + public async Task CreateInMemoryImport() { + if (_unloadCancellationToken.IsCancellationRequested) { + return; + } + + using (var access = await _projectLockService.WriteLockAsync(_unloadCancellationToken)) { + // A bit odd but we have to "check it out" prior to creating it to avoid some of the validations in chk CPS + await access.CheckoutAsync(_inMemoryImportFullPath); + + // Now either open or create the in-memory file. Normally Create will happen, but in + // a scenario where your project had previously failed to load for some reason, need to TryOpen + // to avoid a new reason for a project load failure + _inMemoryImport = ProjectRootElement.TryOpen(_inMemoryImportFullPath, access.ProjectCollection); + if (_inMemoryImport != null) { + // The file already exists. Scrape it out so we don’t add duplicate items. + _inMemoryImport.RemoveAllChildren(); + } else { + // The project didn’t already exist, so create it, and then mark the evaluated project dirty + // so that MSBuild will notice. This step isn’t necessary if the project was already in memory. + _inMemoryImport = CreateEmptyMsBuildProject(_inMemoryImportFullPath, access.ProjectCollection); + + // Note that we actually need to mark every project evaluation dirty that is already loaded. + await ReevaluateLoadedConfiguredProjects(_unloadCancellationToken, access); + } + + _filesItemGroup = _inMemoryImport.AddItemGroup(); + _directoriesItemGroup = _inMemoryImport.AddItemGroup(); + _temporaryAddedItemGroup = _inMemoryImport.AddItemGroup(); + } + } + + public Task> AddTemporaryFiles(ConfiguredProject configuredProject, IEnumerable filesToAdd) { + return AddTemporaryItems(configuredProject, "Content", filesToAdd); + } + + public Task> AddTemporaryDirectories(ConfiguredProject configuredProject, IEnumerable directoriesToAdd) { + return AddTemporaryItems(configuredProject, "Folder", directoriesToAdd); + } + + private async Task> AddTemporaryItems(ConfiguredProject configuredProject, string itemType, IEnumerable itemPathsToAdd) { + var unhandled = new List(); + var relativePathToAdd = new List(); + + foreach (var path in itemPathsToAdd) { + if (PathHelper.IsOutsideProjectDirectory(_projectDirectory, _unconfiguredProject.MakeRooted(path))) { + unhandled.Add(path); + } else { + relativePathToAdd.Add(_unconfiguredProject.MakeRelative(path)); + } + } + + if (relativePathToAdd.Count == 0) { + return unhandled.AsReadOnly(); + } + + using (var access = await _projectLockService.WriteLockAsync(_unloadCancellationToken)) { + await access.CheckoutAsync(_inMemoryImportFullPath); + + foreach (var path in relativePathToAdd) { + _temporaryAddedItemGroup.AddItem(itemType, path, Enumerable.Empty>()); + } + + var project = await access.GetProjectAsync(configuredProject, _unloadCancellationToken); + project.ReevaluateIfNecessary(); + } + + return unhandled.AsReadOnly(); + } + + private async Task ReevaluateLoadedConfiguredProjects(CancellationToken cancellationToken, ProjectWriteLockReleaser access) { + foreach (var configuredProject in _unconfiguredProject.LoadedConfiguredProjects) { + try { + var jsproj = await access.GetProjectAsync(configuredProject, cancellationToken); + jsproj.ReevaluateIfNecessary(); + } catch (Exception ex) { + System.Diagnostics.Debug.Fail("We were unable to mark a configuration as dirty" + ex.Message, ex.StackTrace); + } + } + } + + /// + /// Helper used to create the empty project file. + /// Note that we need to set the IsExplicitlyLoaded property on the ProjectRootElement to true to make sure + /// it is not cleared from the ProjectRootElementCache. Unfortuantely, the constructure which creates a new + /// empty project does not set this flag. However, the one which can be created from an XmlReader does. So we use + /// that one to create the project file in memory and then set the path to make sure it is added correctly to the cache. + /// + private ProjectRootElement CreateEmptyMsBuildProject(string projectFilePath, ProjectCollection collection) { + using (XmlReader reader = EmptyProject.CreateReader()) { +#if VS14 + ProjectRootElement importFile = ProjectRootElement.Create(reader, collection); +#else + ProjectRootElement importFile = ProjectRootElement.Create(reader, collection, preserveFormatting: false); +#endif + importFile.FullPath = projectFilePath; + return importFile; + } + } + + private async Task FileSystemChanged(MsBuildFileSystemWatcher.Changeset changeset) { + _log.ApplyProjectChangesStarted(); + + if (_unloadCancellationToken.IsCancellationRequested) { + return; + } + + try { + using (var access = await _projectLockService.WriteLockAsync(_unloadCancellationToken)) { + await access.CheckoutAsync(_inMemoryImportFullPath); + + _temporaryAddedItemGroup.RemoveAllChildren(); + + await RemoveFiles(changeset.RemovedFiles, access); + await RemoveDirectories(changeset.RemovedDirectories, access); + + await RenameFiles(changeset.RenamedFiles, access); + await RenameDirectories(changeset.RenamedDirectories, access); + + AddDirectories(changeset.AddedDirectories); + AddFiles(changeset.AddedFiles); + + _log.MsBuildAfterChangesApplied(_inMemoryImport); + + foreach (var configuredProject in _unconfiguredProject.LoadedConfiguredProjects) { + try { + var project = + await access.GetProjectAsync(configuredProject, _unloadCancellationToken); + project.ReevaluateIfNecessary(); + } catch (Exception ex) { + Trace.Fail("Unable to mark a configuration as dirty" + ex.Message, ex.StackTrace); + } + } + } + } catch (Exception ex) { + Trace.Fail("Unable to handle file system change:" + ex.Message, ex.StackTrace); + } + + _log.ApplyProjectChangesFinished(); + } + + private Task RemoveFiles(HashSet filesToRemove, ProjectWriteLockReleaser access) { + return RemoveItems(_filesItemGroup, _fileItems, filesToRemove, access); + } + + private async Task RemoveDirectories(IReadOnlyCollection directoriesToRemove, ProjectWriteLockReleaser access) { + foreach (var directoryName in directoriesToRemove) { + await RemoveItems(_filesItemGroup, _fileItems, directoryName, access); + await RemoveItems(_directoriesItemGroup, _directoryItems, directoryName, access); + } + } + + private Task RemoveItems(ProjectItemGroupElement parent, Dictionary items, string directoryName, ProjectWriteLockReleaser access) { + return RemoveItems(parent, items, items.Keys.Where(f => f.StartsWithIgnoreCase(directoryName)).ToList(), access); + } + + private async Task RemoveItems(ProjectItemGroupElement parent, Dictionary items, IReadOnlyCollection itemsToRemove, ProjectWriteLockReleaser access) { + await access.CheckoutAsync(itemsToRemove); + foreach (var path in itemsToRemove) { + RemoveItem(parent, items, path); + } + } + + private void RemoveItem(ProjectItemGroupElement parent, Dictionary items, string path) { + ProjectItemElement item; + if (!items.TryGetValue(path, out item)) { + return; + } + + parent.RemoveChild(item); + items.Remove(path); + } + + private Task RenameFiles(IReadOnlyDictionary filesToRename, ProjectWriteLockReleaser access) { + return RenameItems(_fileItems, filesToRename, access); + } + + private async Task RenameDirectories(IReadOnlyDictionary directoriesToRename, ProjectWriteLockReleaser access) { + foreach (var kvp in directoriesToRename) { + await RenameItems(_fileItems, kvp.Key, kvp.Value, access); + await RenameItems(_directoryItems, kvp.Key, kvp.Value, access); + } + } + + private Task RenameItems(Dictionary items, string oldDirectoryName, string newDirectoryName, ProjectWriteLockReleaser access) { + var itemsToRename = items.Keys + .Where(f => f.StartsWithIgnoreCase(oldDirectoryName)) + .ToDictionary(f => f, f => newDirectoryName + f.Substring(oldDirectoryName.Length)); + + return RenameItems(items, itemsToRename, access); + } + + private async Task RenameItems(Dictionary items, IReadOnlyDictionary itemsToRename, ProjectWriteLockReleaser access) { + await access.CheckoutAsync(itemsToRename.Keys); + foreach (var kvp in itemsToRename) { + ProjectItemElement item; + if (items.TryGetValue(kvp.Key, out item)) { + items.Remove(kvp.Key); + item.Include = kvp.Value; + items[kvp.Value] = item; + } + } + } + + private void AddDirectories(IReadOnlyCollection directoriesToAdd) { + foreach (string path in directoriesToAdd) { + RemoveItem(_directoriesItemGroup, _directoryItems, path); + ProjectItemElement item = _directoriesItemGroup.AddItem("Folder", path, Enumerable.Empty>()); + _directoryItems.Add(path, item); + } + } + + private void AddFiles(IReadOnlyCollection filesToAdd) { + // await InMemoryProjectSourceItemProviderExtension.CallListeners(this.SourceItemsAddingListeners, contexts, false); + + foreach (string path in filesToAdd) { + RemoveItem(_filesItemGroup, _fileItems, path); + + var metadata = Enumerable.Empty>(); + // TODO: consider getting this via a provider + var masterFilePath = _dependencyProvider?.GetMasterFile(path); + if (!string.IsNullOrEmpty(masterFilePath)) { + var dict = new Dictionary(); + dict["DependentUpon"] = masterFilePath; + metadata = dict; + } + var item = _filesItemGroup.AddItem("Content", path, metadata); + _fileItems.Add(path, item); + } + + // await InMemoryProjectSourceItemProviderExtension.CallListeners(this.SourceItemsAddedListeners, contexts, false); + } + } + + /// + /// When files or folders are added from VS, CPS requires new items to be added to project at an early stage + /// But since for the FSMP the only source of truth is file system, these items removed from project during next update + /// (which may restore them as added from file system) + /// + public interface IFileSystemMirroringProjectTemporaryItems { + Task> AddTemporaryFiles(ConfiguredProject configuredProject, IEnumerable filesToAdd); + Task> AddTemporaryDirectories(ConfiguredProject configuredProject, IEnumerable directoriesToAdd); + } +} diff --git a/VisualRust.ProjectSystem.FileSystemMirroring/Project/FileSystemMirroringProjectFileGenerator.cs b/VisualRust.ProjectSystem.FileSystemMirroring/Project/FileSystemMirroringProjectFileGenerator.cs new file mode 100644 index 00000000..e315ddf1 --- /dev/null +++ b/VisualRust.ProjectSystem.FileSystemMirroring/Project/FileSystemMirroringProjectFileGenerator.cs @@ -0,0 +1,97 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Xml.Linq; +using Microsoft.Common.Core; +using VisualRust.ProjectSystem.FileSystemMirroring.MsBuild; +using VisualRust.ProjectSystem.FileSystemMirroring.Shell; +using static System.FormattableString; + +namespace VisualRust.ProjectSystem.FileSystemMirroring.Project { + public abstract class FileSystemMirroringProjectFileGenerator : IVsProjectGenerator { + private readonly Guid _projectType; + private readonly string _projectUiSubcaption; + private readonly string _cpsProjExtension; + private readonly IEnumerable _msBuildImports; + + protected FileSystemMirroringProjectFileGenerator(Guid projectType, string projectUiSubcaption, string cpsProjExtension, IEnumerable msBuildImports) { + _projectType = projectType; + _projectUiSubcaption = projectUiSubcaption; + _cpsProjExtension = cpsProjExtension; + _msBuildImports = msBuildImports; + } + + public void RunGenerator(string szSourceFileMoniker, out bool pfProjectIsGenerated, out string pbstrGeneratedFile, out Guid pGuidProjType) { + pfProjectIsGenerated = true; + pbstrGeneratedFile = GetCpsProjFileName(szSourceFileMoniker); + pGuidProjType = _projectType; + + EnsureCpsProjFile(pbstrGeneratedFile); + } + + private string GetCpsProjFileName(string fileName) { + return Path.GetDirectoryName(fileName) + + Path.DirectorySeparatorChar + + Path.GetFileNameWithoutExtension(fileName) + + _cpsProjExtension; + } + + private void EnsureCpsProjFile(string cpsProjFileName) { + var fileInfo = new FileInfo(cpsProjFileName); + if (fileInfo.Exists) { + return; + } + + var inMemoryTargetsFile = FileSystemMirroringProjectUtilities.GetInMemoryTargetsFileName(cpsProjFileName); + + var xProjDocument = new XProjDocument( + new XProject(Toolset.Version, "Build", + new XPropertyGroup("Globals", null, + new XProperty("ProjectGuid", Guid.NewGuid().ToString("D")) + ), + new XPropertyGroup( + new XDefaultValueProperty("VisualStudioVersion", Toolset.Version), + new XDefaultValueProperty("Configuration", "Debug"), + new XDefaultValueProperty("Platform", "AnyCPU") + ), + CreateProjectSpecificPropertyGroup(cpsProjFileName), + CreateProjectUiSubcaption(), + new XProjElement("ProjectExtensions", + new XProjElement("VisualStudio", + new XProjElement("UserProperties") + ) + ), + new XProjElement("Target", new XAttribute("Name", "Build")), + _msBuildImports.SelectMany(CreateMsBuildExtensionXImports), + new XImportExisting(inMemoryTargetsFile) + ) + ); + + using (var writer = fileInfo.CreateText()) { + xProjDocument.Save(writer); + } + } + + protected virtual XPropertyGroup CreateProjectSpecificPropertyGroup(string cpsProjFileName) { + return null; + } + + private XPropertyGroup CreateProjectUiSubcaption() { + return _projectUiSubcaption != null + ? new XPropertyGroup(new XProperty("ProjectUISubcaption", _projectUiSubcaption)) + : null; + } + + private IEnumerable CreateMsBuildExtensionXImports(string import) { + var msBuildImportExtensionPath = Invariant($@"$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\{import}"); + var msBuildImportUserExtensionPath = Invariant($@"$(MSBuildUserExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\{import}"); + + yield return new XImportExisting(msBuildImportUserExtensionPath); + yield return new XImportExisting(msBuildImportExtensionPath, $"!Exists('{msBuildImportUserExtensionPath}')"); + } + } +} \ No newline at end of file diff --git a/VisualRust.ProjectSystem.FileSystemMirroring/Project/FileSystemMirroringProjectSourceItemProviderExtensionBase.cs b/VisualRust.ProjectSystem.FileSystemMirroring/Project/FileSystemMirroringProjectSourceItemProviderExtensionBase.cs new file mode 100644 index 00000000..6475cfdf --- /dev/null +++ b/VisualRust.ProjectSystem.FileSystemMirroring/Project/FileSystemMirroringProjectSourceItemProviderExtensionBase.cs @@ -0,0 +1,128 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.Build.Evaluation; +using Microsoft.Common.Core; +using Microsoft.VisualStudio.ProjectSystem; +using Microsoft.VisualStudio.Threading; +#if VS14 +using Microsoft.VisualStudio.ProjectSystem.Items; +using Microsoft.VisualStudio.ProjectSystem.Utilities; +#endif +using ItemData = System.Tuple>>; + +namespace VisualRust.ProjectSystem.FileSystemMirroring.Project { + public abstract class FileSystemMirroringProjectSourceItemProviderExtensionBase + : IProjectSourceItemProviderExtension, IProjectFolderItemProviderExtension { + + private readonly UnconfiguredProject _unconfiguredProject; + private readonly ConfiguredProject _configuredProject; + private readonly IProjectLockService _projectLockService; + private readonly IFileSystemMirroringProjectTemporaryItems _temporaryItems; + + protected FileSystemMirroringProjectSourceItemProviderExtensionBase(UnconfiguredProject unconfiguredProject, ConfiguredProject configuredProject, IProjectLockService projectLockService, IFileSystemMirroringProjectTemporaryItems temporaryItems) { + _unconfiguredProject = unconfiguredProject; + _configuredProject = configuredProject; + _projectLockService = projectLockService; + _temporaryItems = temporaryItems; + } + +#region IProjectSourceItemProviderExtension implementation + + public Task CheckSourceItemOwnershipAsync(string itemType, string evaluatedInclude) { + return this.CheckFolderItemOwnershipAsync(evaluatedInclude); + } + + public Task CheckProjectFileOwnershipAsync(string projectFilePath) { + return this.CheckProjectFileOwnership(projectFilePath) + ? TplExtensions.TrueTask + : TplExtensions.FalseTask; + } + + public async Task> AddOwnedSourceItemsAsync(IReadOnlyCollection items) { + var unhandledItems = await _temporaryItems.AddTemporaryFiles(_configuredProject, items.Select(i => i.Item2)); + return items.Where(i => unhandledItems.Contains(i.Item2)).ToImmutableArray(); + } + + public async Task TryAddSourceItemsToOwnedProjectFileAsync(IReadOnlyCollection items, string projectFilePath) { + if (!CheckProjectFileOwnership(projectFilePath)) { + return false; + } + + var unhandledItems = await _temporaryItems.AddTemporaryFiles(_configuredProject, items.Select(i => i.Item2)); + return unhandledItems.Count < items.Count; + } + + public Task> RemoveOwnedSourceItemsAsync( + IReadOnlyCollection projectItems, DeleteOptions deleteOptions) { + var projectDirectory = _unconfiguredProject.GetProjectDirectory(); + List itemsInProjectFolder = projectItems + .Where(item => !PathHelper.IsOutsideProjectDirectory(projectDirectory, item.EvaluatedIncludeAsFullPath)) + .ToList(); + + return + Task.FromResult(itemsInProjectFolder.Count == 0 + ? projectItems + : projectItems.Except(itemsInProjectFolder).ToImmutableArray()); + } + + public Task RenameOwnedSourceItemAsync(IProjectItem projectItem, string newValue) { + return GetMsBuildItemByProjectItem(projectItem); + } + + public Task SetItemTypeOfOwnedSourceItemAsync(IProjectItem projectItem, string newItemType) { + return GetMsBuildItemByProjectItem(projectItem); + } + +#endregion + +#region IProjectFolderItemProviderExtension implementation + + public Task CheckFolderItemOwnershipAsync(string evaluatedInclude) { + return _unconfiguredProject.IsOutsideProjectDirectory(_unconfiguredProject.MakeRooted(evaluatedInclude)) + ? TplExtensions.FalseTask + : TplExtensions.TrueTask; + } + + public async Task>>> AddOwnedFolderItemsAsync(IReadOnlyDictionary>> items) { + var unhandledItems = await _temporaryItems.AddTemporaryDirectories(_configuredProject, items.Keys); + return items.Where(i => unhandledItems.Contains(i.Key)).ToImmutableDictionary(); + } + + public Task> RemoveOwnedFolderItemsAsync( + IReadOnlyCollection projectItems, DeleteOptions deleteOptions) { + List itemsInProjectFolder = projectItems + .Where(item => !_unconfiguredProject.IsOutsideProjectDirectory(item.EvaluatedIncludeAsFullPath)) + .ToList(); + + return + Task.FromResult(itemsInProjectFolder.Count == 0 + ? projectItems + : projectItems.Except(itemsInProjectFolder).ToImmutableArray()); + } + + public Task RenameOwnedFolderItemAsync(IProjectItem projectItem, string newValue) { + return GetMsBuildItemByProjectItem(projectItem); + } + +#endregion + + private bool CheckProjectFileOwnership(string projectFilePath) { + return _unconfiguredProject.GetInMemoryTargetsFileFullPath().EqualsIgnoreCase(projectFilePath); + } + + private async Task GetMsBuildItemByProjectItem(IProjectItem projectItem) { + using (var access = await _projectLockService.ReadLockAsync()) { + var project = await access.GetProjectAsync(_configuredProject); + var item = project.GetItemsByEvaluatedInclude(projectItem.EvaluatedInclude) + .FirstOrDefault(pi => StringComparer.OrdinalIgnoreCase.Equals(pi.ItemType, projectItem.ItemType)); + return item; + } + } + } +} diff --git a/VisualRust.ProjectSystem.FileSystemMirroring/Project/FileSystemMirroringProjectUtilities.cs b/VisualRust.ProjectSystem.FileSystemMirroring/Project/FileSystemMirroringProjectUtilities.cs new file mode 100644 index 00000000..43e40a84 --- /dev/null +++ b/VisualRust.ProjectSystem.FileSystemMirroring/Project/FileSystemMirroringProjectUtilities.cs @@ -0,0 +1,25 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System.IO; +using Microsoft.VisualStudio.ProjectSystem; +#if VS14 +using Microsoft.VisualStudio.ProjectSystem.Utilities; +#endif + +namespace VisualRust.ProjectSystem.FileSystemMirroring.Project { + public static class FileSystemMirroringProjectUtilities { + public static string GetProjectDirectory(this UnconfiguredProject unconfiguredProject) { + return PathHelper.EnsureTrailingSlash(Path.GetDirectoryName(unconfiguredProject.FullPath)); + } + + public static string GetInMemoryTargetsFileFullPath(this UnconfiguredProject unconfiguredProject) { + var projectPath = unconfiguredProject.FullPath; + return Path.Combine(Path.GetDirectoryName(projectPath), GetInMemoryTargetsFileName(projectPath)); + } + + public static string GetInMemoryTargetsFileName(string cpsProjFileName) { + return Path.GetFileNameWithoutExtension(cpsProjFileName) + ".InMemory.Targets"; + } + } +} diff --git a/VisualRust.ProjectSystem.FileSystemMirroring/Project/IProjectItemDependencyProvider.cs b/VisualRust.ProjectSystem.FileSystemMirroring/Project/IProjectItemDependencyProvider.cs new file mode 100644 index 00000000..9215969f --- /dev/null +++ b/VisualRust.ProjectSystem.FileSystemMirroring/Project/IProjectItemDependencyProvider.cs @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +namespace VisualRust.ProjectSystem.FileSystemMirroring.Project { + /// + /// Allows creation of nested items in the project. Exported via MEF. + /// + public interface IProjectItemDependencyProvider { + /// + /// For a given child file returns master file (root of the nested set). + /// For example, returns Script.R for Script.R.sql. + string GetMasterFile(string childFilePath); + } +} diff --git a/VisualRust.ProjectSystem.FileSystemMirroring/Properties/AssemblyInfo.cs b/VisualRust.ProjectSystem.FileSystemMirroring/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..af033a40 --- /dev/null +++ b/VisualRust.ProjectSystem.FileSystemMirroring/Properties/AssemblyInfo.cs @@ -0,0 +1,3 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + diff --git a/VisualRust.ProjectSystem.FileSystemMirroring/Shell/IVsProjectGenerator.cs b/VisualRust.ProjectSystem.FileSystemMirroring/Shell/IVsProjectGenerator.cs new file mode 100644 index 00000000..accd3759 --- /dev/null +++ b/VisualRust.ProjectSystem.FileSystemMirroring/Shell/IVsProjectGenerator.cs @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace VisualRust.ProjectSystem.FileSystemMirroring.Shell { + [Guid("FDFD5BE5-A51B-42D6-932C-CF95686EA4DB")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + public interface IVsProjectGenerator { + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void RunGenerator([ComAliasName("OLE.LPCWSTR"), MarshalAs(UnmanagedType.LPWStr), In] string szSourceFileMoniker, out bool pfProjectIsGenerated, [MarshalAs(UnmanagedType.BStr)] out string pbstrGeneratedFile, out Guid pGuidProjType); + } +} diff --git a/VisualRust.ProjectSystem.FileSystemMirroring/Shell/IVsRegisterProjectGenerators.cs b/VisualRust.ProjectSystem.FileSystemMirroring/Shell/IVsRegisterProjectGenerators.cs new file mode 100644 index 00000000..53ffc817 --- /dev/null +++ b/VisualRust.ProjectSystem.FileSystemMirroring/Shell/IVsRegisterProjectGenerators.cs @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace VisualRust.ProjectSystem.FileSystemMirroring.Shell { + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [Guid("9FDECA99-9A9D-44A8-98AF-C5A285EEFB47")] + [ComImport] + public interface IVsRegisterProjectGenerators { + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void RegisterProjectGenerator([ComAliasName("OLE.REFGUID"), In] ref Guid rguidProjGenerator, [MarshalAs(UnmanagedType.Interface), In] IVsProjectGenerator pProjectGenerator, [ComAliasName("EnvDTE.ULONG_PTR")] out uint pdwCookie); + + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void UnregisterProjectGenerator([ComAliasName("EnvDTE.ULONG_PTR"), In] uint dwCookie); + } +} diff --git a/VisualRust.ProjectSystem.FileSystemMirroring/Utilities/DictionaryExtensions.cs b/VisualRust.ProjectSystem.FileSystemMirroring/Utilities/DictionaryExtensions.cs new file mode 100644 index 00000000..5a65df0f --- /dev/null +++ b/VisualRust.ProjectSystem.FileSystemMirroring/Utilities/DictionaryExtensions.cs @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Linq; + +namespace VisualRust.ProjectSystem.FileSystemMirroring.Utilities { + public static class DictionaryExtensions { + public static TKey GetFirstKeyByValueIgnoreCase(this IDictionary dictionary, string value) { + return dictionary.GetFirstKeyByValue(value, StringComparer.OrdinalIgnoreCase); + } + + public static TKey GetFirstKeyByValue(this IDictionary dictionary, TValue value, IEqualityComparer comparer) { + comparer = comparer ?? EqualityComparer.Default; + return dictionary.FirstOrDefault(kvp => comparer.Equals(kvp.Value, value)).Key; + } + } +} diff --git a/VisualRust.ProjectSystem.FileSystemMirroring/Utilities/PathExtensions.cs b/VisualRust.ProjectSystem.FileSystemMirroring/Utilities/PathExtensions.cs new file mode 100644 index 00000000..22bfd048 --- /dev/null +++ b/VisualRust.ProjectSystem.FileSystemMirroring/Utilities/PathExtensions.cs @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using Microsoft.Common.Core.IO; +#if VS14 +using Microsoft.VisualStudio.ProjectSystem.Utilities; +#endif + +namespace VisualRust.ProjectSystem.FileSystemMirroring.Utilities { + public static class PathExtensions { + /// + /// Converts path to file to a relative 8.3 path. Returns null if file + /// does not exist since OS can only perform 8.3 conversion to existing files. + /// + public static string ToShortRelativePath(this IFileSystem fileSystem, string path, string rootFolder) { + // ToShortPath will return null if files does not exist since conversion + // to 8.3 path can only be performed to files that exist. + var shortPath = fileSystem.ToShortPath(path); + var rootShortPath = fileSystem.ToShortPath(rootFolder); + return !string.IsNullOrEmpty(shortPath) ? PathHelper.MakeRelative(rootShortPath, shortPath) : null; + } + } +} diff --git a/VisualRust.ProjectSystem.FileSystemMirroring/Utilities/ServiceProviderExtensions.cs b/VisualRust.ProjectSystem.FileSystemMirroring/Utilities/ServiceProviderExtensions.cs new file mode 100644 index 00000000..ab9b3b02 --- /dev/null +++ b/VisualRust.ProjectSystem.FileSystemMirroring/Utilities/ServiceProviderExtensions.cs @@ -0,0 +1,15 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.Threading; + +namespace VisualRust.ProjectSystem.FileSystemMirroring.Utilities { + public static class ServiceProviderExtensions { + public static Lazy GetServiceLazy(this IServiceProvider serviceProvider, Type serviceType = null, LazyThreadSafetyMode mode = LazyThreadSafetyMode.ExecutionAndPublication) + where T : class { + serviceType = serviceType ?? typeof(T); + return new Lazy(() => serviceProvider.GetService(serviceType) as T, mode); + } + } +} diff --git a/VisualRust.ProjectSystem.FileSystemMirroring/Utilities/VsSolutionBuildManagerExtensions.cs b/VisualRust.ProjectSystem.FileSystemMirroring/Utilities/VsSolutionBuildManagerExtensions.cs new file mode 100644 index 00000000..6f07e3de --- /dev/null +++ b/VisualRust.ProjectSystem.FileSystemMirroring/Utilities/VsSolutionBuildManagerExtensions.cs @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.Runtime.InteropServices; +using Microsoft.VisualStudio.Shell.Interop; + +namespace VisualRust.ProjectSystem.FileSystemMirroring.Utilities { + public static class VsSolutionBuildManagerExtensions { + public static string FindActiveProjectCfgName(this IVsSolutionBuildManager5 solutionBuildManager, Guid projectId) { + string projectCfgCanonicalName; + var hr = solutionBuildManager.FindActiveProjectCfgName(ref projectId, out projectCfgCanonicalName); + if (hr < 0) { + Marshal.ThrowExceptionForHR(hr); + } + return projectCfgCanonicalName; + } + } +} diff --git a/VisualRust.ProjectSystem.FileSystemMirroring/VisualRust.ProjectSystem.FileSystemMirroring.csproj b/VisualRust.ProjectSystem.FileSystemMirroring/VisualRust.ProjectSystem.FileSystemMirroring.csproj new file mode 100644 index 00000000..1a88977a --- /dev/null +++ b/VisualRust.ProjectSystem.FileSystemMirroring/VisualRust.ProjectSystem.FileSystemMirroring.csproj @@ -0,0 +1,104 @@ + + + + + Debug + AnyCPU + {B8696D0C-8ADB-4C11-8CEE-5C81AA8C6EBD} + Library + Properties + VisualRust.ProjectSystem.FileSystemMirroring + VisualRust.ProjectSystem.FileSystemMirroring + v4.6 + 512 + + + + true + full + false + bin\Debug\ + TRACE;DEBUG;VS14 + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE;VS14 + prompt + 4 + + + true + + + Key.snk + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {5da4c00b-9f16-4ef9-894d-20329544265e} + Microsoft.Common.Core + + + + + \ No newline at end of file diff --git a/VisualRust.ProjectSystem.FileSystemMirroring/VisualRust.ProjectSystem.FileSystemMirroring.nuget.props b/VisualRust.ProjectSystem.FileSystemMirroring/VisualRust.ProjectSystem.FileSystemMirroring.nuget.props new file mode 100644 index 00000000..bbc139e2 --- /dev/null +++ b/VisualRust.ProjectSystem.FileSystemMirroring/VisualRust.ProjectSystem.FileSystemMirroring.nuget.props @@ -0,0 +1,9 @@ + + + + $(UserProfile)\.nuget\packages\ + + + + + \ No newline at end of file diff --git a/VisualRust.ProjectSystem.FileSystemMirroring/VisualRust.ProjectSystem.FileSystemMirroring.nuget.targets b/VisualRust.ProjectSystem.FileSystemMirroring/VisualRust.ProjectSystem.FileSystemMirroring.nuget.targets new file mode 100644 index 00000000..e050113a --- /dev/null +++ b/VisualRust.ProjectSystem.FileSystemMirroring/VisualRust.ProjectSystem.FileSystemMirroring.nuget.targets @@ -0,0 +1,11 @@ + + + + $(UserProfile)\.nuget\packages\ + + + + + + + \ No newline at end of file diff --git a/VisualRust.ProjectSystem.FileSystemMirroring/project.json b/VisualRust.ProjectSystem.FileSystemMirroring/project.json new file mode 100644 index 00000000..fa4fa88f --- /dev/null +++ b/VisualRust.ProjectSystem.FileSystemMirroring/project.json @@ -0,0 +1,18 @@ +{ + "dependencies": { + "MicroBuild.Core": "0.2.0", + "Microsoft.Build": "14.3.0", + "Microsoft.Tpl.Dataflow": "4.5.24", + "Microsoft.VisualStudio.ProjectSystem": "14.1.127-pre", + "Microsoft.VisualStudio.SDK.EmbedInteropTypes": "14.1.2", + "Microsoft.VisualStudio.Shell.Immutable.10.0": "10.0.30319", + "Microsoft.VisualStudio.Shell.Interop.11.0": "11.0.61030", + "System.Collections.Immutable": "1.1.37" + }, + "frameworks": { + "net46": {} + }, + "runtimes": { + "win": {} + } +} \ No newline at end of file diff --git a/VisualRust.Setup/VisualRust.Setup.wixproj b/VisualRust.Setup/VisualRust.Setup.wixproj index eaa9fb33..c0832cc3 100644 --- a/VisualRust.Setup/VisualRust.Setup.wixproj +++ b/VisualRust.Setup/VisualRust.Setup.wixproj @@ -24,31 +24,13 @@ bin\$(Configuration)\ obj\$(Configuration)\ - - Debug - bin\$(Platform)\$(Configuration)\ - obj\$(Platform)\$(Configuration)\ - - - bin\$(Platform)\$(Configuration)\ - obj\$(Platform)\$(Configuration)\ - - - bin\$(Platform)\$(Configuration)\ - obj\$(Platform)\$(Configuration)\ - - - - - - diff --git a/VisualRust.Setup/VisualRust.wxs b/VisualRust.Setup/VisualRust.wxs index 98bfaec8..11dbb329 100644 --- a/VisualRust.Setup/VisualRust.wxs +++ b/VisualRust.Setup/VisualRust.wxs @@ -3,7 +3,7 @@ - - - - @@ -41,22 +37,7 @@ Level="1" Absent="disallow"> - - - - - - - - - - - - - + @@ -81,30 +62,84 @@ + Name="VisualRust"> + + - + - + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + diff --git a/VisualRust.Setup/gdb/gdb.2013.i686.wxs b/VisualRust.Setup/gdb/gdb.2013.i686.wxs deleted file mode 100644 index 752065c2..00000000 --- a/VisualRust.Setup/gdb/gdb.2013.i686.wxs +++ /dev/null @@ -1,619 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/VisualRust.Setup/gdb/gdb.2013.x86_64.wxs b/VisualRust.Setup/gdb/gdb.2013.x86_64.wxs deleted file mode 100644 index c21929ef..00000000 --- a/VisualRust.Setup/gdb/gdb.2013.x86_64.wxs +++ /dev/null @@ -1,619 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/VisualRust.Setup/racer2013.wxs b/VisualRust.Setup/racer2013.wxs deleted file mode 100644 index 28fefb67..00000000 --- a/VisualRust.Setup/racer2013.wxs +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/VisualRust.Setup/templates2013.wxs b/VisualRust.Setup/templates2013.wxs deleted file mode 100644 index e4fc5dfa..00000000 --- a/VisualRust.Setup/templates2013.wxs +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/VisualRust.Setup/vsx2013.wxs b/VisualRust.Setup/vsx2013.wxs deleted file mode 100644 index cf2929b5..00000000 --- a/VisualRust.Setup/vsx2013.wxs +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Removing ancient version of Visual Rust - Configuring Visual Studio 2013 (this might take a few minutes) - - - \ No newline at end of file diff --git a/VisualRust.Setup/vsx2015.wxs b/VisualRust.Setup/vsx2015.wxs index 37298d99..2ee7a54c 100644 --- a/VisualRust.Setup/vsx2015.wxs +++ b/VisualRust.Setup/vsx2015.wxs @@ -10,8 +10,11 @@ - - + + + + + @@ -23,9 +26,6 @@ - - - @@ -35,9 +35,21 @@ + + + + + + + + + + + + - + @@ -46,6 +58,7 @@ + diff --git a/VisualRust.Shared/Cargo.cs b/VisualRust.Shared/Cargo.cs new file mode 100644 index 00000000..9b4af7d1 --- /dev/null +++ b/VisualRust.Shared/Cargo.cs @@ -0,0 +1,122 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading; +using System.Threading.Tasks; + +namespace VisualRust.Shared +{ + // TODO: add rustup support, including automatic detection of installed targets + [DebuggerDisplay("Cargo [{path,nq}]")] + public class Cargo + { + public static readonly JsonSerializer JsonSerializer = new JsonSerializer { MissingMemberHandling = MissingMemberHandling.Ignore }; + public string Executable { get; } + public string RustcExecutable { get; } + + public string WorkingDirectory { get; set; } + + private Cargo(string exe) + { + Executable = exe; + RustcExecutable = Path.Combine(Path.GetDirectoryName(exe), "rustc.exe"); + WorkingDirectory = null; + } + + /// + /// Returns a wrapper for an installed cargo.exe that understands --message-format, + /// or null if none was found. + /// + public static Cargo FindSupportedInstallation() + { + var installPath = Environment.GetAllInstallPaths() + .Select(p => Path.Combine(Path.Combine(p, "bin"), "cargo.exe")) + .FirstOrDefault(p => { + if (!File.Exists(p)) return false; + var version = GetCargoVersion(p); + return version.HasValue && version.Value.Date >= new DateTime(2016, 10, 06); + }); + + if (installPath == null) + { + return null; + } + + return new Cargo(installPath); + } + + public Task RunAsync(params string[] arguments) + { + return RunAsync(arguments, default(CancellationToken)); + } + + public Task RunAsync(string[] arguments, CancellationToken cancellationToken = default(CancellationToken)) + { + return CommandHelper.RunAsync(Executable, arguments, WorkingDirectory, cancellationToken); + } + + public async Task GetSysrootAsync() + { + var result = await CommandHelper.RunAsync(RustcExecutable, "--print=sysroot"); + return result.Output.Trim(); + } + + public async Task GetHostTargetTripleAsync() + { + var result = await CommandHelper.RunAsync(RustcExecutable, "-vV"); + Match hostMatch = Regex.Match(result.Output, "^host:\\s*(.+)$", RegexOptions.Multiline); + if (hostMatch.Groups.Count < 2) + return null; + return TargetTriple.Create(hostMatch.Groups[1].Value.TrimEnd()); + } + + public async Task ReadMetadataAsync(bool includeDependencies) + { + string[] args; + if (includeDependencies) + { + args = new string[] { "metadata" }; + } + else + { + args = new string[] { "metadata", "--no-deps" }; + } + + + var result = await RunAsync(args); + return JsonSerializer.Deserialize(new JsonTextReader(new StringReader(result.Output))); + } + + protected static ToolVersion? GetCargoVersion(string exePath) + { + ProcessStartInfo psi = new ProcessStartInfo + { + UseShellExecute = false, + CreateNoWindow = true, + FileName = exePath, + RedirectStandardOutput = true, + Arguments = "-V" + }; + try + { + Process proc = Process.Start(psi); + string versionOutput = proc.StandardOutput.ReadToEnd(); + return ToolVersion.Parse(versionOutput); + } + catch (Win32Exception) + { + return null; + } + catch (IOException) + { + return null; + } + } + } +} diff --git a/VisualRust.Shared/CommandHelper.cs b/VisualRust.Shared/CommandHelper.cs new file mode 100644 index 00000000..82a7c8e0 --- /dev/null +++ b/VisualRust.Shared/CommandHelper.cs @@ -0,0 +1,116 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading; +using System.Threading.Tasks; + +namespace VisualRust.Shared +{ + public struct CommandResult + { + public string Output { get; } + public int ExitCode { get; } + + public CommandResult(string output, int exitCode) + { + Output = output; + ExitCode = exitCode; + } + } + + public static class CommandHelper + { + private static Regex escapeInvalidChar = new Regex("[\x00\x0a\x0d]", RegexOptions.Compiled);// these can not be escaped + private static Regex escapeNeedsQuotes = new Regex(@"\s|""", RegexOptions.Compiled);// contains whitespace or two quote characters + private static Regex escapeEscapeQuote = new Regex(@"(\\*)(""|$)", RegexOptions.Compiled);// one or more '\' followed with a quote or end of string + + /// + /// Quotes all arguments that contain whitespace, or begin with a quote and returns a single + /// argument string for use with Process.Start(). + /// + /// A list of strings for arguments, may not contain null, '\0', '\r', or '\n' + /// The combined list of escaped/quoted strings + /// Raised when one of the arguments is null + /// Raised if an argument contains '\0', '\r', or '\n' + public static string EscapeArguments(string[] args) + { + // SOURCE OF THIS CODE: http://csharptest.net/529/how-to-correctly-escape-command-line-arguments-in-c/ + StringBuilder arguments = new StringBuilder(); + + for (int carg = 0; args != null && carg < args.Length; carg++) + { + if (args[carg] == null) { throw new ArgumentNullException("args[" + carg + "]"); } + if (escapeInvalidChar.IsMatch(args[carg])) { throw new ArgumentOutOfRangeException("args[" + carg + "]"); } + if (args[carg] == String.Empty) { arguments.Append("\"\""); } + else if (!escapeNeedsQuotes.IsMatch(args[carg])) { arguments.Append(args[carg]); } + else + { + arguments.Append('"'); + arguments.Append(escapeEscapeQuote.Replace(args[carg], m => + m.Groups[1].Value + m.Groups[1].Value + + (m.Groups[2].Value == "\"" ? "\\\"" : "") + )); + arguments.Append('"'); + } + if (carg + 1 < args.Length) + arguments.Append(' '); + } + return arguments.ToString(); + } + + public static Task RunAsync(string command, params string[] arguments) + { + return RunAsync(command, arguments, null, default(CancellationToken)); + } + + public static Task RunAsync(string command, string[] arguments, string workingDirectory = null, CancellationToken cancellationToken = default(CancellationToken)) + { + ProcessStartInfo psi = new ProcessStartInfo + { + UseShellExecute = false, + CreateNoWindow = true, + FileName = command, + RedirectStandardOutput = true, + Arguments = CommandHelper.EscapeArguments(arguments) + }; + + if (!string.IsNullOrEmpty(workingDirectory)) + { + psi.WorkingDirectory = workingDirectory; + } + + var tcs = new TaskCompletionSource(); + var outputBuffer = new StringBuilder(); + var process = new Process(); + process.StartInfo = psi; + process.EnableRaisingEvents = true; + process.OutputDataReceived += (sender, args) => { + if (args.Data == null) + { + Debug.Assert(process.HasExited); + tcs.TrySetResult(new CommandResult(outputBuffer.ToString(), process.ExitCode)); + } + else + { + outputBuffer.AppendLine(args.Data); + } + }; + if (cancellationToken != default(CancellationToken)) + { + cancellationToken.Register(() => + { + tcs.SetCanceled(); + process.Kill(); + }); + } + + process.Start(); + process.BeginOutputReadLine(); + return tcs.Task; + } + } +} diff --git a/VisualRust.Shared/Environment.cs b/VisualRust.Shared/Environment.cs index 37deeee2..8e897496 100644 --- a/VisualRust.Shared/Environment.cs +++ b/VisualRust.Shared/Environment.cs @@ -11,7 +11,7 @@ namespace VisualRust.Shared { - public class Environment + public static class Environment { private const string InnoPath = @"Software\Microsoft\Windows\CurrentVersion\Uninstall\Rust_is1"; private static readonly string[] MozillaPaths = { @"Software\Mozilla Foundation", @"Software\The Rust Project Developers" }; @@ -47,6 +47,7 @@ public static IEnumerable FindCurrentUserInstallPaths() } } + // TODO: this is wrong, because we're checking the host triple, not the availability of a target public static TargetTriple GetTarget(string exePath) { if (!File.Exists(exePath)) @@ -79,7 +80,7 @@ public static TargetTriple GetTarget(string exePath) return TargetTriple.Create(hostMatch.Groups[1].Value); } - private static IEnumerable GetAllInstallPaths() + public static IEnumerable GetAllInstallPaths() { if (System.Environment.Is64BitOperatingSystem) { diff --git a/VisualRust.Shared/Message/CargoMessage.cs b/VisualRust.Shared/Message/CargoMessage.cs new file mode 100644 index 00000000..ccf66ad0 --- /dev/null +++ b/VisualRust.Shared/Message/CargoMessage.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace VisualRust.Shared.Message +{ + // See /src/cargo/util/machine_message.rs in the cargo repository + public class CargoMessage + { + public string reason { get; set; } + public string package_id { get; set; } + public CargoTarget target { get; set; } + public RustcMessageJson message { get; set; } + } +} diff --git a/VisualRust.Shared/Message/CargoMetadata.cs b/VisualRust.Shared/Message/CargoMetadata.cs new file mode 100644 index 00000000..93c95d06 --- /dev/null +++ b/VisualRust.Shared/Message/CargoMetadata.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace VisualRust.Shared.Message +{ + public class CargoMetadata + { + public List packages { get; set; } + // ... more fields omitted, can be added as necessary + } + + public class CargoPackage + { + public string name { get; set; } + public string version { get; set; } // TODO: use better type + public string id { get; set; } + public string manifest_path { get; set; } + public List targets { get; set; } + // ... more fields omitted, can be added as necessary + } + + public class CargoTarget + { + public List kind { get; set; } + public string name { get; set; } + public string src_path { get; set; } + } +} diff --git a/VisualRust.Build/Message/Human/RustcMessageHuman.cs b/VisualRust.Shared/Message/RustcMessageHuman.cs similarity index 95% rename from VisualRust.Build/Message/Human/RustcMessageHuman.cs rename to VisualRust.Shared/Message/RustcMessageHuman.cs index 8f3c2488..207ec7dc 100644 --- a/VisualRust.Build/Message/Human/RustcMessageHuman.cs +++ b/VisualRust.Shared/Message/RustcMessageHuman.cs @@ -1,6 +1,6 @@ -namespace VisualRust.Build.Message.Human +namespace VisualRust.Shared.Message { - class RustcMessageHuman + public class RustcMessageHuman { public RustcMessageType Type; public string Message; diff --git a/VisualRust.Build/Message/Human/RustcMessageHumanParser.cs b/VisualRust.Shared/Message/RustcMessageHumanParser.cs similarity index 96% rename from VisualRust.Build/Message/Human/RustcMessageHumanParser.cs rename to VisualRust.Shared/Message/RustcMessageHumanParser.cs index e555410a..352e06a5 100644 --- a/VisualRust.Build/Message/Human/RustcMessageHumanParser.cs +++ b/VisualRust.Shared/Message/RustcMessageHumanParser.cs @@ -3,9 +3,10 @@ using System.Globalization; using System.Text.RegularExpressions; -namespace VisualRust.Build.Message.Human +namespace VisualRust.Shared.Message { - static class RustcMessageHumanParser + // TODO: probably we should just get rid of this + public static class RustcMessageHumanParser { private static readonly Regex defectRegex = new Regex(@"^([^\n:]+):(\d+):(\d+):\s+(\d+):(\d+)\s+(.*)$", RegexOptions.Multiline | RegexOptions.CultureInvariant); diff --git a/VisualRust.Build/Message/Json/RustcMessageJson.cs b/VisualRust.Shared/Message/RustcMessageJson.cs similarity index 99% rename from VisualRust.Build/Message/Json/RustcMessageJson.cs rename to VisualRust.Shared/Message/RustcMessageJson.cs index e958a4ba..7ddd5c2f 100644 --- a/VisualRust.Build/Message/Json/RustcMessageJson.cs +++ b/VisualRust.Shared/Message/RustcMessageJson.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Linq; -namespace VisualRust.Build.Message.Json +namespace VisualRust.Shared.Message { public class RustcMessageJson { diff --git a/VisualRust.Build/Message/Json/RustcMessageJsonParser.cs b/VisualRust.Shared/Message/RustcMessageJsonParser.cs similarity index 93% rename from VisualRust.Build/Message/Json/RustcMessageJsonParser.cs rename to VisualRust.Shared/Message/RustcMessageJsonParser.cs index c0f8950a..2d5bdd19 100644 --- a/VisualRust.Build/Message/Json/RustcMessageJsonParser.cs +++ b/VisualRust.Shared/Message/RustcMessageJsonParser.cs @@ -3,7 +3,7 @@ using System.IO; using Newtonsoft.Json; -namespace VisualRust.Build.Message.Json +namespace VisualRust.Shared.Message { public static class RustcMessageJsonParser { diff --git a/VisualRust.Build/Message/RustcMessageType.cs b/VisualRust.Shared/Message/RustcMessageType.cs similarity index 73% rename from VisualRust.Build/Message/RustcMessageType.cs rename to VisualRust.Shared/Message/RustcMessageType.cs index a3a3e7f3..6729377a 100644 --- a/VisualRust.Build/Message/RustcMessageType.cs +++ b/VisualRust.Shared/Message/RustcMessageType.cs @@ -1,4 +1,4 @@ -namespace VisualRust.Build.Message +namespace VisualRust.Shared.Message { public enum RustcMessageType { diff --git a/VisualRust.Shared/Properties/AssemblyInfo.cs b/VisualRust.Shared/Properties/AssemblyInfo.cs index 70fbe415..cef605ef 100644 --- a/VisualRust.Shared/Properties/AssemblyInfo.cs +++ b/VisualRust.Shared/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.1.2.0")] -[assembly: AssemblyFileVersion("0.1.2.0")] +[assembly: AssemblyVersion("0.2.0.0")] +[assembly: AssemblyFileVersion("0.2.0.0")] diff --git a/VisualRust.Shared/TargetTriple.cs b/VisualRust.Shared/TargetTriple.cs index 3ed2a06c..53734bf9 100644 --- a/VisualRust.Shared/TargetTriple.cs +++ b/VisualRust.Shared/TargetTriple.cs @@ -26,14 +26,24 @@ public static TargetTriple Create(string text) if(text == null) return null; string[] parts = text.ToLowerInvariant().Split('-'); - if(parts.Length != 4) + string abi; + if (parts.Length < 3) return null; - return new TargetTriple(parts[0], parts[1], parts[2], parts[3]); + else if (parts.Length < 4) + abi = ""; + else if (parts.Length == 4) + abi = parts[3]; + else + return null; + return new TargetTriple(parts[0], parts[1], parts[2], abi); } public override string ToString() { - return String.Format("{0}-{1}-{2}-{3}", Arch, Vendor, System, Abi); + if (String.IsNullOrEmpty(Abi)) + return String.Format("{0}-{1}-{2}", Arch, Vendor, System); + else + return String.Format("{0}-{1}-{2}-{3}", Arch, Vendor, System, Abi); } } } diff --git a/VisualRust.Shared/ToolVersion.cs b/VisualRust.Shared/ToolVersion.cs new file mode 100644 index 00000000..0d89a1fc --- /dev/null +++ b/VisualRust.Shared/ToolVersion.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace VisualRust.Shared +{ + /// + /// Used to parse version strings (-v flag) from Rust tools (rustc and cargo) + /// + public struct ToolVersion + { + public uint Major { get; private set; } + public uint Minor { get; private set; } + public uint Patch { get; private set; } + public string PreRelease { get; private set; } + public string GitHash { get; private set; } + public DateTime Date { get; private set; } + + private static Regex versionRegex = new Regex(@"(\w+) (\d+)\.(\d+)\.(\d+)(-(\w+))? \((\w+) (\d{4})-(\d{2})-(\d{2})\)", RegexOptions.Compiled); + + public static ToolVersion? Parse(string versionString) + { + var match = versionRegex.Match(versionString); + if (!match.Success) return null; + + uint major, minor, patch; + if (!uint.TryParse(match.Groups[2].Value, out major)) return null; + if (!uint.TryParse(match.Groups[3].Value, out minor)) return null; + if (!uint.TryParse(match.Groups[4].Value, out patch)) return null; + string preRelease = match.Groups[6].Value; + string gitHash = match.Groups[7].Value; + int year, month, day; + if (!int.TryParse(match.Groups[8].Value, out year)) return null; + if (!int.TryParse(match.Groups[9].Value, out month)) return null; + if (!int.TryParse(match.Groups[10].Value, out day)) return null; + + return new ToolVersion + { + Major = major, + Minor = minor, + Patch = patch, + PreRelease = preRelease, + GitHash = gitHash, + Date = new DateTime(year, month, day) + }; + } + } +} diff --git a/VisualRust.Shared/VisualRust.Shared.csproj b/VisualRust.Shared/VisualRust.Shared.csproj index ce0ac947..5bd31aec 100644 --- a/VisualRust.Shared/VisualRust.Shared.csproj +++ b/VisualRust.Shared/VisualRust.Shared.csproj @@ -13,6 +13,7 @@ 512 True ..\VisualRust\Key.snk + true @@ -36,11 +37,24 @@ + + + + + + + + + + + + + + + Cargo.toml + main.rs \ No newline at end of file diff --git a/VisualRust.Templates/Projects/Application/Cargo.toml b/VisualRust.Templates/Projects/Application/Cargo.toml new file mode 100644 index 00000000..57b48cdd --- /dev/null +++ b/VisualRust.Templates/Projects/Application/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "$safeprojectname$" +version = "0.1.0" +authors = ["$username$"] + +[dependencies] diff --git a/VisualRust.Templates/Projects/Application/main.rs b/VisualRust.Templates/Projects/Application/main.rs index 39acf833..e7a11a96 100644 --- a/VisualRust.Templates/Projects/Application/main.rs +++ b/VisualRust.Templates/Projects/Application/main.rs @@ -1,3 +1,3 @@ fn main() { - println!("Hello, world!") -} \ No newline at end of file + println!("Hello, world!"); +} diff --git a/VisualRust.Templates/Projects/Library/Cargo.toml b/VisualRust.Templates/Projects/Library/Cargo.toml new file mode 100644 index 00000000..57b48cdd --- /dev/null +++ b/VisualRust.Templates/Projects/Library/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "$safeprojectname$" +version = "0.1.0" +authors = ["$username$"] + +[dependencies] diff --git a/VisualRust.Templates/Projects/Library/LibraryProject.rsproj b/VisualRust.Templates/Projects/Library/LibraryProject.rsproj index e542e32c..c37a5b68 100644 --- a/VisualRust.Templates/Projects/Library/LibraryProject.rsproj +++ b/VisualRust.Templates/Projects/Library/LibraryProject.rsproj @@ -1,26 +1,10 @@ - + + - Debug - default - $guid1$ - library - $safeprojectname$ + 85cf0c42-b86d-4860-9523-a1f555838778 + Cargo.toml - - false - true - 0 - default - - - false - false - 2 - default - - - - - - + + + \ No newline at end of file diff --git a/VisualRust.Templates/Projects/Library/LibraryProject.vstemplate b/VisualRust.Templates/Projects/Library/LibraryProject.vstemplate index d137f0bc..806e4b6e 100644 --- a/VisualRust.Templates/Projects/Library/LibraryProject.vstemplate +++ b/VisualRust.Templates/Projects/Library/LibraryProject.vstemplate @@ -3,15 +3,19 @@ Rust Library A project for creating a Rust library - LibraryProject.ico - Rust - true - rust_library - true + LibraryProject.ico + Rust + true + rust_library + true + true + true - - lib.rs + + + Cargo.toml + lib.rs \ No newline at end of file diff --git a/VisualRust.Templates/Projects/Library/lib.rs b/VisualRust.Templates/Projects/Library/lib.rs index 7b31762a..cdfbe1aa 100644 --- a/VisualRust.Templates/Projects/Library/lib.rs +++ b/VisualRust.Templates/Projects/Library/lib.rs @@ -1,3 +1,6 @@ -#[test] -fn it_works() { -} \ No newline at end of file +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + } +} diff --git a/VisualRust.Templates/Properties/AssemblyInfo.cs b/VisualRust.Templates/Properties/AssemblyInfo.cs index a263a42e..4a771c4e 100644 --- a/VisualRust.Templates/Properties/AssemblyInfo.cs +++ b/VisualRust.Templates/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.1.2.0")] -[assembly: AssemblyFileVersion("0.1.2.0")] +[assembly: AssemblyVersion("0.2.0.0")] +[assembly: AssemblyFileVersion("0.2.0.0")] diff --git a/VisualRust.Templates/VisualRust.Templates.csproj b/VisualRust.Templates/VisualRust.Templates.csproj index 9e9f0165..08d98ec8 100644 --- a/VisualRust.Templates/VisualRust.Templates.csproj +++ b/VisualRust.Templates/VisualRust.Templates.csproj @@ -52,24 +52,16 @@ prompt 4 - - true - bin\Debug-CI\ - DEBUG;TRACE - full - AnyCPU - prompt - - - Designer - + + + Designer @@ -100,6 +92,9 @@ 127 + + + - $(VisualStudioVersion.Substring(0,2)) - UnitTest - - - true - full - false - bin\Debug\ - TRACE;DEBUG;VS$(ShortVisualStudioVersion) - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - true - - - ..\VisualRust\Key.snk - - - true - bin\Debug-CI\ - DEBUG;TRACE - full - AnyCPU - prompt - - - - False - ..\packages\VSSDK.DTE.7.0.4\lib\net20\envdte.dll - - - False - - - - - - ..\packages\VSSDK.GraphModel.11.0.4\lib\net45\Microsoft.VisualStudio.GraphModel.dll - False - - - ..\packages\VSSDK.OLE.Interop.7.0.4\lib\net20\Microsoft.VisualStudio.OLE.Interop.dll - False - - - - ..\packages\VSSDK.Shell.12.12.0.4\lib\net45\Microsoft.VisualStudio.Shell.12.0.dll - True - - - ..\packages\VSSDK.Shell.Immutable.10.10.0.4\lib\net40\Microsoft.VisualStudio.Shell.Immutable.10.0.dll - False - - - ..\packages\VSSDK.Shell.Immutable.11.11.0.4\lib\net45\Microsoft.VisualStudio.Shell.Immutable.11.0.dll - False - - - ..\packages\VSSDK.Shell.Immutable.12.12.0.4\lib\net45\Microsoft.VisualStudio.Shell.Immutable.12.0.dll - False - - - ..\packages\VSSDK.Shell.Interop.7.0.4\lib\net20\Microsoft.VisualStudio.Shell.Interop.dll - False - - - False - ..\packages\VSSDK.Shell.Interop.10.10.0.4\lib\net20\Microsoft.VisualStudio.Shell.Interop.10.0.dll - - - ..\packages\VSSDK.Shell.Interop.8.8.0.4\lib\net20\Microsoft.VisualStudio.Shell.Interop.8.0.dll - False - - - ..\packages\VSSDK.Shell.Interop.9.9.0.4\lib\net20\Microsoft.VisualStudio.Shell.Interop.9.0.dll - False - - - ..\packages\VSSDK.TextManager.Interop.7.0.4\lib\net20\Microsoft.VisualStudio.TextManager.Interop.dll - False - - - ..\packages\VSSDK.TextManager.Interop.8.8.0.4\lib\net20\Microsoft.VisualStudio.TextManager.Interop.8.0.dll - False - - - ..\packages\VSSDK.Threading.12.0.4\lib\net45\Microsoft.VisualStudio.Threading.dll - False - - - - - - - False - ..\packages\VSSDK.DTE.7.0.4\lib\net20\stdole.dll - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {cacb60a9-1e76-4f92-8831-b134a658c695} - Microsoft.VisualStudio.Project - - - {9cf556ab-76fe-4c3d-ad0a-b64b3b9989b4} - VisualRust.Build - - - {475c4df2-4d4b-4f2c-9f27-414148dd6f11} - VisualRust.Project - - - {b99cc9eb-90f2-4040-9e66-418cc7042153} - VisualRust.Shared - - - {8b7b30f7-17c1-4ce8-baf4-88b086af7b25} - VisualRust - - - - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - - - - \ No newline at end of file diff --git a/VisualRust.Test.Integration/app.config b/VisualRust.Test.Integration/app.config deleted file mode 100644 index 4a1c0bf1..00000000 --- a/VisualRust.Test.Integration/app.config +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/VisualRust.Test.Integration/packages.config b/VisualRust.Test.Integration/packages.config deleted file mode 100644 index 8f588f8f..00000000 --- a/VisualRust.Test.Integration/packages.config +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/VisualRust.Test/External/image/src/lib.rs b/VisualRust.Test/External/image/src/lib.rs deleted file mode 100644 index 7407f808..00000000 --- a/VisualRust.Test/External/image/src/lib.rs +++ /dev/null @@ -1,91 +0,0 @@ -//! This crate provides native rust implementations of -//! Image encoders and decoders and basic image manipulation -//! functions. - -#![crate_name = "image"] -#![crate_type = "rlib"] - -#![warn(missing_doc)] -#![warn(unnecessary_qualification)] -#![warn(unnecessary_typecast)] -#![feature(macro_rules)] - -extern crate flate; - -pub use color::ColorType as ColorType; - -pub use color:: { - Grey, - RGB, - Palette, - GreyA, - RGBA, - - Pixel, - - Luma, - LumaA, - Rgb, - Rgba, -}; - -pub use image::ImageDecoder as ImageDecoder; -pub use image::ImageError as ImageError; -pub use image::ImageResult as ImageResult; -pub use image::ImageFormat as ImageFormat; -pub use imageops::FilterType as FilterType; - -pub use imageops:: { - Triangle, - Nearest, - CatmullRom, - Gaussian, - Lanczos3 -}; - -pub use image:: { - PNG, - JPEG, - GIF, - WEBP, - PPM -}; - -//Image Types -pub use image::SubImage as SubImage; -pub use image::ImageBuf as ImageBuf; -pub use dynimage::DynamicImage as DynamicImage; - -//Traits -pub use image::GenericImage as GenericImage; -pub use image::MutableRefImage as MutableRefImage; - -//Iterators -pub use image::Pixels as Pixels; -pub use image::MutPixels as MutPixels; - -///opening and loading images -pub use dynimage:: { - open, - load, - load_from_memory, - - ImageRgb8, - ImageRgba8, - ImageLuma8, - ImageLumaA8, -}; - -//Image Processing Functions -pub mod imageops; - -//Image Codecs -pub mod webp; -pub mod ppm; -pub mod png; -pub mod jpeg; -pub mod gif; - -mod image; -mod dynimage; -mod color; \ No newline at end of file diff --git a/VisualRust.Test/External/servo/components/layout/lib.rs b/VisualRust.Test/External/servo/components/layout/lib.rs deleted file mode 100644 index e9294005..00000000 --- a/VisualRust.Test/External/servo/components/layout/lib.rs +++ /dev/null @@ -1,68 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#![comment = "The Servo Parallel Browser Project"] -#![license = "MPL"] - -#![feature(globs, macro_rules, phase, thread_local, unsafe_destructor)] - -#[phase(plugin, link)] -extern crate log; - -extern crate debug; - -extern crate geom; -extern crate gfx; -extern crate layout_traits; -extern crate script; -extern crate script_traits; -extern crate serialize; -extern crate style; -#[phase(plugin)] -extern crate servo_macros = "macros"; -extern crate servo_net = "net"; -extern crate servo_msg = "msg"; -#[phase(plugin, link)] -extern crate servo_util = "util"; - -extern crate collections; -extern crate green; -extern crate libc; -extern crate sync; -extern crate url; - -// Listed first because of macro definitions -pub mod layout_debug; - -pub mod block; -pub mod construct; -pub mod context; -pub mod floats; -pub mod flow; -pub mod flow_list; -pub mod flow_ref; -pub mod fragment; -pub mod layout_task; -pub mod inline; -pub mod model; -pub mod parallel; -pub mod table_wrapper; -pub mod table; -pub mod table_caption; -pub mod table_colgroup; -pub mod table_rowgroup; -pub mod table_row; -pub mod table_cell; -pub mod text; -pub mod util; -pub mod incremental; -pub mod wrapper; -pub mod extra; - -pub mod css { - mod node_util; - - pub mod matching; - pub mod node_style; -} diff --git a/VisualRust.Test/Internal/Circular/bar.rs b/VisualRust.Test/Internal/Circular/bar.rs deleted file mode 100644 index 40af3a9d..00000000 --- a/VisualRust.Test/Internal/Circular/bar.rs +++ /dev/null @@ -1,2 +0,0 @@ -mod foo; -mod baz; \ No newline at end of file diff --git a/VisualRust.Test/Internal/Circular/baz.rs b/VisualRust.Test/Internal/Circular/baz.rs deleted file mode 100644 index 4944b676..00000000 --- a/VisualRust.Test/Internal/Circular/baz.rs +++ /dev/null @@ -1,2 +0,0 @@ -mod bar; -mod foo; \ No newline at end of file diff --git a/VisualRust.Test/Internal/Circular/foo.rs b/VisualRust.Test/Internal/Circular/foo.rs deleted file mode 100644 index 899b3c07..00000000 --- a/VisualRust.Test/Internal/Circular/foo.rs +++ /dev/null @@ -1,2 +0,0 @@ -mod bar; -mod baz; \ No newline at end of file diff --git a/VisualRust.Test/Internal/Circular/main.rs b/VisualRust.Test/Internal/Circular/main.rs deleted file mode 100644 index 5f282702..00000000 --- a/VisualRust.Test/Internal/Circular/main.rs +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/VisualRust.Test/Internal/CircularAdd/bar.rs b/VisualRust.Test/Internal/CircularAdd/bar.rs deleted file mode 100644 index d2c747fc..00000000 --- a/VisualRust.Test/Internal/CircularAdd/bar.rs +++ /dev/null @@ -1 +0,0 @@ -mod main; \ No newline at end of file diff --git a/VisualRust.Test/Internal/CircularAdd/foo.rs b/VisualRust.Test/Internal/CircularAdd/foo.rs deleted file mode 100644 index 514ca1dc..00000000 --- a/VisualRust.Test/Internal/CircularAdd/foo.rs +++ /dev/null @@ -1 +0,0 @@ -mod bar; \ No newline at end of file diff --git a/VisualRust.Test/Internal/CircularAdd/main.rs b/VisualRust.Test/Internal/CircularAdd/main.rs deleted file mode 100644 index 5f282702..00000000 --- a/VisualRust.Test/Internal/CircularAdd/main.rs +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/VisualRust.Test/Internal/CircularAddClosed/bar.rs b/VisualRust.Test/Internal/CircularAddClosed/bar.rs deleted file mode 100644 index f6046e7a..00000000 --- a/VisualRust.Test/Internal/CircularAddClosed/bar.rs +++ /dev/null @@ -1 +0,0 @@ -mod foo; \ No newline at end of file diff --git a/VisualRust.Test/Internal/CircularAddClosed/foo.rs b/VisualRust.Test/Internal/CircularAddClosed/foo.rs deleted file mode 100644 index 514ca1dc..00000000 --- a/VisualRust.Test/Internal/CircularAddClosed/foo.rs +++ /dev/null @@ -1 +0,0 @@ -mod bar; \ No newline at end of file diff --git a/VisualRust.Test/Internal/CircularAddClosed/main.rs b/VisualRust.Test/Internal/CircularAddClosed/main.rs deleted file mode 100644 index f6046e7a..00000000 --- a/VisualRust.Test/Internal/CircularAddClosed/main.rs +++ /dev/null @@ -1 +0,0 @@ -mod foo; \ No newline at end of file diff --git a/VisualRust.Test/Internal/CircularConnected/bar.rs b/VisualRust.Test/Internal/CircularConnected/bar.rs deleted file mode 100644 index 40af3a9d..00000000 --- a/VisualRust.Test/Internal/CircularConnected/bar.rs +++ /dev/null @@ -1,2 +0,0 @@ -mod foo; -mod baz; \ No newline at end of file diff --git a/VisualRust.Test/Internal/CircularConnected/baz.rs b/VisualRust.Test/Internal/CircularConnected/baz.rs deleted file mode 100644 index 4944b676..00000000 --- a/VisualRust.Test/Internal/CircularConnected/baz.rs +++ /dev/null @@ -1,2 +0,0 @@ -mod bar; -mod foo; \ No newline at end of file diff --git a/VisualRust.Test/Internal/CircularConnected/foo.rs b/VisualRust.Test/Internal/CircularConnected/foo.rs deleted file mode 100644 index 899b3c07..00000000 --- a/VisualRust.Test/Internal/CircularConnected/foo.rs +++ /dev/null @@ -1,2 +0,0 @@ -mod bar; -mod baz; \ No newline at end of file diff --git a/VisualRust.Test/Internal/CircularConnected/main.rs b/VisualRust.Test/Internal/CircularConnected/main.rs deleted file mode 100644 index f6046e7a..00000000 --- a/VisualRust.Test/Internal/CircularConnected/main.rs +++ /dev/null @@ -1 +0,0 @@ -mod foo; \ No newline at end of file diff --git a/VisualRust.Test/Internal/CircularDowngrade/bar.rs b/VisualRust.Test/Internal/CircularDowngrade/bar.rs deleted file mode 100644 index d2c747fc..00000000 --- a/VisualRust.Test/Internal/CircularDowngrade/bar.rs +++ /dev/null @@ -1 +0,0 @@ -mod main; \ No newline at end of file diff --git a/VisualRust.Test/Internal/CircularDowngrade/foo.rs b/VisualRust.Test/Internal/CircularDowngrade/foo.rs deleted file mode 100644 index 514ca1dc..00000000 --- a/VisualRust.Test/Internal/CircularDowngrade/foo.rs +++ /dev/null @@ -1 +0,0 @@ -mod bar; \ No newline at end of file diff --git a/VisualRust.Test/Internal/CircularDowngrade/main.rs b/VisualRust.Test/Internal/CircularDowngrade/main.rs deleted file mode 100644 index f6046e7a..00000000 --- a/VisualRust.Test/Internal/CircularDowngrade/main.rs +++ /dev/null @@ -1 +0,0 @@ -mod foo; \ No newline at end of file diff --git a/VisualRust.Test/Internal/CircularMultiRoot/bar.rs b/VisualRust.Test/Internal/CircularMultiRoot/bar.rs deleted file mode 100644 index 8a937928..00000000 --- a/VisualRust.Test/Internal/CircularMultiRoot/bar.rs +++ /dev/null @@ -1,2 +0,0 @@ -#[path = "lib.rs"] -mod lib; \ No newline at end of file diff --git a/VisualRust.Test/Internal/CircularMultiRoot/foo.rs b/VisualRust.Test/Internal/CircularMultiRoot/foo.rs deleted file mode 100644 index 31f92f37..00000000 --- a/VisualRust.Test/Internal/CircularMultiRoot/foo.rs +++ /dev/null @@ -1 +0,0 @@ -mod bar; \ No newline at end of file diff --git a/VisualRust.Test/Internal/CircularMultiRoot/lib.rs b/VisualRust.Test/Internal/CircularMultiRoot/lib.rs deleted file mode 100644 index a93251b6..00000000 --- a/VisualRust.Test/Internal/CircularMultiRoot/lib.rs +++ /dev/null @@ -1,3 +0,0 @@ -#[test] -fn it_works() { -} diff --git a/VisualRust.Test/Internal/CircularNested/in/foo.rs b/VisualRust.Test/Internal/CircularNested/in/foo.rs deleted file mode 100644 index e01d5eaf..00000000 --- a/VisualRust.Test/Internal/CircularNested/in/foo.rs +++ /dev/null @@ -1,2 +0,0 @@ -#[path = "..\\main.rs"] -mod main \ No newline at end of file diff --git a/VisualRust.Test/Internal/CircularNested/main.rs b/VisualRust.Test/Internal/CircularNested/main.rs deleted file mode 100644 index dcf369b4..00000000 --- a/VisualRust.Test/Internal/CircularNested/main.rs +++ /dev/null @@ -1,2 +0,0 @@ -#[path = "in\\\u0066oo.rs"] -mod inside; \ No newline at end of file diff --git a/VisualRust.Test/Internal/ClosedCircle/bar.rs b/VisualRust.Test/Internal/ClosedCircle/bar.rs deleted file mode 100644 index 40af3a9d..00000000 --- a/VisualRust.Test/Internal/ClosedCircle/bar.rs +++ /dev/null @@ -1,2 +0,0 @@ -mod foo; -mod baz; \ No newline at end of file diff --git a/VisualRust.Test/Internal/ClosedCircle/baz.rs b/VisualRust.Test/Internal/ClosedCircle/baz.rs deleted file mode 100644 index 4944b676..00000000 --- a/VisualRust.Test/Internal/ClosedCircle/baz.rs +++ /dev/null @@ -1,2 +0,0 @@ -mod bar; -mod foo; \ No newline at end of file diff --git a/VisualRust.Test/Internal/ClosedCircle/foo.rs b/VisualRust.Test/Internal/ClosedCircle/foo.rs deleted file mode 100644 index ea307bb1..00000000 --- a/VisualRust.Test/Internal/ClosedCircle/foo.rs +++ /dev/null @@ -1 +0,0 @@ -mod baz; \ No newline at end of file diff --git a/VisualRust.Test/Internal/ClosedCircle/main.rs b/VisualRust.Test/Internal/ClosedCircle/main.rs deleted file mode 100644 index f6046e7a..00000000 --- a/VisualRust.Test/Internal/ClosedCircle/main.rs +++ /dev/null @@ -1 +0,0 @@ -mod foo; \ No newline at end of file diff --git a/VisualRust.Test/Internal/ResolveNonAuthImport/bar/mod.rs b/VisualRust.Test/Internal/ResolveNonAuthImport/bar/mod.rs deleted file mode 100644 index e69de29b..00000000 diff --git a/VisualRust.Test/Internal/ResolveNonAuthImport/baz.rs b/VisualRust.Test/Internal/ResolveNonAuthImport/baz.rs deleted file mode 100644 index 31f92f37..00000000 --- a/VisualRust.Test/Internal/ResolveNonAuthImport/baz.rs +++ /dev/null @@ -1 +0,0 @@ -mod bar; \ No newline at end of file diff --git a/VisualRust.Test/Internal/ResolveNonAuthImport/main.rs b/VisualRust.Test/Internal/ResolveNonAuthImport/main.rs deleted file mode 100644 index 31f92f37..00000000 --- a/VisualRust.Test/Internal/ResolveNonAuthImport/main.rs +++ /dev/null @@ -1 +0,0 @@ -mod bar; \ No newline at end of file diff --git a/VisualRust.Test/Internal/SimpleChain/baz.rs b/VisualRust.Test/Internal/SimpleChain/baz.rs deleted file mode 100644 index 3c8a0ab4..00000000 --- a/VisualRust.Test/Internal/SimpleChain/baz.rs +++ /dev/null @@ -1 +0,0 @@ -mod baz; \ No newline at end of file diff --git a/VisualRust.Test/Internal/SimpleChain/foo.rs b/VisualRust.Test/Internal/SimpleChain/foo.rs deleted file mode 100644 index 3c8a0ab4..00000000 --- a/VisualRust.Test/Internal/SimpleChain/foo.rs +++ /dev/null @@ -1 +0,0 @@ -mod baz; \ No newline at end of file diff --git a/VisualRust.Test/Internal/SimpleChain/main.rs b/VisualRust.Test/Internal/SimpleChain/main.rs deleted file mode 100644 index a63f80fc..00000000 --- a/VisualRust.Test/Internal/SimpleChain/main.rs +++ /dev/null @@ -1,5 +0,0 @@ -#[path = "foo.rs"] -mod bar; - - -fn foo() {} \ No newline at end of file diff --git a/VisualRust.Test/Internal/mod_paths.rs b/VisualRust.Test/Internal/mod_paths.rs deleted file mode 100644 index 5fcef588..00000000 --- a/VisualRust.Test/Internal/mod_paths.rs +++ /dev/null @@ -1,9 +0,0 @@ -#[] -fn foo() {} - -# [ path = "task_files" ] -mod task { - // Load the `local_data` module from `task_files/tls.rs` - # [ path = "tls.rs"] - mod local_data; -} \ No newline at end of file diff --git a/VisualRust.Test/Project/Controls/OutputTargetSectionViewModelTests.cs b/VisualRust.Test/Project/Controls/OutputTargetSectionViewModelTests.cs deleted file mode 100644 index 19834a09..00000000 --- a/VisualRust.Test/Project/Controls/OutputTargetSectionViewModelTests.cs +++ /dev/null @@ -1,374 +0,0 @@ -using NUnit.Framework; -using System; -using System.Collections.Generic; -using System.IO.Abstractions.TestingHelpers; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using VisualRust.Cargo; -using VisualRust.Project; -using VisualRust.Project.Controls; - -namespace VisualRust.Test.Project.Controls -{ - class OutputTargetSectionViewModelTests - { - [Test] - public void EmptyLib() - { - var m = CreateManifest( - @"[package] - name=""foo"" - version=""0.1"" - [lib]"); - var vm = new OutputTargetSectionViewModel(m, null); - OutputTargetViewModel lib = (OutputTargetViewModel)GetOutputTarget(vm.Targets, OutputTargetType.Library); - Assert.AreEqual("foo", lib.Name); - Assert.AreEqual(false, lib.IsPathOverriden); - Assert.AreEqual(@"src\foo.rs", lib.DefaultPath); - } - - [Test] - public void NameOnlyLib() - { - var m = CreateManifest( - @"[package] - name=""foo"" - version=""0.1"" - [lib] - name=""bar"""); - var vm = new OutputTargetSectionViewModel(m, null); - OutputTargetViewModel lib = (OutputTargetViewModel)GetOutputTarget(vm.Targets, OutputTargetType.Library); - Assert.AreEqual("bar", lib.Name); - Assert.AreEqual(false, lib.IsPathOverriden); - Assert.AreEqual(@"src\bar.rs", lib.DefaultPath); - } - - [Test] - public void PathOnlyLib() - { - var m = CreateManifest( - @"[package] - name=""foo"" - version=""0.1"" - [lib] - path=""src\\bar.rs"""); - var vm = new OutputTargetSectionViewModel(m, null); - OutputTargetViewModel lib = (OutputTargetViewModel)GetOutputTarget(vm.Targets, OutputTargetType.Library); - Assert.AreEqual("foo", lib.Name); - Assert.AreEqual(true, lib.IsPathOverriden); - Assert.AreEqual(@"src\bar.rs", lib.Path); - } - - static IOutputTargetViewModel GetOutputTarget(IEnumerable targets, OutputTargetType type) - { - return targets.First(t => t.Type == type); - } - - [Test] - public void DuplicateTarget() - { - var m = CreateManifest( - @"[package] - name=""foo"" - version=""0.1"" - [[bin]] - name=""foo"""); - var vm = new OutputTargetSectionViewModel(m, _ => OutputTargetType.Binary); - vm.Add(); - ((OutputTargetViewModel)vm.Targets[vm.Targets.Count - 1]).Name = "foo"; - ((OutputTargetViewModel)vm.Targets[vm.Targets.Count - 1]).Path = @"src\bar.rs"; - Assert.True(vm.IsDirty); - var changes = vm.PendingChanges(); - Assert.AreEqual(1, changes.TargetsAdded.Count); - Assert.AreEqual("foo", changes.TargetsAdded[0].Value.Name); - Assert.AreEqual(@"src\bar.rs", changes.TargetsAdded[0].Value.Path); - } - - [Test] - public void RemoveFirstDuplicate() - { - var m = CreateManifest( - @"[package] - name=""foo"" - version=""0.1"" - [[bin]] - name=""foo"" - path=""src\foo1.rs"" - [[bin]] - name=""src\foo2.rs"""); - var vm = new OutputTargetSectionViewModel(m, null); - var first = (OutputTargetViewModel)vm.Targets.First(t => t.Type == OutputTargetType.Binary); - var second = (OutputTargetViewModel)Second(vm.Targets, t => t.Type == OutputTargetType.Binary); - Assert.AreNotEqual(first.Handle, second.Handle); - vm.Remove(first); - Assert.True(vm.IsDirty); - var changes = vm.PendingChanges(); - Assert.AreEqual(1, changes.TargetsRemoved.Count); - Assert.AreEqual(first.Handle, changes.TargetsRemoved[0].Handle); - } - - [Test] - public void RemoveSecondDuplicate() - { - var m = CreateManifest( - @"[package] - name=""foo"" - version=""0.1"" - [[bin]] - name=""foo"" - path=""src\foo1.rs"" - [[bin]] - name=""src\foo2.rs"""); - var vm = new OutputTargetSectionViewModel(m, null); - var first = (OutputTargetViewModel)vm.Targets.First(t => t.Type == OutputTargetType.Binary); - var second = (OutputTargetViewModel)Second(vm.Targets, t => t.Type == OutputTargetType.Binary); - Assert.AreNotEqual(first.Handle, second.Handle); - vm.Remove(second); - Assert.True(vm.IsDirty); - var changes = vm.PendingChanges(); - Assert.AreEqual(1, changes.TargetsRemoved.Count); - Assert.AreEqual(second.Handle, changes.TargetsRemoved[0].Handle); - } - - static T Second(IEnumerable coll, Func picker) - { - return coll.Where(x => picker(x)).Skip(1).First(); - } - - [Test] - public void ExposeChanges() - { - var m = CreateManifest( - @"[package] - name=""foo"" - version=""0.1"" - [[bin]] - name=""foo"" - path=""src\foo1.rs"" - [[bin]] - name=""src\foo2.rs"""); - var vm = new OutputTargetSectionViewModel(m, null); - var first = (OutputTargetViewModel)vm.Targets.First(t => t.Type == OutputTargetType.Binary); - var second = (OutputTargetViewModel)Second(vm.Targets, t => t.Type == OutputTargetType.Binary); - Assert.AreNotEqual(first.Handle, second.Handle); - first.Harness = true; - Assert.True(vm.IsDirty); - var changes = vm.PendingChanges(); - Assert.AreEqual(1, changes.TargetsChanged.Count); - var changed = changes.TargetsChanged[0]; - Assert.AreEqual(first.Handle, changed.Value.Handle); - Assert.AreEqual(true, changed.Value.Harness); - Assert.Null(changed.Value.Name); - Assert.Null(changed.Value.Path); - Assert.Null(changed.Value.Test); - Assert.Null(changed.Value.Doctest); - Assert.Null(changed.Value.Bench); - Assert.Null(changed.Value.Doc); - Assert.Null(changed.Value.Plugin); - } - - [Test] - public void RemoveTarget() - { - var m = CreateManifest( - "[package]\n" - +"name=\"foo\"\n" - +"version=\"0.1\"\n" - +"[[bin]]\n" - +"name=\"foo\"\n" - +"path=\"src\\foo1.rs\"\n" - +"[[bin]]\n" - +"name=\"src\\foo2.rs\"\n"); - var vm = new OutputTargetSectionViewModel(m, null); - var first = (OutputTargetViewModel)vm.Targets.First(t => t.Type == OutputTargetType.Binary); - vm.Remove(first); - vm.Apply(); - Assert.AreEqual( - "[package]\n" - +"name=\"foo\"\n" - +"version=\"0.1\"\n" - +"[[bin]]\n" - +"name=\"src\\foo2.rs\"\n", - m.Manifest.ToString()); - Assert.False(vm.IsDirty); - Assert.True(m.Manifest.OutputTargets.All(t => t.Handle != first.Handle)); - } - - [Test] - public void AddTarget() - { - var m = CreateManifest( - "[package]\n" - +"name=\"foo\"\n" - +"version=\"0.1\"\n" - +"[[bin]]\n" - +"name=\"asdf\""); - var vm = new OutputTargetSectionViewModel(m, _ => OutputTargetType.Test); - vm.Add(); - ((OutputTargetViewModel)vm.Targets[vm.Targets.Count - 1]).Name = "bar"; - ((OutputTargetViewModel)vm.Targets[vm.Targets.Count - 1]).Path = "src\\baz.rs"; - ((OutputTargetViewModel)vm.Targets[vm.Targets.Count - 1]).Plugin = false; - vm.Apply(); - Assert.AreEqual( - "[package]\n" - +"name=\"foo\"\n" - +"version=\"0.1\"\n" - +"[[bin]]\n" - +"name=\"asdf\"\n" - +"[[test]]\n" - +"name = \"bar\"\n" - +"path = \"src\\\\baz.rs\"\n" - +"plugin = false\n", - m.Manifest.ToString()); - Assert.False(vm.IsDirty); - var test = vm.Targets.OfType().First(t => t.Type == OutputTargetType.Test); - Assert.AreNotEqual(UIntPtr.Zero, test.Handle); - Assert.NotNull(test.Handle); - Assert.True(m.Manifest.OutputTargets.Any(t => t.Handle == test.Handle)); - } - - [Test] - public void SetTarget() - { - var m = CreateManifest( - "[package]\n" - +"name=\"foo\"\n" - +"version=\"0.1\"\n" - +"[[bin]]\n" - +"name=\"asdf\"\n" - +"[[test]]\n" - +"name = \"bar\"\n" - +"path = \"src\\\\baz.rs\"\n" - +"plugin = false\n"); - var vm = new OutputTargetSectionViewModel(m, null); - var test = (OutputTargetViewModel)vm.Targets.First(t => t.Type == OutputTargetType.Test); - test.Plugin = true; - test.Doctest = true; - Assert.True(vm.IsDirty); - vm.Apply(); - Assert.AreEqual( - "[package]\n" - +"name=\"foo\"\n" - +"version=\"0.1\"\n" - +"[[bin]]\n" - +"name=\"asdf\"\n" - +"[[test]]\n" - +"name = \"bar\"\n" - +"path = \"src\\\\baz.rs\"\n" - +"doctest = true\n" - +"plugin = true\n", - m.Manifest.ToString()); - var rawTest = m.Manifest.OutputTargets.First(t => t.Type == OutputTargetType.Test); - Assert.AreEqual(true, rawTest.Plugin); - Assert.AreEqual(true, rawTest.Doctest); - } - - [Test] - public void SetInlineTarget() - { - var m = CreateManifest( - "bin = [ { name = \"asdf\" } ]\n" - +"[package]\n" - +"name=\"foo\"\n" - +"version=\"0.1\"\n"); - var vm = new OutputTargetSectionViewModel(m,null); - var binary = (OutputTargetViewModel)vm.Targets.First(t => t.Type == OutputTargetType.Binary); - binary.Name = "qwer"; - binary.Plugin = true; - binary.Doctest = true; - Assert.True(vm.IsDirty); - vm.Apply(); - Assert.AreEqual( - "bin = [ { name = \"qwer\", doctest = true, plugin = true } ]\n" - +"[package]\n" - +"name=\"foo\"\n" - +"version=\"0.1\"\n", - m.Manifest.ToString()); - } - - [Test] - public void SetInlineTargetLib() - { - var m = CreateManifest( - "lib = { name = \"asdf\" }\n" - +"[package]\n" - +"name=\"foo\"\n" - +"version=\"0.1\""); - var vm = new OutputTargetSectionViewModel(m, null); - var library = (OutputTargetViewModel)vm.Targets.First(t => t.Type == OutputTargetType.Library); - library.Name = "qwer"; - library.Plugin = true; - library.Doctest = true; - Assert.True(vm.IsDirty); - vm.Apply(); - Assert.AreEqual( - "lib = { name = \"qwer\", doctest = true, plugin = true }\n" - +"[package]\n" - +"name=\"foo\"\n" - +"version=\"0.1\"", - m.Manifest.ToString()); - } - - [Test] - public void SetTargetLibImplicit() - { - var m = CreateManifest( - "[lib.asdf]\n" - +"name = \"foo\"\n" - +"[package]\n" - +"name=\"foo\"\n" - +"version=\"0.1\""); - var vm = new OutputTargetSectionViewModel(m, null); - var library = (OutputTargetViewModel)vm.Targets.First(t => t.Type == OutputTargetType.Library); - Assert.AreEqual(UIntPtr.Zero, library.Handle); - library.Name = "qwer"; - library.Plugin = true; - library.Doctest = true; - Assert.True(vm.IsDirty); - vm.Apply(); - Assert.AreEqual( - "[lib.asdf]\n" - +"name = \"foo\"\n" - +"[package]\n" - +"name=\"foo\"\n" - +"version=\"0.1\"\n" - +"[lib]\n" - +"name = \"qwer\"\n" - +"doctest = true\n" - +"plugin = true\n", - m.Manifest.ToString()); - var libraryAfter = (OutputTargetViewModel)vm.Targets.First(t => t.Type == OutputTargetType.Library); - Assert.AreNotEqual(UIntPtr.Zero, libraryAfter.Handle); - Assert.NotNull(libraryAfter.Handle); - } - - [Test] - public void RemoveTargetLibImplicit() - { - var m = CreateManifest( - "[lib.asdf]\n" - +"name = \"foo\"\n" - +"[package]\n" - +"name=\"foo\"\n" - +"version=\"0.1\"\n"); - var vm = new OutputTargetSectionViewModel(m, null); - var library = (OutputTargetViewModel)vm.Targets.First(t => t.Type == OutputTargetType.Library); - vm.Remove(library); - Assert.True(vm.IsDirty); - vm.Apply(); - Assert.AreEqual( - "[package]\n" - +"name=\"foo\"\n" - +"version=\"0.1\"\n", - m.Manifest.ToString()); - Assert.AreEqual(0, m.Manifest.OutputTargets.Count); - } - - static ManifestFile CreateManifest(string text) - { - ManifestErrors temp; - return ManifestFile.Create(new MockFileSystem(), "Cargo.toml", _ => ManifestLoadResult.CreateSuccess("Cargo.toml", Manifest.TryCreate(text, out temp))); - } - } -} diff --git a/VisualRust.Test/Project/ModuleImportTests.cs b/VisualRust.Test/Project/ModuleImportTests.cs deleted file mode 100644 index d9b8db0e..00000000 --- a/VisualRust.Test/Project/ModuleImportTests.cs +++ /dev/null @@ -1,86 +0,0 @@ -using NUnit.Framework; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using VisualRust.Project; - -namespace VisualRust.Test.Project -{ - public class ModuleImportTests - { - [TestFixture] - public class GetTerminalImports - { - private class ModulePathComparer : IEqualityComparer - { - public bool Equals(PathSegment[] x, PathSegment[] y) - { - if(x.Length != y.Length) - return false; - for(int i =0; i < x.Length; i++) - { - if (x[i].Name != y[i].Name || x[i].IsAuthorative != y[i].IsAuthorative) - return false; - } - return true; - } - - public int GetHashCode(PathSegment[] obj) - { - return obj.Aggregate(0, (acc, str) => acc ^ str.GetHashCode()); - } - } - - private static ModulePathComparer pathComparer = new ModulePathComparer(); - - [Test] - public void Empty() - { - var empty = new ModuleImport(); - CollectionAssert.AreEquivalent(new string[0, 0], empty.GetTerminalImports()); - } - - [Test] - public void SingleLevel() - { - var empty = new ModuleImport() - { - { new PathSegment("foo"), new ModuleImport() }, - { new PathSegment("bar"), new ModuleImport() } - }; - var terminals = empty.GetTerminalImports().ToArray(); - Assert.AreEqual(2, terminals.Length); - Assert.True(terminals.Contains(new PathSegment[] { new PathSegment("foo") }, pathComparer)); - Assert.True(terminals.Contains(new PathSegment[] { new PathSegment("bar") }, pathComparer)); - } - - [Test] - public void Varied() - { - var empty = new ModuleImport() - { - { new PathSegment("foo"), new ModuleImport() - { - { new PathSegment("baz"), new ModuleImport() }, - { new PathSegment("m1"), new ModuleImport() - { - { new PathSegment("m21"), new ModuleImport() }, - { new PathSegment("m22"), new ModuleImport() } - } - } - } - }, - { new PathSegment("bar"), new ModuleImport() } - }; - var terminals = empty.GetTerminalImports().ToArray(); - Assert.AreEqual(4, terminals.Length); - Assert.True(terminals.Contains(new PathSegment[] { new PathSegment("foo"), new PathSegment("baz") }, pathComparer)); - Assert.True(terminals.Contains(new PathSegment[] { new PathSegment("foo"), new PathSegment("m1"), new PathSegment("m21") }, pathComparer)); - Assert.True(terminals.Contains(new PathSegment[] { new PathSegment("foo"), new PathSegment("m1"), new PathSegment("m22") }, pathComparer)); - Assert.True(terminals.Contains(new PathSegment[] { new PathSegment("bar") }, pathComparer)); - } - } - } -} diff --git a/VisualRust.Test/Project/ModuleParserTests.cs b/VisualRust.Test/Project/ModuleParserTests.cs deleted file mode 100644 index ada13714..00000000 --- a/VisualRust.Test/Project/ModuleParserTests.cs +++ /dev/null @@ -1,171 +0,0 @@ -using NUnit.Framework; -using System.Collections.Generic; -using VisualRust.Project; -using System.Linq; -using System; -using Antlr4.Runtime; - -namespace VisualRust.Test.Project -{ - public class ModuleParserTests - { - [TestFixture] - public class ParseImports - { - [Test] - public void AttributePaths() - { - ModuleImport importMods = ModuleParser.ParseImports(new AntlrInputStream(Utils.LoadResource(@"Internal\mod_paths.rs"))); - Assert.AreEqual(1, importMods.Count); - Assert.AreEqual(1, importMods[new PathSegment("task_files", true)].Count); - Assert.False(importMods.ContainsKey(new PathSegment("task_files", false))); - Assert.AreEqual(0, importMods[new PathSegment("task_files", true)][new PathSegment("tls.rs", true)].Count); - Assert.False(importMods[new PathSegment("task_files", true)].ContainsKey(new PathSegment("tls.rs", false))); - } - - [Test] - public void ParsePubModifier() - { - ModuleImport importMods = ModuleParser.ParseImports(new AntlrInputStream( - "pub mod foo { pub mod bar; } #[path=\"foo\"] pub mod ex { mod baz; }")); - Assert.AreEqual(1, importMods.Count); - } - - - [Test] - public void MergeAuthorative() - { - ModuleImport importMods = ModuleParser.ParseImports(new AntlrInputStream( - "mod foo { mod bar; } #[path=\"foo\"] mod foo { mod baz; }")); - Assert.AreEqual(1, importMods.Count); - } - - [Test] - public void MergeModBlocks() - { - ModuleImport importMods = ModuleParser.ParseImports(new AntlrInputStream( - @"fn foo { } mod asd { mod ext; } mod asd { mod bar { mod ext1; } } mod asd { mod bar { mod ext2; } }")); - Assert.AreEqual(1, importMods.Count); - Assert.AreEqual(2, importMods[new PathSegment("asd")].Count); - Assert.AreEqual(0, importMods[new PathSegment("asd")][new PathSegment("ext")].Count); - Assert.AreEqual(2, importMods[new PathSegment("asd")][new PathSegment("bar")].Count); - Assert.AreEqual(0, importMods[new PathSegment("asd")][new PathSegment("bar")][new PathSegment("ext1")].Count); - Assert.AreEqual(0, importMods[new PathSegment("asd")][new PathSegment("bar")][new PathSegment("ext2")].Count); - } - - [Test] - public void ParseModBlock() - { - ModuleImport importMods = ModuleParser.ParseImports(new AntlrInputStream( - @"fn foo { } mod asd { mod ext; }")); - Assert.AreEqual(1, importMods.Count); - Assert.AreEqual(1, importMods[new PathSegment("asd")].Count); - Assert.AreEqual(0, importMods[new PathSegment("asd")][new PathSegment("ext")].Count); - } - - [Test] - public void ParseCommentBlock() - { - ModuleImport importMods = ModuleParser.ParseImports(new AntlrInputStream( - @"/* mod ext; */")); - Assert.AreEqual(0, importMods.Count); - } - - [Test] - public void ParseInnerModBlock() - { - ModuleImport importMods = ModuleParser.ParseImports(new AntlrInputStream( - @"mod foo { mod inner; }")); - Assert.AreEqual(1, importMods.Count); - Assert.AreEqual(1, importMods[new PathSegment("foo")].Count); - Assert.AreEqual(0, importMods[new PathSegment("foo")][new PathSegment("inner")].Count); - } - - [Test] - public void ParseLargeInnerModBlock() - { - ModuleImport importMods = ModuleParser.ParseImports(new AntlrInputStream( - @"mod asd { mod bar { } mod baz { mod inner; } mod ext1; mod ext2; mod ext3; }")); - Assert.AreEqual(1, importMods.Count); - Assert.AreEqual(4, importMods[new PathSegment("asd")].Count); - Assert.AreEqual(1, importMods[new PathSegment("asd")][new PathSegment("baz")].Count); - } - - [Test] - public void EmptyModBlock() - { - ModuleImport importMods = ModuleParser.ParseImports(new AntlrInputStream( - @"mod asd { foo(); }")); - Assert.AreEqual(0, importMods.Count); - } - - [Test] - public void MergeModules() - { - ModuleImport importMods = ModuleParser.ParseImports(new AntlrInputStream( - @"mod asd { mod foo; } mod asd { mod bar; }")); - Assert.AreEqual(1, importMods.Count); - Assert.AreEqual(2, importMods[new PathSegment("asd")].Count); - } - - [Test] - public void ParseCommentNewLine() - { - ModuleImport importMods = ModuleParser.ParseImports(new AntlrInputStream( - @"// mod ext;")); - Assert.AreEqual(0, importMods.Count); - } - - [Test] - public void ParsesServoLayoutLib() - { - ModuleImport importMods = ModuleParser.ParseImports(new AntlrInputStream(Utils.LoadResource(@"External\servo\components\layout\lib.rs"))); - Assert.AreEqual(26, importMods.Count); - Assert.True(importMods[new PathSegment("layout_debug")].Count == 0); - Assert.True(importMods[new PathSegment("construct")].Count == 0); - Assert.True(importMods[new PathSegment("context")].Count == 0); - Assert.True(importMods[new PathSegment("floats")].Count == 0); - Assert.True(importMods[new PathSegment("flow")].Count == 0); - Assert.True(importMods[new PathSegment("flow_list")].Count == 0); - Assert.True(importMods[new PathSegment("flow_ref")].Count == 0); - Assert.True(importMods[new PathSegment("fragment")].Count == 0); - Assert.True(importMods[new PathSegment("layout_task")].Count == 0); - Assert.True(importMods[new PathSegment("inline")].Count == 0); - Assert.True(importMods[new PathSegment("model")].Count == 0); - Assert.True(importMods[new PathSegment("parallel")].Count == 0); - Assert.True(importMods[new PathSegment("table_wrapper")].Count == 0); - Assert.True(importMods[new PathSegment("table")].Count == 0); - Assert.True(importMods[new PathSegment("table_caption")].Count == 0); - Assert.True(importMods[new PathSegment("table_colgroup")].Count == 0); - Assert.True(importMods[new PathSegment("table_rowgroup")].Count == 0); - Assert.True(importMods[new PathSegment("table_row")].Count == 0); - Assert.True(importMods[new PathSegment("table_cell")].Count == 0); - Assert.True(importMods[new PathSegment("text")].Count == 0); - Assert.True(importMods[new PathSegment("util")].Count == 0); - Assert.True(importMods[new PathSegment("incremental")].Count == 0); - Assert.True(importMods[new PathSegment("wrapper")].Count == 0); - Assert.True(importMods[new PathSegment("extra")].Count == 0); - Assert.True(importMods[new PathSegment("css")].Count == 3); - Assert.True(importMods[new PathSegment("css")][new PathSegment("node_util")].Count == 0); - Assert.True(importMods[new PathSegment("css")][new PathSegment("matching")].Count == 0); - Assert.True(importMods[new PathSegment("css")][new PathSegment("node_style")].Count == 0); - } - - [Test] - public void ParsesPistonImageLib() - { - ModuleImport importMods = ModuleParser.ParseImports(new AntlrInputStream(Utils.LoadResource(@"External\image\src\lib.rs"))); - Assert.AreEqual(9, importMods.Count); - Assert.True(importMods[new PathSegment("imageops")].Count == 0); - Assert.True(importMods[new PathSegment("webp")].Count == 0); - Assert.True(importMods[new PathSegment("ppm")].Count == 0); - Assert.True(importMods[new PathSegment("png")].Count == 0); - Assert.True(importMods[new PathSegment("jpeg")].Count == 0); - Assert.True(importMods[new PathSegment("gif")].Count == 0); - Assert.True(importMods[new PathSegment("image")].Count == 0); - Assert.True(importMods[new PathSegment("dynimage")].Count == 0); - Assert.True(importMods[new PathSegment("color")].Count == 0); - } - } - } -} diff --git a/VisualRust.Test/Project/ModuleTrackerTests.cs b/VisualRust.Test/Project/ModuleTrackerTests.cs deleted file mode 100644 index d0672b22..00000000 --- a/VisualRust.Test/Project/ModuleTrackerTests.cs +++ /dev/null @@ -1,442 +0,0 @@ -using NUnit.Framework; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using VisualRust.Project; - -namespace VisualRust.Test.Project -{ - public class ModuleTrackerTests - { - private static void ModelCheck(ModuleTracker t, string root, params string[] additionalRoots) - { -#if TEST // Dirty hack - ModuleTracker model = new ModuleTracker(root); - foreach (string r in additionalRoots) - model.AddRootModule(r); - model.ExtractReachableAndMakeIncremental(); - Assert.True(t.IsEquivalnet(model)); -#endif - } - - - [TestFixture] - public class DeleteModule - { - // [main] --> foo --> baz - [Test] - public void ChainedRemoval() - { - using(TemporaryDirectory temp = Utils.LoadResourceDirectory(@"Internal\SimpleChain")) - { - var tracker = new ModuleTracker(Path.Combine(temp.DirPath, "main.rs")); - var reached = tracker.ExtractReachableAndMakeIncremental(); - Assert.AreEqual(2, reached.Count); - CollectionAssert.Contains(reached, Path.Combine(temp.DirPath, "foo.rs")); - CollectionAssert.Contains(reached, Path.Combine(temp.DirPath, "baz.rs")); - var res = tracker.DeleteModule(Path.Combine(temp.DirPath, "foo.rs")); - File.Delete(Path.Combine(temp.DirPath, "foo.rs")); - ModelCheck(tracker, Path.Combine(temp.DirPath, "main.rs")); - Assert.AreEqual(1, res.Orphans.Count); - CollectionAssert.Contains(res.Orphans, Path.Combine(temp.DirPath, "baz.rs")); - } - } - - /* - * [main] --> foo - * ^---------┘ - */ - [Test] - public void EscapedPaths() - { - using (TemporaryDirectory temp = Utils.LoadResourceDirectory(@"Internal\CircularNested")) - { - var tracker = new ModuleTracker(Path.Combine(temp.DirPath, "main.rs")); - var reached = tracker.ExtractReachableAndMakeIncremental(); - Assert.AreEqual(1, reached.Count); - CollectionAssert.Contains(reached, Path.Combine(temp.DirPath, "in\\foo.rs")); - } - } - - /* - * [main] [foo] --> bar - * ^-------------------┘ - */ - [Test] - public void CircularAddRemove() - { - using (TemporaryDirectory temp = Utils.LoadResourceDirectory(@"Internal\CircularAdd")) - { - var tracker = new ModuleTracker(Path.Combine(temp.DirPath, "main.rs")); - var reached = tracker.ExtractReachableAndMakeIncremental(); - Assert.AreEqual(0, reached.Count); - HashSet added = tracker.AddRootModuleIncremental(Path.Combine(temp.DirPath, "foo.rs")); - CollectionAssert.Contains(added, Path.Combine(temp.DirPath, "bar.rs")); - ModelCheck(tracker, Path.Combine(temp.DirPath, "main.rs"), Path.Combine(temp.DirPath, "foo.rs")); - var rem = tracker.DeleteModule(Path.Combine(temp.DirPath, "foo.rs")); - File.Delete(Path.Combine(temp.DirPath, "foo.rs")); - Assert.AreEqual(2, rem.Orphans.Count); - CollectionAssert.Contains(rem.Orphans, Path.Combine(temp.DirPath, "bar.rs")); - CollectionAssert.Contains(rem.Orphans, Path.Combine(temp.DirPath, "foo.rs")); - Assert.False(rem.IsReferenced); - ModelCheck(tracker, Path.Combine(temp.DirPath, "main.rs")); - } - } - - /* - * [main] [foo] --> bar - * ^-------------------┘ - */ - [Test] - public void CircularAddUnroot() - { - using (TemporaryDirectory temp = Utils.LoadResourceDirectory(@"Internal\CircularAdd")) - { - var tracker = new ModuleTracker(Path.Combine(temp.DirPath, "main.rs")); - var reached = tracker.ExtractReachableAndMakeIncremental(); - Assert.AreEqual(0, reached.Count); - HashSet added = tracker.AddRootModuleIncremental(Path.Combine(temp.DirPath, "foo.rs")); - CollectionAssert.Contains(added, Path.Combine(temp.DirPath, "bar.rs")); - ModelCheck(tracker, Path.Combine(temp.DirPath, "main.rs"), Path.Combine(temp.DirPath, "foo.rs")); - var rem = tracker.DowngradeModule(Path.Combine(temp.DirPath, "foo.rs")); - CollectionAssert.Contains(rem.Orphans, Path.Combine(temp.DirPath, "foo.rs")); - CollectionAssert.Contains(rem.Orphans, Path.Combine(temp.DirPath, "bar.rs")); - ModelCheck(tracker, Path.Combine(temp.DirPath, "main.rs")); - } - } - - /* - * [main] --> foo --> bar - * ^-----------------┘ - */ - [Test] - public void ExplicitlyAddRemoveExisting() - { - using (TemporaryDirectory temp = Utils.LoadResourceDirectory(@"Internal\CircularDowngrade")) - { - var tracker = new ModuleTracker(Path.Combine(temp.DirPath, "main.rs")); - var reached = tracker.ExtractReachableAndMakeIncremental(); - Assert.AreEqual(2, reached.Count); - HashSet added = tracker.AddRootModuleIncremental(Path.Combine(temp.DirPath, "foo.rs")); - Assert.AreEqual(0, added.Count); - ModelCheck(tracker, Path.Combine(temp.DirPath, "main.rs"), Path.Combine(temp.DirPath, "foo.rs")); - var del = tracker.DeleteModule(Path.Combine(temp.DirPath, "foo.rs")); - Assert.AreEqual(1, del.Orphans.Count); - Assert.True(del.IsReferenced); - File.Delete(Path.Combine(temp.DirPath, "foo.rs")); - ModelCheck(tracker, Path.Combine(temp.DirPath, "main.rs")); - } - } - - /* - * [main] --> foo --> bar - * ^-----------------┘ - */ - [Test] - public void ExplicitlyAddUnrootExisting() - { - using (TemporaryDirectory temp = Utils.LoadResourceDirectory(@"Internal\CircularDowngrade")) - { - var tracker = new ModuleTracker(Path.Combine(temp.DirPath, "main.rs")); - var reached = tracker.ExtractReachableAndMakeIncremental(); - Assert.AreEqual(2, reached.Count); - HashSet added = tracker.AddRootModuleIncremental(Path.Combine(temp.DirPath, "foo.rs")); - Assert.AreEqual(0, added.Count); - ModelCheck(tracker, Path.Combine(temp.DirPath, "main.rs"), Path.Combine(temp.DirPath, "foo.rs")); - var unr = tracker.DowngradeModule(Path.Combine(temp.DirPath, "foo.rs")); - Assert.AreEqual(0, unr.Orphans.Count); - ModelCheck(tracker, Path.Combine(temp.DirPath, "main.rs")); - var del = tracker.DeleteModule(Path.Combine(temp.DirPath, "foo.rs")); - Assert.AreEqual(1, del.Orphans.Count); - Assert.True(del.IsReferenced); - File.Delete(Path.Combine(temp.DirPath, "foo.rs")); - ModelCheck(tracker, Path.Combine(temp.DirPath, "main.rs")); - } - } - - /* - * [lib] --> [foo] --> bar - * ^------------------┘ - */ - [Test] - public void NonIncrRootRemoval() - { - using (TemporaryDirectory temp = Utils.LoadResourceDirectory(@"Internal\CircularMultiRoot")) - { - var tracker = new ModuleTracker(Path.Combine(temp.DirPath, "lib.rs")); - tracker.AddRootModule(Path.Combine(temp.DirPath, "foo.rs")); - var reached = tracker.ExtractReachableAndMakeIncremental(); - Assert.AreEqual(1, reached.Count); - HashSet orphans = tracker.DowngradeModule(Path.Combine(temp.DirPath, "foo.rs")).Orphans; - Assert.AreEqual(2, orphans.Count); - ModelCheck(tracker, Path.Combine(temp.DirPath, "lib.rs")); - } - } - - /* - * [main] [lib] <-> foo <-> bar - * ^----------------^ - */ - [Test] - public void CircularHard() - { - using (TemporaryDirectory temp = Utils.LoadResourceDirectory(@"Internal\Circular")) - { - var tracker = new ModuleTracker(Path.Combine(temp.DirPath, "main.rs")); - var reached = tracker.ExtractReachableAndMakeIncremental(); - Assert.AreEqual(0, reached.Count); - var added = tracker.AddRootModuleIncremental(Path.Combine(temp.DirPath, "foo.rs")); - Assert.AreEqual(2, added.Count); - ModelCheck(tracker, Path.Combine(temp.DirPath, "main.rs"), Path.Combine(temp.DirPath, "foo.rs")); - var del = tracker.DeleteModule(Path.Combine(temp.DirPath, "foo.rs")); - Assert.AreEqual(3, del.Orphans.Count); - Assert.False(del.IsReferenced); - File.Delete(Path.Combine(temp.DirPath, "foo.rs")); - ModelCheck(tracker, Path.Combine(temp.DirPath, "main.rs")); - } - } - } - [TestFixture] - public class AddRootModuleIncremental - { - /* - * [main.rs] ---> bar/mod.rs <--- [baz] - */ - [Test] - public void ResolveToAlreadyExisting() - { - using (TemporaryDirectory temp = Utils.LoadResourceDirectory(@"Internal\ResolveNonAuthImport")) - { - // main file points to bar/mod.rs. project gets loaded - var tracker = new ModuleTracker(Path.Combine(temp.DirPath, "main.rs")); - var reached = tracker.ExtractReachableAndMakeIncremental(); - Assert.AreEqual(1, reached.Count); - CollectionAssert.Contains(reached, Path.Combine(temp.DirPath, @"bar\mod.rs")); - // in the mean time bar.rs gets created - File.Create(Path.Combine(temp.DirPath, "bar.rs")).Close(); - // newly added baz.rs should import existing bar\mod.rs - // instead of touching the disk - var rootAdd = tracker.AddRootModuleIncremental(Path.Combine(temp.DirPath, "baz.rs")); - Assert.AreEqual(0, rootAdd.Count); - // WARNING: Dont ModelCheck(...) incrementally created ModTracker with the fresh ones. - // In this one case mod name resolution will be slightly different. - // It is working as indended. - } - } - } - - [TestFixture] - public class DowngradeModule - { - /* - * [main] ---> [lib] <-> foo <-> bar - * ^----------------^ - */ - [Test] - public void UpgradeAndDowngrade() - { - using (TemporaryDirectory temp = Utils.LoadResourceDirectory(@"Internal\CircularConnected")) - { - var tracker = new ModuleTracker(Path.Combine(temp.DirPath, "main.rs")); - tracker.AddRootModule(Path.Combine(temp.DirPath, "foo.rs")); - var reached = tracker.ExtractReachableAndMakeIncremental(); - Assert.AreEqual(2, reached.Count); - CollectionAssert.Contains(reached, Path.Combine(temp.DirPath, "baz.rs")); - CollectionAssert.Contains(reached, Path.Combine(temp.DirPath, "bar.rs")); - var res = tracker.DowngradeModule(Path.Combine(temp.DirPath, "foo.rs")); - ModelCheck(tracker, Path.Combine(temp.DirPath, "main.rs")); - tracker.UpgradeModule(Path.Combine(temp.DirPath, "baz.rs")); - ModelCheck(tracker, Path.Combine(temp.DirPath, "main.rs"), Path.Combine(temp.DirPath, "baz.rs")); - res = tracker.DowngradeModule(Path.Combine(temp.DirPath, "baz.rs")); - ModelCheck(tracker, Path.Combine(temp.DirPath, "main.rs")); - Assert.AreEqual(0, res.Orphans.Count); - Assert.True(res.IsReferenced); - } - } - } - - [TestFixture] - public class Reparse - { - [Test] - public void MultipleBackReferenced() - { - using (TemporaryDirectory temp = Utils.LoadResourceDirectory(@"Internal\ClosedCircle")) - { - var tracker = new ModuleTracker(Path.Combine(temp.DirPath, "main.rs")); - var reached = tracker.ExtractReachableAndMakeIncremental(); - Assert.AreEqual(3, reached.Count); - CollectionAssert.Contains(reached, Path.Combine(temp.DirPath, "baz.rs")); - CollectionAssert.Contains(reached, Path.Combine(temp.DirPath, "bar.rs")); - CollectionAssert.Contains(reached, Path.Combine(temp.DirPath, "foo.rs")); - File.Delete(Path.Combine(temp.DirPath, "foo.rs")); - File.Create(Path.Combine(temp.DirPath, "foo.rs")).Close(); - var diff = tracker.Reparse(Path.Combine(temp.DirPath, "foo.rs")); - // Return check - Assert.AreEqual(0, diff.Added.Count); - Assert.AreEqual(2, diff.Removed.Count); - // Model check - ModelCheck(tracker, Path.Combine(temp.DirPath, "main.rs")); - } - } - - - [Test] - public void ClearCircularRoot() - { - using (TemporaryDirectory temp = Utils.LoadResourceDirectory(@"Internal\Circular")) - { - var tracker = new ModuleTracker(Path.Combine(temp.DirPath, "main.rs")); - tracker.AddRootModule(Path.Combine(temp.DirPath, "foo.rs")); - var reached = tracker.ExtractReachableAndMakeIncremental(); - Assert.AreEqual(2, reached.Count); - CollectionAssert.Contains(reached, Path.Combine(temp.DirPath, "baz.rs")); - CollectionAssert.Contains(reached, Path.Combine(temp.DirPath, "bar.rs")); - File.Delete(Path.Combine(temp.DirPath, "foo.rs")); - File.Create(Path.Combine(temp.DirPath, "foo.rs")).Close(); - var diff = tracker.Reparse(Path.Combine(temp.DirPath, "foo.rs")); - // Return check - Assert.AreEqual(0, diff.Added.Count); - Assert.AreEqual(2, diff.Removed.Count); - // Model check - ModelCheck(tracker, Path.Combine(temp.DirPath, "main.rs"), Path.Combine(temp.DirPath, "foo.rs")); - } - } - - [Test] - public void AddCircularRoot() - { - using (TemporaryDirectory temp = Utils.LoadResourceDirectory(@"Internal\Circular")) - { - File.Delete(Path.Combine(temp.DirPath, "foo.rs")); - File.Create(Path.Combine(temp.DirPath, "foo.rs")).Close(); - var tracker = new ModuleTracker(Path.Combine(temp.DirPath, "main.rs")); - tracker.AddRootModule(Path.Combine(temp.DirPath, "foo.rs")); - var reached = tracker.ExtractReachableAndMakeIncremental(); - Assert.AreEqual(0, reached.Count); - File.Delete(Path.Combine(temp.DirPath, "foo.rs")); - using (var stream = File.Open(Path.Combine(temp.DirPath, "foo.rs"), FileMode.CreateNew)) - { - using (var textStream = new StreamWriter(stream)) - { - textStream.Write("mod bar;"); - } - } - var diff = tracker.Reparse(Path.Combine(temp.DirPath, "foo.rs")); - // Return check - Assert.AreEqual(2, diff.Added.Count); - Assert.AreEqual(0, diff.Removed.Count); - // Model check - ModelCheck(tracker, Path.Combine(temp.DirPath, "main.rs"), Path.Combine(temp.DirPath, "foo.rs")); - } - } - - [Test] - public void RemoveLimited() - { - using (TemporaryDirectory temp = Utils.LoadResourceDirectory(@"Internal\CircularConnected")) - { - var tracker = new ModuleTracker(Path.Combine(temp.DirPath, "main.rs")); - var reached = tracker.ExtractReachableAndMakeIncremental(); - Assert.AreEqual(3, reached.Count); - File.Delete(Path.Combine(temp.DirPath, "foo.rs")); - using (var stream = File.Open(Path.Combine(temp.DirPath, "foo.rs"), FileMode.CreateNew)) - { - using (var textStream = new StreamWriter(stream)) - { - textStream.Write("mod bar;"); - } - } - var diff = tracker.Reparse(Path.Combine(temp.DirPath, "foo.rs")); - // Return check - Assert.AreEqual(0, diff.Added.Count); - Assert.AreEqual(0, diff.Removed.Count); - // Model check - ModelCheck(tracker, Path.Combine(temp.DirPath, "main.rs")); - } - } - - [Test] - public void RemoveAndAdd() - { - using (TemporaryDirectory temp = Utils.LoadResourceDirectory(@"Internal\CircularConnected")) - { - var tracker = new ModuleTracker(Path.Combine(temp.DirPath, "main.rs")); - var reached = tracker.ExtractReachableAndMakeIncremental(); - Assert.AreEqual(3, reached.Count); - File.Delete(Path.Combine(temp.DirPath, "foo.rs")); - using (var stream = File.Open(Path.Combine(temp.DirPath, "foo.rs"), FileMode.CreateNew)) - { - using (var textStream = new StreamWriter(stream)) - { - textStream.Write("mod bar;"); - } - } - var diff = tracker.Reparse(Path.Combine(temp.DirPath, "foo.rs")); - // Return check - Assert.AreEqual(0, diff.Added.Count); - Assert.AreEqual(0, diff.Removed.Count); - // Model check - ModelCheck(tracker, Path.Combine(temp.DirPath, "main.rs")); - File.Delete(Path.Combine(temp.DirPath, "foo.rs")); - using (var stream = File.Open(Path.Combine(temp.DirPath, "foo.rs"), FileMode.CreateNew)) - { - using (var textStream = new StreamWriter(stream)) - { - textStream.Write("mod bar; mod baz;"); - } - } - diff = tracker.Reparse(Path.Combine(temp.DirPath, "foo.rs")); - // Return check - Assert.AreEqual(0, diff.Added.Count); - Assert.AreEqual(0, diff.Removed.Count); - // Model check - ModelCheck(tracker, Path.Combine(temp.DirPath, "main.rs")); - } - } - - [Test] - public void RemoveZombie() - { - using (TemporaryDirectory temp = Utils.LoadResourceDirectory(@"Internal\SimpleChain")) - { - var tracker = new ModuleTracker(Path.Combine(temp.DirPath, "main.rs")); - var reached = tracker.ExtractReachableAndMakeIncremental(); - Assert.AreEqual(2, reached.Count); - File.Delete(Path.Combine(temp.DirPath, "foo.rs")); - File.Delete(Path.Combine(temp.DirPath, "baz.rs")); - using (var stream = File.Open(Path.Combine(temp.DirPath, "foo.rs"), FileMode.CreateNew)) - { - using (var textStream = new StreamWriter(stream)) - { - textStream.Write("mod bar;"); - } - } - var diff = tracker.Reparse(Path.Combine(temp.DirPath, "foo.rs")); - // Return check - Assert.AreEqual(1, diff.Added.Count); - Assert.AreEqual(1, diff.Removed.Count); - // Model check - ModelCheck(tracker, Path.Combine(temp.DirPath, "main.rs")); - File.Delete(Path.Combine(temp.DirPath, "foo.rs")); - using (var stream = File.Open(Path.Combine(temp.DirPath, "foo.rs"), FileMode.CreateNew)) - { - using (var textStream = new StreamWriter(stream)) - { - textStream.Write("mod baz;"); - } - } - diff = tracker.Reparse(Path.Combine(temp.DirPath, "foo.rs")); - // Return check - Assert.AreEqual(1, diff.Added.Count); - Assert.AreEqual(1, diff.Removed.Count); - // Model check - ModelCheck(tracker, Path.Combine(temp.DirPath, "main.rs")); - } - } - } - } -} diff --git a/VisualRust.Test/Build/RustcMessageJsonParserTest.cs b/VisualRust.Test/Shared/RustcMessageJsonParserTest.cs similarity index 97% rename from VisualRust.Test/Build/RustcMessageJsonParserTest.cs rename to VisualRust.Test/Shared/RustcMessageJsonParserTest.cs index 9cb60c90..9d5b832d 100644 --- a/VisualRust.Test/Build/RustcMessageJsonParserTest.cs +++ b/VisualRust.Test/Shared/RustcMessageJsonParserTest.cs @@ -1,7 +1,6 @@ using System.Linq; using NUnit.Framework; -using VisualRust.Build.Message; -using VisualRust.Build.Message.Json; +using VisualRust.Shared.Message; namespace VisualRust.Test.Build { diff --git a/VisualRust.Test/TemporaryDirectory.cs b/VisualRust.Test/TemporaryDirectory.cs deleted file mode 100644 index 86cab811..00000000 --- a/VisualRust.Test/TemporaryDirectory.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System; -using System.IO; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace VisualRust.Test -{ - class TemporaryDirectory : IDisposable - { - private TemporaryDirectory parent; - public string DirPath { get; private set; } - - public TemporaryDirectory() - { - string tempPath = Path.GetTempPath(); - DirPath = Path.Combine(tempPath, Path.GetRandomFileName()); - Directory.CreateDirectory(DirPath); - } - - private TemporaryDirectory(string name, TemporaryDirectory par) - { - DirPath = name; - parent = par; - Directory.CreateDirectory(DirPath); - } - - public void Dispose() - { - if (parent != null) - parent.Dispose(); - else - Directory.Delete(DirPath, true); - } - - // Only single sub temporary dir is currently supported - public TemporaryDirectory SubDir(string name) - { - return new TemporaryDirectory(Path.Combine(this.DirPath, name), this); - } - } -} diff --git a/VisualRust.Test/Utils.cs b/VisualRust.Test/Utils.cs deleted file mode 100644 index 1920aae7..00000000 --- a/VisualRust.Test/Utils.cs +++ /dev/null @@ -1,56 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; - -namespace VisualRust.Test -{ - static class Utils - { - private static string[] resourceNames = Assembly.GetExecutingAssembly().GetManifestResourceNames(); - public static string LoadResource(string path) - { - using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceNames.First(s => s.EndsWith(path.Replace(Path.DirectorySeparatorChar, '.'))))) - { - using(StreamReader reader = new StreamReader(stream)) - { - return reader.ReadToEnd(); - } - } - } - - // We assume that every file has structure: name.ext - // this is obviously not true in general case, but good enough for tests - public static TemporaryDirectory LoadResourceDirectory(string path) - { - string pathStart = Path.Combine(@"VisualRust\Test", path).Replace('\\', '.'); - TemporaryDirectory dir = new TemporaryDirectory(); - int lastSlash = pathStart.LastIndexOf('.'); - TemporaryDirectory actualRoot = dir.SubDir(pathStart.Substring(lastSlash + 1, pathStart.Length - lastSlash - 1)); - foreach(string resName in resourceNames.Where(p => p.StartsWith(pathStart))) - { - string relPath = resName.Substring(pathStart.Length, resName.Length - pathStart.Length); - int extDot = relPath.LastIndexOf('.'); - int fileDot = relPath.LastIndexOf('.', extDot - 1); - string subDir = relPath.Substring(1, fileDot); - string currDir = actualRoot.DirPath; - if(subDir.Length > 0) - { - currDir = Path.Combine(actualRoot.DirPath, subDir); - Directory.CreateDirectory(currDir); - } - using(FileStream fileStream = File.Create(Path.Combine(currDir, relPath.Substring(fileDot + 1, relPath.Length - fileDot - 1)))) - { - using(var resStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resName)) - { - resStream.CopyTo(fileStream); - } - } - } - return actualRoot; - } - } -} diff --git a/VisualRust.Test/VisualRust.Test.csproj b/VisualRust.Test/VisualRust.Test.csproj index 03f1e44a..1d6738f6 100644 --- a/VisualRust.Test/VisualRust.Test.csproj +++ b/VisualRust.Test/VisualRust.Test.csproj @@ -9,8 +9,9 @@ Properties VisualRust.Test VisualRust.Test - v4.5 + v4.6 512 + true @@ -29,86 +30,19 @@ prompt 4 - - true - bin\Debug-CI\ - DEBUG;TRACE - full - AnyCPU - prompt - - - ..\packages\Antlr4.Runtime.4.3.0\lib\net45\Antlr4.Runtime.net45.dll - - - - ..\packages\NUnit.2.6.3\lib\nunit.framework.dll - - - - ..\packages\System.IO.Abstractions.2.0.0.124\lib\net40\System.IO.Abstractions.dll - True - - - ..\packages\System.IO.Abstractions.TestingHelpers.2.0.0.124\lib\net40\System.IO.Abstractions.TestingHelpers.dll - True - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Designer - - + @@ -119,9 +53,9 @@ {2594db0d-03ff-40ea-8d27-9930e5d3ff83} VisualRust.Cargo - - {475c4df2-4d4b-4f2c-9f27-414148dd6f11} - VisualRust.Project + + {b99cc9eb-90f2-4040-9e66-418cc7042153} + VisualRust.Shared diff --git a/VisualRust.Test/app.config b/VisualRust.Test/app.config index 4a1c0bf1..6512c70e 100644 --- a/VisualRust.Test/app.config +++ b/VisualRust.Test/app.config @@ -1,11 +1,11 @@ - + - - + + - \ No newline at end of file + diff --git a/VisualRust.Test/packages.config b/VisualRust.Test/packages.config deleted file mode 100644 index 56894e89..00000000 --- a/VisualRust.Test/packages.config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/VisualRust.Test/project.json b/VisualRust.Test/project.json new file mode 100644 index 00000000..2f64cc25 --- /dev/null +++ b/VisualRust.Test/project.json @@ -0,0 +1,12 @@ +{ + "dependencies": { + "NUnit": "3.5.0", + "NUnit3TestAdapter": "3.4.1" + }, + "frameworks": { + "net46": {} + }, + "runtimes": { + "win": {} + } +} \ No newline at end of file diff --git a/VisualRust.sln b/VisualRust.sln index 6a9e5a5c..7ffc4606 100644 --- a/VisualRust.sln +++ b/VisualRust.sln @@ -1,9 +1,12 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.25123.0 +VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VisualRust", "VisualRust\VisualRust.csproj", "{8B7B30F7-17C1-4CE8-BAF4-88B086AF7B25}" + ProjectSection(ProjectDependencies) = postProject + {9CF556AB-76FE-4C3D-AD0A-B64B3B9989B4} = {9CF556AB-76FE-4C3D-AD0A-B64B3B9989B4} + EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RustLexer", "RustLexer\RustLexer.csproj", "{E983E989-F83A-4643-896A-AD496BF647D0}" EndProject @@ -12,20 +15,14 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution README.md = README.md EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.VisualStudio.Project", "Microsoft.VisualStudio.Project\Microsoft.VisualStudio.Project.csproj", "{CACB60A9-1E76-4F92-8831-B134A658C695}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VisualRust.Build", "VisualRust.Build\VisualRust.Build.csproj", "{9CF556AB-76FE-4C3D-AD0A-B64B3B9989B4}" EndProject Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "VisualRust.Setup", "VisualRust.Setup\VisualRust.Setup.wixproj", "{272707AC-4E61-460E-B925-762E7FEB1CDD}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VisualRust.Templates", "VisualRust.Templates\VisualRust.Templates.csproj", "{59D94B96-1AF7-46F2-8790-AAB6DFAE8D9A}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VisualRust.Project", "VisualRust.Project\VisualRust.Project.csproj", "{475C4DF2-4D4B-4F2C-9F27-414148DD6F11}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VisualRust.Test", "VisualRust.Test\VisualRust.Test.csproj", "{C68F80B6-62AC-44EB-8557-88761524B495}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VisualRust.Test.Integration", "VisualRust.Test.Integration\VisualRust.Test.Integration.csproj", "{5276348D-B99D-408B-A16E-4B2C527E7EA0}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VisualRust.Shared", "VisualRust.Shared\VisualRust.Shared.csproj", "{B99CC9EB-90F2-4040-9E66-418CC7042153}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MIDebugEngine", "MIEngine\src\MIDebugEngine\MIDebugEngine.csproj", "{6D2688FE-6FD8-44A8-B96A-6037457F72A7}" @@ -34,170 +31,62 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MICore", "MIEngine\src\MICo EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VisualRust.Cargo", "VisualRust.Cargo\VisualRust.Cargo.csproj", "{2594DB0D-03FF-40EA-8D27-9930E5D3FF83}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Common.Core", "Microsoft.Common.Core\Microsoft.Common.Core.csproj", "{5DA4C00B-9F16-4EF9-894D-20329544265E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VisualRust.ProjectSystem.FileSystemMirroring", "VisualRust.ProjectSystem.FileSystemMirroring\VisualRust.ProjectSystem.FileSystemMirroring.csproj", "{B8696D0C-8ADB-4C11-8CEE-5C81AA8C6EBD}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug.Lab|Any CPU = Debug.Lab|Any CPU - Debug.Lab|Mixed Platforms = Debug.Lab|Mixed Platforms - Debug.Lab|x64 = Debug.Lab|x64 - Debug.Lab|x86 = Debug.Lab|x86 Debug|Any CPU = Debug|Any CPU Debug|Mixed Platforms = Debug|Mixed Platforms Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 - Debug-CI|Any CPU = Debug-CI|Any CPU - Debug-CI|Mixed Platforms = Debug-CI|Mixed Platforms - Debug-CI|x64 = Debug-CI|x64 - Debug-CI|x86 = Debug-CI|x86 - Release.Lab|Any CPU = Release.Lab|Any CPU - Release.Lab|Mixed Platforms = Release.Lab|Mixed Platforms - Release.Lab|x64 = Release.Lab|x64 - Release.Lab|x86 = Release.Lab|x86 Release|Any CPU = Release|Any CPU Release|Mixed Platforms = Release|Mixed Platforms Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {8B7B30F7-17C1-4CE8-BAF4-88B086AF7B25}.Debug.Lab|Any CPU.ActiveCfg = Debug-CI|Any CPU - {8B7B30F7-17C1-4CE8-BAF4-88B086AF7B25}.Debug.Lab|Any CPU.Build.0 = Debug-CI|Any CPU - {8B7B30F7-17C1-4CE8-BAF4-88B086AF7B25}.Debug.Lab|Mixed Platforms.ActiveCfg = Debug-CI|Any CPU - {8B7B30F7-17C1-4CE8-BAF4-88B086AF7B25}.Debug.Lab|Mixed Platforms.Build.0 = Debug-CI|Any CPU - {8B7B30F7-17C1-4CE8-BAF4-88B086AF7B25}.Debug.Lab|x64.ActiveCfg = Debug|Any CPU - {8B7B30F7-17C1-4CE8-BAF4-88B086AF7B25}.Debug.Lab|x86.ActiveCfg = Debug-CI|Any CPU {8B7B30F7-17C1-4CE8-BAF4-88B086AF7B25}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {8B7B30F7-17C1-4CE8-BAF4-88B086AF7B25}.Debug|Any CPU.Build.0 = Debug|Any CPU {8B7B30F7-17C1-4CE8-BAF4-88B086AF7B25}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU {8B7B30F7-17C1-4CE8-BAF4-88B086AF7B25}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {8B7B30F7-17C1-4CE8-BAF4-88B086AF7B25}.Debug|x64.ActiveCfg = Debug|Any CPU {8B7B30F7-17C1-4CE8-BAF4-88B086AF7B25}.Debug|x86.ActiveCfg = Debug|Any CPU - {8B7B30F7-17C1-4CE8-BAF4-88B086AF7B25}.Debug-CI|Any CPU.ActiveCfg = Debug-CI|Any CPU - {8B7B30F7-17C1-4CE8-BAF4-88B086AF7B25}.Debug-CI|Any CPU.Build.0 = Debug-CI|Any CPU - {8B7B30F7-17C1-4CE8-BAF4-88B086AF7B25}.Debug-CI|Mixed Platforms.ActiveCfg = Debug-CI|Any CPU - {8B7B30F7-17C1-4CE8-BAF4-88B086AF7B25}.Debug-CI|Mixed Platforms.Build.0 = Debug-CI|Any CPU - {8B7B30F7-17C1-4CE8-BAF4-88B086AF7B25}.Debug-CI|x64.ActiveCfg = Debug-CI|Any CPU - {8B7B30F7-17C1-4CE8-BAF4-88B086AF7B25}.Debug-CI|x86.ActiveCfg = Debug-CI|Any CPU - {8B7B30F7-17C1-4CE8-BAF4-88B086AF7B25}.Release.Lab|Any CPU.ActiveCfg = Release|Any CPU - {8B7B30F7-17C1-4CE8-BAF4-88B086AF7B25}.Release.Lab|Any CPU.Build.0 = Release|Any CPU - {8B7B30F7-17C1-4CE8-BAF4-88B086AF7B25}.Release.Lab|Mixed Platforms.ActiveCfg = Release|Any CPU - {8B7B30F7-17C1-4CE8-BAF4-88B086AF7B25}.Release.Lab|Mixed Platforms.Build.0 = Release|Any CPU - {8B7B30F7-17C1-4CE8-BAF4-88B086AF7B25}.Release.Lab|x64.ActiveCfg = Release|Any CPU - {8B7B30F7-17C1-4CE8-BAF4-88B086AF7B25}.Release.Lab|x86.ActiveCfg = Release|Any CPU {8B7B30F7-17C1-4CE8-BAF4-88B086AF7B25}.Release|Any CPU.ActiveCfg = Release|Any CPU {8B7B30F7-17C1-4CE8-BAF4-88B086AF7B25}.Release|Any CPU.Build.0 = Release|Any CPU {8B7B30F7-17C1-4CE8-BAF4-88B086AF7B25}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {8B7B30F7-17C1-4CE8-BAF4-88B086AF7B25}.Release|Mixed Platforms.Build.0 = Release|Any CPU {8B7B30F7-17C1-4CE8-BAF4-88B086AF7B25}.Release|x64.ActiveCfg = Release|Any CPU {8B7B30F7-17C1-4CE8-BAF4-88B086AF7B25}.Release|x86.ActiveCfg = Release|Any CPU - {E983E989-F83A-4643-896A-AD496BF647D0}.Debug.Lab|Any CPU.ActiveCfg = Debug-CI|Any CPU - {E983E989-F83A-4643-896A-AD496BF647D0}.Debug.Lab|Any CPU.Build.0 = Debug-CI|Any CPU - {E983E989-F83A-4643-896A-AD496BF647D0}.Debug.Lab|Mixed Platforms.ActiveCfg = Debug-CI|Any CPU - {E983E989-F83A-4643-896A-AD496BF647D0}.Debug.Lab|Mixed Platforms.Build.0 = Debug-CI|Any CPU - {E983E989-F83A-4643-896A-AD496BF647D0}.Debug.Lab|x64.ActiveCfg = Debug|Any CPU - {E983E989-F83A-4643-896A-AD496BF647D0}.Debug.Lab|x86.ActiveCfg = Debug-CI|Any CPU {E983E989-F83A-4643-896A-AD496BF647D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E983E989-F83A-4643-896A-AD496BF647D0}.Debug|Any CPU.Build.0 = Debug|Any CPU {E983E989-F83A-4643-896A-AD496BF647D0}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU {E983E989-F83A-4643-896A-AD496BF647D0}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {E983E989-F83A-4643-896A-AD496BF647D0}.Debug|x64.ActiveCfg = Debug|Any CPU {E983E989-F83A-4643-896A-AD496BF647D0}.Debug|x86.ActiveCfg = Debug|Any CPU - {E983E989-F83A-4643-896A-AD496BF647D0}.Debug-CI|Any CPU.ActiveCfg = Debug-CI|Any CPU - {E983E989-F83A-4643-896A-AD496BF647D0}.Debug-CI|Any CPU.Build.0 = Debug-CI|Any CPU - {E983E989-F83A-4643-896A-AD496BF647D0}.Debug-CI|Mixed Platforms.ActiveCfg = Debug-CI|Any CPU - {E983E989-F83A-4643-896A-AD496BF647D0}.Debug-CI|Mixed Platforms.Build.0 = Debug-CI|Any CPU - {E983E989-F83A-4643-896A-AD496BF647D0}.Debug-CI|x64.ActiveCfg = Debug-CI|Any CPU - {E983E989-F83A-4643-896A-AD496BF647D0}.Debug-CI|x86.ActiveCfg = Debug-CI|Any CPU - {E983E989-F83A-4643-896A-AD496BF647D0}.Release.Lab|Any CPU.ActiveCfg = Release|Any CPU - {E983E989-F83A-4643-896A-AD496BF647D0}.Release.Lab|Any CPU.Build.0 = Release|Any CPU - {E983E989-F83A-4643-896A-AD496BF647D0}.Release.Lab|Mixed Platforms.ActiveCfg = Release|Any CPU - {E983E989-F83A-4643-896A-AD496BF647D0}.Release.Lab|Mixed Platforms.Build.0 = Release|Any CPU - {E983E989-F83A-4643-896A-AD496BF647D0}.Release.Lab|x64.ActiveCfg = Release|Any CPU - {E983E989-F83A-4643-896A-AD496BF647D0}.Release.Lab|x86.ActiveCfg = Release|Any CPU {E983E989-F83A-4643-896A-AD496BF647D0}.Release|Any CPU.ActiveCfg = Release|Any CPU {E983E989-F83A-4643-896A-AD496BF647D0}.Release|Any CPU.Build.0 = Release|Any CPU {E983E989-F83A-4643-896A-AD496BF647D0}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {E983E989-F83A-4643-896A-AD496BF647D0}.Release|Mixed Platforms.Build.0 = Release|Any CPU {E983E989-F83A-4643-896A-AD496BF647D0}.Release|x64.ActiveCfg = Release|Any CPU {E983E989-F83A-4643-896A-AD496BF647D0}.Release|x86.ActiveCfg = Release|Any CPU - {CACB60A9-1E76-4F92-8831-B134A658C695}.Debug.Lab|Any CPU.ActiveCfg = Debug-CI|Any CPU - {CACB60A9-1E76-4F92-8831-B134A658C695}.Debug.Lab|Any CPU.Build.0 = Debug-CI|Any CPU - {CACB60A9-1E76-4F92-8831-B134A658C695}.Debug.Lab|Mixed Platforms.ActiveCfg = Debug-CI|Any CPU - {CACB60A9-1E76-4F92-8831-B134A658C695}.Debug.Lab|Mixed Platforms.Build.0 = Debug-CI|Any CPU - {CACB60A9-1E76-4F92-8831-B134A658C695}.Debug.Lab|x64.ActiveCfg = Debug|Any CPU - {CACB60A9-1E76-4F92-8831-B134A658C695}.Debug.Lab|x86.ActiveCfg = Debug-CI|Any CPU - {CACB60A9-1E76-4F92-8831-B134A658C695}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CACB60A9-1E76-4F92-8831-B134A658C695}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CACB60A9-1E76-4F92-8831-B134A658C695}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {CACB60A9-1E76-4F92-8831-B134A658C695}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {CACB60A9-1E76-4F92-8831-B134A658C695}.Debug|x64.ActiveCfg = Debug|Any CPU - {CACB60A9-1E76-4F92-8831-B134A658C695}.Debug|x86.ActiveCfg = Debug|Any CPU - {CACB60A9-1E76-4F92-8831-B134A658C695}.Debug-CI|Any CPU.ActiveCfg = Debug-CI|Any CPU - {CACB60A9-1E76-4F92-8831-B134A658C695}.Debug-CI|Any CPU.Build.0 = Debug-CI|Any CPU - {CACB60A9-1E76-4F92-8831-B134A658C695}.Debug-CI|Mixed Platforms.ActiveCfg = Debug-CI|Any CPU - {CACB60A9-1E76-4F92-8831-B134A658C695}.Debug-CI|Mixed Platforms.Build.0 = Debug-CI|Any CPU - {CACB60A9-1E76-4F92-8831-B134A658C695}.Debug-CI|x64.ActiveCfg = Debug-CI|Any CPU - {CACB60A9-1E76-4F92-8831-B134A658C695}.Debug-CI|x86.ActiveCfg = Debug-CI|Any CPU - {CACB60A9-1E76-4F92-8831-B134A658C695}.Release.Lab|Any CPU.ActiveCfg = Release|Any CPU - {CACB60A9-1E76-4F92-8831-B134A658C695}.Release.Lab|Any CPU.Build.0 = Release|Any CPU - {CACB60A9-1E76-4F92-8831-B134A658C695}.Release.Lab|Mixed Platforms.ActiveCfg = Release|Any CPU - {CACB60A9-1E76-4F92-8831-B134A658C695}.Release.Lab|Mixed Platforms.Build.0 = Release|Any CPU - {CACB60A9-1E76-4F92-8831-B134A658C695}.Release.Lab|x64.ActiveCfg = Release|Any CPU - {CACB60A9-1E76-4F92-8831-B134A658C695}.Release.Lab|x86.ActiveCfg = Release|Any CPU - {CACB60A9-1E76-4F92-8831-B134A658C695}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CACB60A9-1E76-4F92-8831-B134A658C695}.Release|Any CPU.Build.0 = Release|Any CPU - {CACB60A9-1E76-4F92-8831-B134A658C695}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {CACB60A9-1E76-4F92-8831-B134A658C695}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {CACB60A9-1E76-4F92-8831-B134A658C695}.Release|x64.ActiveCfg = Release|Any CPU - {CACB60A9-1E76-4F92-8831-B134A658C695}.Release|x86.ActiveCfg = Release|Any CPU - {9CF556AB-76FE-4C3D-AD0A-B64B3B9989B4}.Debug.Lab|Any CPU.ActiveCfg = Debug-CI|Any CPU - {9CF556AB-76FE-4C3D-AD0A-B64B3B9989B4}.Debug.Lab|Any CPU.Build.0 = Debug-CI|Any CPU - {9CF556AB-76FE-4C3D-AD0A-B64B3B9989B4}.Debug.Lab|Mixed Platforms.ActiveCfg = Debug-CI|Any CPU - {9CF556AB-76FE-4C3D-AD0A-B64B3B9989B4}.Debug.Lab|Mixed Platforms.Build.0 = Debug-CI|Any CPU - {9CF556AB-76FE-4C3D-AD0A-B64B3B9989B4}.Debug.Lab|x64.ActiveCfg = Debug|Any CPU - {9CF556AB-76FE-4C3D-AD0A-B64B3B9989B4}.Debug.Lab|x86.ActiveCfg = Debug-CI|Any CPU {9CF556AB-76FE-4C3D-AD0A-B64B3B9989B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {9CF556AB-76FE-4C3D-AD0A-B64B3B9989B4}.Debug|Any CPU.Build.0 = Debug|Any CPU {9CF556AB-76FE-4C3D-AD0A-B64B3B9989B4}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU {9CF556AB-76FE-4C3D-AD0A-B64B3B9989B4}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {9CF556AB-76FE-4C3D-AD0A-B64B3B9989B4}.Debug|x64.ActiveCfg = Debug|Any CPU {9CF556AB-76FE-4C3D-AD0A-B64B3B9989B4}.Debug|x86.ActiveCfg = Debug|Any CPU - {9CF556AB-76FE-4C3D-AD0A-B64B3B9989B4}.Debug-CI|Any CPU.ActiveCfg = Debug-CI|Any CPU - {9CF556AB-76FE-4C3D-AD0A-B64B3B9989B4}.Debug-CI|Any CPU.Build.0 = Debug-CI|Any CPU - {9CF556AB-76FE-4C3D-AD0A-B64B3B9989B4}.Debug-CI|Mixed Platforms.ActiveCfg = Debug-CI|Any CPU - {9CF556AB-76FE-4C3D-AD0A-B64B3B9989B4}.Debug-CI|Mixed Platforms.Build.0 = Debug-CI|Any CPU - {9CF556AB-76FE-4C3D-AD0A-B64B3B9989B4}.Debug-CI|x64.ActiveCfg = Debug-CI|Any CPU - {9CF556AB-76FE-4C3D-AD0A-B64B3B9989B4}.Debug-CI|x86.ActiveCfg = Debug-CI|Any CPU - {9CF556AB-76FE-4C3D-AD0A-B64B3B9989B4}.Release.Lab|Any CPU.ActiveCfg = Release|Any CPU - {9CF556AB-76FE-4C3D-AD0A-B64B3B9989B4}.Release.Lab|Any CPU.Build.0 = Release|Any CPU - {9CF556AB-76FE-4C3D-AD0A-B64B3B9989B4}.Release.Lab|Mixed Platforms.ActiveCfg = Release|Any CPU - {9CF556AB-76FE-4C3D-AD0A-B64B3B9989B4}.Release.Lab|Mixed Platforms.Build.0 = Release|Any CPU - {9CF556AB-76FE-4C3D-AD0A-B64B3B9989B4}.Release.Lab|x64.ActiveCfg = Release|Any CPU - {9CF556AB-76FE-4C3D-AD0A-B64B3B9989B4}.Release.Lab|x86.ActiveCfg = Release|Any CPU {9CF556AB-76FE-4C3D-AD0A-B64B3B9989B4}.Release|Any CPU.ActiveCfg = Release|Any CPU {9CF556AB-76FE-4C3D-AD0A-B64B3B9989B4}.Release|Any CPU.Build.0 = Release|Any CPU {9CF556AB-76FE-4C3D-AD0A-B64B3B9989B4}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {9CF556AB-76FE-4C3D-AD0A-B64B3B9989B4}.Release|Mixed Platforms.Build.0 = Release|Any CPU {9CF556AB-76FE-4C3D-AD0A-B64B3B9989B4}.Release|x64.ActiveCfg = Release|Any CPU {9CF556AB-76FE-4C3D-AD0A-B64B3B9989B4}.Release|x86.ActiveCfg = Release|Any CPU - {272707AC-4E61-460E-B925-762E7FEB1CDD}.Debug.Lab|Any CPU.ActiveCfg = Debug-CI|x86 - {272707AC-4E61-460E-B925-762E7FEB1CDD}.Debug.Lab|Mixed Platforms.ActiveCfg = Debug-CI|x86 - {272707AC-4E61-460E-B925-762E7FEB1CDD}.Debug.Lab|Mixed Platforms.Build.0 = Debug-CI|x86 - {272707AC-4E61-460E-B925-762E7FEB1CDD}.Debug.Lab|x64.ActiveCfg = Debug|x86 - {272707AC-4E61-460E-B925-762E7FEB1CDD}.Debug.Lab|x86.ActiveCfg = Debug-CI|x86 - {272707AC-4E61-460E-B925-762E7FEB1CDD}.Debug.Lab|x86.Build.0 = Debug-CI|x86 {272707AC-4E61-460E-B925-762E7FEB1CDD}.Debug|Any CPU.ActiveCfg = Debug|x86 {272707AC-4E61-460E-B925-762E7FEB1CDD}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 {272707AC-4E61-460E-B925-762E7FEB1CDD}.Debug|x64.ActiveCfg = Debug|x86 {272707AC-4E61-460E-B925-762E7FEB1CDD}.Debug|x86.ActiveCfg = Debug|x86 - {272707AC-4E61-460E-B925-762E7FEB1CDD}.Debug-CI|Any CPU.ActiveCfg = Debug|x86 - {272707AC-4E61-460E-B925-762E7FEB1CDD}.Debug-CI|Mixed Platforms.ActiveCfg = Debug|x86 - {272707AC-4E61-460E-B925-762E7FEB1CDD}.Debug-CI|x64.ActiveCfg = Debug-CI|x86 - {272707AC-4E61-460E-B925-762E7FEB1CDD}.Debug-CI|x86.ActiveCfg = Debug|x86 - {272707AC-4E61-460E-B925-762E7FEB1CDD}.Release.Lab|Any CPU.ActiveCfg = Release|x86 - {272707AC-4E61-460E-B925-762E7FEB1CDD}.Release.Lab|Mixed Platforms.ActiveCfg = Release|x86 - {272707AC-4E61-460E-B925-762E7FEB1CDD}.Release.Lab|Mixed Platforms.Build.0 = Release|x86 - {272707AC-4E61-460E-B925-762E7FEB1CDD}.Release.Lab|x64.ActiveCfg = Release|x86 - {272707AC-4E61-460E-B925-762E7FEB1CDD}.Release.Lab|x86.ActiveCfg = Release|x86 - {272707AC-4E61-460E-B925-762E7FEB1CDD}.Release.Lab|x86.Build.0 = Release|x86 {272707AC-4E61-460E-B925-762E7FEB1CDD}.Release|Any CPU.ActiveCfg = Release|x86 {272707AC-4E61-460E-B925-762E7FEB1CDD}.Release|Any CPU.Build.0 = Release|x86 {272707AC-4E61-460E-B925-762E7FEB1CDD}.Release|Mixed Platforms.ActiveCfg = Release|x86 @@ -205,240 +94,108 @@ Global {272707AC-4E61-460E-B925-762E7FEB1CDD}.Release|x64.ActiveCfg = Release|x86 {272707AC-4E61-460E-B925-762E7FEB1CDD}.Release|x86.ActiveCfg = Release|x86 {272707AC-4E61-460E-B925-762E7FEB1CDD}.Release|x86.Build.0 = Release|x86 - {59D94B96-1AF7-46F2-8790-AAB6DFAE8D9A}.Debug.Lab|Any CPU.ActiveCfg = Debug-CI|Any CPU - {59D94B96-1AF7-46F2-8790-AAB6DFAE8D9A}.Debug.Lab|Any CPU.Build.0 = Debug-CI|Any CPU - {59D94B96-1AF7-46F2-8790-AAB6DFAE8D9A}.Debug.Lab|Mixed Platforms.ActiveCfg = Debug-CI|Any CPU - {59D94B96-1AF7-46F2-8790-AAB6DFAE8D9A}.Debug.Lab|Mixed Platforms.Build.0 = Debug-CI|Any CPU - {59D94B96-1AF7-46F2-8790-AAB6DFAE8D9A}.Debug.Lab|x64.ActiveCfg = Debug|Any CPU - {59D94B96-1AF7-46F2-8790-AAB6DFAE8D9A}.Debug.Lab|x86.ActiveCfg = Debug-CI|Any CPU {59D94B96-1AF7-46F2-8790-AAB6DFAE8D9A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {59D94B96-1AF7-46F2-8790-AAB6DFAE8D9A}.Debug|Any CPU.Build.0 = Debug|Any CPU {59D94B96-1AF7-46F2-8790-AAB6DFAE8D9A}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU {59D94B96-1AF7-46F2-8790-AAB6DFAE8D9A}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {59D94B96-1AF7-46F2-8790-AAB6DFAE8D9A}.Debug|x64.ActiveCfg = Debug|Any CPU {59D94B96-1AF7-46F2-8790-AAB6DFAE8D9A}.Debug|x86.ActiveCfg = Debug|Any CPU - {59D94B96-1AF7-46F2-8790-AAB6DFAE8D9A}.Debug-CI|Any CPU.ActiveCfg = Debug-CI|Any CPU - {59D94B96-1AF7-46F2-8790-AAB6DFAE8D9A}.Debug-CI|Any CPU.Build.0 = Debug-CI|Any CPU - {59D94B96-1AF7-46F2-8790-AAB6DFAE8D9A}.Debug-CI|Mixed Platforms.ActiveCfg = Debug-CI|Any CPU - {59D94B96-1AF7-46F2-8790-AAB6DFAE8D9A}.Debug-CI|Mixed Platforms.Build.0 = Debug-CI|Any CPU - {59D94B96-1AF7-46F2-8790-AAB6DFAE8D9A}.Debug-CI|x64.ActiveCfg = Debug-CI|Any CPU - {59D94B96-1AF7-46F2-8790-AAB6DFAE8D9A}.Debug-CI|x86.ActiveCfg = Debug-CI|Any CPU - {59D94B96-1AF7-46F2-8790-AAB6DFAE8D9A}.Release.Lab|Any CPU.ActiveCfg = Release|Any CPU - {59D94B96-1AF7-46F2-8790-AAB6DFAE8D9A}.Release.Lab|Any CPU.Build.0 = Release|Any CPU - {59D94B96-1AF7-46F2-8790-AAB6DFAE8D9A}.Release.Lab|Mixed Platforms.ActiveCfg = Release|Any CPU - {59D94B96-1AF7-46F2-8790-AAB6DFAE8D9A}.Release.Lab|Mixed Platforms.Build.0 = Release|Any CPU - {59D94B96-1AF7-46F2-8790-AAB6DFAE8D9A}.Release.Lab|x64.ActiveCfg = Release|Any CPU - {59D94B96-1AF7-46F2-8790-AAB6DFAE8D9A}.Release.Lab|x86.ActiveCfg = Release|Any CPU {59D94B96-1AF7-46F2-8790-AAB6DFAE8D9A}.Release|Any CPU.ActiveCfg = Release|Any CPU {59D94B96-1AF7-46F2-8790-AAB6DFAE8D9A}.Release|Any CPU.Build.0 = Release|Any CPU {59D94B96-1AF7-46F2-8790-AAB6DFAE8D9A}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {59D94B96-1AF7-46F2-8790-AAB6DFAE8D9A}.Release|Mixed Platforms.Build.0 = Release|Any CPU {59D94B96-1AF7-46F2-8790-AAB6DFAE8D9A}.Release|x64.ActiveCfg = Release|Any CPU {59D94B96-1AF7-46F2-8790-AAB6DFAE8D9A}.Release|x86.ActiveCfg = Release|Any CPU - {475C4DF2-4D4B-4F2C-9F27-414148DD6F11}.Debug.Lab|Any CPU.ActiveCfg = Debug-CI|Any CPU - {475C4DF2-4D4B-4F2C-9F27-414148DD6F11}.Debug.Lab|Any CPU.Build.0 = Debug-CI|Any CPU - {475C4DF2-4D4B-4F2C-9F27-414148DD6F11}.Debug.Lab|Mixed Platforms.ActiveCfg = Debug-CI|Any CPU - {475C4DF2-4D4B-4F2C-9F27-414148DD6F11}.Debug.Lab|Mixed Platforms.Build.0 = Debug-CI|Any CPU - {475C4DF2-4D4B-4F2C-9F27-414148DD6F11}.Debug.Lab|x64.ActiveCfg = Debug|Any CPU - {475C4DF2-4D4B-4F2C-9F27-414148DD6F11}.Debug.Lab|x86.ActiveCfg = Debug-CI|Any CPU - {475C4DF2-4D4B-4F2C-9F27-414148DD6F11}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {475C4DF2-4D4B-4F2C-9F27-414148DD6F11}.Debug|Any CPU.Build.0 = Debug|Any CPU - {475C4DF2-4D4B-4F2C-9F27-414148DD6F11}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {475C4DF2-4D4B-4F2C-9F27-414148DD6F11}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {475C4DF2-4D4B-4F2C-9F27-414148DD6F11}.Debug|x64.ActiveCfg = Debug|Any CPU - {475C4DF2-4D4B-4F2C-9F27-414148DD6F11}.Debug|x86.ActiveCfg = Debug|Any CPU - {475C4DF2-4D4B-4F2C-9F27-414148DD6F11}.Debug-CI|Any CPU.ActiveCfg = Debug-CI|Any CPU - {475C4DF2-4D4B-4F2C-9F27-414148DD6F11}.Debug-CI|Any CPU.Build.0 = Debug-CI|Any CPU - {475C4DF2-4D4B-4F2C-9F27-414148DD6F11}.Debug-CI|Mixed Platforms.ActiveCfg = Debug-CI|Any CPU - {475C4DF2-4D4B-4F2C-9F27-414148DD6F11}.Debug-CI|Mixed Platforms.Build.0 = Debug-CI|Any CPU - {475C4DF2-4D4B-4F2C-9F27-414148DD6F11}.Debug-CI|x64.ActiveCfg = Debug-CI|Any CPU - {475C4DF2-4D4B-4F2C-9F27-414148DD6F11}.Debug-CI|x86.ActiveCfg = Debug-CI|Any CPU - {475C4DF2-4D4B-4F2C-9F27-414148DD6F11}.Release.Lab|Any CPU.ActiveCfg = Release|Any CPU - {475C4DF2-4D4B-4F2C-9F27-414148DD6F11}.Release.Lab|Any CPU.Build.0 = Release|Any CPU - {475C4DF2-4D4B-4F2C-9F27-414148DD6F11}.Release.Lab|Mixed Platforms.ActiveCfg = Release|Any CPU - {475C4DF2-4D4B-4F2C-9F27-414148DD6F11}.Release.Lab|Mixed Platforms.Build.0 = Release|Any CPU - {475C4DF2-4D4B-4F2C-9F27-414148DD6F11}.Release.Lab|x64.ActiveCfg = Release|Any CPU - {475C4DF2-4D4B-4F2C-9F27-414148DD6F11}.Release.Lab|x86.ActiveCfg = Release|Any CPU - {475C4DF2-4D4B-4F2C-9F27-414148DD6F11}.Release|Any CPU.ActiveCfg = Release|Any CPU - {475C4DF2-4D4B-4F2C-9F27-414148DD6F11}.Release|Any CPU.Build.0 = Release|Any CPU - {475C4DF2-4D4B-4F2C-9F27-414148DD6F11}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {475C4DF2-4D4B-4F2C-9F27-414148DD6F11}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {475C4DF2-4D4B-4F2C-9F27-414148DD6F11}.Release|x64.ActiveCfg = Release|Any CPU - {475C4DF2-4D4B-4F2C-9F27-414148DD6F11}.Release|x86.ActiveCfg = Release|Any CPU - {C68F80B6-62AC-44EB-8557-88761524B495}.Debug.Lab|Any CPU.ActiveCfg = Debug-CI|Any CPU - {C68F80B6-62AC-44EB-8557-88761524B495}.Debug.Lab|Any CPU.Build.0 = Debug-CI|Any CPU - {C68F80B6-62AC-44EB-8557-88761524B495}.Debug.Lab|Mixed Platforms.ActiveCfg = Debug-CI|Any CPU - {C68F80B6-62AC-44EB-8557-88761524B495}.Debug.Lab|Mixed Platforms.Build.0 = Debug-CI|Any CPU - {C68F80B6-62AC-44EB-8557-88761524B495}.Debug.Lab|x64.ActiveCfg = Debug|Any CPU - {C68F80B6-62AC-44EB-8557-88761524B495}.Debug.Lab|x86.ActiveCfg = Debug-CI|Any CPU {C68F80B6-62AC-44EB-8557-88761524B495}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C68F80B6-62AC-44EB-8557-88761524B495}.Debug|Any CPU.Build.0 = Debug|Any CPU {C68F80B6-62AC-44EB-8557-88761524B495}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU {C68F80B6-62AC-44EB-8557-88761524B495}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {C68F80B6-62AC-44EB-8557-88761524B495}.Debug|x64.ActiveCfg = Debug|Any CPU {C68F80B6-62AC-44EB-8557-88761524B495}.Debug|x86.ActiveCfg = Debug|Any CPU - {C68F80B6-62AC-44EB-8557-88761524B495}.Debug-CI|Any CPU.ActiveCfg = Debug-CI|Any CPU - {C68F80B6-62AC-44EB-8557-88761524B495}.Debug-CI|Any CPU.Build.0 = Debug-CI|Any CPU - {C68F80B6-62AC-44EB-8557-88761524B495}.Debug-CI|Mixed Platforms.ActiveCfg = Debug-CI|Any CPU - {C68F80B6-62AC-44EB-8557-88761524B495}.Debug-CI|Mixed Platforms.Build.0 = Debug-CI|Any CPU - {C68F80B6-62AC-44EB-8557-88761524B495}.Debug-CI|x64.ActiveCfg = Debug-CI|Any CPU - {C68F80B6-62AC-44EB-8557-88761524B495}.Debug-CI|x86.ActiveCfg = Debug-CI|Any CPU - {C68F80B6-62AC-44EB-8557-88761524B495}.Release.Lab|Any CPU.ActiveCfg = Release|Any CPU - {C68F80B6-62AC-44EB-8557-88761524B495}.Release.Lab|Any CPU.Build.0 = Release|Any CPU - {C68F80B6-62AC-44EB-8557-88761524B495}.Release.Lab|Mixed Platforms.ActiveCfg = Release|Any CPU - {C68F80B6-62AC-44EB-8557-88761524B495}.Release.Lab|Mixed Platforms.Build.0 = Release|Any CPU - {C68F80B6-62AC-44EB-8557-88761524B495}.Release.Lab|x64.ActiveCfg = Release|Any CPU - {C68F80B6-62AC-44EB-8557-88761524B495}.Release.Lab|x86.ActiveCfg = Release|Any CPU {C68F80B6-62AC-44EB-8557-88761524B495}.Release|Any CPU.ActiveCfg = Debug|Any CPU {C68F80B6-62AC-44EB-8557-88761524B495}.Release|Mixed Platforms.ActiveCfg = Debug|Any CPU {C68F80B6-62AC-44EB-8557-88761524B495}.Release|x64.ActiveCfg = Release|Any CPU {C68F80B6-62AC-44EB-8557-88761524B495}.Release|x86.ActiveCfg = Debug|Any CPU - {5276348D-B99D-408B-A16E-4B2C527E7EA0}.Debug.Lab|Any CPU.ActiveCfg = Debug-CI|Any CPU - {5276348D-B99D-408B-A16E-4B2C527E7EA0}.Debug.Lab|Any CPU.Build.0 = Debug-CI|Any CPU - {5276348D-B99D-408B-A16E-4B2C527E7EA0}.Debug.Lab|Mixed Platforms.ActiveCfg = Debug-CI|Any CPU - {5276348D-B99D-408B-A16E-4B2C527E7EA0}.Debug.Lab|Mixed Platforms.Build.0 = Debug-CI|Any CPU - {5276348D-B99D-408B-A16E-4B2C527E7EA0}.Debug.Lab|x64.ActiveCfg = Debug|Any CPU - {5276348D-B99D-408B-A16E-4B2C527E7EA0}.Debug.Lab|x86.ActiveCfg = Debug-CI|Any CPU - {5276348D-B99D-408B-A16E-4B2C527E7EA0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5276348D-B99D-408B-A16E-4B2C527E7EA0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5276348D-B99D-408B-A16E-4B2C527E7EA0}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {5276348D-B99D-408B-A16E-4B2C527E7EA0}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {5276348D-B99D-408B-A16E-4B2C527E7EA0}.Debug|x64.ActiveCfg = Debug|Any CPU - {5276348D-B99D-408B-A16E-4B2C527E7EA0}.Debug|x86.ActiveCfg = Debug|Any CPU - {5276348D-B99D-408B-A16E-4B2C527E7EA0}.Debug-CI|Any CPU.ActiveCfg = Debug-CI|Any CPU - {5276348D-B99D-408B-A16E-4B2C527E7EA0}.Debug-CI|Mixed Platforms.ActiveCfg = Debug-CI|Any CPU - {5276348D-B99D-408B-A16E-4B2C527E7EA0}.Debug-CI|x64.ActiveCfg = Debug-CI|Any CPU - {5276348D-B99D-408B-A16E-4B2C527E7EA0}.Debug-CI|x86.ActiveCfg = Debug-CI|Any CPU - {5276348D-B99D-408B-A16E-4B2C527E7EA0}.Release.Lab|Any CPU.ActiveCfg = Release|Any CPU - {5276348D-B99D-408B-A16E-4B2C527E7EA0}.Release.Lab|Any CPU.Build.0 = Release|Any CPU - {5276348D-B99D-408B-A16E-4B2C527E7EA0}.Release.Lab|Mixed Platforms.ActiveCfg = Release|Any CPU - {5276348D-B99D-408B-A16E-4B2C527E7EA0}.Release.Lab|Mixed Platforms.Build.0 = Release|Any CPU - {5276348D-B99D-408B-A16E-4B2C527E7EA0}.Release.Lab|x64.ActiveCfg = Release|Any CPU - {5276348D-B99D-408B-A16E-4B2C527E7EA0}.Release.Lab|x86.ActiveCfg = Release|Any CPU - {5276348D-B99D-408B-A16E-4B2C527E7EA0}.Release|Any CPU.ActiveCfg = Debug|Any CPU - {5276348D-B99D-408B-A16E-4B2C527E7EA0}.Release|Mixed Platforms.ActiveCfg = Debug|Any CPU - {5276348D-B99D-408B-A16E-4B2C527E7EA0}.Release|x64.ActiveCfg = Release|Any CPU - {5276348D-B99D-408B-A16E-4B2C527E7EA0}.Release|x86.ActiveCfg = Debug|Any CPU - {B99CC9EB-90F2-4040-9E66-418CC7042153}.Debug.Lab|Any CPU.ActiveCfg = Debug|Any CPU - {B99CC9EB-90F2-4040-9E66-418CC7042153}.Debug.Lab|Any CPU.Build.0 = Debug|Any CPU - {B99CC9EB-90F2-4040-9E66-418CC7042153}.Debug.Lab|Mixed Platforms.ActiveCfg = Debug|Any CPU - {B99CC9EB-90F2-4040-9E66-418CC7042153}.Debug.Lab|Mixed Platforms.Build.0 = Debug|Any CPU - {B99CC9EB-90F2-4040-9E66-418CC7042153}.Debug.Lab|x64.ActiveCfg = Debug|Any CPU - {B99CC9EB-90F2-4040-9E66-418CC7042153}.Debug.Lab|x86.ActiveCfg = Debug|Any CPU {B99CC9EB-90F2-4040-9E66-418CC7042153}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B99CC9EB-90F2-4040-9E66-418CC7042153}.Debug|Any CPU.Build.0 = Debug|Any CPU {B99CC9EB-90F2-4040-9E66-418CC7042153}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU {B99CC9EB-90F2-4040-9E66-418CC7042153}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {B99CC9EB-90F2-4040-9E66-418CC7042153}.Debug|x64.ActiveCfg = Debug|Any CPU {B99CC9EB-90F2-4040-9E66-418CC7042153}.Debug|x86.ActiveCfg = Debug|Any CPU - {B99CC9EB-90F2-4040-9E66-418CC7042153}.Debug-CI|Any CPU.ActiveCfg = Debug|Any CPU - {B99CC9EB-90F2-4040-9E66-418CC7042153}.Debug-CI|Any CPU.Build.0 = Debug|Any CPU - {B99CC9EB-90F2-4040-9E66-418CC7042153}.Debug-CI|Mixed Platforms.ActiveCfg = Debug|Any CPU - {B99CC9EB-90F2-4040-9E66-418CC7042153}.Debug-CI|Mixed Platforms.Build.0 = Debug|Any CPU - {B99CC9EB-90F2-4040-9E66-418CC7042153}.Debug-CI|x64.ActiveCfg = Debug|Any CPU - {B99CC9EB-90F2-4040-9E66-418CC7042153}.Debug-CI|x86.ActiveCfg = Debug|Any CPU - {B99CC9EB-90F2-4040-9E66-418CC7042153}.Release.Lab|Any CPU.ActiveCfg = Release|Any CPU - {B99CC9EB-90F2-4040-9E66-418CC7042153}.Release.Lab|Any CPU.Build.0 = Release|Any CPU - {B99CC9EB-90F2-4040-9E66-418CC7042153}.Release.Lab|Mixed Platforms.ActiveCfg = Release|Any CPU - {B99CC9EB-90F2-4040-9E66-418CC7042153}.Release.Lab|Mixed Platforms.Build.0 = Release|Any CPU - {B99CC9EB-90F2-4040-9E66-418CC7042153}.Release.Lab|x64.ActiveCfg = Release|Any CPU - {B99CC9EB-90F2-4040-9E66-418CC7042153}.Release.Lab|x86.ActiveCfg = Release|Any CPU {B99CC9EB-90F2-4040-9E66-418CC7042153}.Release|Any CPU.ActiveCfg = Release|Any CPU {B99CC9EB-90F2-4040-9E66-418CC7042153}.Release|Any CPU.Build.0 = Release|Any CPU {B99CC9EB-90F2-4040-9E66-418CC7042153}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {B99CC9EB-90F2-4040-9E66-418CC7042153}.Release|Mixed Platforms.Build.0 = Release|Any CPU {B99CC9EB-90F2-4040-9E66-418CC7042153}.Release|x64.ActiveCfg = Release|Any CPU {B99CC9EB-90F2-4040-9E66-418CC7042153}.Release|x86.ActiveCfg = Release|Any CPU - {6D2688FE-6FD8-44A8-B96A-6037457F72A7}.Debug.Lab|Any CPU.ActiveCfg = Debug.Lab|Any CPU - {6D2688FE-6FD8-44A8-B96A-6037457F72A7}.Debug.Lab|Any CPU.Build.0 = Debug.Lab|Any CPU - {6D2688FE-6FD8-44A8-B96A-6037457F72A7}.Debug.Lab|Mixed Platforms.ActiveCfg = Debug.Lab|Any CPU - {6D2688FE-6FD8-44A8-B96A-6037457F72A7}.Debug.Lab|Mixed Platforms.Build.0 = Debug.Lab|Any CPU - {6D2688FE-6FD8-44A8-B96A-6037457F72A7}.Debug.Lab|x64.ActiveCfg = Debug.Lab|Any CPU - {6D2688FE-6FD8-44A8-B96A-6037457F72A7}.Debug.Lab|x86.ActiveCfg = Debug.Lab|Any CPU {6D2688FE-6FD8-44A8-B96A-6037457F72A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6D2688FE-6FD8-44A8-B96A-6037457F72A7}.Debug|Any CPU.Build.0 = Debug|Any CPU {6D2688FE-6FD8-44A8-B96A-6037457F72A7}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU {6D2688FE-6FD8-44A8-B96A-6037457F72A7}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {6D2688FE-6FD8-44A8-B96A-6037457F72A7}.Debug|x64.ActiveCfg = Debug|Any CPU {6D2688FE-6FD8-44A8-B96A-6037457F72A7}.Debug|x86.ActiveCfg = Debug|Any CPU - {6D2688FE-6FD8-44A8-B96A-6037457F72A7}.Debug-CI|Any CPU.ActiveCfg = Debug|Any CPU - {6D2688FE-6FD8-44A8-B96A-6037457F72A7}.Debug-CI|Any CPU.Build.0 = Debug|Any CPU - {6D2688FE-6FD8-44A8-B96A-6037457F72A7}.Debug-CI|Mixed Platforms.ActiveCfg = Debug|Any CPU - {6D2688FE-6FD8-44A8-B96A-6037457F72A7}.Debug-CI|Mixed Platforms.Build.0 = Debug|Any CPU - {6D2688FE-6FD8-44A8-B96A-6037457F72A7}.Debug-CI|x64.ActiveCfg = Debug|Any CPU - {6D2688FE-6FD8-44A8-B96A-6037457F72A7}.Debug-CI|x86.ActiveCfg = Debug|Any CPU - {6D2688FE-6FD8-44A8-B96A-6037457F72A7}.Release.Lab|Any CPU.ActiveCfg = Release.Lab|Any CPU - {6D2688FE-6FD8-44A8-B96A-6037457F72A7}.Release.Lab|Any CPU.Build.0 = Release.Lab|Any CPU - {6D2688FE-6FD8-44A8-B96A-6037457F72A7}.Release.Lab|Mixed Platforms.ActiveCfg = Release.Lab|Any CPU - {6D2688FE-6FD8-44A8-B96A-6037457F72A7}.Release.Lab|Mixed Platforms.Build.0 = Release.Lab|Any CPU - {6D2688FE-6FD8-44A8-B96A-6037457F72A7}.Release.Lab|x64.ActiveCfg = Release.Lab|Any CPU - {6D2688FE-6FD8-44A8-B96A-6037457F72A7}.Release.Lab|x86.ActiveCfg = Release.Lab|Any CPU {6D2688FE-6FD8-44A8-B96A-6037457F72A7}.Release|Any CPU.ActiveCfg = Release|Any CPU {6D2688FE-6FD8-44A8-B96A-6037457F72A7}.Release|Any CPU.Build.0 = Release|Any CPU {6D2688FE-6FD8-44A8-B96A-6037457F72A7}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {6D2688FE-6FD8-44A8-B96A-6037457F72A7}.Release|Mixed Platforms.Build.0 = Release|Any CPU {6D2688FE-6FD8-44A8-B96A-6037457F72A7}.Release|x64.ActiveCfg = Release|Any CPU {6D2688FE-6FD8-44A8-B96A-6037457F72A7}.Release|x86.ActiveCfg = Release|Any CPU - {12CC862D-95B7-4224-8E16-B928C6333677}.Debug.Lab|Any CPU.ActiveCfg = Debug.Lab|Any CPU - {12CC862D-95B7-4224-8E16-B928C6333677}.Debug.Lab|Any CPU.Build.0 = Debug.Lab|Any CPU - {12CC862D-95B7-4224-8E16-B928C6333677}.Debug.Lab|Mixed Platforms.ActiveCfg = Debug.Lab|Any CPU - {12CC862D-95B7-4224-8E16-B928C6333677}.Debug.Lab|Mixed Platforms.Build.0 = Debug.Lab|Any CPU - {12CC862D-95B7-4224-8E16-B928C6333677}.Debug.Lab|x64.ActiveCfg = Debug.Lab|Any CPU - {12CC862D-95B7-4224-8E16-B928C6333677}.Debug.Lab|x86.ActiveCfg = Debug.Lab|Any CPU {12CC862D-95B7-4224-8E16-B928C6333677}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {12CC862D-95B7-4224-8E16-B928C6333677}.Debug|Any CPU.Build.0 = Debug|Any CPU {12CC862D-95B7-4224-8E16-B928C6333677}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU {12CC862D-95B7-4224-8E16-B928C6333677}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {12CC862D-95B7-4224-8E16-B928C6333677}.Debug|x64.ActiveCfg = Debug|Any CPU {12CC862D-95B7-4224-8E16-B928C6333677}.Debug|x86.ActiveCfg = Debug|Any CPU - {12CC862D-95B7-4224-8E16-B928C6333677}.Debug-CI|Any CPU.ActiveCfg = Debug|Any CPU - {12CC862D-95B7-4224-8E16-B928C6333677}.Debug-CI|Any CPU.Build.0 = Debug|Any CPU - {12CC862D-95B7-4224-8E16-B928C6333677}.Debug-CI|Mixed Platforms.ActiveCfg = Debug|Any CPU - {12CC862D-95B7-4224-8E16-B928C6333677}.Debug-CI|Mixed Platforms.Build.0 = Debug|Any CPU - {12CC862D-95B7-4224-8E16-B928C6333677}.Debug-CI|x64.ActiveCfg = Debug|Any CPU - {12CC862D-95B7-4224-8E16-B928C6333677}.Debug-CI|x86.ActiveCfg = Debug|Any CPU - {12CC862D-95B7-4224-8E16-B928C6333677}.Release.Lab|Any CPU.ActiveCfg = Release.Lab|Any CPU - {12CC862D-95B7-4224-8E16-B928C6333677}.Release.Lab|Any CPU.Build.0 = Release.Lab|Any CPU - {12CC862D-95B7-4224-8E16-B928C6333677}.Release.Lab|Mixed Platforms.ActiveCfg = Release.Lab|Any CPU - {12CC862D-95B7-4224-8E16-B928C6333677}.Release.Lab|Mixed Platforms.Build.0 = Release.Lab|Any CPU - {12CC862D-95B7-4224-8E16-B928C6333677}.Release.Lab|x64.ActiveCfg = Release.Lab|Any CPU - {12CC862D-95B7-4224-8E16-B928C6333677}.Release.Lab|x86.ActiveCfg = Release.Lab|Any CPU {12CC862D-95B7-4224-8E16-B928C6333677}.Release|Any CPU.ActiveCfg = Release|Any CPU {12CC862D-95B7-4224-8E16-B928C6333677}.Release|Any CPU.Build.0 = Release|Any CPU {12CC862D-95B7-4224-8E16-B928C6333677}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {12CC862D-95B7-4224-8E16-B928C6333677}.Release|Mixed Platforms.Build.0 = Release|Any CPU {12CC862D-95B7-4224-8E16-B928C6333677}.Release|x64.ActiveCfg = Release|Any CPU {12CC862D-95B7-4224-8E16-B928C6333677}.Release|x86.ActiveCfg = Release|Any CPU - {2594DB0D-03FF-40EA-8D27-9930E5D3FF83}.Debug.Lab|Any CPU.ActiveCfg = Debug|x86 - {2594DB0D-03FF-40EA-8D27-9930E5D3FF83}.Debug.Lab|Mixed Platforms.ActiveCfg = Debug|x86 - {2594DB0D-03FF-40EA-8D27-9930E5D3FF83}.Debug.Lab|Mixed Platforms.Build.0 = Debug|x86 - {2594DB0D-03FF-40EA-8D27-9930E5D3FF83}.Debug.Lab|x64.ActiveCfg = Debug|x86 - {2594DB0D-03FF-40EA-8D27-9930E5D3FF83}.Debug.Lab|x86.ActiveCfg = Debug|x86 - {2594DB0D-03FF-40EA-8D27-9930E5D3FF83}.Debug.Lab|x86.Build.0 = Debug|x86 {2594DB0D-03FF-40EA-8D27-9930E5D3FF83}.Debug|Any CPU.ActiveCfg = Debug|x86 {2594DB0D-03FF-40EA-8D27-9930E5D3FF83}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 {2594DB0D-03FF-40EA-8D27-9930E5D3FF83}.Debug|Mixed Platforms.Build.0 = Debug|x86 {2594DB0D-03FF-40EA-8D27-9930E5D3FF83}.Debug|x64.ActiveCfg = Debug|x86 {2594DB0D-03FF-40EA-8D27-9930E5D3FF83}.Debug|x86.ActiveCfg = Debug|x86 {2594DB0D-03FF-40EA-8D27-9930E5D3FF83}.Debug|x86.Build.0 = Debug|x86 - {2594DB0D-03FF-40EA-8D27-9930E5D3FF83}.Debug-CI|Any CPU.ActiveCfg = Debug|x86 - {2594DB0D-03FF-40EA-8D27-9930E5D3FF83}.Debug-CI|Mixed Platforms.ActiveCfg = Debug|x86 - {2594DB0D-03FF-40EA-8D27-9930E5D3FF83}.Debug-CI|Mixed Platforms.Build.0 = Debug|x86 - {2594DB0D-03FF-40EA-8D27-9930E5D3FF83}.Debug-CI|x64.ActiveCfg = Debug|x86 - {2594DB0D-03FF-40EA-8D27-9930E5D3FF83}.Debug-CI|x86.ActiveCfg = Debug|x86 - {2594DB0D-03FF-40EA-8D27-9930E5D3FF83}.Debug-CI|x86.Build.0 = Debug|x86 - {2594DB0D-03FF-40EA-8D27-9930E5D3FF83}.Release.Lab|Any CPU.ActiveCfg = Release|x86 - {2594DB0D-03FF-40EA-8D27-9930E5D3FF83}.Release.Lab|Mixed Platforms.ActiveCfg = Release|x86 - {2594DB0D-03FF-40EA-8D27-9930E5D3FF83}.Release.Lab|Mixed Platforms.Build.0 = Release|x86 - {2594DB0D-03FF-40EA-8D27-9930E5D3FF83}.Release.Lab|x64.ActiveCfg = Release|x86 - {2594DB0D-03FF-40EA-8D27-9930E5D3FF83}.Release.Lab|x86.ActiveCfg = Release|x86 - {2594DB0D-03FF-40EA-8D27-9930E5D3FF83}.Release.Lab|x86.Build.0 = Release|x86 {2594DB0D-03FF-40EA-8D27-9930E5D3FF83}.Release|Any CPU.ActiveCfg = Release|x86 {2594DB0D-03FF-40EA-8D27-9930E5D3FF83}.Release|Mixed Platforms.ActiveCfg = Release|x86 {2594DB0D-03FF-40EA-8D27-9930E5D3FF83}.Release|Mixed Platforms.Build.0 = Release|x86 {2594DB0D-03FF-40EA-8D27-9930E5D3FF83}.Release|x64.ActiveCfg = Release|x86 {2594DB0D-03FF-40EA-8D27-9930E5D3FF83}.Release|x86.ActiveCfg = Release|x86 {2594DB0D-03FF-40EA-8D27-9930E5D3FF83}.Release|x86.Build.0 = Release|x86 + {5DA4C00B-9F16-4EF9-894D-20329544265E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5DA4C00B-9F16-4EF9-894D-20329544265E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5DA4C00B-9F16-4EF9-894D-20329544265E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {5DA4C00B-9F16-4EF9-894D-20329544265E}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {5DA4C00B-9F16-4EF9-894D-20329544265E}.Debug|x64.ActiveCfg = Debug|Any CPU + {5DA4C00B-9F16-4EF9-894D-20329544265E}.Debug|x64.Build.0 = Debug|Any CPU + {5DA4C00B-9F16-4EF9-894D-20329544265E}.Debug|x86.ActiveCfg = Debug|Any CPU + {5DA4C00B-9F16-4EF9-894D-20329544265E}.Debug|x86.Build.0 = Debug|Any CPU + {5DA4C00B-9F16-4EF9-894D-20329544265E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5DA4C00B-9F16-4EF9-894D-20329544265E}.Release|Any CPU.Build.0 = Release|Any CPU + {5DA4C00B-9F16-4EF9-894D-20329544265E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {5DA4C00B-9F16-4EF9-894D-20329544265E}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {5DA4C00B-9F16-4EF9-894D-20329544265E}.Release|x64.ActiveCfg = Release|Any CPU + {5DA4C00B-9F16-4EF9-894D-20329544265E}.Release|x64.Build.0 = Release|Any CPU + {5DA4C00B-9F16-4EF9-894D-20329544265E}.Release|x86.ActiveCfg = Release|Any CPU + {5DA4C00B-9F16-4EF9-894D-20329544265E}.Release|x86.Build.0 = Release|Any CPU + {B8696D0C-8ADB-4C11-8CEE-5C81AA8C6EBD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B8696D0C-8ADB-4C11-8CEE-5C81AA8C6EBD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B8696D0C-8ADB-4C11-8CEE-5C81AA8C6EBD}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {B8696D0C-8ADB-4C11-8CEE-5C81AA8C6EBD}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {B8696D0C-8ADB-4C11-8CEE-5C81AA8C6EBD}.Debug|x64.ActiveCfg = Debug|Any CPU + {B8696D0C-8ADB-4C11-8CEE-5C81AA8C6EBD}.Debug|x64.Build.0 = Debug|Any CPU + {B8696D0C-8ADB-4C11-8CEE-5C81AA8C6EBD}.Debug|x86.ActiveCfg = Debug|Any CPU + {B8696D0C-8ADB-4C11-8CEE-5C81AA8C6EBD}.Debug|x86.Build.0 = Debug|Any CPU + {B8696D0C-8ADB-4C11-8CEE-5C81AA8C6EBD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B8696D0C-8ADB-4C11-8CEE-5C81AA8C6EBD}.Release|Any CPU.Build.0 = Release|Any CPU + {B8696D0C-8ADB-4C11-8CEE-5C81AA8C6EBD}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {B8696D0C-8ADB-4C11-8CEE-5C81AA8C6EBD}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {B8696D0C-8ADB-4C11-8CEE-5C81AA8C6EBD}.Release|x64.ActiveCfg = Release|Any CPU + {B8696D0C-8ADB-4C11-8CEE-5C81AA8C6EBD}.Release|x64.Build.0 = Release|Any CPU + {B8696D0C-8ADB-4C11-8CEE-5C81AA8C6EBD}.Release|x86.ActiveCfg = Release|Any CPU + {B8696D0C-8ADB-4C11-8CEE-5C81AA8C6EBD}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/VisualRust/Forms/DebuggingOptionsPage.cs b/VisualRust/Forms/DebuggingOptionsPage.cs index c8a41226..f0321c7f 100644 --- a/VisualRust/Forms/DebuggingOptionsPage.cs +++ b/VisualRust/Forms/DebuggingOptionsPage.cs @@ -9,9 +9,9 @@ namespace VisualRust.Options [Guid("93F42A39-0AF6-40EE-AE2C-1C44AB5F8B15")] public partial class DebuggingOptionsPage : DialogPage { - public bool UseCustomGdbPath { get; set; } - public string DebuggerLocation { get; set; } - public string ExtraArgs { get; set; } + public bool UseCustomGdb { get; set; } + public string CustomGdbPath { get; set; } + public string GdbExtraArguments { get; set; } private IWin32Window page; diff --git a/VisualRust/Forms/DebuggingOptionsPageControl.cs b/VisualRust/Forms/DebuggingOptionsPageControl.cs index bc99f433..e56ad714 100644 --- a/VisualRust/Forms/DebuggingOptionsPageControl.cs +++ b/VisualRust/Forms/DebuggingOptionsPageControl.cs @@ -1,7 +1,6 @@ using System; using System.IO; using System.Windows.Forms; -using VisualRust.Project; namespace VisualRust.Options { @@ -35,17 +34,17 @@ void OnCustomGdb_CheckedChanged(object sender, EventArgs e) public void LoadSettings(DebuggingOptionsPage optionsPage) { - defaultGdb.Checked = !optionsPage.UseCustomGdbPath; - customGdb.Checked = optionsPage.UseCustomGdbPath; - customGdbPath.Text = optionsPage.DebuggerLocation; - extraArgs.Text = optionsPage.ExtraArgs; + defaultGdb.Checked = !optionsPage.UseCustomGdb; + customGdb.Checked = optionsPage.UseCustomGdb; + customGdbPath.Text = optionsPage.CustomGdbPath; + extraArgs.Text = optionsPage.GdbExtraArguments; } public void ApplySettings(DebuggingOptionsPage optionsPage) { - optionsPage.UseCustomGdbPath = customGdb.Checked; - optionsPage.DebuggerLocation = customGdbPath.Text; - optionsPage.ExtraArgs = extraArgs.Text; + optionsPage.UseCustomGdb = customGdb.Checked; + optionsPage.CustomGdbPath = customGdbPath.Text; + optionsPage.GdbExtraArguments = extraArgs.Text; } private void OnCustomGdbButton_Click(object sender, EventArgs e) diff --git a/VisualRust/GuidList.cs b/VisualRust/GuidList.cs new file mode 100644 index 00000000..7b033e54 --- /dev/null +++ b/VisualRust/GuidList.cs @@ -0,0 +1,15 @@ +using System; + +namespace VisualRust +{ + static class GuidList + { + public const string guidVisualRustPkgString = "40c1d2b5-528b-4966-a7b1-1974e3568abe"; + public static Guid VisualRustCommandSet = new Guid("{91C8967B-EB9D-4904-AB07-4ACCA9C0ECFE}"); + + public const string CpsProjectFactoryGuidString = "c7cbdbed-50ca-46fc-be3b-1d7809d42a0a"; + public static readonly Guid CpsProjectFactoryGuid = new Guid(CpsProjectFactoryGuidString); + public const string ProjectFileGenerationGuidString = "04486994-cf85-4394-b3cd-53ddc27698f5"; + public static readonly Guid VisualRustPkgGuid = new Guid(guidVisualRustPkgString); + }; +} \ No newline at end of file diff --git a/VisualRust/Guids.cs b/VisualRust/Guids.cs deleted file mode 100644 index 6596d4cd..00000000 --- a/VisualRust/Guids.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; - -namespace VisualRust -{ - static class GuidList - { - public const string guidVisualRustPkgString = "40c1d2b5-528b-4966-a7b1-1974e3568abe"; - public static Guid VisualRustCommandSet = new Guid("{91C8967B-EB9D-4904-AB07-4ACCA9C0ECFE}"); - }; -} \ No newline at end of file diff --git a/VisualRust/ProjectForms/BasePropertyPage.cs b/VisualRust/ProjectForms/BasePropertyPage.cs deleted file mode 100644 index 74987a42..00000000 --- a/VisualRust/ProjectForms/BasePropertyPage.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Microsoft.VisualStudio.OLE.Interop; -using Microsoft.VisualStudioTools.Project; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading.Tasks; - -namespace VisualRust.Project.Forms -{ - [ComVisible(true)] - public abstract class BasePropertyPage : CommonPropertyPage - { - internal ProjectConfig[] Configs { get; private set; } - - public override void SetObjects(uint cObjects, object[] ppunk) - { - if(ppunk != null) - Configs = ppunk.OfType().ToArray(); - else - Configs = new ProjectConfig[0]; - base.SetObjects(cObjects, ppunk); - } - } -} diff --git a/VisualRust/ProjectForms/BuildPropertyPage.cs b/VisualRust/ProjectForms/BuildPropertyPage.cs deleted file mode 100644 index 2f4e1053..00000000 --- a/VisualRust/ProjectForms/BuildPropertyPage.cs +++ /dev/null @@ -1,48 +0,0 @@ -using Microsoft.VisualStudioTools.Project; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading.Tasks; - -namespace VisualRust.Project.Forms -{ - [ComVisible(true)] - [System.Runtime.InteropServices.Guid(Constants.BuildPropertyPage)] - public class BuildPropertyPage : BasePropertyPage - { - private readonly BuildPropertyControl control; - - public BuildPropertyPage() - { - control = new BuildPropertyControl(isDirty => IsDirty = isDirty); - } - - public override System.Windows.Forms.Control Control - { - get { return control; } - } - - public override void Apply() - { - control.ApplyConfig(Configs); - IsDirty = false; - } - - public override void LoadSettings() - { - Loading = true; - try { - control.LoadSettings(Configs); - } finally { - Loading = false; - } - } - - public override string Name - { - get { return "Build"; } - } - } -} diff --git a/VisualRust/ProjectForms/DebugPropertyPage.cs b/VisualRust/ProjectForms/DebugPropertyPage.cs deleted file mode 100644 index 11bffc8c..00000000 --- a/VisualRust/ProjectForms/DebugPropertyPage.cs +++ /dev/null @@ -1,54 +0,0 @@ -using Microsoft.VisualStudioTools.Project; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading.Tasks; -using VisualRust.Project.Configuration; - -namespace VisualRust.Project.Forms -{ - [ComVisible(true)] - [Guid(Constants.DebugPropertyPage)] - public class DebugPropertyPage : BasePropertyPage - { - private readonly DebugPropertyControl control; - - public DebugPropertyPage() - { - control = new DebugPropertyControl(isDirty => IsDirty = isDirty); - } - - public override System.Windows.Forms.Control Control - { - get { return control; } - } - - public override void Apply() - { - control.ApplyConfig(GetUserConfigs()); - IsDirty = false; - } - - public override void LoadSettings() - { - Loading = true; - try { - control.LoadSettings(GetUserConfigs()); - } finally { - Loading = false; - } - } - - public override string Name - { - get { return "Debug"; } - } - - private MsBuildConfiguration[] GetUserConfigs() - { - return Configs.Select(c => ((RustProjectConfig)c).UserCfg).ToArray(); - } - } -} diff --git a/VisualRust/ProjectForms/GeneralPropertyPage.cs b/VisualRust/ProjectForms/GeneralPropertyPage.cs deleted file mode 100644 index bd1848ed..00000000 --- a/VisualRust/ProjectForms/GeneralPropertyPage.cs +++ /dev/null @@ -1,48 +0,0 @@ -using Microsoft.VisualStudioTools.Project; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading.Tasks; - -namespace VisualRust.Project.Forms -{ - [ComVisible(true)] - [System.Runtime.InteropServices.Guid(Constants.ApplicationPropertyPage)] - public class ApplicationPropertyPage : BasePropertyPage - { - private readonly ApplicationPropertyControl control; - - public ApplicationPropertyPage() - { - control = new ApplicationPropertyControl(isDirty => IsDirty = isDirty); - } - - public override System.Windows.Forms.Control Control - { - get { return control; } - } - - public override void Apply() - { - control.ApplyConfig(this.Project); - IsDirty = false; - } - - public override void LoadSettings() - { - Loading = true; - try { - control.LoadSettings(this.Project); - } finally { - Loading = false; - } - } - - public override string Name - { - get { return "General"; } - } - } -} diff --git a/VisualRust/ProjectForms/TargetOutputsPropertyPage.cs b/VisualRust/ProjectForms/TargetOutputsPropertyPage.cs deleted file mode 100644 index 3c0e0110..00000000 --- a/VisualRust/ProjectForms/TargetOutputsPropertyPage.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using VisualRust.Project.Controls; - -namespace VisualRust.Project.Forms -{ - [ComVisible(true)] - [System.Runtime.InteropServices.Guid(Constants.TargetOutputsPage)] - public class TargetOutputsPropertyPage : WpfPropertyPage - { - public override string Name { get { return "Output Targets"; } } - protected override FrameworkElement CreateControl() - { - return new OutputPage(); - } - - protected override IPropertyPageContext CreateDataContext() - { - return new OutputTargetSectionViewModel(this.Config.Manifest, PickTargetOutputTypeWindow.Start); - } - } -} diff --git a/VisualRust/ProjectForms/WpfPropertyPage.cs b/VisualRust/ProjectForms/WpfPropertyPage.cs deleted file mode 100644 index 5cc35e26..00000000 --- a/VisualRust/ProjectForms/WpfPropertyPage.cs +++ /dev/null @@ -1,143 +0,0 @@ -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.OLE.Interop; -using Microsoft.VisualStudioTools.Project; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Interop; -using System.Windows.Media; -using VisualRust.Project.Controls; - -namespace VisualRust.Project.Forms -{ - [ComVisible(true)] - public abstract class WpfPropertyPage : IPropertyPage - { - IPropertyPageContext data; - HwndSource source; - FrameworkElement control; - - protected IPropertyPageSite Site { get; private set; } - public abstract string Name { get; } - internal RustProjectNodeProperties Config { get; private set; } - - public void Activate(IntPtr hWndParent, RECT[] pRect, int bModal) - { - int width = pRect[0].right - pRect[0].left; - int height = pRect[0].bottom - pRect[0].top; - source = new HwndSource(0, 0x54000000, 0, pRect[0].left, pRect[0].top, width, height, "", hWndParent); - control = CreateControl(); - control.DataContext = data; - source.RootVisual = control; - } - - abstract protected FrameworkElement CreateControl(); - abstract protected IPropertyPageContext CreateDataContext(); - - public int Apply() - { - try - { - data.Apply(); - return VSConstants.S_OK; - } - catch (Exception e) - { - return Marshal.GetHRForException(e); - } - } - - public void Deactivate() - { - source.Dispose(); - } - - public void GetPageInfo(PROPPAGEINFO[] pPageInfo) - { - Utilities.ArgumentNotNull("pPageInfo", pPageInfo); - - PROPPAGEINFO info = new PROPPAGEINFO(); - - info.cb = (uint)Marshal.SizeOf(typeof(PROPPAGEINFO)); - info.dwHelpContext = 0; - info.pszDocString = null; - info.pszHelpFile = null; - info.pszTitle = Name; - if (source == null) - { - info.SIZE.cx = 0; - info.SIZE.cy = 0; - } - else - { - RECT[] pRect; - NativeMethods.GetWindowRect(source.Handle, out pRect); - int width = pRect[0].right - pRect[0].left; - int height = pRect[0].bottom - pRect[0].top; - info.SIZE.cx = width; - info.SIZE.cy = height; - } - pPageInfo[0] = info; - } - - public void Help(string pszHelpDir) - { - } - - public void Move(RECT[] pRect) - { - int width = pRect[0].right - pRect[0].left; - int height = pRect[0].bottom - pRect[0].top; - NativeMethods.SetWindowPos(this.source.Handle, IntPtr.Zero, pRect[0].left, pRect[0].top, width, height, 0x44); - } - - public void SetObjects(uint cObjects, object[] ppunk) - { - if (ppunk == null) - { - return; - } - - if (cObjects > 0) - { - RustProjectNodeProperties ctx = ppunk[0] as RustProjectNodeProperties; - if(ctx != null) - { - this.Config = ctx; - data = CreateDataContext(); - data.DirtyChanged += (_, __) => Site.OnStatusChange((uint)(data.IsDirty ? PropPageStatus.Dirty : PropPageStatus.Clean)); - } - } - } - - public void SetPageSite(IPropertyPageSite pPageSite) - { - Site = pPageSite; - } - - public void Show(uint nCmdShow) - { - if (nCmdShow == NativeMethods.SW_SHOW || nCmdShow == NativeMethods.SW_SHOWNORMAL) - control.Visibility = Visibility.Visible; - if (nCmdShow == NativeMethods.SW_HIDE) - control.Visibility = Visibility.Collapsed; - } - - public int TranslateAccelerator(Microsoft.VisualStudio.OLE.Interop.MSG[] pMsg) - { - return VSConstants.E_NOTIMPL; - } - - public int IsPageDirty() - { - if(data == null) - return VSConstants.S_FALSE; - return data.IsDirty ? VSConstants.S_OK : VSConstants.S_FALSE; - } - } -} diff --git a/VisualRust/ProjectProperties.cs b/VisualRust/ProjectProperties.cs new file mode 100644 index 00000000..afd71e09 --- /dev/null +++ b/VisualRust/ProjectProperties.cs @@ -0,0 +1,44 @@ +using System.ComponentModel.Composition; +using Microsoft.VisualStudio.ProjectSystem; +using Microsoft.VisualStudio.ProjectSystem.Properties; +using Microsoft.VisualStudio.ProjectSystem.Utilities; + +namespace VisualRust +{ + [Export] + internal partial class ProjectProperties : StronglyTypedPropertyAccess + { + /// + /// Initializes a new instance of the class. + /// + [ImportingConstructor] + public ProjectProperties(ConfiguredProject configuredProject) + : base(configuredProject) + { + } + + /// + /// Initializes a new instance of the class. + /// + public ProjectProperties(ConfiguredProject configuredProject, string file, string itemType, string itemName) + : base(configuredProject, file, itemType, itemName) + { + } + + /// + /// Initializes a new instance of the class. + /// + public ProjectProperties(ConfiguredProject configuredProject, IProjectPropertiesContext projectPropertiesContext) + : base(configuredProject, projectPropertiesContext) + { + } + + /// + /// Initializes a new instance of the class. + /// + public ProjectProperties(ConfiguredProject configuredProject, UnconfiguredProject unconfiguredProject) + : base(configuredProject, unconfiguredProject) + { + } + } +} diff --git a/VisualRust/ProjectSystem/DummyLogger.cs b/VisualRust/ProjectSystem/DummyLogger.cs new file mode 100644 index 00000000..7c644144 --- /dev/null +++ b/VisualRust/ProjectSystem/DummyLogger.cs @@ -0,0 +1,33 @@ +using Microsoft.Common.Core.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace VisualRust.ProjectSystem +{ + internal class DummyLogger : IActionLog + { + public LogVerbosity LogVerbosity => LogVerbosity.None; + + public void Flush() + { + } + + public Task WriteAsync(LogVerbosity verbosity, MessageCategory category, string message) + { + return Task.CompletedTask; + } + + public Task WriteFormatAsync(LogVerbosity verbosity, MessageCategory category, string format, params object[] arguments) + { + return Task.CompletedTask; + } + + public Task WriteLineAsync(LogVerbosity verbosity, MessageCategory category, string message) + { + return Task.CompletedTask; + } + } +} diff --git a/VisualRust/ProjectSystem/GnuDebugLaunchSettingsProvider.cs b/VisualRust/ProjectSystem/GnuDebugLaunchSettingsProvider.cs new file mode 100644 index 00000000..db90c5f0 --- /dev/null +++ b/VisualRust/ProjectSystem/GnuDebugLaunchSettingsProvider.cs @@ -0,0 +1,145 @@ +using MICore.Xml.LaunchOptions; +using Microsoft.VisualStudio.ProjectSystem.Debuggers; +using Microsoft.VisualStudio.ProjectSystem.Utilities.DebuggerProviders; +using Microsoft.VisualStudio.ProjectSystem.VS.Debuggers; +using System; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using System.Xml; +using System.Xml.Serialization; +using VisualRust.Options; +using VisualRust.Shared; + +namespace VisualRust.ProjectSystem +{ + internal class GnuDebugLaunchSettingsProvider : IDebugLaunchSettingsProvider + { + protected readonly static Guid MIDebugEngineGuid = new Guid(Microsoft.MIDebugEngine.EngineConstants.EngineId); + + public async Task GetLaunchSettingsAsync(string executable, string arguments, string workingDirectory, + DebugLaunchOptions options, Cargo cargo, TargetTriple triple) + { + EnvDTE.DTE env = (EnvDTE.DTE)VisualRustPackage.GetGlobalService(typeof(EnvDTE.DTE)); + var target = new DebugLaunchSettings(options) + { + LaunchOperation = DebugLaunchOperation.CreateProcess, + LaunchDebugEngineGuid = MIDebugEngineGuid, + Executable = executable, + Arguments = arguments, + CurrentDirectory = workingDirectory, + Options = ToXmlString(await BuildLaunchOptionsAsync(executable, arguments, workingDirectory, env, cargo, triple)) + }; + return target; + } + + private async Task BuildLaunchOptionsAsync(string path, string args, string workingDir, + EnvDTE.DTE dte, Cargo cargo, TargetTriple triple) + { + // We could go through LocalLaunchOptions, but this way we can pass additional args + PipeLaunchOptions options = new PipeLaunchOptions(); + options.PipePath = GetGdbPath(dte, triple); + options.PipeArguments = String.Format("-q -interpreter=mi {0}", GetDebuggingConfigProperty(dte, nameof(DebuggingOptionsPage.GdbExtraArguments))); + options.ExePath = EscapePath(path); + options.ExeArguments = args; + options.SetupCommands = GetSetupCommands(); + // this affects the number of bytes the engine reads when disassembling commands, + // x64 has the largest maximum command size, so it should be safe to use for x86 as well + options.TargetArchitecture = TargetArchitecture.x64; + await SetWorkingDirectoryAsync(options, path, workingDir, cargo); + return options; + } + + private async Task SetWorkingDirectoryAsync(PipeLaunchOptions options, string path, string workingDir, Cargo cargo) + { + options.WorkingDirectory = EscapePath(workingDir); + // GDB won't search working directory by default, but this is expected on Windows. + string additionalPath = workingDir; + + // TODO: this is probably wrong, because the sysroot does not directly contain SOLibs + + string rustInstallPath = await cargo.GetSysrootAsync(); + if (rustInstallPath != null) + { + // prepend toolchain directory + additionalPath = rustInstallPath + ";" + additionalPath; + } + options.AdditionalSOLibSearchPath = additionalPath; + } + + string GetGdbPath(EnvDTE.DTE dte, TargetTriple triple) + { + string gdbPath = null; + //bool useCustomPath = false; + //bool.TryParse(GetDebuggingConfigProperty(dte, "")); + bool useCustomPath = GetDebuggingConfigProperty(dte, nameof(DebuggingOptionsPage.UseCustomGdb)); + if (useCustomPath) + { + gdbPath = GetDebuggingConfigProperty(dte, nameof(DebuggingOptionsPage.CustomGdbPath)); + } + + if (gdbPath != null) + return gdbPath; + + return Path.Combine( + Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), + "gdb", + GetArchitectureName(triple), + "bin\\gdb"); + } + + // We need to run the right gdb depending on the architecture of the debuggee + private string GetArchitectureName(TargetTriple triple) + { + if (triple != null) + { + if (triple.Arch == "i686" || triple.Arch == "x86_64") + return triple.Arch; + } + if (System.Environment.Is64BitOperatingSystem) + return "x86_64"; + return "i686"; + } + + private static string ToXmlString(T obj) + { + var builder = new StringBuilder(); + var serializer = new XmlSerializer(typeof(T)); + using (var writer = XmlWriter.Create(builder, new XmlWriterSettings { OmitXmlDeclaration = true })) + { + serializer.Serialize(writer, (object)obj); + } + return builder.ToString(); + } + + private static string EscapePath(string path) + { + if (String.IsNullOrEmpty(path)) + return ""; + return String.Format("\"{0}\"", path); + } + + Command[] GetSetupCommands() + { + return new string[] { "-gdb-set new-console on" } + //.Union(GetScriptLines()) + .Select(cmd => new Command { Value = cmd }) + .ToArray(); + } + + //string[] GetScriptLines() + //{ + // string debuggerScript = env.DebugConfig.DebuggerScript; + // if (String.IsNullOrEmpty(debuggerScript)) + // return new string[0]; + // return debuggerScript.Split(new[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries); + //} + + private T GetDebuggingConfigProperty(EnvDTE.DTE env, string key) + { + return (T)env.get_Properties("Visual Rust", "Debugging").Item(key).Value; + } + } +} diff --git a/VisualRust/ProjectSystem/IDebugLaunchSettingsProvider.cs b/VisualRust/ProjectSystem/IDebugLaunchSettingsProvider.cs new file mode 100644 index 00000000..21887e1a --- /dev/null +++ b/VisualRust/ProjectSystem/IDebugLaunchSettingsProvider.cs @@ -0,0 +1,14 @@ +using Microsoft.VisualStudio.ProjectSystem.Debuggers; +using Microsoft.VisualStudio.ProjectSystem.Utilities.DebuggerProviders; +using System; +using System.Threading.Tasks; +using VisualRust.Shared; + +namespace VisualRust.ProjectSystem +{ + internal interface IDebugLaunchSettingsProvider + { + Task GetLaunchSettingsAsync(string executable, string arguments, string workingDirectory, + DebugLaunchOptions options, Cargo cargo, TargetTriple triple); + } +} diff --git a/VisualRust/ProjectSystem/LoadHooks.cs b/VisualRust/ProjectSystem/LoadHooks.cs new file mode 100644 index 00000000..5953b826 --- /dev/null +++ b/VisualRust/ProjectSystem/LoadHooks.cs @@ -0,0 +1,145 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.Globalization; +using System.IO; +using System.Threading.Tasks; +using Microsoft.Common.Core; +using Microsoft.Common.Core.Enums; +using Microsoft.Common.Core.IO; +using Microsoft.Common.Core.Shell; +using Microsoft.VisualStudio.ProjectSystem; +using VisualRust.ProjectSystem.FileSystemMirroring.IO; +using VisualRust.ProjectSystem.FileSystemMirroring.Project; +using Microsoft.VisualStudio.Shell.Interop; +using Microsoft.Common.Core.Logging; +//#if VS14 +using Microsoft.VisualStudio.ProjectSystem.Utilities; +using IThreadHandling = Microsoft.VisualStudio.ProjectSystem.IThreadHandling; +using Microsoft.VisualStudio; +//#endif +#if VS15 +using Microsoft.VisualStudio.ProjectSystem.VS; +using IThreadHandling = Microsoft.VisualStudio.ProjectSystem.IProjectThreadingService; +#endif + + +namespace VisualRust.ProjectSystem +{ + internal sealed class LoadHooks + { + [Export(typeof(IFileSystemMirroringProjectTemporaryItems))] + [AppliesTo(VisualRustPackage.UniqueCapability)] + private FileSystemMirroringProject Project { get; } + + private readonly MsBuildFileSystemWatcher _fileWatcher; + private readonly string _projectDirectory; + private readonly IFileSystem _fileSystem = new FileSystem(); + private readonly IThreadHandling _threadHandling; + private readonly UnconfiguredProject _unconfiguredProject; + private readonly IEnumerable> _cpsIVsProjects; + + /// + /// Backing field for the similarly named property. + /// + [ImportingConstructor] + public LoadHooks(UnconfiguredProject unconfiguredProject + , [ImportMany("Microsoft.VisualStudio.ProjectSystem.Microsoft.VisualStudio.Shell.Interop.IVsProject")] IEnumerable> cpsIVsProjects + , IProjectLockService projectLockService + , IThreadHandling threadHandling) + { + + _unconfiguredProject = unconfiguredProject; + _cpsIVsProjects = cpsIVsProjects; + _threadHandling = threadHandling; + + _projectDirectory = unconfiguredProject.GetProjectDirectory(); + + var log = new DummyLogger(); + + unconfiguredProject.ProjectUnloading += ProjectUnloading; + _fileWatcher = new MsBuildFileSystemWatcher(_projectDirectory, "*", 25, 1000, _fileSystem, new MsBuildFileSystemFilter(), log); + _fileWatcher.Error += FileWatcherError; + Project = new FileSystemMirroringProject(unconfiguredProject, projectLockService, _fileWatcher, null, log); + } + + public static IVsPackage EnsurePackageLoaded(Guid guidPackage) + { + var shell = (IVsShell)VisualRustPackage.GetGlobalService(typeof(IVsShell)); + var guid = guidPackage; + IVsPackage package; + int hr = ErrorHandler.ThrowOnFailure(shell.IsPackageLoaded(ref guid, out package), VSConstants.E_FAIL); + guid = guidPackage; + if (hr != VSConstants.S_OK) + { + ErrorHandler.ThrowOnFailure(shell.LoadPackage(ref guid, out package), VSConstants.E_FAIL); + } + + return package; + } + + [AppliesTo(VisualRustPackage.UniqueCapability)] +//#if VS14 + [UnconfiguredProjectAutoLoad2(completeBy: UnconfiguredProjectLoadCheckpoint.CapabilitiesEstablished)] +//#else +// [ProjectAutoLoad(startAfter: ProjectLoadCheckpoint.UnconfiguredProjectLocalCapabilitiesEstablished, +// completeBy: ProjectLoadCheckpoint.BeforeLoadInitialConfiguration, +// RequiresUIThread = false)] +//#endif + public async Task InitializeProjectFromDiskAsync() + { + await Project.CreateInMemoryImport(); + _fileWatcher.Start(); + + await _threadHandling.SwitchToUIThread(); + // Make sure package is loaded + EnsurePackageLoaded(GuidList.VisualRustPkgGuid); + + // TODO: start watching the Cargo manifest + } + + private void FileWatcherError(object sender, EventArgs args) + { + _fileWatcher.Error -= FileWatcherError; + //VsAppShell.Current.DispatchOnUIThread(() => { + // foreach (var iVsProjectLazy in _cpsIVsProjects) + // { + // IVsProject iVsProject; + // try + // { + // iVsProject = iVsProjectLazy.Value; + // } + // catch (Exception) + // { + // continue; + // } + + // if (iVsProject.AsUnconfiguredProject() != _unconfiguredProject) + // { + // continue; + // } + + // var solution = VsAppShell.Current.GetGlobalService(typeof(SVsSolution)); + // solution.CloseSolutionElement((uint)__VSSLNCLOSEOPTIONS.SLNCLOSEOPT_UnloadProject, (IVsHierarchy)iVsProject, 0); + // return; + // } + //}); + } + + private async Task ProjectUnloading(object sender, EventArgs args) + { + //VsAppShell.Current.AssertIsOnMainThread(); + + _unconfiguredProject.ProjectUnloading -= ProjectUnloading; + _fileWatcher.Dispose(); + + if (!_fileSystem.DirectoryExists(_projectDirectory)) + { + return; + } + } + } +} \ No newline at end of file diff --git a/VisualRust/ProjectSystem/MsBuildFileSystemFilter.cs b/VisualRust/ProjectSystem/MsBuildFileSystemFilter.cs new file mode 100644 index 00000000..e161b8a3 --- /dev/null +++ b/VisualRust/ProjectSystem/MsBuildFileSystemFilter.cs @@ -0,0 +1,29 @@ +using System.IO; +using System.Linq; +using Microsoft.Common.Core; +using VisualRust.ProjectSystem.FileSystemMirroring.IO; + +namespace VisualRust.ProjectSystem +{ + internal sealed class MsBuildFileSystemFilter : IMsBuildFileSystemFilter + { + public bool IsFileAllowed(string relativePath, FileAttributes attributes) + { + return !attributes.HasFlag(FileAttributes.Hidden) + && !HasExtension(relativePath, ".user", ".rsproj", ".sln"); + } + + public bool IsDirectoryAllowed(string relativePath, FileAttributes attributes) + { + return !attributes.HasFlag(FileAttributes.Hidden) && !relativePath.StartsWith("target\\"); + } + + public void Seal() { } + + private static bool HasExtension(string filePath, params string[] possibleExtensions) + { + var extension = Path.GetExtension(filePath); + return !string.IsNullOrEmpty(extension) && possibleExtensions.Any(pe => extension.EqualsIgnoreCase(pe)); + } + } +} diff --git a/VisualRust/ProjectSystem/MsvcDebugLaunchSettingsProvider.cs b/VisualRust/ProjectSystem/MsvcDebugLaunchSettingsProvider.cs new file mode 100644 index 00000000..44416aa9 --- /dev/null +++ b/VisualRust/ProjectSystem/MsvcDebugLaunchSettingsProvider.cs @@ -0,0 +1,25 @@ +using Microsoft.VisualStudio.ProjectSystem.Debuggers; +using Microsoft.VisualStudio.ProjectSystem.Utilities.DebuggerProviders; +using Microsoft.VisualStudio.ProjectSystem.VS.Debuggers; +using System.Threading.Tasks; +using VisualRust.Shared; + +namespace VisualRust.ProjectSystem +{ + internal class MsvcDebugLaunchSettingsProvider : IDebugLaunchSettingsProvider + { + public Task GetLaunchSettingsAsync(string executable, string arguments, string workingDirectory, + DebugLaunchOptions options, Cargo cargo, TargetTriple triple) + { + var target = new DebugLaunchSettings(options) + { + LaunchOperation = DebugLaunchOperation.CreateProcess, + LaunchDebugEngineGuid = DebuggerEngines.NativeOnlyEngine, + Executable = executable, + Arguments = arguments, + CurrentDirectory = workingDirectory + }; + return Task.FromResult(target); + } + } +} diff --git a/VisualRust/ProjectSystem/ProjectIconProvider.cs b/VisualRust/ProjectSystem/ProjectIconProvider.cs new file mode 100644 index 00000000..0d8176be --- /dev/null +++ b/VisualRust/ProjectSystem/ProjectIconProvider.cs @@ -0,0 +1,60 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System.Windows.Forms; +using Microsoft.VisualStudio.Imaging.Interop; +using Microsoft.VisualStudio.Shell.Interop; + +namespace VisualRust.ProjectSystem +{ + internal static class ProjectIconProvider + { + private static IVsImageMonikerImageList _monikerImageList; + private static ImageList _imageList; + + public static ImageMoniker ProjectNodeImage { get; private set; } + public static ImageMoniker RustFileNodeImage { get; private set; } + public static ImageMoniker CargoManifestNodeImage { get; private set; } + + /// + /// Creates image list and image monikers for project icons. + /// Must be called on UI thread. + /// + public static void LoadProjectImages() + { + if (_monikerImageList == null) + { + IVsImageService2 imageService = VisualRustPackage.GetGlobalService(typeof(SVsImageService)) as IVsImageService2; + + if (_imageList == null) + { + _imageList = new ImageList(); + } + + _imageList.Images.Add(Resources.RustProjectNode); + _imageList.Images.Add(Resources.RustFileNode); + _imageList.Images.Add(Resources.CargoManifestNode); + + _monikerImageList = imageService.CreateMonikerImageListFromHIMAGELIST(_imageList.Handle); + imageService.AddCustomImageList(_monikerImageList); + + ImageMoniker[] monikers = new ImageMoniker[3]; + _monikerImageList.GetImageMonikers(0, 3, monikers); + + ProjectNodeImage = monikers[0]; + RustFileNodeImage = monikers[1]; + CargoManifestNodeImage = monikers[2]; + } + } + + public static void Close() + { + if (_imageList != null) + { + _imageList.Dispose(); + _imageList = null; + _monikerImageList = null; + } + } + } +} diff --git a/VisualRust/ProjectSystem/ProjectTreeModifiers.cs b/VisualRust/ProjectSystem/ProjectTreeModifiers.cs new file mode 100644 index 00000000..757418a2 --- /dev/null +++ b/VisualRust/ProjectSystem/ProjectTreeModifiers.cs @@ -0,0 +1,50 @@ +// TODO: IProjectTreeModifier has been replaced by IProjectTreePropertiesProvider in VS15 +//#if VS14 +using System.ComponentModel.Composition; +using System.IO; +using Microsoft.Common.Core; +using Microsoft.VisualStudio.Imaging; +using Microsoft.VisualStudio.ProjectSystem.Designers; +using Microsoft.VisualStudio.ProjectSystem.Utilities; +using Microsoft.VisualStudio.ProjectSystem.Utilities.Designers; + +namespace VisualRust.ProjectSystem +{ + [Export(typeof(IProjectTreeModifier))] + [AppliesTo(VisualRustPackage.UniqueCapability)] + internal sealed class ProjectTreeModifier : IProjectTreeModifier + { + public IProjectTree ApplyModifications(IProjectTree tree, IProjectTreeProvider projectTreeProvider) + { + if (tree != null) + { + if (tree.Capabilities.Contains(ProjectTreeCapabilities.ProjectRoot)) + { + tree = tree.SetIcon(ProjectIconProvider.ProjectNodeImage.ToProjectSystemType()); + } + else if (tree.Capabilities.Contains(ProjectTreeCapabilities.FileOnDisk)) + { + string name = Path.GetFileName(tree.FilePath).ToLowerInvariant(); + if (name == "cargo.toml") + { + tree = tree.SetIcon(ProjectIconProvider.CargoManifestNodeImage.ToProjectSystemType()); + } + else + { + string ext = Path.GetExtension(tree.FilePath).ToLowerInvariant(); + if (ext == ".rs") + { + tree = tree.SetIcon(ProjectIconProvider.RustFileNodeImage.ToProjectSystemType()); + } + else if (ext == ".md") + { + tree = tree.SetIcon(KnownMonikers.MarkdownFile.ToProjectSystemType()); + } + } + } + } + return tree; + } + } +} +//#endif diff --git a/VisualRust/ProjectSystem/RustDebuggerProvider.cs b/VisualRust/ProjectSystem/RustDebuggerProvider.cs new file mode 100644 index 00000000..40716e76 --- /dev/null +++ b/VisualRust/ProjectSystem/RustDebuggerProvider.cs @@ -0,0 +1,94 @@ +using Microsoft.VisualStudio.ProjectSystem; +using Microsoft.VisualStudio.ProjectSystem.Debuggers; +using Microsoft.VisualStudio.ProjectSystem.Utilities; +using Microsoft.VisualStudio.ProjectSystem.Utilities.DebuggerProviders; +using Microsoft.VisualStudio.ProjectSystem.VS.Debuggers; +using Microsoft.VisualStudio.Shell.Interop; +using Microsoft.VisualStudio.Threading; +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.IO; +using System.Threading.Tasks; +using VisualRust.Shared; + +namespace VisualRust.ProjectSystem +{ + [ExportDebugger(RustDebugger.SchemaName)] + [AppliesTo(VisualRustPackage.UniqueCapability)] + public class RustDebuggerProvider : DebugLaunchProviderBase + { + [Import] + private ProjectProperties Properties { get; set; } + + private Cargo cargo; + + [ImportingConstructor] + public RustDebuggerProvider(ConfiguredProject configuredProject) : base(configuredProject) + { + // TODO: this should initialized once when the project is loaded and then be updated using a file watcher on Cargo.toml + cargo = Cargo.FindSupportedInstallation(); + } + + public override Task CanLaunchAsync(DebugLaunchOptions launchOptions) + { + return TplExtensions.TrueTask; + } + + public override async Task> QueryDebugTargetsAsync(DebugLaunchOptions launchOptions) + { + var targets = new List(); + + if (cargo == null) + { + return targets; + } + + var props = await Properties.GetConfigurationGeneralPropertiesAsync(); + var manifestPath = await props.ManifestPath.GetEvaluatedValueAsync(); + if (String.IsNullOrWhiteSpace(manifestPath)) + { + manifestPath = "Cargo.toml"; + } + cargo.WorkingDirectory = Path.GetDirectoryName(Path.Combine(Path.GetDirectoryName(ConfiguredProject.UnconfiguredProject.FullPath), manifestPath)); + // TODO: this should initialized once when the project is loaded and then be updated using a file watcher on Cargo.toml + // can't use `cargo rustc -- --print file-names`, because it would build all dependencies first + var metadata = await cargo.ReadMetadataAsync(false); + var pkgTarget = metadata.packages[0].targets[0]; + if (pkgTarget.kind.Contains("bin")) // TODO: show a real error when the project is not a binary + { + var debuggerProperties = await Properties.GetRustDebuggerPropertiesAsync(); + var targetConfiguration = ConfiguredProject.ProjectConfiguration.Dimensions["Configuration"].ToLowerInvariant(); + string executablePath = ConfiguredProject.UnconfiguredProject.MakeRooted(Path.Combine("target", targetConfiguration, pkgTarget.name + ".exe")); + string arguments = await debuggerProperties.StartArguments.GetEvaluatedValueAsync(); + string workingDirectory = await debuggerProperties.StartWorkingDirectory.GetValueAsPathAsync(false, false); + if (string.IsNullOrWhiteSpace(workingDirectory)) + { + workingDirectory = Path.GetDirectoryName(ConfiguredProject.UnconfiguredProject.FullPath); + } + + // TODO: support --target flag (the host triple is not necessarily correct) + var targetTriple = await cargo.GetHostTargetTripleAsync(); + IDebugLaunchSettingsProvider provider = null; + if (targetTriple.Abi == "gnu") + provider = new GnuDebugLaunchSettingsProvider(); + else if (targetTriple.Abi == "msvc") + provider = new MsvcDebugLaunchSettingsProvider(); + + var target = await provider.GetLaunchSettingsAsync(executablePath, arguments, workingDirectory, + launchOptions, cargo, targetTriple); + + targets.Add(target); + } + + return targets; + } + + public override async Task LaunchAsync(DebugLaunchOptions launchOptions) + { + await base.LaunchAsync(launchOptions); + IVsCommandWindow commandWnd = (IVsCommandWindow)ServiceProvider.GetService(typeof(SVsCommandWindow)); + commandWnd.ExecuteCommand("Tools.Alias gdb Debug.VRDebugExec"); + } + } +} diff --git a/VisualRust/ProjectSystem/RustProjectFileGenerator.cs b/VisualRust/ProjectSystem/RustProjectFileGenerator.cs new file mode 100644 index 00000000..ec7d327f --- /dev/null +++ b/VisualRust/ProjectSystem/RustProjectFileGenerator.cs @@ -0,0 +1,62 @@ +using Microsoft.Common.Core; +using VisualRust.ProjectSystem.FileSystemMirroring.MsBuild; +using VisualRust.ProjectSystem.FileSystemMirroring.Shell; +using System; +using System.IO; +using System.Runtime.InteropServices; +using System.Xml.Linq; + +namespace VisualRust.ProjectSystem +{ + [Guid(GuidList.ProjectFileGenerationGuidString)] + internal sealed class RustProjectFileGenerator : IVsProjectGenerator + { + public void RunGenerator(string szSourceFileMoniker, out bool pfProjectIsGenerated, out string pbstrGeneratedFile, out Guid pGuidProjType) + { + pfProjectIsGenerated = true; + pbstrGeneratedFile = GetCpsProjFileName(szSourceFileMoniker); + pGuidProjType = GuidList.CpsProjectFactoryGuid; + + EnsureCpsProjFile(pbstrGeneratedFile); + } + + private string GetCpsProjFileName(string fileName) + { + var directory = new DirectoryInfo(Path.GetDirectoryName(fileName)); + return directory.FullName + + Path.DirectorySeparatorChar + + directory.Name + + ".rsproj"; + } + + private void EnsureCpsProjFile(string cpsProjFileName) + { + var fileInfo = new FileInfo(cpsProjFileName); + if (fileInfo.Exists) + { + return; + } + + var xProj = new XProject(); + + xProj.Add( + new XPropertyGroup("Globals", null, + new XProperty("ProjectGuid", Guid.NewGuid().ToString("D")), + new XProperty("ManifestPath", "Cargo.toml") + ), + new XProjElement("Import", new XAttribute("Project", @"$(MSBuildExtensionsPath)\VisualRust\VisualRust.Rust.targets")), + new XProjElement("Import", + new XAttribute("Project", @"$(MSBuildThisFileName).InMemory.Targets"), + new XAttribute("Condition", "Exists('$(MSBuildThisFileName).InMemory.Targets')") + ) + ); + + var xProjDocument = new XProjDocument(xProj); + + using (var writer = fileInfo.CreateText()) + { + xProjDocument.Save(writer); + } + } + } +} diff --git a/VisualRust/ProjectSystem/RustProjectSourceItemProviderExtensions.cs b/VisualRust/ProjectSystem/RustProjectSourceItemProviderExtensions.cs new file mode 100644 index 00000000..0b4b0016 --- /dev/null +++ b/VisualRust/ProjectSystem/RustProjectSourceItemProviderExtensions.cs @@ -0,0 +1,25 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System.ComponentModel.Composition; +using Microsoft.VisualStudio.ProjectSystem; +using VisualRust.ProjectSystem.FileSystemMirroring.Project; +//#if VS14 +using Microsoft.VisualStudio.ProjectSystem.Items; +using Microsoft.VisualStudio.ProjectSystem.Utilities; +//#endif + +namespace VisualRust.ProjectSystem +{ + [Export(typeof(IProjectSourceItemProviderExtension))] + [Export(typeof(IProjectFolderItemProviderExtension))] + [AppliesTo(VisualRustPackage.UniqueCapability)] + internal sealed class RustProjectSourceItemProviderExtension : FileSystemMirroringProjectSourceItemProviderExtensionBase + { + [ImportingConstructor] + public RustProjectSourceItemProviderExtension(UnconfiguredProject unconfiguredProject, ConfiguredProject configuredProject, IProjectLockService projectLockService, IFileSystemMirroringProjectTemporaryItems temporaryItems) + : base(unconfiguredProject, configuredProject, projectLockService, temporaryItems) + { + } + } +} \ No newline at end of file diff --git a/VisualRust/Properties/AssemblyInfo.cs b/VisualRust/Properties/AssemblyInfo.cs index 083362b4..293658e2 100644 --- a/VisualRust/Properties/AssemblyInfo.cs +++ b/VisualRust/Properties/AssemblyInfo.cs @@ -27,8 +27,8 @@ // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("0.1.2.0")] -[assembly: AssemblyFileVersion("0.1.2.0")] +[assembly: AssemblyVersion("0.2.0.0")] +[assembly: AssemblyFileVersion("0.2.0.0")] diff --git a/VisualRust/Racer/RacerSingleton.cs b/VisualRust/Racer/RacerSingleton.cs index 1ab991d9..5ec613a1 100644 --- a/VisualRust/Racer/RacerSingleton.cs +++ b/VisualRust/Racer/RacerSingleton.cs @@ -3,6 +3,7 @@ using System.IO; using System.Reflection; using System.Runtime.InteropServices; +using VisualRust.Options; using Process = System.Diagnostics.Process; namespace VisualRust.Racer @@ -61,13 +62,13 @@ private void ReinitializeRacerPaths() { DTE env = (DTE)VisualRustPackage.GetGlobalService(typeof(DTE)); // If path to racer.exe is specifed, use it - if(GetVisualRustProperty(env, "UseCustomRacer")) - racerPathForExecution = GetVisualRustProperty(env, "CustomRacerPath"); + if(GetVisualRustProperty(env, nameof(RustOptionsPage.UseCustomRacer))) + racerPathForExecution = GetVisualRustProperty(env, nameof(RustOptionsPage.CustomRacerPath)); else racerPathForExecution = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Racer", BundledRacerExecutable); // Same for custom RUST_SRC_PATH - if(GetVisualRustProperty(env, "UseCustomSources")) - racerSourcesLocation = GetVisualRustProperty(env, "CustomSourcesPath"); + if(GetVisualRustProperty(env, nameof(RustOptionsPage.UseCustomSources))) + racerSourcesLocation = GetVisualRustProperty(env, nameof(RustOptionsPage.CustomSourcesPath)); else racerSourcesLocation = null; } diff --git a/VisualRust.Project/Properties/Resources.Designer.cs b/VisualRust/Resources.Designer.cs similarity index 59% rename from VisualRust.Project/Properties/Resources.Designer.cs rename to VisualRust/Resources.Designer.cs index f11b25b8..57caa48d 100644 --- a/VisualRust.Project/Properties/Resources.Designer.cs +++ b/VisualRust/Resources.Designer.cs @@ -1,14 +1,14 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34014 +// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ -namespace VisualRust.Project.Properties { +namespace VisualRust { using System; @@ -39,7 +39,7 @@ internal Resources() { internal static global::System.Resources.ResourceManager ResourceManager { get { if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("VisualRust.Project.Properties.Resources", typeof(Resources).Assembly); + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("VisualRust.Resources", typeof(Resources).Assembly); resourceMan = temp; } return resourceMan; @@ -60,58 +60,33 @@ internal Resources() { } } - /// - /// Looks up a localized string similar to Cannot rename crate's root module file.. - /// - internal static string ErrorRenameEntrypoint { - get { - return ResourceManager.GetString("ErrorRenameEntrypoint", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Cannot rename automatically referenced module file.. - /// - internal static string ErrorRenameReference { - get { - return ResourceManager.GetString("ErrorRenameReference", resourceCulture); - } - } - /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// - internal static System.Drawing.Bitmap IconList { + internal static System.Drawing.Bitmap CargoManifestNode { get { - object obj = ResourceManager.GetObject("IconList", resourceCulture); + object obj = ResourceManager.GetObject("CargoManifestNode", resourceCulture); return ((System.Drawing.Bitmap)(obj)); } } /// - /// Looks up a localized string similar to Import modules. - /// - internal static string TrackModules { - get { - return ResourceManager.GetString("TrackModules", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Specifies whether modules referenced by this file (eg. "mod foo;") should be automatically added to the project.. + /// Looks up a localized resource of type System.Drawing.Bitmap. /// - internal static string TrackModulesDescription { + internal static System.Drawing.Bitmap RustFileNode { get { - return ResourceManager.GetString("TrackModulesDescription", resourceCulture); + object obj = ResourceManager.GetObject("RustFileNode", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); } } /// - /// Looks up a localized string similar to Specifies whether modules referenced by this file (eg. "mod foo;") should be automatically added to the project. If you want to disable it in this file include this file in the project.. + /// Looks up a localized resource of type System.Drawing.Bitmap. /// - internal static string TrackModulesReferencedDescription { + internal static System.Drawing.Bitmap RustProjectNode { get { - return ResourceManager.GetString("TrackModulesReferencedDescription", resourceCulture); + object obj = ResourceManager.GetObject("RustProjectNode", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); } } } diff --git a/VisualRust.Project/Properties/Resources.resx b/VisualRust/Resources.resx similarity index 84% rename from VisualRust.Project/Properties/Resources.resx rename to VisualRust/Resources.resx index 41970279..cf3213e0 100644 --- a/VisualRust.Project/Properties/Resources.resx +++ b/VisualRust/Resources.resx @@ -117,23 +117,14 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - Cannot rename crate's root module file. - - - Cannot rename automatically referenced module file. - - - ..\Resources\IconList.bmp;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - Import modules + + resources\cargomanifestnode.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - Specifies whether modules referenced by this file (eg. "mod foo;") should be automatically added to the project. + + Resources\RustFileNode.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - Specifies whether modules referenced by this file (eg. "mod foo;") should be automatically added to the project. If you want to disable it in this file include this file in the project. + + Resources\RustProjectNode.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a \ No newline at end of file diff --git a/VisualRust/Resources/CargoManifestNode.png b/VisualRust/Resources/CargoManifestNode.png new file mode 100644 index 00000000..a9b63332 Binary files /dev/null and b/VisualRust/Resources/CargoManifestNode.png differ diff --git a/VisualRust/Resources/RustFileNode.png b/VisualRust/Resources/RustFileNode.png new file mode 100644 index 00000000..a259f1f6 Binary files /dev/null and b/VisualRust/Resources/RustFileNode.png differ diff --git a/VisualRust/Resources/RustProjectNode.png b/VisualRust/Resources/RustProjectNode.png new file mode 100644 index 00000000..484ff990 Binary files /dev/null and b/VisualRust/Resources/RustProjectNode.png differ diff --git a/VisualRust/Rules/Content.xaml b/VisualRust/Rules/Content.xaml new file mode 100644 index 00000000..aac12af4 --- /dev/null +++ b/VisualRust/Rules/Content.xaml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/VisualRust/Rules/Debugger.xaml b/VisualRust/Rules/Debugger.xaml new file mode 100644 index 00000000..f4ba4821 --- /dev/null +++ b/VisualRust/Rules/Debugger.xaml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + diff --git a/VisualRust/Rules/Folder.xaml b/VisualRust/Rules/Folder.xaml new file mode 100644 index 00000000..398aca28 --- /dev/null +++ b/VisualRust/Rules/Folder.xaml @@ -0,0 +1,10 @@ + + + + + + + diff --git a/VisualRust/Rules/General.xaml b/VisualRust/Rules/General.xaml new file mode 100644 index 00000000..b17996e2 --- /dev/null +++ b/VisualRust/Rules/General.xaml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/VisualRust/Rules/None.xaml b/VisualRust/Rules/None.xaml new file mode 100644 index 00000000..cfd47341 --- /dev/null +++ b/VisualRust/Rules/None.xaml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/VisualRust/Rules/ProjectItemsSchema.xaml b/VisualRust/Rules/ProjectItemsSchema.xaml new file mode 100644 index 00000000..98a70735 --- /dev/null +++ b/VisualRust/Rules/ProjectItemsSchema.xaml @@ -0,0 +1,12 @@ + + + + + + + + + \ No newline at end of file diff --git a/VisualRust/Rules/RustDebugger.xaml b/VisualRust/Rules/RustDebugger.xaml new file mode 100644 index 00000000..578240e9 --- /dev/null +++ b/VisualRust/Rules/RustDebugger.xaml @@ -0,0 +1,22 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/VisualRust/Rules/Scc.xaml b/VisualRust/Rules/Scc.xaml new file mode 100644 index 00000000..c2dd7c09 --- /dev/null +++ b/VisualRust/Rules/Scc.xaml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + diff --git a/VisualRust/RunningDocTableEventsListener.cs b/VisualRust/RunningDocTableEventsListener.cs deleted file mode 100644 index 2a70ba34..00000000 --- a/VisualRust/RunningDocTableEventsListener.cs +++ /dev/null @@ -1,86 +0,0 @@ -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.Shell.Interop; -using Microsoft.VisualStudioTools.Project.Automation; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using VisualRust.Project; - -namespace VisualRust -{ - sealed class RunningDocTableEventsListener : IVsRunningDocTableEvents, IDisposable - { - private uint cookie; - private IVsRunningDocumentTable rdt; - - public RunningDocTableEventsListener(IVsRunningDocumentTable rdt) - { - this.rdt = rdt; - rdt.AdviseRunningDocTableEvents(this, out cookie); - } - - public int OnAfterAttributeChange(uint docCookie, uint grfAttribs) - { - if (rdt != null && grfAttribs != (uint)__VSRDTATTRIB.RDTA_DocDataIsNotDirty && grfAttribs != (uint)__VSRDTATTRIB.RDTA_DocDataReloaded) - return VSConstants.S_OK; - uint docFlags; - uint readLocks; - uint writeLocks; - string docPath; - IVsHierarchy hier; - uint nodeId; - IntPtr docData; - ErrorHandler.ThrowOnFailure(rdt.GetDocumentInfo(docCookie, out docFlags, out readLocks, out writeLocks, out docPath, out hier, out nodeId, out docData)); - object projectAO; - ErrorHandler.ThrowOnFailure(hier.GetProperty((uint)VSConstants.VSITEMID_ROOT, (int)__VSHPROPID.VSHPROPID_ExtObject, out projectAO)); - OAProject project = projectAO as OAProject; - if (project == null) - return VSConstants.S_OK; - ((RustProjectNode)project.Project).OnNodeDirty(nodeId); - return VSConstants.S_OK; - } - - public int OnAfterDocumentWindowHide(uint docCookie, IVsWindowFrame pFrame) - { - return VSConstants.S_OK; - } - - public int OnAfterFirstDocumentLock(uint docCookie, uint dwRDTLockType, uint dwReadLocksRemaining, uint dwEditLocksRemaining) - { - return VSConstants.S_OK; - } - - public int OnAfterSave(uint docCookie) - { - return VSConstants.S_OK; - } - - public int OnBeforeDocumentWindowShow(uint docCookie, int fFirstShow, IVsWindowFrame pFrame) - { - return VSConstants.S_OK; - } - - public int OnBeforeLastDocumentUnlock(uint docCookie, uint dwRDTLockType, uint dwReadLocksRemaining, uint dwEditLocksRemaining) - { - return VSConstants.S_OK; - } - - public void Dispose() - { - if (rdt != null) - { - rdt.UnadviseRunningDocTableEvents(cookie); - rdt = null; - GC.SuppressFinalize(this); - } - } - - ~RunningDocTableEventsListener() - { - Dispose(); - } - } - -} diff --git a/VisualRust/RustGoToDefinitionCommandHandler.cs b/VisualRust/RustGoToDefinitionCommandHandler.cs index ba2e8976..440aae0f 100644 --- a/VisualRust/RustGoToDefinitionCommandHandler.cs +++ b/VisualRust/RustGoToDefinitionCommandHandler.cs @@ -9,7 +9,6 @@ using VisualRust.Racer; using System.Text.RegularExpressions; using Microsoft.VisualStudio.Shell; -using Microsoft.VisualStudioTools.Project; namespace VisualRust { diff --git a/VisualRust/RustLanguage.cs b/VisualRust/RustLanguage.cs index 2910f788..d3892925 100644 --- a/VisualRust/RustLanguage.cs +++ b/VisualRust/RustLanguage.cs @@ -32,6 +32,7 @@ public override LanguagePreferences GetLanguagePreferences() preferences.AutoListMembers = false; preferences.EnableQuickInfo = false; preferences.ParameterInformation = false; + preferences.InsertTabs = false; } return preferences; } diff --git a/VisualRust/VSPackage.Designer.cs b/VisualRust/VSPackage.Designer.cs index f569142d..fe532e17 100644 --- a/VisualRust/VSPackage.Designer.cs +++ b/VisualRust/VSPackage.Designer.cs @@ -1,7 +1,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.0 +// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -96,6 +96,15 @@ internal static string _114 { } } + /// + /// Looks up a localized string similar to Cargo Manifest Files;Cargo.toml. + /// + internal static string _300 { + get { + return ResourceManager.GetString("300", resourceCulture); + } + } + /// /// Looks up a localized resource of type System.Drawing.Icon similar to (Icon). /// diff --git a/VisualRust/VSPackage.resx b/VisualRust/VSPackage.resx index e80a1d17..59a36107 100644 --- a/VisualRust/VSPackage.resx +++ b/VisualRust/VSPackage.resx @@ -139,6 +139,9 @@ Debugging + + Cargo Manifest Files;Cargo.toml + Resources\Package.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a diff --git a/VisualRust/VisualRust.csproj b/VisualRust/VisualRust.csproj index 0e094b7f..7c744da6 100644 --- a/VisualRust/VisualRust.csproj +++ b/VisualRust/VisualRust.csproj @@ -4,6 +4,9 @@ 12.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) $(VisualStudioVersion) + + + @@ -19,20 +22,9 @@ VisualRust True Key.snk - v4.5 + v4.6 true - - true - bin\Debug-CI\ - TRACE;DEBUG;CONTRACTS_FULL - full - AnyCPU - prompt - false - true - true - true full @@ -56,7 +48,7 @@ false true - + ProjectTemplates\ApplicationProject.zip true @@ -71,126 +63,12 @@ - - ..\packages\Antlr4.Runtime.4.3.0\lib\net45\Antlr4.Runtime.net45.dll - false False - - ..\packages\VSSDK.CoreUtility.12.0.4\lib\net45\Microsoft.VisualStudio.CoreUtility.dll - False - - - ..\packages\VSSDK.Debugger.Interop.10.10.0.4\lib\net40\Microsoft.VisualStudio.Debugger.Interop.10.0.dll - False - - - ..\packages\VSSDK.Debugger.Interop.11.11.0.4\lib\net20\Microsoft.VisualStudio.Debugger.Interop.11.0.dll - False - - - ..\packages\VSSDK.Debugger.Interop.9.9.0.4\lib\net20\Microsoft.VisualStudio.Debugger.InteropA.dll - False - - - ..\packages\VSSDK.Editor.12.0.4\lib\net45\Microsoft.VisualStudio.Editor.dll - False - - - ..\packages\VSSDK.GraphModel.11.0.4\lib\net45\Microsoft.VisualStudio.GraphModel.dll - False - - - ..\packages\VSSDK.Language.12.0.4\lib\net45\Microsoft.VisualStudio.Language.Intellisense.dll - False - - - ..\packages\VSSDK.Language.12.0.4\lib\net45\Microsoft.VisualStudio.Language.StandardClassification.dll - False - - - ..\packages\VSSDK.OLE.Interop.7.0.4\lib\net20\Microsoft.VisualStudio.OLE.Interop.dll - False - - - ..\packages\VSSDK.LanguageService.12.12.0.4\lib\net45\Microsoft.VisualStudio.Package.LanguageService.12.0.dll - False - - - ..\packages\VSSDK.Shell.12.12.0.4\lib\net45\Microsoft.VisualStudio.Shell.12.0.dll - False - - - ..\packages\VSSDK.Shell.Immutable.10.10.0.4\lib\net40\Microsoft.VisualStudio.Shell.Immutable.10.0.dll - False - - - ..\packages\VSSDK.Shell.Immutable.11.11.0.4\lib\net45\Microsoft.VisualStudio.Shell.Immutable.11.0.dll - False - - - ..\packages\VSSDK.Shell.Immutable.12.12.0.4\lib\net45\Microsoft.VisualStudio.Shell.Immutable.12.0.dll - False - - - ..\packages\VSSDK.Shell.Interop.7.0.4\lib\net20\Microsoft.VisualStudio.Shell.Interop.dll - False - - - False - ..\packages\VSSDK.Shell.Interop.10.10.0.4\lib\net20\Microsoft.VisualStudio.Shell.Interop.10.0.dll - False - - - False - ..\packages\VSSDK.Shell.Interop.11.11.0.4\lib\net20\Microsoft.VisualStudio.Shell.Interop.11.0.dll - False - - - ..\packages\VSSDK.Shell.Interop.8.8.0.4\lib\net20\Microsoft.VisualStudio.Shell.Interop.8.0.dll - False - - - ..\packages\VSSDK.Shell.Interop.9.9.0.4\lib\net20\Microsoft.VisualStudio.Shell.Interop.9.0.dll - False - - - ..\packages\VSSDK.Text.12.0.4\lib\net45\Microsoft.VisualStudio.Text.Data.dll - False - - - ..\packages\VSSDK.Text.12.0.4\lib\net45\Microsoft.VisualStudio.Text.Logic.dll - False - - - ..\packages\VSSDK.Text.12.0.4\lib\net45\Microsoft.VisualStudio.Text.UI.dll - False - - - ..\packages\VSSDK.Text.12.0.4\lib\net45\Microsoft.VisualStudio.Text.UI.Wpf.dll - False - - - ..\packages\VSSDK.TextManager.Interop.7.0.4\lib\net20\Microsoft.VisualStudio.TextManager.Interop.dll - False - - - ..\packages\VSSDK.TextManager.Interop.8.8.0.4\lib\net20\Microsoft.VisualStudio.TextManager.Interop.8.0.dll - False - - - ..\packages\VSSDK.Threading.12.0.4\lib\net45\Microsoft.VisualStudio.Threading.dll - False - - - False - ..\packages\VSSDK.DTE.7.0.4\lib\net20\stdole.dll - False - @@ -198,6 +76,7 @@ + @@ -215,9 +94,13 @@ - - - + + + + + + + Component @@ -227,24 +110,30 @@ DebuggingOptionsPageControl.cs - - - UserControl RustOptionsPageControl.cs - + Component + + + - + + True + True + Resources.resx + + + @@ -278,6 +167,7 @@ True VSPackage.resx + @@ -286,6 +176,10 @@ RustOptionsPageControl.cs + + ResXFileCodeGenerator + Resources.Designer.cs + true VSPackage @@ -295,7 +189,7 @@ - + @@ -315,41 +209,72 @@ PreserveNewest true + + + Menus.ctmenu - - {cacb60a9-1e76-4f92-8831-b134a658c695} - Microsoft.VisualStudio.Project + + {5da4c00b-9f16-4ef9-894d-20329544265e} + Microsoft.Common.Core + + + {b8696d0c-8adb-4c11-8cee-5c81aa8c6ebd} + VisualRust.ProjectSystem.FileSystemMirroring {12cc862d-95b7-4224-8e16-b928c6333677} MICore - {6D2688FE-6FD8-44A8-B96A-6037457F72A7} + {6d2688fe-6fd8-44a8-b96a-6037457f72a7} MIDebugEngine {e983e989-f83a-4643-896a-ad496bf647d0} RustLexer - - {2594DB0D-03FF-40EA-8D27-9930E5D3FF83} - VisualRust.Cargo + + {B99CC9EB-90F2-4040-9E66-418CC7042153} + VisualRust.Shared {59D94B96-1AF7-46F2-8790-AAB6DFAE8D9A} VisualRust.Templates false - - {475c4df2-4d4b-4f2c-9f27-414148dd6f11} - VisualRust.Project - + + + + Designer + + + Designer + + + Designer + + + Designer + + + Designer + + + Designer + + + Designer + + + + + Designer + true @@ -365,11 +290,7 @@ - - <_VsixmanifestConfiguration Condition=" '$(Configuration)' == 'Debug-CI' ">Debug - <_VsixmanifestConfiguration Condition=" '$(_VsixmanifestConfiguration)' == '' ">$(Configuration) - - + @@ -378,10 +299,9 @@ - - + - + \ No newline at end of file diff --git a/VisualRust/VisualRust.nuget.targets b/VisualRust/VisualRust.nuget.targets new file mode 100644 index 00000000..109a01e9 --- /dev/null +++ b/VisualRust/VisualRust.nuget.targets @@ -0,0 +1,11 @@ + + + + $(UserProfile)\.nuget\packages\ + + + + + + + \ No newline at end of file diff --git a/VisualRust/VisualRustAutoIndent.cs b/VisualRust/VisualRustAutoIndent.cs index d6ba728f..026ad93f 100644 --- a/VisualRust/VisualRustAutoIndent.cs +++ b/VisualRust/VisualRustAutoIndent.cs @@ -19,16 +19,16 @@ namespace VisualRust [Name("Auto indent controller")] [ContentType("rust")] [TextViewRole(PredefinedTextViewRoles.Editable)] - public class VisaulRustAutoindentProvider : IVsTextViewCreationListener + public class VisualRustAutoIndentProvider : IVsTextViewCreationListener { [Import] - internal IVsEditorAdaptersFactoryService AdaptersService; + internal IVsEditorAdaptersFactoryService AdaptersService { get; set; } [Import] - internal IEditorOperationsFactoryService OperationsService; + internal IEditorOperationsFactoryService OperationsService { get; set; } [Import] - internal ITextUndoHistoryRegistry UndoHistoryRegistry; + internal ITextUndoHistoryRegistry UndoHistoryRegistry { get; set; } public void VsTextViewCreated(IVsTextView textViewAdapter) { diff --git a/VisualRust/VisualRustPackage.cs b/VisualRust/VisualRustPackage.cs index 910f44df..fce43ea2 100644 --- a/VisualRust/VisualRustPackage.cs +++ b/VisualRust/VisualRustPackage.cs @@ -12,11 +12,12 @@ using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Utilities; using Microsoft.VisualStudio.Text.Editor; -using VisualRust.Project; -using Microsoft.VisualStudioTools.Project; -using Microsoft.VisualStudioTools.Project.Automation; using VisualRust.Options; using MICore; +using VisualRust.ProjectSystem.FileSystemMirroring.Package.Registration; +using VisualRust.ProjectSystem.FileSystemMirroring.Shell; +using System.Collections.Generic; +using VisualRust.ProjectSystem; namespace VisualRust { @@ -35,7 +36,7 @@ namespace VisualRust [PackageRegistration(UseManagedResourcesOnly = true)] // This attribute is used to register the information needed to show this package // in the Help/About dialog of Visual Studio. - [InstalledProductRegistration("#110", "#112", "0.1.2", IconResourceID = 400)] + [InstalledProductRegistration("#110", "#112", "0.2.0", IconResourceID = 400)] [ProvideLanguageService(typeof(RustLanguage), "Rust", 100, CodeSense = true, DefaultToInsertSpaces = true, @@ -51,32 +52,26 @@ namespace VisualRust EnableFormatSelection = true, SupportCopyPasteOfHTML = false )] - [ProvideProjectFactory( - typeof(RustProjectFactory), - "Rust", - "Rust Project Files (*.rsproj);*.rsproj", - "rsproj", - "rsproj", - ".\\NullPath", - LanguageVsTemplate="Rust")] [ProvideLanguageExtension(typeof(RustLanguage), ".rs")] [Guid(GuidList.guidVisualRustPkgString)] - [ProvideObject(typeof(Project.Forms.ApplicationPropertyPage))] - [ProvideObject(typeof(Project.Forms.BuildPropertyPage))] - [ProvideObject(typeof(Project.Forms.DebugPropertyPage))] - [ProvideObject(typeof(Project.Forms.TargetOutputsPropertyPage))] [ProvideOptionPage(typeof(RustOptionsPage), "Visual Rust", "General", 110, 113, true)] [ProvideOptionPage(typeof(DebuggingOptionsPage), "Visual Rust", "Debugging", 110, 114, true)] [ProvideProfile(typeof(RustOptionsPage), "Visual Rust", "General", 110, 113, true)] [ProvideDebugEngine("Rust GDB", typeof(AD7ProgramProvider), typeof(AD7Engine), EngineConstants.EngineId)] [ProvideMenuResource("Menus.ctmenu", 1)] - public class VisualRustPackage : CommonProjectPackage, IOleCommandTarget + [ProvideCpsProjectFactory(GuidList.CpsProjectFactoryGuidString, "Rust", "rsproj")] + [ProvideProjectFileGenerator(typeof(RustProjectFileGenerator), GuidList.CpsProjectFactoryGuidString, FileNames = "Cargo.toml", DisplayGeneratorFilter = 300)] + // TODO: not sure what DeveloperActivity actually does + [DeveloperActivity("Rust", GuidList.guidVisualRustPkgString, sortPriority: 40)] + public class VisualRustPackage : Package, IOleCommandTarget { - private RunningDocTableEventsListener docEventsListener; private IOleCommandTarget packageCommandTarget; + private Dictionary _projectFileGenerators; internal static VisualRustPackage Instance { get; private set; } + public const string UniqueCapability = "VisualRust"; + /// /// Default constructor of the package. /// Inside this method you can place any initialization code that does not require @@ -87,7 +82,7 @@ public class VisualRustPackage : CommonProjectPackage, IOleCommandTarget public VisualRustPackage() { Debug.WriteLine(string.Format(CultureInfo.CurrentCulture, "Entering constructor for: {0}", this.ToString())); - Microsoft.VisualStudioTools.UIThread.InitializeAndAlwaysInvokeToCurrentThread(); + //Microsoft.VisualStudioTools.UIThread.InitializeAndAlwaysInvokeToCurrentThread(); } ///////////////////////////////////////////////////////////////////////////// @@ -101,14 +96,63 @@ public VisualRustPackage() protected override void Initialize() { base.Initialize(); + + RegisterProjectFileGenerator(new RustProjectFileGenerator()); + + ProjectIconProvider.LoadProjectImages(); + packageCommandTarget = GetService(typeof(IOleCommandTarget)) as IOleCommandTarget; Instance = this; - docEventsListener = new RunningDocTableEventsListener((IVsRunningDocumentTable)GetService(typeof(SVsRunningDocumentTable))); - Racer.RacerSingleton.Init(); } + private void RegisterProjectFileGenerator(IVsProjectGenerator projectFileGenerator) + { + var registerProjectGenerators = GetService(typeof(SVsRegisterProjectTypes)) as IVsRegisterProjectGenerators; + if (registerProjectGenerators == null) + { + throw new InvalidOperationException(typeof(SVsRegisterProjectTypes).FullName); + } + + uint cookie; + Guid riid = projectFileGenerator.GetType().GUID; + registerProjectGenerators.RegisterProjectGenerator(ref riid, projectFileGenerator, out cookie); + + if (_projectFileGenerators == null) + { + _projectFileGenerators = new Dictionary(); + } + + _projectFileGenerators[projectFileGenerator] = cookie; + } + + private void UnregisterProjectFileGenerators(Dictionary projectFileGenerators) + { + try + { + IVsRegisterProjectGenerators registerProjectGenerators = GetService(typeof(SVsRegisterProjectTypes)) as IVsRegisterProjectGenerators; + if (registerProjectGenerators != null) + { + foreach (var projectFileGenerator in projectFileGenerators) + { + try + { + registerProjectGenerators.UnregisterProjectGenerator(projectFileGenerator.Value); + } + finally + { + (projectFileGenerator.Key as IDisposable)?.Dispose(); + } + } + } + } + catch (Exception e) + { + Debug.Fail(String.Format(CultureInfo.InvariantCulture, "Failed to dispose project file generator for package {0}\n{1}", GetType().FullName, e.Message)); + } + } + int IOleCommandTarget.Exec(ref Guid cmdGroup, uint nCmdID, uint nCmdExecOpt, IntPtr pvaIn, IntPtr pvaOut) { if (cmdGroup == GuidList.VisualRustCommandSet) @@ -244,45 +288,24 @@ static private int EnsureString(IntPtr pvaIn, out string arguments) protected override void Dispose(bool disposing) { - docEventsListener.Dispose(); - base.Dispose(disposing); - } - - #endregion - - public override ProjectFactory CreateProjectFactory() - { - return new RustProjectFactory(this); - } - - public override CommonEditorFactory CreateEditorFactory() - { - return null; - } - - public override uint GetIconIdForAboutBox() - { - throw new NotImplementedException(); - } + ProjectIconProvider.Close(); - public override uint GetIconIdForSplashScreen() - { - throw new NotImplementedException(); - } + if (!disposing) + { + base.Dispose(false); + return; + } - public override string GetProductName() - { - return "Visual Rust"; - } + if (_projectFileGenerators != null) + { + var projectFileGenerators = _projectFileGenerators; + _projectFileGenerators = null; + UnregisterProjectFileGenerators(projectFileGenerators); + } - public override string GetProductDescription() - { - return "Visual Studio integration for the Rust programming language (http://www.rust-lang.org/)"; + base.Dispose(true); } - public override string GetProductVersion() - { - return "0.1.2"; - } + #endregion } } diff --git a/Microsoft.VisualStudio.Project/VSShellUtilities.cs b/VisualRust/VsUtilities.cs similarity index 63% rename from Microsoft.VisualStudio.Project/VSShellUtilities.cs rename to VisualRust/VsUtilities.cs index 0e657668..c6847955 100644 --- a/Microsoft.VisualStudio.Project/VSShellUtilities.cs +++ b/VisualRust/VsUtilities.cs @@ -1,4 +1,4 @@ -//*********************************************************// +//*********************************************************// // Copyright (c) Microsoft. All rights reserved. // // Apache 2.0 License @@ -21,49 +21,21 @@ using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio.TextManager.Interop; -namespace Microsoft.VisualStudioTools.Project { - /// - ///This class provides some useful static shell based methods. - /// - - internal static class UIHierarchyUtilities { - /// - /// Get reference to IVsUIHierarchyWindow interface from guid persistence slot. - /// - /// The service provider. - /// Unique identifier for a tool window created using IVsUIShell::CreateToolWindow. - /// The caller of this method can use predefined identifiers that map to tool windows if those tool windows - /// are known to the caller. - /// A reference to an IVsUIHierarchyWindow interface. - public static IVsUIHierarchyWindow GetUIHierarchyWindow(IServiceProvider serviceProvider, Guid persistenceSlot) { - if (serviceProvider == null) { - throw new ArgumentNullException("serviceProvider"); - } - - IVsUIShell shell = serviceProvider.GetService(typeof(SVsUIShell)) as IVsUIShell; - if (shell == null) { - throw new InvalidOperationException("Could not get the UI shell from the project"); - } - - object pvar; - IVsWindowFrame frame; - - if (ErrorHandler.Succeeded(shell.FindToolWindow(0, ref persistenceSlot, out frame)) && - ErrorHandler.Succeeded(frame.GetProperty((int)__VSFPROPID.VSFPROPID_DocView, out pvar))) { - return pvar as IVsUIHierarchyWindow; - } - - return null; - } - } - - internal static class VsUtilities { - internal static void NavigateTo(IServiceProvider serviceProvider, string filename, Guid docViewGuidType, int line, int col) { +namespace VisualRust +{ + // This is copied from Microsoft.VisualStudioTools.Project (the old project system aka MPFProj) + internal static class VsUtilities + { + internal static void NavigateTo(IServiceProvider serviceProvider, string filename, Guid docViewGuidType, int line, int col) + { IVsTextView viewAdapter; IVsWindowFrame pWindowFrame; - if (docViewGuidType != Guid.Empty) { + if (docViewGuidType != Guid.Empty) + { OpenDocument(serviceProvider, filename, docViewGuidType, out viewAdapter, out pWindowFrame); - } else { + } + else + { OpenDocument(serviceProvider, filename, out viewAdapter, out pWindowFrame); } @@ -75,12 +47,16 @@ internal static void NavigateTo(IServiceProvider serviceProvider, string filenam viewAdapter.CenterLines(line, 1); } - internal static void NavigateTo(IServiceProvider serviceProvider, string filename, Guid docViewGuidType, int pos) { + internal static void NavigateTo(IServiceProvider serviceProvider, string filename, Guid docViewGuidType, int pos) + { IVsTextView viewAdapter; IVsWindowFrame pWindowFrame; - if (docViewGuidType != Guid.Empty) { + if (docViewGuidType != Guid.Empty) + { OpenDocument(serviceProvider, filename, docViewGuidType, out viewAdapter, out pWindowFrame); - } else { + } + else + { OpenDocument(serviceProvider, filename, out viewAdapter, out pWindowFrame); } @@ -92,7 +68,8 @@ internal static void NavigateTo(IServiceProvider serviceProvider, string filenam viewAdapter.CenterLines(line, 1); } - internal static void OpenDocument(IServiceProvider serviceProvider, string filename, out IVsTextView viewAdapter, out IVsWindowFrame pWindowFrame) { + internal static void OpenDocument(IServiceProvider serviceProvider, string filename, out IVsTextView viewAdapter, out IVsWindowFrame pWindowFrame) + { IVsTextManager textMgr = (IVsTextManager)serviceProvider.GetService(typeof(SVsTextManager)); IVsUIHierarchy hierarchy; @@ -107,7 +84,8 @@ internal static void OpenDocument(IServiceProvider serviceProvider, string filen out viewAdapter); } - internal static void OpenDocument(IServiceProvider serviceProvider, string filename, Guid docViewGuid, out IVsTextView viewAdapter, out IVsWindowFrame pWindowFrame) { + internal static void OpenDocument(IServiceProvider serviceProvider, string filename, Guid docViewGuid, out IVsTextView viewAdapter, out IVsWindowFrame pWindowFrame) + { IVsUIHierarchy hierarchy; uint itemid; VsShellUtilities.OpenDocumentWithSpecificEditor( diff --git a/VisualRust/app.config b/VisualRust/app.config index 4a1c0bf1..af64d8ed 100644 --- a/VisualRust/app.config +++ b/VisualRust/app.config @@ -6,6 +6,10 @@ + + + + - \ No newline at end of file + diff --git a/VisualRust/packages.config b/VisualRust/packages.config deleted file mode 100644 index 620872bd..00000000 --- a/VisualRust/packages.config +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/VisualRust/project.json b/VisualRust/project.json new file mode 100644 index 00000000..a60ce858 --- /dev/null +++ b/VisualRust/project.json @@ -0,0 +1,35 @@ +{ + "dependencies": { + "Antlr4.Runtime": "4.3.0", + "Microsoft.Composition": "1.0.27", + "Microsoft.Tpl.Dataflow": "4.5.24", + "Microsoft.Build": "14.3.0", + "Microsoft.VisualStudio.Editor": "14.1.24720", + "Microsoft.VisualStudio.ImageCatalog": "14.1.24720", + "Microsoft.VisualStudio.Imaging": "14.1.24720", + "Microsoft.VisualStudio.Imaging.Interop.14.0.DesignTime": "14.1.24720", + "Microsoft.VisualStudio.Language.Intellisense": "14.1.24720", + "Microsoft.VisualStudio.Language.StandardClassification": "14.1.24720", + "Microsoft.VisualStudio.OLE.Interop": "7.10.6070", + "Microsoft.VisualStudio.Package.LanguageService.14.0": "14.1.24720", + "Microsoft.VisualStudio.ProjectSystem": "14.1.127-pre", + "Microsoft.VisualStudio.ProjectSystem.SDK.Tools": "14.1.127-pre", + "Microsoft.VisualStudio.SDK.EmbedInteropTypes": "14.1.3", + "Microsoft.VisualStudio.SDK.VsixSuppression": "14.1.29", + "Microsoft.VisualStudio.Shell.14.0": "14.1.24720", + "Microsoft.VisualStudio.Shell.Interop": "7.10.6071", + "Microsoft.VisualStudio.Shell.Interop.12.0": "12.0.30110", + "Microsoft.VisualStudio.Shell.Interop.14.0.DesignTime": "14.1.24720", + "Microsoft.VisualStudio.Text.Data": "14.1.24720", + "Microsoft.VisualStudio.TextManager.Interop": "7.10.6070", + "Microsoft.VisualStudio.Threading": "14.1.131", + "Microsoft.VisualStudio.Validation": "14.1.111", + "Newtonsoft.Json": "9.0.1" + }, + "frameworks": { + "net46": {} + }, + "runtimes": { + "win": {} + } +} \ No newline at end of file diff --git a/VisualRust/source.extension.debug.vsixmanifest b/VisualRust/source.extension.debug.vsixmanifest index ddfbd6bc..4de00243 100644 --- a/VisualRust/source.extension.debug.vsixmanifest +++ b/VisualRust/source.extension.debug.vsixmanifest @@ -1,16 +1,18 @@  - + Visual Rust Visual Studio integration for the Rust programming language (http://www.rust-lang.org/) LICENSE.txt - + + + - + @@ -18,5 +20,6 @@ + diff --git a/VisualRust/source.extension.release.vsixmanifest b/VisualRust/source.extension.release.vsixmanifest index 59cbd3ec..93f9c598 100644 --- a/VisualRust/source.extension.release.vsixmanifest +++ b/VisualRust/source.extension.release.vsixmanifest @@ -1,16 +1,18 @@  - + Visual Rust Visual Studio integration for the Rust programming language (http://www.rust-lang.org/) LICENSE.txt - + + + - + diff --git a/VisualRust/source.extension.vsixmanifest b/VisualRust/source.extension.vsixmanifest deleted file mode 100644 index 6bf12172..00000000 --- a/VisualRust/source.extension.vsixmanifest +++ /dev/null @@ -1,18 +0,0 @@ - - - - - VisualRust - Visual Studio integration for the Rust programming language (http://www.rust-lang.org/) - LICENSE.txt - - - - - - - - - - -