diff --git a/src/InteractiveWindow/EditorTest/InteractiveWindowEditorsFactoryService.cs b/src/InteractiveWindow/EditorTest/InteractiveWindowEditorsFactoryService.cs
new file mode 100644
index 0000000000000000000000000000000000000000..17dbfe73bb7aba5baa8b7f702e7c5fe48f3abeb4
--- /dev/null
+++ b/src/InteractiveWindow/EditorTest/InteractiveWindowEditorsFactoryService.cs
@@ -0,0 +1,35 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.ComponentModel.Composition;
+using Microsoft.VisualStudio.Text;
+using Microsoft.VisualStudio.Text.Editor;
+using Microsoft.VisualStudio.Utilities;
+using Roslyn.Editor.InteractiveWindow;
+
+namespace Roslyn.InteractiveWindow.UnitTests
+{
+ [Export(typeof(IInteractiveWindowEditorFactoryService))]
+ internal class InteractiveWindowEditorsFactoryService : IInteractiveWindowEditorFactoryService
+ {
+ private readonly ITextBufferFactoryService _textBufferFactoryService;
+ private readonly ITextEditorFactoryService _textEditorFactoryService;
+
+ [ImportingConstructor]
+ public InteractiveWindowEditorsFactoryService(ITextBufferFactoryService textBufferFactoryService, ITextEditorFactoryService textEditorFactoryService)
+ {
+ _textBufferFactoryService = textBufferFactoryService;
+ _textEditorFactoryService = textEditorFactoryService;
+ }
+
+ IWpfTextView IInteractiveWindowEditorFactoryService.CreateTextView(IInteractiveWindow window, ITextBuffer buffer, ITextViewRoleSet roles)
+ {
+ var textView = _textEditorFactoryService.CreateTextView(buffer, roles);
+ return _textEditorFactoryService.CreateTextViewHost(textView, false).TextView;
+ }
+
+ ITextBuffer IInteractiveWindowEditorFactoryService.CreateAndActivateBuffer(IInteractiveWindow window, IContentType contentType)
+ {
+ return _textBufferFactoryService.CreateTextBuffer(contentType);
+ }
+ }
+}
diff --git a/src/InteractiveWindow/EditorTest/InteractiveWindowTest.csproj b/src/InteractiveWindow/EditorTest/InteractiveWindowTest.csproj
new file mode 100644
index 0000000000000000000000000000000000000000..0d7a5fe80d9093be31f92335c92819e784bc2ee4
--- /dev/null
+++ b/src/InteractiveWindow/EditorTest/InteractiveWindowTest.csproj
@@ -0,0 +1,94 @@
+
+
+
+
+
+
+
+ true
+ Debug
+ x86
+ {7F3CB45E-4993-4FA4-8D6A-C2DFFED2DFC3}
+ Library
+ Roslyn.InteractiveWindow.UnitTests
+ Roslyn.InteractiveWindow.UnitTests
+ x86
+ ..\..\..\
+ true
+
+
+
+
+
+
+
+
+ {01E9BD68-0339-4A13-B42F-A3CA84D164F3}
+ InteractiveWindow
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $(DevEnvDir)\PrivateAssemblies\Microsft.VisualStudio.Platform.VSEditor.Interop.dll
+
+
+
+ False
+ ..\..\..\packages\System.Collections.Immutable.1.1.33-beta\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll
+
+
+
+
+
+
+ ..\..\..\packages\xunit.1.9.2\lib\net20\xunit.dll
+
+
+ False
+ ..\..\..\packages\BasicUndo.0.9.2\lib\net45\BasicUndo.dll
+
+
+
+
+ AssertEx.cs
+
+
+ DiffUtil.cs
+
+
+ WaitHelper.cs
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/InteractiveWindow/EditorTest/InteractiveWindowTestHost.cs b/src/InteractiveWindow/EditorTest/InteractiveWindowTestHost.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a8c4f3bd0d7ee76e6e850e55e1313d41421019f0
--- /dev/null
+++ b/src/InteractiveWindow/EditorTest/InteractiveWindowTestHost.cs
@@ -0,0 +1,102 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.ComponentModel.Composition.Hosting;
+using System.Linq;
+using System.Reflection;
+using System.Threading;
+using System.Windows.Threading;
+using Microsoft.VisualStudio.Language.Intellisense.Utilities;
+using Microsoft.VisualStudio.Text;
+using Microsoft.VisualStudio.Text.Editor;
+using Microsoft.VisualStudio.Utilities;
+using Roslyn.Test.Utilities;
+
+namespace Roslyn.Editor.InteractiveWindow.UnitTests
+{
+ public class InteractiveWindowTestHost : IDisposable
+ {
+ private readonly IInteractiveWindow _window;
+ private readonly CompositionContainer _exportProvider;
+
+ public InteractiveWindowTestHost()
+ {
+ SynchronizationContext.SetSynchronizationContext(new DispatcherSynchronizationContext());
+
+ var types = new[] { typeof(TestInteractiveEngine), typeof(InteractiveWindow) }.Concat(GetVisualStudioTypes());
+ _exportProvider = new CompositionContainer(
+ new AggregateCatalog(types.Select(t => new AssemblyCatalog(t.Assembly))),
+ CompositionOptions.DisableSilentRejection | CompositionOptions.IsThreadSafe);
+
+ var contentTypeRegistryService = _exportProvider.GetExport().Value;
+ _window = _exportProvider.GetExport().Value.CreateWindow(new TestInteractiveEngine(contentTypeRegistryService));
+
+ _window.InitializeAsync().PumpingWait();
+ }
+
+ public CompositionContainer ExportProvider
+ {
+ get
+ {
+ return _exportProvider;
+ }
+ }
+
+ public static Type[] GetVisualStudioTypes()
+ {
+ var types = new[]
+ {
+ // EDITOR
+
+ // Microsoft.VisualStudio.Platform.VSEditor.dll:
+ typeof(Microsoft.VisualStudio.Platform.VSEditor.EventArgsHelper),
+
+ // Microsoft.VisualStudio.Text.Logic.dll:
+ // Must include this because several editor options are actually stored as exported information
+ // on this DLL. Including most importantly, the tab size information.
+ typeof(Microsoft.VisualStudio.Text.Editor.DefaultOptions),
+
+ // Microsoft.VisualStudio.Text.UI.dll:
+ // Include this DLL to get several more EditorOptions including WordWrapStyle.
+ typeof(Microsoft.VisualStudio.Text.Editor.WordWrapStyle),
+
+ // Microsoft.VisualStudio.Text.UI.Wpf.dll:
+ // Include this DLL to get more EditorOptions values.
+ typeof(Microsoft.VisualStudio.Text.Editor.HighlightCurrentLineOption),
+
+ // BasicUndo.dll:
+ // Include this DLL to satisfy ITextUndoHistoryRegistry
+ typeof(BasicUndo.IBasicUndoHistory),
+
+ // Microsoft.VisualStudio.Language.StandardClassification.dll:
+ typeof(Microsoft.VisualStudio.Language.StandardClassification.PredefinedClassificationTypeNames)
+ };
+
+ return types;
+ }
+
+ internal IInteractiveWindow Window
+ {
+ get
+ {
+ return _window;
+ }
+ }
+
+ public void Dispose()
+ {
+ if (_window != null)
+ {
+ // close interactive host process:
+ var engine = _window.Evaluator;
+ if (engine != null)
+ {
+ engine.Dispose();
+ }
+
+ // dispose buffer:
+ _window.Dispose();
+ }
+ }
+ }
+}
diff --git a/src/InteractiveWindow/EditorTest/InteractiveWindowTests.cs b/src/InteractiveWindow/EditorTest/InteractiveWindowTests.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f21f6250c1e8939cb0fe015931c0f65672a806da
--- /dev/null
+++ b/src/InteractiveWindow/EditorTest/InteractiveWindowTests.cs
@@ -0,0 +1,174 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Microsoft.VisualStudio.Text;
+using Moq;
+using Roslyn.Editor.InteractiveWindow.Commands;
+using Roslyn.Test.Utilities;
+using Xunit;
+
+namespace Roslyn.Editor.InteractiveWindow.UnitTests
+{
+ public class InteractiveWindowTests : IDisposable
+ {
+ #region Helpers
+
+ private InteractiveWindowTestHost _testHost;
+
+ public InteractiveWindowTests()
+ {
+ _testHost = new InteractiveWindowTestHost();
+ }
+
+ public void Dispose()
+ {
+ _testHost.Dispose();
+ }
+
+ public IInteractiveWindow Window
+ {
+ get
+ {
+ return _testHost.Window;
+ }
+ }
+
+ public static IEnumerable MockCommands(params string[] commandNames)
+ {
+ foreach (var name in commandNames)
+ {
+ var mock = new Mock();
+ mock.Setup(m => m.Name).Returns(name);
+ yield return mock.Object;
+ }
+ }
+
+ public static ITextSnapshot MockSnapshot(string content)
+ {
+ var snapshotMock = new Mock();
+ snapshotMock.Setup(m => m[It.IsAny()]).Returns(index => content[index]);
+ snapshotMock.Setup(m => m.Length).Returns(content.Length);
+ snapshotMock.Setup(m => m.GetText()).Returns(content);
+ snapshotMock.Setup(m => m.GetText(It.IsAny(), It.IsAny())).Returns((start, length) => content.Substring(start, length));
+ snapshotMock.Setup(m => m.GetText(It.IsAny())).Returns(span => content.Substring(span.Start, span.Length));
+ return snapshotMock.Object;
+ }
+
+ #endregion
+
+ [Fact]
+ public void InteractiveWindow__CommandParsing()
+ {
+ var commandList = MockCommands("foo", "bar", "bz", "command1").ToArray();
+ var commands = new Commands.Commands(null, "%", commandList);
+ AssertEx.Equal(commands.GetCommands(), commandList);
+
+ var cmdBar = commandList[1];
+ Assert.Equal("bar", cmdBar.Name);
+
+ Assert.Equal("%", commands.CommandPrefix);
+ commands.CommandPrefix = "#";
+ Assert.Equal("#", commands.CommandPrefix);
+
+ //// 111111
+ //// 0123456789012345
+ var s1 = MockSnapshot("#bar arg1 arg2 ");
+
+ SnapshotSpan prefixSpan, commandSpan, argsSpan;
+ IInteractiveWindowCommand cmd;
+
+ cmd = commands.TryParseCommand(new SnapshotSpan(s1, Span.FromBounds(0, 0)), out prefixSpan, out commandSpan, out argsSpan);
+ Assert.Null(cmd);
+
+ cmd = commands.TryParseCommand(new SnapshotSpan(s1, Span.FromBounds(0, 1)), out prefixSpan, out commandSpan, out argsSpan);
+ Assert.Null(cmd);
+
+ cmd = commands.TryParseCommand(new SnapshotSpan(s1, Span.FromBounds(0, 2)), out prefixSpan, out commandSpan, out argsSpan);
+ Assert.Null(cmd);
+ Assert.Equal(0, prefixSpan.Start);
+ Assert.Equal(1, prefixSpan.End);
+ Assert.Equal(1, commandSpan.Start);
+ Assert.Equal(2, commandSpan.End);
+ Assert.Equal(2, argsSpan.Start);
+ Assert.Equal(2, argsSpan.End);
+
+ cmd = commands.TryParseCommand(new SnapshotSpan(s1, Span.FromBounds(0, 3)), out prefixSpan, out commandSpan, out argsSpan);
+ Assert.Null(cmd);
+ Assert.Equal(0, prefixSpan.Start);
+ Assert.Equal(1, prefixSpan.End);
+ Assert.Equal(1, commandSpan.Start);
+ Assert.Equal(3, commandSpan.End);
+ Assert.Equal(3, argsSpan.Start);
+ Assert.Equal(3, argsSpan.End);
+
+ cmd = commands.TryParseCommand(new SnapshotSpan(s1, Span.FromBounds(0, 4)), out prefixSpan, out commandSpan, out argsSpan);
+ Assert.Equal(cmdBar, cmd);
+ Assert.Equal(0, prefixSpan.Start);
+ Assert.Equal(1, prefixSpan.End);
+ Assert.Equal(1, commandSpan.Start);
+ Assert.Equal(4, commandSpan.End);
+ Assert.Equal(4, argsSpan.Start);
+ Assert.Equal(4, argsSpan.End);
+
+ cmd = commands.TryParseCommand(new SnapshotSpan(s1, Span.FromBounds(0, 5)), out prefixSpan, out commandSpan, out argsSpan);
+ Assert.Equal(cmdBar, cmd);
+ Assert.Equal(0, prefixSpan.Start);
+ Assert.Equal(1, prefixSpan.End);
+ Assert.Equal(1, commandSpan.Start);
+ Assert.Equal(4, commandSpan.End);
+ Assert.Equal(5, argsSpan.Start);
+ Assert.Equal(5, argsSpan.End);
+
+ cmd = commands.TryParseCommand(s1.GetExtent(), out prefixSpan, out commandSpan, out argsSpan);
+ Assert.Equal(cmdBar, cmd);
+ Assert.Equal(0, prefixSpan.Start);
+ Assert.Equal(1, prefixSpan.End);
+ Assert.Equal(1, commandSpan.Start);
+ Assert.Equal(4, commandSpan.End);
+ Assert.Equal(5, argsSpan.Start);
+ Assert.Equal(14, argsSpan.End);
+
+ ////
+ //// 0123456789
+ var s2 = MockSnapshot(" #bar ");
+ cmd = commands.TryParseCommand(s2.GetExtent(), out prefixSpan, out commandSpan, out argsSpan);
+ Assert.Equal(cmdBar, cmd);
+ Assert.Equal(2, prefixSpan.Start);
+ Assert.Equal(3, prefixSpan.End);
+ Assert.Equal(3, commandSpan.Start);
+ Assert.Equal(6, commandSpan.End);
+ Assert.Equal(9, argsSpan.Start);
+ Assert.Equal(9, argsSpan.End);
+
+ //// 111111
+ //// 0123456789012345
+ var s3 = MockSnapshot(" # bar args");
+ cmd = commands.TryParseCommand(s3.GetExtent(), out prefixSpan, out commandSpan, out argsSpan);
+ Assert.Equal(cmdBar, cmd);
+ Assert.Equal(2, prefixSpan.Start);
+ Assert.Equal(3, prefixSpan.End);
+ Assert.Equal(6, commandSpan.Start);
+ Assert.Equal(9, commandSpan.End);
+ Assert.Equal(11, argsSpan.Start);
+ Assert.Equal(15, argsSpan.End);
+ }
+
+ [Fact]
+ public void InteractiveWindow_GetCommands()
+ {
+ var interactiveCommands = new InteractiveCommandsFactory(null, null).CreateInteractiveCommands(
+ Window,
+ "#",
+ _testHost.ExportProvider.GetExports().Select(x => x.Value).ToArray());
+
+ var commands = interactiveCommands.GetCommands();
+
+ Assert.NotEmpty(commands);
+ Assert.NotNull(commands.Where(n => n.Name == "cls").SingleOrDefault());
+ Assert.NotNull(commands.Where(n => n.Name == "help").SingleOrDefault());
+ Assert.NotNull(commands.Where(n => n.Name == "reset").SingleOrDefault());
+ }
+ }
+}
diff --git a/src/InteractiveWindow/EditorTest/TestContentTypeDefinition.cs b/src/InteractiveWindow/EditorTest/TestContentTypeDefinition.cs
new file mode 100644
index 0000000000000000000000000000000000000000..087b31e3b23a3e2d2a8818c0132f4920c0cbe276
--- /dev/null
+++ b/src/InteractiveWindow/EditorTest/TestContentTypeDefinition.cs
@@ -0,0 +1,17 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.ComponentModel.Composition;
+using Microsoft.VisualStudio.Utilities;
+
+namespace Roslyn.Editor.InteractiveWindow.UnitTests
+{
+ public sealed class TestContentTypeDefinition
+ {
+ public const string ContentTypeName = "InteractiveWindowTest";
+
+ [Export]
+ [Name(ContentTypeName)]
+ [BaseDefinition("code")]
+ public static readonly ContentTypeDefinition Definition;
+ }
+}
diff --git a/src/InteractiveWindow/EditorTest/TestInteractiveEngine.cs b/src/InteractiveWindow/EditorTest/TestInteractiveEngine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0cd7d539d74c7e823fc33b2e4333ee7761463959
--- /dev/null
+++ b/src/InteractiveWindow/EditorTest/TestInteractiveEngine.cs
@@ -0,0 +1,82 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Threading.Tasks;
+using Microsoft.VisualStudio.Text;
+using Microsoft.VisualStudio.Text.Editor;
+using Microsoft.VisualStudio.Utilities;
+
+namespace Roslyn.Editor.InteractiveWindow.UnitTests
+{
+ public class TestInteractiveEngine : IInteractiveEvaluator
+ {
+ private readonly IContentType _contentType;
+ private IInteractiveWindow _currentWindow;
+
+ public TestInteractiveEngine(IContentTypeRegistryService contentTypeRegistryService)
+ {
+ _contentType = contentTypeRegistryService.GetContentType(TestContentTypeDefinition.ContentTypeName);
+ }
+
+ public IContentType ContentType
+ {
+ get { return _contentType; }
+ }
+
+ public IInteractiveWindow CurrentWindow
+ {
+ get
+ {
+ return _currentWindow;
+ }
+
+ set
+ {
+ _currentWindow = value;
+ }
+ }
+
+ public void Dispose()
+ {
+ }
+
+ public Task InitializeAsync()
+ {
+ return Task.FromResult(ExecutionResult.Success);
+ }
+
+ public Task ResetAsync(bool initialize = true)
+ {
+ return Task.FromResult(ExecutionResult.Success);
+ }
+
+ public bool CanExecuteText(string text)
+ {
+ return true;
+ }
+
+ public Task ExecuteTextAsync(string text)
+ {
+ return Task.FromResult(ExecutionResult.Success);
+ }
+
+ public string FormatClipboard()
+ {
+ return "";
+ }
+
+ public void AbortCommand()
+ {
+ }
+
+ public string GetConfiguration()
+ {
+ return "config";
+ }
+
+ public string GetPrompt()
+ {
+ return "> ";
+ }
+ }
+}
diff --git a/src/InteractiveWindow/EditorTest/TestWaitIndicator.cs b/src/InteractiveWindow/EditorTest/TestWaitIndicator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..05d39af91ee4ce6f459fa17372a958151bd00f8f
--- /dev/null
+++ b/src/InteractiveWindow/EditorTest/TestWaitIndicator.cs
@@ -0,0 +1,74 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.ComponentModel.Composition;
+using System.Threading;
+using Microsoft.VisualStudio.Language.Intellisense.Utilities;
+
+namespace Roslyn.Editor.InteractiveWindow.UnitTests
+{
+ [Export(typeof(IWaitIndicator))]
+ internal class TestWaitIndicator : IWaitIndicator
+ {
+ public IWaitContext StartWait(string title, string message, bool allowCancel)
+ {
+ return new WaitContext();
+ }
+
+ public WaitIndicatorResult Wait(string title, string message, bool allowCancel, Action action)
+ {
+ try
+ {
+ action(new WaitContext());
+ }
+ catch
+ {
+ }
+
+ return WaitIndicatorResult.Completed;
+ }
+
+ private class WaitContext : IWaitContext
+ {
+ public bool AllowCancel
+ {
+ get
+ {
+ return false;
+ }
+
+ set
+ {
+ }
+ }
+
+ public CancellationToken CancellationToken
+ {
+ get
+ {
+ return CancellationToken.None;
+ }
+ }
+
+ public string Message
+ {
+ get
+ {
+ return string.Empty;
+ }
+
+ set
+ {
+ }
+ }
+
+ public void UpdateProgress()
+ {
+ }
+
+ public void Dispose()
+ {
+ }
+ }
+ }
+}
diff --git a/src/InteractiveWindow/EditorTest/packages.config b/src/InteractiveWindow/EditorTest/packages.config
new file mode 100644
index 0000000000000000000000000000000000000000..c9c9f2d161f32685ab12a3ce8b53bb644872a641
--- /dev/null
+++ b/src/InteractiveWindow/EditorTest/packages.config
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/src/InteractiveWindow/InteractiveWindow.sln b/src/InteractiveWindow/InteractiveWindow.sln
new file mode 100644
index 0000000000000000000000000000000000000000..27cc46a3438861e9be2ead1a2ad2e7d9d09a706e
--- /dev/null
+++ b/src/InteractiveWindow/InteractiveWindow.sln
@@ -0,0 +1,71 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 14
+VisualStudioVersion = 14.0.21803.0
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InteractiveWindow", "Editor\InteractiveWindow.csproj", "{01E9BD68-0339-4A13-B42F-A3CA84D164F3}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InteractiveWindowTest", "EditorTest\InteractiveWindowTest.csproj", "{7F3CB45E-4993-4FA4-8D6A-C2DFFED2DFC3}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VisualStudioInteractiveWindow", "VisualStudio\VisualStudioInteractiveWindow.csproj", "{20BB6FAC-44D2-4D76-ABFE-0C1E163A1A4F}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Debug|Mixed Platforms = Debug|Mixed Platforms
+ Debug|x86 = Debug|x86
+ Release|Any CPU = Release|Any CPU
+ Release|Mixed Platforms = Release|Mixed Platforms
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {01E9BD68-0339-4A13-B42F-A3CA84D164F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {01E9BD68-0339-4A13-B42F-A3CA84D164F3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {01E9BD68-0339-4A13-B42F-A3CA84D164F3}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {01E9BD68-0339-4A13-B42F-A3CA84D164F3}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {01E9BD68-0339-4A13-B42F-A3CA84D164F3}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {01E9BD68-0339-4A13-B42F-A3CA84D164F3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {01E9BD68-0339-4A13-B42F-A3CA84D164F3}.Release|Any CPU.Build.0 = Release|Any CPU
+ {01E9BD68-0339-4A13-B42F-A3CA84D164F3}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {01E9BD68-0339-4A13-B42F-A3CA84D164F3}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {01E9BD68-0339-4A13-B42F-A3CA84D164F3}.Release|x86.ActiveCfg = Release|Any CPU
+ {7F3CB45E-4993-4FA4-8D6A-C2DFFED2DFC3}.Debug|Any CPU.ActiveCfg = Debug|x86
+ {7F3CB45E-4993-4FA4-8D6A-C2DFFED2DFC3}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
+ {7F3CB45E-4993-4FA4-8D6A-C2DFFED2DFC3}.Debug|Mixed Platforms.Build.0 = Debug|x86
+ {7F3CB45E-4993-4FA4-8D6A-C2DFFED2DFC3}.Debug|x86.ActiveCfg = Debug|x86
+ {7F3CB45E-4993-4FA4-8D6A-C2DFFED2DFC3}.Debug|x86.Build.0 = Debug|x86
+ {7F3CB45E-4993-4FA4-8D6A-C2DFFED2DFC3}.Release|Any CPU.ActiveCfg = Release|x86
+ {7F3CB45E-4993-4FA4-8D6A-C2DFFED2DFC3}.Release|Mixed Platforms.ActiveCfg = Release|x86
+ {7F3CB45E-4993-4FA4-8D6A-C2DFFED2DFC3}.Release|Mixed Platforms.Build.0 = Release|x86
+ {7F3CB45E-4993-4FA4-8D6A-C2DFFED2DFC3}.Release|x86.ActiveCfg = Release|x86
+ {7F3CB45E-4993-4FA4-8D6A-C2DFFED2DFC3}.Release|x86.Build.0 = Release|x86
+ {20BB6FAC-44D2-4D76-ABFE-0C1E163A1A4F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {20BB6FAC-44D2-4D76-ABFE-0C1E163A1A4F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {20BB6FAC-44D2-4D76-ABFE-0C1E163A1A4F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {20BB6FAC-44D2-4D76-ABFE-0C1E163A1A4F}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {20BB6FAC-44D2-4D76-ABFE-0C1E163A1A4F}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {20BB6FAC-44D2-4D76-ABFE-0C1E163A1A4F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {20BB6FAC-44D2-4D76-ABFE-0C1E163A1A4F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {20BB6FAC-44D2-4D76-ABFE-0C1E163A1A4F}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {20BB6FAC-44D2-4D76-ABFE-0C1E163A1A4F}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {20BB6FAC-44D2-4D76-ABFE-0C1E163A1A4F}.Release|x86.ActiveCfg = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(TeamFoundationVersionControl) = preSolution
+ SccNumberOfProjects = 4
+ SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C}
+ SccTeamFoundationServer = http://vstfdevdiv:8080/devdiv2
+ SccLocalPath0 = .
+ SccProjectUniqueName1 = Editor\\InteractiveWindow.csproj
+ SccProjectName1 = Editor
+ SccLocalPath1 = Editor
+ SccProjectUniqueName2 = EditorTest\\InteractiveWindowTest.csproj
+ SccProjectName2 = EditorTest
+ SccLocalPath2 = EditorTest
+ SccProjectUniqueName3 = VisualStudio\\VisualStudioInteractiveWindow.csproj
+ SccProjectName3 = VisualStudio
+ SccLocalPath3 = VisualStudio
+ EndGlobalSection
+EndGlobal
diff --git a/src/InteractiveWindow/VisualStudio/CommandIds.cs b/src/InteractiveWindow/VisualStudio/CommandIds.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8f11e35a740c90dd8d21b3e0803988ebeb32d548
--- /dev/null
+++ b/src/InteractiveWindow/VisualStudio/CommandIds.cs
@@ -0,0 +1,20 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Roslyn.VisualStudio.InteractiveWindow
+{
+ public enum CommandIds : uint
+ {
+ // TODO (crwilcox): should all of these be in the editoroperations?
+ SmartExecute = 0x103,
+ AbortExecution = 0x104,
+ Reset = 0x105,
+ HistoryNext = 0x0106,
+ HistoryPrevious = 0x0107,
+ ClearScreen = 0x0108,
+ BreakLine = 0x0109,
+ SearchHistoryNext = 0x010A,
+ SearchHistoryPrevious = 0x010B,
+ ExecuteInInteractiveWindow = 0x010C,
+ CopyToInteractiveWindow = 0x010D,
+ }
+}
diff --git a/src/InteractiveWindow/VisualStudio/Guids.cs b/src/InteractiveWindow/VisualStudio/Guids.cs
new file mode 100644
index 0000000000000000000000000000000000000000..eb581071f34e1042503b5bd55774b39d32980a4f
--- /dev/null
+++ b/src/InteractiveWindow/VisualStudio/Guids.cs
@@ -0,0 +1,19 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+
+namespace Roslyn.VisualStudio.InteractiveWindow
+{
+ public static class Guids
+ {
+ // vsct guids:
+ // This GUID identifies the VsInteractiveWindow type. We need to pass it to VS in a string form.
+ public const string InteractiveToolWindowIdString = "2D0A56AA-9527-4B78-B6E6-EBE6E05DA749";
+ public const string InteractiveWindowPackageIdString = "F5199A4E-6A60-4F79-82E9-FC92A41C4610";
+ public const string InteractiveCommandSetIdString = "00B8868B-F9F5-4970-A048-410B05508506";
+
+ public static readonly Guid InteractiveToolWindowId = new Guid(InteractiveToolWindowIdString);
+ public static readonly Guid InteractiveWindowPackageId = new Guid(InteractiveWindowPackageIdString);
+ public static readonly Guid InteractiveCommandSetId = new Guid(InteractiveCommandSetIdString);
+ }
+}
diff --git a/src/InteractiveWindow/VisualStudio/IVsInteractiveWindow.cs b/src/InteractiveWindow/VisualStudio/IVsInteractiveWindow.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7e4e49bbbf1881b05482dfe5254e62d45894b099
--- /dev/null
+++ b/src/InteractiveWindow/VisualStudio/IVsInteractiveWindow.cs
@@ -0,0 +1,36 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using Roslyn.Editor.InteractiveWindow;
+
+namespace Roslyn.VisualStudio.InteractiveWindow
+{
+ ///
+ /// Provides access to an interactive window being hosted inside of Visual Studio's process using the
+ /// default tool window.
+ ///
+ /// These tool windows are created using ProvideInteractiveWindowAttribute which provides the normal
+ /// tool window registration options. Instances of the tool window are then created using
+ /// IVsInteractiveWindowFactory when VS calls on your packages IVsToolWindowFactory.CreateToolWindow
+ /// method.
+ ///
+ public interface IVsInteractiveWindow
+ {
+ ///
+ /// Gets the interactive window instance.
+ ///
+ IInteractiveWindow InteractiveWindow { get; }
+
+ ///
+ /// Shows the window.
+ ///
+ void Show(bool focus);
+
+ ///
+ /// Configures the window for the specified VS language service guid language preferences.
+ ///
+ /// Also installs a language appropriate command filter if one is exported via IVsInteractiveWindowOleCommandTargetProvider.
+ ///
+ void SetLanguage(Guid languageServiceGuid);
+ }
+}
diff --git a/src/InteractiveWindow/VisualStudio/IVsInteractiveWindowEditorsFactoryService.cs b/src/InteractiveWindow/VisualStudio/IVsInteractiveWindowEditorsFactoryService.cs
new file mode 100644
index 0000000000000000000000000000000000000000..11f1323d5e37a96911f24f1cca78ee14c8a38bf0
--- /dev/null
+++ b/src/InteractiveWindow/VisualStudio/IVsInteractiveWindowEditorsFactoryService.cs
@@ -0,0 +1,28 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using Microsoft.VisualStudio.Text.Editor;
+using Roslyn.Editor.InteractiveWindow;
+
+namespace Microsoft.VisualStudio
+{
+ ///
+ /// Provides access to information and settings for an interactive window created inside of Visual Studio.
+ ///
+ public interface IVsInteractiveWindowEditorsFactoryService
+ {
+ ///
+ /// Gets the text view host for the given IInteractiveWindow instance.
+ ///
+ ///
+ ///
+ IWpfTextViewHost GetTextViewHost(IInteractiveWindow window);
+
+ ///
+ /// Configures the window for the specified VS language service guid language preferences.
+ ///
+ /// Also installs a language appropriate command filter if one is exported via IVsInteractiveWindowOleCommandTargetProvider.
+ ///
+ void SetLanguage(IInteractiveWindow window, Guid languageServiceGuid);
+ }
+}
diff --git a/src/InteractiveWindow/VisualStudio/IVsInteractiveWindowFactory.cs b/src/InteractiveWindow/VisualStudio/IVsInteractiveWindowFactory.cs
new file mode 100644
index 0000000000000000000000000000000000000000..fc007ce45738d32c0131dc5ab09ea42132e4a9cf
--- /dev/null
+++ b/src/InteractiveWindow/VisualStudio/IVsInteractiveWindowFactory.cs
@@ -0,0 +1,12 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using Roslyn.Editor.InteractiveWindow;
+
+namespace Roslyn.VisualStudio.InteractiveWindow
+{
+ public interface IVsInteractiveWindowFactory
+ {
+ IVsInteractiveWindow Create(Guid providerId, int instanceId, string title, IInteractiveEvaluator evaluator);
+ }
+}
diff --git a/src/InteractiveWindow/VisualStudio/IVsInteractiveWindowOleCommandTargetProvider.cs b/src/InteractiveWindow/VisualStudio/IVsInteractiveWindowOleCommandTargetProvider.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7e70b6139b5928b3967a0e1d95536926255ea769
--- /dev/null
+++ b/src/InteractiveWindow/VisualStudio/IVsInteractiveWindowOleCommandTargetProvider.cs
@@ -0,0 +1,16 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using Microsoft.VisualStudio.OLE.Interop;
+using Microsoft.VisualStudio.Text.Editor;
+
+namespace Roslyn.VisualStudio.InteractiveWindow
+{
+ ///
+ /// The implementer is given a chance to attach a command filter that routes language services
+ /// commands into the Interactive Window command filter chain.
+ ///
+ public interface IVsInteractiveWindowOleCommandTargetProvider
+ {
+ IOleCommandTarget GetCommandTarget(IWpfTextView textView, IOleCommandTarget nextTarget);
+ }
+}
diff --git a/src/InteractiveWindow/VisualStudio/InteractiveWindow.vsct b/src/InteractiveWindow/VisualStudio/InteractiveWindow.vsct
new file mode 100644
index 0000000000000000000000000000000000000000..03eb09bb9dc76ed5694a82917ee8854cfb5655dd
--- /dev/null
+++ b/src/InteractiveWindow/VisualStudio/InteractiveWindow.vsct
@@ -0,0 +1,314 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/InteractiveWindow/VisualStudio/InteractiveWindowPackage.cs b/src/InteractiveWindow/VisualStudio/InteractiveWindowPackage.cs
new file mode 100644
index 0000000000000000000000000000000000000000..522786886ad625b3bb340a8138a0e523062e0086
--- /dev/null
+++ b/src/InteractiveWindow/VisualStudio/InteractiveWindowPackage.cs
@@ -0,0 +1,32 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.ComponentModel;
+using System.Runtime.InteropServices;
+using Microsoft.VisualStudio.Shell;
+using Microsoft.VisualStudio.Shell.Interop;
+using Roslyn.Utilities;
+
+namespace Roslyn.VisualStudio.InteractiveWindow
+{
+ ///
+ /// This is the class that implements the package exposed by this assembly.
+ ///
+ /// The minimum requirement for a class to be considered a valid package for Visual Studio
+ /// is to implement the IVsPackage interface and register itself with the shell.
+ /// This package uses the helper classes defined inside the Managed Package Framework (MPF)
+ /// to do it: it derives from the Package class that provides the implementation of the
+ /// IVsPackage interface and uses the registration attributes defined in the framework to
+ /// register itself and its components with the shell.
+ ///
+ // This attribute tells the PkgDef creation utility (CreatePkgDef.exe) that this class is
+ // a package.
+ [PackageRegistration(UseManagedResourcesOnly = true)]
+ [Description("Visual Studio Interactive Window")]
+ [ProvideKeyBindingTable(Guids.InteractiveToolWindowIdString, 200)] // Resource ID: "Interactive Window"
+ [ProvideMenuResource("Menus.ctmenu", 1)]
+ [Guid(Guids.InteractiveWindowPackageIdString)]
+ internal sealed class InteractiveWindowPackage : Package
+ {
+ }
+}
diff --git a/src/InteractiveWindow/VisualStudio/MenuIds.cs b/src/InteractiveWindow/VisualStudio/MenuIds.cs
new file mode 100644
index 0000000000000000000000000000000000000000..795217bc59e210e164ed517f415eaecaf72b87e8
--- /dev/null
+++ b/src/InteractiveWindow/VisualStudio/MenuIds.cs
@@ -0,0 +1,15 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Microsoft.VisualStudio
+{
+ internal enum MenuIds : uint
+ {
+ InteractiveWindowToolbar = 0x2000,
+ InteractiveWindowContextMenu = 0x2100,
+ }
+}
diff --git a/src/InteractiveWindow/VisualStudio/Properties/AssemblyInfo.cs b/src/InteractiveWindow/VisualStudio/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5ea21f55a92cb842e228bd924aaa910b64ed2b89
--- /dev/null
+++ b/src/InteractiveWindow/VisualStudio/Properties/AssemblyInfo.cs
@@ -0,0 +1,11 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+[assembly: AssemblyTitle("Visual Studio Interactive Window")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+
+[assembly: InternalsVisibleTo("AnalysisTest, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")]
diff --git a/src/InteractiveWindow/VisualStudio/ProvideInteractiveWindowAttribute.cs b/src/InteractiveWindow/VisualStudio/ProvideInteractiveWindowAttribute.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0c62cdd70f6fe4deedee2186b63d5c48101bff25
--- /dev/null
+++ b/src/InteractiveWindow/VisualStudio/ProvideInteractiveWindowAttribute.cs
@@ -0,0 +1,161 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Drawing;
+using System.Globalization;
+using Microsoft.VisualStudio.Shell;
+
+namespace Roslyn.VisualStudio.InteractiveWindow
+{
+ ///
+ /// This attribute declares that a package own an interactive window. Visual Studio uses this
+ /// information to handle the positioning and persistence of your window. The attributes on a
+ /// package do not control the behavior of the package, but they can be used by registration
+ /// tools to register the proper information with Visual Studio.
+ ///
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
+ public sealed class ProvideInteractiveWindowAttribute : RegistrationAttribute
+ {
+ public ProvideInteractiveWindowAttribute(string guid)
+ {
+ this.Id = new Guid(guid);
+ }
+
+ public Guid Id { get; private set; }
+
+ public Rectangle Position { get; set; }
+
+ ///
+ /// Default DockStyle for the ToolWindow
+ ///
+ public VsDockStyle Style { get; set; }
+
+ ///
+ /// Default width of the ToolWindow when docked
+ ///
+ public int DockedWidth { get; set; }
+
+ ///
+ /// Default height of the ToolWindow when docked
+ ///
+ public int DockedHeight { get; set; }
+
+ ///
+ /// Default Orientation for the ToolWindow, relative to the window specified by the Window Property
+ ///
+ public ToolWindowOrientation Orientation { get; set; }
+
+ ///
+ /// Default Window that the ToolWindow will be docked with
+ ///
+ public string Window { get; set; }
+
+ ///
+ /// Set to true if you want a tool window that behaves and has a lifetime like a document.
+ /// The tool window will only be MDI or floating and will remain visible in its position across all layout changes
+ /// until manualy closed by the user at which point it will be destroyed.
+ /// This flag implies DontForceCreate and destructive multi instance.
+ ///
+ public bool DocumentLikeTool { get; set; }
+
+ private string GetRegistryKeyName()
+ {
+ return "ToolWindows\\" + Id.ToString("B");
+ }
+
+ ///
+ /// Called to register this attribute with the given context. The context
+ /// contains the location where the registration information should be placed.
+ /// it also contains such as the type being registered, and path information.
+ ///
+ public override void Register(RegistrationContext context)
+ {
+ using (Key childKey = context.CreateKey(GetRegistryKeyName()))
+ {
+ // Package owning this tool window
+ childKey.SetValue(string.Empty, context.ComponentType.GUID.ToString("B"));
+
+ if (Orientation != ToolWindowOrientation.none)
+ {
+ childKey.SetValue("Orientation", OrientationToString(Orientation));
+ }
+
+ if (Style != VsDockStyle.none)
+ {
+ childKey.SetValue("Style", StyleToString(Style));
+ }
+
+ if (!string.IsNullOrEmpty(Window))
+ {
+ childKey.SetValue("Window", Window);
+ }
+
+ if (Position.Width != 0 && Position.Height != 0)
+ {
+ string positionString = string.Format(CultureInfo.InvariantCulture, "{0}, {1}, {2}, {3}",
+ Position.Left,
+ Position.Top,
+ Position.Right,
+ Position.Bottom);
+
+ childKey.SetValue("Float", positionString);
+ }
+
+ if (DockedWidth > 0)
+ {
+ childKey.SetValue("DockedWidth", DockedWidth);
+ }
+
+ if (DockedHeight > 0)
+ {
+ childKey.SetValue("DockedHeight", DockedHeight);
+ }
+
+ if (DocumentLikeTool)
+ {
+ childKey.SetValue("DocumentLikeTool", 1);
+ }
+ }
+ }
+
+ ///
+ /// Unregister this Tool Window.
+ ///
+ public override void Unregister(RegistrationContext context)
+ {
+ context.RemoveKey(GetRegistryKeyName());
+ }
+
+ private string StyleToString(VsDockStyle style)
+ {
+ switch (style)
+ {
+ case VsDockStyle.MDI: return "MDI";
+ case VsDockStyle.Float: return "Float";
+ case VsDockStyle.Linked: return "Linked";
+ case VsDockStyle.Tabbed: return "Tabbed";
+ case VsDockStyle.AlwaysFloat: return "AlwaysFloat";
+ case VsDockStyle.none: return string.Empty;
+ default:
+ // TODO: error message
+ throw new ArgumentException("Style");
+ }
+ }
+
+ private string OrientationToString(ToolWindowOrientation position)
+ {
+ switch (position)
+ {
+ case ToolWindowOrientation.Top: return "Top";
+ case ToolWindowOrientation.Left: return "Left";
+ case ToolWindowOrientation.Right: return "Right";
+ case ToolWindowOrientation.Bottom: return "Bottom";
+ case ToolWindowOrientation.none: return string.Empty;
+ default:
+ // TODO: error message
+ throw new ArgumentException("Orientation");
+ }
+ }
+ }
+}
+
diff --git a/src/InteractiveWindow/VisualStudio/Resources/InteractiveToolbarImages.png b/src/InteractiveWindow/VisualStudio/Resources/InteractiveToolbarImages.png
new file mode 100644
index 0000000000000000000000000000000000000000..d9d9ee596e30d145270e4985d7ab4f2130afe69e
Binary files /dev/null and b/src/InteractiveWindow/VisualStudio/Resources/InteractiveToolbarImages.png differ
diff --git a/src/InteractiveWindow/VisualStudio/Resources/Package.ico b/src/InteractiveWindow/VisualStudio/Resources/Package.ico
new file mode 100644
index 0000000000000000000000000000000000000000..ea3b23fe8d4b3a45be89f9286e617624007290be
Binary files /dev/null and b/src/InteractiveWindow/VisualStudio/Resources/Package.ico differ
diff --git a/src/InteractiveWindow/VisualStudio/Utils.cs b/src/InteractiveWindow/VisualStudio/Utils.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9822203a3ba5ca3103df5b54eaf5ee42cc2cfc2e
--- /dev/null
+++ b/src/InteractiveWindow/VisualStudio/Utils.cs
@@ -0,0 +1,36 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Diagnostics;
+
+namespace Roslyn.VisualStudio.InteractiveWindow
+{
+ internal static class SpecializedCollections
+ {
+ internal static class Empty
+ {
+ internal class Array
+ {
+ public static readonly T[] Instance = new T[0];
+ }
+ }
+
+ public static T[] EmptyArray()
+ {
+ return Empty.Array.Instance;
+ }
+ }
+
+ internal static class ExceptionUtilities
+ {
+ [DebuggerDisplay("Unreachable")]
+ public static Exception Unreachable
+ {
+ get
+ {
+ Debug.Fail("This code path should not be reachable");
+ return new InvalidOperationException();
+ }
+ }
+ }
+}
diff --git a/src/InteractiveWindow/VisualStudio/VSInteractiveWindowResources.Designer.cs b/src/InteractiveWindow/VisualStudio/VSInteractiveWindowResources.Designer.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d6942f874e62f9c7f5a108bd72503c4d36ad4267
--- /dev/null
+++ b/src/InteractiveWindow/VisualStudio/VSInteractiveWindowResources.Designer.cs
@@ -0,0 +1,63 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.18408
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace Microsoft.VisualStudio {
+ using System;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class VSInteractiveWindowResources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal VSInteractiveWindowResources() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.VisualStudio.VSInteractiveWindowResources", typeof(VSInteractiveWindowResources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+ }
+}
diff --git a/src/InteractiveWindow/VisualStudio/VSInteractiveWindowResources.resx b/src/InteractiveWindow/VisualStudio/VSInteractiveWindowResources.resx
new file mode 100644
index 0000000000000000000000000000000000000000..4fdb1b6aff69ba96d81420fab7a92b738c17f074
--- /dev/null
+++ b/src/InteractiveWindow/VisualStudio/VSInteractiveWindowResources.resx
@@ -0,0 +1,101 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 1.3
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/src/InteractiveWindow/VisualStudio/VSPackage.resx b/src/InteractiveWindow/VisualStudio/VSPackage.resx
new file mode 100644
index 0000000000000000000000000000000000000000..4aaa53dfa23f8cb74d1d2e435b07132ed6d42159
--- /dev/null
+++ b/src/InteractiveWindow/VisualStudio/VSPackage.resx
@@ -0,0 +1,133 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
+ Microsoft Visual Studio Interactive Window
+
+
+ Microsoft Visual Studio Interactive Window
+
+
+ Interactive Window
+
+
+
+ Resources\Package.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
\ No newline at end of file
diff --git a/src/InteractiveWindow/VisualStudio/VisualStudioInteractiveWindow.csproj b/src/InteractiveWindow/VisualStudio/VisualStudioInteractiveWindow.csproj
new file mode 100644
index 0000000000000000000000000000000000000000..acf9c7e12ce00238ebe7ccbfb7348a6ccf231c27
--- /dev/null
+++ b/src/InteractiveWindow/VisualStudio/VisualStudioInteractiveWindow.csproj
@@ -0,0 +1,125 @@
+
+
+
+ CSharp
+ true
+
+
+
+
+
+
+ Debug
+ AnyCPU
+ {20BB6FAC-44D2-4D76-ABFE-0C1E163A1A4F}
+ Library
+ true
+
+ false
+ false
+ Microsoft.VisualStudio
+ Roslyn.VisualStudio.InteractiveWindow
+ Program
+ $(DevEnvDir)devenv.exe
+ /rootsuffix RoslynDev /log
+ AnyCPU
+ $(VisualStudioVersion)
+ true
+ ..\..\..\
+
+
+
+ {01E9BD68-0339-4A13-B42F-A3CA84D164F3}
+ InteractiveWindow
+
+
+
+ MinimumRecommendedRules.ruleset
+
+
+ MinimumRecommendedRules.ruleset
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ True
+ True
+ VSInteractiveWindowResources.resx
+
+
+
+
+ ResXFileCodeGenerator
+ VSInteractiveWindowResources.Designer.cs
+
+
+ true
+ VSPackage
+ Designer
+
+
+
+
+ Menus.ctmenu
+ Designer
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/InteractiveWindow/VisualStudio/VsInteractiveWindow.cs b/src/InteractiveWindow/VisualStudio/VsInteractiveWindow.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c9f1f60333b4698e0b27d069d9b13f09f8589ee9
--- /dev/null
+++ b/src/InteractiveWindow/VisualStudio/VsInteractiveWindow.cs
@@ -0,0 +1,306 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+// Dumps commands in QueryStatus and Exec.
+// #define DUMP_COMMANDS
+
+using System;
+using System.Windows;
+using System.Windows.Input;
+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;
+using Roslyn.Editor.InteractiveWindow;
+
+namespace Roslyn.VisualStudio.InteractiveWindow
+{
+ ///
+ /// Default tool window for hosting interactive windows inside of Visual Studio. This hooks up support for
+ /// find in windows, forwarding commands down to the text view adapter, and providing access for setting
+ /// VS specific concepts (such as language service GUIDs) for the interactive window.
+ ///
+ /// Interactive windows can also be hosted outside of this tool window if the user creates an IInteractiveWindow
+ /// directly. In that case the user is responsible for doing what this class does themselves. But the
+ /// interactive window will be properly initialized for running inside of Visual Studio's process by our
+ /// VsInteractiveWindowEditorsFactoryService which handles all of the mapping of VS commands to API calls
+ /// on the interactive window.
+ ///
+ internal sealed class VsInteractiveWindow : ToolWindowPane, IVsFindTarget, IOleCommandTarget, IVsInteractiveWindow
+ {
+ private readonly IComponentModel _componentModel;
+ private readonly IVsEditorAdaptersFactoryService _editorAdapters;
+
+ private IInteractiveWindow _window;
+ private IVsFindTarget _findTarget;
+ private IOleCommandTarget _commandTarget;
+ private IInteractiveEvaluator _evaluator;
+ private IWpfTextViewHost _textViewHost;
+ private readonly IVsInteractiveWindowEditorsFactoryService _editorFactoryService;
+
+ internal VsInteractiveWindow(IComponentModel model, Guid providerId, int instanceId, string title, IInteractiveEvaluator evaluator)
+ {
+ _componentModel = model;
+ this.Caption = title;
+ _editorAdapters = _componentModel.GetService();
+ _evaluator = evaluator;
+ _editorFactoryService = model.GetService();
+
+ // The following calls this.OnCreate:
+ Guid clsId = this.ToolClsid;
+ Guid empty = Guid.Empty;
+ Guid typeId = providerId;
+ IVsWindowFrame frame;
+ var vsShell = (IVsUIShell)ServiceProvider.GlobalProvider.GetService(typeof(SVsUIShell));
+
+ // we don't pass __VSCREATETOOLWIN.CTW_fMultiInstance because multi instance panes are
+ // destroyed when closed. We are really multi instance but we don't want to be closed.
+
+ ErrorHandler.ThrowOnFailure(
+ vsShell.CreateToolWindow(
+ (uint)(__VSCREATETOOLWIN.CTW_fInitNew | __VSCREATETOOLWIN.CTW_fForceCreate | __VSCREATETOOLWIN.CTW_fToolbarHost),
+ (uint)instanceId,
+ this.GetIVsWindowPane(),
+ ref clsId,
+ ref typeId,
+ ref empty,
+ null,
+ title,
+ null,
+ out frame
+ )
+ );
+
+ this.Frame = frame;
+ }
+
+ public void SetLanguage(Guid languageServiceGuid)
+ {
+ _editorFactoryService.SetLanguage(_window, languageServiceGuid);
+ }
+
+ public IInteractiveWindow InteractiveWindow { get { return _window; } }
+
+ #region ToolWindowPane overrides
+
+ protected override void OnCreate()
+ {
+ _window = _componentModel.GetService().CreateWindow(_evaluator);
+ _window.SubmissionBufferAdded += SubmissionBufferAdded;
+ _textViewHost = _editorFactoryService.GetTextViewHost(_window);
+ var viewAdapter = _editorAdapters.GetViewAdapter(_textViewHost.TextView);
+ _findTarget = viewAdapter as IVsFindTarget;
+ _commandTarget = viewAdapter as IOleCommandTarget;
+ }
+
+ private void SubmissionBufferAdded(object sender, SubmissionBufferAddedEventArgs e)
+ {
+ GetToolbarHost().ForceUpdateUI();
+ }
+
+ protected override void OnClose()
+ {
+ _window.Close();
+ base.OnClose();
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ if (_window != null)
+ {
+ _window.Dispose();
+ }
+ }
+ }
+
+ ///
+ /// This property returns the control that should be hosted in the Tool Window. It can be
+ /// either a FrameworkElement (for easy creation of tool windows hosting WPF content), or it
+ /// can be an object implementing one of the IVsUIWPFElement or IVsUIWin32Element
+ /// interfaces.
+ ///
+ public override object Content
+ {
+ get { return _textViewHost; }
+ set { }
+ }
+
+ public override void OnToolWindowCreated()
+ {
+ Guid commandUiGuid = VSConstants.GUID_TextEditorFactory;
+ ((IVsWindowFrame)Frame).SetGuidProperty((int)__VSFPROPID.VSFPROPID_InheritKeyBindings, ref commandUiGuid);
+
+ base.OnToolWindowCreated();
+
+ // add our toolbar which is defined in our VSCT file
+ var toolbarHost = GetToolbarHost();
+ Guid guidInteractiveCmdSet = Guids.InteractiveCommandSetId;
+ ErrorHandler.ThrowOnFailure(toolbarHost.AddToolbar(VSTWT_LOCATION.VSTWT_TOP, ref guidInteractiveCmdSet, (uint)MenuIds.InteractiveWindowToolbar));
+ }
+
+ #endregion
+
+ #region Window IOleCommandTarget
+
+ public int QueryStatus(ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText)
+ {
+ return _commandTarget.QueryStatus(ref pguidCmdGroup, cCmds, prgCmds, pCmdText);
+ }
+
+ public int Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut)
+ {
+ return _commandTarget.Exec(ref pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut);
+ }
+
+ #endregion
+
+ #region IVsInteractiveWindow
+
+ public void Show(bool focus)
+ {
+ var windowFrame = (IVsWindowFrame)Frame;
+ ErrorHandler.ThrowOnFailure(focus ? windowFrame.Show() : windowFrame.ShowNoActivate());
+
+ if (focus)
+ {
+ IInputElement input = _window.TextView as IInputElement;
+ if (input != null)
+ {
+ Keyboard.Focus(input);
+ }
+ }
+ }
+
+ private IVsToolWindowToolbarHost GetToolbarHost()
+ {
+ var frame = (IVsWindowFrame)Frame;
+ object result;
+ ErrorHandler.ThrowOnFailure(frame.GetProperty((int)__VSFPROPID.VSFPROPID_ToolbarHost, out result));
+ return (IVsToolWindowToolbarHost)result;
+ }
+
+ #endregion
+
+ #region IVsFindTarget
+
+ public int Find(string pszSearch, uint grfOptions, int fResetStartPoint, IVsFindHelper pHelper, out uint pResult)
+ {
+ if (_findTarget != null)
+ {
+ return _findTarget.Find(pszSearch, grfOptions, fResetStartPoint, pHelper, out pResult);
+ }
+ pResult = 0;
+ return VSConstants.E_NOTIMPL;
+ }
+
+ public int GetCapabilities(bool[] pfImage, uint[] pgrfOptions)
+ {
+ if (_findTarget != null && pgrfOptions != null && pgrfOptions.Length > 0)
+ {
+ return _findTarget.GetCapabilities(pfImage, pgrfOptions);
+ }
+ return VSConstants.E_NOTIMPL;
+ }
+
+ public int GetCurrentSpan(TextSpan[] pts)
+ {
+ if (_findTarget != null)
+ {
+ return _findTarget.GetCurrentSpan(pts);
+ }
+ return VSConstants.E_NOTIMPL;
+ }
+
+ public int GetFindState(out object ppunk)
+ {
+ if (_findTarget != null)
+ {
+ return _findTarget.GetFindState(out ppunk);
+ }
+ ppunk = null;
+ return VSConstants.E_NOTIMPL;
+ }
+
+ public int GetMatchRect(RECT[] prc)
+ {
+ if (_findTarget != null)
+ {
+ return _findTarget.GetMatchRect(prc);
+ }
+ return VSConstants.E_NOTIMPL;
+ }
+
+ public int GetProperty(uint propid, out object pvar)
+ {
+ if (_findTarget != null)
+ {
+ return _findTarget.GetProperty(propid, out pvar);
+ }
+ pvar = null;
+ return VSConstants.E_NOTIMPL;
+ }
+
+ public int GetSearchImage(uint grfOptions, IVsTextSpanSet[] ppSpans, out IVsTextImage ppTextImage)
+ {
+ if (_findTarget != null)
+ {
+ return _findTarget.GetSearchImage(grfOptions, ppSpans, out ppTextImage);
+ }
+ ppTextImage = null;
+ return VSConstants.E_NOTIMPL;
+ }
+
+ public int MarkSpan(TextSpan[] pts)
+ {
+ if (_findTarget != null)
+ {
+ return _findTarget.MarkSpan(pts);
+ }
+ return VSConstants.E_NOTIMPL;
+ }
+
+ public int NavigateTo(TextSpan[] pts)
+ {
+ if (_findTarget != null)
+ {
+ return _findTarget.NavigateTo(pts);
+ }
+ return VSConstants.E_NOTIMPL;
+ }
+
+ public int NotifyFindTarget(uint notification)
+ {
+ if (_findTarget != null)
+ {
+ return _findTarget.NotifyFindTarget(notification);
+ }
+ return VSConstants.E_NOTIMPL;
+ }
+
+ public int Replace(string pszSearch, string pszReplace, uint grfOptions, int fResetStartPoint, IVsFindHelper pHelper, out int pfReplaced)
+ {
+ if (_findTarget != null)
+ {
+ return _findTarget.Replace(pszSearch, pszReplace, grfOptions, fResetStartPoint, pHelper, out pfReplaced);
+ }
+ pfReplaced = 0;
+ return VSConstants.E_NOTIMPL;
+ }
+
+ public int SetFindState(object pUnk)
+ {
+ if (_findTarget != null)
+ {
+ return _findTarget.SetFindState(pUnk);
+ }
+ return VSConstants.E_NOTIMPL;
+ }
+
+ #endregion
+ }
+}
diff --git a/src/InteractiveWindow/VisualStudio/VsInteractiveWindowCommandFilter.cs b/src/InteractiveWindow/VisualStudio/VsInteractiveWindowCommandFilter.cs
new file mode 100644
index 0000000000000000000000000000000000000000..26c008eb0f5f8f712c79bdc2ad951674ee13015c
--- /dev/null
+++ b/src/InteractiveWindow/VisualStudio/VsInteractiveWindowCommandFilter.cs
@@ -0,0 +1,415 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+// Dumps commands in QueryStatus and Exec.
+// #define DUMP_COMMANDS
+
+using System;
+using Microsoft.VisualStudio;
+using Microsoft.VisualStudio.Editor;
+using Microsoft.VisualStudio.OLE.Interop;
+using Microsoft.VisualStudio.Shell.Interop;
+using Microsoft.VisualStudio.Text.Editor;
+using Microsoft.VisualStudio.TextManager.Interop;
+using Roslyn.Editor.InteractiveWindow;
+
+namespace Roslyn.VisualStudio.InteractiveWindow
+{
+ internal sealed class VsInteractiveWindowCommandFilter : IOleCommandTarget
+ {
+ //
+ // Command filter chain:
+ // *window* -> VsTextView -> ... -> *pre-language + the current language service's filter* -> editor services -> *preEditor* -> editor
+ //
+ private IOleCommandTarget _preLanguageCommandFilter;
+ private IOleCommandTarget _editorServicesCommandFilter;
+ private IOleCommandTarget _preEditorCommandFilter;
+ private IOleCommandTarget _editorCommandFilter;
+ // we route undo/redo commands to this target:
+ internal IOleCommandTarget currentBufferCommandHandler;
+ internal IOleCommandTarget firstLanguageServiceCommandFilter;
+ private readonly IInteractiveWindow _window;
+ internal readonly IVsTextView textViewAdapter;
+ private readonly IWpfTextViewHost _textViewHost;
+
+ public VsInteractiveWindowCommandFilter(IVsEditorAdaptersFactoryService adapterFactory, IInteractiveWindow window, IVsTextView textViewAdapter, IVsTextBuffer bufferAdapter)
+ {
+ _window = window;
+ this.textViewAdapter = textViewAdapter;
+
+ // make us a code window so we'll have the same colors as a normal code window.
+ IVsTextEditorPropertyContainer propContainer;
+ ErrorHandler.ThrowOnFailure(((IVsTextEditorPropertyCategoryContainer)textViewAdapter).GetPropertyCategory(Microsoft.VisualStudio.Editor.DefGuidList.guidEditPropCategoryViewMasterSettings, out propContainer));
+ propContainer.SetProperty(VSEDITPROPID.VSEDITPROPID_ViewComposite_AllCodeWindowDefaults, true);
+ propContainer.SetProperty(VSEDITPROPID.VSEDITPROPID_ViewGlobalOpt_AutoScrollCaretOnTextEntry, true);
+
+ // editor services are initialized in textViewAdapter.Initialize - hook underneath them:
+ _preEditorCommandFilter = new CommandFilter(this, CommandFilterLayer.PreEditor);
+ ErrorHandler.ThrowOnFailure(textViewAdapter.AddCommandFilter(_preEditorCommandFilter, out _editorCommandFilter));
+
+ textViewAdapter.Initialize(
+ (IVsTextLines)bufferAdapter,
+ IntPtr.Zero,
+ (uint)TextViewInitFlags.VIF_HSCROLL | (uint)TextViewInitFlags.VIF_VSCROLL | (uint)TextViewInitFlags3.VIF_NO_HWND_SUPPORT,
+ new[] { new INITVIEW { fSelectionMargin = 0, fWidgetMargin = 0, fVirtualSpace = 0, fDragDropMove = 1 } });
+
+ // disable change tracking because everything will be changed
+ var textViewHost = adapterFactory.GetWpfTextViewHost(textViewAdapter);
+
+ _preLanguageCommandFilter = new CommandFilter(this, CommandFilterLayer.PreLanguage);
+ ErrorHandler.ThrowOnFailure(textViewAdapter.AddCommandFilter(_preLanguageCommandFilter, out _editorServicesCommandFilter));
+
+ _textViewHost = textViewHost;
+ }
+
+ private IOleCommandTarget TextViewCommandFilterChain
+ {
+ get
+ {
+ // Non-character command processing starts with WindowFrame which calls ReplWindow.Exec.
+ // We need to invoke the view's Exec method in order to invoke its full command chain
+ // (features add their filters to the view).
+ return (IOleCommandTarget)textViewAdapter;
+ }
+ }
+
+ #region IOleCommandTarget
+
+ public int QueryStatus(ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText)
+ {
+ var nextTarget = TextViewCommandFilterChain;
+
+ return nextTarget.QueryStatus(ref pguidCmdGroup, cCmds, prgCmds, pCmdText);
+ }
+
+ public int Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut)
+ {
+ var nextTarget = TextViewCommandFilterChain;
+
+ return nextTarget.Exec(ref pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut);
+ }
+
+ #endregion
+
+ public IWpfTextViewHost TextViewHost
+ {
+ get
+ {
+ return _textViewHost;
+ }
+ }
+
+ private enum CommandFilterLayer
+ {
+ PreLanguage,
+ PreEditor
+ }
+
+ private sealed class CommandFilter : IOleCommandTarget
+ {
+ private readonly VsInteractiveWindowCommandFilter _window;
+ private readonly CommandFilterLayer _layer;
+
+ public CommandFilter(VsInteractiveWindowCommandFilter window, CommandFilterLayer layer)
+ {
+ _window = window;
+ _layer = layer;
+ }
+
+ public int QueryStatus(ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText)
+ {
+ switch (_layer)
+ {
+ case CommandFilterLayer.PreLanguage:
+ return _window.PreLanguageCommandFilterQueryStatus(ref pguidCmdGroup, cCmds, prgCmds, pCmdText);
+
+ case CommandFilterLayer.PreEditor:
+ return _window.PreEditorCommandFilterQueryStatus(ref pguidCmdGroup, cCmds, prgCmds, pCmdText);
+ }
+
+ throw new InvalidOperationException();
+ }
+
+ public int Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut)
+ {
+ switch (_layer)
+ {
+ case CommandFilterLayer.PreLanguage:
+ return _window.PreLanguageCommandFilterExec(ref pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut);
+
+ case CommandFilterLayer.PreEditor:
+ return _window.PreEditorCommandFilterExec(ref pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut);
+ }
+
+ throw new InvalidOperationException();
+ }
+ }
+
+ private int PreEditorCommandFilterQueryStatus(ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText)
+ {
+ return _editorCommandFilter.QueryStatus(ref pguidCmdGroup, cCmds, prgCmds, pCmdText);
+ }
+
+ private int PreEditorCommandFilterExec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut)
+ {
+ var nextTarget = _editorCommandFilter;
+
+ if (pguidCmdGroup == Guids.InteractiveCommandSetId)
+ {
+ switch ((CommandIds)nCmdID)
+ {
+ case CommandIds.BreakLine:
+ if (_window.BreakLine())
+ {
+ return VSConstants.S_OK;
+ }
+ break;
+ }
+ }
+ else if (pguidCmdGroup == VSConstants.VSStd2K)
+ {
+ switch ((VSConstants.VSStd2KCmdID)nCmdID)
+ {
+ case VSConstants.VSStd2KCmdID.RETURN:
+ if (_window.Return())
+ {
+ return VSConstants.S_OK;
+ }
+ break;
+
+ // TODO:
+ //case VSConstants.VSStd2KCmdID.DELETEWORDLEFT:
+ //case VSConstants.VSStd2KCmdID.DELETEWORDRIGHT:
+ // break;
+
+ case VSConstants.VSStd2KCmdID.BACKSPACE:
+ if (_window.Backspace())
+ {
+ return VSConstants.S_OK;
+ }
+ break;
+
+
+ case VSConstants.VSStd2KCmdID.UP:
+
+ if (_window.CurrentLanguageBuffer != null && !_window.IsRunning && CaretAtEnd && UseSmartUpDown)
+ {
+ _window.HistoryPrevious();
+ return VSConstants.S_OK;
+ }
+ break;
+
+ case VSConstants.VSStd2KCmdID.DOWN:
+ if (_window.CurrentLanguageBuffer != null && !_window.IsRunning && CaretAtEnd && UseSmartUpDown)
+ {
+ _window.HistoryNext();
+ return VSConstants.S_OK;
+ }
+ break;
+
+ case VSConstants.VSStd2KCmdID.CANCEL:
+ if (_window.TextView.Selection.IsEmpty)
+ {
+ _window.Cancel();
+ }
+ break;
+
+ case VSConstants.VSStd2KCmdID.BOL:
+ _window.Home(false);
+ return VSConstants.S_OK;
+
+ case VSConstants.VSStd2KCmdID.BOL_EXT:
+ _window.Home(true);
+ return VSConstants.S_OK;
+
+ case VSConstants.VSStd2KCmdID.EOL:
+ _window.End(false);
+ return VSConstants.S_OK;
+
+ case VSConstants.VSStd2KCmdID.EOL_EXT:
+ _window.End(true);
+ return VSConstants.S_OK;
+ }
+ }
+ else if (pguidCmdGroup == VSConstants.GUID_VSStandardCommandSet97)
+ {
+ // undo/redo support:
+ switch ((VSConstants.VSStd97CmdID)nCmdID)
+ {
+ case VSConstants.VSStd97CmdID.Paste:
+ _window.Paste();
+ return VSConstants.S_OK;
+
+ case VSConstants.VSStd97CmdID.Cut:
+ _window.Cut();
+ return VSConstants.S_OK;
+
+ case VSConstants.VSStd97CmdID.Delete:
+ if (_window.Delete())
+ {
+ return VSConstants.S_OK;
+ }
+ break;
+
+ case VSConstants.VSStd97CmdID.SelectAll:
+ _window.SelectAll();
+ return VSConstants.S_OK;
+ }
+ }
+
+ return nextTarget.Exec(ref pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut);
+ }
+
+ private int PreLanguageCommandFilterQueryStatus(ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText)
+ {
+ var nextTarget = firstLanguageServiceCommandFilter;
+
+ if (pguidCmdGroup == Guids.InteractiveCommandSetId)
+ {
+ switch ((CommandIds)prgCmds[0].cmdID)
+ {
+ case CommandIds.HistoryNext:
+ case CommandIds.HistoryPrevious:
+ case CommandIds.SearchHistoryNext:
+ case CommandIds.SearchHistoryPrevious:
+ // TODO: Submit?
+ prgCmds[0].cmdf = _window.CurrentLanguageBuffer != null ? CommandEnabled : CommandDisabled;
+ break;
+ case CommandIds.AbortExecution:
+ prgCmds[0].cmdf = _window.IsRunning ? CommandEnabled : CommandDisabled;
+ break;
+ case CommandIds.Reset:
+ prgCmds[0].cmdf = !_window.IsResetting ? CommandEnabled : CommandDisabled;
+ break;
+ default:
+ prgCmds[0].cmdf = CommandEnabled;
+ break;
+ }
+ prgCmds[0].cmdf |= (uint)OLECMDF.OLECMDF_DEFHIDEONCTXTMENU;
+ }
+ else if (currentBufferCommandHandler != null && pguidCmdGroup == VSConstants.GUID_VSStandardCommandSet97)
+ {
+ // undo/redo support:
+ switch ((VSConstants.VSStd97CmdID)prgCmds[0].cmdID)
+ {
+ case VSConstants.VSStd97CmdID.Undo:
+ case VSConstants.VSStd97CmdID.MultiLevelUndo:
+ case VSConstants.VSStd97CmdID.MultiLevelUndoList:
+ case VSConstants.VSStd97CmdID.Redo:
+ case VSConstants.VSStd97CmdID.MultiLevelRedo:
+ case VSConstants.VSStd97CmdID.MultiLevelRedoList:
+ return currentBufferCommandHandler.QueryStatus(ref pguidCmdGroup, cCmds, prgCmds, pCmdText);
+ }
+ }
+
+ var result = nextTarget.QueryStatus(ref pguidCmdGroup, cCmds, prgCmds, pCmdText);
+#if DUMP_COMMANDS
+ //DumpCmd("QS", result, ref pguidCmdGroup, prgCmds[0].cmdID, prgCmds[0].cmdf);
+#endif
+ return result;
+ }
+
+ private int PreLanguageCommandFilterExec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut)
+ {
+ var nextTarget = firstLanguageServiceCommandFilter ?? _editorServicesCommandFilter;
+
+ if (pguidCmdGroup == Guids.InteractiveCommandSetId)
+ {
+ switch ((CommandIds)nCmdID)
+ {
+ case CommandIds.AbortExecution: _window.AbortCommand(); return VSConstants.S_OK;
+ case CommandIds.Reset: _window.ResetAsync(); return VSConstants.S_OK;
+ case CommandIds.SmartExecute: _window.ExecuteInput(); return VSConstants.S_OK;
+ case CommandIds.HistoryNext: _window.HistoryNext(); return VSConstants.S_OK;
+ case CommandIds.HistoryPrevious: _window.HistoryPrevious(); return VSConstants.S_OK;
+ case CommandIds.ClearScreen: _window.ClearView(); return VSConstants.S_OK;
+ case CommandIds.SearchHistoryNext:
+ _window.HistorySearchNext();
+ return VSConstants.S_OK;
+ case CommandIds.SearchHistoryPrevious:
+ _window.HistorySearchPrevious();
+ return VSConstants.S_OK;
+ }
+ }
+ else if (pguidCmdGroup == VSConstants.VSStd2K)
+ {
+ switch ((VSConstants.VSStd2KCmdID)nCmdID)
+ {
+ case VSConstants.VSStd2KCmdID.TYPECHAR:
+ _window.Delete();
+ break;
+
+ case VSConstants.VSStd2KCmdID.RETURN:
+ if (_window.TrySubmitStandardInput())
+ {
+ return VSConstants.S_OK;
+ }
+ break;
+ case VSConstants.VSStd2KCmdID.SHOWCONTEXTMENU:
+ ShowContextMenu();
+ return VSConstants.S_OK;
+ }
+ }
+ else if (currentBufferCommandHandler != null && pguidCmdGroup == VSConstants.GUID_VSStandardCommandSet97)
+ {
+ // undo/redo support:
+ switch ((VSConstants.VSStd97CmdID)nCmdID)
+ {
+ case VSConstants.VSStd97CmdID.Undo:
+ case VSConstants.VSStd97CmdID.MultiLevelUndo:
+ case VSConstants.VSStd97CmdID.MultiLevelUndoList:
+ case VSConstants.VSStd97CmdID.Redo:
+ case VSConstants.VSStd97CmdID.MultiLevelRedo:
+ case VSConstants.VSStd97CmdID.MultiLevelRedoList:
+ return currentBufferCommandHandler.Exec(ref pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut);
+ }
+ }
+
+ int res = nextTarget.Exec(ref pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut);
+#if DUMP_COMMANDS
+ DumpCmd("Exec", result, ref pguidCmdGroup, nCmdID, 0);
+#endif
+ return res;
+ }
+
+ private void ShowContextMenu()
+ {
+ var uishell = (IVsUIShell)InteractiveWindowPackage.GetGlobalService(typeof(SVsUIShell));
+ if (uishell != null)
+ {
+ var pt = System.Windows.Forms.Cursor.Position;
+ var position = new[] { new POINTS { x = (short)pt.X, y = (short)pt.Y } };
+ var guid = Guids.InteractiveCommandSetId;
+ ErrorHandler.ThrowOnFailure(uishell.ShowContextMenu(0, ref guid, (int)MenuIds.InteractiveWindowContextMenu, position, this));
+ }
+ }
+
+ private const uint CommandEnabled = (uint)(OLECMDF.OLECMDF_ENABLED | OLECMDF.OLECMDF_SUPPORTED);
+ private const uint CommandDisabled = (uint)(OLECMDF.OLECMDF_SUPPORTED);
+ private const uint CommandDisabledAndHidden = (uint)(OLECMDF.OLECMDF_INVISIBLE | OLECMDF.OLECMDF_SUPPORTED);
+
+ private bool CaretAtEnd
+ {
+ get
+ {
+ var caret = _window.TextView.Caret;
+ return caret.Position.BufferPosition.Position == caret.Position.BufferPosition.Snapshot.Length;
+ }
+ }
+
+ private bool UseSmartUpDown
+ {
+ get
+ {
+ return _window.TextView.Options.GetOptionValue(InteractiveWindowOptions.SmartUpDown);
+ }
+ }
+
+ public IOleCommandTarget EditorServicesCommandFilter
+ {
+ get
+ {
+ return _editorServicesCommandFilter;
+ }
+ }
+ }
+}
diff --git a/src/InteractiveWindow/VisualStudio/VsInteractiveWindowEditorFactoryService.cs b/src/InteractiveWindow/VisualStudio/VsInteractiveWindowEditorFactoryService.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d4b28002b9501d6d91df54e63bf78db8afd99e5c
--- /dev/null
+++ b/src/InteractiveWindow/VisualStudio/VsInteractiveWindowEditorFactoryService.cs
@@ -0,0 +1,125 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.Composition;
+using System.Windows;
+using System.Windows.Threading;
+using Microsoft.VisualStudio.Editor;
+using Microsoft.VisualStudio.OLE.Interop;
+using Microsoft.VisualStudio.Shell.Interop;
+using Microsoft.VisualStudio.Text;
+using Microsoft.VisualStudio.Text.Editor;
+using Microsoft.VisualStudio.TextManager.Interop;
+using Microsoft.VisualStudio.Utilities;
+using Roslyn.Editor.InteractiveWindow;
+using Roslyn.VisualStudio.InteractiveWindow;
+
+namespace Microsoft.VisualStudio
+{
+ using IOleServiceProvider = Microsoft.VisualStudio.OLE.Interop.IServiceProvider;
+
+ [Export(typeof(IInteractiveWindowEditorFactoryService))]
+ [Export(typeof(IVsInteractiveWindowEditorsFactoryService))]
+ internal sealed class VsInteractiveWindowEditorFactoryService : IInteractiveWindowEditorFactoryService, IVsInteractiveWindowEditorsFactoryService
+ {
+ private readonly IOleServiceProvider _provider;
+ private readonly IVsEditorAdaptersFactoryService _adapterFactory;
+ private readonly IContentTypeRegistryService _contentTypeRegistry;
+ private readonly IEnumerable> _oleCommandTargetProviders;
+
+ [ImportingConstructor]
+ public VsInteractiveWindowEditorFactoryService(IVsEditorAdaptersFactoryService adaptersFactory, IContentTypeRegistryService contentTypeRegistry, [ImportMany]IEnumerable> oleCommandTargetProviders)
+ {
+ _adapterFactory = adaptersFactory;
+ _provider = (IOleServiceProvider)InteractiveWindowPackage.GetGlobalService(typeof(IOleServiceProvider));
+ _contentTypeRegistry = contentTypeRegistry;
+ _oleCommandTargetProviders = oleCommandTargetProviders;
+ }
+
+ IWpfTextView IInteractiveWindowEditorFactoryService.CreateTextView(IInteractiveWindow window, ITextBuffer buffer, ITextViewRoleSet roles)
+ {
+ var bufferAdapter = _adapterFactory.CreateVsTextBufferAdapterForSecondaryBuffer(_provider, buffer);
+
+ // Create and initialize text view adapter.
+ // WARNING: This might trigger various services like IntelliSense, margins, taggers, etc.
+ var textViewAdapter = _adapterFactory.CreateVsTextViewAdapter(_provider, roles);
+
+ var commandFilter = new VsInteractiveWindowCommandFilter(_adapterFactory, window, textViewAdapter, bufferAdapter);
+ window.Properties[typeof(VsInteractiveWindowCommandFilter)] = commandFilter;
+ return commandFilter.TextViewHost.TextView;
+ }
+
+ ITextBuffer IInteractiveWindowEditorFactoryService.CreateAndActivateBuffer(IInteractiveWindow window, IContentType contentType)
+ {
+ // create buffer adapter to support undo/redo:
+ var bufferAdapter = _adapterFactory.CreateVsTextBufferAdapter(_provider, contentType);
+ bufferAdapter.InitializeContent("", 0);
+
+ var commandFilter = GetCommandFilter(window);
+ if (commandFilter.currentBufferCommandHandler != null)
+ {
+ ((IVsPersistDocData)commandFilter.currentBufferCommandHandler).Close();
+ }
+
+ commandFilter.currentBufferCommandHandler = (IOleCommandTarget)bufferAdapter;
+
+ return _adapterFactory.GetDocumentBuffer(bufferAdapter);
+ }
+
+ public IWpfTextViewHost GetTextViewHost(IInteractiveWindow window)
+ {
+ var cmdFilter = GetCommandFilter(window);
+ if (cmdFilter != null)
+ {
+ return cmdFilter.TextViewHost;
+ }
+ return null;
+ }
+
+ public void SetLanguage(IInteractiveWindow window, Guid languageServiceGuid)
+ {
+ // REVIEW: What happens to the current input buffer here?
+ // REVIEW: What happens when the window is already initialized?
+ GetDispatcher(window).CheckAccess();
+
+ var commandFilter = GetCommandFilter(window);
+ commandFilter.firstLanguageServiceCommandFilter = null;
+ var provider = _oleCommandTargetProviders.OfContentType(window.Evaluator.ContentType, _contentTypeRegistry);
+ if (provider != null)
+ {
+ var targetFilter = commandFilter.firstLanguageServiceCommandFilter ?? GetCommandFilter(window).EditorServicesCommandFilter;
+ var target = provider.GetCommandTarget(window.TextView, targetFilter);
+ if (target != null)
+ {
+ commandFilter.firstLanguageServiceCommandFilter = target;
+ }
+ }
+
+ SetEditorOptions(window.TextView.Options, languageServiceGuid);
+ }
+
+ private void SetEditorOptions(IEditorOptions options, Guid languageServiceGuid)
+ {
+ IVsTextManager textMgr = (IVsTextManager)InteractiveWindowPackage.GetGlobalService(typeof(SVsTextManager));
+ var langPrefs = new LANGPREFERENCES[1];
+ langPrefs[0].guidLang = languageServiceGuid;
+ ErrorHandler.ThrowOnFailure(textMgr.GetUserPreferences(null, null, langPrefs, null));
+
+ options.SetOptionValue(DefaultTextViewHostOptions.ChangeTrackingId, false);
+ options.SetOptionValue(DefaultOptions.ConvertTabsToSpacesOptionId, langPrefs[0].fInsertTabs == 0);
+ options.SetOptionValue(DefaultOptions.TabSizeOptionId, (int)langPrefs[0].uTabSize);
+ options.SetOptionValue(DefaultOptions.IndentSizeOptionId, (int)langPrefs[0].uIndentSize);
+ }
+
+ private Dispatcher GetDispatcher(IInteractiveWindow window)
+ {
+ return ((FrameworkElement)window.TextView).Dispatcher;
+ }
+
+ public VsInteractiveWindowCommandFilter GetCommandFilter(IInteractiveWindow window)
+ {
+ return (VsInteractiveWindowCommandFilter)window.Properties[typeof(VsInteractiveWindowCommandFilter)];
+ }
+ }
+}
diff --git a/src/InteractiveWindow/VisualStudio/VsInteractiveWindowFactory.cs b/src/InteractiveWindow/VisualStudio/VsInteractiveWindowFactory.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6cfd93a610c60446188c908375d453e2539ebcdc
--- /dev/null
+++ b/src/InteractiveWindow/VisualStudio/VsInteractiveWindowFactory.cs
@@ -0,0 +1,27 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.ComponentModel.Composition;
+using Microsoft.VisualStudio.ComponentModelHost;
+using Microsoft.VisualStudio.Shell;
+using Roslyn.Editor.InteractiveWindow;
+
+namespace Roslyn.VisualStudio.InteractiveWindow
+{
+ [Export(typeof(IVsInteractiveWindowFactory))]
+ internal sealed class VsInteractiveWindowFactory : IVsInteractiveWindowFactory
+ {
+ private readonly IComponentModel _componentModel;
+
+ [ImportingConstructor]
+ internal VsInteractiveWindowFactory(SVsServiceProvider serviceProvider)
+ {
+ _componentModel = (IComponentModel)serviceProvider.GetService(typeof(SComponentModel));
+ }
+
+ public IVsInteractiveWindow Create(Guid providerId, int instanceId, string title, IInteractiveEvaluator evaluator)
+ {
+ return new VsInteractiveWindow(_componentModel, providerId, instanceId, title, evaluator);
+ }
+ }
+}
diff --git a/src/InteractiveWindow/VisualStudio/packages.config b/src/InteractiveWindow/VisualStudio/packages.config
new file mode 100644
index 0000000000000000000000000000000000000000..79ece06bef6a23c7f75492ed821f546d8bd403e2
--- /dev/null
+++ b/src/InteractiveWindow/VisualStudio/packages.config
@@ -0,0 +1,3 @@
+
+
+
diff --git a/src/Roslyn.sln b/src/Roslyn.sln
index b17111ff0d4e9a51a899395bf1c7fc8ceed15072..2942336b953af3a08e5042f959b1e485e3f7a2cf 100644
--- a/src/Roslyn.sln
+++ b/src/Roslyn.sln
@@ -219,6 +219,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "csi", "Interactive\csi\csi.
EndProject
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "vbi", "Interactive\vbi\vbi.vbproj", "{6E62A0FF-D0DC-4109-9131-AB8E60CDFF7B}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InteractiveWindowTest", "InteractiveWindow\EditorTest\InteractiveWindowTest.csproj", "{7F3CB45E-4993-4FA4-8D6A-C2DFFED2DFC3}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VisualStudioInteractiveWindow", "InteractiveWindow\VisualStudio\VisualStudioInteractiveWindow.csproj", "{20BB6FAC-44D2-4D76-ABFE-0C1E163A1A4F}"
+EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
Compilers\Core\SharedCollections\SharedCollections.projitems*{5f8d2414-064a-4b3a-9b42-8e2a04246be5}*SharedItemsImports = 4
@@ -1297,6 +1301,18 @@ Global
{6E62A0FF-D0DC-4109-9131-AB8E60CDFF7B}.Release|Mixed Platforms.ActiveCfg = Release|x86
{6E62A0FF-D0DC-4109-9131-AB8E60CDFF7B}.Release|Mixed Platforms.Build.0 = Release|x86
{6E62A0FF-D0DC-4109-9131-AB8E60CDFF7B}.Release|x64.ActiveCfg = Release|x86
+ {7F3CB45E-4993-4FA4-8D6A-C2DFFED2DFC3}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
+ {7F3CB45E-4993-4FA4-8D6A-C2DFFED2DFC3}.Debug|Mixed Platforms.Build.0 = Debug|x86
+ {7F3CB45E-4993-4FA4-8D6A-C2DFFED2DFC3}.Debug|x64.ActiveCfg = Debug|x86
+ {7F3CB45E-4993-4FA4-8D6A-C2DFFED2DFC3}.Release|Mixed Platforms.ActiveCfg = Release|x86
+ {7F3CB45E-4993-4FA4-8D6A-C2DFFED2DFC3}.Release|Mixed Platforms.Build.0 = Release|x86
+ {7F3CB45E-4993-4FA4-8D6A-C2DFFED2DFC3}.Release|x64.ActiveCfg = Release|x86
+ {20BB6FAC-44D2-4D76-ABFE-0C1E163A1A4F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {20BB6FAC-44D2-4D76-ABFE-0C1E163A1A4F}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {20BB6FAC-44D2-4D76-ABFE-0C1E163A1A4F}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {20BB6FAC-44D2-4D76-ABFE-0C1E163A1A4F}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {20BB6FAC-44D2-4D76-ABFE-0C1E163A1A4F}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {20BB6FAC-44D2-4D76-ABFE-0C1E163A1A4F}.Release|x64.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE