Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/monodevelop.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--main/Main.sln26
-rw-r--r--main/src/addins/CSharpBinding/CSharpBinding.addin.xml4
-rw-r--r--main/src/addins/CSharpBinding/CSharpBinding.csproj1
-rw-r--r--main/src/addins/CSharpBinding/MonoDevelop.CSharp.Formatting/CSharpFormattingPolicy.cs16
-rw-r--r--main/src/addins/CSharpBinding/MonoDevelop.CSharp.Parser/CSharpFoldingParser.cs393
-rw-r--r--main/src/addins/CSharpBinding/MonoDevelop.CSharp.Project/CSharpCompilerParameters.cs7
-rw-r--r--main/src/addins/CSharpBinding/MonoDevelop.CSharp/CSharpBindingCompilerManager.cs2
-rw-r--r--main/src/addins/GnomePlatform/GnomePlatform.cs6
-rw-r--r--main/src/addins/MacPlatform/MacPlatform.cs22
-rw-r--r--main/src/addins/MacPlatform/MainToolbar/SelectorView.cs40
-rw-r--r--main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/ExceptionCaughtDialog.cs57
-rw-r--r--main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/Styles.cs21
-rw-r--r--main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.Toolbox/IToolboxWidget.cs1
-rw-r--r--main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.Toolbox/MacToolbox.cs28
-rw-r--r--main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.Toolbox/MacToolboxWidget.cs4
-rw-r--r--main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.Toolbox/ToolboxWidget.cs3
-rw-r--r--main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/DesignerSupportService.cs42
-rw-r--r--main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/ToolboxPad.cs7
-rw-r--r--main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/DotNetCoreProjectSupportedTargetFrameworks.cs2
-rw-r--r--main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/DotNetCoreSdk.cs5
-rw-r--r--main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/MonoRuntimeInfoExtensions.cs2
-rw-r--r--main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Tests/MonoDevelop.PackageManagement.Tests/DotNetCoreRestoreTests.cs2
-rw-r--r--main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeActions/CodeFixMenuService.cs8
-rw-r--r--main/src/addins/MonoDevelop.UnitTesting/Commands/UnitTestCommands.cs15
-rw-r--r--main/src/addins/MonoDevelop.UnitTesting/MonoDevelop.UnitTesting.addin.xml3
-rw-r--r--main/src/addins/MonoDevelop.UnitTesting/Services/AbstractUnitTestEditorExtension.cs150
-rw-r--r--main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl.Views/LogWidget.cs21
-rw-r--r--main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl.csproj8
-rw-r--r--main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl/Instrumentation.cs163
-rw-r--r--main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl/Repository.cs236
-rw-r--r--main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl/VersionControlService.cs15
-rw-r--r--main/src/addins/VersionControl/MonoDevelop.VersionControl/packages.config4
-rw-r--r--main/src/addins/Xml/Completion/XmlSchemaCompletionData.cs11
-rw-r--r--main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/Document/TextDocument.cs260
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/AssemblyUtilities.cs65
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/SystemAssemblyService.cs282
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/RemoteProcessConnection.cs9
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.csproj2
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildFileFormat.cs52
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildProcessService.cs12
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/SdkResolution.cs21
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProject.cs10
-rw-r--r--main/src/core/MonoDevelop.Ide/ExtensionModel/Commands.addin.xml2
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components/GtkWorkarounds.cs6
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.CodeCompletion/CompletionListWindow.cs6
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Composition/CompositionManager.Caching.cs113
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Composition/CompositionManager.cs22
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/TextEditorViewContent.cs6
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Dialogs/NewFolderDialog.cs221
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Pads.ProjectPad/FolderNodeBuilder.cs26
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/BaseViewContent.cs56
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/DefaultWorkbench.cs21
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/SdiWorkspaceWindow.cs6
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/Workbench.cs6
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Projects/ApplyPolicyDialog.cs34
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Projects/ExportProjectPolicyDialog.cs1
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopPersistentStorageLocationService.cs114
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.ProjectData.cs20
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.ProjectDataMap.cs21
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.ProjectSystemHandler.cs127
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.cs79
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/TypeSystemParserNode.cs11
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/TypeSystemService.cs13
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.csproj5
-rw-r--r--main/src/core/MonoDevelop.Projects.Formats.MSBuild/MonoDevelop.MSBuildResolver/Resolver.cs2
-rw-r--r--main/src/tools/ExtensionTools/AddinDependencyTreeWidget.cs144
-rw-r--r--main/src/tools/ExtensionTools/AddinInfo.cs15
-rw-r--r--main/src/tools/ExtensionTools/AddinListWidget.cs68
-rw-r--r--main/src/tools/ExtensionTools/AddinRegistryExtensions.cs64
-rw-r--r--main/src/tools/ExtensionTools/Application.cs97
-rw-r--r--main/src/tools/ExtensionTools/ExtensionNodesWidget.cs120
-rw-r--r--main/src/tools/ExtensionTools/ExtensionPointsWidget.cs97
-rw-r--r--main/src/tools/ExtensionTools/ExtensionTools.csproj56
-rw-r--r--main/src/tools/ExtensionTools/HashSetExtensions.cs41
-rw-r--r--main/src/tools/ExtensionTools/LazyNotebook.cs71
-rw-r--r--main/src/tools/ExtensionTools/MonoDevelop.ExtensionTools.addin.xml7
-rw-r--r--main/src/tools/ExtensionTools/Properties/AssemblyInfo.cs51
-rw-r--r--main/tests/Ide.Tests/MonoDevelop.Ide.Composition/CompositionManager.CachingTests.cs56
-rw-r--r--main/tests/MonoDevelop.Core.Tests/MonoDevelop.Core.Assemblies/SystemAssemblyServiceTests.cs80
-rw-r--r--main/tests/MonoDevelop.Core.Tests/MonoDevelop.Core.Tests.csproj1
-rw-r--r--main/tests/MonoDevelop.Core.Tests/MonoDevelop.Core/SdkResolverTests.cs107
-rw-r--r--main/tests/StressTest/Mono.Profiling.Log/LogEnums.cs27
-rw-r--r--main/tests/StressTest/Mono.Profiling.Log/LogEventVisitor.cs4
-rw-r--r--main/tests/StressTest/Mono.Profiling.Log/LogEvents.cs21
-rw-r--r--main/tests/StressTest/Mono.Profiling.Log/LogProcessor.cs41
-rw-r--r--main/tests/StressTest/Mono.Profiling.Log/LogStreamHeader.cs9
-rw-r--r--main/tests/StressTest/MonoDevelop.StressTest/ProfilerProcessor.cs6
-rw-r--r--main/tests/StressTest/MonoDevelop.StressTest/StressTestApp.cs5
-rw-r--r--main/tests/StressTest/StressTest.csproj4
-rwxr-xr-xmain/tests/test-projects/restore-netcore-offline/dotnetcoreconsole.csproj2
91 files changed, 3274 insertions, 877 deletions
diff --git a/.gitignore b/.gitignore
index 78f7e19612..0ef24a84e4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -278,3 +278,4 @@ main/po/StripMnemonics.pdb
main/po/StripMnemonics.exe
*.binlog
*.ProjectImports.zip
+main/tests/StressTest/bin
diff --git a/main/Main.sln b/main/Main.sln
index 469368ab29..62e6985a55 100644
--- a/main/Main.sln
+++ b/main/Main.sln
@@ -474,6 +474,7 @@ EndProject
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "RoslynIntegration", "external\vs-editor-core\src\RoslynIntegration\RoslynIntegration.shproj", "{A10C6E18-A872-4D43-9BB2-2B28C70C7BF7}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NavigationProvidersImpl", "external\vs-editor-core\src\Editor\Text\Impl\NavigationProviders\NavigationProvidersImpl.csproj", "{3E8ABAB5-CE9A-484E-B82B-73B89EA2E51A}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExtensionTools", "src\tools\ExtensionTools\ExtensionTools.csproj", "{E33F7901-AA45-4C25-9868-DBB6CC8DC40C}"
EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
@@ -2740,6 +2741,30 @@ Global
{3E8ABAB5-CE9A-484E-B82B-73B89EA2E51A}.ReleaseMac|Any CPU.Build.0 = Release|Any CPU
{3E8ABAB5-CE9A-484E-B82B-73B89EA2E51A}.ReleaseWin32|Any CPU.ActiveCfg = Release|Any CPU
{3E8ABAB5-CE9A-484E-B82B-73B89EA2E51A}.ReleaseWin32|Any CPU.Build.0 = Release|Any CPU
+ {44FFFDDA-156F-49F9-AE6A-BA640C198B33}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {44FFFDDA-156F-49F9-AE6A-BA640C198B33}.Debug|x86.Build.0 = Debug|Any CPU
+ {44FFFDDA-156F-49F9-AE6A-BA640C198B33}.Release|x86.ActiveCfg = Release|Any CPU
+ {44FFFDDA-156F-49F9-AE6A-BA640C198B33}.Release|x86.Build.0 = Release|Any CPU
+ {E33F7901-AA45-4C25-9868-DBB6CC8DC40C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E33F7901-AA45-4C25-9868-DBB6CC8DC40C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E33F7901-AA45-4C25-9868-DBB6CC8DC40C}.DebugGnome|Any CPU.ActiveCfg = Debug|Any CPU
+ {E33F7901-AA45-4C25-9868-DBB6CC8DC40C}.DebugGnome|Any CPU.Build.0 = Debug|Any CPU
+ {E33F7901-AA45-4C25-9868-DBB6CC8DC40C}.DebugMac|Any CPU.ActiveCfg = DebugMac|Any CPU
+ {E33F7901-AA45-4C25-9868-DBB6CC8DC40C}.DebugMac|Any CPU.Build.0 = DebugMac|Any CPU
+ {E33F7901-AA45-4C25-9868-DBB6CC8DC40C}.DebugWin32|Any CPU.ActiveCfg = Debug|Any CPU
+ {E33F7901-AA45-4C25-9868-DBB6CC8DC40C}.DebugWin32|Any CPU.Build.0 = Debug|Any CPU
+ {E33F7901-AA45-4C25-9868-DBB6CC8DC40C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E33F7901-AA45-4C25-9868-DBB6CC8DC40C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E33F7901-AA45-4C25-9868-DBB6CC8DC40C}.ReleaseGnome|Any CPU.ActiveCfg = Release|Any CPU
+ {E33F7901-AA45-4C25-9868-DBB6CC8DC40C}.ReleaseGnome|Any CPU.Build.0 = Release|Any CPU
+ {E33F7901-AA45-4C25-9868-DBB6CC8DC40C}.ReleaseMac|Any CPU.ActiveCfg = ReleaseMac|Any CPU
+ {E33F7901-AA45-4C25-9868-DBB6CC8DC40C}.ReleaseMac|Any CPU.Build.0 = ReleaseMac|Any CPU
+ {E33F7901-AA45-4C25-9868-DBB6CC8DC40C}.ReleaseWin32|Any CPU.ActiveCfg = Release|Any CPU
+ {E33F7901-AA45-4C25-9868-DBB6CC8DC40C}.ReleaseWin32|Any CPU.Build.0 = Release|Any CPU
+ {E33F7901-AA45-4C25-9868-DBB6CC8DC40C}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {E33F7901-AA45-4C25-9868-DBB6CC8DC40C}.Debug|x86.Build.0 = Debug|Any CPU
+ {E33F7901-AA45-4C25-9868-DBB6CC8DC40C}.Release|x86.ActiveCfg = Release|Any CPU
+ {E33F7901-AA45-4C25-9868-DBB6CC8DC40C}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -2960,6 +2985,7 @@ Global
{6C7ADE4D-2544-581E-918B-659243920781} = {32539734-6484-4451-9EF3-61610CA25BBF}
{A10C6E18-A872-4D43-9BB2-2B28C70C7BF7} = {5A92B792-BF17-4748-B29E-34C99B2E8722}
{3E8ABAB5-CE9A-484E-B82B-73B89EA2E51A} = {32539734-6484-4451-9EF3-61610CA25BBF}
+ {E33F7901-AA45-4C25-9868-DBB6CC8DC40C} = {5D3F7E65-E55B-45CA-A83B-D1E10040281E}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {856CF524-E2A7-4DB0-B80F-8F1B080A2E25}
diff --git a/main/src/addins/CSharpBinding/CSharpBinding.addin.xml b/main/src/addins/CSharpBinding/CSharpBinding.addin.xml
index 2d78c132f9..93f01bbc85 100644
--- a/main/src/addins/CSharpBinding/CSharpBinding.addin.xml
+++ b/main/src/addins/CSharpBinding/CSharpBinding.addin.xml
@@ -186,6 +186,10 @@
<Parser class="MonoDevelop.CSharp.Parser.TypeSystemParser" mimeType = "text/x-csharp" />
</Extension>
+ <Extension path = "/MonoDevelop/TypeSystem/FoldingParser">
+ <Parser class = "MonoDevelop.CSharp.Parser.CSharpFoldingParser" mimeType="text/x-csharp" />
+ </Extension>
+
<Extension path = "/MonoDevelop/TypeSystem/CodeGenerators">
<Generator class="MonoDevelop.CSharp.Refactoring.CSharpCodeGenerator" mimeType = "text/x-csharp" />
</Extension>
diff --git a/main/src/addins/CSharpBinding/CSharpBinding.csproj b/main/src/addins/CSharpBinding/CSharpBinding.csproj
index 56890dbec4..83b8ee7e48 100644
--- a/main/src/addins/CSharpBinding/CSharpBinding.csproj
+++ b/main/src/addins/CSharpBinding/CSharpBinding.csproj
@@ -141,6 +141,7 @@
<Compile Include="MonoDevelop.CSharp.Completion\CSharpCompletionTextEditorExtension.cs" />
<Compile Include="MonoDevelop.CSharp.Refactoring\CSharpCodeGenerator.cs" />
<Compile Include="MonoDevelop.CSharp.Refactoring\HelperMethods.cs" />
+ <Compile Include="MonoDevelop.CSharp.Parser\CSharpFoldingParser.cs" />
<Compile Include="MonoDevelop.CSharp.CodeGeneration\AbstractGenerateAction.cs" />
<Compile Include="MonoDevelop.CSharp.CodeGeneration\CodeGenerationCommands.cs" />
<Compile Include="MonoDevelop.CSharp.CodeGeneration\CodeGenerationOptions.cs" />
diff --git a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Formatting/CSharpFormattingPolicy.cs b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Formatting/CSharpFormattingPolicy.cs
index 1a752ea206..a0277eb99d 100644
--- a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Formatting/CSharpFormattingPolicy.cs
+++ b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Formatting/CSharpFormattingPolicy.cs
@@ -584,22 +584,6 @@ namespace MonoDevelop.CSharp.Formatting
#endregion
- #region Code Style options
- bool placeSystemDirectiveFirst = true;
- [Obsolete("Not used anymore.")]
- [ItemProperty]
- public bool PlaceSystemDirectiveFirst {
- get {
- return placeSystemDirectiveFirst;
- }
-
- set {
- placeSystemDirectiveFirst = value;
- }
- }
-
- #endregion
-
public CSharpFormattingPolicy ()
{
this.options = TypeSystemService.Workspace?.Options;
diff --git a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Parser/CSharpFoldingParser.cs b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Parser/CSharpFoldingParser.cs
new file mode 100644
index 0000000000..cf6ba5fb22
--- /dev/null
+++ b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Parser/CSharpFoldingParser.cs
@@ -0,0 +1,393 @@
+//
+// CSharpFoldingParser.cs
+//
+// Author:
+// Mike Krüger <mkrueger@xamarin.com>
+//
+// Copyright (c) 2012 Xamarin Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+using System.Collections.Generic;
+using MonoDevelop.Ide.TypeSystem;
+using MonoDevelop.Ide.Editor;
+using MonoDevelop.Core;
+
+namespace MonoDevelop.CSharp.Parser
+{
+ unsafe class CSharpFoldingParser : IFoldingParser
+ {
+ #region IFoldingParser implementation
+
+ static unsafe bool StartsIdentifier (char* ptr, char* endPtr, string identifier)
+ {
+ fixed (char* startId = identifier) {
+ char* idPtr = startId;
+ char* endId = startId + identifier.Length;
+ while (idPtr < endId) {
+ if (ptr >= endPtr)
+ return false;
+ if (*idPtr != *ptr)
+ return false;
+ idPtr++;
+ ptr++;
+ }
+ return true;
+ }
+ }
+
+ static unsafe void SkipWhitespaces (ref char* ptr, char* endPtr, ref int column)
+ {
+ while (ptr < endPtr) {
+ char ch = *ptr;
+ if (ch != ' ' && ch != '\t')
+ return;
+ column++;
+ ptr++;
+ }
+ }
+
+ static unsafe string ReadToEol (string content, ref char* ptr, char* endPtr, ref int line, ref int column)
+ {
+ char* lineBeginPtr = ptr;
+ char* lineEndPtr = lineBeginPtr;
+
+ while (ptr < endPtr) {
+ switch (*ptr) {
+ case '\n':
+ if (lineEndPtr == lineBeginPtr)
+ lineEndPtr = ptr;
+ line++;
+ column = 1;
+ ptr++;
+ fixed (char* startPtr = content) {
+ return content.Substring ((int)(lineBeginPtr - startPtr), (int)(lineEndPtr - lineBeginPtr));
+ }
+ case '\r':
+ lineEndPtr = ptr;
+ if (ptr + 1 < endPtr && *(ptr + 1) == '\n')
+ ptr++;
+ goto case '\n';
+ }
+ column++;
+ ptr++;
+ }
+ return "";
+ }
+
+ public unsafe ParsedDocument Parse (string fileName, string content)
+ {
+ var regionStack = new Stack<Tuple<string, DocumentLocation>> ();
+ var result = new DefaultParsedDocument (fileName);
+ bool inSingleComment = false, inMultiLineComment = false;
+ bool inString = false, inVerbatimString = false;
+ bool inChar = false;
+ bool inLineStart = true, hasStartedAtLine = false;
+ int line = 1, column = 1;
+ int bracketDepth = 0;
+ var startLoc = DocumentLocation.Empty;
+
+ fixed (char* startPtr = content) {
+ char* endPtr = startPtr + content.Length;
+ char* ptr = startPtr;
+ char* beginPtr = ptr;
+ while (ptr < endPtr) {
+ switch (*ptr) {
+ case '{':
+ if (inString || inChar || inVerbatimString || inMultiLineComment || inSingleComment)
+ break;
+ bracketDepth++;
+ break;
+ case '}':
+ if (inString || inChar || inVerbatimString || inMultiLineComment || inSingleComment)
+ break;
+ bracketDepth--;
+ break;
+ case '#':
+ if (!inLineStart)
+ break;
+ inLineStart = false;
+ ptr++;
+
+ if (StartsIdentifier (ptr, endPtr, "region")) {
+ var regionLocation = new DocumentLocation (line, column);
+ column++;
+ ptr += "region".Length;
+ column += "region".Length;
+ SkipWhitespaces (ref ptr, endPtr, ref column);
+ regionStack.Push (Tuple.Create (ReadToEol (content, ref ptr, endPtr, ref line, ref column), regionLocation));
+ continue;
+ } else if (StartsIdentifier (ptr, endPtr, "endregion")) {
+ column++;
+ ptr += "endregion".Length;
+ column += "endregion".Length;
+ if (regionStack.Count > 0) {
+ var beginRegion = regionStack.Pop ();
+ result.Add (new FoldingRegion (
+ beginRegion.Item1,
+ new DocumentRegion (beginRegion.Item2.Line, beginRegion.Item2.Column, line, column),
+ FoldType.UserRegion,
+ true));
+ }
+ continue;
+ } else {
+ column++;
+ }
+ break;
+ case '/':
+ if (inString || inChar || inVerbatimString || inMultiLineComment || inSingleComment) {
+ inLineStart = false;
+ break;
+ }
+ if (ptr + 1 < endPtr) {
+ char nextCh = *(ptr + 1);
+ if (nextCh == '/') {
+ hasStartedAtLine = inLineStart;
+ beginPtr = ptr + 2;
+ startLoc = new DocumentLocation (line, column);
+ ptr++;
+ column++;
+ inSingleComment = true;
+ } else if (nextCh == '*') {
+ hasStartedAtLine = inLineStart;
+ beginPtr = ptr + 2;
+ startLoc = new DocumentLocation (line, column);
+ ptr++;
+ column++;
+ inMultiLineComment = true;
+ }
+ }
+ inLineStart = false;
+ break;
+ case '*':
+ inLineStart = false;
+ if (inString || inChar || inVerbatimString || inSingleComment)
+ break;
+ if (inMultiLineComment && ptr + 1 < endPtr) {
+ if (ptr + 1 < endPtr && *(ptr + 1) == '/') {
+ ptr += 2;
+ column += 2;
+ inMultiLineComment = false;
+ if (bracketDepth <= 1) {
+ result.Add (new MonoDevelop.Ide.TypeSystem.Comment () {
+ Region = new DocumentRegion (startLoc, new DocumentLocation (line, column)),
+ OpenTag = "/*",
+ CommentType = MonoDevelop.Ide.TypeSystem.CommentType.Block,
+ Text = content.Substring ((int)(beginPtr - startPtr), (int)(ptr - beginPtr)),
+ CommentStartsLine = hasStartedAtLine
+ });
+ }
+ continue;
+ }
+ }
+ break;
+ case '@':
+ inLineStart = false;
+ if (inString || inChar || inVerbatimString || inSingleComment || inMultiLineComment)
+ break;
+ if (ptr + 1 < endPtr && *(ptr + 1) == '"') {
+ ptr++;
+ column++;
+ inVerbatimString = true;
+ }
+ break;
+ case '\n':
+ if (inSingleComment && hasStartedAtLine) {
+ bool isDocumentation = *beginPtr == '/';
+ if (isDocumentation)
+ beginPtr++;
+ if (isDocumentation || bracketDepth <= 1) {
+ // Doesn't matter much that some comments are not correctly recognized - they'll get added later
+ // It's important that header comments are in.
+ result.Add (new MonoDevelop.Ide.TypeSystem.Comment () {
+ Region = new DocumentRegion (startLoc, new DocumentLocation (line, column)),
+ CommentType = MonoDevelop.Ide.TypeSystem.CommentType.SingleLine,
+ OpenTag = "//",
+ Text = content.Substring ((int)(beginPtr - startPtr), (int)(ptr - beginPtr)),
+ CommentStartsLine = hasStartedAtLine,
+ IsDocumentation = isDocumentation
+ });
+ }
+ inSingleComment = false;
+ }
+ inString = false;
+ inChar = false;
+ inLineStart = true;
+ line++;
+ column = 1;
+ ptr++;
+ continue;
+ case '\r':
+ if (ptr + 1 < endPtr && *(ptr + 1) == '\n')
+ ptr++;
+ goto case '\n';
+ case '\\':
+ if (inString || inChar)
+ ptr++;
+ break;
+ case '"':
+ if (inSingleComment || inMultiLineComment || inChar)
+ break;
+ if (inVerbatimString) {
+ if (ptr + 1 < endPtr && *(ptr + 1) == '"') {
+ ptr++;
+ column++;
+ break;
+ }
+ inVerbatimString = false;
+ break;
+ }
+ inString = !inString;
+ break;
+ case '\'':
+ if (inSingleComment || inMultiLineComment || inString || inVerbatimString)
+ break;
+ inChar = !inChar;
+ break;
+ default:
+ inLineStart &= *ptr == ' ' || *ptr == '\t';
+ break;
+ }
+
+ column++;
+ ptr++;
+ }
+ }
+ foreach (var fold in ToFolds (result.GetCommentsAsync().Result)) {
+ result.Add (fold);
+ }
+ return result;
+ }
+ #endregion
+
+ static IEnumerable<FoldingRegion> ToFolds (IReadOnlyList<Comment> comments)
+ {
+ for (int i = 0; i < comments.Count; i++) {
+ Comment comment = comments [i];
+
+ if (comment.CommentType == CommentType.Block) {
+ int startOffset = 0;
+ if (comment.Region.BeginLine == comment.Region.EndLine)
+ continue;
+ while (startOffset < comment.Text.Length) {
+ char ch = comment.Text [startOffset];
+ if (!char.IsWhiteSpace (ch) && ch != '*')
+ break;
+ startOffset++;
+ }
+ int endOffset = startOffset;
+ while (endOffset < comment.Text.Length) {
+ char ch = comment.Text [endOffset];
+ if (ch == '\r' || ch == '\n' || ch == '*')
+ break;
+ endOffset++;
+ }
+
+ string txt;
+ if (endOffset > startOffset) {
+ txt = "/* " + GetFirstLine (comment.Text) + " ...";
+ } else {
+ txt = "/* */";
+ }
+ yield return new FoldingRegion (txt, comment.Region, FoldType.Comment);
+ continue;
+ }
+
+ if (!comment.CommentStartsLine)
+ continue;
+ int j = i;
+ int curLine = comment.Region.BeginLine - 1;
+ var end = comment.Region.End;
+ var commentText = StringBuilderCache.Allocate ();
+ for (; j < comments.Count; j++) {
+ Comment curComment = comments [j];
+ if (curComment == null || !curComment.CommentStartsLine
+ || curComment.CommentType != comment.CommentType
+ || curLine + 1 != curComment.Region.BeginLine)
+ break;
+ commentText.Append (curComment.Text);
+ end = curComment.Region.End;
+ curLine = curComment.Region.BeginLine;
+ }
+
+ if (j - i > 1 || (comment.IsDocumentation && comment.Region.BeginLine < comment.Region.EndLine)) {
+ string txt = null;
+ if (comment.IsDocumentation) {
+ string cmtText = commentText.ToString ();
+ int idx = cmtText.IndexOf ("<summary>", StringComparison.Ordinal);
+ if (idx >= 0) {
+ int maxOffset = cmtText.IndexOf ("</summary>", StringComparison.Ordinal);
+ while (maxOffset > 0 && cmtText [maxOffset - 1] == ' ')
+ maxOffset--;
+ if (maxOffset < 0)
+ maxOffset = cmtText.Length;
+ int startOffset = idx + "<summary>".Length;
+ while (startOffset < maxOffset) {
+ char ch = cmtText [startOffset];
+ if (!char.IsWhiteSpace (ch) && ch != '/')
+ break;
+ startOffset++;
+ }
+ int endOffset = startOffset;
+ while (endOffset < maxOffset) {
+ char ch = cmtText [endOffset];
+ if (ch == '\r' || ch == '\n')
+ break;
+ endOffset++;
+ }
+ if (endOffset > startOffset)
+ txt = "/// <summary> " + cmtText.Substring (startOffset, endOffset - startOffset).Trim () + " ...";
+ }
+ if (txt == null)
+ txt = "/// " + comment.Text.Trim () + " ...";
+ } else {
+ txt = "// " + comment.Text.Trim () + " ...";
+ }
+ StringBuilderCache.Free (commentText);
+ yield return new FoldingRegion (txt,
+ new DocumentRegion (comment.Region.Begin, end),
+ FoldType.Comment);
+ i = j - 1;
+ }
+ }
+ }
+
+ static string GetFirstLine (string text)
+ {
+ int start = 0;
+ while (start < text.Length) {
+ char ch = text [start];
+ if (ch != ' ' && ch != '\t')
+ break;
+ start++;
+ }
+ int end = start;
+
+ while (end < text.Length) {
+ char ch = text [end];
+ if (MonoDevelop.Core.Text.NewLine.IsNewLine (ch))
+ break;
+ end++;
+ }
+ if (end <= start)
+ return "";
+ return text.Substring (start, end - start);
+ }
+ }
+} \ No newline at end of file
diff --git a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Project/CSharpCompilerParameters.cs b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Project/CSharpCompilerParameters.cs
index eecaeb2247..f02a5db1c4 100644
--- a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Project/CSharpCompilerParameters.cs
+++ b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Project/CSharpCompilerParameters.cs
@@ -186,11 +186,10 @@ namespace MonoDevelop.CSharp.Project
var items = warnings.Split (new [] { ';', ',' }, StringSplitOptions.RemoveEmptyEntries).Distinct ();
foreach (string warning in items) {
- if (warning.StartsWith ("CS", StringComparison.OrdinalIgnoreCase)) {
- yield return warning;
- } else {
+ if (int.TryParse (warning, out _))
yield return "CS" + warning;
- }
+ else
+ yield return warning;
}
}
diff --git a/main/src/addins/CSharpBinding/MonoDevelop.CSharp/CSharpBindingCompilerManager.cs b/main/src/addins/CSharpBinding/MonoDevelop.CSharp/CSharpBindingCompilerManager.cs
index 29fa4a5f5d..28f5ec22b8 100644
--- a/main/src/addins/CSharpBinding/MonoDevelop.CSharp/CSharpBindingCompilerManager.cs
+++ b/main/src/addins/CSharpBinding/MonoDevelop.CSharp/CSharpBindingCompilerManager.cs
@@ -167,7 +167,7 @@ namespace MonoDevelop.CSharp
}
}
- if (alreadyAddedReference.Any (reference => SystemAssemblyService.ContainsReferenceToSystemRuntime (reference))) {
+ if (alreadyAddedReference.Any (reference => SystemAssemblyService.RequiresFacadeAssembliesAsync (reference).WaitAndGetResult (monitor.CancellationToken))) {
LoggingService.LogInfo ("Found PCLv2 assembly.");
var facades = runtime.FindFacadeAssembliesForPCL (project.TargetFramework);
foreach (var facade in facades)
diff --git a/main/src/addins/GnomePlatform/GnomePlatform.cs b/main/src/addins/GnomePlatform/GnomePlatform.cs
index 88d6e8fa31..d24bd6f705 100644
--- a/main/src/addins/GnomePlatform/GnomePlatform.cs
+++ b/main/src/addins/GnomePlatform/GnomePlatform.cs
@@ -165,8 +165,10 @@ namespace MonoDevelop.Platform
CreateNoWindow = true,
UseShellExecute = false,
};
- foreach (var env in environmentVariables)
- psi.EnvironmentVariables [env.Key] = env.Value;
+ if (environmentVariables != null) {
+ foreach (var env in environmentVariables)
+ psi.EnvironmentVariables [env.Key] = env.Value;
+ }
ProcessWrapper proc = new ProcessWrapper ();
if (terminal_command.Contains ("gnome-terminal")) {
diff --git a/main/src/addins/MacPlatform/MacPlatform.cs b/main/src/addins/MacPlatform/MacPlatform.cs
index fa2c985018..da6dc40138 100644
--- a/main/src/addins/MacPlatform/MacPlatform.cs
+++ b/main/src/addins/MacPlatform/MacPlatform.cs
@@ -266,6 +266,7 @@ namespace MonoDevelop.MacIntegration
e.Reply = NSApplicationTerminateReply.Now;
}
};
+ appDelegate.ShowDockMenu += AppDelegate_ShowDockMenu;
}
// Listen to the AtkCocoa notification for the presence of VoiceOver
@@ -298,6 +299,27 @@ namespace MonoDevelop.MacIntegration
return loaded;
}
+ void AppDelegate_ShowDockMenu (object sender, ShowDockMenuArgs e)
+ {
+ if (((FilePath)NSBundle.MainBundle.BundlePath).Extension != ".app")
+ return;
+ var menu = new NSMenu ();
+ var newInstanceMenuItem = new NSMenuItem ();
+ newInstanceMenuItem.Title = GettextCatalog.GetString ("New Instance");
+ newInstanceMenuItem.Activated += NewInstanceMenuItem_Activated;
+ menu.AddItem (newInstanceMenuItem);
+ e.DockMenu = menu;
+ }
+
+ static void NewInstanceMenuItem_Activated (object sender, EventArgs e)
+ {
+ var bundlePath = NSBundle.MainBundle.BundlePath;
+ NSWorkspace.SharedWorkspace.LaunchApplication (NSUrl.FromFilename (bundlePath), NSWorkspaceLaunchOptions.NewInstance, new NSDictionary (), out NSError error);
+ if (error != null)
+ LoggingService.LogError ($"Failed to start new instance: {error.LocalizedDescription}");
+ }
+
+
const string EnabledKey = "com.monodevelop.AccessibilityEnabled";
static void ShowVoiceOverNotice ()
{
diff --git a/main/src/addins/MacPlatform/MainToolbar/SelectorView.cs b/main/src/addins/MacPlatform/MainToolbar/SelectorView.cs
index d28760db4c..6eb52e52e5 100644
--- a/main/src/addins/MacPlatform/MainToolbar/SelectorView.cs
+++ b/main/src/addins/MacPlatform/MainToolbar/SelectorView.cs
@@ -562,6 +562,28 @@ namespace MonoDevelop.MacIntegration.MainToolbar
int focusedCellIndex = 0;
NSPathComponentCellFocusable focusedItem;
+ bool UpdatePreviousCellForResponderChain (int fromPosition)
+ {
+ for (focusedCellIndex = fromPosition; focusedCellIndex >= 0; focusedCellIndex--) {
+ var cell = Cells [focusedCellIndex].Cell;
+ if (PathComponentCells.Contains (cell) && cell.Enabled) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool UpdateNextCellForResponderChain (int fromPosition)
+ {
+ for (focusedCellIndex = fromPosition; focusedCellIndex < Cells.Length; focusedCellIndex++) {
+ var cell = Cells [focusedCellIndex].Cell;
+ if (PathComponentCells.Contains (cell) && cell.Enabled) {
+ return true;
+ }
+ }
+ return false;
+ }
+
public override void KeyDown (NSEvent theEvent)
{
if (theEvent.KeyCode == (ushort) KeyCodes.Space) {
@@ -580,9 +602,10 @@ namespace MonoDevelop.MacIntegration.MainToolbar
focusedItem = null;
}
} else {
- focusedCellIndex--;
- SetSelection ();
- return;
+ if (UpdatePreviousCellForResponderChain (focusedCellIndex - 1)) {
+ SetSelection ();
+ return;
+ }
}
} else {
if (focusedCellIndex >= VisibleCellIds.Length - 1) {
@@ -592,9 +615,10 @@ namespace MonoDevelop.MacIntegration.MainToolbar
focusedItem = null;
}
} else {
- focusedCellIndex++;
- SetSelection ();
- return;
+ if (UpdateNextCellForResponderChain (focusedCellIndex + 1)) {
+ SetSelection ();
+ return;
+ }
}
}
}
@@ -632,9 +656,9 @@ namespace MonoDevelop.MacIntegration.MainToolbar
if (currentEvent.Type == NSEventType.KeyDown) {
if (currentEvent.KeyCode == (ushort) KeyCodes.Tab) {
if ((currentEvent.ModifierFlags & NSEventModifierMask.ShiftKeyMask) == NSEventModifierMask.ShiftKeyMask) {
- focusedCellIndex = Cells.Length - 1;
+ UpdatePreviousCellForResponderChain (Cells.Length - 1);
} else {
- focusedCellIndex = 0;
+ UpdateNextCellForResponderChain (0);
}
}
}
diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/ExceptionCaughtDialog.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/ExceptionCaughtDialog.cs
index d3d79b584e..0dd7160a94 100644
--- a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/ExceptionCaughtDialog.cs
+++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/ExceptionCaughtDialog.cs
@@ -41,6 +41,8 @@ using MonoDevelop.Ide.Gui.Content;
using MonoDevelop.Ide.Editor.Extension;
using MonoDevelop.Ide.Fonts;
using System.Collections.Generic;
+using System.Drawing;
+using System.Text;
namespace MonoDevelop.Debugger
{
@@ -765,7 +767,7 @@ widget ""*.exception_dialog_expander"" style ""exception-dialog-expander""
Context = ctx;
}
- string GetMethodMarkup (bool selected)
+ string GetMethodMarkup (bool selected, string foregroundColor)
{
if (Markup != null)
return $"<span foreground='{Styles.ExceptionCaughtDialog.ExternalCodeTextColor.ToHexString (false)}'>{Markup}</span>";
@@ -777,30 +779,28 @@ widget ""*.exception_dialog_expander"" style ""exception-dialog-expander""
var markup = $"<b>{GLib.Markup.EscapeText (methodName)}</b> {GLib.Markup.EscapeText (parameters)}";
- if (selected)
- markup = $"<span foreground='#FFFFFF'>{markup}</span>";
- else {
- var textColor = IsUserCode ? Ide.Gui.Styles.BaseForegroundColor.ToHexString (false) : Styles.ExceptionCaughtDialog.ExternalCodeTextColor.ToHexString (false);
- markup = $"<span foreground='{textColor}'>{markup}</span>";
+ if (string.IsNullOrEmpty (foregroundColor)) {
+ return markup;
}
-
- return markup;
+ return $"<span foreground='{foregroundColor}'>{markup}</span>";
}
- string GetFileMarkup (bool selected)
+ string GetFileMarkup (bool selected, string foregroundColor)
{
if (Frame == null || string.IsNullOrEmpty (Frame.File)) {
return "";
}
- var markup = string.Format ("<span foreground='{0}'>{1}", selected ? "#FFFFFF" : Styles.ExceptionCaughtDialog.LineNumberTextColor.ToHexString (false), GLib.Markup.EscapeText (Path.GetFileName (Frame.File)));
+ var markup = GLib.Markup.EscapeText (Path.GetFileName (Frame.File));
if (Frame.Line > 0) {
markup += ":" + Frame.Line;
if (Frame.Column > 0)
markup += "," + Frame.Column;
}
- markup += "</span>";
- return markup;
+ if (string.IsNullOrEmpty (foregroundColor)) {
+ return markup;
+ }
+ return $"<span foreground='{foregroundColor}'>{markup}</span>";
}
public override void GetSize (Widget widget, ref Gdk.Rectangle cell_area, out int x_offset, out int y_offset, out int width, out int height)
@@ -808,7 +808,11 @@ widget ""*.exception_dialog_expander"" style ""exception-dialog-expander""
using (var layout = new Pango.Layout (Context)) {
Pango.Rectangle ink, logical;
layout.FontDescription = font;
- layout.SetMarkup (GetMethodMarkup (false));
+
+ var selected = false;
+ var foregroundColor = Styles.GetStackFrameForegroundHexColor (selected, IsUserCode);
+
+ layout.SetMarkup (GetMethodMarkup (selected, foregroundColor));
layout.GetPixelExtents (out ink, out logical);
height = logical.Height;
@@ -821,10 +825,20 @@ widget ""*.exception_dialog_expander"" style ""exception-dialog-expander""
protected override void Render (Gdk.Drawable window, Widget widget, Gdk.Rectangle background_area, Gdk.Rectangle cell_area, Gdk.Rectangle expose_area, CellRendererState flags)
{
using (var cr = Gdk.CairoHelper.Create (window)) {
+ if (!widget.HasFocus) {
+ cr.Rectangle (background_area.ToCairoRect ());
+ cr.SetSourceColor (Styles.ObjectValueTreeDisabledBackgroundColor);
+ cr.Fill ();
+ }
+
Pango.Rectangle ink, logical;
using (var layout = new Pango.Layout (Context)) {
layout.FontDescription = font;
- layout.SetMarkup (GetFileMarkup ((flags & CellRendererState.Selected) != 0));
+
+ var selected = (flags & CellRendererState.Selected) != 0;
+ var foregroundColor = Styles.GetStackFrameForegroundHexColor (selected, IsUserCode);
+
+ layout.SetMarkup (GetFileMarkup (selected, foregroundColor));
layout.GetPixelExtents (out ink, out logical);
var width = widget.Allocation.Width;
cr.Translate (width - logical.Width - 10, cell_area.Y);
@@ -832,7 +846,7 @@ widget ""*.exception_dialog_expander"" style ""exception-dialog-expander""
cr.IdentityMatrix ();
- layout.SetMarkup (GetMethodMarkup ((flags & CellRendererState.Selected) != 0));
+ layout.SetMarkup (GetMethodMarkup (selected, foregroundColor));
layout.Width = (int)((width - logical.Width - 35) * Pango.Scale.PangoScale);
layout.Ellipsize = Pango.EllipsizeMode.Middle;
cr.Translate (cell_area.X + 10, cell_area.Y);
@@ -1105,12 +1119,19 @@ widget ""*.exception_dialog_expander"" style ""exception-dialog-expander""
{
public override bool KeyPress (KeyDescriptor descriptor)
{
- if (descriptor.SpecialKey == SpecialKey.Escape && DebuggingService.ExceptionCaughtMessage != null &&
+ if (DebuggingService.ExceptionCaughtMessage != null &&
!DebuggingService.ExceptionCaughtMessage.IsMinimized &&
DebuggingService.ExceptionCaughtMessage.File.CanonicalPath == new FilePath (DocumentContext.Name).CanonicalPath) {
- DebuggingService.ExceptionCaughtMessage.ShowMiniButton ();
- return true;
+ if (descriptor.SpecialKey == SpecialKey.Escape) {
+ DebuggingService.ExceptionCaughtMessage.ShowMiniButton ();
+ return true;
+ }
+
+ if (descriptor.SpecialKey == SpecialKey.Return) {
+ DebuggingService.ExceptionCaughtMessage.ShowDialog ();
+ return false;
+ }
}
return base.KeyPress (descriptor);
diff --git a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/Styles.cs b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/Styles.cs
index 411e8c5eda..e65c855147 100644
--- a/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/Styles.cs
+++ b/main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger/Styles.cs
@@ -26,6 +26,7 @@
using MonoDevelop.Ide;
using Xwt.Drawing;
+using MonoDevelop.Components;
namespace MonoDevelop.Debugger
{
@@ -94,7 +95,13 @@ namespace MonoDevelop.Debugger
ExceptionCaughtDialog.ValueTreeBackgroundColor = Color.FromName ("#525252");
}
+ //Disabled state
+ ObjectValueTreeDisabledBackgroundColor = new Cairo.Color (0.64f, 0.64f, 0.64f);
+
// Shared
+ ObjectValueTreeSelectedTextColor = Ide.Gui.Styles.BaseSelectionTextColor.ToHexString (false);
+ ObjectValueTreeForegroundTextColor = Ide.Gui.Styles.BaseSelectionTextColor.ToHexString (false);
+ ObjectValueTreeExternalCodeForegroundTextColor = ExceptionCaughtDialog.ExternalCodeTextColor.ToHexString (false);
ObjectValueTreeValueErrorText = Ide.Gui.Styles.WarningForegroundColor;
@@ -102,6 +109,20 @@ namespace MonoDevelop.Debugger
PreviewVisualizerTextColor = Ide.Gui.Styles.PopoverWindow.DefaultTextColor;
PreviewVisualizerHeaderTextColor = Ide.Gui.Styles.PopoverWindow.DefaultTextColor;
}
+
+ public static string ObjectValueTreeSelectedTextColor { get; private set; }
+ public static string ObjectValueTreeForegroundTextColor { get; private set; }
+ public static string ObjectValueTreeExternalCodeForegroundTextColor { get; private set; }
+
+ public static Cairo.Color ObjectValueTreeDisabledBackgroundColor { get; private set; }
+
+ internal static string GetStackFrameForegroundHexColor (bool selected, bool isUserCode)
+ {
+ if (selected) {
+ return ObjectValueTreeSelectedTextColor;
+ }
+ return isUserCode ? ObjectValueTreeForegroundTextColor : ObjectValueTreeExternalCodeForegroundTextColor;
+ }
}
}
diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.Toolbox/IToolboxWidget.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.Toolbox/IToolboxWidget.cs
index 23045937ef..ae61656bc9 100644
--- a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.Toolbox/IToolboxWidget.cs
+++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.Toolbox/IToolboxWidget.cs
@@ -40,7 +40,6 @@ namespace MonoDevelop.DesignerSupport.Toolbox
IEnumerable<ToolboxWidgetCategory> Categories { get; }
IEnumerable<ToolboxWidgetItem> AllItems { get; }
- event EventHandler SelectedItemChanged;
event EventHandler ActivateSelectedItem;
void AddCategory (ToolboxWidgetCategory category);
diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.Toolbox/MacToolbox.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.Toolbox/MacToolbox.cs
index 470addae0c..4a3633ed96 100644
--- a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.Toolbox/MacToolbox.cs
+++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.Toolbox/MacToolbox.cs
@@ -62,7 +62,7 @@ namespace MonoDevelop.DesignerSupport.Toolbox
public event EventHandler<Gtk.TargetEntry []> DragSourceSet;
public event EventHandler ContentFocused;
- public ItemToolboxNode selectedNode;
+ public ItemToolboxNode SelectedNode => toolboxWidget.SelectedItem?.Node;
NativeViews.ToggleButton catToggleButton;
NativeViews.ToggleButton compactModeToggleButton;
@@ -180,7 +180,6 @@ namespace MonoDevelop.DesignerSupport.Toolbox
filterEntry.Changed += FilterEntry_Changed;
- toolboxWidget.SelectedItemChanged += ToolboxWidget_SelectedItemChanged;
toolboxWidget.DragBegin += ToolboxWidget_DragBegin;
toolboxWidget.MouseDownActivated += ToolboxWidget_MouseDownActivated;
toolboxWidget.ActivateSelectedItem += ToolboxWidget_ActivateSelectedItem;
@@ -205,15 +204,13 @@ namespace MonoDevelop.DesignerSupport.Toolbox
Refresh ();
}
- void ToolboxWidget_SelectedItemChanged (object sender, EventArgs e)
- {
- selectedNode = this.toolboxWidget.SelectedItem != null ? this.toolboxWidget.SelectedItem.Tag as ItemToolboxNode : null;
- toolboxService.SelectItem (selectedNode);
- }
-
void ToolboxWidget_ActivateSelectedItem (object sender, EventArgs e)
{
- toolboxService.UseSelectedItem ();
+ var selectedNode = SelectedNode;
+ if (selectedNode != null) {
+ DesignerSupport.Service.ToolboxService.SelectItem (selectedNode);
+ toolboxService.UseSelectedItem ();
+ }
}
void FilterEntry_Changed (object sender, EventArgs e)
@@ -438,13 +435,17 @@ namespace MonoDevelop.DesignerSupport.Toolbox
[CommandHandler (MonoDevelop.Ide.Commands.EditCommands.Delete)]
internal void OnDeleteItem ()
{
- if (MessageService.Confirm (GettextCatalog.GetString ("Are you sure you want to remove the selected Item?"), AlertButton.Delete))
- toolboxService.RemoveUserItem (selectedNode);
+ var selectedNode = SelectedNode;
+ if (selectedNode != null) {
+ if (MessageService.Confirm (GettextCatalog.GetString ("Are you sure you want to remove the selected Item?"), AlertButton.Delete))
+ toolboxService.RemoveUserItem (SelectedNode);
+ }
}
[CommandUpdateHandler (MonoDevelop.Ide.Commands.EditCommands.Delete)]
internal void OnUpdateDeleteItem (CommandInfo info)
{
+ var selectedNode = SelectedNode;
// Hack manually filter out gtk# widgets & container since they cannot be re added
// because they're missing the toolbox attributes.
info.Enabled = selectedNode != null && toolboxService.CanRemoveUserItem (selectedNode)
@@ -540,7 +541,6 @@ namespace MonoDevelop.DesignerSupport.Toolbox
toolboxAddButton.Activated -= ToolboxAddButton_Clicked;
toolboxAddButton.Focused -= ToolboxAddButton_Focused;
- toolboxWidget.SelectedItemChanged -= ToolboxWidget_SelectedItemChanged;
toolboxWidget.ActivateSelectedItem -= ToolboxWidget_ActivateSelectedItem;
toolboxWidget.MenuOpened -= ToolboxWidget_MenuOpened;
toolboxWidget.MouseDownActivated -= ToolboxWidget_MouseDownActivated;
@@ -560,12 +560,12 @@ namespace MonoDevelop.DesignerSupport.Toolbox
object IPropertyPadProvider.GetActiveComponent ()
{
- return selectedNode;
+ return SelectedNode;
}
object IPropertyPadProvider.GetProvider ()
{
- return selectedNode;
+ return SelectedNode;
}
void IPropertyPadProvider.OnEndEditing (object obj)
diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.Toolbox/MacToolboxWidget.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.Toolbox/MacToolboxWidget.cs
index 361798aca1..e52c52eb18 100644
--- a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.Toolbox/MacToolboxWidget.cs
+++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.Toolbox/MacToolboxWidget.cs
@@ -56,7 +56,6 @@ namespace MonoDevelop.DesignerSupport.Toolbox
public event EventHandler Focused;
public event EventHandler DragBegin;
public event EventHandler<CGPoint> MenuOpened;
- public event EventHandler SelectedItemChanged;
public event EventHandler ActivateSelectedItem;
public Action<NSEvent> MouseDownActivated { get; set; }
@@ -74,8 +73,6 @@ namespace MonoDevelop.DesignerSupport.Toolbox
internal void PerformActivateSelectedItem () => OnActivateSelectedItem (EventArgs.Empty);
void OnActivateSelectedItem (EventArgs args) => ActivateSelectedItem?.Invoke (this, args);
-
- void OnSelectedItemChanged (EventArgs args) => SelectedItemChanged?.Invoke (this, args);
NSIndexPath selectedIndexPath;
public NSIndexPath SelectedIndexPath {
@@ -85,7 +82,6 @@ namespace MonoDevelop.DesignerSupport.Toolbox
set {
if (selectedIndexPath != value) {
selectedIndexPath = value;
- OnSelectedItemChanged (EventArgs.Empty);
}
}
}
diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.Toolbox/ToolboxWidget.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.Toolbox/ToolboxWidget.cs
index 18d9ca7f3d..70a7f4462c 100644
--- a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.Toolbox/ToolboxWidget.cs
+++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.Toolbox/ToolboxWidget.cs
@@ -1149,8 +1149,7 @@ namespace MonoDevelop.DesignerSupport.Toolbox
}
}
- [Obsolete("This class should never have been public")]
- public class Item : IComparable<Item>
+ class Item : IComparable<Item>
{
ToolboxWidgetItem inner;
diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/DesignerSupportService.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/DesignerSupportService.cs
index 5af30a213a..10f6e33171 100644
--- a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/DesignerSupportService.cs
+++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/DesignerSupportService.cs
@@ -36,12 +36,11 @@ using System;
using System.Collections;
using Mono.Addins;
+using MonoDevelop.Core;
using MonoDevelop.Ide;
namespace MonoDevelop.DesignerSupport
{
-
-
public class DesignerSupportService
{
PropertyPad propertyPad = null;
@@ -78,10 +77,17 @@ namespace MonoDevelop.DesignerSupport
propertyPad.PropertyGrid.Changed += OnPropertyGridChanged;
}
else if (lastCustomProvider != null) {
- propertyPad.UseCustomWidget (lastCustomProvider.GetCustomPropertyWidget ());
- var customizer = lastCustomProvider as IPropertyPadCustomizer;
- if (customizer != null)
- customizer.Customize (pad.PadWindow, null);
+ try {
+ var currentCustomWidget = lastCustomProvider.GetCustomPropertyWidget ();
+ if (currentCustomWidget != null) {
+ propertyPad.UseCustomWidget (currentCustomWidget);
+ if (lastCustomProvider is IPropertyPadCustomizer customizer)
+ customizer.Customize (pad.PadWindow, null);
+ }
+ } catch (Exception ex) {
+ LoggingService.LogInternalError ($"There was an error trying to GetCustomPropertyWidget from '{lastCustomProvider.GetType ()}' provider", ex);
+ ReSetPad ();
+ }
}
}
}
@@ -174,12 +180,24 @@ namespace MonoDevelop.DesignerSupport
lastCustomProvider = provider;
if (propertyPad != null) {
- propertyPad.UseCustomWidget (provider.GetCustomPropertyWidget ());
- propertyPad.CommandRouteOrigin = commandRouteOrigin;
-
- var customizer = provider as IPropertyPadCustomizer;
- if (customizer != null)
- customizer.Customize (propertyPad.PadWindow, null);
+ try {
+ var customWidget = provider.GetCustomPropertyWidget ();
+ if (customWidget != null) {
+ propertyPad.UseCustomWidget (customWidget);
+ propertyPad.CommandRouteOrigin = commandRouteOrigin;
+
+ var customizer = provider as IPropertyPadCustomizer;
+ if (customizer != null)
+ customizer.Customize (propertyPad.PadWindow, null);
+ } else {
+ propertyPad?.BlankPad ();
+ return;
+ }
+ } catch (Exception ex) {
+ LoggingService.LogInternalError ($"There was an error trying to GetCustomPropertyWidget from '{lastCustomProvider.GetType ()}' provider", ex);
+ propertyPad?.BlankPad ();
+ return;
+ }
}
}
else {
diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/ToolboxPad.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/ToolboxPad.cs
index 1be634b3a0..b69333c078 100644
--- a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/ToolboxPad.cs
+++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport/ToolboxPad.cs
@@ -82,14 +82,17 @@ namespace MonoDevelop.DesignerSupport
targets.AddTable (e);
};
toolbox.DragBegin += (object sender, EventArgs e) => {
- if (!isDragging) {
+ var selectedNode = toolbox.SelectedNode;
+ if (!isDragging && selectedNode != null) {
+
+ DesignerSupport.Service.ToolboxService.SelectItem (selectedNode);
Gtk.Drag.SourceUnset (widget);
// Gtk.Application.CurrentEvent and other copied gdk_events seem to have a problem
// when used as they use gdk_event_copy which seems to crash on de-allocating the private slice.
IntPtr currentEvent = GtkWorkarounds.GetCurrentEventHandle ();
- Gtk.Drag.Begin (widget, targets, Gdk.DragAction.Copy | Gdk.DragAction.Move, 1, new Gdk.Event (currentEvent));
+ Gtk.Drag.Begin (widget, targets, Gdk.DragAction.Copy | Gdk.DragAction.Move, 1, new Gdk.Event (currentEvent, false));
// gtk_drag_begin does not store the event, so we're okay
GtkWorkarounds.FreeEvent (currentEvent);
diff --git a/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/DotNetCoreProjectSupportedTargetFrameworks.cs b/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/DotNetCoreProjectSupportedTargetFrameworks.cs
index 97be6b2649..9863575fb1 100644
--- a/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/DotNetCoreProjectSupportedTargetFrameworks.cs
+++ b/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/DotNetCoreProjectSupportedTargetFrameworks.cs
@@ -94,7 +94,7 @@ namespace MonoDevelop.DotNetCore
public static IEnumerable<TargetFramework> GetNetCoreAppTargetFrameworks ()
{
foreach (Version runtimeVersion in GetMajorRuntimeVersions ()) {
- if (runtimeVersion.Major == 3 && runtimeVersion.Minor > 0) {
+ if (runtimeVersion.Major > 3 || (runtimeVersion.Major == 3 && runtimeVersion.Minor > 0)) {
// Skip versions > 3.0 since this is not currently supported.
continue;
}
diff --git a/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/DotNetCoreSdk.cs b/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/DotNetCoreSdk.cs
index 3da4bca039..534c810f88 100644
--- a/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/DotNetCoreSdk.cs
+++ b/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/DotNetCoreSdk.cs
@@ -36,11 +36,10 @@ namespace MonoDevelop.DotNetCore
public static class DotNetCoreSdk
{
static readonly Version DotNetCoreVersion2_1 = new Version (2, 1, 0);
- static readonly DotNetCoreSdkPaths sdkPaths;
static DotNetCoreSdk ()
{
- sdkPaths = new DotNetCoreSdkPaths ();
+ var sdkPaths = new DotNetCoreSdkPaths ();
sdkPaths.ResolveSDK ();
Update (sdkPaths);
}
@@ -84,6 +83,8 @@ namespace MonoDevelop.DotNetCore
internal static DotNetCoreSdkPaths FindSdkPaths (string[] sdks)
{
+ var sdkPaths = new DotNetCoreSdkPaths ();
+ sdkPaths.ResolveSDK ();
sdkPaths.FindSdkPaths (sdks);
return sdkPaths;
}
diff --git a/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/MonoRuntimeInfoExtensions.cs b/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/MonoRuntimeInfoExtensions.cs
index f336abfb60..2e9a399908 100644
--- a/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/MonoRuntimeInfoExtensions.cs
+++ b/main/src/addins/MonoDevelop.DotNetCore/MonoDevelop.DotNetCore/MonoRuntimeInfoExtensions.cs
@@ -34,7 +34,7 @@ namespace MonoDevelop.DotNetCore
static readonly Version MonoVersion5_4 = new Version (5, 4, 0);
static readonly Version DotNetCore2_1 = new Version (2, 1);
- internal static Version CurrentRuntimeVersion { get; set; } = MonoRuntimeInfo.FromCurrentRuntime ().RuntimeVersion;
+ internal static Version CurrentRuntimeVersion { get; set; } = MonoRuntimeInfo.FromCurrentRuntime ()?.RuntimeVersion ?? new Version ();
public static bool SupportsNetStandard20 (this Version monoVersion)
{
diff --git a/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Tests/MonoDevelop.PackageManagement.Tests/DotNetCoreRestoreTests.cs b/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Tests/MonoDevelop.PackageManagement.Tests/DotNetCoreRestoreTests.cs
index 13e91f8a09..b501bd500e 100644
--- a/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Tests/MonoDevelop.PackageManagement.Tests/DotNetCoreRestoreTests.cs
+++ b/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Tests/MonoDevelop.PackageManagement.Tests/DotNetCoreRestoreTests.cs
@@ -63,7 +63,7 @@ namespace MonoDevelop.PackageManagement.Tests
}
[Test]
- public async Task OfflineRestore_NetCore22Project ()
+ public async Task OfflineRestore_NetCore21Project ()
{
FilePath solutionFileName = Util.GetSampleProject ("restore-netcore-offline", "dotnetcoreconsole.sln");
solution = (Solution)await Services.ProjectService.ReadWorkspaceItem (Util.GetMonitor (), solutionFileName);
diff --git a/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeActions/CodeFixMenuService.cs b/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeActions/CodeFixMenuService.cs
index 2f9a69c8dd..601bb3173e 100644
--- a/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeActions/CodeFixMenuService.cs
+++ b/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeActions/CodeFixMenuService.cs
@@ -186,11 +186,11 @@ namespace MonoDevelop.CodeActions
var item = new CodeFixMenuEntry (label, async delegate {
// Task.Run here so we don't end up binding the whole document on popping the menu, also there is no cancellation token support
- var fix = await Task.Run (() => {
- var context = fixState.CreateFixAllContext (new RoslynProgressTracker (), token);
- return provider.GetFixAsync (context);
- });
+
Microsoft.CodeAnalysis.Text.TextChange[] result = await Task.Run (async () => {
+ var context = fixState.CreateFixAllContext (new RoslynProgressTracker (), token);
+ var fix = await provider.GetFixAsync (context);
+
var previewOperations = await fix.GetPreviewOperationsAsync (token);
return await Runtime.RunInMainThread (() => {
var engine = Xwt.Toolkit.CurrentEngine; // NativeEngine
diff --git a/main/src/addins/MonoDevelop.UnitTesting/Commands/UnitTestCommands.cs b/main/src/addins/MonoDevelop.UnitTesting/Commands/UnitTestCommands.cs
index 5f776ccc60..6d0a84150d 100644
--- a/main/src/addins/MonoDevelop.UnitTesting/Commands/UnitTestCommands.cs
+++ b/main/src/addins/MonoDevelop.UnitTesting/Commands/UnitTestCommands.cs
@@ -44,7 +44,7 @@ namespace MonoDevelop.UnitTesting.Commands
GoToFailure,
RerunTest,
}
-
+
public enum TestChartCommands
{
ShowResults,
@@ -55,13 +55,20 @@ namespace MonoDevelop.UnitTesting.Commands
ShowFailedTests,
ShowIgnoredTests
}
-
+
public enum NUnitProjectCommands
{
AddAssembly
}
-
- class RunAllTestsHandler: CommandHandler
+
+ public enum TextEditorCommands
+ {
+ RunTestAtCaret,
+ DebugTestAtCaret,
+ SelectTestAtCaret
+ }
+
+ class RunAllTestsHandler : CommandHandler
{
protected override void Run ()
{
diff --git a/main/src/addins/MonoDevelop.UnitTesting/MonoDevelop.UnitTesting.addin.xml b/main/src/addins/MonoDevelop.UnitTesting/MonoDevelop.UnitTesting.addin.xml
index c2158343b2..4fd591a678 100644
--- a/main/src/addins/MonoDevelop.UnitTesting/MonoDevelop.UnitTesting.addin.xml
+++ b/main/src/addins/MonoDevelop.UnitTesting/MonoDevelop.UnitTesting.addin.xml
@@ -75,6 +75,9 @@
<Command id = "MonoDevelop.UnitTesting.Commands.TestChartCommands.ShowSuccessfulTests" _label = "Show successful tests" type="check"/>
<Command id = "MonoDevelop.UnitTesting.Commands.TestChartCommands.ShowFailedTests" _label = "Show failed tests" type="check"/>
<Command id = "MonoDevelop.UnitTesting.Commands.TestChartCommands.ShowIgnoredTests" _label = "Show ignored tests" type="check"/>
+ <Command id = "MonoDevelop.UnitTesting.Commands.TextEditorCommands.RunTestAtCaret" _label = "Run Test at Caret"/>
+ <Command id = "MonoDevelop.UnitTesting.Commands.TextEditorCommands.DebugTestAtCaret" _label = "Debug Test at Caret"/>
+ <Command id = "MonoDevelop.UnitTesting.Commands.TextEditorCommands.SelectTestAtCaret" _label = "Select Test at Caret"/>
</Category>
</Extension>
diff --git a/main/src/addins/MonoDevelop.UnitTesting/Services/AbstractUnitTestEditorExtension.cs b/main/src/addins/MonoDevelop.UnitTesting/Services/AbstractUnitTestEditorExtension.cs
index 58449a06a8..27464ad5b2 100644
--- a/main/src/addins/MonoDevelop.UnitTesting/Services/AbstractUnitTestEditorExtension.cs
+++ b/main/src/addins/MonoDevelop.UnitTesting/Services/AbstractUnitTestEditorExtension.cs
@@ -37,6 +37,8 @@ using MonoDevelop.Ide.Editor.Extension;
using MonoDevelop.Ide.Editor;
using MonoDevelop.Projects;
using Mono.Addins;
+using MonoDevelop.Components.Commands;
+using MonoDevelop.UnitTesting.Commands;
namespace MonoDevelop.UnitTesting
{
@@ -137,6 +139,36 @@ namespace MonoDevelop.UnitTesting
List<IUnitTestMarker> currentMarker = new List<IUnitTestMarker>();
+ TestRunner GetTestRunnerAtCaret (bool debug)
+ {
+ var line = Editor.GetLine (Editor.CaretLine);
+ if (line == null)
+ return null;
+ foreach (var marker in Editor.GetLineMarkers (line)) {
+ if (marker is IUnitTestMarker result)
+ return new TestRunner (result.UnitTest.UnitTestIdentifier, DocumentContext.Project, debug);
+ }
+ return null;
+ }
+
+ [CommandHandler (TextEditorCommands.RunTestAtCaret)]
+ protected void OnRunTestAtCaret ()
+ {
+ GetTestRunnerAtCaret (false)?.Run (this, EventArgs.Empty);
+ }
+
+ [CommandHandler (TextEditorCommands.DebugTestAtCaret)]
+ protected void OnDebugTestAtCaret ()
+ {
+ GetTestRunnerAtCaret (true)?.Run (this, EventArgs.Empty);
+ }
+
+ [CommandHandler (TextEditorCommands.SelectTestAtCaret)]
+ protected void OnSelectTestAtCaret ()
+ {
+ GetTestRunnerAtCaret (false)?.Select (this, EventArgs.Empty);
+ }
+
class UnitTestMarkerHostImpl : UnitTestMarkerHost
{
readonly AbstractUnitTestTextEditorExtension ext;
@@ -277,82 +309,70 @@ namespace MonoDevelop.UnitTesting
#endregion
- class TestRunner
- {
- readonly string testCase;
- readonly bool debug;
- IBuildTarget project;
-
- public TestRunner (string testCase, IBuildTarget project, bool debug)
- {
- this.testCase = testCase;
- this.debug = debug;
- this.project = project;
- }
-
- bool TimeoutHandler ()
- {
- var test = UnitTestService.SearchTestByDocumentId (testCase);
- if (test != null) {
- RunTest (test);
- timeoutHandler = 0;
- } else {
- return true;
- }
- return false;
- }
+ }
+ class TestRunner
+ {
+ readonly string testCase;
+ readonly bool debug;
+ IBuildTarget project;
- internal async void Run (object sender, EventArgs e)
- {
- if (IdeApp.ProjectOperations.IsBuilding (IdeApp.ProjectOperations.CurrentSelectedSolution) ||
- IdeApp.ProjectOperations.IsRunning (IdeApp.ProjectOperations.CurrentSelectedSolution))
- return;
+ public TestRunner (string testCase, IBuildTarget project, bool debug)
+ {
+ this.testCase = testCase;
+ this.debug = debug;
+ this.project = project;
+ }
- var foundTest = UnitTestService.SearchTestByDocumentId (testCase);
- if (foundTest != null) {
- RunTest (foundTest);
- return;
- }
+ internal async void Run (object sender, EventArgs e)
+ {
+ if (IdeApp.ProjectOperations.IsBuilding (IdeApp.ProjectOperations.CurrentSelectedSolution) ||
+ IdeApp.ProjectOperations.IsRunning (IdeApp.ProjectOperations.CurrentSelectedSolution))
+ return;
- bool buildBeforeExecuting = IdeApp.Preferences.BuildBeforeRunningTests;
+ var foundTest = UnitTestService.SearchTestByDocumentId (testCase);
+ if (foundTest != null) {
+ RunTest (foundTest);
+ return;
+ }
- if (buildBeforeExecuting) {
- await IdeApp.ProjectOperations.Build (project).Task;
- await UnitTestService.RefreshTests (CancellationToken.None);
- }
+ bool buildBeforeExecuting = IdeApp.Preferences.BuildBeforeRunningTests;
- foundTest = UnitTestService.SearchTestByDocumentId (testCase);
- if (foundTest != null)
- RunTest (foundTest);
- else
- UnitTestService.ReportExecutionError (GettextCatalog.GetString ("Unit test '{0}' could not be loaded.", testCase));
+ if (buildBeforeExecuting) {
+ await IdeApp.ProjectOperations.Build (project).Task;
+ await UnitTestService.RefreshTests (CancellationToken.None);
}
- internal void Select (object sender, EventArgs e)
- {
- var test = UnitTestService.SearchTestByDocumentId (testCase);
- if (test == null)
- return;
- UnitTestService.CurrentSelectedTest = test;
- }
+ foundTest = UnitTestService.SearchTestByDocumentId (testCase);
+ if (foundTest != null)
+ RunTest (foundTest);
+ else
+ UnitTestService.ReportExecutionError (GettextCatalog.GetString ("Unit test '{0}' could not be loaded.", testCase));
+ }
- void RunTest (UnitTest test)
- {
- var debugModeSet = Runtime.ProcessService.GetDebugExecutionMode ();
- Core.Execution.IExecutionHandler ctx = null;
- if (debug && debugModeSet != null) {
- foreach (var executionMode in debugModeSet.ExecutionModes) {
- if (test.CanRun (executionMode.ExecutionHandler)) {
- ctx = executionMode.ExecutionHandler;
- break;
- }
+ internal void Select (object sender, EventArgs e)
+ {
+ var test = UnitTestService.SearchTestByDocumentId (testCase);
+ if (test == null)
+ return;
+ UnitTestService.CurrentSelectedTest = test;
+ }
+
+ void RunTest (UnitTest test)
+ {
+ var debugModeSet = Runtime.ProcessService.GetDebugExecutionMode ();
+ Core.Execution.IExecutionHandler ctx = null;
+ if (debug && debugModeSet != null) {
+ foreach (var executionMode in debugModeSet.ExecutionModes) {
+ if (test.CanRun (executionMode.ExecutionHandler)) {
+ ctx = executionMode.ExecutionHandler;
+ break;
}
}
- // NUnitService.Instance.RunTest (test, ctx);
- var pad = IdeApp.Workbench.GetPad<TestPad> ();
- var content = (TestPad)pad.Content;
- content.RunTest (test, ctx);
}
+ // NUnitService.Instance.RunTest (test, ctx);
+ var pad = IdeApp.Workbench.GetPad<TestPad> ();
+ var content = (TestPad)pad.Content;
+ content.RunTest (test, ctx);
}
}
}
diff --git a/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl.Views/LogWidget.cs b/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl.Views/LogWidget.cs
index 4801dc0450..6ce42aff48 100644
--- a/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl.Views/LogWidget.cs
+++ b/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl.Views/LogWidget.cs
@@ -36,6 +36,7 @@ using Mono.TextEditor;
using System.Linq;
using MonoDevelop.Ide.Editor;
using MonoDevelop.Ide.Fonts;
+using Humanizer;
namespace MonoDevelop.VersionControl.Views
{
@@ -512,21 +513,15 @@ namespace MonoDevelop.VersionControl.Views
static void DateFunc (Gtk.TreeViewColumn tree_column, Gtk.CellRenderer cell, Gtk.TreeModel model, Gtk.TreeIter iter)
{
- CellRendererText renderer = (CellRendererText)cell;
- var rev = (Revision)model.GetValue (iter, 0);
- string day;
-
+ var renderer = (CellRendererText)cell;
+ var revision = (Revision)model.GetValue (iter, 0);
// Grab today's day and the start of tomorrow's day to make Today/Yesterday calculations.
var now = DateTime.Now;
- var age = new DateTime (now.Year, now.Month, now.Day).AddDays(1) - rev.Time;
- if (age.Days >= 0 && age.Days < 1) { // Check whether it's a commit that's less than a day away. Also discard future commits.
- day = GettextCatalog.GetString ("Today");
- } else if (age.Days < 2) { // Check whether it's a commit from yesterday.
- day = GettextCatalog.GetString ("Yesterday");
- } else {
- day = rev.Time.ToShortDateString ();
- }
- renderer.Text = string.Format ("{0} {1:HH:mm}", day, rev.Time);
+ var age = new DateTime (now.Year, now.Month, now.Day).AddDays (1) - revision.Time;
+
+ renderer.Text = age.Days >= 2 ?
+ revision.Time.ToShortDateString () :
+ revision.Time.Humanize (utcDate: false, dateToCompareAgainst: now);
}
static void GraphFunc (Gtk.TreeViewColumn tree_column, Gtk.CellRenderer cell, Gtk.TreeModel model, Gtk.TreeIter iter)
diff --git a/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl.csproj b/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl.csproj
index 63b2eef317..790a4e46b0 100644
--- a/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl.csproj
+++ b/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl.csproj
@@ -78,6 +78,10 @@
<HintPath>..\..\..\..\build\bin\Microsoft.VisualStudio.Text.UI.dll</HintPath>
<Private>False</Private>
</Reference>
+ <Reference Include="Humanizer">
+ <HintPath>..\..\..\..\packages\Humanizer.Core.2.2.0\lib\netstandard1.0\Humanizer.dll</HintPath>
+ <Private>False</Private>
+ </Reference>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="icons\added-overlay-16.png" />
@@ -516,10 +520,14 @@
<Compile Include="Gui\MonoDevelop.VersionControl.UrlBasedRepositoryEditor.cs" />
<Compile Include="Gui\MonoDevelop.VersionControl.Views.DiffWidget.cs" />
<Compile Include="Gui\MonoDevelop.VersionControl.Views.LogWidget.cs" />
+ <Compile Include="MonoDevelop.VersionControl\Instrumentation.cs" />
</ItemGroup>
<ItemGroup>
<InternalsVisibleTo Include="MonoDevelop.VersionControl.Git.Tests" />
<InternalsVisibleTo Include="MonoDevelop.MacDev" />
</ItemGroup>
+ <ItemGroup>
+ <None Include="packages.config" />
+ </ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>
diff --git a/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl/Instrumentation.cs b/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl/Instrumentation.cs
new file mode 100644
index 0000000000..402ec0183a
--- /dev/null
+++ b/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl/Instrumentation.cs
@@ -0,0 +1,163 @@
+//
+// Counters.cs
+//
+// Author:
+// Vsevolod Kukol <sevoku@microsoft.com>
+//
+// Copyright (c) 2019 (c) Microsoft Corporation
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+using MonoDevelop.Core.Instrumentation;
+using System.Threading;
+using MonoDevelop.Core;
+
+namespace MonoDevelop.VersionControl
+{
+ static class Instrumentation
+ {
+ const string Category = "Version Control";
+ const string Identifier = "VersionControl";
+
+ public static readonly Counter<RepositoryMetadata> Repositories = InstrumentationService.CreateCounter<RepositoryMetadata> ("VersionControl.RepositoryOpened", Category, id: $"{Identifier}.RepositoryOpened");
+ public static readonly TimerCounter<MultipathOperationMetadata> CheckoutCounter = InstrumentationService.CreateTimerCounter<MultipathOperationMetadata> ("Checkout", Category, id: $"{Identifier}.Checkout");
+ public static readonly TimerCounter<MultipathOperationMetadata> CommitCounter = InstrumentationService.CreateTimerCounter<MultipathOperationMetadata> ("Commit", Category, id: $"{Identifier}.Commit");
+ public static readonly TimerCounter<RevertMetadata> RevertCounter = InstrumentationService.CreateTimerCounter<RevertMetadata> ("Revert", Category, id: $"{Identifier}.Revert");
+ public static readonly TimerCounter<PublishMetadata> PublishCounter = InstrumentationService.CreateTimerCounter<PublishMetadata> ("Publish", Category, id: $"{Identifier}.Publish");
+ public static readonly TimerCounter<MultipathOperationMetadata> UpdateCounter = InstrumentationService.CreateTimerCounter<MultipathOperationMetadata> ("Update", Category, id: $"{Identifier}.Update");
+ public static readonly TimerCounter<MultipathOperationMetadata> AddCounter = InstrumentationService.CreateTimerCounter<MultipathOperationMetadata> ("Add", Category, id: $"{Identifier}.Add");
+ public static readonly TimerCounter<MoveMetadata> MoveCounter = InstrumentationService.CreateTimerCounter<MoveMetadata> ("Move", Category, id: $"{Identifier}.Move");
+ public static readonly TimerCounter<DeleteMetadata> DeleteCounter = InstrumentationService.CreateTimerCounter<DeleteMetadata> ("Delete", Category, id: $"{Identifier}.Delete");
+ public static readonly TimerCounter<MultipathOperationMetadata> LockCounter = InstrumentationService.CreateTimerCounter<MultipathOperationMetadata> ("Lock", Category, id: $"{Identifier}.Lock");
+ public static readonly TimerCounter<MultipathOperationMetadata> UnlockCounter = InstrumentationService.CreateTimerCounter<MultipathOperationMetadata> ("Unlock", Category, id: $"{Identifier}.Unlock");
+ public static readonly TimerCounter<MultipathOperationMetadata> IgnoreCounter = InstrumentationService.CreateTimerCounter<MultipathOperationMetadata> ("Ignore", Category, id: $"{Identifier}.Ignore");
+ public static readonly TimerCounter<MultipathOperationMetadata> UnignoreCounter = InstrumentationService.CreateTimerCounter<MultipathOperationMetadata> ("Unignore", Category, id: $"{Identifier}.Unignore");
+
+ public static readonly TimerCounter<RepositoryMetadata> GetRevisionChangesCounter = InstrumentationService.CreateTimerCounter<RepositoryMetadata> ("Get Revision Changes", Category, id: $"{Identifier}.GetRevisionChanges");
+ public static readonly TimerCounter<RepositoryMetadata> GetHistoryCounter = InstrumentationService.CreateTimerCounter<RepositoryMetadata> ("Get History", Category, id: $"{Identifier}.GetHistory");
+ }
+
+ class MultipathOperationMetadata : RepositoryMetadata
+ {
+ public MultipathOperationMetadata ()
+ {
+ }
+
+ public MultipathOperationMetadata (VersionControlSystem versionControl) : base (versionControl)
+ {
+ }
+
+ public int PathsCount {
+ get => GetProperty<int> ();
+ set => SetProperty (value);
+ }
+
+ public bool Recursive {
+ get => GetProperty<bool> ();
+ set => SetProperty (value);
+ }
+ }
+
+ class RevertMetadata : MultipathOperationMetadata
+ {
+ public enum RevertType
+ {
+ LocalChanges,
+ ToRevision,
+ SpecificRevision
+ };
+
+ public RevertMetadata ()
+ {
+ }
+
+ public RevertMetadata (VersionControlSystem versionControl) : base (versionControl)
+ {
+ }
+
+ public RevertType OperationType {
+ get => GetProperty<RevertType> ();
+ set => SetProperty (value);
+ }
+ }
+
+ class PublishMetadata : MultipathOperationMetadata
+ {
+ public PublishMetadata ()
+ {
+ }
+
+ public PublishMetadata (VersionControlSystem versionControl) : base (versionControl)
+ {
+ }
+
+ public bool SubFolder {
+ get => GetProperty<bool> ();
+ set => SetProperty (value);
+ }
+ }
+
+ class DeleteMetadata : MultipathOperationMetadata
+ {
+ public DeleteMetadata ()
+ {
+ }
+
+ public DeleteMetadata (VersionControlSystem versionControl) : base (versionControl)
+ {
+ }
+
+ public bool Force {
+ get => GetProperty<bool> ();
+ set => SetProperty (value);
+ }
+
+ public bool KeepLocal {
+ get => GetProperty<bool> ();
+ set => SetProperty (value);
+ }
+ }
+
+ class MoveMetadata : RepositoryMetadata
+ {
+ public enum MoveType
+ {
+ File,
+ Directory
+ }
+
+ public MoveMetadata ()
+ {
+ }
+
+ public MoveMetadata (VersionControlSystem versionControl) : base (versionControl)
+ {
+ }
+
+ public bool Force {
+ get => GetProperty<bool> ();
+ set => SetProperty (value);
+ }
+
+ public MoveType OperationType {
+ get => GetProperty<MoveType> ();
+ set => SetProperty (value);
+ }
+ }
+}
diff --git a/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl/Repository.cs b/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl/Repository.cs
index 12f642acf8..f5b4c4b020 100644
--- a/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl/Repository.cs
+++ b/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl/Repository.cs
@@ -468,7 +468,14 @@ namespace MonoDevelop.VersionControl
/// </param>
public RevisionPath[] GetRevisionChanges (Revision revision)
{
- return OnGetRevisionChanges (revision);
+ using (var tracker = Instrumentation.GetRevisionChangesCounter.BeginTiming (new RepositoryMetadata (VersionControlSystem))) {
+ try {
+ return OnGetRevisionChanges (revision);
+ } catch {
+ tracker.Metadata.SetFailure ();
+ throw;
+ }
+ }
}
@@ -478,7 +485,14 @@ namespace MonoDevelop.VersionControl
// Returns the revision history of a file
public Revision[] GetHistory (FilePath localFile, Revision since)
{
- return OnGetHistory (localFile, since);
+ using (var tracker = Instrumentation.GetHistoryCounter.BeginTiming (new RepositoryMetadata (VersionControlSystem))) {
+ try {
+ return OnGetHistory (localFile, since);
+ } catch {
+ tracker.Metadata.SetFailure ();
+ throw;
+ }
+ }
}
protected abstract Revision[] OnGetHistory (FilePath localFile, Revision since);
@@ -505,9 +519,17 @@ namespace MonoDevelop.VersionControl
// repository directory (must use absolute local paths).
public Repository Publish (string serverPath, FilePath localPath, FilePath[] files, string message, ProgressMonitor monitor)
{
- var res = OnPublish (serverPath, localPath, files, message, monitor);
- ClearCachedVersionInfo (localPath);
- return res;
+ var metadata = new PublishMetadata (VersionControlSystem) { PathsCount = files.Length, SubFolder = localPath.IsChildPathOf (RootPath) };
+ using (var tracker = Instrumentation.PublishCounter.BeginTiming (metadata, monitor.CancellationToken)) {
+ try {
+ var res = OnPublish (serverPath, localPath, files, message, monitor);
+ ClearCachedVersionInfo (localPath);
+ return res;
+ } catch {
+ metadata.SetFailure ();
+ throw;
+ }
+ }
}
protected abstract Repository OnPublish (string serverPath, FilePath localPath, FilePath[] files, string message, ProgressMonitor monitor);
@@ -521,8 +543,16 @@ namespace MonoDevelop.VersionControl
public void Update (FilePath[] localPaths, bool recurse, ProgressMonitor monitor)
{
- OnUpdate (localPaths, recurse, monitor);
- ClearCachedVersionInfo (localPaths);
+ var metadata = new MultipathOperationMetadata (VersionControlSystem) { PathsCount = localPaths.Length, Recursive = recurse };
+ using (var tracker = Instrumentation.UpdateCounter.BeginTiming (metadata, monitor.CancellationToken)) {
+ try {
+ OnUpdate (localPaths, recurse, monitor);
+ ClearCachedVersionInfo (localPaths);
+ } catch {
+ metadata.SetFailure ();
+ throw;
+ }
+ }
}
protected abstract void OnUpdate (FilePath[] localPaths, bool recurse, ProgressMonitor monitor);
@@ -553,8 +583,16 @@ namespace MonoDevelop.VersionControl
// Commits changes in a set of files or directories into the repository
public void Commit (ChangeSet changeSet, ProgressMonitor monitor)
{
- ClearCachedVersionInfo (changeSet.BaseLocalPath);
- OnCommit (changeSet, monitor);
+ var metadata = new MultipathOperationMetadata (VersionControlSystem) { PathsCount = changeSet.Count };
+ using (var tracker = Instrumentation.CommitCounter.BeginTiming (metadata, monitor.CancellationToken)) {
+ try {
+ ClearCachedVersionInfo (changeSet.BaseLocalPath);
+ OnCommit (changeSet, monitor);
+ } catch {
+ metadata.SetFailure ();
+ throw;
+ }
+ }
}
protected abstract void OnCommit (ChangeSet changeSet, ProgressMonitor monitor);
@@ -567,16 +605,37 @@ namespace MonoDevelop.VersionControl
public void Checkout (FilePath targetLocalPath, Revision rev, bool recurse, ProgressMonitor monitor)
{
- ClearCachedVersionInfo (targetLocalPath);
- OnCheckout (targetLocalPath, rev, recurse, monitor);
+ var metadata = new MultipathOperationMetadata (VersionControlSystem) { Recursive = recurse };
+ using (var tracker = Instrumentation.CheckoutCounter.BeginTiming (metadata, monitor.CancellationToken)) {
+ try {
+ ClearCachedVersionInfo (targetLocalPath);
+ OnCheckout (targetLocalPath, rev, recurse, monitor);
+
+ if (!Directory.Exists (targetLocalPath))
+ metadata.SetFailure ();
+ else
+ metadata.SetSuccess ();
+ } catch {
+ metadata.SetFailure ();
+ throw;
+ }
+ }
}
protected abstract void OnCheckout (FilePath targetLocalPath, Revision rev, bool recurse, ProgressMonitor monitor);
public void Revert (FilePath[] localPaths, bool recurse, ProgressMonitor monitor)
{
- ClearCachedVersionInfo (localPaths);
- OnRevert (localPaths, recurse, monitor);
+ var metadata = new RevertMetadata (VersionControlSystem) { PathsCount = localPaths.Length, Recursive = recurse, OperationType = RevertMetadata.RevertType.LocalChanges };
+ using (var tracker = Instrumentation.RevertCounter.BeginTiming (metadata, monitor.CancellationToken)) {
+ try {
+ ClearCachedVersionInfo (localPaths);
+ OnRevert (localPaths, recurse, monitor);
+ } catch {
+ metadata.SetFailure ();
+ throw;
+ }
+ }
}
public void Revert (FilePath localPath, bool recurse, ProgressMonitor monitor)
@@ -588,16 +647,32 @@ namespace MonoDevelop.VersionControl
public void RevertRevision (FilePath localPath, Revision revision, ProgressMonitor monitor)
{
- ClearCachedVersionInfo (localPath);
- OnRevertRevision (localPath, revision, monitor);
+ var metadata = new RevertMetadata (VersionControlSystem) { PathsCount = 1, Recursive = true, OperationType = RevertMetadata.RevertType.SpecificRevision };
+ using (var tracker = Instrumentation.RevertCounter.BeginTiming (metadata, monitor.CancellationToken)) {
+ try {
+ ClearCachedVersionInfo (localPath);
+ OnRevertRevision (localPath, revision, monitor);
+ } catch {
+ metadata.SetFailure ();
+ throw;
+ }
+ }
}
protected abstract void OnRevertRevision (FilePath localPath, Revision revision, ProgressMonitor monitor);
public void RevertToRevision (FilePath localPath, Revision revision, ProgressMonitor monitor)
{
- ClearCachedVersionInfo (localPath);
- OnRevertToRevision (localPath, revision, monitor);
+ var metadata = new RevertMetadata (VersionControlSystem) { PathsCount = 1, Recursive = true, OperationType = RevertMetadata.RevertType.ToRevision };
+ using (var tracker = Instrumentation.RevertCounter.BeginTiming (metadata, monitor.CancellationToken)) {
+ try {
+ ClearCachedVersionInfo (localPath);
+ OnRevertToRevision (localPath, revision, monitor);
+ } catch {
+ metadata.SetFailure ();
+ throw;
+ }
+ }
}
protected abstract void OnRevertToRevision (FilePath localPath, Revision revision, ProgressMonitor monitor);
@@ -610,12 +685,17 @@ namespace MonoDevelop.VersionControl
public void Add (FilePath[] localPaths, bool recurse, ProgressMonitor monitor)
{
- try {
- OnAdd (localPaths, recurse, monitor);
- } catch (Exception e) {
- LoggingService.LogError ("Failed to add file", e);
+ var metadata = new MultipathOperationMetadata (VersionControlSystem) { PathsCount = localPaths.Length, Recursive = recurse };
+ using (var tracker = Instrumentation.AddCounter.BeginTiming (metadata, monitor.CancellationToken)) {
+ try {
+ OnAdd (localPaths, recurse, monitor);
+ } catch (Exception e) {
+ LoggingService.LogError ("Failed to add file", e);
+ metadata.SetFailure ();
+ } finally {
+ ClearCachedVersionInfo (localPaths);
+ }
}
- ClearCachedVersionInfo (localPaths);
}
protected abstract void OnAdd (FilePath[] localPaths, bool recurse, ProgressMonitor monitor);
@@ -635,11 +715,15 @@ namespace MonoDevelop.VersionControl
public void MoveFile (FilePath localSrcPath, FilePath localDestPath, bool force, ProgressMonitor monitor)
{
ClearCachedVersionInfo (localSrcPath, localDestPath);
- try {
- OnMoveFile (localSrcPath, localDestPath, force, monitor);
- } catch (Exception e) {
- LoggingService.LogError ("Failed to move file", e);
- File.Move (localSrcPath, localDestPath);
+ var metadata = new MoveMetadata (VersionControlSystem) { Force = force, OperationType = MoveMetadata.MoveType.File };
+ using (var tracker = Instrumentation.MoveCounter.BeginTiming (metadata, monitor.CancellationToken)) {
+ try {
+ OnMoveFile (localSrcPath, localDestPath, force, monitor);
+ } catch (Exception e) {
+ LoggingService.LogError ("Failed to move file", e);
+ metadata.SetFailure ();
+ File.Move (localSrcPath, localDestPath);
+ }
}
}
@@ -653,11 +737,15 @@ namespace MonoDevelop.VersionControl
public void MoveDirectory (FilePath localSrcPath, FilePath localDestPath, bool force, ProgressMonitor monitor)
{
ClearCachedVersionInfo (localSrcPath, localDestPath);
- try {
- OnMoveDirectory (localSrcPath, localDestPath, force, monitor);
- } catch (Exception e) {
- LoggingService.LogError ("Failed to move directory", e);
- FileService.SystemDirectoryRename (localSrcPath, localDestPath);
+ var metadata = new MoveMetadata (VersionControlSystem) { Force = force, OperationType = MoveMetadata.MoveType.Directory };
+ using (var tracker = Instrumentation.MoveCounter.BeginTiming (metadata, monitor.CancellationToken)) {
+ try {
+ OnMoveDirectory (localSrcPath, localDestPath, force, monitor);
+ } catch (Exception e) {
+ LoggingService.LogError ("Failed to move directory", e);
+ metadata.SetFailure ();
+ FileService.SystemDirectoryRename (localSrcPath, localDestPath);
+ }
}
}
@@ -675,13 +763,17 @@ namespace MonoDevelop.VersionControl
public void DeleteFiles (FilePath[] localPaths, bool force, ProgressMonitor monitor, bool keepLocal = true)
{
- try {
- OnDeleteFiles (localPaths, force, monitor, keepLocal);
- } catch (Exception e) {
- LoggingService.LogError ("Failed to delete file", e);
- if (!keepLocal)
- foreach (var path in localPaths)
- File.Delete (path);
+ var metadata = new DeleteMetadata (VersionControlSystem) { PathsCount = localPaths.Length, Force = force, KeepLocal = keepLocal };
+ using (var tracker = Instrumentation.DeleteCounter.BeginTiming (metadata, monitor.CancellationToken)) {
+ try {
+ OnDeleteFiles (localPaths, force, monitor, keepLocal);
+ } catch (Exception e) {
+ LoggingService.LogError ("Failed to delete file", e);
+ metadata.SetFailure ();
+ if (!keepLocal)
+ foreach (var path in localPaths)
+ File.Delete (path);
+ }
}
ClearCachedVersionInfo (localPaths);
}
@@ -695,13 +787,17 @@ namespace MonoDevelop.VersionControl
public void DeleteDirectories (FilePath[] localPaths, bool force, ProgressMonitor monitor, bool keepLocal = true)
{
- try {
- OnDeleteDirectories (localPaths, force, monitor, keepLocal);
- } catch (Exception e) {
- LoggingService.LogError ("Failed to delete directory", e);
- if (!keepLocal)
- foreach (var path in localPaths)
- Directory.Delete (path, true);
+ var metadata = new DeleteMetadata (VersionControlSystem) { PathsCount = localPaths.Length, Force = force, KeepLocal = keepLocal };
+ using (var tracker = Instrumentation.DeleteCounter.BeginTiming (metadata, monitor.CancellationToken)) {
+ try {
+ OnDeleteDirectories (localPaths, force, monitor, keepLocal);
+ } catch (Exception e) {
+ LoggingService.LogError ("Failed to delete directory", e);
+ metadata.SetFailure ();
+ if (!keepLocal)
+ foreach (var path in localPaths)
+ Directory.Delete (path, true);
+ }
}
ClearCachedVersionInfo (localPaths);
}
@@ -733,8 +829,16 @@ namespace MonoDevelop.VersionControl
// Locks a file in the repository so no other users can change it
public void Lock (ProgressMonitor monitor, params FilePath[] localPaths)
{
- ClearCachedVersionInfo (localPaths);
- OnLock (monitor, localPaths);
+ var metadata = new MultipathOperationMetadata (VersionControlSystem) { PathsCount = localPaths.Length };
+ using (var tracker = Instrumentation.LockCounter.BeginTiming (metadata, monitor.CancellationToken)) {
+ try {
+ ClearCachedVersionInfo (localPaths);
+ OnLock (monitor, localPaths);
+ } catch {
+ metadata.SetFailure ();
+ throw;
+ }
+ }
}
// Locks a file in the repository so no other users can change it
@@ -746,8 +850,16 @@ namespace MonoDevelop.VersionControl
// Unlocks a file in the repository so other users can change it
public void Unlock (ProgressMonitor monitor, params FilePath[] localPaths)
{
- ClearCachedVersionInfo (localPaths);
- OnUnlock (monitor, localPaths);
+ var metadata = new MultipathOperationMetadata (VersionControlSystem) { PathsCount = localPaths.Length };
+ using (var tracker = Instrumentation.UnlockCounter.BeginTiming (metadata, monitor.CancellationToken)) {
+ try {
+ ClearCachedVersionInfo (localPaths);
+ OnUnlock (monitor, localPaths);
+ } catch {
+ metadata.SetFailure ();
+ throw;
+ }
+ }
}
protected virtual void OnUnlock (ProgressMonitor monitor, params FilePath[] localPaths)
@@ -882,8 +994,16 @@ namespace MonoDevelop.VersionControl
// Ignores a file for version control operations.
public void Ignore (FilePath[] localPath)
{
- ClearCachedVersionInfo (localPath);
- OnIgnore (localPath);
+ var metadata = new MultipathOperationMetadata (VersionControlSystem) { PathsCount = localPath.Length };
+ using (var tracker = Instrumentation.IgnoreCounter.BeginTiming (metadata)) {
+ try {
+ ClearCachedVersionInfo (localPath);
+ OnIgnore (localPath);
+ } catch {
+ metadata.SetFailure ();
+ throw;
+ }
+ }
}
protected abstract void OnIgnore (FilePath[] localPath);
@@ -891,8 +1011,16 @@ namespace MonoDevelop.VersionControl
// Unignores a file for version control operations.
public void Unignore (FilePath[] localPath)
{
- ClearCachedVersionInfo (localPath);
- OnUnignore (localPath);
+ var metadata = new MultipathOperationMetadata (VersionControlSystem) { PathsCount = localPath.Length };
+ using (var tracker = Instrumentation.UnignoreCounter.BeginTiming (metadata)) {
+ try {
+ ClearCachedVersionInfo (localPath);
+ OnUnignore (localPath);
+ } catch {
+ metadata.SetFailure ();
+ throw;
+ }
+ }
}
protected abstract void OnUnignore (FilePath[] localPath);
diff --git a/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl/VersionControlService.cs b/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl/VersionControlService.cs
index 6f43ccae81..aa25a066f2 100644
--- a/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl/VersionControlService.cs
+++ b/main/src/addins/VersionControl/MonoDevelop.VersionControl/MonoDevelop.VersionControl/VersionControlService.cs
@@ -226,7 +226,6 @@ namespace MonoDevelop.VersionControl
return repo;
}
- readonly static Counter<RepositoryMetadata> Repositories = InstrumentationService.CreateCounter<RepositoryMetadata> ("VersionControl.RepositoryOpened", "Version Control", id:"VersionControl.RepositoryOpened");
internal static readonly Dictionary<FilePath,Repository> repositoryCache = new Dictionary<FilePath,Repository> ();
public static Repository GetRepositoryReference (string path, string id)
{
@@ -257,10 +256,7 @@ namespace MonoDevelop.VersionControl
var repo = detectedVCS?.GetRepositoryReference (bestMatch, id);
if (repo != null) {
repositoryCache.Add (bestMatch, repo);
- Repositories.Inc (new RepositoryMetadata {
- Type = detectedVCS.Name,
- Version = detectedVCS.Version,
- });
+ Instrumentation.Repositories.Inc (new RepositoryMetadata (detectedVCS));
}
return repo;
} catch (Exception e) {
@@ -841,10 +837,17 @@ namespace MonoDevelop.VersionControl
Other
}
- public class RepositoryMetadata : CounterMetadata
+ class RepositoryMetadata : CounterMetadata
{
public RepositoryMetadata ()
{
+ throw new InvalidOperationException ();
+ }
+
+ public RepositoryMetadata (VersionControlSystem versionControl)
+ {
+ Type = versionControl?.Name;
+ Version = versionControl?.Version;
}
public string Type {
diff --git a/main/src/addins/VersionControl/MonoDevelop.VersionControl/packages.config b/main/src/addins/VersionControl/MonoDevelop.VersionControl/packages.config
new file mode 100644
index 0000000000..f3aeebbbc7
--- /dev/null
+++ b/main/src/addins/VersionControl/MonoDevelop.VersionControl/packages.config
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="Humanizer.Core" version="2.2.0" targetFramework="net471" />
+</packages> \ No newline at end of file
diff --git a/main/src/addins/Xml/Completion/XmlSchemaCompletionData.cs b/main/src/addins/Xml/Completion/XmlSchemaCompletionData.cs
index 0ecc94b5a9..27562c546d 100644
--- a/main/src/addins/Xml/Completion/XmlSchemaCompletionData.cs
+++ b/main/src/addins/Xml/Completion/XmlSchemaCompletionData.cs
@@ -66,17 +66,6 @@ namespace MonoDevelop.Xml.Completion
}
/// <summary>
- /// Creates completion data from the schema passed in
- /// via the reader object.
- /// </summary>
- [Obsolete ("Please pass in a TextReader instead")]
- public XmlSchemaCompletionData(XmlTextReader reader)
- {
- reader.XmlResolver = new LocalOnlyXmlResolver ();
- ReadSchema(reader);
- }
-
- /// <summary>
/// Creates the completion data from the specified schema file.
/// </summary>
public XmlSchemaCompletionData (string fileName) : this (String.Empty, fileName)
diff --git a/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/Document/TextDocument.cs b/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/Document/TextDocument.cs
index 4ac4cf29c3..6138d7529e 100644
--- a/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/Document/TextDocument.cs
+++ b/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/Document/TextDocument.cs
@@ -1,22 +1,22 @@
-//
+//
// TextDocument.cs
-//
+//
// Author:
// Mike Krüger <mkrueger@xamarin.com>
-//
+//
// Copyright (c) 2007 Novell, Inc (http://www.novell.com)
// Copyright (c) 2012 Xamarin Inc. (http://xamarin.com)
-//
+//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
-//
+//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
-//
+//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -42,6 +42,9 @@ using MonoDevelop.Core.Text;
using MonoDevelop.Ide;
using MonoDevelop.Ide.Editor;
using MonoDevelop.Ide.Editor.Highlighting;
+using Microsoft.VisualStudio.Platform;
+using Microsoft.VisualStudio.Text.Tagging;
+using Microsoft.VisualStudio.Utilities;
namespace Mono.TextEditor
{
@@ -133,7 +136,7 @@ namespace Mono.TextEditor
{
if (e == MonoDevelop.Ide.Editor.LineEventArgs.AllLines) {
CommitUpdateAll (true);
- } else {
+ } else {
CommitMultipleLineUpdate (e.Line.LineNumber, e.Line.LineNumber, true);
}
}
@@ -235,8 +238,8 @@ namespace Mono.TextEditor
}
var textChange = new TextChangeEventArgs(changes);
- InterruptFoldWorker();
TextChanging?.Invoke (this, textChange);
+
// After TextChanging notification has been sent, we can update the cached snapshot
this.currentSnapshot = args.After;
}
@@ -372,7 +375,7 @@ namespace Mono.TextEditor
{
ReplaceText (offset, count, (string)null);
}
-
+
public void RemoveText (ISegment segment)
{
RemoveText (segment.Offset, segment.Length);
@@ -430,17 +433,17 @@ namespace Mono.TextEditor
{
return GetTextBetween (LocationToOffset (start), LocationToOffset (end));
}
-
+
public string GetTextBetween (int startLine, int startColumn, int endLine, int endColumn)
{
return GetTextBetween (LocationToOffset (startLine, startColumn), LocationToOffset (endLine, endColumn));
}
-
+
public string GetTextAt (int offset, int count)
{
return this.currentSnapshot.GetText(offset, count);
}
-
+
public string GetTextAt (DocumentRegion region)
{
return GetTextAt (region.GetSegment (this));
@@ -465,13 +468,13 @@ namespace Mono.TextEditor
var lineSegment = GetLine (line);
return lineSegment != null ? GetTextAt (lineSegment.Offset, lineSegment.Length) : null;
}
-
+
public string GetLineText (int line, bool includeDelimiter)
{
var lineSegment = GetLine (line);
return GetTextAt (lineSegment.Offset, includeDelimiter ? lineSegment.LengthIncludingDelimiter : lineSegment.Length);
}
-
+
public char GetCharAt (int offset)
{
return this.currentSnapshot[offset];
@@ -563,7 +566,7 @@ namespace Mono.TextEditor
{
return Text.IndexOfAny (anyOf, startIndex, count);
}
-
+
/// <summary>
/// Gets the index of the first occurrence of the specified search text in this text source.
/// </summary>
@@ -576,7 +579,7 @@ namespace Mono.TextEditor
{
return Text.IndexOf (searchText, startIndex, count, comparisonType);
}
-
+
/// <summary>
/// Gets the index of the last occurrence of the specified character in this text source.
/// </summary>
@@ -590,7 +593,7 @@ namespace Mono.TextEditor
{
return Text.LastIndexOf (c, startIndex, count);
}
-
+
/// <summary>
/// Gets the index of the last occurrence of the specified search text in this text source.
/// </summary>
@@ -655,12 +658,12 @@ namespace Mono.TextEditor
DocumentLine documentLine = GetLine(line);
return System.Math.Min(Length, documentLine.Offset + System.Math.Max(0, System.Math.Min(documentLine.Length, column - 1)));
}
-
+
public int LocationToOffset (DocumentLocation location)
{
return LocationToOffset(location.Line, location.Column);
}
-
+
public DocumentLocation OffsetToLocation (int offset)
{
IDocumentLine line = this.GetLineByOffset(offset);
@@ -675,19 +678,19 @@ namespace Mono.TextEditor
{
return GetLineIndent (GetLine (lineNumber));
}
-
+
public string GetLineIndent (DocumentLine segment)
{
if (segment == null)
return "";
return segment.GetIndentation (this);
}
-
+
public DocumentLine GetLine (int lineNumber)
{
if (lineNumber < DocumentLocation.MinLine)
return null;
-
+
return this.Get (lineNumber);
}
@@ -751,12 +754,12 @@ namespace Mono.TextEditor
return changes;
}
}
-
+
public object Tag {
get;
set;
}
-
+
protected UndoOperation()
{
// The type is in the consolidated editor implementation assembly
@@ -785,7 +788,7 @@ namespace Mono.TextEditor
if (fireEvent)
OnUndoDone ();
}
-
+
public virtual void Redo (TextDocument doc, bool fireEvent = true)
{
if (this.Changes.Count > 0) {
@@ -800,14 +803,14 @@ namespace Mono.TextEditor
if (fireEvent)
OnRedoDone ();
}
-
+
protected virtual void OnUndoDone ()
{
if (UndoDone != null)
UndoDone (this, EventArgs.Empty);
}
public event EventHandler UndoDone;
-
+
protected virtual void OnRedoDone ()
{
if (RedoDone != null)
@@ -815,7 +818,7 @@ namespace Mono.TextEditor
}
public event EventHandler RedoDone;
}
-
+
class AtomicUndoOperation : UndoOperation
{
OperationType operationType;
@@ -826,7 +829,7 @@ namespace Mono.TextEditor
return operationType;
}
}
-
+
public List<UndoOperation> Operations {
get {
return operations;
@@ -843,18 +846,18 @@ namespace Mono.TextEditor
{
this.operationType = operationType;
}
-
+
public void Insert (int index, UndoOperation operation)
{
operations.Insert (index, operation);
}
-
+
public void Add (UndoOperation operation)
{
operations.Add (operation);
}
-
+
public override void Undo (TextDocument doc, bool fireEvent = true)
{
doc.BeginAtomicUndo (operationType);
@@ -869,7 +872,7 @@ namespace Mono.TextEditor
if (fireEvent)
OnUndoDone ();
}
-
+
public override void Redo (TextDocument doc, bool fireEvent = true)
{
doc.BeginAtomicUndo (operationType);
@@ -885,11 +888,11 @@ namespace Mono.TextEditor
OnRedoDone ();
}
}
-
+
class KeyboardStackUndo : AtomicUndoOperation
{
bool isClosed = false;
-
+
public bool IsClosed {
get {
return isClosed;
@@ -905,7 +908,7 @@ namespace Mono.TextEditor
}
}
}
-
+
bool isInUndo = false;
Stack<UndoOperation> undoStack = new Stack<UndoOperation> ();
Stack<UndoOperation> redoStack = new Stack<UndoOperation> ();
@@ -942,7 +945,7 @@ namespace Mono.TextEditor
return this.undoStack.Count > 0 || currentAtomicOperation != null;
}
}
-
+
UndoOperation[] savePoint = null;
public bool IsDirty {
get {
@@ -960,7 +963,7 @@ namespace Mono.TextEditor
return false;
}
}
-
+
public enum LineState {
Unchanged,
Dirty,
@@ -977,13 +980,13 @@ namespace Mono.TextEditor
diffTracker = value;
}
}
-
+
public LineState GetLineState (DocumentLine line)
{
return diffTracker.GetLineState (line);
}
-
-
+
+
/// <summary>
/// Marks the document not dirty at this point (should be called after save).
/// </summary>
@@ -995,7 +998,7 @@ namespace Mono.TextEditor
this.CommitUpdateAll ();
DiffTracker.SetBaseDocument (CreateDocumentSnapshot ());
}
-
+
public void OptimizeTypedUndo ()
{
if (undoStack.Count == 0)
@@ -1030,12 +1033,12 @@ namespace Mono.TextEditor
undoStack.Push (keyUndo);
}
}
-
+
public int GetCurrentUndoDepth ()
{
return undoStack.Count;
}
-
+
public void StackUndoToDepth (int depth)
{
if (undoStack.Count == depth)
@@ -1046,7 +1049,7 @@ namespace Mono.TextEditor
}
undoStack.Push (atomicUndo);
}
-
+
public void MergeUndoOperations (int number)
{
number = System.Math.Min (number, undoStack.Count);
@@ -1056,7 +1059,7 @@ namespace Mono.TextEditor
}
undoStack.Push (atomicUndo);
}
-
+
public void Undo ()
{
if (undoStack.Count <= 0)
@@ -1088,7 +1091,7 @@ namespace Mono.TextEditor
}
public event EventHandler<UndoOperationEventArgs> Undone;
-
+
internal protected virtual void OnBeforeUndoOperation (EventArgs e)
{
var handler = this.BeforeUndoOperation;
@@ -1103,7 +1106,7 @@ namespace Mono.TextEditor
return this.redoStack.Count > 0;
}
}
-
+
public void Redo ()
{
if (redoStack.Count <= 0)
@@ -1115,16 +1118,16 @@ namespace Mono.TextEditor
isInUndo = false;
OnRedone (new UndoOperationEventArgs (operation));
}
-
+
internal protected virtual void OnRedone (UndoOperationEventArgs e)
{
EventHandler<UndoOperationEventArgs> handler = this.Redone;
if (handler != null)
handler (this, e);
}
-
+
public event EventHandler<UndoOperationEventArgs> Redone;
-
+
Stack<OperationType> currentAtomicUndoOperationType = new Stack<OperationType> ();
int atomicUndoLevel;
@@ -1139,11 +1142,11 @@ namespace Mono.TextEditor
return currentAtomicUndoOperationType.Count > 0 ? currentAtomicUndoOperationType.Peek () : OperationType.Undefined;
}
}
-
+
class UndoGroup : IDisposable
{
TextDocument doc;
-
+
public UndoGroup (TextDocument doc, OperationType operationType)
{
if (doc == null)
@@ -1160,7 +1163,7 @@ namespace Mono.TextEditor
}
}
}
-
+
public IDisposable OpenUndoGroup()
{
return OpenUndoGroup(OperationType.Undefined);
@@ -1175,7 +1178,7 @@ namespace Mono.TextEditor
{
currentAtomicUndoOperationType.Push (operationType);
if (currentAtomicOperation == null) {
- Debug.Assert (atomicUndoLevel == 0);
+ Debug.Assert (atomicUndoLevel == 0);
currentAtomicOperation = new AtomicUndoOperation (operationType);
OnBeginUndo ();
}
@@ -1187,8 +1190,8 @@ namespace Mono.TextEditor
if (atomicUndoLevel <= 0)
throw new InvalidOperationException ("There is no atomic undo operation running.");
atomicUndoLevel--;
- Debug.Assert (atomicUndoLevel >= 0);
-
+ Debug.Assert (atomicUndoLevel >= 0);
+
if (atomicUndoLevel == 0 && currentAtomicOperation != null) {
var cuao = currentAtomicOperation;
currentAtomicOperation = null;
@@ -1207,19 +1210,19 @@ namespace Mono.TextEditor
}
currentAtomicUndoOperationType.Pop ();
}
-
+
protected virtual void OnBeginUndo ()
{
- if (BeginUndo != null)
+ if (BeginUndo != null)
BeginUndo (this, EventArgs.Empty);
}
-
+
public void ClearUndoBuffer ()
{
undoStack.Clear ();
redoStack.Clear ();
}
-
+
[Serializable]
public sealed class UndoOperationEventArgs : EventArgs
{
@@ -1229,41 +1232,41 @@ namespace Mono.TextEditor
{
this.Operation = operation;
}
-
+
}
-
+
protected virtual void OnEndUndo (UndoOperationEventArgs e)
{
EventHandler<UndoOperationEventArgs> handler = this.EndUndo;
if (handler != null)
handler (this, e);
}
-
+
public event EventHandler BeginUndo;
public event EventHandler<UndoOperationEventArgs> EndUndo;
#endregion
-
+
#region Folding
-
+
SegmentTree<FoldSegment> foldSegmentTree = new SegmentTree<FoldSegment> ();
-
+
public bool IgnoreFoldings {
get;
set;
}
-
+
public bool HasFoldSegments {
get {
return FoldSegments.Any ();
}
}
-
+
public IEnumerable<FoldSegment> FoldSegments {
get {
return foldSegmentTree.Segments;
}
}
-
+
readonly object syncObject = new object();
CancellationTokenSource foldSegmentSrc;
@@ -1309,17 +1312,13 @@ namespace Mono.TextEditor
}, token);
}
}
-
+
void RemoveFolding (FoldSegment folding)
{
folding.isAttached = false;
- if (folding.isFolded) {
- foldedSegments.Remove (folding);
- CommitUpdateAll ();
- }
foldSegmentTree.Remove (folding);
}
-
+
/// <summary>
/// Updates the fold segments in a background worker thread. Don't call this method outside of a background worker.
/// Use UpdateFoldSegments instead.
@@ -1328,7 +1327,7 @@ namespace Mono.TextEditor
{
var oldSegments = new List<FoldSegment> (FoldSegments);
int oldIndex = 0;
- bool foldedSegmentAdded = false;
+ bool foldedSegmentAdded = false, foldedFoldingRemoved = false;
var newSegments = segments.ToList ();
newSegments.Sort ();
var newFoldedSegments = new HashSet<FoldSegment> ();
@@ -1341,6 +1340,7 @@ namespace Mono.TextEditor
int offset = newFoldSegment.Offset;
while (oldIndex < oldSegments.Count && offset > oldSegments [oldIndex].Offset) {
RemoveFolding (oldSegments [oldIndex]);
+ foldedFoldingRemoved |= oldSegments [oldIndex].IsCollapsed;
oldIndex++;
}
if (oldIndex < oldSegments.Count && offset == oldSegments [oldIndex].Offset) {
@@ -1374,57 +1374,43 @@ namespace Mono.TextEditor
return null;
}
RemoveFolding (oldSegments [oldIndex]);
+ foldedFoldingRemoved |= oldSegments [oldIndex].IsCollapsed;
oldIndex++;
}
bool countChanged = foldedSegments.Count != newFoldedSegments.Count;
- update = foldedSegmentAdded || countChanged;
+ update = foldedSegmentAdded || countChanged || foldedFoldingRemoved;
return newFoldedSegments;
}
-
- public void WaitForFoldUpdateFinished ()
- {
- if (foldSegmentTask != null) {
- try {
- foldSegmentTask.Wait (5000);
- } catch (AggregateException e) {
- e.Flatten ().Handle (x => x is OperationCanceledException);
- } catch (OperationCanceledException) {
-
- }
- foldSegmentTask = null;
- }
- }
-
+
internal void InterruptFoldWorker ()
{
if (foldSegmentSrc == null)
return;
foldSegmentSrc.Cancel ();
- WaitForFoldUpdateFinished ();
foldSegmentSrc = null;
}
-
+
public void ClearFoldSegments ()
{
InterruptFoldWorker ();
foldSegmentTree = new SegmentTree<FoldSegment> ();
- foldSegmentTree.tree.NodeRemoved += HandleFoldSegmentTreetreeNodeRemoved;
+ foldSegmentTree.tree.NodeRemoved += HandleFoldSegmentTreetreeNodeRemoved;
foldedSegments.Clear ();
InformFoldTreeUpdated ();
}
-
+
public IEnumerable<FoldSegment> GetFoldingsFromOffset (int offset)
{
if (offset < 0 || offset >= Length)
return new FoldSegment[0];
return foldSegmentTree.GetSegmentsAt (offset);
}
-
+
public IEnumerable<FoldSegment> GetFoldingContaining (int lineNumber)
{
return GetFoldingContaining(this.GetLine (lineNumber));
}
-
+
public IEnumerable<FoldSegment> GetFoldingContaining (DocumentLine line)
{
if (line == null)
@@ -1441,7 +1427,7 @@ namespace Mono.TextEditor
{
return GetStartFoldings (this.GetLine (lineNumber));
}
-
+
public IEnumerable<FoldSegment> GetStartFoldings (DocumentLine line)
{
if (line == null)
@@ -1461,7 +1447,7 @@ namespace Mono.TextEditor
{
return GetStartFoldings (this.GetLine (lineNumber));
}
-
+
public IEnumerable<FoldSegment> GetEndFoldings (DocumentLine line)
{
var lineOffset = line.Offset;
@@ -1480,7 +1466,7 @@ namespace Mono.TextEditor
{
return segment.GetEndLine (this).LineNumber - segment.GetStartLine (this).LineNumber;
}
-
+
public void EnsureOffsetIsUnfolded (int offset)
{
foreach (FoldSegment fold in GetFoldingsFromOffset (offset).Where (f => f.IsCollapsed && f.Offset < offset && offset < f.EndOffset)) {
@@ -1506,7 +1492,7 @@ namespace Mono.TextEditor
handler (this, EventArgs.Empty);
}
public event EventHandler FoldTreeUpdated;
-
+
HashSet<FoldSegment> foldedSegments = new HashSet<FoldSegment> ();
public IEnumerable<FoldSegment> FoldedSegments {
@@ -1548,7 +1534,7 @@ namespace Mono.TextEditor
handler (this, e);
}
-
+
List<TextLineMarker> extendingTextMarkers = new List<TextLineMarker> ();
public IEnumerable<DocumentLine> LinesWithExtendingTextMarkers {
get {
@@ -1556,15 +1542,15 @@ namespace Mono.TextEditor
var line = marker.LineSegment;
if (line != null)
yield return line;
- }
+ }
}
}
-
+
public void AddMarker (int lineNumber, TextLineMarker marker)
{
AddMarker (this.GetLine (lineNumber), marker);
}
-
+
public void AddMarker (DocumentLine line, TextLineMarker marker)
{
AddMarker (line, marker, true);
@@ -1628,7 +1614,7 @@ namespace Mono.TextEditor
if (line == null)
return;
foreach (var marker in GetTextSegmentMarkersAt (line).OfType<DocumentLineTextSegmentMarker> ())
- RemoveMarker (marker);
+ RemoveMarker (marker);
}
public void AddMarker (DocumentLine line, TextLineMarker marker, bool commitUpdate, int idx = -1)
@@ -1647,19 +1633,19 @@ namespace Mono.TextEditor
if (commitUpdate)
this.CommitLineUpdate (line);
}
-
+
static int CompareMarkers (TextLineMarker left, TextLineMarker right)
{
if (left.LineSegment == null || right.LineSegment == null)
return 0;
return left.LineSegment.Offset.CompareTo (right.LineSegment.Offset);
}
-
+
public void RemoveMarker (TextLineMarker marker)
{
RemoveMarker (marker, true);
}
-
+
public void RemoveMarker (TextLineMarker marker, bool updateLine)
{
if (marker == null)
@@ -1688,17 +1674,17 @@ namespace Mono.TextEditor
if (updateLine)
this.CommitLineUpdate (line);
}
-
+
public void RemoveMarker (int lineNumber, Type type)
{
RemoveMarker (this.GetLine (lineNumber), type);
}
-
+
public void RemoveMarker (DocumentLine line, Type type)
{
RemoveMarker (line, type, true);
}
-
+
public void RemoveMarker (DocumentLine line, Type type, bool updateLine)
{
if (line == null || type == null)
@@ -1772,7 +1758,7 @@ namespace Mono.TextEditor
textMarkerCacheOffset = offset;
return textMarkerSegmentCache = textSegmentMarkerTree.GetSegmentsAt (offset).ToList ();
}
-
+
public void AddMarker (TextSegmentMarker marker)
{
@@ -1807,16 +1793,16 @@ namespace Mono.TextEditor
{
return new TextSegment (0, Length).Contains (offset);
}
-
+
public bool Contains (ISegment segment)
{
return new TextSegment (0, Length).Contains (segment);
}
-
-
+
+
#region Update logic
List<DocumentUpdateRequest> updateRequests = new List<DocumentUpdateRequest> ();
-
+
public IEnumerable<DocumentUpdateRequest> UpdateRequests {
get {
return updateRequests;
@@ -1836,7 +1822,7 @@ namespace Mono.TextEditor
updateRequests.Add (request);
}
}
-
+
public void CommitDocumentUpdate ()
{
lock (syncObject) {
@@ -1845,13 +1831,13 @@ namespace Mono.TextEditor
updateRequests.Clear ();
}
}
-
+
public void CommitLineUpdate (int line)
{
RequestUpdate (new LineUpdate (line));
CommitDocumentUpdate ();
}
-
+
public void CommitLineUpdate (DocumentLine line)
{
CommitLineUpdate (line.LineNumber);
@@ -1889,12 +1875,12 @@ namespace Mono.TextEditor
#region Helper functions
public const string openBrackets = "([{<";
public const string closingBrackets = ")]}>";
-
+
public static bool IsBracket (char ch)
{
return (openBrackets + closingBrackets).IndexOf (ch) >= 0;
}
-
+
public static bool IsWordSeparator (char ch)
{
return !(char.IsLetterOrDigit (ch) || ch == '_');
@@ -1905,12 +1891,12 @@ namespace Mono.TextEditor
return (offset == 0 || IsWordSeparator (GetCharAt (offset - 1))) &&
(offset + length == Length || IsWordSeparator (GetCharAt (offset + length)));
}
-
+
public bool IsEmptyLine (DocumentLine line)
{
for (int i = 0; i < line.Length; i++) {
char ch = GetCharAt (line.Offset + i);
- if (!Char.IsWhiteSpace (ch))
+ if (!Char.IsWhiteSpace (ch))
return false;
}
return true;
@@ -1924,7 +1910,7 @@ namespace Mono.TextEditor
IdentifierPart
}
-
+
public static CharacterClass GetCharacterClass (char ch)
@@ -1937,7 +1923,7 @@ namespace Mono.TextEditor
return CharacterClass.Unknown;
}
-
+
public static void RemoveTrailingWhitespaces (TextEditorData data, DocumentLine line)
{
if (line == null)
@@ -1950,7 +1936,7 @@ namespace Mono.TextEditor
break;
}
}
-
+
if (whitespaces > 0) {
var removeOffset = line.Offset + line.Length - whitespaces;
data.Remove (removeOffset, whitespaces);
@@ -1963,7 +1949,7 @@ namespace Mono.TextEditor
return isInUndo;
}
}
-
+
#region Diff
@@ -1982,7 +1968,7 @@ namespace Mono.TextEditor
}
return result;
}
-
+
public IEnumerable<Hunk> Diff (TextDocument changedDocument, bool includeEol = true)
{
var codeDictionary = new Dictionary<string, int> ();
@@ -1992,18 +1978,18 @@ namespace Mono.TextEditor
}
#endregion
-
-#region ContentLoaded
+
+#region ContentLoaded
// The problem: Action to perform on a newly opened text editor, but content didn't get loaded because autosave file exist.
// At this point the document is open, but the content didn't yet have loaded - therefore the action on the conent can't be perfomed.
- // Solution: Perform the action after the user did choose load autosave or not.
+ // Solution: Perform the action after the user did choose load autosave or not.
// This is done by the RunWhenLoaded method. Text editors should call the InformLoadComplete () when the content has successfully been loaded
// at that point the outstanding actions are run.
bool isLoaded;
List<Action> loadedActions = new List<Action> ();
List<Action> realizedActions = new List<Action> ();
-
+
/// <summary>
/// Gets a value indicating whether this instance is loaded.
/// </summary>
@@ -2018,7 +2004,7 @@ namespace Mono.TextEditor
get;
private set;
}
-
+
/// <summary>
/// Informs the document when the content is loaded. All outstanding actions are executed.
/// </summary>
@@ -2040,7 +2026,7 @@ namespace Mono.TextEditor
realizedActions.ForEach (act => act ());
realizedActions = null;
}
-
+
/// <summary>
/// Performs an action when the content is loaded.
/// </summary>
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/AssemblyUtilities.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/AssemblyUtilities.cs
index d4eb34291f..bcb83e52a9 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/AssemblyUtilities.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/AssemblyUtilities.cs
@@ -38,44 +38,65 @@ using MonoDevelop.Core.AddIns;
using MonoDevelop.Core.Serialization;
using Mono.Addins;
using Mono.PkgConfig;
+using System.Reflection.PortableExecutable;
+using System.Reflection.Metadata;
namespace MonoDevelop.Core.Assemblies
{
public static class AssemblyUtilities
{
- static bool Is64BitPE (Mono.Cecil.TargetArchitecture machine)
+ static bool Is64BitPE (Machine machine)
{
- return machine == Mono.Cecil.TargetArchitecture.AMD64 ||
- machine == Mono.Cecil.TargetArchitecture.IA64 ||
- machine == Mono.Cecil.TargetArchitecture.ARM64;
+ return machine == Machine.Amd64 || machine == Machine.Arm64 || machine == Machine.IA64 || machine == Machine.Alpha64;
}
- public static ProcessExecutionArchitecture GetProcessExecutionArchitectureForAssembly (string assemblyPath)
+ static bool TryReadPEHeaders (string assemblyPath, out PortableExecutableKinds peKind, out Machine machine)
{
- if (string.IsNullOrEmpty (assemblyPath))
- throw new ArgumentNullException (nameof (assemblyPath));
+ peKind = default;
+ machine = default;
try {
- Mono.Cecil.ModuleAttributes peKind;
- Mono.Cecil.TargetArchitecture machine;
if (!File.Exists (assemblyPath))
- return ProcessExecutionArchitecture.Unspecified;
- try {
- using (var adef = Mono.Cecil.AssemblyDefinition.ReadAssembly (assemblyPath)) {
- peKind = adef.MainModule.Attributes;
- machine = adef.MainModule.Architecture;
- }
- } catch {
- peKind = Mono.Cecil.ModuleAttributes.ILOnly;
- machine = Mono.Cecil.TargetArchitecture.I386;
+ return false;
+
+ using (var reader = new PEReader (File.OpenRead (assemblyPath))) {
+ var peHeaders = reader.PEHeaders;
+
+ var corFlags = peHeaders.CorHeader.Flags;
+ if ((corFlags & CorFlags.ILOnly) != 0)
+ peKind |= PortableExecutableKinds.ILOnly;
+
+ if ((corFlags & CorFlags.Prefers32Bit) != 0)
+ peKind |= PortableExecutableKinds.Preferred32Bit;
+ else if ((corFlags & CorFlags.Requires32Bit) != 0)
+ peKind |= PortableExecutableKinds.Required32Bit;
+
+ if (peHeaders.PEHeader.Magic == PEMagic.PE32Plus)
+ peKind |= PortableExecutableKinds.PE32Plus;
+
+ machine = peHeaders.CoffHeader.Machine;
}
- if ((peKind & (Mono.Cecil.ModuleAttributes.Required32Bit | Mono.Cecil.ModuleAttributes.Preferred32Bit)) != 0)
- return ProcessExecutionArchitecture.X86;
- if (Is64BitPE (machine))
- return ProcessExecutionArchitecture.X64;
+
+ return true;
} catch (Exception e) {
LoggingService.LogError ("Error while determining 64/32 bit assembly.", e);
+ return false;
}
+ }
+
+ public static ProcessExecutionArchitecture GetProcessExecutionArchitectureForAssembly (string assemblyPath)
+ {
+ if (string.IsNullOrEmpty (assemblyPath))
+ throw new ArgumentNullException (nameof (assemblyPath));
+
+ if (TryReadPEHeaders (assemblyPath, out var peKind, out var machine)) {
+ if ((peKind & (PortableExecutableKinds.Preferred32Bit | PortableExecutableKinds.Required32Bit)) != 0)
+ return ProcessExecutionArchitecture.X86;
+
+ if ((peKind & PortableExecutableKinds.PE32Plus) != 0 || Is64BitPE (machine))
+ return ProcessExecutionArchitecture.X64;
+ }
+
return ProcessExecutionArchitecture.Unspecified;
}
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/SystemAssemblyService.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/SystemAssemblyService.cs
index 4ec62572f9..95290ab3ed 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/SystemAssemblyService.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/SystemAssemblyService.cs
@@ -30,12 +30,14 @@
using System;
using System.Collections.Generic;
+using System.Collections.Immutable;
using System.IO;
using System.Linq;
using System.Reflection;
+using System.Reflection.Metadata;
+using System.Reflection.PortableExecutable;
using System.Threading;
using Mono.Addins;
-using Mono.Cecil;
using MonoDevelop.Core.AddIns;
namespace MonoDevelop.Core.Assemblies
@@ -369,29 +371,50 @@ namespace MonoDevelop.Core.Assemblies
{
if (!File.Exists (file))
return TargetFrameworkMoniker.UNKNOWN;
- AssemblyDefinition assembly = null;
+
try {
- assembly = AssemblyDefinition.ReadAssembly (file);
- var att = assembly.CustomAttributes.FirstOrDefault (a =>
- a.AttributeType.FullName == "System.Runtime.Versioning.TargetFrameworkAttribute"
- );
- if (att != null) {
- if (att.ConstructorArguments.Count == 1) {
- var v = att.ConstructorArguments[0].Value as string;
- TargetFrameworkMoniker m;
- if (v != null && TargetFrameworkMoniker.TryParse (v, out m)) {
+ using (var reader = new PEReader (File.OpenRead (file))) {
+ var mr = reader.GetMetadataReader ();
+
+ foreach (var customAttributeHandle in mr.GetAssemblyDefinition ().GetCustomAttributes ()) {
+ var customAttribute = mr.GetCustomAttribute (customAttributeHandle);
+
+ var ctor = mr.GetMemberReference ((MemberReferenceHandle)customAttribute.Constructor);
+ var attrType = mr.GetTypeReference ((TypeReferenceHandle)ctor.Parent);
+
+ var ns = mr.GetString (attrType.Namespace);
+ if (ns != "System.Runtime.Versioning")
+ continue;
+
+ var typeName = mr.GetString (attrType.Name);
+ if (typeName != "TargetFrameworkAttribute")
+ continue;
+
+ var provider = new StringParameterValueTypeProvider (mr, customAttribute.Value);
+ var signature = ctor.DecodeMethodSignature (provider, null);
+ var parameterTypes = signature.ParameterTypes;
+ if (parameterTypes.Length != 1)
+ continue;
+
+ var value = parameterTypes [0];
+ if (value != null && TargetFrameworkMoniker.TryParse (value, out var m)) {
return m;
}
+ LoggingService.LogError ("Invalid TargetFrameworkAttribute in assembly {0} - {1}", file, value);
}
- LoggingService.LogError ("Invalid TargetFrameworkAttribute in assembly {0}", file);
- }
- if (tr != null) {
- foreach (var r in assembly.MainModule.AssemblyReferences) {
- if (r.Name == "mscorlib") {
+
+ if (tr != null) {
+ foreach (var assemblyReferenceHandle in mr.AssemblyReferences) {
+ var assemblyReference = mr.GetAssemblyReference (assemblyReferenceHandle);
+
+ var name = mr.GetString (assemblyReference.Name);
+ if (name != "mscorlib")
+ continue;
+
TargetFramework compatibleFramework = null;
// If there are several frameworks that can run the file, pick one that is installed
foreach (TargetFramework tf in GetKnownFrameworks ()) {
- if (tf.GetCorlibVersion () == r.Version.ToString ()) {
+ if (tf.GetCorlibVersion () == assemblyReference.Version.ToString ()) {
compatibleFramework = tf;
if (tr.IsInstalled (tf))
return tf.Id;
@@ -405,125 +428,66 @@ namespace MonoDevelop.Core.Assemblies
}
} catch (Exception ex) {
LoggingService.LogError ("Error determining target framework for assembly {0}: {1}", file, ex);
- return TargetFrameworkMoniker.UNKNOWN;
- } finally {
- assembly?.Dispose ();
}
- LoggingService.LogError ("Failed to determine target framework for assembly {0}", file);
return TargetFrameworkMoniker.UNKNOWN;
}
/// <summary>
/// Simply get all assembly reference names from an assembly given it's file name.
/// </summary>
- public static IEnumerable<string> GetAssemblyReferences (string fileName)
- {
- AssemblyDefinition assembly = null;
- try {
- try {
- assembly = Mono.Cecil.AssemblyDefinition.ReadAssembly (fileName);
- } catch {
- return Enumerable.Empty<string> ();
- }
- return assembly.MainModule.AssemblyReferences.Select (x => x.Name);
- } finally {
- assembly?.Dispose ();
- }
- }
+ public static ImmutableArray<string> GetAssemblyReferences (string fileName)
+ {
+ try {
+ using (var reader = new PEReader (File.OpenRead (fileName))) {
+ var mr = reader.GetMetadataReader ();
+ var assemblyReferences = mr.AssemblyReferences;
- static Dictionary<string, bool> referenceDict = new Dictionary<string, bool> ();
+ var builder = ImmutableArray.CreateBuilder<string> (assemblyReferences.Count);
- static bool ContainsReferenceToSystemRuntimeInternal (string fileName)
- {
- bool result;
- if (referenceDict.TryGetValue (fileName, out result))
- return result;
-
- //const int cacheLimit = 4096;
- //if (referenceDict.Count > cacheLimit)
- // referenceDict = ImmutableDictionary<string, bool>.Empty
-
- AssemblyDefinition assembly = null;
- try {
- try {
- assembly = Mono.Cecil.AssemblyDefinition.ReadAssembly (fileName);
- } catch {
- return false;
- }
- foreach (var r in assembly.MainModule.AssemblyReferences) {
- // Don't compare the version number since it may change depending on the version of .net standard
- if (r.Name.Equals ("System.Runtime")) {
- referenceDict [fileName] = true; ;
- return true;
- }
- }
- } finally {
- assembly?.Dispose ();
- }
- referenceDict [fileName] = false;
- return false;
+ foreach (var assemblyReferenceHandle in assemblyReferences) {
+ var assemblyReference = mr.GetAssemblyReference (assemblyReferenceHandle);
+ builder.Add (mr.GetString (assemblyReference.Name));
+ }
+
+ return builder.MoveToImmutable();
+ }
+ } catch {
+ return ImmutableArray<string>.Empty;
+ }
}
static Dictionary<string, bool> facadeReferenceDict = new Dictionary<string, bool> ();
static bool RequiresFacadeAssembliesInternal (string fileName)
{
- bool result;
- if (facadeReferenceDict.TryGetValue (fileName, out result))
+ if (facadeReferenceDict.TryGetValue (fileName, out var result))
return result;
- AssemblyDefinition assembly = null;
try {
- try {
- assembly = Mono.Cecil.AssemblyDefinition.ReadAssembly (fileName);
- } catch {
- return false;
- }
- foreach (var r in assembly.MainModule.AssemblyReferences) {
- // Don't compare the version number since it may change depending on the version of .net standard
- if (r.Name.Equals ("System.Runtime") || r.Name.Equals ("netstandard")) {
- facadeReferenceDict [fileName] = true; ;
- return true;
+ using (var reader = new PEReader (File.OpenRead (fileName))) {
+ var mr = reader.GetMetadataReader ();
+
+ foreach (var assemblyReferenceHandle in mr.AssemblyReferences) {
+ var assemblyReference = mr.GetAssemblyReference (assemblyReferenceHandle);
+ var name = mr.GetString (assemblyReference.Name);
+
+ // Don't compare the version number since it may change depending on the version of .net standard
+ if (name.Equals ("System.Runtime") || name.Equals ("netstandard")) {
+ facadeReferenceDict [fileName] = true;
+ return true;
+ }
}
}
- } finally {
- assembly?.Dispose ();
+ } catch {
+ return false;
}
+
facadeReferenceDict [fileName] = false;
return false;
}
- static object referenceLock = new object ();
-
- [Obsolete ("Use RequiresFacadeAssemblies (string fileName)")]
- public static bool ContainsReferenceToSystemRuntime (string fileName)
- {
- lock (referenceLock) {
- return ContainsReferenceToSystemRuntimeInternal (fileName);
- }
- }
-
- static SemaphoreSlim referenceLockAsync = new SemaphoreSlim (1, 1);
-
- [Obsolete ("Use RequiresFacadeAssembliesAsync (string fileName)")]
- public static async System.Threading.Tasks.Task<bool> ContainsReferenceToSystemRuntimeAsync (string filename)
- {
- try {
- await referenceLockAsync.WaitAsync ().ConfigureAwait (false);
- return ContainsReferenceToSystemRuntimeInternal (filename);
- } finally {
- referenceLockAsync.Release ();
- }
- }
-
- internal static bool RequiresFacadeAssemblies (string fileName)
- {
- lock (referenceLock) {
- return RequiresFacadeAssembliesInternal (fileName);
- }
- }
-
- internal static async System.Threading.Tasks.Task<bool> RequiresFacadeAssembliesAsync (string filename)
+ static readonly SemaphoreSlim referenceLockAsync = new SemaphoreSlim (1, 1);
+ public static async System.Threading.Tasks.Task<bool> RequiresFacadeAssembliesAsync (string filename)
{
try {
await referenceLockAsync.WaitAsync ().ConfigureAwait (false);
@@ -556,25 +520,51 @@ namespace MonoDevelop.Core.Assemblies
/// Simply get all assembly manifest resources from an assembly given it's file name.
/// </summary>
public static IEnumerable<ManifestResource> GetAssemblyManifestResources (string fileName)
- {
- AssemblyDefinition assembly = null;
- try {
- try {
- assembly = Mono.Cecil.AssemblyDefinition.ReadAssembly (fileName);
- } catch {
- yield break;
- }
- foreach (var r in assembly.MainModule.Resources) {
- if (r.ResourceType == ResourceType.Embedded) {
- var er = (EmbeddedResource)r;
-
- // Explicitly create a capture and query it here so the stream isn't queried after the module is disposed.
- var rs = er.GetResourceStream ();
- yield return new ManifestResource (er.Name, () => rs);
- }
- }
- } finally {
- assembly?.Dispose ();
+ {
+ using (var reader = new PEReader (File.OpenRead (fileName))) {
+ var mr = reader.GetMetadataReader ();
+
+ var headers = reader.PEHeaders;
+ var resources = headers.CorHeader.ResourcesDirectory;
+ var sectionData = reader.GetSectionData (resources.RelativeVirtualAddress);
+ if (sectionData.Length == 0)
+ return Array.Empty<ManifestResource> (); // RVA could not be found in any section
+
+ var sectionReader = sectionData.GetReader ();
+ var manifestResources = mr.ManifestResources;
+ var result = new List<ManifestResource> (manifestResources.Count);
+
+ foreach (var manifestResourceHandle in manifestResources) {
+ var manifestResource = mr.GetManifestResource (manifestResourceHandle);
+
+ // This means the type is Embedded.
+ var isEmbeddedResource = manifestResource.Implementation.IsNil;
+ if (!isEmbeddedResource)
+ continue;
+
+ int offset = (int)manifestResource.Offset;
+ sectionReader.Offset += offset;
+ try {
+ int length = sectionReader.ReadInt32 ();
+ if ((uint)length > sectionReader.RemainingBytes) {
+ LoggingService.LogError ("Resource stream invalid length {0}", length.ToString ());
+ continue;
+ }
+
+ var name = mr.GetString (manifestResource.Name);
+ unsafe {
+ using (var unmanagedStream = new UnmanagedMemoryStream (sectionReader.CurrentPointer, length, length, FileAccess.Read)) {
+ var memoryStream = new MemoryStream (length);
+ unmanagedStream.CopyTo (memoryStream);
+ memoryStream.Position = 0;
+ result.Add (new ManifestResource (name, () => memoryStream));
+ }
+ }
+ } finally {
+ sectionReader.Offset -= offset;
+ }
+ }
+ return result;
}
}
@@ -583,5 +573,37 @@ namespace MonoDevelop.Core.Assemblies
{
return Runtime.LoadAssemblyFrom (asmPath);
}
+
+ sealed class StringParameterValueTypeProvider : ISignatureTypeProvider<string, object>
+ {
+ readonly BlobReader valueReader;
+
+ public StringParameterValueTypeProvider (MetadataReader reader, BlobHandle value)
+ {
+ valueReader = reader.GetBlobReader (value);
+
+ var prolog = valueReader.ReadUInt16 ();
+ if (prolog != 1)
+ throw new BadImageFormatException ("Invalid custom attribute prolog.");
+ }
+
+ public string GetPrimitiveType (PrimitiveTypeCode typeCode) => typeCode != PrimitiveTypeCode.String ? "" : valueReader.ReadSerializedString ();
+ public string GetArrayType (string elementType, ArrayShape shape) => "";
+ public string GetByReferenceType (string elementType) => "";
+ public string GetFunctionPointerType (MethodSignature<string> signature) => "";
+ public string GetGenericInstance (string genericType, ImmutableArray<string> typestrings) => "";
+ public string GetGenericInstantiation (string genericType, ImmutableArray<string> typeArguments) { throw new NotImplementedException (); }
+ public string GetGenericMethodParameter (int index) => "";
+ public string GetGenericMethodParameter (object genericContext, int index) { throw new NotImplementedException (); }
+ public string GetGenericTypeParameter (int index) => "";
+ public string GetGenericTypeParameter (object genericContext, int index) { throw new NotImplementedException (); }
+ public string GetModifiedType (string modifier, string unmodifiedType, bool isRequired) => "";
+ public string GetPinnedType (string elementType) => "";
+ public string GetPointerType (string elementType) => "";
+ public string GetSZArrayType (string elementType) => "";
+ public string GetTypeFromDefinition (MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind) => "";
+ public string GetTypeFromReference (MetadataReader reader, TypeReferenceHandle handle, byte rawTypeKind) => "";
+ public string GetTypeFromSpecification (MetadataReader reader, object genericContext, TypeSpecificationHandle handle, byte rawTypeKind) => "";
+ }
}
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/RemoteProcessConnection.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/RemoteProcessConnection.cs
index aa974f8028..2d804cf738 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/RemoteProcessConnection.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/RemoteProcessConnection.cs
@@ -156,15 +156,6 @@ namespace MonoDevelop.Core.Execution
}
}
- [Obsolete ("Use Disconnect()")]
- public void Disconnect (bool waitUntilDone)
- {
- if (waitUntilDone)
- Disconnect ().Wait (TimeSpan.FromSeconds (7));
- else
- Disconnect ().Ignore ();
- }
-
public async Task Disconnect ()
{
StopPinger ();
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.csproj b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.csproj
index 6f4a10936f..aa35162478 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.csproj
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.csproj
@@ -89,7 +89,7 @@
<PackageReference Include="Microsoft.CodeAnalysis.ExternalAccess.MonoDevelop" Version="$(NuGetVersionRoslyn)" PrivateAssets="runtime" />
<PackageReference Include="Microsoft.VisualStudio.CodingConventions" Version="1.1.20180503.2" PrivateAssets="runtime" />
<PackageReference Include="Microsoft.VisualStudio.Composition" Version="$(NuGetVersionVSComposition)" ExcludeAssets="all" />
- <!-- Need the net45 version, see https://github.com/mono/mono/issues/12461 -->
+ <!-- Need the net45 version, see https://github.com/mono/mono/issues/12461 -->
<Reference Include="$(NuGetPackageRoot)microsoft.visualstudio.composition/$(NuGetVersionVSComposition)/lib/net45/Microsoft.VisualStudio.Composition.dll">
<Private>true</Private>
</Reference>
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildFileFormat.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildFileFormat.cs
index e35886fdfe..57f4a1f42b 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildFileFormat.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildFileFormat.cs
@@ -37,7 +37,7 @@ using System.Linq;
namespace MonoDevelop.Projects.MSBuild
{
- public abstract class MSBuildFileFormat
+ public abstract class MSBuildFileFormat : IComparable<MSBuildFileFormat>, IEquatable<MSBuildFileFormat>
{
readonly SlnFileFormat slnFileFormat;
@@ -51,9 +51,6 @@ namespace MonoDevelop.Projects.MSBuild
public static readonly MSBuildFileFormat VS2010 = new MSBuildFileFormatVS10 ();
public static readonly MSBuildFileFormat VS2012 = new MSBuildFileFormatVS12 ();
- [Obsolete("This is the same as VS2012")]
- public static readonly MSBuildFileFormat VS2017 = VS2012;
-
public static IEnumerable<MSBuildFileFormat> GetSupportedFormats ()
{
yield return VS2012;
@@ -68,12 +65,6 @@ namespace MonoDevelop.Projects.MSBuild
}
public static MSBuildFileFormat DefaultFormat => VS2012;
-
- [Obsolete ("Use ProductDescription or ID")]
- public string Name => "MSBuild";
-
- [Obsolete]
- public abstract Version Version { get; }
internal SlnFileFormat SlnFileFormat {
get { return slnFileFormat; }
@@ -229,17 +220,41 @@ namespace MonoDevelop.Projects.MSBuild
}
return string.Empty;
}
-
+
public abstract string Id { get; }
+
+ #region IComparable<MSBuildFileFormat> implementation and overloads
+
+ public override bool Equals (object obj) => obj is MSBuildFileFormat other && Equals (other);
+ public bool Equals (MSBuildFileFormat other) => other != null && Id == other.Id;
+ public override int GetHashCode () => Id.GetHashCode ();
+
+ public int CompareTo (MSBuildFileFormat other) => Version.Parse (SlnVersion).CompareTo (Version.Parse (other.SlnVersion));
+
+ public static bool operator == (MSBuildFileFormat a, MSBuildFileFormat b)
+ {
+ if (ReferenceEquals (a, b))
+ return true;
+
+ if (a is null)
+ return b is null;
+
+ return a.Equals (b);
+ }
+
+ public static bool operator != (MSBuildFileFormat a, MSBuildFileFormat b) => !(a == b);
+ public static bool operator < (MSBuildFileFormat a, MSBuildFileFormat b) => a.CompareTo (b) < 0;
+ public static bool operator > (MSBuildFileFormat a, MSBuildFileFormat b) => a.CompareTo (b) > 0;
+ public static bool operator <= (MSBuildFileFormat a, MSBuildFileFormat b) => a.CompareTo (b) <= 0;
+ public static bool operator >= (MSBuildFileFormat a, MSBuildFileFormat b) => a.CompareTo (b) >= 0;
+
+ #endregion
}
class MSBuildFileFormatVS05 : MSBuildFileFormat
{
public override string Id => "MSBuild05";
- [Obsolete("Unused")]
- public override Version Version => new Version ("2005");
-
public override string DefaultProductVersion => "8.0.50727";
public override string DefaultToolsVersion => "2.0";
public override string DefaultSchemaVersion => "2.0";
@@ -255,9 +270,6 @@ namespace MonoDevelop.Projects.MSBuild
{
public override string Id => "MSBuild08";
- [Obsolete ("Unused")]
- public override Version Version => new Version ("2008");
-
public override string DefaultProductVersion => "9.0.21022";
public override string DefaultToolsVersion => "3.5";
public override string DefaultSchemaVersion => "2.0";
@@ -279,9 +291,6 @@ namespace MonoDevelop.Projects.MSBuild
{
public override string Id => "MSBuild10";
- [Obsolete ("Unused")]
- public override Version Version => new Version ("2010");
-
public override string DefaultProductVersion => "8.0.30703";
public override string DefaultSchemaVersion => "2.0";
public override string DefaultToolsVersion => "4.0";
@@ -294,9 +303,6 @@ namespace MonoDevelop.Projects.MSBuild
{
public override string Id => "MSBuild12";
- [Obsolete ("Unused")]
- public override Version Version => new Version ("2012");
-
// This is mostly irrelevant, the builder always uses the latest
// tools version. It's only used for new projects created with
// the old project template engine.
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildProcessService.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildProcessService.cs
index 2062fae1a8..40cf37edf2 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildProcessService.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildProcessService.cs
@@ -63,9 +63,19 @@ namespace MonoDevelop.Projects.MSBuild
return MSBuildProjectService.GetMSBuildBinPath (Runtime.SystemAssemblyService.CurrentRuntime);
}
+ static FilePath GetMSBuildBinDirectory (TargetRuntime runtime)
+ {
+ return MSBuildProjectService.GetMSBuildBinPath (runtime);
+ }
+
static FilePath GetMSBuildBinPath ()
{
- FilePath binDirectory = GetMSBuildBinDirectory ();
+ return GetMSBuildBinPath (Runtime.SystemAssemblyService.CurrentRuntime);
+ }
+
+ internal static FilePath GetMSBuildBinPath (TargetRuntime runtime)
+ {
+ FilePath binDirectory = GetMSBuildBinDirectory (runtime);
FilePath binPath = binDirectory.Combine ("MSBuild.dll");
if (File.Exists (binPath)) {
return binPath;
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/SdkResolution.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/SdkResolution.cs
index 9cd247fc19..28484ef612 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/SdkResolution.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/SdkResolution.cs
@@ -3,13 +3,13 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using Microsoft.Build.Framework;
using MonoDevelop.Core.Assemblies;
-using MonoDevelop.Core;
namespace MonoDevelop.Projects.MSBuild
{
@@ -24,6 +24,7 @@ namespace MonoDevelop.Projects.MSBuild
readonly object _lockObject = new object ();
IList<SdkResolver> _resolvers;
TargetRuntime runtime;
+ Version msbuildVersion;
internal SdkResolution (TargetRuntime runtime)
{
@@ -58,7 +59,7 @@ namespace MonoDevelop.Projects.MSBuild
try {
var buildEngineLogger = new SdkLoggerImpl (logger, buildEventContext);
foreach (var sdkResolver in _resolvers) {
- var context = new SdkResolverContextImpl (buildEngineLogger, projectFile, solutionPath);
+ var context = new SdkResolverContextImpl (buildEngineLogger, projectFile, solutionPath, msbuildVersion);
var resultFactory = new SdkResultFactoryImpl (sdk);
try {
var result = (SdkResultImpl)sdkResolver.Resolve (sdk, context, resultFactory);
@@ -96,10 +97,21 @@ namespace MonoDevelop.Projects.MSBuild
{
lock (_lockObject) {
if (_resolvers != null) return;
+ msbuildVersion = GetMSBuildVersion ();
_resolvers = LoadResolvers (logger);
}
}
+ Version GetMSBuildVersion ()
+ {
+ var msbuildFileName = MSBuildProcessService.GetMSBuildBinPath (runtime);
+ if (!File.Exists (msbuildFileName))
+ return null;
+
+ var versionInfo = FileVersionInfo.GetVersionInfo (msbuildFileName);
+ return new Version (versionInfo.FileMajorPart, versionInfo.FileMinorPart, versionInfo.FileBuildPart, versionInfo.FilePrivatePart);
+ }
+
IList<SdkResolver> LoadResolvers (ILoggingService logger)
{
// Add the MonoDevelop resolver, which resolves SDKs registered by add-ins.
@@ -287,7 +299,7 @@ namespace MonoDevelop.Projects.MSBuild
public IEnumerable<string> Warnings { get; }
}
- class SdkResultFactoryImpl : SdkResultFactory
+ internal class SdkResultFactoryImpl : SdkResultFactory
{
readonly SdkReference _sdkReference;
@@ -309,11 +321,12 @@ namespace MonoDevelop.Projects.MSBuild
sealed class SdkResolverContextImpl : SdkResolverContext
{
- public SdkResolverContextImpl (SdkLogger logger, string projectFilePath, string solutionPath)
+ public SdkResolverContextImpl (SdkLogger logger, string projectFilePath, string solutionPath, Version msbuildVersion)
{
Logger = logger;
ProjectFilePath = projectFilePath;
SolutionFilePath = solutionPath;
+ MSBuildVersion = msbuildVersion;
}
}
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProject.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProject.cs
index 7631c0cb30..66a96402f4 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProject.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProject.cs
@@ -1915,8 +1915,14 @@ namespace MonoDevelop.Projects
{
bool externalConsole = false, pauseConsole = false;
- var dotNetExecutionCommand = executionCommand as DotNetExecutionCommand;
- if (dotNetExecutionCommand != null) {
+ if (executionCommand is ProcessExecutionCommand processExecutionCommand) {
+ if (!Directory.Exists (processExecutionCommand.WorkingDirectory)) {
+ monitor.ReportError (GettextCatalog.GetString ("Can not execute. The run configuration working directory doesn't exist at {0}", processExecutionCommand.WorkingDirectory), null);
+ return;
+ }
+ }
+
+ if (executionCommand is DotNetExecutionCommand dotNetExecutionCommand) {
dotNetExecutionCommand.UserAssemblyPaths = GetUserAssemblyPaths (configuration);
externalConsole = dotNetExecutionCommand.ExternalConsole;
pauseConsole = dotNetExecutionCommand.PauseConsoleOutput;
diff --git a/main/src/core/MonoDevelop.Ide/ExtensionModel/Commands.addin.xml b/main/src/core/MonoDevelop.Ide/ExtensionModel/Commands.addin.xml
index cd0d4d9e31..333f953015 100644
--- a/main/src/core/MonoDevelop.Ide/ExtensionModel/Commands.addin.xml
+++ b/main/src/core/MonoDevelop.Ide/ExtensionModel/Commands.addin.xml
@@ -256,7 +256,7 @@
_description = "Adds and existing folder and its contents"
_label = "_Add Existing Folder..." />
<Command id = "MonoDevelop.Ide.Commands.ProjectCommands.NewFolder"
- _label = "New _Folder"
+ _label = "New _Folder…"
_description = "Create a new folder"
icon = "md-new-folder" />
<Command id = "MonoDevelop.Ide.Commands.ProjectCommands.IncludeToProject"
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/GtkWorkarounds.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/GtkWorkarounds.cs
index 98cd671d2c..a6c2af0429 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/GtkWorkarounds.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/GtkWorkarounds.cs
@@ -1538,7 +1538,11 @@ namespace MonoDevelop.Components
[DllImport ("libgdk-win32-2.0-0.dll", CallingConvention = CallingConvention.Cdecl)]
static extern void gdk_event_free (IntPtr raw);
- public static void FreeEvent (IntPtr raw) => gdk_event_free (raw);
+ public static void FreeEvent (IntPtr raw)
+ {
+ if (raw != IntPtr.Zero)
+ gdk_event_free (raw);
+ }
}
public readonly struct KeyboardShortcut : IEquatable<KeyboardShortcut>
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.CodeCompletion/CompletionListWindow.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.CodeCompletion/CompletionListWindow.cs
index 9e7fef13ea..a954a6d4b2 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.CodeCompletion/CompletionListWindow.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.CodeCompletion/CompletionListWindow.cs
@@ -263,12 +263,6 @@ namespace MonoDevelop.Ide.CodeCompletion
controller.HideWindow ();
}
- [Obsolete("Use CompletionWindowManager.ToggleCategoryMode")]
- public void ToggleCategoryMode ()
- {
- controller.ToggleCategoryMode ();
- }
-
/// <summary>
/// Gets or sets a value indicating that shift was pressed during enter.
/// </summary>
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Composition/CompositionManager.Caching.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Composition/CompositionManager.Caching.cs
index 8793e3596a..9e71fd04a2 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Composition/CompositionManager.Caching.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Composition/CompositionManager.Caching.cs
@@ -27,7 +27,9 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
-using System.Reflection;
+using System.Reflection;
+using System.Reflection.Metadata;
+using System.Reflection.PortableExecutable;
using System.Threading.Tasks;
using Microsoft.VisualStudio.Composition;
using Mono.Addins;
@@ -52,18 +54,20 @@ namespace MonoDevelop.Ide.Composition
/// </summary>
internal class Caching
{
- internal static bool writeCache;
readonly ICachingFaultInjector cachingFaultInjector;
Task saveTask;
- public HashSet<Assembly> Assemblies { get; }
+ readonly HashSet<Assembly> loadedAssemblies;
+ public HashSet<Assembly> MefAssemblies { get; }
internal string MefCacheFile { get; }
internal string MefCacheControlFile { get; }
- public Caching (HashSet<Assembly> assemblies, Func<string, string> getCacheFilePath = null, ICachingFaultInjector cachingFaultInjector = null)
+ public Caching (HashSet<Assembly> mefAssemblies, Func<string, string> getCacheFilePath = null, ICachingFaultInjector cachingFaultInjector = null)
{
getCacheFilePath = getCacheFilePath ?? (file => Path.Combine (AddinManager.CurrentAddin.PrivateDataPath, file));
- Assemblies = assemblies;
+ loadedAssemblies = new HashSet<Assembly> (AppDomain.CurrentDomain.GetAssemblies ());
+
+ MefAssemblies = mefAssemblies;
MefCacheFile = getCacheFilePath ("mef-cache");
MefCacheControlFile = getCacheFilePath ("mef-cache-control");
this.cachingFaultInjector = cachingFaultInjector;
@@ -119,37 +123,58 @@ namespace MonoDevelop.Ide.Composition
LoggingService.LogError ("MEF cache control deserialized as null");
DeleteFiles ();
return false;
- }
+ }
- var currentAssemblies = new HashSet<string> (Assemblies.Select (asm => asm.Location));
-
- // Short-circuit on number of assemblies change
- if (controlCache.AssemblyInfos.Length != currentAssemblies.Count)
+ try {
+ // Short-circuit on number of assemblies change
+ if (controlCache.MefAssemblyInfos.Count != MefAssemblies.Count)
+ return false;
+
+ if (!ValidateAssemblyCacheListIntegrity (MefAssemblies, controlCache.MefAssemblyInfos, cachingFaultInjector))
+ return false;
+
+ if (!ValidateAssemblyCacheListIntegrity (loadedAssemblies, controlCache.AdditionalInputAssemblyInfos, cachingFaultInjector))
+ return false;
+ } catch (Exception e) {
+ LoggingService.LogError ("MEF cache validation failed", e);
return false;
+ }
- // Validate that the assemblies match and we have the same time stamps on them.
- foreach (var assemblyInfo in controlCache.AssemblyInfos) {
+ return true;
+ }
+
+ static bool ValidateAssemblyCacheListIntegrity (HashSet<Assembly> assemblies, List<MefControlCacheAssemblyInfo> cachedAssemblyInfos, ICachingFaultInjector cachingFaultInjector)
+ {
+ var currentAssemblies = new Dictionary<string, Guid> (assemblies.Count);
+ foreach (var asm in assemblies) {
+ if (asm.IsDynamic)
+ continue;
+
+ currentAssemblies.Add (asm.Location, asm.ManifestModule.ModuleVersionId);
+ }
+
+ foreach (var assemblyInfo in cachedAssemblyInfos) {
cachingFaultInjector?.FaultAssemblyInfo (assemblyInfo);
- if (!currentAssemblies.Contains (assemblyInfo.Location))
- return false;
- if (File.GetLastWriteTimeUtc (assemblyInfo.Location) != assemblyInfo.LastWriteTimeUtc)
+ if (!currentAssemblies.TryGetValue (assemblyInfo.Location, out var mvid))
return false;
- }
+ if (mvid != assemblyInfo.ModuleVersionId)
+ return false;
+ }
return true;
}
- internal Task Write (RuntimeComposition runtimeComposition, CachedComposition cacheManager)
+ internal Task Write (RuntimeComposition runtimeComposition, ComposableCatalog catalog, CachedComposition cacheManager)
{
return Runtime.RunInMainThread (async () => {
IdeApp.Exiting += IdeApp_Exiting;
saveTask = Task.Run (async () => {
try {
- await WriteMefCache (runtimeComposition, cacheManager);
+ await WriteMefCache (runtimeComposition, catalog, cacheManager);
} catch (Exception ex) {
- LoggingService.LogError ("Failed to write MEF cache", ex);
+ LoggingService.LogInternalError ("Failed to write MEF cache", ex);
}
});
await saveTask;
@@ -159,10 +184,10 @@ namespace MonoDevelop.Ide.Composition
});
}
- async Task WriteMefCache (RuntimeComposition runtimeComposition, CachedComposition cacheManager)
+ async Task WriteMefCache (RuntimeComposition runtimeComposition, ComposableCatalog catalog, CachedComposition cacheManager)
{
using (var timer = Counters.CompositionSave.BeginTiming ()) {
- WriteMefCacheControl (timer);
+ WriteMefCacheControl (catalog, timer);
// Serialize the MEF cache.
using (var stream = File.Open (MefCacheFile, FileMode.Create)) {
@@ -171,14 +196,41 @@ namespace MonoDevelop.Ide.Composition
}
}
- void WriteMefCacheControl (ITimeTracker timer)
- {
+ void WriteMefCacheControl (ComposableCatalog catalog, ITimeTracker timer)
+ {
+ var mefAssemblyNames = new HashSet<string> ();
+ var mefAssemblyInfos = new List<MefControlCacheAssemblyInfo> ();
+
+ foreach (var assembly in MefAssemblies) {
+ mefAssemblyNames.Add (assembly.GetName ().ToString ());
+
+ mefAssemblyInfos.Add (new MefControlCacheAssemblyInfo {
+ Location = assembly.Location,
+ ModuleVersionId = assembly.ManifestModule.ModuleVersionId,
+ });
+ }
+
+ var additionalInputAssemblies = new List<MefControlCacheAssemblyInfo> ();
+ var loadedMap = loadedAssemblies.ToDictionary (x => x.GetName ().ToString (), x => x);
+
+ foreach (var asm in catalog.GetInputAssemblies ()) {
+ var assemblyName = asm.ToString ();
+ if (mefAssemblyNames.Contains (assemblyName))
+ continue;
+
+ bool found = loadedMap.TryGetValue (assemblyName, out var assembly);
+ System.Diagnostics.Debug.Assert (found);
+
+ additionalInputAssemblies.Add (new MefControlCacheAssemblyInfo {
+ Location = assembly.Location,
+ ModuleVersionId = assembly.ManifestModule.ModuleVersionId,
+ });
+ }
+
// Create cache control data.
var controlCache = new MefControlCache {
- AssemblyInfos = Assemblies.Select (asm => new MefControlCacheAssemblyInfo {
- Location = asm.Location,
- LastWriteTimeUtc = File.GetLastWriteTimeUtc (asm.Location),
- }).ToArray (),
+ MefAssemblyInfos = mefAssemblyInfos,
+ AdditionalInputAssemblyInfos = additionalInputAssemblies,
};
var serializer = new JsonSerializer ();
@@ -195,7 +247,10 @@ namespace MonoDevelop.Ide.Composition
class MefControlCache
{
[JsonRequired]
- public MefControlCacheAssemblyInfo [] AssemblyInfos;
+ public List<MefControlCacheAssemblyInfo> MefAssemblyInfos;
+
+ [JsonRequired]
+ public List<MefControlCacheAssemblyInfo> AdditionalInputAssemblyInfos;
}
[Serializable]
@@ -205,7 +260,7 @@ namespace MonoDevelop.Ide.Composition
public string Location;
[JsonRequired]
- public DateTime LastWriteTimeUtc;
+ public Guid ModuleVersionId;
}
}
}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Composition/CompositionManager.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Composition/CompositionManager.cs
index fce217127d..8fe37a6e6e 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Composition/CompositionManager.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Composition/CompositionManager.cs
@@ -1,4 +1,4 @@
-// CompositionManager.cs
+// CompositionManager.cs
//
// Author:
// Kirill Osenkov <https://github.com/KirillOsenkov>
@@ -131,16 +131,17 @@ namespace MonoDevelop.Ide.Composition
var fullTimer = System.Diagnostics.Stopwatch.StartNew ();
var stepTimer = System.Diagnostics.Stopwatch.StartNew ();
- var assemblies = ReadAssembliesFromAddins (timer);
+ var mefAssemblies = ReadAssembliesFromAddins (timer);
timings ["ReadFromAddins"] = stepTimer.ElapsedMilliseconds;
stepTimer.Restart ();
- var caching = new Caching (assemblies);
+ var caching = new Caching (mefAssemblies);
// Try to use cached MEF data
var canUse = metadata.ValidCache = caching.CanUse ();
if (canUse) {
+ LoggingService.LogInfo ("Creating MEF composition from cache");
RuntimeComposition = await TryCreateRuntimeCompositionFromCache (caching);
}
timings ["LoadFromCache"] = stepTimer.ElapsedMilliseconds;
@@ -148,10 +149,12 @@ namespace MonoDevelop.Ide.Composition
// Otherwise fallback to runtime discovery.
if (RuntimeComposition == null) {
- RuntimeComposition = await CreateRuntimeCompositionFromDiscovery (caching, timer);
+ LoggingService.LogInfo ("Creating MEF composition from runtime");
+ var (runtimeComposition, catalog) = await CreateRuntimeCompositionFromDiscovery (caching, timer);
+ RuntimeComposition = runtimeComposition;
CachedComposition cacheManager = new CachedComposition ();
- caching.Write (RuntimeComposition, cacheManager).Ignore ();
+ caching.Write (RuntimeComposition, catalog, cacheManager).Ignore ();
}
timings ["LoadRuntimeComposition"] = stepTimer.ElapsedMilliseconds;
stepTimer.Restart ();
@@ -167,7 +170,7 @@ namespace MonoDevelop.Ide.Composition
internal static async Task<RuntimeComposition> TryCreateRuntimeCompositionFromCache (Caching caching)
{
- CachedComposition cacheManager = new CachedComposition ();
+ var cacheManager = new CachedComposition ();
try {
using (var cacheStream = caching.OpenCacheStream ()) {
@@ -180,9 +183,9 @@ namespace MonoDevelop.Ide.Composition
return null;
}
- internal static async Task<RuntimeComposition> CreateRuntimeCompositionFromDiscovery (Caching caching, ITimeTracker timer = null)
+ internal static async Task<(RuntimeComposition, ComposableCatalog)> CreateRuntimeCompositionFromDiscovery (Caching caching, ITimeTracker timer = null)
{
- var parts = await Discovery.CreatePartsAsync (caching.Assemblies);
+ var parts = await Discovery.CreatePartsAsync (caching.MefAssemblies);
timer?.Trace ("Composition parts discovered");
ComposableCatalog catalog = ComposableCatalog.Create (StandardResolver)
@@ -216,7 +219,7 @@ namespace MonoDevelop.Ide.Composition
var runtimeComposition = RuntimeComposition.CreateRuntimeComposition (configuration);
timer?.Trace ("Composition created");
- return runtimeComposition;
+ return (runtimeComposition, catalog);
}
internal static HashSet<Assembly> ReadAssembliesFromAddins (ITimeTracker<CompositionLoadMetadata> timer = null)
@@ -240,6 +243,7 @@ namespace MonoDevelop.Ide.Composition
string assemblyName = assemblyNode.FileName;
// Make sure the add-in that registered the assembly is loaded, since it can bring other
// other assemblies required to load this one
+
AddinManager.LoadAddin (null, id);
var assemblyFilePath = assemblyNode.Addin.GetFilePath (assemblyNode.FileName);
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/TextEditorViewContent.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/TextEditorViewContent.cs
index b4a27fa0df..160df00400 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/TextEditorViewContent.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/TextEditorViewContent.cs
@@ -384,8 +384,10 @@ namespace MonoDevelop.Ide.Editor
}
#endregion
-
-
+ public override void GrabFocus ()
+ {
+ textEditor.GrabFocus ();
+ }
}
} \ No newline at end of file
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Dialogs/NewFolderDialog.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Dialogs/NewFolderDialog.cs
new file mode 100644
index 0000000000..03785e23a7
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Dialogs/NewFolderDialog.cs
@@ -0,0 +1,221 @@
+//
+// NewFolderDialog.cs
+//
+// Author:
+// Matt Ward <matt.ward@microsoft.com>
+//
+// Copyright (c) 2019 Microsoft
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using MonoDevelop.Components;
+using MonoDevelop.Components.AtkCocoaHelper;
+using MonoDevelop.Core;
+using MonoDevelop.Ide.Gui.Pads.ProjectPad;
+using MonoDevelop.Ide.Tasks;
+using Xwt;
+
+namespace MonoDevelop.Ide.Gui.Dialogs
+{
+ class NewFolderDialog : Xwt.Dialog
+ {
+ readonly FilePath parentFolder;
+ TextEntry folderNameTextEntry;
+ DialogButton addButton;
+ InformationPopoverWidget warningPopover;
+
+ public NewFolderDialog (FilePath parentFolder)
+ {
+ this.parentFolder = parentFolder;
+
+ Build ();
+
+ folderNameTextEntry.Text = GetDefaultFolderName ();
+ folderNameTextEntry.SetFocus ();
+ folderNameTextEntry.Changed += FolderNameTextEntryChanged;
+ addButton.Clicked += AddButtonClicked;
+ }
+
+ public FilePath NewFolderCreated { get; private set; }
+
+ void Build ()
+ {
+ Padding = 0;
+ Resizable = false;
+ Width = 320;
+ Title = GettextCatalog.GetString ("New Folder");
+
+ var mainVBox = new VBox ();
+
+ var folderNameHBox = new HBox ();
+ folderNameHBox.Margin = 20;
+ var folderNameLabel = new Label ();
+ folderNameLabel.Text = GettextCatalog.GetString ("Folder Name:");
+ folderNameHBox.PackStart (folderNameLabel);
+
+ folderNameTextEntry = new TextEntry ();
+ folderNameHBox.PackStart (folderNameTextEntry, true, true);
+ folderNameTextEntry.SetCommonAccessibilityAttributes (
+ "NewFolderDialog.FolderNameTextEntry",
+ folderNameLabel.Text,
+ GettextCatalog.GetString ("Enter the name for the new folder"));
+
+ warningPopover = new InformationPopoverWidget ();
+ warningPopover.Visible = false;
+ folderNameHBox.PackStart (warningPopover);
+
+ mainVBox.PackStart (folderNameHBox);
+
+ var cancelButton = new DialogButton (Command.Cancel);
+ Buttons.Add (cancelButton);
+
+ addButton = new DialogButton (Command.Add);
+ Buttons.Add (addButton);
+
+ DefaultCommand = addButton.Command;
+
+ Content = mainVBox;
+ }
+
+ protected override void Dispose (bool disposing)
+ {
+ base.Dispose (disposing);
+ if (disposing) {
+ folderNameTextEntry.Changed -= FolderNameTextEntryChanged;
+ addButton.Clicked -= AddButtonClicked;
+ }
+ }
+
+ internal static Task<FilePath> Open (FilePath parentFolder)
+ {
+ var result = new TaskCompletionSource<FilePath> ();
+ Toolkit.NativeEngine.Invoke (delegate {
+ using (var dialog = new NewFolderDialog (parentFolder)) {
+ dialog.Run (MessageDialog.RootWindow);
+ result.SetResult (dialog.NewFolderCreated);
+ }
+ });
+ return result.Task;
+ }
+
+ string GetDefaultFolderName ()
+ {
+ string childFolderName = GettextCatalog.GetString ("New Folder");
+ string directoryName = Path.Combine (parentFolder, childFolderName);
+ int index = -1;
+
+ if (Directory.Exists (directoryName)) {
+ while (Directory.Exists (directoryName + (++index + 1))) {
+ }
+ }
+
+ if (index >= 0) {
+ return childFolderName += index + 1;
+ }
+ return childFolderName;
+ }
+
+ void FolderNameTextEntryChanged (object sender, EventArgs e)
+ {
+ FilePath directoryPath = GetNewFolderPath ();
+
+ if (folderNameTextEntry.Text.Length == 0) {
+ addButton.Sensitive = false;
+ HidePopoverMessage ();
+ } else if (!IsValidFolderName (directoryPath, folderNameTextEntry.Text)) {
+ ShowWarning (GettextCatalog.GetString ("The name you have chosen contains illegal characters. Please choose a different name."));
+ addButton.Sensitive = false;
+ } else if (Directory.Exists (directoryPath)) {
+ ShowWarning (GettextCatalog.GetString ("Folder name is already in use. Please choose a different name."));
+ addButton.Sensitive = false;
+ } else {
+ addButton.Sensitive = true;
+ HidePopoverMessage ();
+ }
+ }
+
+ void AddButtonClicked (object sender, EventArgs e)
+ {
+ try {
+ bool canClose = AddNewFolder ();
+ if (canClose) {
+ Close ();
+ }
+ } catch (Exception ex) {
+ LoggingService.LogError ("Could not create folder", ex);
+ ShowError (GettextCatalog.GetString ("An error occurred creating the folder. {0}", ex.Message));
+ }
+ }
+
+ FilePath GetNewFolderPath ()
+ {
+ return parentFolder.Combine (folderNameTextEntry.Text);
+ }
+
+ bool AddNewFolder ()
+ {
+ FilePath directoryPath = GetNewFolderPath ();
+
+ Directory.CreateDirectory (directoryPath);
+ NewFolderCreated = directoryPath;
+
+ return true;
+ }
+
+ bool IsValidFolderName (FilePath folderPath, string folderName)
+ {
+ return FileService.IsValidPath (folderPath) &&
+ !ProjectFolderCommandHandler.ContainsDirectorySeparator (folderName);
+ }
+
+ protected override void OnCommandActivated (Command cmd)
+ {
+ if (cmd == Command.Add) {
+ // Prevent dialog closing after Add button is activated since an alert message dialog may have been shown.
+ return;
+ }
+ base.OnCommandActivated (cmd);
+ }
+
+ void ShowWarning (string message)
+ {
+ ShowPopoverMessage (message, TaskSeverity.Warning);
+ }
+
+ void ShowError (string message)
+ {
+ ShowPopoverMessage (message, TaskSeverity.Error);
+ }
+
+ void ShowPopoverMessage (string message, TaskSeverity severity)
+ {
+ warningPopover.Message = message;
+ warningPopover.Severity = severity;
+ warningPopover.Show ();
+ }
+
+ void HidePopoverMessage ()
+ {
+ warningPopover.Hide ();
+ }
+ }
+}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Pads.ProjectPad/FolderNodeBuilder.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Pads.ProjectPad/FolderNodeBuilder.cs
index ac19f26664..73a8f2c1c8 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Pads.ProjectPad/FolderNodeBuilder.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Pads.ProjectPad/FolderNodeBuilder.cs
@@ -438,7 +438,6 @@ namespace MonoDevelop.Ide.Gui.Pads.ProjectPad
void OnFileInserted (ITreeNavigator nav)
{
nav.Selected = true;
- Tree.StartLabelEdit ();
}
///<summary>Imports files and folders from a target folder into the current folder</summary>
@@ -549,27 +548,20 @@ namespace MonoDevelop.Ide.Gui.Pads.ProjectPad
// project node is collapsed and Refresh was used the project node would not expand and the new folder
// node would not be selected.
CurrentNode.Expanded = true;
- Project project = CurrentNode.GetParentDataItem (typeof(Project), true) as Project;
-
+
+ var project = CurrentNode.GetParentDataItem (typeof (Project), true) as Project;
string baseFolderPath = GetFolderPath (CurrentNode.DataItem);
- string directoryName = Path.Combine (baseFolderPath, GettextCatalog.GetString("New Folder"));
- int index = -1;
- if (Directory.Exists(directoryName)) {
- while (Directory.Exists(directoryName + (++index + 1))) ;
- }
-
- if (index >= 0) {
- directoryName += index + 1;
- }
-
- Directory.CreateDirectory (directoryName);
-
- ProjectFile newFolder = new ProjectFile (directoryName);
+ FilePath folder = await NewFolderDialog.Open (baseFolderPath);
+
+ if (folder.IsNull)
+ return;
+
+ var newFolder = new ProjectFile (folder);
newFolder.Subtype = Subtype.Directory;
project.Files.Add (newFolder);
- Tree.AddNodeInsertCallback (new ProjectFolder (directoryName, project), new TreeNodeCallback (OnFileInserted));
+ Tree.AddNodeInsertCallback (new ProjectFolder (folder, project), new TreeNodeCallback (OnFileInserted));
await IdeApp.ProjectOperations.SaveAsync (project);
}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/BaseViewContent.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/BaseViewContent.cs
index e7c991caf4..028ad662c3 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/BaseViewContent.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/BaseViewContent.cs
@@ -33,6 +33,7 @@ using MonoDevelop.Components;
using MonoDevelop.Core;
using System.Collections.Immutable;
using MonoDevelop.Projects;
+using Gtk;
namespace MonoDevelop.Ide.Gui
{
@@ -159,6 +160,61 @@ namespace MonoDevelop.Ide.Gui
/// </summary>
/// <value>The display binding used to create this view.</value>
public IDisplayBinding Binding { get; internal set; }
+
+ public virtual void GrabFocus ()
+ {
+ Widget widget = Control;
+ Widget first = null;
+ foreach (var f in GetFocusableWidgets (widget)) {
+ if (f.HasFocus)
+ return;
+
+ if (first == null)
+ first = f;
+ }
+ if (first != null) {
+ first.GrabFocus ();
+ }
+ }
+
+ static IEnumerable<Gtk.Widget> GetFocusableWidgets (Gtk.Widget widget)
+ {
+ if (widget.CanFocus) {
+ yield return widget;
+ }
+
+ if (widget is Container c) {
+ foreach (var f in c.FocusChain.SelectMany (x => GetFocusableWidgets (x))) {
+ yield return f;
+ }
+
+ if (c.Children is var children) {
+ foreach (var f in children) {
+ if (f is Container container) {
+ foreach (var child in GetFocusableChildren (container)) {
+ yield return child;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ static IEnumerable<Gtk.Widget> GetFocusableChildren (Gtk.Container container)
+ {
+ if (container.CanFocus) {
+ yield return container;
+ }
+
+ foreach (var f in container.Children) {
+ if (f is Container c) {
+ foreach (var child in GetFocusableChildren (c)) {
+ yield return child;
+ }
+ }
+ }
+ }
+
}
public enum ProjectReloadCapability
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/DefaultWorkbench.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/DefaultWorkbench.cs
index 5aff4156f8..2a6c8e1d7a 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/DefaultWorkbench.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/DefaultWorkbench.cs
@@ -79,6 +79,7 @@ namespace MonoDevelop.Ide.Gui
IWorkbenchWindow lastActive;
bool closeAll;
+ bool? fullScreenState = null;
Rectangle normalBounds = new Rectangle(0, 0, MinimumWidth, MinimumHeight);
@@ -146,13 +147,20 @@ namespace MonoDevelop.Ide.Gui
public DockFrame DockFrame {
get { return dock; }
}
-
+
public bool FullScreen {
get {
return DesktopService.GetIsFullscreen (this);
}
set {
- DesktopService.SetIsFullscreen (this, value);
+ // If this window is not visible, don't set full screen mode
+ // until it is, as that would conflict with other windows we
+ // might be opening before (Start Window, for instance)
+ if (Visible) {
+ DesktopService.SetIsFullscreen (this, value);
+ } else {
+ fullScreenState = value;
+ }
}
}
@@ -738,6 +746,15 @@ namespace MonoDevelop.Ide.Gui
}
}
+ protected override void OnShown ()
+ {
+ base.OnShown ();
+ if (fullScreenState != null && fullScreenState != DesktopService.GetIsFullscreen (this)) {
+ DesktopService.SetIsFullscreen (this, (bool) fullScreenState);
+ fullScreenState = null;
+ }
+ }
+
bool closing;
protected /*override*/ async void OnClosing(object o, Gtk.DeleteEventArgs e)
{
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/SdiWorkspaceWindow.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/SdiWorkspaceWindow.cs
index ed23c84b9d..a1f25edd5e 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/SdiWorkspaceWindow.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/SdiWorkspaceWindow.cs
@@ -262,9 +262,10 @@ namespace MonoDevelop.Ide.Gui
{
if (subViewToolbar != null)
subViewToolbar.Tabs [subViewToolbar.ActiveTab].Activate ();
+ SelectWindow ();
}
- public void SelectWindow()
+ public void SelectWindow ()
{
var window = tabControl.Toplevel as Gtk.Window;
if (window != null) {
@@ -287,11 +288,10 @@ namespace MonoDevelop.Ide.Gui
// The tab change must be done now to ensure that the content is created
// before exiting this method.
tabControl.CurrentTabIndex = tab.Index;
-
// Focus the tab in the next iteration since presenting the window may take some time
Application.Invoke ((o, args) => {
DockNotebook.ActiveNotebook = tabControl;
- DeepGrabFocus (this.ActiveViewContent.Control);
+ ActiveViewContent.GrabFocus ();
});
}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/Workbench.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/Workbench.cs
index f1846c03ff..2669def837 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/Workbench.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/Workbench.cs
@@ -418,12 +418,6 @@ namespace MonoDevelop.Ide.Gui
AlertButton.CloseWithoutSave, AlertButton.Cancel, doc.Window.ViewContent.IsUntitled ? AlertButton.SaveAs : AlertButton.Save);
}
- [Obsolete("Use CloseAllDocumentsAsync")]
- public void CloseAllDocuments (bool leaveActiveDocumentOpen)
- {
- CloseAllDocumentsAsync (leaveActiveDocumentOpen).Ignore ();
- }
-
public async Task CloseAllDocumentsAsync (bool leaveActiveDocumentOpen)
{
Document[] docs = new Document [Documents.Count];
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Projects/ApplyPolicyDialog.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Projects/ApplyPolicyDialog.cs
index c301f2cbbf..5e6d401e43 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Projects/ApplyPolicyDialog.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Projects/ApplyPolicyDialog.cs
@@ -31,6 +31,7 @@ using MonoDevelop.Core;
using System.Collections.Generic;
using System.Text;
using MonoDevelop.Components;
+using MonoDevelop.Components.AtkCocoaHelper;
namespace MonoDevelop.Ide.Projects
{
@@ -59,6 +60,22 @@ namespace MonoDevelop.Ide.Projects
combPolicies.Active = 0;
OnRadioCustomToggled (null, null);
UpdateContentLabels ();
+
+ combPolicies.Accessible.Name = "ApplyPolicyDialog.PolicyCombo";
+ combPolicies.SetAccessibilityLabelRelationship (label2);
+ CombPolicies_Changed (null, null);
+ combPolicies.Changed += CombPolicies_Changed;
+ }
+
+ protected override void OnDestroyed ()
+ {
+ combPolicies.Changed -= CombPolicies_Changed;
+ base.OnDestroyed ();
+ }
+
+ void CombPolicies_Changed (object sender, EventArgs e)
+ {
+ combPolicies.Accessible.Description = GettextCatalog.GetString ("Select policy, current: {0}", combPolicies.ActiveText);
}
protected void OnRadioCustomToggled (object sender, System.EventArgs e)
@@ -189,7 +206,7 @@ namespace MonoDevelop.Ide.Projects
public PoliciesListSummaryTree () : base (new Gtk.ListStore (typeof (string)))
{
- CanFocus = false;
+ CanFocus = true;
HeadersVisible = false;
store = (Gtk.ListStore) Model;
this.AppendColumn ("", new Gtk.CellRendererText (), "text", 0);
@@ -204,6 +221,8 @@ namespace MonoDevelop.Ide.Projects
var win = evnt.Window;
win.Clear ();
if (string.IsNullOrEmpty (message)) {
+ if (ShowEmptyItem)
+ return base.OnExposeEvent (evnt);
return true;
}
@@ -233,7 +252,9 @@ namespace MonoDevelop.Ide.Projects
}
}
}
-
+
+ bool ShowEmptyItem { get; set; }
+
public void SetPolicies (PolicyContainer pset)
{
if (pset == null) {
@@ -279,6 +300,13 @@ namespace MonoDevelop.Ide.Projects
}
StringBuilderCache.Free (sb);
HasPolicies = sorted.Count > 0;
+ if (!HasPolicies) {
+ store.AppendValues (GettextCatalog.GetString ("No policies"));
+ ShowEmptyItem = true;
+ }
+ if (store.GetIterFirst (out var iter)) {
+ Selection.SelectIter (iter);
+ }
}
}
-} \ No newline at end of file
+}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Projects/ExportProjectPolicyDialog.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Projects/ExportProjectPolicyDialog.cs
index b10e87b681..a8574cac8c 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Projects/ExportProjectPolicyDialog.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Projects/ExportProjectPolicyDialog.cs
@@ -64,7 +64,6 @@ namespace MonoDevelop.Ide.Projects
tree.SetPolicies (policyProvider.Policies);
if (!tree.HasPolicies) {
- tree.Message = GettextCatalog.GetString ("No policies");
buttonOk.Sensitive = false;
}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopPersistentStorageLocationService.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopPersistentStorageLocationService.cs
index f5cc57498c..48ca40df10 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopPersistentStorageLocationService.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopPersistentStorageLocationService.cs
@@ -40,36 +40,124 @@ using Microsoft.CodeAnalysis.SQLite;
using Microsoft.CodeAnalysis.Storage;
using Microsoft.CodeAnalysis.SolutionSize;
using MonoDevelop.Core;
+using System.Diagnostics.Contracts;
+using System.Diagnostics;
namespace MonoDevelop.Ide.TypeSystem
{
[ExportWorkspaceService (typeof (IPersistentStorageLocationService), ServiceLayer.Host), Shared]
class MonoDevelopPersistentStorageLocationService : IPersistentStorageLocationService
{
+ private readonly object _gate = new object ();
+ private WorkspaceId primaryWorkspace = WorkspaceId.Empty;
+ private SolutionId _currentSolutionId = null;
+ private string _currentWorkingFolderPath = null;
+
+ public event EventHandler<PersistentStorageLocationChangingEventArgs> StorageLocationChanging;
+
+ [ImportingConstructor]
+ [Obsolete (MefConstruction.ImportingConstructorMessage, error: true)]
+ public MonoDevelopPersistentStorageLocationService ()
+ {
+ }
+
+ public IDisposable RegisterPrimaryWorkspace (WorkspaceId id)
+ {
+ if (primaryWorkspace.Equals (WorkspaceId.Empty)) {
+ primaryWorkspace = id;
+ return new WorkspaceRegistration (this);
+ }
+ return null;
+ }
+
+ class WorkspaceRegistration : IDisposable
+ {
+ readonly MonoDevelopPersistentStorageLocationService service;
+ bool disposed;
+
+ public WorkspaceRegistration (MonoDevelopPersistentStorageLocationService service) => this.service = service;
+
+ public void Dispose ()
+ {
+ if (!disposed) {
+ service.DisconnectCurrentStorage ();
+ disposed = true;
+ }
+ }
+ }
+
public bool IsSupported (Workspace workspace) => workspace is MonoDevelopWorkspace;
- // PERF: cache for the solution location. This is needed due to roslyn querying GetStorageLocation a lot of times.
- internal ConditionalWeakTable<SolutionId, string> storageMap = new ConditionalWeakTable<SolutionId, string> ();
+ public string TryGetStorageLocation (SolutionId solutionId)
+ {
+ lock (_gate) {
+ if (solutionId == _currentSolutionId) {
+ return _currentWorkingFolderPath;
+ }
+ }
- public event EventHandler<PersistentStorageLocationChangingEventArgs> StorageLocationChanging;
+ return null;
+ }
- internal void NotifyStorageLocationChanging (SolutionId sol, string path)
+ internal void SetupSolution (MonoDevelopWorkspace visualStudioWorkspace)
{
- lock (storageMap) {
- if (storageMap.TryGetValue (sol, out string cached) && path == cached)
+ lock (_gate) {
+ // Don't trigger events for workspaces other than those we want to inspect.
+ if (!primaryWorkspace.Equals (visualStudioWorkspace.Id))
+ return;
+
+ if (visualStudioWorkspace.CurrentSolution.Id == _currentSolutionId && _currentWorkingFolderPath != null) {
return;
+ }
- StorageLocationChanging?.Invoke (this, new PersistentStorageLocationChangingEventArgs (sol, path, true));
- storageMap.Remove (sol);
- storageMap.Add (sol, path);
+ var solution = visualStudioWorkspace.MonoDevelopSolution;
+ solution.Modified += OnSolutionModified;
+ if (string.IsNullOrWhiteSpace (solution.BaseDirectory))
+ return;
+
+ var workingFolderPath = solution.GetPreferencesDirectory ();
+
+ try {
+ if (!string.IsNullOrWhiteSpace (workingFolderPath)) {
+ OnWorkingFolderChanging_NoLock (
+ new PersistentStorageLocationChangingEventArgs (
+ visualStudioWorkspace.CurrentSolution.Id,
+ workingFolderPath,
+ mustUseNewStorageLocationImmediately: false));
+ }
+ } catch {
+ // don't crash just because solution having problem getting working folder information
+ }
}
}
- public string TryGetStorageLocation (SolutionId solutionId)
+ async void OnSolutionModified (object sender, MonoDevelop.Projects.WorkspaceItemEventArgs args)
+ {
+ var sol = (MonoDevelop.Projects.Solution)args.Item;
+ var workspace = await TypeSystemService.GetWorkspaceAsync (sol, CancellationToken.None);
+ if (workspace.Id.Equals (primaryWorkspace)) {
+ DisconnectCurrentStorage ();
+ }
+ }
+
+ private void OnWorkingFolderChanging_NoLock (PersistentStorageLocationChangingEventArgs eventArgs)
+ {
+ StorageLocationChanging?.Invoke (this, eventArgs);
+
+ _currentSolutionId = eventArgs.SolutionId;
+ _currentWorkingFolderPath = eventArgs.NewStorageLocation;
+ }
+
+ void DisconnectCurrentStorage ()
{
- lock (storageMap) {
- storageMap.TryGetValue (solutionId, out var path);
- return path;
+ lock (_gate) {
+ // We want to make sure everybody synchronously detaches
+ OnWorkingFolderChanging_NoLock (
+ new PersistentStorageLocationChangingEventArgs (
+ _currentSolutionId,
+ newStorageLocation: null,
+ mustUseNewStorageLocationImmediately: true));
+ primaryWorkspace = WorkspaceId.Empty;
}
}
}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.ProjectData.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.ProjectData.cs
index ff49e10dd0..3d62435d25 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.ProjectData.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.ProjectData.cs
@@ -48,9 +48,10 @@ namespace MonoDevelop.Ide.TypeSystem
DocumentData = new DocumentMap (projectId);
this.metadataReferences = new List<MonoDevelopMetadataReference> (metadataReferences.Length);
- System.Diagnostics.Debug.Assert (Monitor.IsEntered (ws.updatingProjectDataLock));
- foreach (var metadataReference in metadataReferences) {
- AddMetadataReference_NoLock (metadataReference, ws);
+ lock (this.metadataReferences) {
+ foreach (var metadataReference in metadataReferences) {
+ AddMetadataReference_NoLock (metadataReference, ws);
+ }
}
}
@@ -61,7 +62,7 @@ namespace MonoDevelop.Ide.TypeSystem
if (!workspaceRef.TryGetTarget (out var workspace))
return;
- lock (workspace.updatingProjectDataLock) {
+ lock (metadataReferences) {
if (!RemoveMetadataReference_NoLock (reference, workspace))
return;
workspace.OnMetadataReferenceRemoved (projectId, args.OldSnapshot);
@@ -73,7 +74,7 @@ namespace MonoDevelop.Ide.TypeSystem
void AddMetadataReference_NoLock (MonoDevelopMetadataReference metadataReference, MonoDevelopWorkspace ws)
{
- System.Diagnostics.Debug.Assert (Monitor.IsEntered (ws.updatingProjectDataLock));
+ System.Diagnostics.Debug.Assert (Monitor.IsEntered (metadataReferences));
metadataReferences.Add (metadataReference);
metadataReference.SnapshotUpdated += OnMetadataReferenceUpdated;
@@ -81,7 +82,7 @@ namespace MonoDevelop.Ide.TypeSystem
bool RemoveMetadataReference_NoLock (MonoDevelopMetadataReference metadataReference, MonoDevelopWorkspace ws)
{
- System.Diagnostics.Debug.Assert (Monitor.IsEntered (ws.updatingProjectDataLock));
+ System.Diagnostics.Debug.Assert (Monitor.IsEntered (metadataReferences));
metadataReference.SnapshotUpdated -= OnMetadataReferenceUpdated;
return metadataReferences.Remove (metadataReference);
@@ -92,9 +93,10 @@ namespace MonoDevelop.Ide.TypeSystem
if (!workspaceRef.TryGetTarget (out var ws))
return;
- System.Diagnostics.Debug.Assert (Monitor.IsEntered (ws.updatingProjectDataLock));
- foreach (var reference in metadataReferences)
- reference.SnapshotUpdated -= OnMetadataReferenceUpdated;
+ lock (metadataReferences) {
+ foreach (var reference in metadataReferences)
+ reference.SnapshotUpdated -= OnMetadataReferenceUpdated;
+ }
}
}
}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.ProjectDataMap.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.ProjectDataMap.cs
index 3cdf74b32b..0d0561eb5b 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.ProjectDataMap.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.ProjectDataMap.cs
@@ -26,6 +26,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
+using System.Linq;
using Microsoft.CodeAnalysis;
namespace MonoDevelop.Ide.TypeSystem
@@ -39,8 +40,8 @@ namespace MonoDevelop.Ide.TypeSystem
ImmutableDictionary<ProjectId, MonoDevelop.Projects.Project> projectIdToMdProjectMap = ImmutableDictionary<ProjectId, MonoDevelop.Projects.Project>.Empty;
readonly Dictionary<MonoDevelop.Projects.Project, ProjectId> projectIdMap = new Dictionary<MonoDevelop.Projects.Project, ProjectId> ();
- // FIXME: Make this private
- internal readonly Dictionary<ProjectId, ProjectData> projectDataMap = new Dictionary<ProjectId, ProjectData> ();
+ readonly Dictionary<ProjectId, ProjectData> projectDataMap = new Dictionary<ProjectId, ProjectData> ();
+ readonly object updatingProjectDataLock = new object ();
public ProjectDataMap (MonoDevelopWorkspace workspace)
{
@@ -92,7 +93,7 @@ namespace MonoDevelop.Ide.TypeSystem
projectIdToMdProjectMap = projectIdToMdProjectMap.Remove (val);
}
- lock (Workspace.updatingProjectDataLock) {
+ lock (updatingProjectDataLock) {
projectDataMap.Remove (id);
}
}
@@ -106,14 +107,14 @@ namespace MonoDevelop.Ide.TypeSystem
internal bool Contains (ProjectId projectId)
{
- lock (Workspace.updatingProjectDataLock) {
+ lock (updatingProjectDataLock) {
return projectDataMap.ContainsKey (projectId);
}
}
internal ProjectData GetData (ProjectId id)
{
- lock (Workspace.updatingProjectDataLock) {
+ lock (updatingProjectDataLock) {
projectDataMap.TryGetValue (id, out ProjectData result);
return result;
}
@@ -121,7 +122,7 @@ namespace MonoDevelop.Ide.TypeSystem
internal ProjectData RemoveData (ProjectId id)
{
- lock (Workspace.updatingProjectDataLock) {
+ lock (updatingProjectDataLock) {
if (projectDataMap.TryGetValue (id, out ProjectData result)) {
projectDataMap.Remove (id);
result.Disconnect ();
@@ -132,12 +133,18 @@ namespace MonoDevelop.Ide.TypeSystem
internal ProjectData CreateData (ProjectId id, ImmutableArray<MonoDevelopMetadataReference> metadataReferences)
{
- lock (Workspace.updatingProjectDataLock) {
+ lock (updatingProjectDataLock) {
var result = new ProjectData (id, metadataReferences, Workspace);
projectDataMap [id] = result;
return result;
}
}
+ internal ProjectId[] GetProjectIds ()
+ {
+ lock (updatingProjectDataLock) {
+ return projectDataMap.Keys.ToArray ();
+ }
+ }
}
}
} \ No newline at end of file
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.ProjectSystemHandler.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.ProjectSystemHandler.cs
index 66d10598f3..e1a5ef532d 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.ProjectSystemHandler.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.ProjectSystemHandler.cs
@@ -43,7 +43,7 @@ namespace MonoDevelop.Ide.TypeSystem
{
public partial class MonoDevelopWorkspace
{
- internal class ProjectSystemHandler
+ internal class ProjectSystemHandler : IDisposable
{
readonly MonoDevelopWorkspace workspace;
readonly ProjectDataMap projectMap;
@@ -51,6 +51,8 @@ namespace MonoDevelop.Ide.TypeSystem
readonly Lazy<MetadataReferenceHandler> metadataHandler;
readonly Lazy<HostDiagnosticUpdateSource> hostDiagnosticUpdateSource;
readonly HackyWorkspaceFilesCache hackyCache;
+ readonly List<MonoDevelopAnalyzer> analyzersToDispose = new List<MonoDevelopAnalyzer> ();
+ IDisposable persistentStorageLocationServiceRegistration;
bool added;
readonly object addLock = new object ();
@@ -66,6 +68,10 @@ namespace MonoDevelop.Ide.TypeSystem
metadataHandler = new Lazy<MetadataReferenceHandler> (() => new MetadataReferenceHandler (workspace.MetadataReferenceManager, projectMap));
hostDiagnosticUpdateSource = new Lazy<HostDiagnosticUpdateSource> (() => new HostDiagnosticUpdateSource (workspace, Composition.CompositionManager.GetExportedValue<IDiagnosticUpdateSourceRegistrationService> ()));
+
+ var persistentStorageLocationService = (MonoDevelopPersistentStorageLocationService)workspace.Services.GetService<IPersistentStorageLocationService> ();
+ if (workspace.MonoDevelopSolution != null)
+ persistentStorageLocationServiceRegistration = persistentStorageLocationService.RegisterPrimaryWorkspace (workspace.Id);
}
#region Solution mapping
@@ -84,26 +90,6 @@ namespace MonoDevelop.Ide.TypeSystem
return result;
}
}
-
- static async void OnSolutionModified (object sender, MonoDevelop.Projects.WorkspaceItemEventArgs args)
- {
- var sol = (MonoDevelop.Projects.Solution)args.Item;
- var workspace = await TypeSystemService.GetWorkspaceAsync (sol, CancellationToken.None);
- var solId = workspace.ProjectHandler.GetSolutionId (sol);
- if (solId == null)
- return;
-
- NotifySolutionModified (sol, solId, workspace);
- }
-
- static void NotifySolutionModified (MonoDevelop.Projects.Solution sol, SolutionId solId, MonoDevelopWorkspace workspace)
- {
- if (string.IsNullOrWhiteSpace (sol.BaseDirectory))
- return;
-
- var locService = (MonoDevelopPersistentStorageLocationService)workspace.Services.GetService<IPersistentStorageLocationService> ();
- locService.NotifyStorageLocationChanging (solId, sol.GetPreferencesDirectory ());
- }
#endregion
class SolutionData
@@ -122,7 +108,7 @@ namespace MonoDevelop.Ide.TypeSystem
fileName = new FilePath (p.Name + ".dll");
if (!hackyCache.TryGetCachedItems (p, workspace.MetadataReferenceManager, projectMap, out var sourceFiles, out var analyzerFiles, out var references, out var projectReferences)) {
- (references, projectReferences) = await metadataHandler.Value.CreateReferences (p, token);
+ (references, projectReferences) = await metadataHandler.Value.CreateReferences (p, token).ConfigureAwait (false);
if (token.IsCancellationRequested)
return null;
@@ -141,37 +127,46 @@ namespace MonoDevelop.Ide.TypeSystem
var loader = workspace.Services.GetService<IAnalyzerService> ().GetLoader ();
- lock (workspace.updatingProjectDataLock) {
+ ProjectData projectData, oldProjectData;
+ List<DocumentInfo> mainDocuments, additionalDocuments;
+ try {
+ await workspace.LoadLock.WaitAsync ().ConfigureAwait (false);
//when reloading e.g. after a save, preserve document IDs
- var oldProjectData = projectMap.RemoveData (projectId);
- var projectData = projectMap.CreateData (projectId, references);
+ oldProjectData = projectMap.RemoveData (projectId);
+ projectData = projectMap.CreateData (projectId, references);
- var documents = CreateDocuments (projectData, p, token, sourceFiles, oldProjectData);
+ var documents = await CreateDocuments (projectData, p, token, sourceFiles, oldProjectData).ConfigureAwait (false);
if (documents == null)
return null;
- // TODO: Pass in the WorkspaceMetadataFileReferenceResolver
- var info = ProjectInfo.Create (
- projectId,
- VersionStamp.Create (),
- p.Name,
- fileName.FileNameWithoutExtension,
- (p as MonoDevelop.Projects.DotNetProject)?.RoslynLanguageName ?? LanguageNames.CSharp,
- p.FileName,
- fileName,
- cp?.CreateCompilationOptions (),
- cp?.CreateParseOptions (config),
- documents.Item1,
- projectReferences,
- references.Select (x => x.CurrentSnapshot),
- analyzerReferences: analyzerFiles.SelectAsArray (x => {
- var analyzer = new MonoDevelopAnalyzer (x, hostDiagnosticUpdateSource.Value, projectId, workspace, loader, LanguageNames.CSharp);
- return analyzer.GetReference ();
- }),
- additionalDocuments: documents.Item2
- );
- return info;
+ mainDocuments = documents.Item1;
+ additionalDocuments = documents.Item2;
+ } finally {
+ workspace.LoadLock.Release ();
}
+
+ // TODO: Pass in the WorkspaceMetadataFileReferenceResolver
+ var info = ProjectInfo.Create (
+ projectId,
+ VersionStamp.Create (),
+ p.Name,
+ fileName.FileNameWithoutExtension,
+ (p as MonoDevelop.Projects.DotNetProject)?.RoslynLanguageName ?? LanguageNames.CSharp,
+ p.FileName,
+ fileName,
+ cp?.CreateCompilationOptions (),
+ cp?.CreateParseOptions (config),
+ mainDocuments,
+ projectReferences,
+ references.Select (x => x.CurrentSnapshot),
+ analyzerReferences: analyzerFiles.SelectAsArray (x => {
+ var analyzer = new MonoDevelopAnalyzer (x, hostDiagnosticUpdateSource.Value, projectId, workspace, loader, LanguageNames.CSharp);
+ analyzersToDispose.Add (analyzer);
+ return analyzer.GetReference ();
+ }),
+ additionalDocuments: additionalDocuments
+ );
+ return info;
}
async Task<ConcurrentBag<ProjectInfo>> CreateProjectInfos (IEnumerable<MonoDevelop.Projects.Project> mdProjects, CancellationToken token)
@@ -278,9 +273,6 @@ namespace MonoDevelop.Ide.TypeSystem
lock (addLock) {
if (!added) {
added = true;
- solution.Modified += OnSolutionModified;
- NotifySolutionModified (solution, solutionId, workspace);
- workspace.OnSolutionAdded (solutionInfo);
OnSolutionOpened (workspace, solutionInfo);
}
}
@@ -296,6 +288,11 @@ namespace MonoDevelop.Ide.TypeSystem
void OnSolutionOpened (MonoDevelopWorkspace workspace, SolutionInfo solutionInfo)
{
+ var service = (MonoDevelopPersistentStorageLocationService)workspace.Services.GetService<IPersistentStorageLocationService> ();
+ service.SetupSolution (workspace);
+
+ workspace.OnSolutionAdded (solutionInfo);
+
AssignOpenDocumentsToWorkspace (workspace);
OpenGeneratedFiles (workspace);
}
@@ -336,7 +333,7 @@ namespace MonoDevelop.Ide.TypeSystem
return node.Parser.CanGenerateAnalysisDocument (mimeType, f.BuildAction, p.SupportedLanguages);
}
- Tuple<List<DocumentInfo>, List<DocumentInfo>> CreateDocuments (ProjectData projectData, MonoDevelop.Projects.Project p, CancellationToken token, ImmutableArray<MonoDevelop.Projects.ProjectFile> sourceFiles, ProjectData oldProjectData)
+ async Task<Tuple<List<DocumentInfo>, List<DocumentInfo>>> CreateDocuments (ProjectData projectData, MonoDevelop.Projects.Project p, CancellationToken token, ImmutableArray<MonoDevelop.Projects.ProjectFile> sourceFiles, ProjectData oldProjectData)
{
var documents = new List<DocumentInfo> ();
// We don' add additionalDocuments anymore because they were causing slowdown of compilation generation
@@ -357,7 +354,7 @@ namespace MonoDevelop.Ide.TypeSystem
continue;
documents.Add (CreateDocumentInfo (solutionData, p.Name, projectData, f));
} else {
- foreach (var projectedDocument in GenerateProjections (f, projectData.DocumentData, p, oldProjectData, null)) {
+ foreach (var projectedDocument in await GenerateProjections (f, projectData.DocumentData, p, token, oldProjectData, null)) {
var projectedId = projectData.DocumentData.GetOrCreate (projectedDocument.FilePath, oldProjectData?.DocumentData);
if (!duplicates.Add (projectedId))
continue;
@@ -375,41 +372,44 @@ namespace MonoDevelop.Ide.TypeSystem
return Tuple.Create (documents, additionalDocuments);
}
- IEnumerable<DocumentInfo> GenerateProjections (MonoDevelop.Projects.ProjectFile f, DocumentMap documentMap, MonoDevelop.Projects.Project p, ProjectData oldProjectData, HashSet<DocumentId> duplicates)
+ async Task<List<DocumentInfo>> GenerateProjections (MonoDevelop.Projects.ProjectFile f, DocumentMap documentMap, MonoDevelop.Projects.Project p, CancellationToken token, ProjectData oldProjectData, HashSet<DocumentId> duplicates)
{
var mimeType = DesktopService.GetMimeTypeForUri (f.FilePath);
var node = TypeSystemService.GetTypeSystemParserNode (mimeType, f.BuildAction);
if (node == null || !node.Parser.CanGenerateProjection (mimeType, f.BuildAction, p.SupportedLanguages))
- yield break;
+ return new List<DocumentInfo> ();
+
var options = new ParseOptions {
FileName = f.FilePath,
Project = p,
Content = TextFileProvider.Instance.GetReadOnlyTextEditorData (f.FilePath),
};
- var generatedProjections = node.Parser.GenerateProjections (options);
+ var generatedProjections = await node.Parser.GenerateProjections (options, token);
var list = new List<Projection> ();
var entry = new ProjectionEntry {
File = f,
Projections = list,
};
- foreach (var projection in generatedProjections.Result) {
+ var result = new List<DocumentInfo> (generatedProjections.Count);
+ foreach (var projection in generatedProjections) {
list.Add (projection);
if (duplicates != null && !duplicates.Add (documentMap.GetOrCreate (projection.Document.FileName, oldProjectData?.DocumentData)))
continue;
var plainName = projection.Document.FileName.FileName;
var folders = GetFolders (p.Name, f);
- yield return DocumentInfo.Create (
+ result.Add(DocumentInfo.Create (
documentMap.GetOrCreate (projection.Document.FileName, oldProjectData?.DocumentData),
plainName,
folders,
SourceCodeKind.Regular,
TextLoader.From (TextAndVersion.Create (new MonoDevelopSourceText (projection.Document), VersionStamp.Create (), projection.Document.FileName)),
projection.Document.FileName,
- false
+ false)
);
}
projections.AddProjectionEntry (entry);
+ return result;
}
static DocumentInfo CreateDocumentInfo (SolutionData data, string projectName, ProjectData id, MonoDevelop.Projects.ProjectFile f)
@@ -434,6 +434,17 @@ namespace MonoDevelop.Ide.TypeSystem
{
return new [] { projectName }.Concat (f.ProjectVirtualPath.ParentDirectory.ToString ().Split (Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar));
}
+
+ public void Dispose ()
+ {
+ persistentStorageLocationServiceRegistration?.Dispose ();
+
+ solutionIdMap.Clear ();
+
+ foreach (var analyzer in analyzersToDispose)
+ analyzer.Dispose ();
+ analyzersToDispose.Clear ();
+ }
}
}
}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.cs
index 485885b12b..bb7c9bcb68 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.cs
@@ -76,8 +76,9 @@ namespace MonoDevelop.Ide.TypeSystem
internal readonly WorkspaceId Id;
CancellationTokenSource src = new CancellationTokenSource ();
- bool disposed;
- readonly object updatingProjectDataLock = new object ();
+ bool disposed;
+
+ internal readonly SemaphoreSlim LoadLock = new SemaphoreSlim (1, 1);
Lazy<MonoDevelopMetadataReferenceManager> manager;
Lazy<MetadataReferenceHandler> metadataHandler;
ProjectionData Projections { get; }
@@ -254,12 +255,12 @@ namespace MonoDevelop.Ide.TypeSystem
protected override void Dispose (bool finalize)
{
- base.Dispose (finalize);
if (disposed)
return;
disposed = true;
+ ProjectHandler.Dispose ();
MetadataReferenceManager.ClearCache ();
IdeApp.Preferences.EnableSourceAnalysis.Changed -= OnEnableSourceAnalysisChanged;
@@ -281,8 +282,10 @@ namespace MonoDevelop.Ide.TypeSystem
if (backgroundCompiler != null) {
backgroundCompiler.Dispose ();
- backgroundCompiler = null; // PartialSemanticsEnabled will now return false
+ backgroundCompiler = null; // PartialSemanticsEnabled will now return false
}
+
+ base.Dispose (finalize);
}
internal void InformDocumentTextChange (DocumentId id, SourceText text)
@@ -723,9 +726,9 @@ namespace MonoDevelop.Ide.TypeSystem
var projections = await node.Parser.GenerateProjections (options);
UpdateProjectionEntry (file, projections);
var projectId = GetProjectId (project);
- var projectdata = ProjectMap.GetData (projectId);
- foreach (var projected in projections) {
- OnDocumentTextChanged (projectdata.DocumentData.Get (projected.Document.FileName), new MonoDevelopSourceText (projected.Document), PreservationMode.PreserveValue);
+ var projectdata = ProjectMap.GetData (projectId);
+ foreach (var projected in projections) {
+ OnDocumentTextChanged (projectdata.DocumentData.Get (projected.Document.FileName), new MonoDevelopSourceText (projected.Document), PreservationMode.PreserveValue);
}
}
}
@@ -1091,41 +1094,43 @@ namespace MonoDevelop.Ide.TypeSystem
return project.GetAdditionalDocument (documentId);
}
- internal Task UpdateFileContent (string fileName, string text)
+ internal async Task UpdateFileContent (string fileName, string text)
{
SourceText newText = SourceText.From (text);
var tasks = new List<Task> ();
- lock (updatingProjectDataLock) {
- foreach (var kv in ProjectMap.projectDataMap) {
- var projectId = kv.Key;
- var docId = this.GetDocumentId (projectId, fileName);
- if (docId != null) {
- try {
- if (this.GetDocument (docId) != null) {
- OnDocumentTextChanged (docId, newText, PreservationMode.PreserveIdentity);
- } else if (this.GetAdditionalDocument (docId) != null) {
- base.OnAdditionalDocumentTextChanged (docId, newText, PreservationMode.PreserveIdentity);
- }
- } catch (Exception e) {
- LoggingService.LogWarning ("Roslyn error on text change", e);
- }
- }
- var monoProject = GetMonoProject (projectId);
- if (monoProject != null) {
- var pf = monoProject.GetProjectFile (fileName);
- if (pf != null) {
- var mimeType = DesktopService.GetMimeTypeForUri (fileName);
- if (TypeSystemService.CanParseProjections (monoProject, mimeType, fileName)) {
- var parseOptions = new ParseOptions { Project = monoProject, FileName = fileName, Content = new StringTextSource (text), BuildAction = pf.BuildAction };
- var task = TypeSystemService.ParseProjection (parseOptions, mimeType);
- tasks.Add (task);
- }
- }
- }
- }
+ try {
+ await LoadLock.WaitAsync ();
+ foreach (var projectId in ProjectMap.GetProjectIds ()) {
+ var docId = this.GetDocumentId (projectId, fileName);
+ if (docId != null) {
+ try {
+ if (this.GetDocument (docId) != null) {
+ base.OnDocumentTextChanged (docId, newText, PreservationMode.PreserveIdentity);
+ } else if (this.GetAdditionalDocument (docId) != null) {
+ base.OnAdditionalDocumentTextChanged (docId, newText, PreservationMode.PreserveIdentity);
+ }
+ } catch (Exception e) {
+ LoggingService.LogWarning ("Roslyn error on text change", e);
+ }
+ }
+ var monoProject = GetMonoProject (projectId);
+ if (monoProject != null) {
+ var pf = monoProject.GetProjectFile (fileName);
+ if (pf != null) {
+ var mimeType = DesktopService.GetMimeTypeForUri (fileName);
+ if (TypeSystemService.CanParseProjections (monoProject, mimeType, fileName)) {
+ var parseOptions = new ParseOptions { Project = monoProject, FileName = fileName, Content = new StringTextSource (text), BuildAction = pf.BuildAction };
+ var task = TypeSystemService.ParseProjection (parseOptions, mimeType);
+ tasks.Add (task);
+ }
+ }
+ }
+ }
+ } finally {
+ LoadLock.Release ();
}
- return Task.WhenAll (tasks);
+ await Task.WhenAll (tasks);
}
internal void RemoveProject (MonoDevelop.Projects.Project project)
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/TypeSystemParserNode.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/TypeSystemParserNode.cs
index fbd88c1e4c..3124ad9a0d 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/TypeSystemParserNode.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/TypeSystemParserNode.cs
@@ -84,16 +84,5 @@ namespace MonoDevelop.Ide.TypeSystem
}
return false;
}
-
- [Obsolete ("Use p.IsCompileable")]
- public static bool IsCompileableFile (ProjectFile file, out Microsoft.CodeAnalysis.SourceCodeKind sck)
- => IsCompileableFile (null, file, out sck);
-
- [Obsolete ("Use p.IsCompileable")]
- public static bool IsCompileableFile (MonoDevelop.Projects.Project p, ProjectFile file, out Microsoft.CodeAnalysis.SourceCodeKind sck)
- {
- sck = file.SourceCodeKind;
- return p.IsCompileable (file.FilePath);
- }
}
}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/TypeSystemService.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/TypeSystemService.cs
index 5a10d45e8b..541589e497 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/TypeSystemService.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/TypeSystemService.cs
@@ -237,11 +237,16 @@ namespace MonoDevelop.Ide.TypeSystem
var projectFile = options.Project.GetProjectFile (options.FileName);
if (projectFile != null) {
ws.UpdateProjectionEntry (projectFile, result.Projections);
- foreach (var projection in result.Projections) {
- var docId = ws.GetDocumentId (projectId, projection.Document.FileName);
- if (docId != null) {
- ws.InformDocumentTextChange (docId, new MonoDevelopSourceText (projection.Document));
+ await ws.LoadLock.WaitAsync ();
+ try {
+ foreach (var projection in result.Projections) {
+ var docId = ws.GetDocumentId (projectId, projection.Document.FileName);
+ if (docId != null) {
+ ws.InformDocumentTextChange (docId, new MonoDevelopSourceText (projection.Document));
+ }
}
+ } finally {
+ ws.LoadLock.Release ();
}
}
}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.csproj b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.csproj
index f7dd7ddd67..a81b6a6027 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.csproj
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.csproj
@@ -4195,6 +4195,9 @@
<Compile Include="MonoDevelop.Components\Mac\NSStackViewExtensions.cs" />
<Compile Include="MonoDevelop.Components\Mac\NSLabel.cs" />
<Compile Include="MonoDevelop.Components\Mac\NSLine.cs" />
+ <Compile Include="MonoDevelop.Ide.Projects\NewSolutionRunConfigurationDialog.cs" />
+ <Compile Include="MonoDevelop.Ide.TypeSystem\HackyWorkspaceFilesCache.cs" />
+ <Compile Include="MonoDevelop.Ide.Gui.Dialogs\NewFolderDialog.cs" />
</ItemGroup>
<ItemGroup>
<Data Include="options\DefaultEditingLayout.xml" />
@@ -4294,4 +4297,4 @@
<Target Name="AfterBuild">
<Copy SourceFiles="@(Data)" DestinationFolder="..\..\..\build\data\%(Data.RelativeDir)" SkipUnchangedFiles="true" />
</Target>
-</Project> \ No newline at end of file
+</Project>
diff --git a/main/src/core/MonoDevelop.Projects.Formats.MSBuild/MonoDevelop.MSBuildResolver/Resolver.cs b/main/src/core/MonoDevelop.Projects.Formats.MSBuild/MonoDevelop.MSBuildResolver/Resolver.cs
index 5deb40613d..d899b0fcf1 100644
--- a/main/src/core/MonoDevelop.Projects.Formats.MSBuild/MonoDevelop.MSBuildResolver/Resolver.cs
+++ b/main/src/core/MonoDevelop.Projects.Formats.MSBuild/MonoDevelop.MSBuildResolver/Resolver.cs
@@ -82,7 +82,7 @@ namespace MonoDevelop.Projects.MSBuild
// Pick the SDK with the highest version
foreach (var sdk in sdkFetcher ()) {
- if (sdk.Name == sdkReference.Name) {
+ if (StringComparer.OrdinalIgnoreCase.Equals (sdk.Name, sdkReference.Name)) {
if (sdk.Version != null) {
// If the sdk has a version, it must satisfy the min version requirement
if (minVersion != null && sdk.Version < minVersion)
diff --git a/main/src/tools/ExtensionTools/AddinDependencyTreeWidget.cs b/main/src/tools/ExtensionTools/AddinDependencyTreeWidget.cs
new file mode 100644
index 0000000000..311f852b83
--- /dev/null
+++ b/main/src/tools/ExtensionTools/AddinDependencyTreeWidget.cs
@@ -0,0 +1,144 @@
+//
+// AddinDependencyTreeWidget.cs
+//
+// Author:
+// Marius Ungureanu <maungu@microsoft.com>
+//
+// Copyright (c) 2018 Microsoft Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+using System.Collections.Generic;
+using Mono.Addins;
+using Mono.Addins.Description;
+using Xwt;
+namespace MonoDevelop.ExtensionTools
+{
+ class AddinDependencyTreeWidget : Widget
+ {
+ readonly TreeStore treeStore;
+ readonly TreeView treeView;
+ readonly DataField<string> labelField = new DataField<string> ();
+ readonly Label summary = new Label ();
+
+ public AddinDependencyTreeWidget (Addin[] addins = null)
+ {
+ addins = addins ?? AddinManager.Registry.GetAllAddins ();
+
+ treeStore = new TreeStore (labelField);
+ treeView = new TreeView (treeStore);
+
+ var col = treeView.Columns.Add ("Name", labelField);
+ col.Expands = true;
+
+ FillData (addins);
+ treeView.ExpandAll ();
+
+ var vbox = new VBox ();
+ vbox.PackStart (summary);
+ vbox.PackStart (treeView, true);
+ Content = vbox;
+ }
+
+ void FillData(Addin[] addins)
+ {
+ var roots = MakeDependencyTree (addins);
+ var node = treeStore.AddNode ();
+
+ node.SetValue (labelField, "Root");
+ int depth = BuildTree (node, roots, new HashSet<AddinNode> (), 1);
+
+ summary.Text = $"Depth: {depth}";
+ }
+
+ int BuildTree (TreeNavigator currentPosition, IEnumerable<AddinNode> addins, HashSet<AddinNode> visited, int currentDepth)
+ {
+ int maxDepth = currentDepth;
+
+ foreach (var addinNode in addins) {
+ if (!visited.Add (addinNode))
+ continue;
+
+ var node = currentPosition.Clone ().AddChild ();
+ node.SetValue (labelField, addinNode.Label);
+
+ var childDepth = BuildTree (node, addinNode.Children, visited, currentDepth + 1);
+ maxDepth = Math.Max (maxDepth, childDepth);
+ }
+
+ return maxDepth;
+ }
+
+ List<AddinNode> MakeDependencyTree (Addin[] addins)
+ {
+ var cache = new Dictionary<Addin, AddinNode> ();
+ var roots = new List<AddinNode> ();
+
+ foreach (var addin in addins) {
+ var addinNode = GetOrCreateNode (addin);
+
+ if (addin.Description.IsRoot)
+ roots.Add (addinNode);
+ }
+
+ foreach (var kvp in cache) {
+ var addin = kvp.Key;
+ var addinNode = kvp.Value;
+
+ // TODO: handle optional dependencies and other modules
+ foreach (Dependency dep in addin.Description.MainModule.Dependencies) {
+ if (dep is AddinDependency adep) {
+ string adepid = Addin.GetFullId (addin.Namespace, adep.AddinId, adep.Version);
+
+ var addinDep = AddinManager.Registry.GetAddin (adepid);
+
+ cache [addinDep].Children.Add (addinNode);
+ }
+ }
+ }
+
+ return roots;
+
+ AddinNode GetOrCreateNode (Addin addin)
+ {
+ if (!cache.TryGetValue (addin, out var addinNode)) {
+ var addinLabel = Addin.GetIdName (addin.Id);
+ cache [addin] = addinNode = new AddinNode (addinLabel);
+ }
+ return addinNode;
+ }
+ }
+
+ class AddinNode : IEquatable<AddinNode>
+ {
+ public HashSet<AddinNode> Children { get; } = new HashSet<AddinNode> ();
+ public string Label { get; }
+
+ public AddinNode (string label)
+ {
+ Label = label;
+ }
+
+ public bool Equals (AddinNode other)
+ {
+ return Label == other.Label;
+ }
+ }
+ }
+}
diff --git a/main/src/tools/ExtensionTools/AddinInfo.cs b/main/src/tools/ExtensionTools/AddinInfo.cs
new file mode 100644
index 0000000000..2ca91262e8
--- /dev/null
+++ b/main/src/tools/ExtensionTools/AddinInfo.cs
@@ -0,0 +1,15 @@
+
+using System;
+using Mono.Addins;
+using Mono.Addins.Description;
+
+[assembly:Addin ("ExtensionTool",
+ Namespace = "MonoDevelop",
+ Version = MonoDevelop.BuildInfo.Version,
+ Category = "MonoDevelop Core")]
+
+[assembly:AddinName ("Extension Developer Tools")]
+[assembly:AddinDescription ("Tools used to analyze the extension model")]
+[assembly:AddinFlags (AddinFlags.Hidden)]
+
+[assembly:AddinDependency ("Core", MonoDevelop.BuildInfo.Version)]
diff --git a/main/src/tools/ExtensionTools/AddinListWidget.cs b/main/src/tools/ExtensionTools/AddinListWidget.cs
new file mode 100644
index 0000000000..d842be1e14
--- /dev/null
+++ b/main/src/tools/ExtensionTools/AddinListWidget.cs
@@ -0,0 +1,68 @@
+//
+// AddinListWidget.cs
+//
+// Author:
+// Marius Ungureanu <maungu@microsoft.com>
+//
+// Copyright (c) 2018 Microsoft Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+using Mono.Addins;
+using Xwt;
+
+namespace MonoDevelop.ExtensionTools
+{
+ class AddinListWidget : Widget
+ {
+ readonly ListStore listStore;
+ readonly ListView listView;
+ readonly DataField<string> labelField = new DataField<string> ();
+ readonly Label summary = new Label ();
+
+ public AddinListWidget (Addin[] addins = null)
+ {
+ addins = addins ?? AddinManager.Registry.GetAllAddins (x => x.Name);
+
+ listStore = new ListStore (labelField);
+ listView = new ListView (listStore);
+
+ var col = listView.Columns.Add ("Name", labelField);
+ col.Expands = true;
+
+ FillData (addins);
+
+ var vbox = new VBox ();
+ vbox.PackStart (summary, false);
+ vbox.PackStart (listView, true);
+ Content = vbox;
+ }
+
+ void FillData (Addin[] addins)
+ {
+ summary.Text = $"Count: {addins.Length}";
+
+ foreach (var addin in addins) {
+ int row = listStore.AddRow ();
+ listStore.SetValue (row, labelField, addin.Name);
+ }
+ // TODO: clicking a node should open addin info tab
+ }
+ }
+}
diff --git a/main/src/tools/ExtensionTools/AddinRegistryExtensions.cs b/main/src/tools/ExtensionTools/AddinRegistryExtensions.cs
new file mode 100644
index 0000000000..493c421d59
--- /dev/null
+++ b/main/src/tools/ExtensionTools/AddinRegistryExtensions.cs
@@ -0,0 +1,64 @@
+//
+// AddinRegistryExtensions.cs
+//
+// Author:
+// Marius Ungureanu <maungu@microsoft.com>
+//
+// Copyright (c) 2018 Microsoft Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+using System.Collections.Generic;
+using Mono.Addins;
+
+namespace MonoDevelop.ExtensionTools
+{
+ static class AddinRegistryExtensions
+ {
+ public static Addin[] GetAllAddins (this AddinRegistry registry, Func<Addin, string> sortItemSelector = null)
+ {
+ if (sortItemSelector == null)
+ sortItemSelector = x => x.Id;
+
+ var array = registry.GetModules (AddinSearchFlags.IncludeAll | AddinSearchFlags.LatestVersionsOnly);
+
+ var comparer = new NameComparer (sortItemSelector);
+ Array.Sort (array, comparer);
+
+ return array;
+ }
+
+ class NameComparer : IComparer<Addin>
+ {
+ readonly Func<Addin, string> selector;
+
+ public NameComparer (Func<Addin, string> selector)
+ {
+ this.selector = selector;
+ }
+
+ public int Compare (Addin x, Addin y)
+ {
+ var xString = selector (x);
+ var yString = selector (y);
+ return string.Compare (xString, yString, StringComparison.Ordinal);
+ }
+ }
+ }
+}
diff --git a/main/src/tools/ExtensionTools/Application.cs b/main/src/tools/ExtensionTools/Application.cs
new file mode 100644
index 0000000000..7403015edb
--- /dev/null
+++ b/main/src/tools/ExtensionTools/Application.cs
@@ -0,0 +1,97 @@
+//
+// MyClass.cs
+//
+// Author:
+// Marius Ungureanu <maungu@microsoft.com>
+//
+// Copyright (c) 2018 Microsoft Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Threading;
+using System.Threading.Tasks;
+using Mono.Addins;
+using MonoDevelop.Core;
+using Xwt;
+
+namespace MonoDevelop.ExtensionTools
+{
+ public class Application: IApplication
+ {
+ // HACK: Make this proper
+ internal static LazyNotebook MainNotebook;
+
+ public Task<int> Run (string[] arguments)
+ {
+ Xwt.Application.Initialize (ToolkitType.Gtk);
+#if MAC
+ var dir = Path.GetDirectoryName (typeof (Application).Assembly.Location);
+ if (ObjCRuntime.Dlfcn.dlopen (Path.Combine (dir, "libxammac.dylib"), 0) == IntPtr.Zero) {
+ LoggingService.LogFatalError ("Unable to load libxammac");
+ return Task.FromResult (1);
+ }
+#endif
+ LoggingService.LogInfo ("Initialized toolkit");
+
+ Xwt.Toolkit.NativeEngine.Invoke (() => {
+ using (CreateWindow ()) {
+ LoggingService.LogInfo ("Showing main window");
+ Xwt.Application.Run ();
+ }
+ });
+
+ return Task.FromResult (0);
+ }
+
+ static Window CreateWindow ()
+ {
+ var window = new Window {
+ Content = CreateWindowContent (),
+ Width = 800,
+ Height = 800,
+ };
+
+ window.Closed += (_, __) => Xwt.Application.Exit ();
+ window.Show ();
+
+ return window;
+ }
+
+ static Widget CreateWindowContent ()
+ {
+ var nb = MainNotebook = new LazyNotebook ();
+
+ foreach (var (widgetFunc, title) in GetTabs ()) {
+ nb.Add (widgetFunc, title);
+ }
+
+ return nb;
+ }
+
+ static IEnumerable<(Func<Widget> widgetFunc, string title)> GetTabs ()
+ {
+ yield return (() => new AddinListWidget (), "List");
+ yield return (() => new AddinDependencyTreeWidget (), "Dependency Tree");
+ yield return (() => new ExtensionPointsWidget (), "Extension Points");
+ }
+ }
+}
diff --git a/main/src/tools/ExtensionTools/ExtensionNodesWidget.cs b/main/src/tools/ExtensionTools/ExtensionNodesWidget.cs
new file mode 100644
index 0000000000..d8a63369cc
--- /dev/null
+++ b/main/src/tools/ExtensionTools/ExtensionNodesWidget.cs
@@ -0,0 +1,120 @@
+//
+// ExtensionNodesWidget.cs
+//
+// Author:
+// Marius Ungureanu <maungu@microsoft.com>
+//
+// Copyright (c) 2018 Microsoft Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Mono.Addins;
+using Mono.Addins.Description;
+using Xwt;
+
+namespace MonoDevelop.ExtensionTools
+{
+ class ExtensionNodesWidget : Widget
+ {
+ readonly TreeStore treeStore;
+ readonly TreeView treeView;
+ readonly DataField<string> labelField = new DataField<string> ();
+ readonly Label summary = new Label ();
+
+ public ExtensionNodesWidget (string path, Addin[] addins = null)
+ {
+ addins = addins ?? AddinManager.Registry.GetAllAddins ();
+
+ treeStore = new TreeStore (labelField);
+ treeView = new TreeView (treeStore);
+
+ var col = treeView.Columns.Add ("Name", labelField);
+ col.Expands = true;
+
+ FillData (path, addins);
+ treeView.ExpandAll ();
+
+ var vbox = new VBox ();
+ vbox.PackStart (summary, false);
+ vbox.PackStart (treeView, true);
+ Content = vbox;
+ }
+
+ void FillData (string path, Addin[] addins)
+ {
+ // TODO: add group by addin support.
+ var allNodes = addins
+ .SelectMany (x => x.Description.AllModules)
+ .SelectMany (x => x.Extensions)
+ .Where (x => x.Path == path)
+ .Select (x => x.ExtensionNodes);
+
+ var nav = treeStore.AddNode ();
+
+ int maxDepth = 0;
+ int count = 0;
+ foreach (var node in allNodes) {
+ int depth = BuildTree (nav, node, 1, ref count);
+ maxDepth = Math.Max (maxDepth, depth);
+ }
+
+ summary.Text = $"'{path}' Count: {count} Depth: {maxDepth}";
+ }
+
+ int BuildTree (TreeNavigator currentPosition, ExtensionNodeDescriptionCollection nodes, int currentDepth, ref int count)
+ {
+ int maxDepth = currentDepth;
+
+ // TODO: insertbefore/after
+
+ foreach (ExtensionNodeDescription node in nodes) {
+ count++;
+ var pos = currentPosition.Clone ().AddChild ();
+
+ var label = GetLabelForNode (node);
+ pos.SetValue (labelField, label);
+
+ var childDepth = BuildTree (pos, node.ChildNodes, currentDepth + 1, ref count);
+ maxDepth = Math.Max (maxDepth, childDepth);
+ }
+
+ return maxDepth;
+ }
+
+ string GetLabelForNode (ExtensionNodeDescription node)
+ {
+ if (node.IsCondition) {
+ var value = node.GetAttribute ("value");
+ if (!string.IsNullOrEmpty (value))
+ return $"Condition: {node.Id} == {value}";
+ return $"Condition: {node.Id}";
+ }
+
+ var type = node.GetAttribute ("class");
+ if (!string.IsNullOrEmpty (type))
+ return type;
+
+ return node.Id;
+ }
+
+ // TODO: add full attribute visualization
+ }
+}
diff --git a/main/src/tools/ExtensionTools/ExtensionPointsWidget.cs b/main/src/tools/ExtensionTools/ExtensionPointsWidget.cs
new file mode 100644
index 0000000000..0784222b45
--- /dev/null
+++ b/main/src/tools/ExtensionTools/ExtensionPointsWidget.cs
@@ -0,0 +1,97 @@
+//
+// ExtensionPointsWidget.cs
+//
+// Author:
+// Marius Ungureanu <maungu@microsoft.com>
+//
+// Copyright (c) 2018 Microsoft Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Mono.Addins;
+using Mono.Addins.Description;
+using Xwt;
+namespace MonoDevelop.ExtensionTools
+{
+ class ExtensionPointsWidget : Widget
+ {
+ readonly ListStore listStore;
+ readonly ListView listView;
+ readonly DataField<string> labelField = new DataField<string> ();
+ readonly Label summary = new Label ();
+
+ public ExtensionPointsWidget (Addin[] addins = null)
+ {
+ addins = addins ?? AddinManager.Registry.GetAllAddins ();
+
+ listStore = new ListStore (labelField);
+ listView = new ListView (listStore);
+ listView.RowActivated += ListView_RowActivated;
+
+ var col = listView.Columns.Add ("Name", labelField);
+ col.Expands = true;
+
+ FillData (addins);
+
+ var vbox = new VBox ();
+ vbox.PackStart (summary, false);
+ vbox.PackStart (listView, true);
+ Content = vbox;
+ }
+
+ void ListView_RowActivated (object sender, ListViewRowEventArgs e)
+ {
+ var value = listStore.GetValue (e.RowIndex, labelField);
+
+ var window = new Window {
+ Content = new ExtensionNodesWidget (value),
+ Height = 800,
+ Width = 600,
+ };
+ window.Show ();
+ }
+
+ void FillData (Addin[] addins)
+ {
+ var points = GatherExtensionPoints (addins);
+
+ summary.Text = $"Count: {points.Length}";
+
+ foreach (var point in points) {
+ int row = listStore.AddRow ();
+ listStore.SetValue (row, labelField, point);
+ }
+ }
+
+ string[] GatherExtensionPoints (Addin[] addins)
+ {
+ var points = new HashSet<string> ();
+
+ foreach (var addin in addins) {
+ foreach (ExtensionPoint extensionPoint in addin.Description.ExtensionPoints) {
+ points.Add (extensionPoint.Path);
+ }
+ }
+
+ return points.ToSortedArray ();
+ }
+ }
+}
diff --git a/main/src/tools/ExtensionTools/ExtensionTools.csproj b/main/src/tools/ExtensionTools/ExtensionTools.csproj
new file mode 100644
index 0000000000..5d45e69fc3
--- /dev/null
+++ b/main/src/tools/ExtensionTools/ExtensionTools.csproj
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="..\..\..\MonoDevelop.props" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{E33F7901-AA45-4C25-9868-DBB6CC8DC40C}</ProjectGuid>
+ <TargetFrameworkVersion>$(MDFrameworkVersion)</TargetFrameworkVersion>
+ <OutputPath>..\..\..\build\bin</OutputPath>
+ <RootNamespace>MonoDevelop.ExtensionTools</RootNamespace>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' " />
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'DebugMac|AnyCPU' " />
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " />
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseMac|AnyCPU' " />
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="Xamarin.Mac" Condition=" '$(Configuration)' == 'DebugMac' OR '$(Configuration)' == 'ReleaseMac' ">
+ <HintPath>..\..\..\build\bin\Xamarin.Mac.dll</HintPath>
+ <Private>False</Private>
+ </Reference>
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Application.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="AddinInfo.cs" />
+ <Compile Include="AddinDependencyTreeWidget.cs" />
+ <Compile Include="AddinListWidget.cs" />
+ <Compile Include="AddinRegistryExtensions.cs" />
+ <Compile Include="ExtensionPointsWidget.cs" />
+ <Compile Include="LazyNotebook.cs" />
+ <Compile Include="ExtensionNodesWidget.cs" />
+ <Compile Include="HashSetExtensions.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\core\MonoDevelop.Core\MonoDevelop.Core.csproj">
+ <Project>{7525BB88-6142-4A26-93B9-A30C6983390A}</Project>
+ <Name>MonoDevelop.Core</Name>
+ <Private>False</Private>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\external\mono-addins\Mono.Addins\Mono.Addins.csproj">
+ <Project>{91DD5A2D-9FE3-4C3C-9253-876141874DAD}</Project>
+ <Name>Mono.Addins</Name>
+ <Private>False</Private>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\external\xwt\Xwt\Xwt.csproj">
+ <Project>{92494904-35FA-4DC9-BDE9-3A3E87AC49D3}</Project>
+ <Name>Xwt</Name>
+ <Private>False</Private>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <EmbeddedResource Include="MonoDevelop.ExtensionTools.addin.xml" />
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+</Project> \ No newline at end of file
diff --git a/main/src/tools/ExtensionTools/HashSetExtensions.cs b/main/src/tools/ExtensionTools/HashSetExtensions.cs
new file mode 100644
index 0000000000..138ee4c378
--- /dev/null
+++ b/main/src/tools/ExtensionTools/HashSetExtensions.cs
@@ -0,0 +1,41 @@
+//
+// HashSetExtensions.cs
+//
+// Author:
+// Marius Ungureanu <maungu@microsoft.com>
+//
+// Copyright (c) 2018 Microsoft Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace MonoDevelop.ExtensionTools
+{
+ static class HashSetExtensions
+ {
+ public static T[] ToSortedArray<T> (this HashSet<T> set)
+ {
+ var arr = set.ToArray ();
+ Array.Sort (arr);
+ return arr;
+ }
+ }
+}
diff --git a/main/src/tools/ExtensionTools/LazyNotebook.cs b/main/src/tools/ExtensionTools/LazyNotebook.cs
new file mode 100644
index 0000000000..bdba85338c
--- /dev/null
+++ b/main/src/tools/ExtensionTools/LazyNotebook.cs
@@ -0,0 +1,71 @@
+//
+// LazyNotebook.cs
+//
+// Author:
+// Marius Ungureanu <maungu@microsoft.com>
+//
+// Copyright (c) 2018 Microsoft Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+using Xwt;
+
+namespace MonoDevelop.ExtensionTools
+{
+ class LazyNotebook : Notebook
+ {
+ public void Add (Func<Widget> createWidget, string label)
+ {
+ var createWidgetChain = OnAdd (createWidget);
+ var widget = new LazyWidget (createWidgetChain);
+ Add (widget, label);
+ }
+
+ protected override void OnCurrentTabChanged (EventArgs e)
+ {
+ base.OnCurrentTabChanged (e);
+ Xwt.Application.TimeoutInvoke (0, () => {
+ Toolkit.NativeEngine.Invoke (() => {
+ var tab = Tabs [CurrentTabIndex];
+ if (tab.Child is LazyWidget lazy)
+ lazy.CreateContent ();
+ });
+ return false;
+ });
+ }
+
+ protected virtual Func<Widget> OnAdd (Func<Widget> createWidget) => createWidget;
+
+ class LazyWidget : Widget
+ {
+ readonly Func<Widget> createWidget;
+
+ public LazyWidget (Func<Widget> createWidget)
+ {
+ this.createWidget = createWidget;
+ }
+
+ public void CreateContent ()
+ {
+ if (Content == null)
+ Content = createWidget ();
+ }
+ }
+ }
+}
diff --git a/main/src/tools/ExtensionTools/MonoDevelop.ExtensionTools.addin.xml b/main/src/tools/ExtensionTools/MonoDevelop.ExtensionTools.addin.xml
new file mode 100644
index 0000000000..25998713d8
--- /dev/null
+++ b/main/src/tools/ExtensionTools/MonoDevelop.ExtensionTools.addin.xml
@@ -0,0 +1,7 @@
+<ExtensionModel>
+
+ <Extension path = "/MonoDevelop/Core/Applications">
+ <Application id = "extension-tool" class = "MonoDevelop.ExtensionTools.Application" description = "Developer overview over the extension model"/>
+ </Extension>
+
+</ExtensionModel>
diff --git a/main/src/tools/ExtensionTools/Properties/AssemblyInfo.cs b/main/src/tools/ExtensionTools/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..061f89aac8
--- /dev/null
+++ b/main/src/tools/ExtensionTools/Properties/AssemblyInfo.cs
@@ -0,0 +1,51 @@
+//
+// AssemblyInfo.cs
+//
+// Author:
+// Marius Ungureanu <maungu@microsoft.com>
+//
+// Copyright (c) 2018 Microsoft Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+// Information about this assembly is defined by the following attributes.
+// Change them to the values specific to your project.
+
+[assembly: AssemblyTitle ("ExtensionTools")]
+[assembly: AssemblyDescription ("")]
+[assembly: AssemblyConfiguration ("")]
+[assembly: AssemblyCompany ("Microsoft")]
+[assembly: AssemblyProduct ("")]
+[assembly: AssemblyCopyright ("Microsoft Inc.")]
+[assembly: AssemblyTrademark ("")]
+[assembly: AssemblyCulture ("")]
+
+// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
+// The form "{Major}.{Minor}.*" will automatically update the build and revision,
+// and "{Major}.{Minor}.{Build}.*" will update just the revision.
+
+[assembly: AssemblyVersion ("1.0.0")]
+
+// The following attributes are used to specify the signing key for the assembly,
+// if desired. See the Mono documentation for more information about signing.
+
+//[assembly: AssemblyDelaySign(false)]
+//[assembly: AssemblyKeyFile("")]
diff --git a/main/tests/Ide.Tests/MonoDevelop.Ide.Composition/CompositionManager.CachingTests.cs b/main/tests/Ide.Tests/MonoDevelop.Ide.Composition/CompositionManager.CachingTests.cs
index 74d5219df9..a198a31855 100644
--- a/main/tests/Ide.Tests/MonoDevelop.Ide.Composition/CompositionManager.CachingTests.cs
+++ b/main/tests/Ide.Tests/MonoDevelop.Ide.Composition/CompositionManager.CachingTests.cs
@@ -26,6 +26,7 @@
using System;
using System.Collections.Generic;
using System.IO;
+using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
@@ -38,35 +39,28 @@ namespace MonoDevelop.Ide.Composition
[TestFixture]
public class CompositionManagerCachingTests
{
- internal class NewerStampCachingFaultInjector : CompositionManager.ICachingFaultInjector
- {
- public void FaultAssemblyInfo (CompositionManager.MefControlCacheAssemblyInfo info)
- {
- info.LastWriteTimeUtc = info.LastWriteTimeUtc.Subtract (TimeSpan.FromSeconds (1));
- }
- }
-
- internal class OlderStampCachingFaultInjector : CompositionManager.ICachingFaultInjector
+ internal class LocationCachingFaultInjector : CompositionManager.ICachingFaultInjector
{
public void FaultAssemblyInfo (CompositionManager.MefControlCacheAssemblyInfo info)
{
- info.LastWriteTimeUtc = info.LastWriteTimeUtc.Add (TimeSpan.FromSeconds (1));
+ // Change one of the assemblies' path
+ info.Location = typeof (LocationCachingFaultInjector).Assembly.Location;
}
}
- internal class LocationCachingFaultInjector : CompositionManager.ICachingFaultInjector
+ internal class ModuleVersionIdCachingFaultInjector : CompositionManager.ICachingFaultInjector
{
public void FaultAssemblyInfo (CompositionManager.MefControlCacheAssemblyInfo info)
{
- // Change one of the assemblies' paths
- info.Location = typeof (LocationCachingFaultInjector).Assembly.Location;
+ // Change one of the assemblies' mvid
+ info.ModuleVersionId = Guid.NewGuid ();
}
}
static CompositionManager.Caching GetCaching (CompositionManager.ICachingFaultInjector faultInjector = null, Action<string> onCacheFileRequested = null, [CallerMemberName] string testName = null)
{
- var assemblies = CompositionManager.ReadAssembliesFromAddins ();
- var caching = new CompositionManager.Caching (assemblies, file => {
+ var mefAssemblies = CompositionManager.ReadAssembliesFromAddins ();
+ var caching = new CompositionManager.Caching (mefAssemblies, file => {
onCacheFileRequested?.Invoke (file);
var tmpDir = Path.Combine (Util.TmpDir, "mef", testName);
@@ -82,10 +76,10 @@ namespace MonoDevelop.Ide.Composition
static async Task<RuntimeComposition> CreateAndWrite (CompositionManager.Caching caching)
{
- var composition = await CompositionManager.CreateRuntimeCompositionFromDiscovery (caching);
+ var (composition, catalog) = await CompositionManager.CreateRuntimeCompositionFromDiscovery (caching);
var cacheManager = new CachedComposition ();
- await caching.Write (composition, cacheManager);
+ await caching.Write (composition, catalog, cacheManager);
return composition;
}
@@ -233,27 +227,41 @@ namespace MonoDevelop.Ide.Composition
public async Task TestControlCacheFileStaleList ()
{
var caching = GetCaching ();
- var composition = await CompositionManager.CreateRuntimeCompositionFromDiscovery (caching);
+ var (composition, catalog) = await CompositionManager.CreateRuntimeCompositionFromDiscovery (caching);
var cacheManager = new CachedComposition ();
- await caching.Write (composition, cacheManager);
+ await caching.Write (composition, catalog, cacheManager);
- caching.Assemblies.Add (typeof (Console).Assembly);
+ caching.MefAssemblies.Add (typeof (CompositionManagerCachingTests).Assembly);
Assert.IsFalse (caching.CanUse ());
}
- [TestCase (typeof (OlderStampCachingFaultInjector))]
- [TestCase (typeof (NewerStampCachingFaultInjector))]
+ [Test]
+ public async Task TestCacheControlDataIntegrity ()
+ {
+ var caching = GetCaching ();
+
+ var (composition, catalog) = await CompositionManager.CreateRuntimeCompositionFromDiscovery (caching);
+
+ var inputAssemblies = catalog.GetInputAssemblies ().Select (x => x.ToString ()).ToArray ();
+ Assert.That (caching.MefAssemblies, Contains.Item (typeof (CompositionManager).Assembly));
+ Assert.That (inputAssemblies, Contains.Item (typeof (CompositionManager).Assembly.GetName ().ToString ()));
+
+ Assert.That (caching.MefAssemblies, Is.Not.Contains (typeof (Console).Assembly));
+ Assert.That (inputAssemblies, Contains.Item (typeof (Console).Assembly.GetName ().ToString ()));
+ }
+
[TestCase (typeof (LocationCachingFaultInjector))]
+ [TestCase (typeof (ModuleVersionIdCachingFaultInjector))]
public async Task TestControlCacheFaultInjection (Type injectorType)
{
var injector = (CompositionManager.ICachingFaultInjector)Activator.CreateInstance (injectorType);
var caching = GetCaching (injector);
- var composition = await CompositionManager.CreateRuntimeCompositionFromDiscovery (caching);
+ var (composition, catalog) = await CompositionManager.CreateRuntimeCompositionFromDiscovery (caching);
var cacheManager = new CachedComposition ();
- await caching.Write (composition, cacheManager);
+ await caching.Write (composition, catalog, cacheManager);
Assert.IsFalse (caching.CanUse ());
}
diff --git a/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Core.Assemblies/SystemAssemblyServiceTests.cs b/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Core.Assemblies/SystemAssemblyServiceTests.cs
index 184c23f1f1..8775319221 100644
--- a/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Core.Assemblies/SystemAssemblyServiceTests.cs
+++ b/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Core.Assemblies/SystemAssemblyServiceTests.cs
@@ -1,4 +1,4 @@
-//
+//
// SystemAssemblyServiceTests.cs
//
// Author:
@@ -25,6 +25,7 @@
// THE SOFTWARE.
using System;
using System.IO;
+using System.Linq;
using System.Threading.Tasks;
using MonoDevelop.Projects;
using NUnit.Framework;
@@ -35,38 +36,9 @@ namespace MonoDevelop.Core.Assemblies
[TestFixture]
public class SystemAssemblyServiceTests
{
- static string GetDllPath(string dllName)
- {
- var directory = Path.GetDirectoryName (typeof(Runtime).Assembly.Location);
- return Path.Combine (directory, dllName);
- }
-
- [TestCase(true, "Humanizer.dll")]
- [TestCase(false, "MonoDevelop.Core.dll")]
- public void ImmutableCollectionsContainReferenceToSystemRuntime (bool withSystemRuntime, string relativeDllPath)
- {
- var result = SystemAssemblyService.ContainsReferenceToSystemRuntime(GetDllPath (relativeDllPath));
- Assert.That(result, Is.EqualTo(withSystemRuntime));
- }
-
- [TestCase(true, "Humanizer.dll")]
- [TestCase(false, "MonoDevelop.Core.dll")]
- public async Task ImmutableCollectionsContainReferenceToSystemRuntimeAsync (bool withSystemRuntime, string relativeDllPath)
- {
- var result = await SystemAssemblyService.ContainsReferenceToSystemRuntimeAsync(GetDllPath (relativeDllPath));
- Assert.That(result, Is.EqualTo(withSystemRuntime));
- }
-
- [TestCase (true, "System.Collections.Immutable.dll")]
- [TestCase (false, "MonoDevelop.Core.dll")]
- public void RequiresFacadeAssemblies (bool addFacades, string relativeDllPath)
- {
- var result = SystemAssemblyService.RequiresFacadeAssemblies (GetDllPath (relativeDllPath));
- Assert.That (result, Is.EqualTo (addFacades));
- }
-
[TestCase (true, "System.Collections.Immutable.dll")]
[TestCase (false, "MonoDevelop.Core.dll")]
+ [TestCase (false, "NonExistingDll.dll")]
public async Task RequiresFacadeAssembliesAsync (bool addFacades, string relativeDllPath)
{
var result = await SystemAssemblyService.RequiresFacadeAssembliesAsync (GetDllPath (relativeDllPath));
@@ -86,5 +58,51 @@ namespace MonoDevelop.Core.Assemblies
var references = SystemAssemblyService.GetAssemblyReferences(cecilPath);
Assert.That(references, Is.EquivalentTo(names));
}
+
+ [Test]
+ public void CheckAssemblyReferences ()
+ {
+ var monoAddinsPath = GetDllPath ("Mono.Addins.dll");
+ var result = SystemAssemblyService.GetAssemblyReferences (monoAddinsPath);
+
+ Assert.AreEqual (4, result.Length);
+ Assert.That (result, Contains.Item ("mscorlib"));
+ Assert.That (result, Contains.Item ("System"));
+ Assert.That (result, Contains.Item ("System.Core"));
+ Assert.That (result, Contains.Item ("System.Xml"));
+ }
+
+ [Test]
+ public void GetManifestResources ()
+ {
+ var mdCorePath = GetDllPath ("MonoDevelop.Core.dll");
+ var result = SystemAssemblyService.GetAssemblyManifestResources (mdCorePth).ToArray ();
+
+ Assert.That (result.Length, Is.GreaterThanOrEqualTo (1));
+
+ var addinXml = result.SingleOrDefault (x => x.Name == "MonoDevelop.Core.addin.xml");
+ Assert.IsNotNull (addinXml);
+
+ string fromReader, actual;
+
+ using (var streamReader = new StreamReader (addinXml.Open ())) {
+ fromReader = streamReader.ReadToEnd ();
+ }
+ using (var streamReader = new StreamReader (typeof (SystemAssemblyService).Assembly.GetManifestResourceStream ("MonoDevelop.Core.addin.xml"))) {
+ actual = streamReader.ReadToEnd ();
+ }
+
+ Assert.AreEqual (actual, fromReader);
+ }
+
+ [Test]
+ public void TestFrameworkVersion ()
+ {
+ var xwtPath = GetDllPath ("Xwt.dll");
+ var result = new SystemAssemblyService ().GetTargetFrameworkForAssembly (null, xwtPath);
+
+ Assert.AreEqual (TargetFrameworkMoniker.ID_NET_FRAMEWORK, result.Identifier);
+ Assert.AreEqual ("4.0", result.Version);
+ }
}
}
diff --git a/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Core.Tests.csproj b/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Core.Tests.csproj
index b2f1c84d33..d6ef7f69db 100644
--- a/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Core.Tests.csproj
+++ b/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Core.Tests.csproj
@@ -83,6 +83,7 @@
<Compile Include="MonoDevelop.Core.Instrumentation\BucketTimingsTests.cs" />
<Compile Include="MonoDevelop.Utilities\RaceCheckerTests.cs" />
<Compile Include="MonoDevelop.Core\FeatureSwitchServiceTests.cs" />
+ <Compile Include="MonoDevelop.Core\SdkResolverTests.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\core\MonoDevelop.Core\MonoDevelop.Core.csproj">
diff --git a/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Core/SdkResolverTests.cs b/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Core/SdkResolverTests.cs
new file mode 100644
index 0000000000..729051a4f0
--- /dev/null
+++ b/main/tests/MonoDevelop.Core.Tests/MonoDevelop.Core/SdkResolverTests.cs
@@ -0,0 +1,107 @@
+//
+// SdkResolverTests.cs
+//
+// Author:
+// Matt Ward <matt.ward@microsoft.com>
+//
+// Copyright (c) 2019 Microsoft
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Microsoft.Build.Framework;
+using MonoDevelop.Projects.MSBuild;
+using NUnit.Framework;
+using UnitTests;
+
+namespace MonoDevelop.Core
+{
+ [TestFixture]
+ public class SdkResolverTests : TestBase
+ {
+ /// <summary>
+ /// Tests that the MSBuild version is passed to sdk resolvers. The DotNetMSBuildSdkResolver throws an
+ /// ArgumentNullException if it is not set. Have to use an unknown sdk otherwise other resolvers will
+ /// be used and the DotNetMSBuildSdkResolver will not be used.
+ /// </summary>
+ [Test]
+ public void UnknownSdk_DotNetMSBuildSdkResolverDoesNotFatalReportError ()
+ {
+ var resolution = SdkResolution.GetResolver (Runtime.SystemAssemblyService.CurrentRuntime);
+ // Using a sdk with an invalid version to prevent the NuGet sdk resolver causing a test crash.
+ // Invalid version numbers cause the NuGet sdk resolver to not try to resolve the sdk. The crash
+ // only seems to happen with this test - using the IDE does not trigger the crash. There is a
+ // separate NuGet sdk resolver test that runs the resolver. Crash error:
+ // NuGet.Configuration.NuGetPathContext doesn't implement interface NuGet.Common.INuGetPathContext
+ var sdkReference = new SdkReference ("MonoDevelop.Unknown.Test.Sdk", "InvalidVersion", null);
+ var logger = new TestLoggingService ();
+ var context = new MSBuildContext ();
+ var result = resolution.GetSdkPath (sdkReference, logger, context, null, null);
+
+ var error = logger.FatalBuildErrors.FirstOrDefault ();
+ Assert.AreEqual (0, logger.FatalBuildErrors.Count, "First error: " + error);
+ Assert.IsNull (result);
+ }
+
+ [Test]
+ public void SdkReference_DifferentCase_StillFindsMatchWithMonoDevelopResolver ()
+ {
+ var sdks = new List<SdkInfo> ();
+ var info = new SdkInfo ("MonoDevelop.Test.NET.Sdk", SdkVersion.Parse ("1.2.3"), null);
+ sdks.Add (info);
+
+ var resolver = new Resolver (() => sdks);
+
+ var sdkReference = new SdkReference ("monodevelop.test.net.sdk", null, null);
+ var factory = new SdkResolution.SdkResultFactoryImpl (sdkReference);
+ var result = resolver.Resolve (sdkReference, null, factory);
+
+ Assert.IsTrue (result.Success);
+ Assert.AreEqual (result.Version, info.Version.ToString ());
+ }
+
+ class TestLoggingService : ILoggingService
+ {
+ public List<Exception> FatalBuildErrors = new List<Exception> ();
+
+ public void LogCommentFromText (MSBuildContext buildEventContext, MessageImportance messageImportance, string message)
+ {
+ }
+
+ public void LogErrorFromText (MSBuildContext buildEventContext, object subcategoryResourceName, object errorCode, object helpKeyword, string file, string message)
+ {
+ }
+
+ public void LogFatalBuildError (MSBuildContext buildEventContext, Exception e, string projectFile)
+ {
+ FatalBuildErrors.Add (e);
+ }
+
+ public void LogWarning (string message)
+ {
+ }
+
+ public void LogWarningFromText (MSBuildContext bec, object p1, object p2, object p3, string projectFile, string warning)
+ {
+ }
+ }
+ }
+}
diff --git a/main/tests/StressTest/Mono.Profiling.Log/LogEnums.cs b/main/tests/StressTest/Mono.Profiling.Log/LogEnums.cs
index 8d9c7fb33f..e5535f9fb8 100644
--- a/main/tests/StressTest/Mono.Profiling.Log/LogEnums.cs
+++ b/main/tests/StressTest/Mono.Profiling.Log/LogEnums.cs
@@ -66,6 +66,7 @@ namespace Mono.Profiler.Log {
RuntimeJitHelper = 1 << 4,
MetaSynchronizationPoint = 0 << 4,
+ MetaAotId = 1 << 4,
}
// mono/profiler/log.h : TYPE_*
@@ -122,17 +123,18 @@ namespace Mono.Profiler.Log {
// mono/metadata/profiler.h : MonoProfilerCodeBufferType
public enum LogJitHelper {
- Unknown = 0,
- Method = 1,
- MethodTrampoline = 2,
- UnboxTrampoline = 3,
- ImtTrampoline = 4,
- GenericsTrampoline = 5,
- SpecificTrampoline = 6,
- Helper = 7,
- Monitor = 8,
- DelegateInvoke = 9,
- ExceptionHandling = 10,
+ Method = 0,
+ [Obsolete ("This value is no longer produced.")]
+ MethodTrampoline = 1,
+ UnboxTrampoline = 2,
+ ImtTrampoline = 3,
+ GenericsTrampoline = 4,
+ SpecificTrampoline = 5,
+ Helper = 6,
+ [Obsolete ("This value is no longer produced.")]
+ Monitor = 7,
+ DelegateInvoke = 8,
+ ExceptionHandling = 9,
}
// mono/metadata/profiler.h : MonoProfilerGCRootType
@@ -168,7 +170,8 @@ namespace Mono.Profiler.Log {
Marshal = 11,
ThreadPool = 12,
Debugger = 13,
- RuntimeHandle = 14,
+ Handle = 14,
+ Ephemeron = 15,
}
// mono/profiler/log.h : MonoProfilerMonitorEvent
diff --git a/main/tests/StressTest/Mono.Profiling.Log/LogEventVisitor.cs b/main/tests/StressTest/Mono.Profiling.Log/LogEventVisitor.cs
index 79d6140523..1e5f338839 100644
--- a/main/tests/StressTest/Mono.Profiling.Log/LogEventVisitor.cs
+++ b/main/tests/StressTest/Mono.Profiling.Log/LogEventVisitor.cs
@@ -189,5 +189,9 @@ namespace Mono.Profiler.Log {
public virtual void Visit (SynchronizationPointEvent ev)
{
}
+
+ public virtual void Visit (AotIdEvent ev)
+ {
+ }
}
}
diff --git a/main/tests/StressTest/Mono.Profiling.Log/LogEvents.cs b/main/tests/StressTest/Mono.Profiling.Log/LogEvents.cs
index ba6887c0c7..16a216a44f 100644
--- a/main/tests/StressTest/Mono.Profiling.Log/LogEvents.cs
+++ b/main/tests/StressTest/Mono.Profiling.Log/LogEvents.cs
@@ -101,6 +101,8 @@ namespace Mono.Profiler.Log {
public string Name { get; internal set; }
+ public Guid ModuleVersionId { get; internal set; }
+
internal override void Accept (LogEventVisitor visitor)
{
visitor.Visit (this);
@@ -260,6 +262,8 @@ namespace Mono.Profiler.Log {
public long ObjectSize { get; internal set; }
+ public int Generation { get; internal set; }
+
public IReadOnlyList<HeapObjectReference> References { get; internal set; }
internal override void Accept (LogEventVisitor visitor)
@@ -272,7 +276,7 @@ namespace Mono.Profiler.Log {
public struct HeapRoot {
- public long AddressPointer { get; internal set; }
+ public long SlotPointer { get; internal set; }
public long ObjectPointer { get; internal set; }
@@ -314,7 +318,7 @@ namespace Mono.Profiler.Log {
public sealed class HeapRootUnregisterEvent : LogEvent {
- public long StartPointer { get; internal set; }
+ public long RootPointer { get; internal set; }
internal override void Accept (LogEventVisitor visitor)
{
@@ -326,7 +330,7 @@ namespace Mono.Profiler.Log {
public LogGCEvent Type { get; internal set; }
- public byte Generation { get; internal set; }
+ public int Generation { get; internal set; }
internal override void Accept (LogEventVisitor visitor)
{
@@ -554,6 +558,7 @@ namespace Mono.Profiler.Log {
}
}
+ [Obsolete ("This event is no longer produced.")]
public sealed class UnmanagedBinaryEvent : LogEvent {
public long SegmentPointer { get; internal set; }
@@ -593,4 +598,14 @@ namespace Mono.Profiler.Log {
visitor.Visit (this);
}
}
+
+ public sealed class AotIdEvent : LogEvent {
+
+ public Guid AotId { get; internal set; }
+
+ internal override void Accept (LogEventVisitor visitor)
+ {
+ visitor.Visit (this);
+ }
+ }
}
diff --git a/main/tests/StressTest/Mono.Profiling.Log/LogProcessor.cs b/main/tests/StressTest/Mono.Profiling.Log/LogProcessor.cs
index 161199b2fc..e792b1dfb3 100644
--- a/main/tests/StressTest/Mono.Profiling.Log/LogProcessor.cs
+++ b/main/tests/StressTest/Mono.Profiling.Log/LogProcessor.cs
@@ -52,6 +52,16 @@ namespace Mono.Profiler.Log {
}
}
+ void ProcessEvents (List<LogEvent> events, CancellationToken token)
+ {
+ foreach (var ev in events.OrderBy (x => x.Timestamp)) {
+ token.ThrowIfCancellationRequested ();
+ ProcessEvent (SortedVisitor, ev);
+ }
+
+ events.Clear ();
+ }
+
public void Process (CancellationToken token)
{
if (_used)
@@ -62,6 +72,8 @@ namespace Mono.Profiler.Log {
StreamHeader = new LogStreamHeader (_reader);
+ var events = new List<LogEvent> (Environment.ProcessorCount * 1000);
+
while (!Stream.EndOfStream) {
token.ThrowIfCancellationRequested ();
@@ -87,11 +99,17 @@ namespace Mono.Profiler.Log {
var ev = ReadEvent ();
ProcessEvent (ImmediateVisitor, ev);
+ events.Add (ev);
+
+ if (ev is SynchronizationPointEvent)
+ ProcessEvents (events, token);
}
_reader = oldReader;
}
}
+
+ ProcessEvents (events, token);
}
LogEvent ReadEvent ()
@@ -214,10 +232,18 @@ namespace Mono.Profiler.Log {
break;
case LogMetadataType.Image:
if (load) {
- ev = new ImageLoadEvent {
+ var ile = new ImageLoadEvent {
ImagePointer = ReadPointer (),
Name = _reader.ReadCString (),
};
+
+ if (StreamHeader.FormatVersion >= 16) {
+ var guid = _reader.ReadCString ();
+
+ ile.ModuleVersionId = guid == string.Empty ? Guid.Empty : Guid.Parse (guid);
+ }
+
+ ev = ile;
} else if (unload) {
ev = new ImageUnloadEvent {
ImagePointer = ReadPointer (),
@@ -390,6 +416,7 @@ namespace Mono.Profiler.Log {
ClassPointer = StreamHeader.FormatVersion < 15 ? ReadPointer () : 0,
VTablePointer = StreamHeader.FormatVersion >= 15 ? ReadPointer () : 0,
ObjectSize = (long) _reader.ReadULeb128 (),
+ Generation = StreamHeader.FormatVersion >= 16 ? _reader.ReadByte () : 0,
};
var list = new HeapObjectEvent.HeapObjectReference [(int) _reader.ReadULeb128 ()];
@@ -416,7 +443,7 @@ namespace Mono.Profiler.Log {
for (var i = 0; i < list.Length; i++) {
list [i] = new HeapRootsEvent.HeapRoot {
- AddressPointer = StreamHeader.FormatVersion >= 15 ? ReadPointer () : 0,
+ SlotPointer = StreamHeader.FormatVersion >= 15 ? ReadPointer () : 0,
ObjectPointer = ReadObject (),
Attributes = StreamHeader.FormatVersion < 15 ?
(StreamHeader.FormatVersion == 13 ?
@@ -443,7 +470,7 @@ namespace Mono.Profiler.Log {
break;
case LogEventType.HeapRootUnregister:
ev = new HeapRootUnregisterEvent {
- StartPointer = ReadPointer (),
+ RootPointer = ReadPointer (),
};
break;
default:
@@ -557,6 +584,9 @@ namespace Mono.Profiler.Log {
case LogEventType.RuntimeJitHelper: {
var helperType = (LogJitHelper) _reader.ReadByte ();
+ if (StreamHeader.FormatVersion < 14)
+ helperType--;
+
ev = new JitHelperEvent {
Type = helperType,
BufferPointer = ReadPointer (),
@@ -576,6 +606,11 @@ namespace Mono.Profiler.Log {
Type = (LogSynchronizationPoint) _reader.ReadByte (),
};
break;
+ case LogEventType.MetaAotId:
+ ev = new AotIdEvent {
+ AotId = Guid.Parse (_reader.ReadCString ()),
+ };
+ break;
default:
throw new LogException ($"Invalid extended event type ({extType}).");
}
diff --git a/main/tests/StressTest/Mono.Profiling.Log/LogStreamHeader.cs b/main/tests/StressTest/Mono.Profiling.Log/LogStreamHeader.cs
index aa86b75444..e00030c493 100644
--- a/main/tests/StressTest/Mono.Profiling.Log/LogStreamHeader.cs
+++ b/main/tests/StressTest/Mono.Profiling.Log/LogStreamHeader.cs
@@ -9,7 +9,8 @@ namespace Mono.Profiler.Log {
public sealed class LogStreamHeader {
const int MinVersion = 13;
- const int MaxVersion = 15;
+
+ const int MaxVersion = 17;
const int Id = 0x4d505a01;
@@ -21,6 +22,8 @@ namespace Mono.Profiler.Log {
public ulong StartupTime { get; }
+ public ulong TimestampStartupTime { get; }
+
public int TimerOverhead { get; }
public int Flags { get; }
@@ -50,6 +53,10 @@ namespace Mono.Profiler.Log {
PointerSize = reader.ReadByte ();
StartupTime = reader.ReadUInt64 ();
+
+ if (Version.Major >= 3)
+ TimestampStartupTime = reader.ReadUInt64 ();
+
TimerOverhead = reader.ReadInt32 ();
Flags = reader.ReadInt32 ();
ProcessId = reader.ReadInt32 ();
diff --git a/main/tests/StressTest/MonoDevelop.StressTest/ProfilerProcessor.cs b/main/tests/StressTest/MonoDevelop.StressTest/ProfilerProcessor.cs
index 6b5c2548f4..7f94b27d4c 100644
--- a/main/tests/StressTest/MonoDevelop.StressTest/ProfilerProcessor.cs
+++ b/main/tests/StressTest/MonoDevelop.StressTest/ProfilerProcessor.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@@ -166,9 +166,9 @@ namespace MonoDevelop.StressTest
{
switch (Options.Type) {
case StressTestOptions.ProfilerOptions.ProfilerType.HeapOnly:
- return $"--profile=log:heapshot=ondemand,noalloc,nocalls,maxframes=0,output=\"{Options.MlpdOutputPath}\"";
+ return $"--profile=log:nodefaults,heapshot=ondemand,output=\"{Options.MlpdOutputPath}\"";
case StressTestOptions.ProfilerOptions.ProfilerType.All:
- return $"--profile=log:heapshot=ondemand,alloc,nocalls,maxframes={Options.MaxFrames},output=\"{Options.MlpdOutputPath}\"";
+ return $"--profile=log:nodefaults,heapshot-on-shutdown,heapshot=ondemand,gcalloc,gcmove,gcroot,counter,maxframes={Options.MaxFrames},output=\"{Options.MlpdOutputPath}\"";
case StressTestOptions.ProfilerOptions.ProfilerType.Custom:
return Options.CustomProfilerArguments;
default:
diff --git a/main/tests/StressTest/MonoDevelop.StressTest/StressTestApp.cs b/main/tests/StressTest/MonoDevelop.StressTest/StressTestApp.cs
index f46f99016c..557c299009 100644
--- a/main/tests/StressTest/MonoDevelop.StressTest/StressTestApp.cs
+++ b/main/tests/StressTest/MonoDevelop.StressTest/StressTestApp.cs
@@ -1,4 +1,4 @@
-//
+//
// StressTestApp.cs
//
// Author:
@@ -67,6 +67,8 @@ namespace MonoDevelop.StressTest
if (ProfilerOptions.Type != StressTestOptions.ProfilerOptions.ProfilerType.Disabled) {
if (ProfilerOptions.MlpdOutputPath == null)
ProfilerOptions.MlpdOutputPath = Path.Combine (profilePath, "profiler.mlpd");
+ if (File.Exists (ProfilerOptions.MlpdOutputPath))
+ File.Delete (ProfilerOptions.MlpdOutputPath);
profilerProcessor = new ProfilerProcessor (ProfilerOptions);
string monoPath = Environment.GetEnvironmentVariable ("PATH")
.Split (Path.PathSeparator)
@@ -83,6 +85,7 @@ namespace MonoDevelop.StressTest
scenario = TestScenarioProvider.GetTestScenario ();
+ ReportMemoryUsage (-1);
for (int i = 0; i < Iterations; ++i) {
scenario.Run ();
ReportMemoryUsage (i);
diff --git a/main/tests/StressTest/StressTest.csproj b/main/tests/StressTest/StressTest.csproj
index 45559639c6..29ede46fa2 100644
--- a/main/tests/StressTest/StressTest.csproj
+++ b/main/tests/StressTest/StressTest.csproj
@@ -5,7 +5,7 @@
<ProjectGuid>{A1F9B020-6573-4BB2-A887-7F26561A9D18}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>MonoDevelop.StressTest</RootNamespace>
- <TargetFrameworkVersion>4.6.1</TargetFrameworkVersion>
+ <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<DebugSymbols>true</DebugSymbols>
@@ -95,6 +95,6 @@
</ItemGroup>
<Copy SourceFiles="@(TestProjectFiles)" DestinationFolder="$(OutputPath)\TestProject\%(RecursiveDir)" SkipUnchangedFiles="true" />
<Copy SourceFiles="@(MonoAddinsFiles)" DestinationFolder="$(OutputPath)\TestProject\mono-addins\Mono.Addins\%(RecursiveDir)" SkipUnchangedFiles="true" />
- <Copy SourceFiles="$(MonoAddinsDir)\Version.props;$(MonoAddinsDir)\mono-addins.snk" DestinationFolder="$(OutputPath)\TestProject\mono-addins" SkipUnchangedFiles="true" />
+ <Copy SourceFiles="$(MonoAddinsDir)\Version.props;$(MonoAddinsDir)\TargetFrameworks.props;$(MonoAddinsDir)\mono-addins.snk" DestinationFolder="$(OutputPath)\TestProject\mono-addins" SkipUnchangedFiles="true" />
</Target>
</Project> \ No newline at end of file
diff --git a/main/tests/test-projects/restore-netcore-offline/dotnetcoreconsole.csproj b/main/tests/test-projects/restore-netcore-offline/dotnetcoreconsole.csproj
index 21dff5ca2e..23df6047ff 100755
--- a/main/tests/test-projects/restore-netcore-offline/dotnetcoreconsole.csproj
+++ b/main/tests/test-projects/restore-netcore-offline/dotnetcoreconsole.csproj
@@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
- <TargetFramework>netcoreapp2.2</TargetFramework>
+ <TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup>
</Project>