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:
authorMatt Ward <matt.ward@microsoft.com>2018-03-26 11:43:28 +0300
committerMatt Ward <matt.ward@microsoft.com>2018-03-26 11:43:28 +0300
commit6c1c012b34afc411d99bda52a09cececb3e20666 (patch)
tree6cf209a60dc27806db81af78cb1997fd612df919 /main/src/core
parent3707fcf78ead900e97acb4b160c33739c43259a9 (diff)
parent2014698650693b56a4a213e1653c2af98fb0ce11 (diff)
Merge branch 'master' into xamarin-forms-use-dotnet-templating-project-templates
Diffstat (limited to 'main/src/core')
-rw-r--r--main/src/core/Mono.TextEditor.Shared/Mono.TextEditor.Shared.projitems1
-rw-r--r--main/src/core/Mono.TextEditor.Shared/Mono.TextEditor.Utils/CompressingTreeList.cs8
-rw-r--r--main/src/core/Mono.TextEditor.Shared/Mono.TextEditor.Utils/Diff.cs5
-rw-r--r--main/src/core/Mono.TextEditor.Shared/Mono.TextEditor.Utils/HtmlWriter.cs4
-rw-r--r--main/src/core/Mono.TextEditor.Shared/Mono.TextEditor.Utils/RedBlackTree.cs5
-rw-r--r--main/src/core/Mono.TextEditor.Shared/Mono.TextEditor.Utils/RtfWriter.cs13
-rw-r--r--main/src/core/Mono.TextEditor.Shared/Mono.TextEditor.Vi/ViActions.cs9
-rw-r--r--main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/Actions/CaretMoveActions.cs28
-rw-r--r--main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/Actions/ClipboardActions.cs15
-rw-r--r--main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/Actions/DeleteActions.cs14
-rw-r--r--main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/Actions/MiscActions.cs11
-rw-r--r--main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/CaretImpl.ITextCaret.cs236
-rw-r--r--main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/CaretImpl.cs8
-rw-r--r--main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/Document/DiffTracker.cs35
-rw-r--r--main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/Document/DocumentLine.cs5
-rw-r--r--main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/Document/DocumentUpdateRequest.cs4
-rw-r--r--main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/Document/TextDocument.cs54
-rw-r--r--main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/TextEditorData.cs20
-rw-r--r--main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/UrlMarker.cs25
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/PcFileCache.cs7
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/LocalConsole.cs12
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/ProcessArgumentBuilder.cs4
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.Logging/AssertLoggingTraceListener.cs4
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.Text/TextChangeEventArgs.cs4
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.csproj40
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core/ErrorHelper.cs4
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core/LoggingService.cs28
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core/ObjectPool.cs269
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core/Properties.cs4
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core/PropertyBag.cs12
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core/Runtime.cs7
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core/SharedPools.cs58
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core/StringBuilderCache.cs65
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core/StringParserService.cs4
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild.Conditions/ConditionParser.cs4
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/DefaultMSBuildEngine.cs44
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/EscapingUtilities.cs13
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/IMSBuildPropertySet.cs8
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildEngine.cs4
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildEvaluationContext.cs11
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildImport.cs10
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildProject.cs32
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildProjectInstance.cs4
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/RemoteBuildEngineManager.cs45
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/SdkResolution.cs2
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Policies/PolicyService.cs3
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Text/TextFormatter.cs9
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProject.cs18
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ItemCollection.cs11
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/MonoExecutionParameters.cs4
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs252
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectExtension.cs5
-rw-r--r--main/src/core/MonoDevelop.Core/packages.config200
-rw-r--r--main/src/core/MonoDevelop.Ide/ExtensionModel/MonoDevelop.Ide.addin.xml8
-rw-r--r--main/src/core/MonoDevelop.Ide/ExtensionModel/Templates.addin.xml10
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AtkCocoaHelper/AtkCocoaHelperMac.cs27
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AtkCocoaHelper/AtkCocoaHelperNoOp.cs4
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AutoTest/AppResult.cs7
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.DockNotebook/DockNotebookTab.cs9
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.DockNotebook/TabStrip.cs7
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockItem.cs20
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockItemContainer.cs23
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockItemTitleTab.cs33
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockItemToolbar.cs31
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/TabStrip.cs7
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.MainToolbar/MainToolbarController.cs4
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.MainToolbar/SearchResult.cs4
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components/ContextMenuExtensionsMac.cs4
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components/GtkUtil.cs10
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Mac/MDMenu.cs2
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.CodeCompletion/CompletionController.cs26
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.CodeCompletion/CompletionPresenterSession.cs92
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.CodeCompletion/CompletionWindowManager.cs26
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.CodeCompletion/RoslynCompletionData.cs93
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.CodeTemplates/CodeTemplate.cs20
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.CodeTemplates/CodeTemplateService.cs8
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Codons/ItemTemplateExtensionNode.cs80
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Composition/CommonEditorAssetServiceFactory.cs41
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Composition/CompositionManager.cs20
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Composition/InlineRenameService.cs24
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Composition/JoinableTaskContextHost.cs5
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Composition/PlatformCatalog.cs12
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Composition/StreamingFindUsagesPresenter.cs29
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Desktop/PlatformService.cs29
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Extension/CompletionTextEditorExtension.cs32
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Extension/HighlightUrlExtension.cs4
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Extension/LineSeparatorTextEditorExtension.cs18
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/EditorThemeColors.cs27
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/Formats/OldFormat.cs27
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/ISyntaxHighlighting.cs17
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/PObject.cs4
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/RoslynClassificationHighlighting.cs127
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/StackMatchExpression.cs4
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/SyntaxHighlighting.cs19
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/themes/FallbackStyle.json2
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/themes/LightStyle.json2
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.TextMate/TextMateCompletionTextEditorExtension.cs4
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/AutoSave.cs4
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/DefaultSourceEditorOptions.cs81
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/EditActions.cs92
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/EditorConfigService.cs134
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/InternalExtensionAPI/IMonoDevelopEditorOperations.cs (renamed from main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/InternalExtensionAPI/IEditorActionHost.cs)72
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/InternalExtensionAPI/ITextEditorImpl.cs4
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/Projection/ProjectedDocumentContext.cs8
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/TextEditor.cs8
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/TextEditorDisplayBinding.cs18
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/TextEditorViewContent.cs17
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Execution/MonoExecutionParametersPreview.cs4
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Extensions/MimeTypeNode.cs4
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.FindInFiles/FindInFilesDialog.cs20
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.FindInFiles/Scope.cs34
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Components/LogView.cs9
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Content/TextStylePolicy.cs13
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Pads.ProjectPad/ProjectFileNodeBuilder.cs94
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/Document.cs13
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/ViewCommandHandlers.cs20
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Projects.OptionPanels/BaseDirectoryPanelWidget.cs2
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Projects/ApplyPolicyDialog.cs8
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Projects/AssemblyReferencePanel.cs4
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Projects/IdeFileSystemExtensionExtension.cs3
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Projects/NewFileDialog.cs4
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.StandardHeader/StandardHeaderService.cs4
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/DirectoryTemplate.cs23
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/FileDescriptionTemplate.cs13
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/FileTemplate.cs13
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/FileTemplateReference.cs23
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/ItemTemplate.cs49
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/ItemTemplatePackageInstaller.cs37
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/MicrosoftTemplateEngine.cs349
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/MicrosoftTemplateEngineItemTemplate.cs50
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/MicrosoftTemplateEngineItemTemplatingProvider.cs166
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/MicrosoftTemplateEngineProjectTemplatingProvider.cs158
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/MicrosoftTemplateEngineSolutionTemplate.cs8
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/NewItemConfiguration.cs77
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/ProjectDescriptor.cs6
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/PropertyDescriptionTemplate.cs7
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/ResourceFileDescriptionTemplate.cs13
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/SingleFileDescriptionTemplate.cs208
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/TemplatePackageReference.cs40
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/TemplatingService.cs18
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/TextFileDescriptionTemplate.cs8
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/Ambience.cs79
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/IMonoDevelopHostDocument.cs44
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MarkupUtilities.cs1
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopPersistentStorageLocationService.cs22
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopSourceTextContainer.cs54
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.cs153
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/NR5CompatibiltyExtensions.cs4
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/TypeSystemService.cs4
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/TypeSystemService_WorkspaceHandling.cs124
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/WorkspaceExtensions.cs46
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.csproj42
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/DesktopService.cs2
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/DispatchService.cs28
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/Ide.cs19
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/IdeStartup.cs3
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/IdeVersionInfo.cs7
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/ImageService.cs4
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/MessageService.cs3
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/RootWorkspace.cs41
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/RoslynLogger.cs8
-rw-r--r--main/src/core/MonoDevelop.Ide/packages.config2
-rw-r--r--main/src/core/MonoDevelop.Startup/app.config24
-rw-r--r--main/src/core/MonoDevelop.TextEditor.Tests/Mono.TextEditor.Tests.DefaultEditActions/CaretMoveActionTests.cs38
-rw-r--r--main/src/core/MonoDevelop.TextEditor.Tests/Mono.TextEditor.Tests.DefaultEditActions/DeleteActionTests.cs16
-rw-r--r--main/src/core/MonoDevelop.TextEditor.Tests/Mono.TextEditor.Tests.DefaultEditActions/MiscActionsTest.cs11
-rw-r--r--main/src/core/MonoDevelop.TextEditor.Tests/Mono.TextEditor.Tests/DiffTrackerTests.cs112
-rw-r--r--main/src/core/MonoDevelop.TextEditor.Tests/MonoDevelop.TextEditor.Tests.csproj1
168 files changed, 4306 insertions, 1229 deletions
diff --git a/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor.Shared.projitems b/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor.Shared.projitems
index 957dd9b2eb..003ef36856 100644
--- a/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor.Shared.projitems
+++ b/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor.Shared.projitems
@@ -79,6 +79,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Mono.TextEditor\UrlMarker.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Mono.TextEditor\TextEditorData.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Mono.TextEditor\DefaultIndentationTracker.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)Mono.TextEditor\CaretImpl.ITextCaret.cs" />
</ItemGroup>
<ItemGroup>
<Folder Include="$(MSBuildThisFileDirectory)Mono.TextEditor\" />
diff --git a/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor.Utils/CompressingTreeList.cs b/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor.Utils/CompressingTreeList.cs
index 068763df76..60a86146a0 100644
--- a/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor.Utils/CompressingTreeList.cs
+++ b/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor.Utils/CompressingTreeList.cs
@@ -37,7 +37,7 @@ namespace Mono.TextEditor.Utils
internal class CompressingNode : IRedBlackTreeNode
{
- internal readonly T value;
+ internal T value;
internal int count, totalCount;
public CompressingNode (T value, int count)
@@ -311,7 +311,11 @@ namespace Mono.TextEditor.Utils
return GetNode (ref index).value;
}
set {
- RemoveAt (index);
+ if (index < Count) {
+ RemoveAt (index);
+ } else {
+ InsertRange (Count, index - Count, default (T));
+ }
Insert (index, value);
}
}
diff --git a/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor.Utils/Diff.cs b/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor.Utils/Diff.cs
index 452719762c..9b532cca71 100644
--- a/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor.Utils/Diff.cs
+++ b/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor.Utils/Diff.cs
@@ -96,6 +96,7 @@ using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
+using MonoDevelop.Core;
namespace Mono.TextEditor.Utils
{
@@ -486,7 +487,7 @@ namespace Mono.TextEditor.Utils
if (diff == null)
return "";
- StringBuilder sb = new StringBuilder ();
+ StringBuilder sb = StringBuilderCache.Allocate ();
IEnumerator<Hunk> he = diff.GetEnumerator ();
he.MoveNext ();
@@ -533,7 +534,7 @@ namespace Mono.TextEditor.Utils
sb.Append ("@@ -").Append (remStart).Append (",").Append (remEnd - remStart).Append (" +").Append (insStart).Append (",").Append (insEnd - insStart).AppendLine (" @@");
WriteHunks (qh, baseDocument, changedDocument, sb);
}
- return sb.ToString ();
+ return StringBuilderCache.ReturnAndFree (sb);
}
}
diff --git a/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor.Utils/HtmlWriter.cs b/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor.Utils/HtmlWriter.cs
index 0b767362dd..ec69683c7a 100644
--- a/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor.Utils/HtmlWriter.cs
+++ b/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor.Utils/HtmlWriter.cs
@@ -49,7 +49,7 @@ namespace Mono.TextEditor.Utils
public static string GenerateHtml (List<List<ClipboardColoredText>> chunks, EditorTheme style, ITextEditorOptions options, bool includeBoilerplate = true)
{
- var htmlText = new StringBuilder ();
+ var htmlText = StringBuilderCache.Allocate ();
if (includeBoilerplate) {
htmlText.AppendLine (@"<!DOCTYPE HTML PUBLIC ""-//W3C//DTD HTML 4.0 Transitional//EN"">");
htmlText.AppendLine ("<HTML>");
@@ -100,7 +100,7 @@ namespace Mono.TextEditor.Utils
if (Platform.IsWindows)
return GenerateCFHtml (htmlText.ToString ());
- return htmlText.ToString ();
+ return StringBuilderCache.ReturnAndFree (htmlText);
}
static readonly string emptyCFHtmlHeader = GenerateCFHtmlHeader (0, 0, 0, 0);
diff --git a/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor.Utils/RedBlackTree.cs b/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor.Utils/RedBlackTree.cs
index f75e298da7..0ac5ecbe76 100644
--- a/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor.Utils/RedBlackTree.cs
+++ b/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor.Utils/RedBlackTree.cs
@@ -29,6 +29,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
+using MonoDevelop.Core;
namespace Mono.TextEditor.Utils
{
@@ -510,9 +511,9 @@ namespace Mono.TextEditor.Utils
{
if (Root == null)
return "<null>";
- var result = new StringBuilder ();
+ var result = StringBuilderCache.Allocate ();
AppendNode (result, Root, 0);
- return result.ToString ();
+ return StringBuilderCache.ReturnAndFree (result);
}
}
}
diff --git a/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor.Utils/RtfWriter.cs b/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor.Utils/RtfWriter.cs
index 6a62622f19..4a5e01b847 100644
--- a/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor.Utils/RtfWriter.cs
+++ b/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor.Utils/RtfWriter.cs
@@ -29,6 +29,7 @@ using System.Collections.Generic;
using Mono.TextEditor.Highlighting;
using MonoDevelop.Core.Text;
using MonoDevelop.Ide;
+using MonoDevelop.Core;
namespace Mono.TextEditor.Utils
{
@@ -36,7 +37,7 @@ namespace Mono.TextEditor.Utils
{
static string CreateColorTable (List<Cairo.Color> colorList)
{
- var colorTable = new StringBuilder ();
+ var colorTable = StringBuilderCache.Allocate ();
colorTable.Append (@"{\colortbl ;");
for (int i = 0; i < colorList.Count; i++) {
var color = colorList [i];
@@ -49,7 +50,7 @@ namespace Mono.TextEditor.Utils
colorTable.Append (";");
}
colorTable.Append ("}");
- return colorTable.ToString ();
+ return StringBuilderCache.ReturnAndFree (colorTable);
}
public static string GenerateRtf (TextEditorData data)
@@ -97,7 +98,7 @@ namespace Mono.TextEditor.Utils
internal static string GenerateRtf (List<List<ClipboardColoredText>> chunks, MonoDevelop.Ide.Editor.Highlighting.EditorTheme style, ITextEditorOptions options)
{
- var rtfText = new StringBuilder ();
+ var rtfText = StringBuilderCache.Allocate ();
var colorList = new List<Cairo.Color> ();
bool isItalic = false;
@@ -131,7 +132,7 @@ namespace Mono.TextEditor.Utils
rtfText.AppendLine (@"\line");
}
- var rtf = new StringBuilder();
+ var rtf = StringBuilderCache.Allocate ();
rtf.AppendLine (@"{\rtf1\ansi\deff0\adeflang1025");
rtf.AppendLine (@"{\fonttbl");
@@ -147,9 +148,9 @@ namespace Mono.TextEditor.Utils
rtf.Append (fontSize);
} catch (Exception) {};
rtf.AppendLine (@"\cf1");
- rtf.Append (rtfText.ToString ());
+ rtf.Append (StringBuilderCache.ReturnAndFree (rtfText));
rtf.Append("}");
- return rtf.ToString ();
+ return StringBuilderCache.ReturnAndFree (rtf);
}
}
}
diff --git a/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor.Vi/ViActions.cs b/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor.Vi/ViActions.cs
index 9b8c9d1df0..17eb2a7457 100644
--- a/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor.Vi/ViActions.cs
+++ b/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor.Vi/ViActions.cs
@@ -29,6 +29,7 @@
using System;
using System.Collections.Generic;
using System.Text;
+using MonoDevelop.Core;
using MonoDevelop.Core.Text;
using MonoDevelop.Ide.Editor;
@@ -121,7 +122,7 @@ namespace Mono.TextEditor.Vi
DocumentLine seg = data.Document.GetLine (startLine);
startOffset = seg.Offset;
- StringBuilder sb = new StringBuilder (data.Document.GetTextAt (seg).TrimEnd ());
+ StringBuilder sb = StringBuilderCache.Allocate (data.Document.GetTextAt (seg).TrimEnd ());
//lastSpaceOffset = startOffset + sb.Length;
for (int i = startLine + 1; i <= endLine; i++) {
@@ -132,7 +133,7 @@ namespace Mono.TextEditor.Vi
}
length = (seg.Offset - startOffset) + seg.Length;
// TODO: handle conversion issues ?
- data.Replace (startOffset, length, sb.ToString ());
+ data.Replace (startOffset, length, StringBuilderCache.ReturnAndFree (sb));
}
public static void ToggleCase (TextEditorData data)
@@ -141,7 +142,7 @@ namespace Mono.TextEditor.Vi
if (!data.CanEditSelection)
return;
- StringBuilder sb = new StringBuilder (data.SelectedText);
+ StringBuilder sb = StringBuilderCache.Allocate (data.SelectedText);
for (int i = 0; i < sb.Length; i++) {
char ch = sb [i];
if (Char.IsLower (ch))
@@ -149,7 +150,7 @@ namespace Mono.TextEditor.Vi
else if (Char.IsUpper (ch))
sb [i] = Char.ToLower (ch);
}
- data.Replace (data.SelectionRange.Offset, data.SelectionRange.Length, sb.ToString ());
+ data.Replace (data.SelectionRange.Offset, data.SelectionRange.Length, StringBuilderCache.ReturnAndFree (sb));
} else if (data.CanEdit (data.Caret.Line)) {
char ch = data.Document.GetCharAt (data.Caret.Offset);
if (Char.IsLower (ch))
diff --git a/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/Actions/CaretMoveActions.cs b/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/Actions/CaretMoveActions.cs
index ff898c56b5..c00fd946c2 100644
--- a/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/Actions/CaretMoveActions.cs
+++ b/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/Actions/CaretMoveActions.cs
@@ -42,6 +42,9 @@ namespace Mono.TextEditor
{
static class CaretMoveActions
{
+ internal const ushort HighSurrogateMarker = 0b1101_1000_0000_0000;
+ internal const ushort LowSurrogateMarker = 0b1101_1100_0000_0000;
+
public static void Left (TextEditorData data)
{
using (var undo = data.OpenUndoGroup ()) {
@@ -88,6 +91,10 @@ namespace Mono.TextEditor
nextLocation = new DocumentLocation (data.Caret.Line - 1, data.GetVirtualIndentationColumn (nextLocation));
data.Caret.Location = nextLocation;
}
+ var curOffset = data.Caret.Offset;
+ if (curOffset > 0 && curOffset < data.Length && ((ushort)data.GetCharAt (curOffset) & LowSurrogateMarker) == LowSurrogateMarker)
+ data.Caret.Offset--;
+
}
}
@@ -104,7 +111,7 @@ namespace Mono.TextEditor
data.Caret.Offset = data.FindPrevSubwordOffset (data.Caret.Offset);
}
}
-
+
public static void Right (TextEditorData data)
{
using (var undo = data.OpenUndoGroup ()) {
@@ -113,9 +120,8 @@ namespace Mono.TextEditor
data.ClearSelection ();
return;
}
-
DocumentLine line = data.Document.GetLine (data.Caret.Line);
- IEnumerable<FoldSegment > foldings = data.Document.GetStartFoldings (line);
+ IEnumerable<FoldSegment> foldings = data.Document.GetStartFoldings (line);
FoldSegment segment = null;
foreach (FoldSegment folding in foldings) {
if (folding.IsCollapsed && folding.Offset == data.Caret.Offset) {
@@ -124,7 +130,7 @@ namespace Mono.TextEditor
}
}
if (segment != null) {
- data.Caret.Offset = segment.EndOffset;
+ data.Caret.Offset = segment.EndOffset;
return;
}
@@ -156,9 +162,17 @@ namespace Mono.TextEditor
}
}
}
+ MoveOutOfUTF32Character (data);
}
}
-
+
+ static void MoveOutOfUTF32Character (TextEditorData data)
+ {
+ var curOffset = data.Caret.Offset;
+ if (curOffset > 0 && curOffset < data.Length && ((ushort)data.GetCharAt (curOffset) & HighSurrogateMarker) == HighSurrogateMarker)
+ data.Caret.Offset++;
+ }
+
public static void NextWord (TextEditorData data)
{
using (var undo = data.OpenUndoGroup ()) {
@@ -185,6 +199,7 @@ namespace Mono.TextEditor
data.ClearSelection ();
data.Caret.Location = (line >= DocumentLocation.MinLine) ? new DocumentLocation (line, col) : new DocumentLocation (DocumentLocation.MinLine, DocumentLocation.MinColumn);
data.Caret.SetToDesiredColumn (desiredColumn);
+ MoveOutOfUTF32Character (data);
return;
}
@@ -196,6 +211,7 @@ namespace Mono.TextEditor
} else {
ToDocumentStart (data);
}
+ MoveOutOfUTF32Character (data);
}
}
@@ -237,6 +253,7 @@ namespace Mono.TextEditor
} else {
data.Caret.Offset = data.Document.Length;
}
+ MoveOutOfUTF32Character (data);
return;
}
@@ -248,6 +265,7 @@ namespace Mono.TextEditor
} else {
ToDocumentEnd (data);
}
+ MoveOutOfUTF32Character (data);
}
}
diff --git a/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/Actions/ClipboardActions.cs b/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/Actions/ClipboardActions.cs
index f87a6d2bf4..c0894e600b 100644
--- a/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/Actions/ClipboardActions.cs
+++ b/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/Actions/ClipboardActions.cs
@@ -86,7 +86,7 @@ namespace Mono.TextEditor
string GetCopiedPlainText (string eol = "\n")
{
- var plainText = new StringBuilder ();
+ var plainText = StringBuilderCache.Allocate ();
bool first = true;
foreach (var line in copiedColoredChunks) {
if (!first) {
@@ -99,7 +99,7 @@ namespace Mono.TextEditor
plainText.Append (chunk.Text);
}
}
- return plainText.ToString ();
+ return StringBuilderCache.ReturnAndFree (plainText);
}
public void SetData (SelectionData selection_data, uint info)
@@ -435,12 +435,17 @@ namespace Mono.TextEditor
data.Document.CommitLineUpdate (data.GetLineByOffset (insertionOffset));
return result;
}
-
+
public static void Paste (TextEditorData data)
{
+ PasteWithResult (data);
+ }
+
+ public static bool PasteWithResult (TextEditorData data)
+ {
if (!data.CanEditSelection)
- return;
- PasteFrom (Clipboard.Get (CopyOperation.CLIPBOARD_ATOM), data, false, data.IsSomethingSelected ? data.SelectionRange.Offset : data.Caret.Offset);
+ return false;
+ return PasteFrom (Clipboard.Get (CopyOperation.CLIPBOARD_ATOM), data, false, data.IsSomethingSelected ? data.SelectionRange.Offset : data.Caret.Offset) > 0;
}
public static string GetClipboardContent()
diff --git a/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/Actions/DeleteActions.cs b/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/Actions/DeleteActions.cs
index 83c0cbf553..2e061396f2 100644
--- a/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/Actions/DeleteActions.cs
+++ b/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/Actions/DeleteActions.cs
@@ -315,7 +315,12 @@ namespace Mono.TextEditor
if (offset <= 0)
return;
var version = data.Version;
- data.Remove (offset - 1, 1);
+ var o = data.Caret.Offset;
+ if (((ushort)data.GetCharAt (offset - 1) & CaretMoveActions.LowSurrogateMarker) == CaretMoveActions.LowSurrogateMarker) {
+ data.Remove (offset - 2, 2);
+ } else {
+ data.Remove (offset - 1, 1);
+ }
data.Caret.Location = data.OffsetToLocation (version.MoveOffsetTo (data.Version, offset));
}
@@ -380,7 +385,12 @@ namespace Mono.TextEditor
line.UnicodeNewline = UnicodeNewline.Unknown;
}
} else {
- data.Remove (data.Caret.Offset, 1);
+ var o = data.Caret.Offset;
+ if (((ushort)data.GetCharAt (o) & CaretMoveActions.HighSurrogateMarker) == CaretMoveActions.HighSurrogateMarker) {
+ data.Remove (o, 2);
+ } else {
+ data.Remove (o, 1);
+ }
data.Document.CommitLineUpdate (data.Caret.Line);
}
data.FixVirtualIndentation ();
diff --git a/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/Actions/MiscActions.cs b/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/Actions/MiscActions.cs
index 5bf609cd3a..e38d528e9d 100644
--- a/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/Actions/MiscActions.cs
+++ b/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/Actions/MiscActions.cs
@@ -242,9 +242,16 @@ namespace Mono.TextEditor
{
using (var undo = data.OpenUndoGroup ()) {
data.EnsureCaretIsNotVirtual ();
+
+ var oldCaretLine = data.Caret.Location.Line;
+
string indentString = data.GetIndentationString (data.Caret.Location);
data.InsertAtCaret (data.EolMarker);
- data.InsertAtCaret (indentString);
+
+ // Don't insert the indent string if the EOL insertion modified the caret location in an unexpected fashion
+ // (This likely means someone has custom logic regarding insertion of the EOL)
+ if (data.Caret.Location.Line == oldCaretLine + 1 && data.Caret.Location.Column == 1)
+ data.InsertAtCaret (indentString);
}
}
@@ -365,6 +372,8 @@ namespace Mono.TextEditor
//int relCaretOffset = data.Caret.Offset - startLine.Offset;
Mono.TextEditor.DocumentLine prevLine = data.Document.GetLine (lineStart - 1);
+ if (prevLine == null)
+ return;
string text = data.Document.GetTextAt (prevLine.Offset, prevLine.Length);
List<TextLineMarker> prevLineMarkers = new List<TextLineMarker> (data.Document.GetMarkers (prevLine));
data.Document.ClearMarkers (prevLine);
diff --git a/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/CaretImpl.ITextCaret.cs b/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/CaretImpl.ITextCaret.cs
new file mode 100644
index 0000000000..386a85f6c1
--- /dev/null
+++ b/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/CaretImpl.ITextCaret.cs
@@ -0,0 +1,236 @@
+ο»Ώ//
+// CaretImpl.ITextCaret.cs
+//
+// Author:
+// Mike KrΓΌger <mikkrg@microsoft.com>
+//
+// Copyright (c) 2018 Microsoft Corporation. All rights reserved.
+//
+// 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.Linq;
+using MonoDevelop.Core.Text;
+using MonoDevelop.Ide.Editor;
+using System;
+using Microsoft.VisualStudio.Text;
+using Microsoft.VisualStudio.Text.Editor;
+using Microsoft.VisualStudio.Text.Formatting;
+using Mono.TextEditor;
+using MonoDevelop.Ide.Editor;
+
+namespace Mono.TextEditor
+{
+ partial class CaretImpl : ITextCaret
+ {
+ MonoTextEditor TextEditor => TextEditorData.Parent;
+
+ VirtualSnapshotPoint insertionPoint;
+ PositionAffinity _caretAffinity;
+
+ ITextViewLine ITextCaret.ContainingTextViewLine => TextEditor.GetTextViewLineContainingBufferPosition (((ITextCaret)this).Position.VirtualBufferPosition.Position);
+
+ double ITextCaret.Left => TextEditor.TextArea.TextViewMargin.caretX;
+
+ double ITextCaret.Width => TextEditor.TextArea.TextViewMargin.charWidth;
+
+ double ITextCaret.Right => TextEditor.TextArea.TextViewMargin.caretX + TextEditor.TextArea.TextViewMargin.charWidth;
+
+ double ITextCaret.Top => TextEditor.TextArea.TextViewMargin.caretY;
+
+ double ITextCaret.Height => TextEditor.LineHeight;
+
+ double ITextCaret.Bottom => TextEditor.TextArea.TextViewMargin.caretY + TextEditor.LineHeight;
+
+ CaretPosition ITextCaret.Position {
+ get {
+#if TARGET_VS
+ //In theory the _insertion point is always at the same snapshot at the _wpfTextView but there could be cases
+ //where someone is using the position in a classifier that is using the caret position in the classificaiton changed event.
+ //In that case return the old insertion point.
+ return new CaretPosition(_insertionPoint,
+ _textView.BufferGraph.CreateMappingPoint(_insertionPoint.Position, PointTrackingMode.Positive),
+ _caretAffinity);
+#else
+ // MD doesn't update the caret location until after the command has gone completely through the command chain. Too much VS stuff depends on it getting updated earlier.
+ // Thus, I'm going to ensure this is returning a position based on the current snapshot, ignoring/breaking the scenario outlined in the above comment.
+ VirtualSnapshotPoint insertionPointInLatestSnapshot = insertionPoint.TranslateTo (insertionPoint.Position.Snapshot.TextBuffer.CurrentSnapshot, PointTrackingMode.Positive);
+ return new CaretPosition (insertionPointInLatestSnapshot,
+ TextEditor.BufferGraph.CreateMappingPoint (insertionPointInLatestSnapshot.Position, PointTrackingMode.Positive),
+ _caretAffinity);
+#endif
+ }
+ }
+
+
+ bool ITextCaret.OverwriteMode => !IsInInsertMode;
+
+ bool ITextCaret.InVirtualSpace {
+ get {
+ var snapshotLine = TextEditor.TextBuffer.CurrentSnapshot.GetLineFromPosition (((ITextCaret)this).Position.BufferPosition);
+
+ return TextEditor.Caret.Column > snapshotLine.Length + 1;
+ }
+ }
+
+ bool ITextCaret.IsHidden {
+ get {
+ return !IsVisible;
+ }
+ set {
+ IsVisible = !value;
+ }
+ }
+
+ DocumentLocation oldCaretLocation;
+ void PositionChanged_ITextCaret (CaretLocationEventArgs args)
+ {
+ //Some unit tests don't initialize full UI representation of MonoTextEditor
+ //which means they don't depend on ITextCaret implementation, so we can return here
+ //If something is using MonoTextEditor directly(e.g. DiffView) and is not initializing ITextView
+ //TextBuffer is null, in that case don't depend on ITextCaret implementation, so we can return here
+ if (TextEditor?.TextBuffer == null)
+ return;
+ // MD doesn't fire textEditor.CaretPositionChanged until after the command has gone completely through the command chain.
+ // Too much VS stuff depends on it getting updated earlier, so we'll use this event which fires earlier.
+ int position = TextEditor.Caret.Offset;
+ VirtualSnapshotPoint vsp = new VirtualSnapshotPoint (TextEditor.TextSnapshot, position);
+
+ insertionPoint = vsp;
+ if (args.CaretChangeReason == CaretChangeReason.Movement) {
+ oldCaretLocation = args.Location;
+ var oldOffset = TextEditor.LocationToOffset (args.Location);
+ var snapshotPoint = new SnapshotPoint (TextEditor.TextSnapshot, oldOffset);
+ var mappingPoint = TextEditor.BufferGraph.CreateMappingPoint (snapshotPoint, PointTrackingMode.Positive);
+ var oldCaretPosition = new CaretPosition (vsp, mappingPoint, _caretAffinity);
+ var eventArgs = new CaretPositionChangedEventArgs (TextEditor, oldCaretPosition, ((ITextCaret)this).Position);
+
+ ITextCaret_PositionChanged?.Invoke (this, eventArgs);
+ }
+ }
+
+ event EventHandler<CaretPositionChangedEventArgs> ITextCaret_PositionChanged;
+ event EventHandler<CaretPositionChangedEventArgs> ITextCaret.PositionChanged {
+ add { ITextCaret_PositionChanged += value; }
+ remove { ITextCaret_PositionChanged -= value; }
+ }
+
+ void ITextCaret.EnsureVisible ()
+ {
+ TextEditor.ScrollToCaret ();
+ }
+
+
+ CaretPosition ITextCaret.MoveTo (ITextViewLine textLine, double xCoordinate)
+ {
+ Line = textLine.Start;
+ // TODO: xCoordinate - is that just visual or does it have an impact on the column ?
+ return ((ITextCaret)this).Position;
+ }
+
+ CaretPosition ITextCaret.MoveTo (ITextViewLine textLine, double xCoordinate, bool captureHorizontalPosition)
+ {
+ Line = textLine.Start;
+ // TODO: xCoordinate - is that just visual or does it have an impact on the column ?
+ return ((ITextCaret)this).Position;
+ }
+
+ CaretPosition ITextCaret.MoveTo (ITextViewLine textLine)
+ {
+ Line = textLine.Start;
+ return ((ITextCaret)this).Position;
+ }
+
+ CaretPosition ITextCaret.MoveTo (SnapshotPoint bufferPosition)
+ {
+ this.InternalMoveTo (new VirtualSnapshotPoint (bufferPosition), PositionAffinity.Successor, true, true, true);
+
+ return ((ITextCaret)this).Position;
+ }
+
+ CaretPosition ITextCaret.MoveTo (SnapshotPoint bufferPosition, PositionAffinity caretAffinity)
+ {
+ this.InternalMoveTo (new VirtualSnapshotPoint (bufferPosition), caretAffinity, true, true, true);
+
+ return ((ITextCaret)this).Position;
+ }
+
+ CaretPosition ITextCaret.MoveTo (SnapshotPoint bufferPosition, PositionAffinity caretAffinity, bool captureHorizontalPosition)
+ {
+ this.InternalMoveTo (new VirtualSnapshotPoint (bufferPosition), caretAffinity, captureHorizontalPosition, true, true);
+
+ return ((ITextCaret)this).Position;
+ }
+
+ CaretPosition ITextCaret.MoveTo (VirtualSnapshotPoint bufferPosition)
+ {
+ this.InternalMoveTo (bufferPosition, PositionAffinity.Successor, true, true, true);
+
+ return ((ITextCaret)this).Position;
+ }
+
+ CaretPosition ITextCaret.MoveTo (VirtualSnapshotPoint bufferPosition, PositionAffinity caretAffinity)
+ {
+ this.InternalMoveTo (bufferPosition, caretAffinity, true, true, true);
+
+ return ((ITextCaret)this).Position;
+ }
+
+ CaretPosition ITextCaret.MoveTo (VirtualSnapshotPoint bufferPosition, PositionAffinity caretAffinity, bool captureHorizontalPosition)
+ {
+ this.InternalMoveTo (bufferPosition, caretAffinity, captureHorizontalPosition, true, true);
+
+ return ((ITextCaret)this).Position;
+ }
+
+ CaretPosition ITextCaret.MoveToNextCaretPosition ()
+ {
+ // TODO: Implement me - not sure if we've a 'next' position. What should this be ?
+ return ((ITextCaret)this).Position;
+ }
+
+ CaretPosition ITextCaret.MoveToPreferredCoordinates ()
+ {
+ TextEditor.GetTextEditorData ().FixVirtualIndentation ();
+ return ((ITextCaret)this).Position;
+ }
+
+ CaretPosition ITextCaret.MoveToPreviousCaretPosition ()
+ {
+ Location = oldCaretLocation;
+ return ((ITextCaret)this).Position;
+ }
+
+ void InternalMoveTo (VirtualSnapshotPoint bufferPosition, PositionAffinity caretAffinity, bool captureHorizontalPosition, bool captureVerticalPosition, bool raiseEvent)
+ {
+ int requestedPosition = bufferPosition.Position;
+ ITextSnapshotLine snapshotLine = TextEditor.TextSnapshot.GetLineFromPosition (requestedPosition);
+ int line = snapshotLine.LineNumber + 1;
+
+ int col;
+ if (bufferPosition.IsInVirtualSpace) {
+ col = bufferPosition.VirtualSpaces;
+ } else {
+ col = requestedPosition - snapshotLine.Start + 1;
+ }
+
+ TextEditor.SetCaretTo (line, col, false, false);
+ }
+ }
+} \ No newline at end of file
diff --git a/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/CaretImpl.cs b/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/CaretImpl.cs
index d27baf33ae..9822b5a151 100644
--- a/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/CaretImpl.cs
+++ b/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/CaretImpl.cs
@@ -27,12 +27,13 @@
using System;
using System.Linq;
+using Microsoft.VisualStudio.Text;
using MonoDevelop.Core.Text;
using MonoDevelop.Ide.Editor;
namespace Mono.TextEditor
{
- class CaretImpl : MonoDevelop.Ide.Editor.Caret
+ partial class CaretImpl : MonoDevelop.Ide.Editor.Caret
{
bool isInInsertMode = true;
bool autoScrollToCaret = true;
@@ -196,6 +197,10 @@ namespace Mono.TextEditor
AllowCaretBehindLineEnd = false;
DesiredColumn = DocumentLocation.MinColumn;
AutoUpdatePosition = true;
+
+ // Set up initial values
+ _caretAffinity = PositionAffinity.Successor;
+ insertionPoint = new VirtualSnapshotPoint (new SnapshotPoint (editor.Document.TextBuffer.CurrentSnapshot, 0));
}
/// <summary>
@@ -324,6 +329,7 @@ namespace Mono.TextEditor
{
TextEditorData.Document.EnsureOffsetIsUnfolded (Offset);
base.OnPositionChanged (args);
+ PositionChanged_ITextCaret (args);
}
protected virtual void OnModeChanged ()
diff --git a/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/Document/DiffTracker.cs b/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/Document/DiffTracker.cs
index d35ced6951..2246c19076 100644
--- a/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/Document/DiffTracker.cs
+++ b/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/Document/DiffTracker.cs
@@ -33,9 +33,13 @@ namespace Mono.TextEditor
{
class LineChangeInfo
{
+ internal readonly static LineChangeInfo Unchanged = new LineChangeInfo (TextDocument.LineState.Unchanged);
+ internal readonly static LineChangeInfo Dirty = new LineChangeInfo (TextDocument.LineState.Dirty);
+ internal readonly static LineChangeInfo Changed = new LineChangeInfo (TextDocument.LineState.Changed);
+
public Mono.TextEditor.TextDocument.LineState state;
- public LineChangeInfo (Mono.TextEditor.TextDocument.LineState state)
+ LineChangeInfo (Mono.TextEditor.TextDocument.LineState state)
{
this.state = state;
}
@@ -70,7 +74,9 @@ namespace Mono.TextEditor
if (lineStates == null)
return;
for(int i = e.TextChanges.Count - 1; i >= 0; i--) {
- var change = e.TextChanges[i];
+ var change = e.TextChanges[i];
+ if (change.RemovalLength == 0)
+ continue;
var startLine = trackDocument.GetLineByOffset (change.Offset);
var endRemoveLine = trackDocument.GetLineByOffset (change.Offset + change.RemovalLength);
if (startLine == null || endRemoveLine == null)
@@ -91,17 +97,20 @@ namespace Mono.TextEditor
var startLine = trackDocument.GetLineByOffset (change.NewOffset);
var endLine = trackDocument.GetLineByOffset (change.NewOffset + change.InsertionLength);
var lineNumber = startLine.LineNumber;
- var oldState = lineNumber < lineStates.Count ? lineStates [lineNumber] : null;
- if (oldState != null && oldState.state == TextDocument.LineState.Dirty)
- continue;
var insertedLines = endLine.LineNumber - lineNumber;
+ if (insertedLines == 0) {
+ var oldState = lineNumber < lineStates.Count ? lineStates [lineNumber] : null;
+ if (oldState != null && oldState.state == TextDocument.LineState.Dirty)
+ continue;
+ lineStates[lineNumber] = LineChangeInfo.Dirty;
+ if (trackDocument != null)
+ trackDocument.CommitMultipleLineUpdate (lineNumber, lineNumber + insertedLines);
+ continue;
+ }
try {
- lineStates [lineNumber] = new LineChangeInfo (Mono.TextEditor.TextDocument.LineState.Dirty);
+ lineStates.InsertRange (lineNumber, insertedLines , LineChangeInfo.Dirty);
if (trackDocument != null)
- trackDocument.CommitLineUpdate (lineNumber);
- while (insertedLines-- > 0) {
- lineStates.Insert (lineNumber, new LineChangeInfo (Mono.TextEditor.TextDocument.LineState.Dirty));
- }
+ trackDocument.CommitMultipleLineUpdate (lineNumber, lineNumber + insertedLines);
} catch (Exception ex) {
Console.WriteLine ("error while DiffTracker.TrackDocument_TextChanged:" + ex);
}
@@ -113,11 +122,11 @@ namespace Mono.TextEditor
if (lineStates != null) {
foreach (var node in lineStates.tree) {
if (node.value.state == Mono.TextEditor.TextDocument.LineState.Dirty)
- node.value.state = Mono.TextEditor.TextDocument.LineState.Changed;
+ node.value = LineChangeInfo.Changed;
}
} else {
lineStates = new CompressingTreeList<LineChangeInfo>((x, y) => x.Equals(y));
- lineStates.InsertRange(0, document.LineCount + 1, new LineChangeInfo (Mono.TextEditor.TextDocument.LineState.Unchanged));
+ lineStates.InsertRange (0, document.LineCount + 1, LineChangeInfo.Unchanged);
trackDocument.TextChanging += TrackDocument_TextChanging;
trackDocument.TextChanged += TrackDocument_TextChanged;
}
@@ -126,7 +135,7 @@ namespace Mono.TextEditor
public void Reset ()
{
lineStates = new CompressingTreeList<LineChangeInfo>((x, y) => x.Equals(y));
- lineStates.InsertRange(0, trackDocument.LineCount + 1, new LineChangeInfo (Mono.TextEditor.TextDocument.LineState.Unchanged));
+ lineStates.InsertRange(0, trackDocument.LineCount + 1, LineChangeInfo.Unchanged);
}
}
}
diff --git a/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/Document/DocumentLine.cs b/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/Document/DocumentLine.cs
index d05fb34a1f..2ee0d26d59 100644
--- a/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/Document/DocumentLine.cs
+++ b/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/Document/DocumentLine.cs
@@ -32,6 +32,7 @@ using Mono.TextEditor.Highlighting;
using System.Linq;
using MonoDevelop.Ide.Editor;
using MonoDevelop.Core.Text;
+using MonoDevelop.Core;
namespace Mono.TextEditor
{
@@ -175,7 +176,7 @@ namespace Mono.TextEditor
/// </returns>
public string GetIndentation (TextDocument doc)
{
- var result = new StringBuilder ();
+ var result = StringBuilderCache.Allocate ();
int offset = Offset;
int max = System.Math.Min (offset + LengthIncludingDelimiter, doc.Length);
for (int i = offset; i < max; i++) {
@@ -184,7 +185,7 @@ namespace Mono.TextEditor
break;
result.Append (ch);
}
- return result.ToString ();
+ return StringBuilderCache.ReturnAndFree (result);
}
public int GetLogicalColumn (TextEditorData editor, int visualColumn)
diff --git a/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/Document/DocumentUpdateRequest.cs b/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/Document/DocumentUpdateRequest.cs
index 2cd7c20c7c..dded9bdb91 100644
--- a/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/Document/DocumentUpdateRequest.cs
+++ b/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/Document/DocumentUpdateRequest.cs
@@ -84,12 +84,8 @@ namespace Mono.TextEditor
public override void Update (MonoTextEditor editor)
{
if (start == end) {
- editor.TextViewMargin.RemoveCachedLine (start);
editor.RedrawLine (start);
} else {
- for (int i = start; i <= end; i++) {
- editor.TextViewMargin.RemoveCachedLine (i);
- }
editor.RedrawLines (start, end);
}
}
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 3d39f9b743..05a1c1db71 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
@@ -35,6 +35,7 @@ using System.ComponentModel;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
+using MonoDevelop.Ide.Composition;
using MonoDevelop.Core.Text;
using MonoDevelop.Ide.Editor;
using MonoDevelop.Core;
@@ -42,6 +43,7 @@ using System.IO;
using MonoDevelop.Ide.Editor.Highlighting;
using Microsoft.VisualStudio.Platform;
using Microsoft.VisualStudio.Text.Tagging;
+using Microsoft.VisualStudio.Utilities;
namespace Mono.TextEditor
{
@@ -69,7 +71,7 @@ namespace Mono.TextEditor
return PlatformCatalog.Instance.MimeToContentTypeRegistryService.GetMimeType(snapshot.ContentType) ?? snapshot.ContentType.TypeName;
}
set {
- var newContentType = value != null ? GetContentTypeFromMimeType(value) : PlatformCatalog.Instance.ContentTypeRegistryService.UnknownContentType;
+ var newContentType = value != null ? GetContentTypeFromMimeType(null, value) : PlatformCatalog.Instance.ContentTypeRegistryService.UnknownContentType;
if (this.TextBuffer.CurrentSnapshot.ContentType != newContentType) {
this.TextBuffer.ChangeContentType(newContentType, null);
@@ -77,9 +79,20 @@ namespace Mono.TextEditor
}
}
- private static Microsoft.VisualStudio.Utilities.IContentType GetContentTypeFromMimeType(string mimeType)
+ private static Microsoft.VisualStudio.Utilities.IContentType GetContentTypeFromMimeType(string filePath, string mimeType)
{
- Microsoft.VisualStudio.Utilities.IContentType contentType = PlatformCatalog.Instance.MimeToContentTypeRegistryService.GetContentType(mimeType);
+ if (filePath != null)
+ {
+ IFilePathRegistryService filePathRegistryService = CompositionManager.GetExportedValue<IFilePathRegistryService> ();
+
+ IContentType contentTypeFromPath = filePathRegistryService.GetContentTypeForPath (filePath);
+ if (contentTypeFromPath != PlatformCatalog.Instance.ContentTypeRegistryService.UnknownContentType)
+ {
+ return contentTypeFromPath;
+ }
+ }
+
+ IContentType contentType = PlatformCatalog.Instance.MimeToContentTypeRegistryService.GetContentType (mimeType);
if (contentType == null)
{
// fallback 1: see if there is a content tyhpe with the same name
@@ -147,7 +160,7 @@ namespace Mono.TextEditor
void SyntaxMode_HighlightingStateChanged (object sender, MonoDevelop.Ide.Editor.LineEventArgs e)
{
- CommitDocumentUpdate ();
+ CommitMultipleLineUpdate (e.Line.LineNumber, e.Line.LineNumber);
}
void OnSyntaxModeChanged (SyntaxModeChangeEventArgs e)
@@ -213,6 +226,7 @@ namespace Mono.TextEditor
this.TextBuffer.Properties.AddProperty(typeof(ITextDocument), this);
this.TextBuffer.Changed += this.OnTextBufferChanged;
+ (this.TextBuffer as Microsoft.VisualStudio.Text.Implementation.BaseBuffer).ChangedImmediate += OnTextBufferChangedImmediate;
this.TextBuffer.ContentTypeChanged += this.OnTextBufferContentTypeChanged;
this.VsTextDocument.FileActionOccurred += this.OnTextDocumentFileActionOccured;
@@ -230,7 +244,7 @@ namespace Mono.TextEditor
SyntaxMode = null;
}
- void OnTextBufferChanged(object sender, Microsoft.VisualStudio.Text.TextContentChangedEventArgs args)
+ private void OnTextBufferChangedImmediate (object sender, Microsoft.VisualStudio.Text.TextContentChangedEventArgs args)
{
if (args.Changes == null)
return;
@@ -239,14 +253,25 @@ namespace Mono.TextEditor
changes.Add (new TextChange (change.OldPosition, change.NewPosition, change.OldText, change.NewText));
EnsureSegmentIsUnfolded(change.OldPosition, change.NewLength);
}
- bool endUndo = false;
- UndoOperation operation = null;
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;
+ }
+
+ void OnTextBufferChanged(object sender, Microsoft.VisualStudio.Text.TextContentChangedEventArgs args)
+ {
+ if (args.Changes == null)
+ return;
+ var changes = new List<TextChange> ();
+ foreach (var change in args.Changes) {
+ changes.Add (new TextChange (change.OldPosition, change.NewPosition, change.OldText, change.NewText));
+ }
+ bool endUndo = false;
+ UndoOperation operation = null;
+ var textChange = new TextChangeEventArgs(changes);
if (!isInUndo) {
operation = new UndoOperation(args);
@@ -294,11 +319,11 @@ namespace Mono.TextEditor
public TextDocument (string fileName, string mimeType)
{
- var contentType = GetContentTypeFromMimeType (mimeType);
+ var contentType = (mimeType == null) ? PlatformCatalog.Instance.TextBufferFactoryService.InertContentType : GetContentTypeFromMimeType(fileName, mimeType);
Encoding enc;
var text = TextFileUtility.GetText (fileName, out enc);
var buffer = PlatformCatalog.Instance.TextBufferFactoryService.CreateTextBuffer (text ?? string.Empty,
- PlatformCatalog.Instance.TextBufferFactoryService.InertContentType);
+ contentType);
this.VsTextDocument = PlatformCatalog.Instance.TextDocumentFactoryService.CreateTextDocument (buffer, fileName);
this.VsTextDocument.Encoding = enc;
@@ -306,13 +331,14 @@ namespace Mono.TextEditor
this.Initialize();
}
- public TextDocument (string text = null)
+ public TextDocument (string text = null, string fileName = null, string mimeType = null)
{
- var buffer = PlatformCatalog.Instance.TextBufferFactoryService.CreateTextBuffer(text ?? string.Empty,
- PlatformCatalog.Instance.TextBufferFactoryService.InertContentType);
+ var contentType = (mimeType == null) ? PlatformCatalog.Instance.TextBufferFactoryService.InertContentType : GetContentTypeFromMimeType(fileName, mimeType);
+ var buffer = PlatformCatalog.Instance.TextBufferFactoryService.CreateTextBuffer (text ?? string.Empty,
+ contentType);
- this.VsTextDocument = PlatformCatalog.Instance.TextDocumentFactoryService.CreateTextDocument(buffer, string.Empty);
- this.VsTextDocument.Encoding = MonoDevelop.Core.Text.TextFileUtility.DefaultEncoding;
+ this.VsTextDocument = PlatformCatalog.Instance.TextDocumentFactoryService.CreateTextDocument(buffer, fileName ?? string.Empty);
+ this.VsTextDocument.Encoding = TextFileUtility.DefaultEncoding;
this.Initialize();
}
diff --git a/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/TextEditorData.cs b/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/TextEditorData.cs
index 8216ea1169..1609832a40 100644
--- a/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/TextEditorData.cs
+++ b/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/TextEditorData.cs
@@ -39,6 +39,7 @@ using System.Threading;
using MonoDevelop.Ide;
using System.Linq;
using System.Threading.Tasks;
+using MonoDevelop.Core;
namespace Mono.TextEditor
{
@@ -205,12 +206,13 @@ namespace Mono.TextEditor
{
LineHeight = 16;
- caret = new CaretImpl (this);
- caret.PositionChanged += CaretPositionChanged;
-
options = TextEditorOptions.DefaultOptions;
document = doc;
AttachDocument ();
+
+ caret = new CaretImpl (this);
+ caret.PositionChanged += CaretPositionChanged;
+
SearchEngine = new BasicSearchEngine ();
HeightTree = new HeightTree (this);
@@ -352,7 +354,7 @@ namespace Mono.TextEditor
{
if (str == null)
throw new ArgumentNullException ("str");
- var result = new StringBuilder ();
+ var result = StringBuilderCache.Allocate ();
foreach (char ch in str) {
switch (ch) {
case '&':
@@ -376,7 +378,7 @@ namespace Mono.TextEditor
break;
}
}
- return result.ToString ();
+ return StringBuilderCache.ReturnAndFree (result);
}
internal static int CalcIndentLength (string indent)
@@ -424,7 +426,7 @@ namespace Mono.TextEditor
int indentLength = -1;
int curOffset = offset;
- StringBuilder result = new StringBuilder ();
+ StringBuilder result = StringBuilderCache.Allocate ();
while (curOffset < offset + length && curOffset < Document.Length) {
DocumentLine line = Document.GetLineByOffset (curOffset);
int toOffset = System.Math.Min (line.Offset + line.Length, offset + length);
@@ -481,7 +483,7 @@ namespace Mono.TextEditor
if (result.Length > 0 && curOffset < offset + length)
result.AppendLine ();
}
- return result.ToString ();
+ return StringBuilderCache.ReturnAndFree (result);
}
internal async Task<IEnumerable<MonoDevelop.Ide.Editor.Highlighting.ColoredSegment>> GetChunks (DocumentLine line, int offset, int length)
@@ -518,7 +520,7 @@ namespace Mono.TextEditor
{
if (string.IsNullOrEmpty (str))
return "";
- StringBuilder sb = new StringBuilder ();
+ StringBuilder sb = StringBuilderCache.Allocate ();
bool convertTabs = TabsToSpaces;
var tabSize = Options.TabSize;
for (int i = 0; i < str.Length; i++) {
@@ -549,7 +551,7 @@ namespace Mono.TextEditor
break;
}
}
- return sb.ToString ();
+ return StringBuilderCache.ReturnAndFree (sb);
}
public string FormatString (int offset, string str)
diff --git a/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/UrlMarker.cs b/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/UrlMarker.cs
index 07517710f7..79fb4fba8d 100644
--- a/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/UrlMarker.cs
+++ b/main/src/core/Mono.TextEditor.Shared/Mono.TextEditor/UrlMarker.cs
@@ -86,25 +86,9 @@ namespace Mono.TextEditor
this.endColumn = endColumn;
}
-
- void Doc_TextChanging (object sender, MonoDevelop.Core.Text.TextChangeEventArgs e)
- {
- var lineSegment = LineSegment.Segment;
- for (int i = 0; i < e.TextChanges.Count; ++i) {
- var change = e.TextChanges[i];
- if (lineSegment.IsInside (change.Offset) || lineSegment.IsInside (change.Offset + change.RemovalLength) ||
- change.Offset <= lineSegment.Offset && lineSegment.Offset <= change.Offset + change.RemovalLength) {
- doc.RemoveMarker (this);
- }
- }
- }
-
public void Dispose ()
{
- if (doc != null) {
- doc.TextChanging -= Doc_TextChanging;
- doc = null;
- }
+ doc = null;
}
public override void Draw (MonoTextEditor editor, Cairo.Context cr, LineMetrics metrics)
@@ -146,9 +130,12 @@ namespace Mono.TextEditor
to = System.Math.Max (to, editor.TextViewMargin.XOffset);
if (@from < to) {
if (color == null) {
- foreach (var chunk in metrics.Layout.Chunks)
- if (chunk.Contains (startOffset))
+ foreach (var chunk in metrics.Layout.Chunks) {
+ if (chunk.Contains (markerStart)) {
color = editor.EditorTheme.GetForeground (editor.EditorTheme.GetChunkStyle (chunk.ScopeStack));
+ break;
+ }
+ }
if (color == null)
color = editor.EditorTheme.GetForeground (editor.EditorTheme.GetChunkStyle (new ScopeStack (style)));
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/PcFileCache.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/PcFileCache.cs
index 167d48924e..3b7e7a3b88 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/PcFileCache.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/PcFileCache.cs
@@ -29,6 +29,7 @@ using System.Text;
using System.Xml;
using System.IO;
using System.Collections.Generic;
+using MonoDevelop.Core;
// IMPORTANT IMPORTANT IMPORTANT IMPORTANT IMPORTANT IMPORTANT
// This code is shared with xbuild, which has to build with .NET 2.0,
@@ -535,7 +536,7 @@ namespace Mono.PkgConfig
if (i == -1)
return value;
- StringBuilder sb = new StringBuilder ();
+ StringBuilder sb = StringBuilderCache.Allocate ();
int last = 0;
while (i != -1 && i < value.Length) {
sb.Append (value, last, i - last);
@@ -546,6 +547,7 @@ namespace Mono.PkgConfig
if (n == -1 || n == i) {
// Closing bracket not found or empty name
HasErrors = true;
+ StringBuilderCache.Free (sb);
return value;
}
string rname = value.Substring (i, n - i);
@@ -554,6 +556,7 @@ namespace Mono.PkgConfig
sb.Append (rval);
else {
HasErrors = true;
+ StringBuilderCache.Free (sb);
return value;
}
i = n + 1;
@@ -565,7 +568,7 @@ namespace Mono.PkgConfig
i = value.IndexOf ("${", i);
}
sb.Append (value, last, value.Length - last);
- return sb.ToString ();
+ return StringBuilderCache.ReturnAndFree (sb);
}
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/LocalConsole.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/LocalConsole.cs
index 17b496bf80..cadd1fd113 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/LocalConsole.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/LocalConsole.cs
@@ -221,36 +221,36 @@ namespace MonoDevelop.Core.Execution
public override string ReadLine ()
{
- StringBuilder sb = new StringBuilder ();
+ StringBuilder sb = StringBuilderCache.Allocate ();
while (LoadCurrent (true)) {
for (int i=idx; i < current.Length; i++) {
if (current[i] == '\n') {
idx = i + 1;
sb.Append (current, 0, i);
- return sb.ToString ();
+ return StringBuilderCache.ReturnAndFree (sb);
}
if (current[i] == '\r') {
idx = i + 1;
sb.Append (current, 0, i);
if (LoadCurrent (true) && current [idx] == '\n')
idx++;
- return sb.ToString ();
+ return StringBuilderCache.ReturnAndFree (sb);
}
}
sb.Append (current, idx, current.Length - idx);
current = null;
}
- return sb.ToString ();
+ return StringBuilderCache.ReturnAndFree (sb);
}
public override string ReadToEnd ()
{
- StringBuilder sb = new StringBuilder ();
+ StringBuilder sb = StringBuilderCache.Allocate ();
while (LoadCurrent (true)) {
sb.Append (current, idx, current.Length - idx);
current = null;
}
- return sb.ToString ();
+ return StringBuilderCache.ReturnAndFree (sb);
}
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/ProcessArgumentBuilder.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/ProcessArgumentBuilder.cs
index f43d1d72a5..f875d79a2d 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/ProcessArgumentBuilder.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Execution/ProcessArgumentBuilder.cs
@@ -115,11 +115,11 @@ namespace MonoDevelop.Core.Execution
/// arguments, only quoted arguments with escaped quotes.</remarks>
public static string Quote (string s)
{
- var sb = new StringBuilder ();
+ var sb = StringBuilderCache.Allocate ();
sb.Append ('"');
AppendEscaped (sb, escapeDoubleQuoteCharsStr, s);
sb.Append ('"');
- return sb.ToString ();
+ return StringBuilderCache.ReturnAndFree (sb);
}
public override string ToString ()
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Logging/AssertLoggingTraceListener.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Logging/AssertLoggingTraceListener.cs
index 9cf02b44e3..3778df5720 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Logging/AssertLoggingTraceListener.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Logging/AssertLoggingTraceListener.cs
@@ -45,7 +45,7 @@ namespace MonoDevelop.Core.Logging
if (callerFrame == frames.Length - 1)
callerFrame = 0;
- var sb = new StringBuilder ();
+ var sb = StringBuilderCache.Allocate();
if (IsRealMessage (message)) {
if (!string.IsNullOrEmpty (detailMessage)) {
sb.AppendFormat ("Failed assertion: {0} - {1}", message, detailMessage);
@@ -61,7 +61,7 @@ namespace MonoDevelop.Core.Logging
sb.Append ("\n");
FormatStackTrace (sb, frames, callerFrame);
- LoggingService.LogError (sb.ToString ());
+ LoggingService.LogError (StringBuilderCache.ReturnAndFree(sb));
}
static bool IsRealMessage (string message)
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Text/TextChangeEventArgs.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Text/TextChangeEventArgs.cs
index 31e5958e46..2f312311ac 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Text/TextChangeEventArgs.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Text/TextChangeEventArgs.cs
@@ -222,7 +222,7 @@ namespace MonoDevelop.Core.Text
{
if (text == null)
return null;
- var sb = new StringBuilder ();
+ var sb = StringBuilderCache.Allocate ();
foreach (var ch in text) {
switch (ch) {
case '\r':
@@ -239,7 +239,7 @@ namespace MonoDevelop.Core.Text
break;
}
}
- return sb.ToString ();
+ return StringBuilderCache.ReturnAndFree (sb);
}
}
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.csproj b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.csproj
index 9fdd2d303a..122cc76e90 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.csproj
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.csproj
@@ -106,20 +106,17 @@
<Reference Include="Humanizer.Core">
<HintPath>..\..\..\packages\Humanizer.Core.2.2.0\lib\netstandard1.0\Humanizer.dll</HintPath>
</Reference>
- <Reference Include="Esent.Interop, Version=1.9.4.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
- <HintPath>..\..\..\packages\ManagedEsent.1.9.4\lib\net40\Esent.Interop.dll</HintPath>
- </Reference>
<Reference Include="SQLitePCLRaw.batteries_e_sqlite3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=17faffbb2a73a73f, processorArchitecture=MSIL">
- <HintPath>..\..\..\packages\SQLitePCLRaw.bundle_e_sqlite3.1.1.6\lib\net45\SQLitePCLRaw.batteries_e_sqlite3.dll</HintPath>
+ <HintPath>..\..\..\packages\SQLitePCLRaw.bundle_e_sqlite3.1.1.9\lib\net45\SQLitePCLRaw.batteries_e_sqlite3.dll</HintPath>
</Reference>
<Reference Include="SQLitePCLRaw.batteries_v2, Version=1.0.0.0, Culture=neutral, PublicKeyToken=8226ea5df37bcae9, processorArchitecture=MSIL">
- <HintPath>..\..\..\packages\SQLitePCLRaw.bundle_e_sqlite3.1.1.6\lib\net45\SQLitePCLRaw.batteries_v2.dll</HintPath>
+ <HintPath>..\..\..\packages\SQLitePCLRaw.bundle_e_sqlite3.1.1.9\lib\net45\SQLitePCLRaw.batteries_v2.dll</HintPath>
</Reference>
<Reference Include="SQLitePCLRaw.core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1488e028ca7ab535, processorArchitecture=MSIL">
- <HintPath>..\..\..\packages\SQLitePCLRaw.core.1.1.6\lib\net45\SQLitePCLRaw.core.dll</HintPath>
+ <HintPath>..\..\..\packages\SQLitePCLRaw.core.1.1.9\lib\net45\SQLitePCLRaw.core.dll</HintPath>
</Reference>
<Reference Include="SQLitePCLRaw.provider.e_sqlite3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9c301db686d0bd12, processorArchitecture=MSIL">
- <HintPath>..\..\..\packages\SQLitePCLRaw.provider.e_sqlite3.net45.1.1.6\lib\net45\SQLitePCLRaw.provider.e_sqlite3.dll</HintPath>
+ <HintPath>..\..\..\packages\SQLitePCLRaw.provider.e_sqlite3.net45.1.1.9\lib\net45\SQLitePCLRaw.provider.e_sqlite3.dll</HintPath>
</Reference>
<Reference Include="Mono.Posix" />
<Reference Include="System.Composition.AttributedModel, Version=1.0.31.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
@@ -159,16 +156,16 @@
<Private>False</Private>
</Reference>
<Reference Include="Mono.Cecil">
- <HintPath>..\..\..\packages\Mono.Cecil.0.10.0-beta6\lib\net40\Mono.Cecil.dll</HintPath>
+ <HintPath>..\..\..\packages\Mono.Cecil.0.10.0-beta7\lib\net40\Mono.Cecil.dll</HintPath>
</Reference>
<Reference Include="Mono.Cecil.Mdb">
- <HintPath>..\..\..\packages\Mono.Cecil.0.10.0-beta6\lib\net40\Mono.Cecil.Mdb.dll</HintPath>
+ <HintPath>..\..\..\packages\Mono.Cecil.0.10.0-beta7\lib\net40\Mono.Cecil.Mdb.dll</HintPath>
</Reference>
<Reference Include="Mono.Cecil.Pdb">
- <HintPath>..\..\..\packages\Mono.Cecil.0.10.0-beta6\lib\net40\Mono.Cecil.Pdb.dll</HintPath>
+ <HintPath>..\..\..\packages\Mono.Cecil.0.10.0-beta7\lib\net40\Mono.Cecil.Pdb.dll</HintPath>
</Reference>
<Reference Include="Mono.Cecil.Rocks">
- <HintPath>..\..\..\packages\Mono.Cecil.0.10.0-beta6\lib\net40\Mono.Cecil.Rocks.dll</HintPath>
+ <HintPath>..\..\..\packages\Mono.Cecil.0.10.0-beta7\lib\net40\Mono.Cecil.Rocks.dll</HintPath>
</Reference>
<Reference Include="monodoc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756" />
<Reference Include="mscorlib" />
@@ -241,6 +238,9 @@
<Reference Include="System.Xml.XPath.XDocument">
<HintPath>..\..\..\packages\System.Xml.XPath.XDocument.4.3.0\lib\net46\System.Xml.XPath.XDocument.dll</HintPath>
</Reference>
+ <Reference Include="Microsoft.VisualStudio.CodingConventions">
+ <HintPath>..\..\..\packages\Microsoft.VisualStudio.CodingConventions.1.1.20180226.4\lib\netstandard1.3\Microsoft.VisualStudio.CodingConventions.dll</HintPath>
+ </Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="MonoDevelop.Core\StringParserService.cs" />
@@ -756,6 +756,9 @@
<Compile Include="MonoDevelop.FSW\OSX\SR.cs" />
<Compile Include="MonoDevelop.FSW\FileSystemWatcher.cs" />
<Compile Include="MonoDevelop.FSW\Mono\FileSystemWatcher.cs" />
+ <Compile Include="MonoDevelop.Core\StringBuilderCache.cs" />
+ <Compile Include="MonoDevelop.Core\ObjectPool.cs" />
+ <Compile Include="MonoDevelop.Core\SharedPools.cs" />
</ItemGroup>
<ItemGroup>
<None Include="Makefile.am" />
@@ -800,7 +803,7 @@
<InternalsVisibleTo Include="MonoDevelop.Ide.Tests" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
- <Target Name="BeforeBuild" Inputs="BuildVariables.cs.in; $(MSBuildProjectDirectory)\..\..\..\..\version.config" Outputs="BuildVariables.cs" Condition="Exists('$(MSBuildProjectDirectory)\..\..\..\..\version.config')" >
+ <Target Name="BeforeBuild" Inputs="BuildVariables.cs.in; $(MSBuildProjectDirectory)\..\..\..\..\version.config" Outputs="BuildVariables.cs" Condition="Exists('$(MSBuildProjectDirectory)\..\..\..\..\version.config')">
<MakeDir Directories="$(FullBuildInfo)" />
<Csc Sources="$(ConfigureScript)" OutputAssembly="$(ConfigureScriptExe)" ToolExe="$(CscToolExe)" ToolPath="$(CscToolPath)" Condition="!Exists('$(ConfigureScriptExe)')" />
<Exec Command="$(MonoLauncher)$(ConfigureScriptExe) gen-buildinfo $(FullBuildInfo)" WorkingDirectory="$(MSBuildProjectDirectory)" />
@@ -812,15 +815,16 @@
<Exec Command="&quot;$(Git)&quot; rev-parse HEAD &gt; $(VcRevision)" WorkingDirectory="$(MSBuildProjectDirectory)" IgnoreExitCode="True" />
<RemoveDir Directories="$(FullBuildInfo)" />
</Target>
- <Import Project="..\..\..\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.6\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets" Condition="Exists('..\..\..\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.6\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets')" />
+ <Import Project="..\..\..\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.9\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets" Condition="Exists('..\..\..\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.9\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
- <Error Condition="!Exists('..\..\..\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.6\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.6\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets'))" />
- <Error Condition="!Exists('..\..\..\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.6\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.6\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets'))" />
- <Error Condition="!Exists('..\..\..\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.6\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.6\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets'))" />
+ <Error Condition="!Exists('..\..\..\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.9\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.9\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets'))" />
+ <Error Condition="!Exists('..\..\..\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.9\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.9\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets'))" />
+ <Error Condition="!Exists('..\..\..\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.9\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.9\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets'))" />
</Target>
- <Import Project="..\..\..\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.6\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets" Condition="Exists('..\..\..\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.6\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets')" />
- <Import Project="..\..\..\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.6\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets" Condition="Exists('..\..\..\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.6\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets')" />
+ <Import Project="..\..\..\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.9\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets" Condition="Exists('..\..\..\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.9\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets')" />
+ <Import Project="..\..\..\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.9\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets" Condition="Exists('..\..\..\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.9\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets')" />
+ <Import Project="..\..\..\msbuild\SQLiteOSXHack.targets" />
</Project>
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core/ErrorHelper.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core/ErrorHelper.cs
index 73e1f56ec5..610d7cd346 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core/ErrorHelper.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core/ErrorHelper.cs
@@ -51,13 +51,13 @@ namespace MonoDevelop.Core
var ae = (AggregateException)ex;
if (ae.InnerExceptions.Count == 1)
return GetErrorMessage (ae.InnerException);
- StringBuilder sb = new StringBuilder ();
+ StringBuilder sb = StringBuilderCache.Allocate ();
foreach (var e in ae.InnerExceptions) {
if (sb.Length > 0 && sb [sb.Length - 1] != '.')
sb.Append (". ");
sb.Append (GetErrorMessage (ex).Trim ());
}
- return sb.ToString ();
+ return StringBuilderCache.ReturnAndFree (sb);
} else if (ex is UserException) {
var ue = (UserException)ex;
if (!string.IsNullOrEmpty (ue.Details)) {
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core/LoggingService.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core/LoggingService.cs
index af14d65bad..f226217773 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core/LoggingService.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core/LoggingService.cs
@@ -37,6 +37,7 @@ using MonoDevelop.Core.LogReporting;
using MonoDevelop.Core.Logging;
using Mono.Unix.Native;
using System.Text;
+using System.Collections.Immutable;
namespace MonoDevelop.Core
{
@@ -46,7 +47,8 @@ namespace MonoDevelop.Core
const string ReportCrashesKey = "MonoDevelop.LogAgent.ReportCrashes";
const string ReportUsageKey = "MonoDevelop.LogAgent.ReportUsage";
- static List<ILogger> loggers = new List<ILogger> ();
+ static object serviceLock = new object ();
+ static ImmutableList<ILogger> loggers = ImmutableList<ILogger>.Empty;
static RemoteLogger remoteLogger;
static DateTime timestamp;
static int logFileSuffix;
@@ -65,8 +67,8 @@ namespace MonoDevelop.Core
static LoggingService ()
{
var consoleLogger = new ConsoleLogger ();
- loggers.Add (consoleLogger);
- loggers.Add (new InstrumentationLogger ());
+ loggers = loggers.Add (consoleLogger);
+ loggers = loggers.Add (new InstrumentationLogger ());
string consoleLogLevelEnv = Environment.GetEnvironmentVariable ("MONODEVELOP_CONSOLE_LOG_LEVEL");
if (!string.IsNullOrEmpty (consoleLogLevelEnv)) {
@@ -88,7 +90,7 @@ namespace MonoDevelop.Core
if (!string.IsNullOrEmpty (logFileEnv)) {
try {
var fileLogger = new FileLogger (logFileEnv);
- loggers.Add (fileLogger);
+ loggers = loggers.Add (fileLogger);
string logFileLevelEnv = Environment.GetEnvironmentVariable ("MONODEVELOP_FILE_LOG_LEVEL");
fileLogger.EnabledLevel = (EnabledLoggingLevel) Enum.Parse (typeof (EnabledLoggingLevel), logFileLevelEnv, true);
} catch (Exception e) {
@@ -412,17 +414,21 @@ namespace MonoDevelop.Core
public static void AddLogger (ILogger logger)
{
- if (GetLogger (logger.Name) != null)
- throw new Exception ("There is already a logger with the name '" + logger.Name + "'");
- loggers.Add (logger);
+ lock (serviceLock) {
+ if (GetLogger (logger.Name) != null)
+ throw new Exception ("There is already a logger with the name '" + logger.Name + "'");
+ loggers = loggers.Add (logger);
+ }
}
public static void RemoveLogger (string name)
{
- ILogger logger = GetLogger (name);
- if (logger == null)
- throw new Exception ("There is no logger registered with the name '" + name + "'");
- loggers.Remove (logger);
+ lock (serviceLock) {
+ ILogger logger = GetLogger (name);
+ if (logger == null)
+ throw new Exception ("There is no logger registered with the name '" + name + "'");
+ loggers = loggers.Remove (logger);
+ }
}
#endregion
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core/ObjectPool.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core/ObjectPool.cs
new file mode 100644
index 0000000000..2d01f24c08
--- /dev/null
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core/ObjectPool.cs
@@ -0,0 +1,269 @@
+ο»Ώ// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+// define TRACE_LEAKS to get additional diagnostics that can lead to the leak sources. note: it will
+// make everything about 2-3x slower
+//
+// #define TRACE_LEAKS
+
+// define DETECT_LEAKS to detect possible leaks
+// #if DEBUG
+// #define DETECT_LEAKS //for now always enable DETECT_LEAKS in debug.
+// #endif
+
+using System;
+using System.Diagnostics;
+using System.Threading;
+
+#if DETECT_LEAKS
+using System.Runtime.CompilerServices;
+
+#endif
+
+namespace MonoDevelop.Core
+{
+ /// <summary>
+ /// Generic implementation of object pooling pattern with predefined pool size limit. The main
+ /// purpose is that limited number of frequently used objects can be kept in the pool for
+ /// further recycling.
+ ///
+ /// Notes:
+ /// 1) it is not the goal to keep all returned objects. Pool is not meant for storage. If there
+ /// is no space in the pool, extra returned objects will be dropped.
+ ///
+ /// 2) it is implied that if object was obtained from a pool, the caller will return it back in
+ /// a relatively short time. Keeping checked out objects for long durations is ok, but
+ /// reduces usefulness of pooling. Just new up your own.
+ ///
+ /// Not returning objects to the pool in not detrimental to the pool's work, but is a bad practice.
+ /// Rationale:
+ /// If there is no intent for reusing the object, do not use pool - just use "new".
+ /// </summary>
+ internal class ObjectPool<T> where T : class
+ {
+ [DebuggerDisplay ("{Value,nq}")]
+ private struct Element
+ {
+ internal T Value;
+ }
+
+ /// <remarks>
+ /// Not using System.Func{T} because this file is linked into the (debugger) Formatter,
+ /// which does not have that type (since it compiles against .NET 2.0).
+ /// </remarks>
+ internal delegate T Factory ();
+
+ // Storage for the pool objects. The first item is stored in a dedicated field because we
+ // expect to be able to satisfy most requests from it.
+ private T _firstItem;
+ private readonly Element [] _items;
+
+ // factory is stored for the lifetime of the pool. We will call this only when pool needs to
+ // expand. compared to "new T()", Func gives more flexibility to implementers and faster
+ // than "new T()".
+ private readonly Factory _factory;
+
+#if DETECT_LEAKS
+ private static readonly ConditionalWeakTable<T, LeakTracker> leakTrackers = new ConditionalWeakTable<T, LeakTracker>();
+
+ private class LeakTracker : IDisposable
+ {
+ private volatile bool disposed;
+
+#if TRACE_LEAKS
+ internal volatile object Trace = null;
+#endif
+
+ public void Dispose()
+ {
+ disposed = true;
+ GC.SuppressFinalize(this);
+ }
+
+ private string GetTrace()
+ {
+#if TRACE_LEAKS
+ return Trace == null ? "" : Trace.ToString();
+#else
+ return "Leak tracing information is disabled. Define TRACE_LEAKS on ObjectPool`1.cs to get more info \n";
+#endif
+ }
+
+ ~LeakTracker()
+ {
+ if (!this.disposed && !Environment.HasShutdownStarted)
+ {
+ var trace = GetTrace();
+
+ // If you are seeing this message it means that object has been allocated from the pool
+ // and has not been returned back. This is not critical, but turns pool into rather
+ // inefficient kind of "new".
+ Debug.WriteLine($"TRACEOBJECTPOOLLEAKS_BEGIN\nPool detected potential leaking of {typeof(T)}. \n Location of the leak: \n {GetTrace()} TRACEOBJECTPOOLLEAKS_END");
+ }
+ }
+ }
+#endif
+
+ internal ObjectPool (Factory factory)
+ : this (factory, Environment.ProcessorCount * 2)
+ { }
+
+ internal ObjectPool (Factory factory, int size)
+ {
+ Debug.Assert (size >= 1);
+ _factory = factory;
+ _items = new Element [size - 1];
+ }
+
+ private T CreateInstance ()
+ {
+ var inst = _factory ();
+ return inst;
+ }
+
+ /// <summary>
+ /// Produces an instance.
+ /// </summary>
+ /// <remarks>
+ /// Search strategy is a simple linear probing which is chosen for it cache-friendliness.
+ /// Note that Free will try to store recycled objects close to the start thus statistically
+ /// reducing how far we will typically search.
+ /// </remarks>
+ internal T Allocate ()
+ {
+ // PERF: Examine the first element. If that fails, AllocateSlow will look at the remaining elements.
+ // Note that the initial read is optimistically not synchronized. That is intentional.
+ // We will interlock only when we have a candidate. in a worst case we may miss some
+ // recently returned objects. Not a big deal.
+ T inst = _firstItem;
+ if (inst == null || inst != Interlocked.CompareExchange (ref _firstItem, null, inst)) {
+ inst = AllocateSlow ();
+ }
+
+#if DETECT_LEAKS
+ var tracker = new LeakTracker();
+ leakTrackers.Add(inst, tracker);
+
+#if TRACE_LEAKS
+ var frame = CaptureStackTrace();
+ tracker.Trace = frame;
+#endif
+#endif
+ return inst;
+ }
+
+ private T AllocateSlow ()
+ {
+ var items = _items;
+
+ for (int i = 0; i < items.Length; i++) {
+ // Note that the initial read is optimistically not synchronized. That is intentional.
+ // We will interlock only when we have a candidate. in a worst case we may miss some
+ // recently returned objects. Not a big deal.
+ T inst = items [i].Value;
+ if (inst != null) {
+ if (inst == Interlocked.CompareExchange (ref items [i].Value, null, inst)) {
+ return inst;
+ }
+ }
+ }
+
+ return CreateInstance ();
+ }
+
+ /// <summary>
+ /// Returns objects to the pool.
+ /// </summary>
+ /// <remarks>
+ /// Search strategy is a simple linear probing which is chosen for it cache-friendliness.
+ /// Note that Free will try to store recycled objects close to the start thus statistically
+ /// reducing how far we will typically search in Allocate.
+ /// </remarks>
+ internal void Free (T obj)
+ {
+ Validate (obj);
+ ForgetTrackedObject (obj);
+
+ if (_firstItem == null) {
+ // Intentionally not using interlocked here.
+ // In a worst case scenario two objects may be stored into same slot.
+ // It is very unlikely to happen and will only mean that one of the objects will get collected.
+ _firstItem = obj;
+ } else {
+ FreeSlow (obj);
+ }
+ }
+
+ private void FreeSlow (T obj)
+ {
+ var items = _items;
+ for (int i = 0; i < items.Length; i++) {
+ if (items [i].Value == null) {
+ // Intentionally not using interlocked here.
+ // In a worst case scenario two objects may be stored into same slot.
+ // It is very unlikely to happen and will only mean that one of the objects will get collected.
+ items [i].Value = obj;
+ break;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Removes an object from leak tracking.
+ ///
+ /// This is called when an object is returned to the pool. It may also be explicitly
+ /// called if an object allocated from the pool is intentionally not being returned
+ /// to the pool. This can be of use with pooled arrays if the consumer wants to
+ /// return a larger array to the pool than was originally allocated.
+ /// </summary>
+ [Conditional ("DEBUG")]
+ internal void ForgetTrackedObject (T old, T replacement = null)
+ {
+#if DETECT_LEAKS
+ LeakTracker tracker;
+ if (leakTrackers.TryGetValue(old, out tracker))
+ {
+ tracker.Dispose();
+ leakTrackers.Remove(old);
+ }
+ else
+ {
+ var trace = CaptureStackTrace();
+ Debug.WriteLine($"TRACEOBJECTPOOLLEAKS_BEGIN\nObject of type {typeof(T)} was freed, but was not from pool. \n Callstack: \n {trace} TRACEOBJECTPOOLLEAKS_END");
+ }
+
+ if (replacement != null)
+ {
+ tracker = new LeakTracker();
+ leakTrackers.Add(replacement, tracker);
+ }
+#endif
+ }
+
+#if DETECT_LEAKS
+ private static Lazy<Type> _stackTraceType = new Lazy<Type>(() => Type.GetType("System.Diagnostics.StackTrace"));
+
+ private static object CaptureStackTrace()
+ {
+ return Activator.CreateInstance(_stackTraceType.Value);
+ }
+#endif
+
+ [Conditional ("DEBUG")]
+ private void Validate (object obj)
+ {
+ Debug.Assert (obj != null, "freeing null?");
+
+ Debug.Assert (_firstItem != obj, "freeing twice?");
+
+ var items = _items;
+ for (int i = 0; i < items.Length; i++) {
+ var value = items [i].Value;
+ if (value == null) {
+ return;
+ }
+
+ Debug.Assert (value != obj, "freeing twice?");
+ }
+ }
+ }
+}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core/Properties.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core/Properties.cs
index 1f33234b3d..8b18107d45 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core/Properties.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core/Properties.cs
@@ -344,7 +344,7 @@ namespace MonoDevelop.Core
public override string ToString ()
{
- StringBuilder result = new StringBuilder ();
+ StringBuilder result = StringBuilderCache.Allocate ();
result.Append ("[Properties:");
foreach (KeyValuePair<string, object> property in this.properties) {
result.Append (property.Key);
@@ -353,7 +353,7 @@ namespace MonoDevelop.Core
result.Append (",");
}
result.Append ("]");
- return result.ToString ();
+ return StringBuilderCache.ReturnAndFree (result);
}
public Properties Clone ()
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core/PropertyBag.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core/PropertyBag.cs
index 6f306b490d..5af30dff22 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core/PropertyBag.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core/PropertyBag.cs
@@ -246,7 +246,7 @@ namespace MonoDevelop.Core
string EscapeName (string str)
{
- StringBuilder sb = new StringBuilder (str.Length);
+ StringBuilder sb = StringBuilderCache.Allocate ();
for (int n=0; n<str.Length; n++) {
char c = str [n];
if (c == '_')
@@ -259,24 +259,24 @@ namespace MonoDevelop.Core
else
sb.Append (c);
}
- return sb.ToString ();
+ return StringBuilderCache.ReturnAndFree (sb);
}
string UnescapeName (string str)
{
- StringBuilder sb = new StringBuilder (str.Length);
+ StringBuilder sb = StringBuilderCache.Allocate ();
for (int n=0; n<str.Length; n++) {
char c = str [n];
if (c == '_') {
if (n + 1 >= str.Length)
- return sb.ToString ();
+ return StringBuilderCache.ReturnAndFree (sb);
if (str [n + 1] == '_') {
sb.Append (c);
n++;
} else {
int len = int.Parse (str.Substring (n+1,1));
if (n + 2 + len - 1 >= str.Length)
- return sb.ToString ();
+ return StringBuilderCache.ReturnAndFree (sb);
int ic;
if (int.TryParse (str.Substring (n + 2, len), NumberStyles.HexNumber, null, out ic))
sb.Append ((char)ic);
@@ -285,7 +285,7 @@ namespace MonoDevelop.Core
} else
sb.Append (c);
}
- return sb.ToString ();
+ return StringBuilderCache.ReturnAndFree (sb);
}
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core/Runtime.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core/Runtime.cs
index a3d2c63e95..ac941637e6 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core/Runtime.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core/Runtime.cs
@@ -221,7 +221,7 @@ namespace MonoDevelop.Core
Counters.AddinsLoaded.Dec ("Add-in unloaded: " + args.AddinId);
}
- internal static bool Initialized {
+ public static bool Initialized {
get { return initialized; }
}
@@ -417,6 +417,11 @@ namespace MonoDevelop.Core
}
/// <summary>
+ /// The main UI thread of the application. Needed to initialize the JoinableTaskContext.
+ /// </summary>
+ public static Thread MainThread => mainThread;
+
+ /// <summary>
/// Returns true if current thread is GUI thread.
/// </summary>
public static bool IsMainThread
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core/SharedPools.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core/SharedPools.cs
new file mode 100644
index 0000000000..b74dd4a279
--- /dev/null
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core/SharedPools.cs
@@ -0,0 +1,58 @@
+ο»Ώ//
+// StringBuilderCache.cs
+//
+// Author:
+// Mike KrΓΌger <mikkrg@microsoft.com>
+//
+// Copyright (c) 2018 Microsoft Corporation. All rights reserved.
+//
+// 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.
+
+
+namespace MonoDevelop.Core
+{
+ static class SharedPools
+ {
+ /// <summary>
+ /// pool that uses default constructor with 100 elements pooled
+ /// </summary>
+ public static ObjectPool<T> BigDefault<T> () where T : class, new()
+ {
+ return DefaultBigPool<T>.Instance;
+ }
+
+ /// <summary>
+ /// pool that uses default constructor with 20 elements pooled
+ /// </summary>
+ public static ObjectPool<T> Default<T> () where T : class, new()
+ {
+ return DefaultNormalPool<T>.Instance;
+ }
+
+ static class DefaultBigPool<T> where T : class, new()
+ {
+ public static readonly ObjectPool<T> Instance = new ObjectPool<T> (() => new T (), 100);
+ }
+
+ static class DefaultNormalPool<T> where T : class, new()
+ {
+ public static readonly ObjectPool<T> Instance = new ObjectPool<T> (() => new T (), 20);
+ }
+ }
+} \ No newline at end of file
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core/StringBuilderCache.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core/StringBuilderCache.cs
new file mode 100644
index 0000000000..b2957ed843
--- /dev/null
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core/StringBuilderCache.cs
@@ -0,0 +1,65 @@
+ο»Ώ//
+// StringBuilderCache.cs
+//
+// Author:
+// Mike KrΓΌger <mikkrg@microsoft.com>
+//
+// Copyright (c) 2018 Microsoft Corporation. All rights reserved.
+//
+// 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.Text;
+
+namespace MonoDevelop.Core
+{
+ /// <summary>
+ /// This is a pool for storing StringBuilder objects.
+ /// </summary>
+ public static class StringBuilderCache
+ {
+ const int Threshold = 4096;
+
+ public static StringBuilder Allocate ()
+ {
+ var result = SharedPools.Default<StringBuilder> ().Allocate ();
+ result.Clear ();
+ return result;
+ }
+
+ public static StringBuilder Allocate (string text)
+ {
+ return Allocate ().Append (text);
+ }
+
+ public static void Free (StringBuilder sb)
+ {
+ sb.Clear ();
+ if (sb.Capacity > Threshold)
+ sb.Capacity = Threshold;
+ SharedPools.Default<StringBuilder> ().Free (sb);
+ }
+
+ public static string ReturnAndFree (StringBuilder sb)
+ {
+ var result = sb.ToString ();
+ Free (sb);
+ return result;
+ }
+ }
+} \ No newline at end of file
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core/StringParserService.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core/StringParserService.cs
index 77ebc71804..d78ff2f29d 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core/StringParserService.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core/StringParserService.cs
@@ -196,7 +196,7 @@ namespace MonoDevelop.Core
public static string Parse (string input, IStringTagModel customTags)
{
- StringBuilder result = new StringBuilder (input.Length);
+ StringBuilder result = StringBuilderCache.Allocate ();
int brace;
int i = 0;
@@ -225,7 +225,7 @@ namespace MonoDevelop.Core
}
i++;
}
- return result.ToString ();
+ return StringBuilderCache.ReturnAndFree (result);
}
public static IEnumerable<IStringTagProvider> GetProviders ()
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild.Conditions/ConditionParser.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild.Conditions/ConditionParser.cs
index 65cc6cbfa4..98f58747ae 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild.Conditions/ConditionParser.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild.Conditions/ConditionParser.cs
@@ -257,7 +257,7 @@ namespace MonoDevelop.Projects.MSBuild.Conditions {
if (tokenizer.IsEOF ())
throw new ExpressionParseException ("Missing closing parenthesis in condition " + conditionStr);
- StringBuilder sb = new StringBuilder ();
+ StringBuilder sb = Core.StringBuilderCache.Allocate ();
sb.AppendFormat ("{0}({1}", prefix, tokenizer.Token.Value);
tokenizer.GetNextToken ();
@@ -280,7 +280,7 @@ namespace MonoDevelop.Projects.MSBuild.Conditions {
sb.Append (")");
//FIXME: HACKY!
- return new ConditionFactorExpression (new Token (sb.ToString (), TokenType.String, token_pos));
+ return new ConditionFactorExpression (new Token (Core.StringBuilderCache.ReturnAndFree (sb), TokenType.String, token_pos));
}
void ThrowParseException(TokenType type, string error_fmt, params object[] args)
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/DefaultMSBuildEngine.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/DefaultMSBuildEngine.cs
index e5e9a05e5c..90adb3c67b 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/DefaultMSBuildEngine.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/DefaultMSBuildEngine.cs
@@ -64,6 +64,7 @@ namespace MonoDevelop.Projects.MSBuild
public Dictionary<MSBuildImport, List<ProjectInfo>> ImportedProjects = new Dictionary<MSBuildImport, List<ProjectInfo>> ();
public ConditionedPropertyCollection ConditionedProperties = new ConditionedPropertyCollection ();
public List<GlobInfo> GlobIncludes = new List<GlobInfo> ();
+ public bool OnlyEvaluateProperties;
public MSBuildProject GetRootMSBuildProject ()
{
@@ -182,6 +183,11 @@ namespace MonoDevelop.Projects.MSBuild
public override void Evaluate (object projectInstance)
{
+ Evaluate (projectInstance, false);
+ }
+
+ public override void Evaluate (object projectInstance, bool onlyEvaluateProperties)
+ {
var pi = (ProjectInfo) projectInstance;
pi.EvaluatedItemsIgnoringCondition.Clear ();
@@ -190,6 +196,7 @@ namespace MonoDevelop.Projects.MSBuild
pi.Imports.Clear ();
pi.Targets.Clear ();
pi.TargetsIgnoringCondition.Clear ();
+ pi.OnlyEvaluateProperties = onlyEvaluateProperties;
// Unload referenced projects after evaluating to avoid unnecessary unload + load
var oldRefProjects = pi.ReferencedProjects;
@@ -248,13 +255,15 @@ namespace MonoDevelop.Projects.MSBuild
LogEndEvalProject (context, pi);
LogEndEvaluationStage (context);
- LogBeginEvaluationStage (context, "Evaluating Items");
- LogBeginEvalProject (context, pi);
+ if (!pi.OnlyEvaluateProperties) {
+ LogBeginEvaluationStage (context, "Evaluating Items");
+ LogBeginEvalProject (context, pi);
- EvaluateObjects (pi, context, objects, true);
+ EvaluateObjects (pi, context, objects, true);
- LogEndEvalProject (context, pi);
- LogEndEvaluationStage (context);
+ LogEndEvalProject (context, pi);
+ LogEndEvaluationStage (context);
+ }
// Once items have been evaluated, we need to re-evaluate properties that contain item transformations
// (or that contain references to properties that have transformations).
@@ -489,11 +498,14 @@ namespace MonoDevelop.Projects.MSBuild
static void AddRemoveToGlobInclude (ProjectInfo project, MSBuildItem item, string remove)
{
var exclude = ExcludeToRegex (remove);
- foreach (var globInclude in project.GlobIncludes.Where (g => g.Item.Name == item.Name)) {
- if (globInclude.RemoveRegex != null)
- exclude = globInclude.RemoveRegex + "|" + exclude;
- globInclude.RemoveRegex = new Regex (exclude);
- }
+ do {
+ foreach (var globInclude in project.GlobIncludes.Where (g => g.Item.Name == item.Name)) {
+ if (globInclude.RemoveRegex != null)
+ exclude = globInclude.RemoveRegex + "|" + exclude;
+ globInclude.RemoveRegex = new Regex (exclude);
+ }
+ project = project.Parent;
+ } while (project != null);
}
static void RemoveEvaluatedItemFromAllProjects (ProjectInfo project, MSBuildItem item, string include, bool trueCond)
@@ -645,18 +657,18 @@ namespace MonoDevelop.Projects.MSBuild
items = result;
return true;
} else if (ExecuteTransformItemListFunction (ref transformItems, itemFunction, itemFunctionArgs, out ignoreMetadata)) {
- var sb = new StringBuilder ();
+ var sb = StringBuilderCache.Allocate ();
for (int n = 0; n < transformItems.Length; n++) {
if (n > 0)
sb.Append (';');
sb.Append (transformItems[n].Include);
}
- items = sb.ToString ();
+ items = StringBuilderCache.ReturnAndFree (sb);
return true;
}
}
- var sbi = new StringBuilder ();
+ var sbi = StringBuilderCache.Allocate ();
int count = 0;
foreach (var eit in transformItems) {
@@ -678,7 +690,7 @@ namespace MonoDevelop.Projects.MSBuild
context.ClearItemContext ();
}
}
- items = sbi.ToString ();
+ items = Core.StringBuilderCache.ReturnAndFree (sbi);
return true;
}
@@ -943,7 +955,7 @@ namespace MonoDevelop.Projects.MSBuild
static string ExcludeToRegex (string exclude, bool excludeDirectoriesOnly = false)
{
exclude = exclude.Replace ('/', '\\').Replace (@"\\", @"\");
- var sb = new StringBuilder ();
+ var sb = StringBuilderCache.Allocate ();
foreach (var ep in exclude.Split (new char [] { ';' }, StringSplitOptions.RemoveEmptyEntries)) {
var ex = ep.Trim ();
if (excludeDirectoriesOnly) {
@@ -977,7 +989,7 @@ namespace MonoDevelop.Projects.MSBuild
}
sb.Append ('$');
}
- return sb.ToString ();
+ return Core.StringBuilderCache.ReturnAndFree (sb);
}
static char [] regexEscapeChars = { '\\', '^', '$', '{', '}', '[', ']', '(', ')', '.', '*', '+', '?', '|', '<', '>', '-', '&' };
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/EscapingUtilities.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/EscapingUtilities.cs
index 94a180f36d..803ff6df8a 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/EscapingUtilities.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/EscapingUtilities.cs
@@ -5,7 +5,8 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
-
+using MonoDevelop.Core;
+
namespace Microsoft.Build.Shared
{
/// <summary>
@@ -70,7 +71,7 @@ namespace Microsoft.Build.Shared
}
// This is where we're going to build up the final string to return to the caller.
- StringBuilder unescapedString = new StringBuilder (escapedString.Length);
+ StringBuilder unescapedString = StringBuilderCache.Allocate ();
int currentPosition = 0;
@@ -112,7 +113,7 @@ namespace Microsoft.Build.Shared
// characters into the destination.
unescapedString.Append(escapedString, currentPosition, escapedString.Length - currentPosition);
- return unescapedString.ToString ();
+ return StringBuilderCache.ReturnAndFree (unescapedString);
}
@@ -172,16 +173,16 @@ namespace Microsoft.Build.Shared
}
// This is where we're going to build up the final string to return to the caller.
- StringBuilder escapedStringBuilder = new StringBuilder (unescapedString.Length * 2);
+ StringBuilder escapedStringBuilder = StringBuilderCache.Allocate ();
AppendEscapedString(escapedStringBuilder, unescapedString);
if (!cache)
{
- return escapedStringBuilder.ToString ();
+ return StringBuilderCache.ReturnAndFree (escapedStringBuilder);
}
- string escapedString = escapedStringBuilder.ToString ();
+ string escapedString = StringBuilderCache.ReturnAndFree (escapedStringBuilder);
lock (s_unescapedToEscapedStrings)
{
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/IMSBuildPropertySet.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/IMSBuildPropertySet.cs
index 76e96caa7b..73990668a0 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/IMSBuildPropertySet.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/IMSBuildPropertySet.cs
@@ -228,7 +228,7 @@ namespace MonoDevelop.Projects.MSBuild
int i = val.IndexOfAny (new char[] {'\n','\r','\t'});
if (i != -1 || val [0] == '@') {
- StringBuilder sb = new StringBuilder ();
+ StringBuilder sb = StringBuilderCache.Allocate ();
if (i != -1) {
int fi = val.IndexOf ('\\');
if (fi != -1 && fi < i) i = fi;
@@ -248,7 +248,7 @@ namespace MonoDevelop.Projects.MSBuild
else
sb.Append (c);
}
- val = "@" + sb.ToString ();
+ val = "@" + StringBuilderCache.ReturnAndFree (sb);
}
char fc = val [0];
char lc = val [val.Length - 1];
@@ -283,7 +283,7 @@ namespace MonoDevelop.Projects.MSBuild
end--;
}
if (val [start] == '@') {
- StringBuilder sb = new StringBuilder (val.Length);
+ StringBuilder sb = StringBuilderCache.Allocate ();
for (int n = start + 1; n < end; n++) {
char c = val [n];
if (c == '\\') {
@@ -294,7 +294,7 @@ namespace MonoDevelop.Projects.MSBuild
}
sb.Append (c);
}
- return sb.ToString ();
+ return StringBuilderCache.ReturnAndFree (sb);
}
else
return val.Substring (start, end - start);
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildEngine.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildEngine.cs
index 60cd785242..2e1ca86a37 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildEngine.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildEngine.cs
@@ -68,6 +68,10 @@ namespace MonoDevelop.Projects.MSBuild
{
}
+ public virtual void Evaluate (object projectInstance, bool onlyEvaluateProperties)
+ {
+ }
+
public abstract bool GetItemHasMetadata (object item, string name);
public abstract string GetItemMetadata (object item, string name);
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildEvaluationContext.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildEvaluationContext.cs
index 807075f2e0..7afbf74a5e 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildEvaluationContext.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildEvaluationContext.cs
@@ -841,9 +841,9 @@ namespace MonoDevelop.Projects.MSBuild
if (sval != null && parameterType.IsEnum) {
var enumValue = sval;
- if (enumValue.StartsWith (parameterType.Name))
+ if (enumValue.StartsWith (parameterType.Name, StringComparison.Ordinal))
enumValue = enumValue.Substring (parameterType.Name.Length + 1);
- if (enumValue.StartsWith (parameterType.FullName))
+ if (enumValue.StartsWith (parameterType.FullName, StringComparison.Ordinal))
enumValue = enumValue.Substring (parameterType.FullName.Length + 1);
return Enum.Parse(parameterType, enumValue, ignoreCase: true);
}
@@ -854,9 +854,12 @@ namespace MonoDevelop.Projects.MSBuild
var res = Convert.ChangeType (value, parameterType, CultureInfo.InvariantCulture);
bool convertPath = false;
- if ((method.DeclaringType == typeof (System.IO.File) || method.DeclaringType == typeof (System.IO.Directory)) && argNum == 0) {
+ if ((method.DeclaringType == typeof (System.IO.File) || method.DeclaringType == typeof (System.IO.Directory)) && argNum == 0)
convertPath = true;
- } else if (method.DeclaringType == typeof (IntrinsicFunctions)) {
+ else if (method.DeclaringType == typeof (System.IO.Path))
+ // The windows path is already converted to a native path, but it may contain escape sequences
+ res = MSBuildProjectService.UnescapePath ((string)res);
+ else if (method.DeclaringType == typeof (IntrinsicFunctions)) {
if (method.Name == "MakeRelative")
convertPath = true;
else if (method.Name == "GetDirectoryNameOfFileAbove" && argNum == 0)
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildImport.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildImport.cs
index d2efb3d97d..80dadba4be 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildImport.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildImport.cs
@@ -68,12 +68,18 @@ namespace MonoDevelop.Projects.MSBuild
public string Project {
get { return target; }
- set { AssertCanModify (); target = value; NotifyChanged (); }
+ set { AssertCanModify (); target = value; NotifyImportChanged (); }
}
public string Sdk {
get { return sdk; }
- set { AssertCanModify (); sdk = value; NotifyChanged (); }
+ set { AssertCanModify (); sdk = value; NotifyImportChanged (); }
+ }
+
+ void NotifyImportChanged ()
+ {
+ if (ParentProject != null)
+ ParentProject.NotifyImportChanged ();
}
internal override void Write (XmlWriter writer, WriteContext context)
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildProject.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildProject.cs
index 72c36e7b45..54bb12b055 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildProject.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildProject.cs
@@ -432,6 +432,18 @@ namespace MonoDevelop.Projects.MSBuild
changeStamp++;
}
+ internal void NotifyImportChanged ()
+ {
+ NotifyChanged ();
+
+ ImportChanged?.Invoke (this, EventArgs.Empty);
+ }
+
+ /// <summary>
+ /// Occurs when an import has changed, is added or removed.
+ /// </summary>
+ internal event EventHandler ImportChanged;
+
/// <summary>
/// Gets or sets a value indicating whether this project uses the msbuild engine for evaluation.
/// </summary>
@@ -465,7 +477,7 @@ namespace MonoDevelop.Projects.MSBuild
object readLock = new object ();
- internal MSBuildProjectInstanceInfo LoadNativeInstance ()
+ internal MSBuildProjectInstanceInfo LoadNativeInstance (bool evaluateItems)
{
lock (readLock) {
var supportsMSBuild = UseMSBuildEngine && GetGlobalPropertyGroup ().GetValue ("UseMSBuildEngine", true);
@@ -502,8 +514,10 @@ namespace MonoDevelop.Projects.MSBuild
};
var xml = SaveToString (ctx);
- foreach (var it in GetAllItems ())
- it.EvaluatedItemCount = 0;
+ if (evaluateItems) {
+ foreach (var it in GetAllItems ())
+ it.EvaluatedItemCount = 0;
+ }
nativeProjectInfo.Project = e.LoadProject (this, xml, FileName);
} catch (Exception ex) {
@@ -613,7 +627,7 @@ namespace MonoDevelop.Projects.MSBuild
ChildNodes = ChildNodes.Add (import);
import.ResetIndent (false);
- NotifyChanged ();
+ NotifyImportChanged ();
return import;
}
@@ -629,7 +643,7 @@ namespace MonoDevelop.Projects.MSBuild
if (i != null) {
i.RemoveIndent ();
ChildNodes = ChildNodes.Remove (i);
- NotifyChanged ();
+ NotifyImportChanged ();
}
}
@@ -642,7 +656,7 @@ namespace MonoDevelop.Projects.MSBuild
if (import.ParentObject == this) {
import.RemoveIndent ();
ChildNodes = ChildNodes.Remove (import);
- NotifyChanged ();
+ NotifyImportChanged ();
} else
((MSBuildImportGroup)import.ParentObject).RemoveImport (import);
}
@@ -1152,7 +1166,7 @@ namespace MonoDevelop.Projects.MSBuild
if (elem == null)
return "";
var node = elem.PreviousSibling;
- StringBuilder res = new StringBuilder ();
+ StringBuilder res = StringBuilderCache.Allocate ();
while (node != null) {
var ws = node as XmlWhitespace;
@@ -1163,13 +1177,13 @@ namespace MonoDevelop.Projects.MSBuild
res.Append (t);
} else {
res.Append (t, i + 1, t.Length - i - 1);
- return res.ToString ();
+ return StringBuilderCache.ReturnAndFree (res);
}
} else
res.Clear ();
node = node.PreviousSibling;
}
- return res.ToString ();
+ return StringBuilderCache.ReturnAndFree (res);
}
public static void Indent (TextFormatInfo format, XmlElement elem, bool closeInNewLine)
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildProjectInstance.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildProjectInstance.cs
index d470fbe8ff..73ddbe648a 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildProjectInstance.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildProjectInstance.cs
@@ -87,7 +87,7 @@ namespace MonoDevelop.Projects.MSBuild
if (projectInstance != null)
engine.DisposeProjectInstance (projectInstance);
- info = msproject.LoadNativeInstance ();
+ info = msproject.LoadNativeInstance (!OnlyEvaluateProperties);
engine = info.Engine;
projectInstance = engine.CreateProjectInstance (info.Project);
@@ -103,7 +103,7 @@ namespace MonoDevelop.Projects.MSBuild
foreach (var prop in globalProperties)
engine.SetGlobalProperty (projectInstance, prop.Key, prop.Value);
- engine.Evaluate (projectInstance);
+ engine.Evaluate (projectInstance, OnlyEvaluateProperties);
SyncBuildProject (info.ItemMap, info.Engine, projectInstance);
} catch (Exception ex) {
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/RemoteBuildEngineManager.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/RemoteBuildEngineManager.cs
index ea8f0b4273..15dab944b7 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/RemoteBuildEngineManager.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/RemoteBuildEngineManager.cs
@@ -1,4 +1,4 @@
-ο»Ώ//
+//
// RemoteBuildEngineManager.cs
//
// Author:
@@ -77,6 +77,7 @@ namespace MonoDevelop.Projects.MSBuild
static bool searchPathConfigNeedsUpdate;
static AsyncCriticalSection buildersLock = new AsyncCriticalSection ();
static BuilderCache builders = new BuilderCache ();
+ static bool shutDown;
internal static int EngineDisposalDelay = 60000;
@@ -97,6 +98,27 @@ namespace MonoDevelop.Projects.MSBuild
searchPathConfigNeedsUpdate = true;
RecycleAllBuilders ().Ignore ();
};
+ Runtime.ShuttingDown += Shutdown;
+ }
+
+ static async void Shutdown (object s, EventArgs a)
+ {
+ using (await buildersLock.EnterAsync ().ConfigureAwait (false)) {
+ shutDown = true;
+ foreach (var engine in builders.GetAllBuilders ().ToList ()) {
+ // Signal all project builder of the engine to stop
+ engine.Shutdown ();
+ engine.CancelScheduledDisposal ();
+ builders.Remove (engine);
+ engine.DisposeGracefully ();
+ }
+ }
+ }
+
+ static void CheckShutDown ()
+ {
+ if (shutDown)
+ throw new InvalidOperationException ("Runtime is shut down");
}
internal static int ActiveEnginesCount => builders.GetAllBuilders ().Where (b => !b.IsShuttingDown).Count ();
@@ -127,6 +149,8 @@ namespace MonoDevelop.Projects.MSBuild
/// </remarks>
public async static Task<IRemoteProjectBuilder> GetRemoteProjectBuilder (string projectFile, string solutionFile, TargetRuntime runtime, string minToolsVersion, bool requiresMicrosoftBuild, object buildSessionId, bool setBusy = false, bool allowBusy = true)
{
+ CheckShutDown ();
+
RemoteBuildEngine engine;
using (await buildersLock.EnterAsync ().ConfigureAwait (false)) {
// Get a builder with the provided requirements
@@ -270,6 +294,7 @@ namespace MonoDevelop.Projects.MSBuild
{
List<RemoteBuildEngine> projectBuilders;
using (await buildersLock.EnterAsync ().ConfigureAwait (false)) {
+ if (shutDown) return;
projectBuilders = builders.GetAllBuilders ().Where (b => b.IsProjectLoaded (projectFile)).ToList ();
}
foreach (var b in projectBuilders)
@@ -282,6 +307,7 @@ namespace MonoDevelop.Projects.MSBuild
public static async Task UnloadSolution (string solutionFile)
{
using (await buildersLock.EnterAsync ().ConfigureAwait (false)) {
+ if (shutDown) return;
foreach (var engine in builders.GetAllBuilders ().Where (b => b.SolutionFile == solutionFile).ToList ())
ShutdownBuilderNoLock (engine);
}
@@ -294,6 +320,7 @@ namespace MonoDevelop.Projects.MSBuild
{
List<RemoteBuildEngine> projectBuilders;
using (await buildersLock.EnterAsync ().ConfigureAwait (false)) {
+ if (shutDown) return;
projectBuilders = builders.GetAllBuilders ().Where (b => b.IsProjectLoaded (projectFile)).ToList ();
}
foreach (var b in projectBuilders)
@@ -307,6 +334,7 @@ namespace MonoDevelop.Projects.MSBuild
{
List<RemoteBuildEngine> projectBuilders;
using (await buildersLock.EnterAsync ().ConfigureAwait (false)) {
+ if (shutDown) return;
projectBuilders = builders.GetAllBuilders ().Where (b => b.IsProjectLoaded (projectFile)).ToList ();
}
foreach (var b in projectBuilders)
@@ -325,6 +353,7 @@ namespace MonoDevelop.Projects.MSBuild
public static async Task RecycleAllBuilders ()
{
using (await buildersLock.EnterAsync ().ConfigureAwait (false)) {
+ if (shutDown) return;
foreach (var b in builders.GetAllBuilders ().ToList ())
ShutdownBuilderNoLock (b);
}
@@ -338,6 +367,7 @@ namespace MonoDevelop.Projects.MSBuild
/// <param name="verbosity">MSBuild verbosity.</param>
internal static object StartBuildSession (TextWriter tw, MSBuildLogger logger, MSBuildVerbosity verbosity, ProjectConfigurationInfo[] configurations)
{
+ CheckShutDown ();
return new SessionInfo {
Writer = tw,
Verbosity = verbosity,
@@ -354,6 +384,7 @@ namespace MonoDevelop.Projects.MSBuild
internal static async Task EndBuildSession (object session)
{
using (await buildersLock.EnterAsync ().ConfigureAwait (false)) {
+ if (shutDown) return;
foreach (var b in builders.GetAllBuilders ())
if (b.BuildSessionId == session) {
b.BuildSessionId = null;
@@ -367,6 +398,7 @@ namespace MonoDevelop.Projects.MSBuild
// Update the global properties in all builders
using (await buildersLock.EnterAsync ().ConfigureAwait (false)) {
+ if (shutDown) return;
var gpp = (IMSBuildGlobalPropertyProvider)sender;
foreach (var builder in builders.GetAllBuilders ())
await builder.SetGlobalProperties (new Dictionary<string, string> (gpp.GetGlobalProperties ()));
@@ -609,12 +641,12 @@ namespace MonoDevelop.Projects.MSBuild
spid = spid.Substring (0, i);
int pid;
if (int.TryParse (Path.GetFileName (spid), out pid)) {
- try {
- // If there is a process running with this id it means the builder is still being used
- if (Process.GetProcessById (pid) != null)
+ try {
+ // If there is a process running with this id it means the builder is still being used
+ if (Process.GetProcessById (pid) != null)
continue;
} catch {
- // Ignore
+ // Ignore
}
// No process for this id, it should be safe to delete the folder
try {
@@ -649,6 +681,8 @@ namespace MonoDevelop.Projects.MSBuild
static Task ReleaseProjectBuilderNoLock (RemoteBuildEngine engine)
{
+ if (shutDown)
+ return Task.CompletedTask;
if (--engine.ReferenceCount != 0)
return Task.CompletedTask;
if (engine.IsShuttingDown) {
@@ -674,6 +708,5 @@ namespace MonoDevelop.Projects.MSBuild
}
return Task.CompletedTask;
}
-
}
} \ No newline at end of file
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 46768a95f0..6b0b36c660 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/SdkResolution.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/SdkResolution.cs
@@ -115,7 +115,7 @@ namespace MonoDevelop.Projects.MSBuild
resolvers.AddRange (assembly.ExportedTypes
.Select (type => new { type, info = type.GetTypeInfo () })
- .Where (t => t.info.IsClass && t.info.IsPublic && typeof (SdkResolver).IsAssignableFrom (t.type))
+ .Where (t => t.info.IsClass && t.info.IsPublic && !t.info.IsAbstract && typeof (SdkResolver).IsAssignableFrom (t.type))
.Select (t => (SdkResolver)Activator.CreateInstance (t.type)));
} catch (Exception e) {
logger.LogWarning (e.Message);
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Policies/PolicyService.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Policies/PolicyService.cs
index 72e2c2df70..57e57f7ada 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Policies/PolicyService.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Policies/PolicyService.cs
@@ -530,7 +530,7 @@ namespace MonoDevelop.Projects.Policies
}
}
- StringBuilder removed = new StringBuilder ();
+ StringBuilder removed = StringBuilderCache.Allocate ();
for (int n=0; n<baseline.ItemData.Count; n++) {
DataNode node = baseline.ItemData [n];
if (!extracted.Contains (node)) {
@@ -545,6 +545,7 @@ namespace MonoDevelop.Projects.Policies
if (removed.Length > 0)
newItem.ItemData.Add (new DataValue ("__removed", removed.ToString ()) {StoreAsAttribute = true});
+ StringBuilderCache.Free (removed);
return newItem;
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Text/TextFormatter.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Text/TextFormatter.cs
index cc1f54ac19..bae1958b4b 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Text/TextFormatter.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Text/TextFormatter.cs
@@ -26,6 +26,7 @@
using System;
using System.Text;
+using MonoDevelop.Core;
namespace MonoDevelop.Projects.Text
{
@@ -343,17 +344,17 @@ namespace MonoDevelop.Projects.Text
void CreateIndentString ()
{
- StringBuilder sb = new StringBuilder ();
+ StringBuilder sb = StringBuilderCache.Allocate ();
indentColumnWidth = AddIndentString (sb, indentString);
-
- paragFormattedIndentString = sb.ToString () + new string (' ', paragraphStartMargin);
+ sb.Append (new string (' ', paragraphStartMargin));
+ paragFormattedIndentString = sb.ToString ();
paragIndentColumnWidth = indentColumnWidth + paragraphStartMargin;
if (LeftMargin > 0) {
sb.Append (' ', LeftMargin);
indentColumnWidth += LeftMargin;
}
- formattedIndentString = sb.ToString ();
+ formattedIndentString = StringBuilderCache.ReturnAndFree (sb);
if (paragraphStart)
curCol = paragIndentColumnWidth;
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProject.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProject.cs
index 9dee0e5bc1..07b2ca1735 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProject.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/DotNetProject.cs
@@ -1084,6 +1084,11 @@ namespace MonoDevelop.Projects
if (result == null)
return new List<PackageDependency> ();
+ if (monitor.CancellationToken.IsCancellationRequested && !result.Items.Any ()) {
+ // Avoid caching 0 items which can happen if a cancellation occurs.
+ return new List<PackageDependency> ();
+ }
+
packageDependencies = result.Items.Select (i => PackageDependency.Create (i)).Where (dependency => dependency != null).ToList ();
packageDependenciesCache = packageDependenciesCache .SetItem (confId, packageDependencies);
@@ -1571,17 +1576,17 @@ namespace MonoDevelop.Projects
static string GetHierarchicalNamespace (string relativePath)
{
- StringBuilder sb = new StringBuilder (relativePath);
+ StringBuilder sb = StringBuilderCache.Allocate (relativePath);
for (int i = 0; i < sb.Length; i++) {
if (sb[i] == Path.DirectorySeparatorChar)
sb[i] = '.';
}
- return sb.ToString ();
+ return StringBuilderCache.ReturnAndFree (sb);
}
static string SanitisePotentialNamespace (string potential)
{
- StringBuilder sb = new StringBuilder ();
+ StringBuilder sb = StringBuilderCache.Allocate ();
foreach (char c in potential) {
if (char.IsLetter (c) || c == '_' || (sb.Length > 0 && (char.IsLetterOrDigit (sb[sb.Length - 1]) || sb[sb.Length - 1] == '_') && (c == '.' || char.IsNumber (c)))) {
sb.Append (c);
@@ -1591,9 +1596,10 @@ namespace MonoDevelop.Projects
if (sb[sb.Length - 1] == '.')
sb.Remove (sb.Length - 1, 1);
- return sb.ToString ();
- } else
- return null;
+ return StringBuilderCache.ReturnAndFree (sb);
+ }
+ StringBuilderCache.Free (sb);
+ return null;
}
void RuntimeSystemAssemblyServiceDefaultRuntimeChanged (object sender, EventArgs e)
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ItemCollection.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ItemCollection.cs
index cad57828ac..c978c93e41 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ItemCollection.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ItemCollection.cs
@@ -86,6 +86,17 @@ namespace MonoDevelop.Projects
OnItemsRemoved (removedItems);
}
+ internal void SetItems (IEnumerable<T> items, IEnumerable<T> newItems, IEnumerable<T> removedItems)
+ {
+ AssertCanWrite ();
+
+ list = ImmutableList<T>.Empty.AddRange (items);
+ if (newItems.Any ())
+ OnItemsAdded (newItems);
+ if (removedItems.Any ())
+ OnItemsRemoved (removedItems);
+ }
+
IEnumerable<T> ReuseExistingItems (IEnumerable<T> items)
{
var updatedItems = new List<T> ();
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/MonoExecutionParameters.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/MonoExecutionParameters.cs
index b37e4343d6..f172182f44 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/MonoExecutionParameters.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/MonoExecutionParameters.cs
@@ -269,7 +269,7 @@ namespace MonoDevelop.Projects
public string GenerateDescription ()
{
- StringBuilder ops = new StringBuilder ();
+ StringBuilder ops = StringBuilderCache.Allocate ();
foreach (var kvp in itemPropertyAttributes) {
var prop = kvp.Key;
@@ -286,7 +286,7 @@ namespace MonoDevelop.Projects
ops.Append (": ").Append (GetValue (pval));
}
}
- return ops.ToString ();
+ return StringBuilderCache.ReturnAndFree (ops);
}
public MonoExecutionParameters Clone ()
{
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs
index 210b33befb..ff4e9112c5 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs
@@ -556,8 +556,29 @@ namespace MonoDevelop.Projects
return results.ToArray ();
}
+ /// <summary>
+ /// When the MSBuild imports in a project change we need to let the type system know so
+ /// it can update its source files. A NuGet package may contain only MSBuild targets
+ /// which modify the CoreCompileDependsOn property. Just having the MSBuild targets
+ /// file in the NuGet package will not trigger any notifications that the type system
+ /// is monitoring so here we trigger a Files notification.
+ /// </summary>
+ void OnMSBuildProjectImportChanged (object sender, EventArgs args)
+ {
+ lock (evaluatedCompileItemsLock) {
+ // Do not re-evaluate if the compile items have never been evaluated.
+ if (evaluatedCompileItemsTask != null)
+ reevaluateCoreCompileDependsOn = true;
+ }
+
+ Runtime.RunInMainThread (() => {
+ NotifyModified ("Files");
+ }).Ignore ();
+ }
+
object evaluatedCompileItemsLock = new object ();
string evaluatedCompileItemsConfiguration;
+ bool reevaluateCoreCompileDependsOn;
TaskCompletionSource<ProjectFile[]> evaluatedCompileItemsTask;
/// <summary>
@@ -573,17 +594,26 @@ namespace MonoDevelop.Projects
TaskCompletionSource<ProjectFile []> currentTask = null;
bool startTask = false;
+ bool reevaluate = false;
lock (evaluatedCompileItemsLock) {
- if (evaluatedCompileItemsConfiguration != config.Id) {
+
+ if (evaluatedCompileItemsConfiguration != config.Id || reevaluateCoreCompileDependsOn) {
// The configuration changed or query not yet done
evaluatedCompileItemsConfiguration = config.Id;
evaluatedCompileItemsTask = new TaskCompletionSource<ProjectFile []> ();
startTask = true;
+ reevaluate = reevaluateCoreCompileDependsOn;
+ reevaluateCoreCompileDependsOn = false;
}
currentTask = evaluatedCompileItemsTask;
}
+ if (reevaluate) {
+ // Ensure CoreCompileDependsOn is up to date.
+ await ReevaluateProject (monitor, resetCachedCompileItems: false);
+ }
+
if (startTask) {
var coreCompileDependsOn = sourceProject.EvaluatedProperties.GetValue<string> ("CoreCompileDependsOn");
@@ -620,6 +650,7 @@ namespace MonoDevelop.Projects
{
lock (evaluatedCompileItemsLock) {
evaluatedCompileItemsConfiguration = null;
+ reevaluateCoreCompileDependsOn = false;
}
}
@@ -694,6 +725,9 @@ namespace MonoDevelop.Projects
ProjectOpenedCounter.Inc (1, null, GetProjectEventMetadata (null));
+ if (sourceProject != null)
+ sourceProject.ImportChanged += OnMSBuildProjectImportChanged;
+
InitializeFileWatcher ();
}
@@ -956,6 +990,12 @@ namespace MonoDevelop.Projects
if (buildActions != null)
return buildActions;
+ buildActions = GetBuildActions (predicate: null);
+ return buildActions;
+ }
+
+ string[] GetBuildActions (Predicate<string> predicate)
+ {
// find all the actions in use and add them to the list of standard actions
HashSet<string> actions = new HashSet<string> ();
//ad the standard actions
@@ -972,6 +1012,9 @@ namespace MonoDevelop.Projects
if (actions.Contains (action))
actions.Remove (action);
+ if (predicate != null)
+ commonActions = commonActions.Where (action => predicate (action)).ToList ();
+
//calculate dimensions for our new array and create it
int dashPos = commonActions.Count;
bool hasDash = commonActions.Count > 0 && actions.Count > 0;
@@ -979,7 +1022,7 @@ namespace MonoDevelop.Projects
int uncommonStart = hasDash ? dashPos + 1 : dashPos;
if (hasDash)
arrayLen++;
- buildActions = new string[arrayLen];
+ var buildActions = new string[arrayLen];
//populate it
if (commonActions.Count > 0)
@@ -999,6 +1042,18 @@ namespace MonoDevelop.Projects
}
return buildActions;
}
+
+ /// <summary>
+ /// Gets a list of build actions supported by this project for the file.
+ /// </summary>
+ /// <remarks>
+ /// Common actions are grouped at the top, separated by a "--" entry *IF* there are
+ /// "uncommon" actions and "common" actions
+ /// </remarks>
+ public string[] GetBuildActions (string fileName)
+ {
+ return GetBuildActions (buildAction => ProjectExtension.OnGetFileSupportsBuildAction (fileName, buildAction));
+ }
/// <summary>
/// Gets a list of standard build actions.
@@ -1016,6 +1071,11 @@ namespace MonoDevelop.Projects
return BuildAction.StandardActions;
}
+ protected virtual bool OnGetFileSupportsBuildAction (string fileName, string buildAction)
+ {
+ return true;
+ }
+
protected override void OnDispose ()
{
DisposeFileWatcher ();
@@ -1033,6 +1093,7 @@ namespace MonoDevelop.Projects
RemoteBuildEngineManager.UnloadProject (FileName).Ignore ();
if (sourceProject != null) {
+ sourceProject.ImportChanged -= OnMSBuildProjectImportChanged;
sourceProject.Dispose ();
sourceProject = null;
}
@@ -1584,6 +1645,12 @@ namespace MonoDevelop.Projects
}
}
+ ProjectFile newFile = CreateProjectFileForGlobItem (filename, buildAction);
+ if (newFile != null) {
+ Files.Add (newFile);
+ return newFile;
+ }
+
if (String.IsNullOrEmpty (buildAction)) {
buildAction = GetDefaultBuildAction (filename);
}
@@ -1597,6 +1664,12 @@ namespace MonoDevelop.Projects
{
List<ProjectFile> newFiles = new List<ProjectFile> ();
foreach (FilePath filename in files) {
+ ProjectFile newFile = CreateProjectFileForGlobItem (filename, buildAction);
+ if (newFile != null) {
+ newFiles.Add (newFile);
+ continue;
+ }
+
string ba = buildAction;
if (String.IsNullOrEmpty (ba))
ba = GetDefaultBuildAction (filename);
@@ -1607,6 +1680,31 @@ namespace MonoDevelop.Projects
Files.AddRange (newFiles);
return newFiles;
}
+
+ /// <summary>
+ /// Imported glob item may define a different build action and metadata for a file
+ /// so this is read and applied to the new ProjectFile.
+ /// </summary>
+ ProjectFile CreateProjectFileForGlobItem (FilePath file, string buildAction)
+ {
+ if (!UseAdvancedGlobSupport)
+ return null;
+
+ var include = MSBuildProjectService.ToMSBuildPath (ItemDirectory, file);
+ var globItems = sourceProject.FindGlobItemsIncludingFile (include).ToList ();
+ if ((globItems.Count == 1) && (buildAction == null || globItems [0].Name == buildAction)) {
+ var eit = CreateFakeEvaluatedItem (sourceProject, globItems [0], include, null);
+ var projectFile = CreateProjectItem (eit) as ProjectFile;
+ if (projectFile != null) {
+ projectFile.Read (this, eit);
+ // Force UnevaluatedInclude to be reset to prevent Remove items
+ // being left in project after file is re-added.
+ projectFile.BackingItem = null;
+ return projectFile;
+ }
+ }
+ return null;
+ }
/// <summary>
/// Adds a file to the project
@@ -2816,26 +2914,58 @@ namespace MonoDevelop.Projects
if (loadedItems != null)
loadedItems.Clear ();
+ HashSet<ProjectItem> unusedItems = null;
+ Dictionary<(string Name, string Include), ProjectItem> lookupItems = null;
+ ImmutableList<ProjectItem>.Builder newItems = null;
+ if (IsReevaluating) {
+ unusedItems = new HashSet<ProjectItem> (Items);
+ lookupItems = new Dictionary<(string Name, string Include), ProjectItem> ();
+ newItems = ImmutableList.CreateBuilder<ProjectItem> ();
+
+ // Improve ReadItem performance by creating a dictionary of items that can be
+ // searched faster than using Items.FirstOrDefault. Building this dictionary takes ~15ms
+ foreach (var it in Items) {
+ if (it.BackingItem != null && it.BackingEvalItem != null) {
+ lookupItems.Add (GetProjectItemLookupKey (it.BackingEvalItem), it);
+ }
+ }
+ }
+
var localItems = new List<ProjectItem> ();
foreach (var buildItem in msproject.EvaluatedItemsIgnoringCondition) {
if (buildItem.IsImported && !ProjectExtension.OnGetSupportsImportedItem (buildItem))
continue;
if (BuildAction.ReserverIdeActions.Contains (buildItem.Name))
continue;
- ProjectItem it = ReadItem (buildItem);
- if (it == null)
+ var result = ReadItem (buildItem, lookupItems);
+ if (result.Item == null)
continue;
- it.Flags = flags;
- localItems.Add (it);
- if (loadedItems != null)
- loadedItems.Add (buildItem.SourceItem);
+
+ result.Item.Flags = flags;
+ localItems.Add (result.Item);
+ if (result.IsNew) {
+ newItems?.Add (result.Item);
+ } else {
+ unusedItems?.Remove (result.Item);
+ }
+
+ if (loadedItems != null) {
+ foreach (var item in buildItem.SourceItems) {
+ loadedItems.Add (item);
+ }
+ }
}
if (IsReevaluating)
- Items.SetItems (localItems);
+ Items.SetItems (localItems, newItems, unusedItems);
else
Items.AddRange (localItems);
}
+ static (string Name, string Include) GetProjectItemLookupKey (IMSBuildItemEvaluated item)
+ {
+ return (item.Name, item.Include);
+ }
+
protected override void OnSetFormat (MSBuildFileFormat format)
{
base.OnSetFormat (format);
@@ -2853,15 +2983,16 @@ namespace MonoDevelop.Projects
productVersion = FileFormat.DefaultProductVersion;
}
- internal ProjectItem ReadItem (IMSBuildItemEvaluated buildItem)
+ internal (ProjectItem Item, bool IsNew) ReadItem (IMSBuildItemEvaluated buildItem, Dictionary<(string Name, string Include), ProjectItem> lookupItems)
{
if (IsReevaluating) {
// If this item already exists in the current collection of items, reuse it
- var eit = Items.FirstOrDefault (it => it.BackingItem != null && it.BackingEvalItem != null && it.BackingEvalItem.Name == buildItem.Name && it.BackingEvalItem.Include == buildItem.Include && ItemsAreEqual (buildItem, it.BackingEvalItem));
- if (eit != null) {
- eit.BackingItem = buildItem.SourceItem;
- eit.BackingEvalItem = buildItem;
- return eit;
+ if (lookupItems.TryGetValue (GetProjectItemLookupKey (buildItem), out ProjectItem eit)) {
+ if (ItemsAreEqual (buildItem, eit.BackingEvalItem) || CheckProjectReferenceItemsAreEqual (buildItem, eit)) {
+ eit.BackingItem = buildItem.SourceItem;
+ eit.BackingEvalItem = buildItem;
+ return (eit, false);
+ }
}
}
@@ -2869,7 +3000,27 @@ namespace MonoDevelop.Projects
item.Read (this, buildItem);
item.BackingItem = buildItem.SourceItem;
item.BackingEvalItem = buildItem;
- return item;
+ return (item, true);
+ }
+
+ /// <summary>
+ /// Special case ProjectReference items when checking for a match for ReadItem. The underlying build
+ /// items may not have matching metadata properties but the ProjectReference.Equals method may
+ /// indicate a match. This is tested for in the ProjectReevaluationTests
+ /// ReevaluateNewProjectReferencesAfterSave test.
+ /// </summary>
+ bool CheckProjectReferenceItemsAreEqual (IMSBuildItemEvaluated buildItem, ProjectItem item)
+ {
+ if (!(item is ProjectReference existingProjectReference))
+ return false;
+
+ var newProjectReference = CreateProjectItem (buildItem) as ProjectReference;
+ if (newProjectReference != null) {
+ newProjectReference.Read (this, buildItem);
+ return item.Equals (newProjectReference);
+ }
+
+ return false;
}
struct MergedPropertyValue
@@ -3275,6 +3426,14 @@ namespace MonoDevelop.Projects
/// </summary>
public bool UseAdvancedGlobSupport { get; set; }
+ /// <summary>
+ /// When set to true if new file is added to a project that does not have
+ /// the metadata properties defined by a update glob item then the item will
+ /// not be excluded but will be treated as though it had these metadata properties
+ /// with the same values.
+ /// </summary>
+ public bool UseDefaultMetadataForExcludedExpandedItems { get; set; }
+
HashSet<MSBuildItem> usedMSBuildItems = new HashSet<MSBuildItem> ();
HashSet<ProjectItem> loadedProjectItems = new HashSet<ProjectItem> ();
@@ -3333,7 +3492,7 @@ namespace MonoDevelop.Projects
foreach (var it in unusedItems) {
if (it.ParentGroup != null) { // It may already have been deleted
// Remove wildcard item if it is not imported.
- if (!it.IsWildcardItem || it.ParentProject == msproject) {
+ if ((!it.IsWildcardItem && it.ParentProject == msproject) || it.ParentProject == msproject) {
msproject.RemoveItem (it);
if (!UseAdvancedGlobSupport)
@@ -3496,6 +3655,13 @@ namespace MonoDevelop.Projects
loadedItems.Add (buildItem);
unusedItems.Remove (buildItem);
+ if (sourceItems != null) {
+ foreach (var sourceItem in sourceItems) {
+ loadedItems.Add (sourceItem);
+ unusedItems.Remove (sourceItem);
+ }
+ }
+
if (!buildItem.IsWildcardItem) {
if (buildItem.IsUpdate) {
var propertiesAlreadySet = new HashSet<string> (buildItem.Metadata.GetProperties ().Select (p => p.Name));
@@ -3597,6 +3763,8 @@ namespace MonoDevelop.Projects
updateItems = FindUpdateItemsForItem (globItem, item.Include).ToList ();
updateItem = updateItems.LastOrDefault ();
if (updateItem == null) {
+ if (UpdateGlobHasMatchingPropertyValue (p, evalItem))
+ continue;
// There is no existing update item. A new one will be generated.
generateNewUpdateItem = true;
continue;
@@ -3661,7 +3829,7 @@ namespace MonoDevelop.Projects
it.ParentProject.RemoveItem (it);
}
// If this metadata is defined in the glob item, the only option is to exclude the item from the glob.
- if (globItem.Metadata.HasProperty (p.Name)) {
+ if (globItem.Metadata.HasProperty (p.Name) && !UseDefaultMetadataForExcludedExpandedItems) {
// Get rid of all update items, not needed anymore since a full new item will be added
foreach (var it in updateItems) {
if (it.ParentNode != null)
@@ -3702,6 +3870,28 @@ namespace MonoDevelop.Projects
}
}
+ bool UpdateGlobHasMatchingPropertyValue (MSBuildProperty p, IMSBuildItemEvaluated evalItem)
+ {
+ MSBuildEvaluationContext context = null;
+
+ foreach (var updateItem in evalItem.SourceItems) {
+ if (!updateItem.IsUpdate)
+ continue;
+
+ var p2 = updateItem.Metadata.GetProperty (p.Name);
+ if (p2 != null) {
+ if (context == null) {
+ context = new MSBuildEvaluationContext ();
+ context.InitEvaluation (MSBuildProject);
+ }
+
+ string value = context.Evaluate (p.UnevaluatedValue);
+ return p.ValueType.Equals (p.Value, value);
+ }
+ }
+ return false;
+ }
+
bool ItemsAreEqual (IMSBuildItemEvaluated item1, IMSBuildItemEvaluated item2)
{
// Compare only metadata, since item name and include can't change
@@ -3811,6 +4001,15 @@ namespace MonoDevelop.Projects
/// </remarks>
public Task ReevaluateProject (ProgressMonitor monitor)
{
+ return ReevaluateProject (monitor, true);
+ }
+
+ /// <summary>
+ /// Reevaluates the MSBuild project and optionally resets the cached compile items
+ /// taken from CoreCompileDependsOn.
+ /// </summary>
+ Task ReevaluateProject (ProgressMonitor monitor, bool resetCachedCompileItems)
+ {
return BindTask (ct => Runtime.RunInMainThread (async () => {
using (await writeProjectLock.EnterAsync ()) {
var oldCapabilities = new HashSet<string> (projectCapabilities);
@@ -3834,7 +4033,8 @@ namespace MonoDevelop.Projects
IsReevaluating = false;
}
- ResetCachedCompileItems ();
+ if (resetCachedCompileItems)
+ ResetCachedCompileItems ();
if (!oldCapabilities.SetEquals (projectCapabilities))
NotifyProjectCapabilitiesChanged ();
@@ -4038,7 +4238,14 @@ namespace MonoDevelop.Projects
}
string include = MSBuildProjectService.ToMSBuildPath (ItemDirectory, fileName);
- foreach (var it in sourceProject.FindGlobItemsIncludingFile (include).Where (it => it.Metadata.GetProperties ().Count () == 0)) {
+ var globItems = sourceProject.FindGlobItemsIncludingFile (include);
+ if (globItems == null) {
+ // If the MSBuildEngine no glob items can be found.
+ LoggingService.LogWarning ("File created externally not processed. {0}", fileName);
+ return;
+ }
+
+ foreach (var it in globItems.Where (it => it.Metadata.GetProperties ().Count () == 0)) {
var eit = CreateFakeEvaluatedItem (sourceProject, it, include, null);
var pi = CreateProjectItem (eit);
pi.Read (this, eit);
@@ -4235,6 +4442,11 @@ namespace MonoDevelop.Projects
return Project.OnGetCommonBuildActions ();
}
+ internal protected override bool OnGetFileSupportsBuildAction (string fileName, string buildAction)
+ {
+ return Project.OnGetFileSupportsBuildAction (fileName, buildAction);
+ }
+
internal protected override ProjectItem OnCreateProjectItem (IMSBuildItemEvaluated item)
{
return Project.OnCreateProjectItem (item);
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectExtension.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectExtension.cs
index 3544528240..b99a83ead4 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectExtension.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectExtension.cs
@@ -205,6 +205,11 @@ namespace MonoDevelop.Projects
return next.OnGetCommonBuildActions ();
}
+ internal protected virtual bool OnGetFileSupportsBuildAction (string fileName, string buildAction)
+ {
+ return next.OnGetFileSupportsBuildAction (fileName, buildAction);
+ }
+
internal protected virtual ProjectItem OnCreateProjectItem (IMSBuildItemEvaluated item)
{
return next.OnCreateProjectItem (item);
diff --git a/main/src/core/MonoDevelop.Core/packages.config b/main/src/core/MonoDevelop.Core/packages.config
index b71392f474..6600de18a0 100644
--- a/main/src/core/MonoDevelop.Core/packages.config
+++ b/main/src/core/MonoDevelop.Core/packages.config
@@ -1,90 +1,110 @@
-<?xml version="1.0" encoding="utf-8"?>
-<packages>
- <package id="Humanizer.Core" version="2.2.0" targetFramework="net461" />
- <package id="ManagedEsent" version="1.9.4" targetFramework="net461" />
- <package id="Microsoft.CodeAnalysis" version="2.7.0-beta3-62509-03" targetFramework="net461" />
- <package id="Microsoft.CodeAnalysis.Analyzers" version="1.2.0-beta2" targetFramework="net461" />
- <package id="Microsoft.CodeAnalysis.Common" version="2.7.0-beta3-62509-03" targetFramework="net461" />
- <package id="Microsoft.CodeAnalysis.CSharp" version="2.7.0-beta3-62509-03" targetFramework="net461" />
- <package id="Microsoft.CodeAnalysis.CSharp.Features" version="2.7.0-beta3-62509-03" targetFramework="net461" />
- <package id="Microsoft.CodeAnalysis.CSharp.Workspaces" version="2.7.0-beta3-62509-03" targetFramework="net461" />
- <package id="Microsoft.CodeAnalysis.EditorFeatures" version="2.7.0-beta3-62509-03" targetFramework="net461" />
- <package id="Microsoft.CodeAnalysis.EditorFeatures.Text" version="2.7.0-beta3-62509-03" targetFramework="net461" />
- <package id="Microsoft.CodeAnalysis.Elfie" version="1.0.0-rc9" targetFramework="net461" />
- <package id="Microsoft.CodeAnalysis.Features" version="2.7.0-beta3-62509-03" targetFramework="net461" />
- <package id="Microsoft.CodeAnalysis.VisualBasic" version="2.7.0-beta3-62509-03" targetFramework="net461" />
- <package id="Microsoft.CodeAnalysis.VisualBasic.Features" version="2.7.0-beta3-62509-03" targetFramework="net461" />
- <package id="Microsoft.CodeAnalysis.VisualBasic.Workspaces" version="2.7.0-beta3-62509-03" targetFramework="net461" />
- <package id="Microsoft.CodeAnalysis.Workspaces.Common" version="2.7.0-beta3-62509-03" targetFramework="net461" />
- <package id="Microsoft.Composition" version="1.0.30" targetFramework="net461" />
- <package id="Microsoft.VisualStudio.Composition" version="15.3.38" targetFramework="net461" />
- <package id="Microsoft.VisualStudio.CoreUtility" version="15.6.161-preview" targetFramework="net45" />
- <package id="Microsoft.VisualStudio.Language.Intellisense" version="15.6.161-preview" targetFramework="net45" />
- <package id="Microsoft.VisualStudio.Language.StandardClassification" version="15.6.161-preview" targetFramework="net45" />
- <package id="Microsoft.VisualStudio.Text.Data" version="15.6.161-preview" targetFramework="net45" />
- <package id="Microsoft.VisualStudio.Text.Internal" version="15.6.161-preview" targetFramework="net45" />
- <package id="Microsoft.VisualStudio.Text.Logic" version="15.6.161-preview" targetFramework="net45" />
- <package id="Microsoft.VisualStudio.Text.UI" version="15.6.161-preview" targetFramework="net45" />
- <package id="Microsoft.VisualStudio.Text.UI.Wpf" version="15.6.161-preview" targetFramework="net45" />
- <package id="Microsoft.VisualStudio.Text.Implementation" version="15.0.7-pre" targetFramework="net45" />
- <package id="Microsoft.VisualStudio.Threading" version="15.4.4" targetFramework="net461" />
- <package id="Microsoft.VisualStudio.Validation" version="15.3.15" targetFramework="net461" />
- <package id="Mono.Cecil" version="0.10.0-beta6" targetFramework="net45" />
- <package id="Newtonsoft.Json" version="10.0.3" targetFramework="net461" />
- <package id="SharpZipLib" version="0.86.0" targetFramework="net45" />
- <package id="SQLitePCLRaw.bundle_e_sqlite3" version="1.1.6" targetFramework="net461" />
- <package id="SQLitePCLRaw.core" version="1.1.6" targetFramework="net461" />
- <package id="SQLitePCLRaw.lib.e_sqlite3.linux" version="1.1.6" targetFramework="net461" />
- <package id="SQLitePCLRaw.lib.e_sqlite3.osx" version="1.1.6" targetFramework="net461" />
- <package id="SQLitePCLRaw.lib.e_sqlite3.v110_xp" version="1.1.6" targetFramework="net461" />
- <package id="SQLitePCLRaw.provider.e_sqlite3.net45" version="1.1.6" targetFramework="net461" />
- <package id="System.AppContext" version="4.3.0" targetFramework="net461" />
- <package id="System.Collections" version="4.3.0" targetFramework="net461" />
- <package id="System.Collections.Concurrent" version="4.3.0" targetFramework="net461" />
- <package id="System.Collections.Immutable" version="1.3.1" targetFramework="net461" />
- <package id="System.Composition.AttributedModel" version="1.0.31" targetFramework="net461" />
- <package id="System.Composition.Hosting" version="1.0.31" targetFramework="net461" />
- <package id="System.Composition.Runtime" version="1.0.31" targetFramework="net461" />
- <package id="System.Composition.TypedParts" version="1.0.31" targetFramework="net461" />
- <package id="System.Console" version="4.3.0" targetFramework="net461" />
- <package id="System.Diagnostics.Contracts" version="4.3.0" targetFramework="net461" />
- <package id="System.Diagnostics.Debug" version="4.3.0" targetFramework="net461" />
- <package id="System.Diagnostics.FileVersionInfo" version="4.3.0" targetFramework="net461" />
- <package id="System.Diagnostics.StackTrace" version="4.3.0" targetFramework="net461" />
- <package id="System.Diagnostics.Tools" version="4.3.0" targetFramework="net461" />
- <package id="System.Dynamic.Runtime" version="4.3.0" targetFramework="net461" />
- <package id="System.Globalization" version="4.3.0" targetFramework="net461" />
- <package id="System.IO.Compression" version="4.3.0" targetFramework="net461" />
- <package id="System.IO.FileSystem" version="4.3.0" targetFramework="net461" />
- <package id="System.IO.FileSystem.Primitives" version="4.3.0" targetFramework="net461" />
- <package id="System.Linq" version="4.3.0" targetFramework="net461" />
- <package id="System.Linq.Expressions" version="4.3.0" targetFramework="net461" />
- <package id="System.Linq.Parallel" version="4.3.0" targetFramework="net461" />
- <package id="System.ObjectModel" version="4.3.0" targetFramework="net461" />
- <package id="System.Reflection" version="4.3.0" targetFramework="net461" />
- <package id="System.Reflection.Metadata" version="1.4.2" targetFramework="net461" />
- <package id="System.Resources.ResourceManager" version="4.3.0" targetFramework="net461" />
- <package id="System.Runtime" version="4.3.0" targetFramework="net461" />
- <package id="System.Runtime.Extensions" version="4.3.0" targetFramework="net461" />
- <package id="System.Runtime.InteropServices" version="4.3.0" targetFramework="net461" />
- <package id="System.Runtime.InteropServices.RuntimeInformation" version="4.3.0" targetFramework="net461" />
- <package id="System.Runtime.Numerics" version="4.3.0" targetFramework="net461" />
- <package id="System.Security.Cryptography.Algorithms" version="4.3.0" targetFramework="net461" />
- <package id="System.Security.Cryptography.Encoding" version="4.3.0" targetFramework="net461" />
- <package id="System.Security.Cryptography.Primitives" version="4.3.0" targetFramework="net461" />
- <package id="System.Security.Cryptography.X509Certificates" version="4.3.0" targetFramework="net461" />
- <package id="System.Text.Encoding" version="4.3.0" targetFramework="net461" />
- <package id="System.Text.Encoding.CodePages" version="4.3.0" targetFramework="net461" />
- <package id="System.Text.Encoding.Extensions" version="4.3.0" targetFramework="net461" />
- <package id="System.Text.RegularExpressions" version="4.3.0" targetFramework="net461" />
- <package id="System.Threading" version="4.3.0" targetFramework="net461" />
- <package id="System.Threading.Tasks" version="4.3.0" targetFramework="net461" />
- <package id="System.Threading.Tasks.Parallel" version="4.3.0" targetFramework="net461" />
- <package id="System.Threading.Thread" version="4.3.0" targetFramework="net461" />
- <package id="System.ValueTuple" version="4.4.0" targetFramework="net461" />
- <package id="System.Xml.ReaderWriter" version="4.3.0" targetFramework="net461" />
- <package id="System.Xml.XDocument" version="4.3.0" targetFramework="net461" />
- <package id="System.Xml.XmlDocument" version="4.3.0" targetFramework="net461" />
- <package id="System.Xml.XPath" version="4.3.0" targetFramework="net461" />
- <package id="System.Xml.XPath.XDocument" version="4.3.0" targetFramework="net461" />
-</packages>
+ο»Ώ<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="Humanizer.Core" version="2.2.0" targetFramework="net461" />
+ <package id="ManagedEsent" version="1.9.4" targetFramework="net461" />
+ <package id="Microsoft.CodeAnalysis" version="2.8.0-beta2-62708-11" targetFramework="net461" />
+ <package id="Microsoft.CodeAnalysis.Analyzers" version="1.2.0-beta2" targetFramework="net461" />
+ <package id="Microsoft.CodeAnalysis.Common" version="2.8.0-beta2-62708-11" targetFramework="net461" />
+ <package id="Microsoft.CodeAnalysis.CSharp" version="2.8.0-beta2-62708-11" targetFramework="net461" />
+ <package id="Microsoft.CodeAnalysis.CSharp.Features" version="2.8.0-beta2-62708-11" targetFramework="net461" />
+ <package id="Microsoft.CodeAnalysis.CSharp.Workspaces" version="2.8.0-beta2-62708-11" targetFramework="net461" />
+ <package id="Microsoft.CodeAnalysis.EditorFeatures" version="2.8.0-beta2-62708-11" targetFramework="net461" />
+ <package id="Microsoft.CodeAnalysis.EditorFeatures.Text" version="2.8.0-beta2-62708-11" targetFramework="net461" />
+ <package id="Microsoft.CodeAnalysis.Elfie" version="1.0.0-rc9" targetFramework="net461" />
+ <package id="Microsoft.CodeAnalysis.Features" version="2.8.0-beta2-62708-11" targetFramework="net461" />
+ <package id="Microsoft.CodeAnalysis.VisualBasic" version="2.8.0-beta2-62708-11" targetFramework="net461" />
+ <package id="Microsoft.CodeAnalysis.VisualBasic.Features" version="2.8.0-beta2-62708-11" targetFramework="net461" />
+ <package id="Microsoft.CodeAnalysis.VisualBasic.Workspaces" version="2.8.0-beta2-62708-11" targetFramework="net461" />
+ <package id="Microsoft.CodeAnalysis.Workspaces.Common" version="2.8.0-beta2-62708-11" targetFramework="net461" />
+ <package id="Microsoft.Composition" version="1.0.30" targetFramework="net461" />
+ <package id="Microsoft.NETCore.Platforms" version="1.0.1" targetFramework="net461" />
+ <package id="Microsoft.NETCore.Portable.Compatibility" version="1.0.1" targetFramework="net461" />
+ <package id="Microsoft.VisualStudio.CodingConventions" version="1.1.20180226.4" targetFramework="net461" />
+ <package id="Microsoft.VisualStudio.Composition" version="15.6.36" targetFramework="net461" />
+ <package id="Microsoft.VisualStudio.CoreUtility" version="15.6.281-preview" targetFramework="net45" />
+ <package id="Microsoft.VisualStudio.Language" version="15.6.281-preview" targetFramework="net461" />
+ <package id="Microsoft.VisualStudio.Language.Intellisense" version="15.6.281-preview" targetFramework="net45" />
+ <package id="Microsoft.VisualStudio.Language.StandardClassification" version="15.6.281-preview" targetFramework="net45" />
+ <package id="Microsoft.VisualStudio.Text.Data" version="15.6.281-preview" targetFramework="net45" />
+ <package id="Microsoft.VisualStudio.Text.Internal" version="15.6.281-preview" targetFramework="net45" />
+ <package id="Microsoft.VisualStudio.Text.Logic" version="15.6.281-preview" targetFramework="net45" />
+ <package id="Microsoft.VisualStudio.Text.UI" version="15.6.281-preview" targetFramework="net45" />
+ <package id="Microsoft.VisualStudio.Text.UI.Wpf" version="15.6.281-preview" targetFramework="net45" />
+ <package id="Microsoft.VisualStudio.Text.Implementation" version="15.2.0-pre" targetFramework="net461" />
+ <package id="Microsoft.VisualStudio.Threading" version="15.6.46" targetFramework="net461" />
+ <package id="Microsoft.VisualStudio.Validation" version="15.3.32" targetFramework="net461" />
+ <package id="Microsoft.Win32.Primitives" version="4.0.1" targetFramework="net461" />
+ <package id="Mono.Cecil" version="0.10.0-beta7" targetFramework="net45" />
+ <package id="NETStandard.Library" version="1.6.0" targetFramework="net461" />
+ <package id="Newtonsoft.Json" version="10.0.3" targetFramework="net461" />
+ <package id="SharpZipLib" version="0.86.0" targetFramework="net45" />
+ <package id="SQLitePCLRaw.bundle_e_sqlite3" version="1.1.9" targetFramework="net461" />
+ <package id="SQLitePCLRaw.core" version="1.1.9" targetFramework="net461" />
+ <package id="SQLitePCLRaw.lib.e_sqlite3.linux" version="1.1.9" targetFramework="net461" />
+ <package id="SQLitePCLRaw.lib.e_sqlite3.osx" version="1.1.9" targetFramework="net461" />
+ <package id="SQLitePCLRaw.lib.e_sqlite3.v110_xp" version="1.1.9" targetFramework="net461" />
+ <package id="SQLitePCLRaw.provider.e_sqlite3.net45" version="1.1.9" targetFramework="net461" />
+ <package id="System.AppContext" version="4.3.0" targetFramework="net461" />
+ <package id="System.Collections" version="4.3.0" targetFramework="net461" />
+ <package id="System.Collections.Concurrent" version="4.3.0" targetFramework="net461" />
+ <package id="System.Collections.Immutable" version="1.3.1" targetFramework="net461" />
+ <package id="System.Composition" version="1.0.31" targetFramework="net461" />
+ <package id="System.Composition.AttributedModel" version="1.0.31" targetFramework="net461" />
+ <package id="System.Composition.Convention" version="1.0.31" targetFramework="net461" />
+ <package id="System.Composition.Hosting" version="1.0.31" targetFramework="net461" />
+ <package id="System.Composition.Runtime" version="1.0.31" targetFramework="net461" />
+ <package id="System.Composition.TypedParts" version="1.0.31" targetFramework="net461" />
+ <package id="System.Console" version="4.3.0" targetFramework="net461" />
+ <package id="System.Diagnostics.Contracts" version="4.3.0" targetFramework="net461" />
+ <package id="System.Diagnostics.Debug" version="4.3.0" targetFramework="net461" />
+ <package id="System.Diagnostics.DiagnosticSource" version="4.0.0" targetFramework="net461" />
+ <package id="System.Diagnostics.FileVersionInfo" version="4.3.0" targetFramework="net461" />
+ <package id="System.Diagnostics.StackTrace" version="4.3.0" targetFramework="net461" />
+ <package id="System.Diagnostics.Tools" version="4.3.0" targetFramework="net461" />
+ <package id="System.Diagnostics.Tracing" version="4.1.0" targetFramework="net461" />
+ <package id="System.Dynamic.Runtime" version="4.3.0" targetFramework="net461" />
+ <package id="System.Globalization" version="4.3.0" targetFramework="net461" />
+ <package id="System.Globalization.Calendars" version="4.0.1" targetFramework="net461" />
+ <package id="System.IO" version="4.1.0" targetFramework="net461" />
+ <package id="System.IO.Compression" version="4.3.0" targetFramework="net461" />
+ <package id="System.IO.Compression.ZipFile" version="4.0.1" targetFramework="net461" />
+ <package id="System.IO.FileSystem" version="4.3.0" targetFramework="net461" />
+ <package id="System.IO.FileSystem.Primitives" version="4.3.0" targetFramework="net461" />
+ <package id="System.Linq" version="4.3.0" targetFramework="net461" />
+ <package id="System.Linq.Expressions" version="4.3.0" targetFramework="net461" />
+ <package id="System.Linq.Parallel" version="4.3.0" targetFramework="net461" />
+ <package id="System.Net.Http" version="4.1.0" targetFramework="net461" />
+ <package id="System.Net.Primitives" version="4.0.11" targetFramework="net461" />
+ <package id="System.Net.Sockets" version="4.1.0" targetFramework="net461" />
+ <package id="System.ObjectModel" version="4.3.0" targetFramework="net461" />
+ <package id="System.Reflection" version="4.3.0" targetFramework="net461" />
+ <package id="System.Reflection.Extensions" version="4.0.1" targetFramework="net461" />
+ <package id="System.Reflection.Metadata" version="1.4.2" targetFramework="net461" />
+ <package id="System.Reflection.Primitives" version="4.0.1" targetFramework="net461" />
+ <package id="System.Resources.ResourceManager" version="4.3.0" targetFramework="net461" />
+ <package id="System.Runtime" version="4.3.0" targetFramework="net461" />
+ <package id="System.Runtime.Extensions" version="4.3.0" targetFramework="net461" />
+ <package id="System.Runtime.Handles" version="4.0.1" targetFramework="net461" />
+ <package id="System.Runtime.InteropServices" version="4.3.0" targetFramework="net461" />
+ <package id="System.Runtime.InteropServices.RuntimeInformation" version="4.3.0" targetFramework="net461" />
+ <package id="System.Runtime.Numerics" version="4.3.0" targetFramework="net461" />
+ <package id="System.Security.Cryptography.Algorithms" version="4.3.0" targetFramework="net461" />
+ <package id="System.Security.Cryptography.Encoding" version="4.3.0" targetFramework="net461" />
+ <package id="System.Security.Cryptography.Primitives" version="4.3.0" targetFramework="net461" />
+ <package id="System.Security.Cryptography.X509Certificates" version="4.3.0" targetFramework="net461" />
+ <package id="System.Text.Encoding" version="4.3.0" targetFramework="net461" />
+ <package id="System.Text.Encoding.CodePages" version="4.3.0" targetFramework="net461" />
+ <package id="System.Text.Encoding.Extensions" version="4.3.0" targetFramework="net461" />
+ <package id="System.Text.RegularExpressions" version="4.3.0" targetFramework="net461" />
+ <package id="System.Threading" version="4.3.0" targetFramework="net461" />
+ <package id="System.Threading.Tasks" version="4.3.0" targetFramework="net461" />
+ <package id="System.Threading.Tasks.Parallel" version="4.3.0" targetFramework="net461" />
+ <package id="System.Threading.Thread" version="4.3.0" targetFramework="net461" />
+ <package id="System.Threading.Timer" version="4.0.1" targetFramework="net461" />
+ <package id="System.ValueTuple" version="4.4.0" targetFramework="net461" />
+ <package id="System.Xml.ReaderWriter" version="4.3.0" targetFramework="net461" />
+ <package id="System.Xml.XDocument" version="4.3.0" targetFramework="net461" />
+ <package id="System.Xml.XmlDocument" version="4.3.0" targetFramework="net461" />
+ <package id="System.Xml.XPath" version="4.3.0" targetFramework="net461" />
+ <package id="System.Xml.XPath.XDocument" version="4.3.0" targetFramework="net461" />
+</packages>
diff --git a/main/src/core/MonoDevelop.Ide/ExtensionModel/MonoDevelop.Ide.addin.xml b/main/src/core/MonoDevelop.Ide/ExtensionModel/MonoDevelop.Ide.addin.xml
index 4423f6f512..3846ff564c 100644
--- a/main/src/core/MonoDevelop.Ide/ExtensionModel/MonoDevelop.Ide.addin.xml
+++ b/main/src/core/MonoDevelop.Ide/ExtensionModel/MonoDevelop.Ide.addin.xml
@@ -238,6 +238,10 @@
<ExtensionNode name = "Assembly" type = "MonoDevelop.Core.AddIns.AssemblyExtensionNode" />
</ExtensionPoint>
+ <ExtensionPoint path="/MonoDevelop/Ide/TypeService/OptionProviders">
+ <ExtensionNode name="Class" />
+ </ExtensionPoint>
+
<!-- Extensions -->
<Extension path = "/MonoDevelop/Core/Applications">
@@ -401,6 +405,8 @@
</Extension>
<Extension path="/MonoDevelop/Ide/Composition">
+ <Assembly file="Microsoft.CodeAnalysis.CSharp.EditorFeatures.dll"/>
+ <Assembly file="Microsoft.CodeAnalysis.EditorFeatures.dll"/>
<Assembly file="Microsoft.CodeAnalysis.Features.dll" />
<Assembly file="Microsoft.CodeAnalysis.Workspaces.dll" />
<Assembly file="Microsoft.CodeAnalysis.Workspaces.Desktop.dll" />
@@ -410,6 +416,8 @@
<Assembly file="Microsoft.CodeAnalysis.VisualBasic.Workspaces.dll" />
<Assembly file="MonoDevelop.Ide.dll"/>
<Assembly file="Microsoft.VisualStudio.Text.Implementation.dll"/>
+ <Assembly file="Microsoft.VisualStudio.Text.Logic.dll"/>
+ <Assembly file="Microsoft.VisualStudio.Text.UI.dll"/>
<Assembly file="Microsoft.VisualStudio.Language.StandardClassification.dll"/>
<Assembly file="Microsoft.CodeAnalysis.CSharp.EditorFeatures.dll" />
</Extension>
diff --git a/main/src/core/MonoDevelop.Ide/ExtensionModel/Templates.addin.xml b/main/src/core/MonoDevelop.Ide/ExtensionModel/Templates.addin.xml
index 8ac342586a..0de8c942f8 100644
--- a/main/src/core/MonoDevelop.Ide/ExtensionModel/Templates.addin.xml
+++ b/main/src/core/MonoDevelop.Ide/ExtensionModel/Templates.addin.xml
@@ -35,11 +35,21 @@
<ExtensionNode name="Template" type="MonoDevelop.Ide.Codons.TemplateExtensionNode"/>
</ExtensionPoint>
+<ExtensionPoint path = "/MonoDevelop/Ide/ItemTemplates" name = "Microsoft Templating Engine file templates">
+ <Description>Microsoft templating engine file templates.</Description>
+ <ExtensionNode name="Template" type="MonoDevelop.Ide.Codons.ItemTemplateExtensionNode"/>
+</ExtensionPoint>
+
<ExtensionPoint path = "/MonoDevelop/Ide/ProjectTemplatePackageInstallers" name = "Project template package installers">
<Description>Installs packages defined in the project template. Must implement MonoDevelop.Ide.Templates.ProjectTemplatePackageInstaller</Description>
<ExtensionNode name="Class" />
</ExtensionPoint>
+<ExtensionPoint path = "/MonoDevelop/Ide/ItemTemplatePackageInstallers" name = "Item template package installers">
+ <Description>Installs packages defined in the template. Must implement MonoDevelop.Ide.Templates.ItemTemplatePackageInstaller</Description>
+ <ExtensionNode name="Class" />
+</ExtensionPoint>
+
<ExtensionPoint path="/MonoDevelop/Ide/ProjectTemplatePackageRepositories">
<Description>Defines a path where NuGet packages are searched for when creating a project from a template.</Description>
<ExtensionNode name="PackageRepository" type="MonoDevelop.Ide.Templates.PackageRepositoryNode" />
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AtkCocoaHelper/AtkCocoaHelperMac.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AtkCocoaHelper/AtkCocoaHelperMac.cs
index 591fdc2de8..920f3ce669 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AtkCocoaHelper/AtkCocoaHelperMac.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AtkCocoaHelper/AtkCocoaHelperMac.cs
@@ -466,6 +466,33 @@ namespace MonoDevelop.Components.AtkCocoaHelper
nsa.AccessibilityChildren = newChildren;
}
+ public static void TransferAccessibleChild (this Atk.Object from, Atk.Object to, Atk.Object child)
+ {
+ var fromNsa = GetNSAccessibilityElement (from);
+ var toNsa = GetNSAccessibilityElement (to);
+ var childNsa = GetNSAccessibilityElement (child);
+
+ if (fromNsa == null || toNsa == null || childNsa == null) {
+ return;
+ }
+
+ var fromChildren = fromNsa.AccessibilityChildren;
+
+ if (fromChildren == null || fromChildren.Length == 0) {
+ return;
+ }
+
+ var fromList = fromChildren.ToList ();
+ fromList.Remove ((NSObject) childNsa);
+ fromNsa.AccessibilityChildren = fromList.ToArray ();
+
+ var toChildren = toNsa.AccessibilityChildren;
+ List<NSObject> toList = toChildren == null ? new List<NSObject> () : toChildren.ToList ();
+
+ toList.Add ((NSObject)childNsa);
+ toNsa.AccessibilityChildren = toList.ToArray ();
+ }
+
public static void SetAccessibleChildren (this Atk.Object o, AccessibilityElementProxy [] children)
{
var nsa = GetNSAccessibilityElement (o);
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AtkCocoaHelper/AtkCocoaHelperNoOp.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AtkCocoaHelper/AtkCocoaHelperNoOp.cs
index b9bc3f936b..bcd62c1c87 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AtkCocoaHelper/AtkCocoaHelperNoOp.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AtkCocoaHelper/AtkCocoaHelperNoOp.cs
@@ -157,6 +157,10 @@ namespace MonoDevelop.Components.AtkCocoaHelper
public static void MakeAccessibilityAnnouncement (this Atk.Object o, string message)
{
}
+
+ public static void TransferAccessibleChild (this Atk.Object from, Atk.Object to, Atk.Object child)
+ {
+ }
}
public class AccessibilityElementProxy : IAccessibilityElementProxy
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AutoTest/AppResult.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AutoTest/AppResult.cs
index 3f9665b513..4bce0b11d5 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AutoTest/AppResult.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.AutoTest/AppResult.cs
@@ -31,6 +31,7 @@ using System.Reflection;
using System.Linq;
using System.Collections.ObjectModel;
using MonoDevelop.Components.AutoTest.Results;
+using MonoDevelop.Core;
namespace MonoDevelop.Components.AutoTest
{
@@ -140,9 +141,15 @@ namespace MonoDevelop.Components.AutoTest
protected object GetPropertyValue (string propertyName, object requestedObject)
{
+ if (requestedObject == null) {
+ LoggingService.LogError ("GetPropertyValue : requestedObject == null property requested : " + propertyName);
+ return null;
+ }
return AutoTestService.CurrentSession.UnsafeSync (delegate {
PropertyInfo propertyInfo = requestedObject.GetType().GetProperty(propertyName,
BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic);
+ if (propertyInfo == null)
+ LoggingService.LogError ($"GetPropertyValue : propertyName {propertyName} not found on object {requestedObject}.");
if (propertyInfo != null && propertyInfo.CanRead && !propertyInfo.GetIndexParameters ().Any ()) {
var propertyValue = propertyInfo.GetValue (requestedObject);
if (propertyValue != null) {
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.DockNotebook/DockNotebookTab.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.DockNotebook/DockNotebookTab.cs
index dc9ff17c2c..fbd6a1ed22 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.DockNotebook/DockNotebookTab.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.DockNotebook/DockNotebookTab.cs
@@ -79,10 +79,10 @@ namespace MonoDevelop.Components.DockNotebook
Gdk.Rectangle cocoaFrame;
// value is in the TabStrip's coordinate space, whereas we need to set the button in the tab space.
- cocoaFrame.X = (int)value.X - allocation.X;
- int halfParentWidth = allocation.Height / 2;
- double dy = value.Y - halfParentWidth;
- cocoaFrame.Y = (int) (halfParentWidth + dy) - allocation.Y;
+ cocoaFrame.X = (int)value.X;// - allocation.X;
+ int halfParentHeight = (int)(strip.Allocation.Height / 2);
+ double dy = value.Y - halfParentHeight;
+ cocoaFrame.Y = (int) ((halfParentHeight + dy) - ((int)value.Height / 2));
cocoaFrame.Width = (int) value.Width;
cocoaFrame.Height = (int) value.Height;
@@ -247,7 +247,6 @@ namespace MonoDevelop.Components.DockNotebook
CloseButtonAccessible.PerformShowMenu += OnCloseButtonShowMenu;
CloseButtonAccessible.Title = Core.GettextCatalog.GetString ("Close document");
CloseButtonAccessible.Identifier = "DockNotebook.Tab.CloseButton";
- Accessible.AddAccessibleChild (CloseButtonAccessible);
}
this.notebook = notebook;
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.DockNotebook/TabStrip.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.DockNotebook/TabStrip.cs
index 3feed3bf53..8fbd898711 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.DockNotebook/TabStrip.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.DockNotebook/TabStrip.cs
@@ -147,6 +147,9 @@ namespace MonoDevelop.Components.DockNotebook
if (notebook == null)
throw new ArgumentNullException ("notebook");
+ Accessible.SetCommonAttributes ("Document.Tabstrip",
+ Core.GettextCatalog.GetString ("Document Navigation Bar"),
+ Core.GettextCatalog.GetString ("Contains controls to select which document is being edited"));
Accessible.SetRole (AtkCocoa.Roles.AXTabGroup);
// Handle focus for the tabs.
@@ -254,7 +257,8 @@ namespace MonoDevelop.Components.DockNotebook
var tab = args.Tab;
if (tab.Accessible != null) {
- Accessible.AddAccessibleElement (tab.Accessible);
+ Accessible.AddAccessibleElement (tab.Accessible);
+ Accessible.AddAccessibleElement (tab.CloseButtonAccessible);
tab.AccessibilityPressTab += OnAccessibilityPressTab;
tab.AccessibilityPressCloseButton += OnAccessibilityPressCloseButton;
@@ -276,6 +280,7 @@ namespace MonoDevelop.Components.DockNotebook
tab.AccessibilityShowMenu -= OnAccessibilityShowMenu;
Accessible.RemoveAccessibleElement (tab.Accessible);
+ Accessible.RemoveAccessibleElement (tab.CloseButtonAccessible);
}
tab.Dispose ();
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockItem.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockItem.cs
index 2eb346a6ae..428943c8ae 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockItem.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockItem.cs
@@ -32,6 +32,8 @@ using System;
using System.Xml;
using Mono.Unix;
+using MonoDevelop.Components.AtkCocoaHelper;
+
namespace MonoDevelop.Components.Docking
{
public class DockItem
@@ -87,7 +89,8 @@ namespace MonoDevelop.Components.Docking
get { return stickyVisible; }
set { stickyVisible = value; }
}
-
+
+ internal event EventHandler LabelChanged;
public string Label {
get { return label ?? string.Empty; }
set {
@@ -97,6 +100,13 @@ namespace MonoDevelop.Components.Docking
frame.UpdateTitle (this);
if (floatingWindow != null)
floatingWindow.Title = GetWindowTitle ();
+
+ toolbarTop?.UpdateAccessibilityLabel ();
+ toolbarLeft?.UpdateAccessibilityLabel ();
+ toolbarRight?.UpdateAccessibilityLabel ();
+ toolbarBottom?.UpdateAccessibilityLabel ();
+
+ LabelChanged?.Invoke (this, EventArgs.Empty);
}
}
@@ -123,6 +133,10 @@ namespace MonoDevelop.Components.Docking
titleTab.VisualStyle = currentVisualStyle;
titleTab.SetLabel (Widget, icon, label);
titleTab.ShowAll ();
+
+ if (widget != null) {
+ titleTab.Accessible.AddLinkedUIElement (widget.Accessible);
+ }
}
return titleTab;
}
@@ -144,6 +158,10 @@ namespace MonoDevelop.Components.Docking
widget.VisualStyle = currentVisualStyle;
widget.Visible = false; // Required to ensure that the Shown event is fired
widget.Shown += SetupContent;
+
+ if (titleTab != null) {
+ titleTab.Accessible.AddLinkedUIElement (titleTab.Accessible);
+ }
}
return widget;
}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockItemContainer.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockItemContainer.cs
index 3aae1c9242..45a896b436 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockItemContainer.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockItemContainer.cs
@@ -47,25 +47,27 @@ namespace MonoDevelop.Components.Docking
public DockItemContainer (DockFrame frame, DockItem item)
{
this.item = item;
+ item.LabelChanged += UpdateAccessibilityLabel;
mainBox = new VBox ();
- mainBox.Accessible.SetShouldIgnore (true);
+ mainBox.Accessible.SetShouldIgnore (false);
+ UpdateAccessibilityLabel (null, null);
Add (mainBox);
mainBox.ResizeMode = Gtk.ResizeMode.Queue;
mainBox.Spacing = 0;
ShowAll ();
-
+
mainBox.PackStart (item.GetToolbar (DockPositionType.Top).Container, false, false, 0);
HBox hbox = new HBox ();
- hbox.Accessible.SetShouldIgnore (true);
+ hbox.Accessible.SetTitle ("Hbox");
hbox.Show ();
hbox.PackStart (item.GetToolbar (DockPositionType.Left).Container, false, false, 0);
contentBox = new HBox ();
- contentBox.Accessible.SetShouldIgnore (true);
+ hbox.Accessible.SetTitle ("Content");
contentBox.Show ();
hbox.PackStart (contentBox, true, true, 0);
@@ -76,6 +78,11 @@ namespace MonoDevelop.Components.Docking
mainBox.PackStart (item.GetToolbar (DockPositionType.Bottom).Container, false, false, 0);
}
+ void UpdateAccessibilityLabel (object sender, EventArgs args)
+ {
+ mainBox.Accessible.SetTitle (Core.GettextCatalog.GetString ("{0} Pad", item.Label));
+ }
+
DockVisualStyle visualStyle;
public DockVisualStyle VisualStyle {
@@ -91,7 +98,13 @@ namespace MonoDevelop.Components.Docking
item.Status = DockItemStatus.AutoHide;
}
- public void UpdateContent ()
+ protected override void OnDestroyed()
+ {
+ item.LabelChanged -= UpdateAccessibilityLabel;
+ base.OnDestroyed();
+ }
+
+ public void UpdateContent ()
{
if (widget != null)
((Gtk.Container)widget.Parent).Remove (widget);
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockItemTitleTab.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockItemTitleTab.cs
index a9b6a3b919..d4532109ac 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockItemTitleTab.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockItemTitleTab.cs
@@ -105,8 +105,7 @@ namespace MonoDevelop.Components.Docking
actionHandler.PerformPress += HandlePress;
actionHandler.PerformShowMenu += HandleShowMenu;
- Accessible.SetRole (AtkCocoa.Roles.AXGroup, "pad header");
- Accessible.SetSubRole ("XAPadHeader");
+ UpdateRole (false, null);
CanFocus = true;
this.item = item;
@@ -123,6 +122,36 @@ namespace MonoDevelop.Components.Docking
subscribedLeaveEvent = this.SubscribeLeaveEvent (OnLeave);
}
+ internal void UpdateRole (bool isTab, TabStrip strip)
+ {
+ Atk.Object fromAccessible = null, toAccessible = null;
+
+ if (!isTab) {
+ Accessible.SetRole (AtkCocoa.Roles.AXGroup, "pad header");
+ Accessible.SetSubRole ("XAPadHeader");
+
+ // Take the button accessibles back from the strip
+ if (strip != null) {
+ fromAccessible = strip.Accessible;
+ toAccessible = Accessible;
+ }
+ } else {
+ Accessible.SetRole (AtkCocoa.Roles.AXRadioButton, "tab");
+ Accessible.SetSubRole ("");
+
+ // Give the button accessibles to the strip
+ if (strip != null) {
+ fromAccessible = Accessible;
+ toAccessible = strip.Accessible;
+ }
+ }
+
+ if (fromAccessible != null && toAccessible != null) {
+ fromAccessible.TransferAccessibleChild (toAccessible, btnDock.Accessible);
+ fromAccessible.TransferAccessibleChild (toAccessible, btnClose.Accessible);
+ }
+ }
+
public DockVisualStyle VisualStyle {
get { return visualStyle; }
set {
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockItemToolbar.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockItemToolbar.cs
index 5b0340cf57..f8fe43fc83 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockItemToolbar.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockItemToolbar.cs
@@ -28,6 +28,8 @@ using System;
using System.Linq;
using Gtk;
+using MonoDevelop.Components.AtkCocoaHelper;
+
namespace MonoDevelop.Components.Docking
{
public class DockItemToolbar
@@ -76,6 +78,35 @@ namespace MonoDevelop.Components.Docking
topFrame.Add (box);
// topFrame.GradientBackround = true;
+
+ box.Accessible.SetShouldIgnore (false);
+ box.Accessible.Role = Atk.Role.ToolBar;
+
+ UpdateAccessibilityLabel ();
+ }
+
+ internal void UpdateAccessibilityLabel ()
+ {
+ string name = "";
+ switch (position) {
+ case DockPositionType.Bottom:
+ name = Core.GettextCatalog.GetString ("Bottom {0} pad toolbar", parentItem.Label);
+ break;
+
+ case DockPositionType.Left:
+ name = Core.GettextCatalog.GetString ("Left {0} pad toolbar", parentItem.Label);
+ break;
+
+ case DockPositionType.Right:
+ name = Core.GettextCatalog.GetString ("Right {0} pad toolbar", parentItem.Label);
+ break;
+
+ case DockPositionType.Top:
+ name = Core.GettextCatalog.GetString ("Top {0} pad toolbar", parentItem.Label);
+ break;
+ }
+
+ box.Accessible.SetCommonAttributes ("padtoolbar", name, "");
}
internal void SetStyle (DockVisualStyle style)
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/TabStrip.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/TabStrip.cs
index f3dc20616d..89de00dbc1 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/TabStrip.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/TabStrip.cs
@@ -49,6 +49,9 @@ namespace MonoDevelop.Components.Docking
public TabStrip (DockFrame frame)
{
Accessible.SetRole (AtkCocoa.Roles.AXTabGroup);
+ Accessible.SetCommonAttributes ("Docking.TabStrip",
+ GettextCatalog.GetString ("Pad Tab Bar"),
+ GettextCatalog.GetString ("The different pads in this dock position"));
VBox vbox = new VBox ();
vbox.Accessible.SetShouldIgnore (true);
@@ -95,12 +98,16 @@ namespace MonoDevelop.Components.Docking
}
tab.TabPressed += OnTabPress;
+ tab.UpdateRole (true, this);
+
UpdateAccessibilityTabs ();
}
void HandleRemoved (object o, RemovedArgs args)
{
var w = (DockItemTitleTab)args.Widget;
+ w.UpdateRole (false, this);
+
w.TabPressed -= OnTabPress;
if (currentTab >= box.Children.Length)
currentTab = box.Children.Length - 1;
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.MainToolbar/MainToolbarController.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.MainToolbar/MainToolbarController.cs
index 0140114a63..721faff88e 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.MainToolbar/MainToolbarController.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.MainToolbar/MainToolbarController.cs
@@ -1092,7 +1092,7 @@ namespace MonoDevelop.Components.MainToolbar
int i = s.IndexOf ('_');
if (i == -1)
return s;
- var sb = new StringBuilder (i);
+ var sb = StringBuilderCache.Allocate ();
sb.Append (s, 0, i);
for (; i < s.Length; i++) {
if (s [i] == '_') {
@@ -1102,7 +1102,7 @@ namespace MonoDevelop.Components.MainToolbar
}
sb.Append (s [i]);
}
- return sb.ToString ();
+ return StringBuilderCache.ReturnAndFree (sb);
}
}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.MainToolbar/SearchResult.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.MainToolbar/SearchResult.cs
index c44cd39d56..c6e6c03918 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.MainToolbar/SearchResult.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.MainToolbar/SearchResult.cs
@@ -106,7 +106,7 @@ namespace MonoDevelop.Components.MainToolbar
{
var lane = StringMatcher.GetMatcher (toMatch, true).GetMatch (text);
var matchHexColor = selected ? selectedResultMatchTextColor : resultMatchTextColor;
- StringBuilder result = new StringBuilder (text.Length + matchHexColor.Length + 46);
+ var result = StringBuilderCache.Allocate ();
if (lane != null) {
int lastPos = 0;
for (int n=0; n < lane.Length; n++) {
@@ -125,7 +125,7 @@ namespace MonoDevelop.Components.MainToolbar
} else {
MarkupUtilities.AppendEscapedString (result, text, 0, text.Length);
}
- return result.ToString ();
+ return StringBuilderCache.ReturnAndFree (result);
}
public virtual bool CanActivate {
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/ContextMenuExtensionsMac.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/ContextMenuExtensionsMac.cs
index 30706dedee..34f8345a9c 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/ContextMenuExtensionsMac.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/ContextMenuExtensionsMac.cs
@@ -157,7 +157,8 @@ namespace MonoDevelop.Components
public NSContextMenuItem (string label, ContextMenuItem item) : base (label)
{
contextMenu = new WeakReference<ContextMenuItem> (item);
- this.Activated += OnActivated;
+ if (item.SubMenu == null || item.SubMenu.Items.Count == 0)
+ this.Activated += OnActivated;
}
static void OnActivated (object sender, EventArgs args)
@@ -195,6 +196,7 @@ namespace MonoDevelop.Components
public NSLocationAwareMenu (ContextMenu menu, Action closeHandler, NSLocationAwareMenu parent)
{
WeakDelegate = new ContextMenuDelegate (menu) { CloseHandler = closeHandler };
+
Parent = parent != null ? new WeakReference<NSLocationAwareMenu> (parent) : null;
}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/GtkUtil.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/GtkUtil.cs
index f1f8f2aea3..c3a176f3db 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/GtkUtil.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/GtkUtil.cs
@@ -945,12 +945,16 @@ namespace MonoDevelop.Components
{
TreeViewColumn col;
TreeView tree;
+ TreePath path;
TreeIter iter;
+ TreeStore treeStore;
public CellTooltipWindow (TreeView tree, TreeViewColumn col, TreePath path)
{
this.tree = tree;
this.col = col;
+ this.treeStore = tree.Model as TreeStore;
+ this.path = path;
NudgeHorizontal = true;
@@ -991,6 +995,12 @@ namespace MonoDevelop.Components
bool hasFgColor = false;
int x = 1;
+ // Make sure that the row has not been removed inbetween.
+ // If the model is a TreeStore, it can do the validation for us, otherwise we need to validate the path.
+ if ((treeStore != null && treeStore.IterIsValid (iter) == false) || !tree.Model.GetIter (out iter, path)) {
+ GtkUtil.HideTooltip (tree);
+ return true;
+ }
col.CellSetCellData (tree.Model, iter, false, false);
foreach (CellRenderer cr in col.CellRenderers) {
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Mac/MDMenu.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Mac/MDMenu.cs
index 8d2882e059..793ab813f3 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Mac/MDMenu.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Mac/MDMenu.cs
@@ -82,7 +82,7 @@ namespace MonoDevelop.Components.Mac
continue;
}
- Command cmd = manager.GetCommand (ce.CommandId);
+ Command cmd = ce.GetCommand (manager);
if (cmd == null) {
LoggingService.LogError ("MacMenu: '{0}' maps to null command", ce.CommandId);
continue;
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.CodeCompletion/CompletionController.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.CodeCompletion/CompletionController.cs
index 1263f0f5a7..00e5de7e0c 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.CodeCompletion/CompletionController.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.CodeCompletion/CompletionController.cs
@@ -1,4 +1,4 @@
-ο»Ώ//
+//
// CodeCompletionSession.cs
//
// Author:
@@ -32,6 +32,7 @@ using Gtk;
using MonoDevelop.Ide.Editor.Extension;
using Xwt.Drawing;
using MonoDevelop.Core;
+using MonoDevelop.Ide.Editor;
namespace MonoDevelop.Ide.CodeCompletion
{
@@ -205,7 +206,6 @@ namespace MonoDevelop.Ide.CodeCompletion
initialWordLength = CompletionWidget.SelectedLength > 0 ? 0 : text.Length;
StartOffset = CompletionWidget.CaretOffset - initialWordLength;
- HideWhenWordDeleted = initialWordLength != 0;
ResetSizes ();
UpdateWordSelection ();
@@ -259,7 +259,6 @@ namespace MonoDevelop.Ide.CodeCompletion
{
usingPreviewEntry = false;
previewCompletionEntryText = "";
- HideWhenWordDeleted = false;
SelectedItemCompletionText = null;
ResetViewState();
}
@@ -505,10 +504,6 @@ namespace MonoDevelop.Ide.CodeCompletion
get { return initialWordLength; }
}
- bool HideWhenWordDeleted {
- get; set;
- }
-
public CompletionTextEditorExtension Extension {
get;
set;
@@ -710,15 +705,7 @@ namespace MonoDevelop.Ide.CodeCompletion
set;
}
- int startOffset;
- internal int StartOffset {
- get {
- return startOffset;
- }
- set {
- startOffset = value;
- }
- }
+ internal int StartOffset { get; set; }
public int EndOffset {
get;
@@ -1058,13 +1045,10 @@ namespace MonoDevelop.Ide.CodeCompletion
public KeyActions PostProcessKey (KeyDescriptor descriptor)
{
- if (CompletionWidget == null || StartOffset > CompletionWidget.CaretOffset) {// CompletionWidget == null may happen in unit tests.
+ if (CompletionWidget == null) {// CompletionWidget == null may happen in unit tests.
return KeyActions.CloseWindow | KeyActions.Process;
}
- if (HideWhenWordDeleted && StartOffset >= CompletionWidget.CaretOffset) {
- return KeyActions.CloseWindow | KeyActions.Process;
- }
switch (descriptor.SpecialKey) {
case SpecialKey.BackSpace:
ResetSizes ();
@@ -1166,7 +1150,7 @@ namespace MonoDevelop.Ide.CodeCompletion
void UpdateLastWordChar ()
{
if (CompletionWidget != null)
- EndOffset = CompletionWidget.CaretOffset;
+ EndOffset = Math.Max (StartOffset, CompletionWidget.CaretOffset);
}
void SelectEntry (string s)
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.CodeCompletion/CompletionPresenterSession.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.CodeCompletion/CompletionPresenterSession.cs
deleted file mode 100644
index 8e760d05d1..0000000000
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.CodeCompletion/CompletionPresenterSession.cs
+++ /dev/null
@@ -1,92 +0,0 @@
-ο»Ώ//
-// CompletionPresenterSession.cs
-//
-// Author:
-// Mike KrΓΌger <mikkrg@microsoft.com>
-//
-// Copyright (c) 2017 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 System.Collections.Generic;
-using System.Collections.Immutable;
-using Microsoft.CodeAnalysis.Completion;
-using Microsoft.VisualStudio.Text;
-
-namespace MonoDevelop.Ide.CodeCompletion
-{
- abstract class CompletionPresenterSession
- {
- protected abstract RoslynCompletionData WrapItem (CompletionItem item);
-
- public void PresentItems (ITrackingSpan triggerSpan, IList<CompletionItem> items, CompletionItem selectedItem, CompletionItem suggestionModeItem, bool suggestionMode, bool isSoftSelected, ImmutableArray<CompletionItemFilter> completionItemFilters, string filterText)
- {
- var result = new CompletionDataList ();
-
- foreach (var item in items) {
- if (string.IsNullOrEmpty (item.DisplayText))
- continue;
- result.Add (WrapItem (item));
- }
- if (suggestionMode)
- result.AutoSelect = false;
- if (filterText != null)
- result.DefaultCompletionString = filterText;
- if (suggestionModeItem != null) {
- result.DefaultCompletionString = suggestionModeItem.DisplayText;
- result.AutoSelect = false;
- }
-
- if (selectedItem != null) {
- result.DefaultCompletionString = selectedItem.DisplayText;
- }
-
- // TODO: isSoftSelected
- // TODO: completionItemFilters
- var editor = IdeApp.Workbench.ActiveDocument.Editor;
- var widget = IdeApp.Workbench.ActiveDocument.GetContent<ICompletionWidget> ();
- CompletionWindowManager.ShowWindow (null, (char)0, result, widget, widget.CreateCodeCompletionContext (editor.CaretOffset));
- }
-
- public void SelectPreviousItem ()
- {
- CompletionWindowManager.PreProcessKeyEvent (Editor.Extension.KeyDescriptor.Up);
- }
-
- public void SelectNextItem ()
- {
- CompletionWindowManager.PreProcessKeyEvent (Editor.Extension.KeyDescriptor.Down);
- }
-
- public void SelectPreviousPageItem ()
- {
- CompletionWindowManager.PreProcessKeyEvent (Editor.Extension.KeyDescriptor.PageUp);
- }
-
- public void SelectNextPageItem ()
- {
- CompletionWindowManager.PreProcessKeyEvent (Editor.Extension.KeyDescriptor.PageDown);
- }
-
- // public event EventHandler<CompletionItemEventArgs> ItemSelected;
- // public event EventHandler<CompletionItemEventArgs> ItemCommitted;
- //public event EventHandler<CompletionItemFilterStateChangedEventArgs> FilterStateChanged;
- }
-}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.CodeCompletion/CompletionWindowManager.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.CodeCompletion/CompletionWindowManager.cs
index df602402bb..96dea0addf 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.CodeCompletion/CompletionWindowManager.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.CodeCompletion/CompletionWindowManager.cs
@@ -28,6 +28,7 @@ using System;
using MonoDevelop.Core;
using MonoDevelop.Ide.Gui.Content;
using MonoDevelop.Ide.Editor.Extension;
+using MonoDevelop.Ide.Editor;
namespace MonoDevelop.Ide.CodeCompletion
{
@@ -176,15 +177,29 @@ namespace MonoDevelop.Ide.CodeCompletion
return wnd.PreProcessKeyEvent (descriptor);
}
+ static bool isInUpdate;
public static void UpdateCursorPosition ()
{
if (!IsVisible)
return;
- if (wnd.IsInCompletion || isShowing)
+ if (wnd.IsInCompletion || isShowing || isInUpdate)
return;
- var caretOffset = wnd.CompletionWidget.CaretOffset;
- if (caretOffset < wnd.StartOffset || caretOffset > wnd.EndOffset + 1) {
- HideWindow ();
+ isInUpdate = true;
+ try {
+ var widget = wnd.CompletionWidget;
+ if (widget == null)
+ return;
+ var impl = widget as ITextEditorImpl;
+ if (impl != null)
+ impl.EnsureCaretIsNotVirtual ();
+ var caretOffset = widget.CaretOffset;
+ if (caretOffset < wnd.StartOffset || caretOffset > wnd.EndOffset + 1) {
+ HideWindow ();
+ }
+ if (impl != null)
+ impl.FixVirtualIndentation ();
+ } finally {
+ isInUpdate = false;
}
}
@@ -213,8 +228,9 @@ namespace MonoDevelop.Ide.CodeCompletion
public static void HideWindow ()
{
isShowing = false;
- if (IsVisible)
+ if (IsVisible) {
wnd.HideWindow ();
+ }
}
static void HandleWndVisibleChanged (object sender, EventArgs args)
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.CodeCompletion/RoslynCompletionData.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.CodeCompletion/RoslynCompletionData.cs
index f8dde4354a..0dd6926ff2 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.CodeCompletion/RoslynCompletionData.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.CodeCompletion/RoslynCompletionData.cs
@@ -82,22 +82,26 @@ namespace MonoDevelop.Ide.CodeCompletion
protected abstract string MimeType { get; }
public override IconId Icon {
- get {
- if (CompletionItem.Tags.Contains ("Snippet")) {
- var template = CodeTemplateService.GetCodeTemplates (MimeType).FirstOrDefault (t => t.Shortcut == CompletionItem.DisplayText);
- if (template != null)
- return template.Icon;
- }
- var modifier = GetItemModifier ();
- var type = GetItemType ();
- var hash = modifier | type << 16;
- if (!IconIdCache.ContainsKey (hash))
- IconIdCache [hash] = "md-" + modifierType[modifier] + completionType[type];
- return IconIdCache [hash];
+ get => GetIcon (CompletionItem, MimeType);
+ }
+
+
+ internal static string GetIcon (CompletionItem completionItem, string mimeType)
+ {
+ if (completionItem.Tags.Contains ("Snippet")) {
+ var template = CodeTemplateService.GetCodeTemplates (mimeType).FirstOrDefault (t => t.Shortcut == completionItem.DisplayText);
+ if (template != null)
+ return template.Icon;
}
+ var modifier = GetItemModifier (completionItem);
+ var type = GetItemType (completionItem);
+ var hash = modifier | type << 16;
+ if (!IconIdCache.ContainsKey (hash))
+ IconIdCache [hash] = "md-" + modifierType [modifier] + completionType [type];
+ return IconIdCache [hash];
}
- static Dictionary<int, string> IconIdCache = new Dictionary<int, string>();
+ static Dictionary<int, string> IconIdCache = new Dictionary<int, string> ();
public RoslynCompletionData (Microsoft.CodeAnalysis.Document document, ITextSnapshot triggerSnapshot, CompletionService completionService, CompletionItem completionItem)
{
@@ -121,7 +125,7 @@ namespace MonoDevelop.Ide.CodeCompletion
return null;
}
- string [] completionType = {
+ readonly static string [] completionType = {
"field",
"literal",
"variable",
@@ -140,7 +144,7 @@ namespace MonoDevelop.Ide.CodeCompletion
"extensionmethod"
};
- static Dictionary<string, int> roslynCompletionTypeTable = new Dictionary<string, int> {
+ readonly static Dictionary<string, int> roslynCompletionTypeTable = new Dictionary<string, int> {
{ "Field", 0 },
{ "Alias", 0 },
{ "ArrayType", 0 },
@@ -188,17 +192,17 @@ namespace MonoDevelop.Ide.CodeCompletion
{ "ExtensionMethod", 15 }
};
- int GetItemType ()
+ static int GetItemType (CompletionItem completionItem)
{
- foreach (var tag in CompletionItem.Tags) {
+ foreach (var tag in completionItem.Tags) {
if (roslynCompletionTypeTable.TryGetValue (tag, out int result))
return result;
}
- LoggingService.LogWarning ("RoslynCompletionData: Can't find item type '" + string.Join (",", CompletionItem.Tags) + "'");
+ LoggingService.LogWarning ("RoslynCompletionData: Can't find item type '" + string.Join (",", completionItem.Tags) + "'");
return 1;
}
- string[] modifierType = {
+ readonly static string [] modifierType = {
"",
"private-",
"ProtectedOrInternal-",
@@ -208,7 +212,7 @@ namespace MonoDevelop.Ide.CodeCompletion
};
- static Dictionary<string, int> modifierTypeTable = new Dictionary<string, int> {
+ readonly static Dictionary<string, int> modifierTypeTable = new Dictionary<string, int> {
{ "Private", 1 },
{ "ProtectedAndInternal", 2 },
{ "Protected", 3 },
@@ -216,9 +220,9 @@ namespace MonoDevelop.Ide.CodeCompletion
{ "ProtectedOrInternal", 5 }
};
- int GetItemModifier ()
+ static int GetItemModifier (CompletionItem completionItem)
{
- foreach (var tag in CompletionItem.Tags) {
+ foreach (var tag in completionItem.Tags) {
if (modifierTypeTable.TryGetValue (tag, out int result))
return result;
}
@@ -257,7 +261,7 @@ namespace MonoDevelop.Ide.CodeCompletion
editor.ReplaceText (mappedSpan.Start + 1, mappedSpan.Length - 1, completionChange.TextChange.NewText);
} else
editor.ReplaceText (mappedSpan.Start, mappedSpan.Length, completionChange.TextChange.NewText);
-
+
if (completionChange.NewPosition.HasValue)
editor.CaretOffset = completionChange.NewPosition.Value;
@@ -271,10 +275,23 @@ namespace MonoDevelop.Ide.CodeCompletion
protected abstract void Format (TextEditor editor, Gui.Document document, int start, int end);
- public override async Task<TooltipInformation> CreateTooltipInformation (bool smartWrap, CancellationToken cancelToken)
+ public override Task<TooltipInformation> CreateTooltipInformation (bool smartWrap, CancellationToken cancelToken)
+ {
+ return CreateTooltipInformation (doc, CompletionItem, smartWrap, cancelToken);
+ }
+
+ internal static async Task<TooltipInformation> CreateTooltipInformation (Microsoft.CodeAnalysis.Document doc, CompletionItem CompletionItem, bool smartWrap, CancellationToken cancelToken)
{
- var description = await Task.Run (() => completionService.GetDescriptionAsync (doc, CompletionItem)).ConfigureAwait (false);
- var markup = new StringBuilder ();
+ CompletionDescription description;
+ var completionService = doc.Project.Solution.Workspace.Services.GetLanguageServices (doc.Project.Language).GetService<CompletionService> ();
+ if (completionService == null)
+ return null;
+ if (CommonCompletionItem.HasDescription (CompletionItem)) {
+ description = CommonCompletionItem.GetDescription (CompletionItem);
+ } else {
+ description = await Task.Run (() => completionService.GetDescriptionAsync (doc, CompletionItem)).ConfigureAwait (false);
+ }
+ var markup = StringBuilderCache.Allocate ();
var theme = SyntaxHighlightingService.GetIdeFittingTheme (DefaultSourceEditorOptions.Instance.GetEditorTheme ());
var taggedParts = description.TaggedParts;
int i = 0;
@@ -294,9 +311,27 @@ namespace MonoDevelop.Ide.CodeCompletion
markup.Append ("</span>");
}
return new TooltipInformation {
- SignatureMarkup = markup.ToString ()
+ SignatureMarkup = StringBuilderCache.ReturnAndFree (markup)
};
}
- }
-}
+ public override bool IsCommitCharacter (char keyChar, string partialWord)
+ {
+ foreach (var rule in CompletionItem.Rules.CommitCharacterRules) {
+ switch (rule.Kind) {
+ case CharacterSetModificationKind.Add:
+ if (rule.Characters.Contains (keyChar))
+ return true;
+ continue;
+ case CharacterSetModificationKind.Remove:
+ if (rule.Characters.Contains (keyChar))
+ return false;
+ continue;
+ case CharacterSetModificationKind.Replace:
+ return rule.Characters.Contains (keyChar);
+ }
+ }
+ return base.IsCommitCharacter (keyChar, partialWord);
+ }
+ }
+} \ No newline at end of file
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.CodeTemplates/CodeTemplate.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.CodeTemplates/CodeTemplate.cs
index 02874129d6..1dc585dcf8 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.CodeTemplates/CodeTemplate.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.CodeTemplates/CodeTemplate.cs
@@ -244,7 +244,7 @@ namespace MonoDevelop.Ide.CodeTemplates
{
var expansion = CodeTemplateService.GetExpansionObject (this);
var result = new TemplateResult ();
- var sb = new StringBuilder ();
+ var sb = StringBuilderCache.Allocate ();
int lastOffset = 0;
string code = context.Editor.FormatString (context.InsertPosition, context.TemplateCode);
result.TextLinks = new List<TextLink> ();
@@ -339,7 +339,7 @@ namespace MonoDevelop.Ide.CodeTemplates
// format & indent template code
var data = TextEditorFactory.CreateNewDocument ();
- data.Text = sb.ToString ();
+ data.Text = StringBuilderCache.ReturnAndFree (sb);
data.TextChanged += delegate(object sender, MonoDevelop.Core.Text.TextChangeEventArgs e) {
for (int i = 0; i < e.TextChanges.Count; ++i) {
var change = e.TextChanges[i];
@@ -369,7 +369,7 @@ namespace MonoDevelop.Ide.CodeTemplates
public string IndentCode (string code, string eol, string indent)
{
- var result = new StringBuilder ();
+ var result = StringBuilderCache.Allocate ();
for (int i = 0; i < code.Length; i++) {
switch (code[i]) {
case '\r':
@@ -385,7 +385,7 @@ namespace MonoDevelop.Ide.CodeTemplates
break;
}
}
- return result.ToString ();
+ return StringBuilderCache.ReturnAndFree (result);
}
static void IndentCode (ITextDocument data, string lineIndent)
@@ -404,38 +404,38 @@ namespace MonoDevelop.Ide.CodeTemplates
while (i >= 0 && !Char.IsWhiteSpace (str[i])) {
i--;
}
- var indent = new StringBuilder ();
+ var indent = StringBuilderCache.Allocate ();
while (i >= 0 && (str[i] == ' ' || str[i] == '\t')) {
indent.Append (str[i]);
i--;
}
- return indent.ToString ();
+ return StringBuilderCache.ReturnAndFree (indent);
}
string RemoveIndent (string text, string indent)
{
var doc = TextEditorFactory.CreateNewDocument ();
doc.Text = text;
- var result = new StringBuilder ();
+ var result = StringBuilderCache.Allocate ();
foreach (var line in doc.GetLines ()) {
string curLineIndent = line.GetIndentation (doc);
int offset = Math.Min (curLineIndent.Length, indent.Length);
result.Append (doc.GetTextBetween (line.Offset + offset, line.EndOffsetIncludingDelimiter));
}
- return result.ToString ();
+ return StringBuilderCache.ReturnAndFree (result);
}
string Reindent (string text, string indent)
{
var doc = TextEditorFactory.CreateNewDocument ();
doc.Text = text;
- var result = new StringBuilder ();
+ var result = StringBuilderCache.Allocate ();
foreach (var line in doc.GetLines ()) {
if (result.Length > 0)
result.Append (indent);
result.Append (doc.GetTextAt (line.SegmentIncludingDelimiter));
}
- return result.ToString ();
+ return StringBuilderCache.ReturnAndFree (result);
}
public void Insert (MonoDevelop.Ide.Gui.Document document)
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.CodeTemplates/CodeTemplateService.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.CodeTemplates/CodeTemplateService.cs
index f8556dbc51..043c670ebe 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.CodeTemplates/CodeTemplateService.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.CodeTemplates/CodeTemplateService.cs
@@ -122,8 +122,8 @@ namespace MonoDevelop.Ide.CodeTemplates
{
var result = new CodeTemplate ();
result.Shortcut = setting.TabTrigger;
- var sb = new StringBuilder ();
- var nameBuilder = new StringBuilder ();
+ var sb = StringBuilderCache.Allocate ();
+ var nameBuilder = StringBuilderCache.Allocate ();
bool readDollar = false;
bool inBracketExpression = false;
bool inExpressionContent = false;
@@ -194,8 +194,8 @@ namespace MonoDevelop.Ide.CodeTemplates
nameBuilder.Length = 0;
inVariable = false;
}
-
- result.Code = sb.ToString ();
+ StringBuilderCache.Free (nameBuilder);
+ result.Code = StringBuilderCache.ReturnAndFree (sb);
result.CodeTemplateContext = CodeTemplateContext.Standard;
result.CodeTemplateType = CodeTemplateType.Expansion;
result.Description = setting.Name;
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Codons/ItemTemplateExtensionNode.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Codons/ItemTemplateExtensionNode.cs
new file mode 100644
index 0000000000..5da1f66ff8
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Codons/ItemTemplateExtensionNode.cs
@@ -0,0 +1,80 @@
+ο»Ώ//
+// ItemTemplateExtensionNode.cs
+//
+// Author:
+// Matt Ward <matt.ward@xamarin.com>
+//
+// Copyright (c) 2017 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
+// 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;
+
+namespace MonoDevelop.Ide.Codons
+{
+ [ExtensionNode (Description = "A file template")]
+ class ItemTemplateExtensionNode : ExtensionNode
+ {
+ [NodeAttribute ("path", "A .nupkg file or a folder.")]
+ string path;
+
+ public string ScanPath {
+ get {
+ return Addin.GetFilePath (path);
+ }
+ }
+
+ [NodeAttribute ("templateId", "Overrides the template id from the extension node id. Allows the same template to be used with different parameters.")]
+ string templateId;
+
+ public string TemplateId {
+ get {
+ return templateId ?? Id;
+ }
+ }
+
+ [NodeAttribute ("_overrideName", "Override name used in template.json file.", Localizable = true)]
+ string overrideName;
+
+ public string OverrideName {
+ get {
+ return overrideName;
+ }
+ }
+
+ [NodeAttribute ("defaultParameters", "Default parameters for template.")]
+ string defaultParameters;
+
+ public string DefaultParameters {
+ get {
+ return defaultParameters;
+ }
+ }
+
+ [NodeAttribute ("supportedParameters", "Parameters supported by the template.")]
+ string supportedParameters;
+
+ public string SupportedParameters {
+ get {
+ return supportedParameters;
+ }
+ }
+ }
+}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Composition/CommonEditorAssetServiceFactory.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Composition/CommonEditorAssetServiceFactory.cs
new file mode 100644
index 0000000000..d2e2fd09d9
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Composition/CommonEditorAssetServiceFactory.cs
@@ -0,0 +1,41 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.Composition;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Editor;
+using Microsoft.CodeAnalysis.Editor.Host;
+using Microsoft.CodeAnalysis.FindUsages;
+using Microsoft.CodeAnalysis.Text;
+using Microsoft.VisualStudio.Editor;
+using Microsoft.VisualStudio.Text;
+
+namespace MonoDevelop.Ide.Composition
+{
+ [Export (typeof (ICommonEditorAssetServiceFactory))]
+ internal class CommonEditorAssetServiceFactory : ICommonEditorAssetServiceFactory
+ {
+ public ICommonEditorAssetService GetOrCreate (ITextBuffer textBuffer)
+ {
+ return new CommonEditorAssetService (textBuffer);
+ }
+ }
+
+ public class CommonEditorAssetService : ICommonEditorAssetService
+ {
+ private ITextBuffer textBuffer;
+
+ public CommonEditorAssetService (ITextBuffer textBuffer)
+ {
+ this.textBuffer = textBuffer;
+ }
+
+ public T FindAsset<T> (Predicate<ICommonEditorAssetMetadata> isMatch = null) where T : class
+ {
+ return default(T);
+ }
+ }
+}
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 70ac6f0610..5f4a061be3 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Composition/CompositionManager.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Composition/CompositionManager.cs
@@ -128,21 +128,25 @@ namespace MonoDevelop.Ide.Composition
var discoveryErrors = catalog.DiscoveredParts.DiscoveryErrors;
if (!discoveryErrors.IsEmpty) {
- throw new ApplicationException ($"MEF catalog scanning errors encountered.\n{string.Join ("\n", discoveryErrors)}");
+ foreach (var error in discoveryErrors) {
+ LoggingService.LogInfo ("MEF discovery error", error);
+ }
+
+ // throw new ApplicationException ("MEF discovery errors");
}
CompositionConfiguration configuration = CompositionConfiguration.Create (catalog);
- if (!configuration.CompositionErrors.IsEmpty) {
- // capture the errors in an array for easier debugging
- var errors = configuration.CompositionErrors.ToArray ();
+ if (!configuration.CompositionErrors.IsEmpty) {
+ // capture the errors in an array for easier debugging
+ var errors = configuration.CompositionErrors.SelectMany (e => e).ToArray ();
+ foreach (var error in errors) {
+ LoggingService.LogInfo ("MEF composition error: " + error.Message);
+ }
// For now while we're still transitioning to VSMEF it's useful to work
// even if the composition has some errors. TODO: re-enable this.
- //var messages = errors.SelectMany (e => e).Select (e => e.Message);
- //var text = string.Join (Environment.NewLine, messages);
- //Xwt.Clipboard.SetText (text);
- //configuration.ThrowOnErrors ();
+ //configuration.ThrowOnErrors ();
}
RuntimeComposition = RuntimeComposition.CreateRuntimeComposition (configuration);
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Composition/InlineRenameService.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Composition/InlineRenameService.cs
new file mode 100644
index 0000000000..a13d665518
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Composition/InlineRenameService.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.Composition;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Editor;
+using Microsoft.CodeAnalysis.Text;
+
+namespace MonoDevelop.Ide.Composition
+{
+ [Export(typeof(IInlineRenameService))]
+ internal class InlineRenameService : IInlineRenameService
+ {
+ public IInlineRenameSession ActiveSession => null;
+
+ public InlineRenameSessionInfo StartInlineSession (Document document, TextSpan triggerSpan, CancellationToken cancellationToken = default (CancellationToken))
+ {
+ throw new NotImplementedException ();
+ }
+ }
+}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Composition/JoinableTaskContextHost.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Composition/JoinableTaskContextHost.cs
index 303b5a01f3..cd0b7f82b2 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Composition/JoinableTaskContextHost.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Composition/JoinableTaskContextHost.cs
@@ -43,10 +43,7 @@ namespace MonoDevelop.Ide.Composition
[ImportingConstructor]
public JoinableTaskContextHost ()
{
- Runtime.RunInMainThread (() => {
- var joinableTaskContext = new JoinableTaskContext ();
- this.JoinableTaskContext = joinableTaskContext;
- });
+ JoinableTaskContext = new JoinableTaskContext (Runtime.MainThread, Runtime.MainSynchronizationContext);
}
}
}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Composition/PlatformCatalog.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Composition/PlatformCatalog.cs
index c0148e3a65..2e8163e388 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Composition/PlatformCatalog.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Composition/PlatformCatalog.cs
@@ -94,7 +94,7 @@ namespace Microsoft.VisualStudio.Platform
return mimeType;
}
- return null;
+ return (ContentTypeRegistryService as IContentTypeRegistryService2).GetMimeType (type);
}
public IContentType GetContentType(string type)
@@ -105,7 +105,7 @@ namespace Microsoft.VisualStudio.Platform
return contentType;
}
- return null;
+ return (ContentTypeRegistryService as IContentTypeRegistryService2).GetContentTypeForMimeType (type);
}
public void LinkTypes(string mimeType, IContentType contentType)
@@ -136,14 +136,6 @@ namespace Microsoft.VisualStudio.Platform
{
LinkTypes ("text/plain", "text");
LinkTypes ("text/x-csharp", "csharp");
-
- if (this.ContentTypeRegistryService.GetContentType ("css") != null) {
- LinkTypes ("text/x-css", "css");
- LinkTypes ("text/x-less-web", "LESS");
- LinkTypes ("text/x-scss-web", "SCSS");
- LinkTypes ("text/x-html", "htmlx");
- LinkTypes ("text/x-json", "JSON");
- }
}
Tuple<ImmutableDictionary<string, IContentType>, ImmutableDictionary<IContentType, string>> maps = Tuple.Create(ImmutableDictionary<string, IContentType>.Empty, ImmutableDictionary<IContentType, string>.Empty);
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Composition/StreamingFindUsagesPresenter.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Composition/StreamingFindUsagesPresenter.cs
new file mode 100644
index 0000000000..bc0c1a1dfc
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Composition/StreamingFindUsagesPresenter.cs
@@ -0,0 +1,29 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.Composition;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Editor;
+using Microsoft.CodeAnalysis.Editor.Host;
+using Microsoft.CodeAnalysis.FindUsages;
+using Microsoft.CodeAnalysis.Text;
+
+namespace MonoDevelop.Ide.Composition
+{
+ [Export (typeof (IStreamingFindUsagesPresenter))]
+ internal class StreamingFindUsagesPresenter : IStreamingFindUsagesPresenter
+ {
+ public void ClearAll ()
+ {
+ throw new NotImplementedException ();
+ }
+
+ public FindUsagesContext StartSearch (string title, bool supportsReferences)
+ {
+ throw new NotImplementedException ();
+ }
+ }
+}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Desktop/PlatformService.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Desktop/PlatformService.cs
index 486c780048..137851a310 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Desktop/PlatformService.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Desktop/PlatformService.cs
@@ -34,6 +34,9 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Text.RegularExpressions;
+using Microsoft.VisualStudio.Platform;
+using Microsoft.VisualStudio.Utilities;
+
using Mono.Addins;
using MonoDevelop.Core;
using Mono.Unix;
@@ -41,8 +44,8 @@ using MonoDevelop.Ide.Extensions;
using MonoDevelop.Core.Execution;
using MonoDevelop.Components;
using MonoDevelop.Components.MainToolbar;
-
-
+using MonoDevelop.Ide.Composition;
+
namespace MonoDevelop.Ide.Desktop
{
public abstract class PlatformService
@@ -296,6 +299,23 @@ namespace MonoDevelop.Ide.Desktop
MimeTypeNode FindMimeTypeForFile (string fileName)
{
+ IFilePathRegistryService filePathRegistryService = CompositionManager.GetExportedValue<IFilePathRegistryService> ();
+
+ try {
+ IContentType contentType = filePathRegistryService.GetContentTypeForPath (fileName);
+ if (contentType != PlatformCatalog.Instance.ContentTypeRegistryService.UnknownContentType) {
+ string mimeType = PlatformCatalog.Instance.MimeToContentTypeRegistryService.GetMimeType (contentType);
+ if (mimeType != null) {
+ MimeTypeNode mt = FindMimeType (mimeType);
+ if (mt != null) {
+ return mt;
+ }
+ }
+ }
+ } catch (Exception ex) {
+ LoggingService.LogError ("IFilePathRegistryService query failed", ex);
+ }
+
foreach (MimeTypeNode mt in mimeTypeNodes) {
if (mt.SupportsFile (fileName))
return mt;
@@ -560,6 +580,11 @@ namespace MonoDevelop.Ide.Desktop
}
public static bool AccessibilityInUse { get; protected set; }
+
+ internal virtual string GetNativeRuntimeDescription ()
+ {
+ return null;
+ }
}
}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Extension/CompletionTextEditorExtension.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Extension/CompletionTextEditorExtension.cs
index 9eda1df61f..76d02a6bfa 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Extension/CompletionTextEditorExtension.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Extension/CompletionTextEditorExtension.cs
@@ -25,8 +25,8 @@
//
//
-
using System;
+using System.Collections.Generic;
using MonoDevelop.Projects;
using MonoDevelop.Ide.CodeCompletion;
using MonoDevelop.Components.Commands;
@@ -191,8 +191,11 @@ namespace MonoDevelop.Ide.Editor.Extension
completionTokenSrc = new CancellationTokenSource ();
var caretOffset = Editor.CaretOffset;
var token = completionTokenSrc.Token;
+
+ var metadata = new Dictionary<string, string> ();
+ metadata ["Result"] = "Success";
try {
- Counters.ProcessCodeCompletion.BeginTiming ();
+ Counters.ProcessCodeCompletion.BeginTiming (metadata);
var task = DoHandleCodeCompletionAsync (CurrentCompletionContext, new CompletionTriggerInfo (CompletionTriggerReason.CharTyped, descriptor.KeyChar), token);
if (task != null) {
// Show the completion window in two steps. The call to PrepareShowWindow creates the window but
@@ -225,6 +228,9 @@ namespace MonoDevelop.Ide.Editor.Extension
CurrentCompletionContext = null;
}
} finally {
+ if (token.IsCancellationRequested) {
+ metadata ["Result"] = "UserCancel";
+ }
Counters.ProcessCodeCompletion.EndTiming ();
}
}, Runtime.MainTaskScheduler);
@@ -233,10 +239,13 @@ namespace MonoDevelop.Ide.Editor.Extension
Counters.ProcessCodeCompletion.EndTiming ();
}
} catch (TaskCanceledException) {
+ metadata ["Result"] = "UserCancel";
Counters.ProcessCodeCompletion.EndTiming ();
} catch (AggregateException) {
+ metadata ["Result"] = "Failure";
Counters.ProcessCodeCompletion.EndTiming ();
} catch {
+ metadata ["Result"] = "Failure";
Counters.ProcessCodeCompletion.EndTiming ();
throw;
}
@@ -260,8 +269,11 @@ namespace MonoDevelop.Ide.Editor.Extension
completionTokenSrc = new CancellationTokenSource ();
var caretOffset = Editor.CaretOffset;
var token = completionTokenSrc.Token;
+
+ var metadata = new Dictionary<string, string> ();
+ metadata ["Result"] = "Success";
try {
- Counters.ProcessCodeCompletion.BeginTiming ();
+ Counters.ProcessCodeCompletion.BeginTiming (metadata);
var task = DoHandleCodeCompletionAsync (CurrentCompletionContext, new CompletionTriggerInfo (CompletionTriggerReason.BackspaceOrDeleteCommand, deleteOrBackspaceTriggerChar), token);
if (task != null) {
// Show the completion window in two steps. The call to PrepareShowWindow creates the window but
@@ -299,6 +311,9 @@ namespace MonoDevelop.Ide.Editor.Extension
CurrentCompletionContext = null;
}
} finally {
+ if (token.IsCancellationRequested) {
+ metadata ["Result"] = "UserCancel";
+ }
Counters.ProcessCodeCompletion.EndTiming ();
}
}, Runtime.MainTaskScheduler);
@@ -307,11 +322,14 @@ namespace MonoDevelop.Ide.Editor.Extension
}
} catch (TaskCanceledException) {
CurrentCompletionContext = null;
+ metadata ["Result"] = "UserCancel";
Counters.ProcessCodeCompletion.EndTiming ();
} catch (AggregateException) {
CurrentCompletionContext = null;
+ metadata ["Result"] = "Failure";
Counters.ProcessCodeCompletion.EndTiming ();
} catch {
+ metadata ["Result"] = "Failure";
Counters.ProcessCodeCompletion.EndTiming ();
throw;
}
@@ -429,8 +447,11 @@ namespace MonoDevelop.Ide.Editor.Extension
CurrentCompletionContext = CompletionWidget.CreateCodeCompletionContext (cpos);
CurrentCompletionContext.TriggerWordLength = wlen;
+
+ var metadata = new Dictionary<string, string> ();
+ metadata ["Result"] = "Success";
try {
- Counters.ProcessCodeCompletion.BeginTiming ();
+ Counters.ProcessCodeCompletion.BeginTiming (metadata);
completionList = await DoHandleCodeCompletionAsync (CurrentCompletionContext, new CompletionTriggerInfo (reason), token);
if (completionList != null && completionList.TriggerWordStart >= 0) {
CurrentCompletionContext.TriggerOffset = completionList.TriggerWordStart;
@@ -439,6 +460,9 @@ namespace MonoDevelop.Ide.Editor.Extension
if (completionList == null || !CompletionWindowManager.ShowWindow (this, (char)0, completionList, CompletionWidget, CurrentCompletionContext)) {
CurrentCompletionContext = null;
}
+ } catch (Exception) {
+ metadata ["Result"] = "Failure";
+ throw;
} finally {
Counters.ProcessCodeCompletion.EndTiming ();
}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Extension/HighlightUrlExtension.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Extension/HighlightUrlExtension.cs
index 17b1e8cec4..8fc4366b7a 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Extension/HighlightUrlExtension.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Extension/HighlightUrlExtension.cs
@@ -108,7 +108,7 @@ namespace MonoDevelop.Ide.Editor.Extension
var matches = new List<(UrlType, Match, IDocumentLine)> ();
var line = startLine;
int o = 0;
- while (line != null && line.Offset < endOffset) {
+ while (line != null && line.Offset <= endOffset) {
if (token.IsCancellationRequested)
return;
string lineText = input.GetTextAt (line.Offset, line.Length);
@@ -143,7 +143,7 @@ namespace MonoDevelop.Ide.Editor.Extension
if (token.IsCancellationRequested)
return;
line = startLine;
- while (line != null && line.Offset < endOffset) {
+ while (line != null && line.Offset <= endOffset) {
foreach (var u in Editor.GetLineMarkers (line).OfType<IUrlTextLineMarker> ()) {
Editor.RemoveMarker (u);
markers.Remove (u);
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Extension/LineSeparatorTextEditorExtension.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Extension/LineSeparatorTextEditorExtension.cs
index 9cef24e485..6565d9fdeb 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Extension/LineSeparatorTextEditorExtension.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Extension/LineSeparatorTextEditorExtension.cs
@@ -31,6 +31,7 @@ using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Text;
using Microsoft.CodeAnalysis.Editor;
+using MonoDevelop.Core;
namespace MonoDevelop.Ide.Editor.Extension
{
@@ -84,24 +85,23 @@ namespace MonoDevelop.Ide.Editor.Extension
src = new CancellationTokenSource ();
if (!enabled)
return;
- var token = src.Token;
-
- var lineSeparatorService = DocumentContext?.RoslynWorkspace?.Services.GetLanguageServices (DocumentContext.AnalysisDocument.Project.Language).GetService<ILineSeparatorService> ();
+ var analysisDocument = DocumentContext?.AnalysisDocument;
+ if (analysisDocument == null)
+ return;
+ var lineSeparatorService = DocumentContext?.RoslynWorkspace?.Services.GetLanguageServices (analysisDocument.Project.Language).GetService<ILineSeparatorService> ();
if (lineSeparatorService == null)
return;
- var separators = await lineSeparatorService.GetLineSeparatorsAsync (DocumentContext.AnalysisDocument, new TextSpan (0, Editor.Length), token);
+ var token = src.Token;
+ var separators = await lineSeparatorService.GetLineSeparatorsAsync (analysisDocument, new TextSpan (0, Editor.Length), token);
if (token.IsCancellationRequested)
return;
- var newMarkers = new List<ITextLineMarker> ();
+ RemoveMarkers ();
foreach (var s in separators) {
var line = Editor.GetLineByOffset (s.Start);
var marker = Editor.TextMarkerFactory.CreateLineSeparatorMarker (Editor);
Editor.AddMarker (line, marker);
- newMarkers.Add (marker);
+ markers.Add (marker);
}
-
- RemoveMarkers ();
- markers = newMarkers;
}
void RemoveMarkers ()
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/EditorThemeColors.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/EditorThemeColors.cs
index 2ab3563dbf..2dfdc6e619 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/EditorThemeColors.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/EditorThemeColors.cs
@@ -139,22 +139,45 @@ namespace MonoDevelop.Ide.Editor.Highlighting
public static readonly string UserTypesDelegates = "entity.name.delegate";
public static readonly string UserTypesMutable = "entity.name.mutable";
+ public static readonly string UserField = "entity.name.field";
+ [Obsolete ("Use UserField")]
public static readonly string UserFieldDeclaration = "entity.name.field";
- public static readonly string UserFieldUsage = "entity.name.field.usage";
+ [Obsolete ("Use UserField")]
+ public static readonly string UserFieldUsage = "entity.name.field";
+ public static readonly string UserEnumMember = "entity.name.enummember";
+ public static readonly string UserConstant = "entity.name.constant";
+
+ public static readonly string UserProperty = "entity.name.property";
+ [Obsolete ("Use UserProperty")]
public static readonly string UserPropertyDeclaration = "entity.name.property";
- public static readonly string UserPropertyUsage = "entity.name.property.usage";
+ [Obsolete ("Use UserProperty")]
+ public static readonly string UserPropertyUsage = "entity.name.property";
+
+ public static readonly string UserEvent = "entity.name.event";
+ [Obsolete ("Use UserEvent")]
public static readonly string UserEventDeclaration = "entity.name.event";
+ [Obsolete ("Use UserEvent")]
public static readonly string UserEventUsage = "entity.name.event.usage";
+ public static readonly string UserMethod = "entity.name.function";
+ public static readonly string UserExtensionMethod = "entity.name.extensionmethod";
+ [Obsolete ("Use UserMethod")]
public static readonly string UserMethodDeclaration = "entity.name.function";
+ [Obsolete ("Use UserMethod")]
public static readonly string UserMethodUsage = "entity.name.function.usage";
+ public static readonly string UserParameter = "entity.name.parameter";
+ [Obsolete ("Use UserParameter")]
public static readonly string UserParameterDeclaration = "entity.name.parameter";
+ [Obsolete ("Use UserParameter")]
public static readonly string UserParameterUsage = "entity.name.parameter.usage";
+ public static readonly string UserLocal = "entity.name.local";
+ [Obsolete ("Use UserLocal")]
public static readonly string UserVariableDeclaration = "entity.name.local";
+ [Obsolete ("Use UserLocal")]
public static readonly string UserVariableUsage = "entity.name.local.usage";
}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/Formats/OldFormat.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/Formats/OldFormat.cs
index 09675a6a12..91ddd3b9db 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/Formats/OldFormat.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/Formats/OldFormat.cs
@@ -33,6 +33,7 @@ using System.Xml.XPath;
using System.Reflection;
using System.Text;
using System.Xml;
+using MonoDevelop.Core;
using MonoDevelop.Components;
using MonoDevelop.Core.Text;
using System.Collections.Immutable;
@@ -77,7 +78,7 @@ namespace MonoDevelop.Ide.Editor.Highlighting
};
if (style.FontStyle != Xwt.Drawing.FontStyle.Normal ||
style.FontWeight != Xwt.Drawing.FontWeight.Normal) {
- var fontStyle = new StringBuilder ();
+ var fontStyle = StringBuilderCache.Allocate ();
if (style.FontStyle != Xwt.Drawing.FontStyle.Normal) {
fontStyle.Append (style.FontStyle.ToString ().ToLower ());
fontStyle.Append (" ");
@@ -85,7 +86,7 @@ namespace MonoDevelop.Ide.Editor.Highlighting
if (style.FontWeight != Xwt.Drawing.FontWeight.Normal) {
fontStyle.Append (style.FontWeight.ToString ().ToLower ());
}
- result ["fontStyle"] = fontStyle.ToString ();
+ result ["fontStyle"] = StringBuilderCache.ReturnAndFree (fontStyle);
}
return result;
}
@@ -258,18 +259,16 @@ namespace MonoDevelop.Ide.Editor.Highlighting
settings.Add (new ThemeSetting ("User Types(Delegates)", new List<string> { EditorThemeColors.UserTypesDelegates }, ConvertChunkStyle (colorScheme.UserTypesDelegates)));
settings.Add (new ThemeSetting ("User Types(Mutable)", new List<string> { EditorThemeColors.UserTypesMutable }, ConvertChunkStyle (colorScheme.UserTypesMutable)));
- settings.Add (new ThemeSetting ("User Field(Declaration)", new List<string> { EditorThemeColors.UserFieldDeclaration }, ConvertChunkStyle (colorScheme.UserFieldDeclaration)));
- settings.Add (new ThemeSetting ("User Field(Usage)", new List<string> { EditorThemeColors.UserFieldUsage }, ConvertChunkStyle (colorScheme.UserFieldUsage)));
- settings.Add (new ThemeSetting ("User Property(Declaration)", new List<string> { EditorThemeColors.UserPropertyDeclaration }, ConvertChunkStyle (colorScheme.UserPropertyDeclaration)));
- settings.Add (new ThemeSetting ("User Property(Usage)", new List<string> { EditorThemeColors.UserPropertyUsage }, ConvertChunkStyle (colorScheme.UserPropertyUsage)));
- settings.Add (new ThemeSetting ("User Event(Declaration)", new List<string> { EditorThemeColors.UserEventDeclaration }, ConvertChunkStyle (colorScheme.UserEventDeclaration)));
- settings.Add (new ThemeSetting ("User Event(Usage)", new List<string> { EditorThemeColors.UserEventUsage }, ConvertChunkStyle (colorScheme.UserEventUsage)));
- settings.Add (new ThemeSetting ("User Method(Declaration)", new List<string> { EditorThemeColors.UserMethodDeclaration }, ConvertChunkStyle (colorScheme.UserMethodDeclaration)));
- settings.Add (new ThemeSetting ("User Method(Usage)", new List<string> { EditorThemeColors.UserMethodUsage }, ConvertChunkStyle (colorScheme.UserMethodUsage)));
- settings.Add (new ThemeSetting ("User Parameter(Declaration)", new List<string> { EditorThemeColors.UserParameterDeclaration }, ConvertChunkStyle (colorScheme.UserParameterDeclaration)));
- settings.Add (new ThemeSetting ("User Parameter(Usage)", new List<string> { EditorThemeColors.UserParameterUsage }, ConvertChunkStyle (colorScheme.UserParameterUsage)));
- settings.Add (new ThemeSetting ("User Variable(Declaration)", new List<string> { EditorThemeColors.UserVariableDeclaration }, ConvertChunkStyle (colorScheme.UserVariableDeclaration)));
- settings.Add (new ThemeSetting ("User Variable(Usage)", new List<string> { EditorThemeColors.UserVariableUsage }, ConvertChunkStyle (colorScheme.UserVariableUsage)));
+ settings.Add (new ThemeSetting ("User Field", new List<string> { EditorThemeColors.UserField }, ConvertChunkStyle (colorScheme.UserFieldDeclaration)));
+ settings.Add (new ThemeSetting ("User Enum Member", new List<string> { EditorThemeColors.UserField }, ConvertChunkStyle (colorScheme.UserFieldDeclaration)));
+ settings.Add (new ThemeSetting ("User Constant", new List<string> { EditorThemeColors.UserConstant }, ConvertChunkStyle (colorScheme.UserFieldDeclaration)));
+
+ settings.Add (new ThemeSetting ("User Property", new List<string> { EditorThemeColors.UserProperty }, ConvertChunkStyle (colorScheme.UserPropertyDeclaration)));
+ settings.Add (new ThemeSetting ("User Event", new List<string> { EditorThemeColors.UserEvent }, ConvertChunkStyle (colorScheme.UserEventDeclaration)));
+ settings.Add (new ThemeSetting ("User Method", new List<string> { EditorThemeColors.UserMethod }, ConvertChunkStyle (colorScheme.UserMethodDeclaration)));
+ settings.Add (new ThemeSetting ("User Extension Method", new List<string> { EditorThemeColors.UserExtensionMethod }, ConvertChunkStyle (colorScheme.UserMethodDeclaration)));
+ settings.Add (new ThemeSetting ("User Parameter", new List<string> { EditorThemeColors.UserParameter }, ConvertChunkStyle (colorScheme.UserParameterDeclaration)));
+ settings.Add (new ThemeSetting ("User Variable", new List<string> { EditorThemeColors.UserLocal }, ConvertChunkStyle (colorScheme.UserVariableDeclaration)));
settings.Add (new ThemeSetting ("CSS Comment", new List<string> { "comment.block.css" }, ConvertChunkStyle (colorScheme.CssComment)));
settings.Add (new ThemeSetting ("CSS Keyword", new List<string> { "keyword.other.css" }, ConvertChunkStyle (colorScheme.CssKeyword)));
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/ISyntaxHighlighting.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/ISyntaxHighlighting.cs
index 34b6f7d4f3..215e49ba47 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/ISyntaxHighlighting.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/ISyntaxHighlighting.cs
@@ -31,6 +31,7 @@ using MonoDevelop.Core.Text;
using System.Collections.Immutable;
using System.Threading.Tasks;
using System.Threading;
+using System.Linq;
namespace MonoDevelop.Ide.Editor.Highlighting
{
@@ -41,6 +42,20 @@ namespace MonoDevelop.Ide.Editor.Highlighting
/// The segment offsets are 0 at line start regardless of where the line is inside the document.
/// </summary>
public IReadOnlyList<ColoredSegment> Segments { get; private set; }
+
+ bool? isContinuedBeyondLineEnd;
+ public bool? IsContinuedBeyondLineEnd {
+ get {
+ if (isContinuedBeyondLineEnd.HasValue)
+ return isContinuedBeyondLineEnd.Value;
+ var result = Segments.Count > 0 ? TextSegment.Length < Segments.Last ().EndOffset : false;
+ return isContinuedBeyondLineEnd = result;
+ }
+ set {
+ isContinuedBeyondLineEnd = value;
+ }
+ }
+
public HighlightedLine (ISegment textSegment, IReadOnlyList<ColoredSegment> segments)
{
TextSegment = textSegment;
@@ -89,4 +104,4 @@ namespace MonoDevelop.Ide.Editor.Highlighting
{
}
}
-} \ No newline at end of file
+}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/PObject.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/PObject.cs
index 865191b39d..b4616c511c 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/PObject.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/PObject.cs
@@ -887,13 +887,13 @@ namespace MonoDevelop.Ide.Editor.Highlighting
public string ToStringList ()
{
- var sb = new StringBuilder ();
+ var sb = StringBuilderCache.Allocate ();
foreach (PString str in list.OfType<PString> ()) {
if (sb.Length > 0)
sb.Append (", ");
sb.Append (str);
}
- return sb.ToString ();
+ return StringBuilderCache.ReturnAndFree (sb);
}
public IEnumerator<PObject> GetEnumerator ()
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/RoslynClassificationHighlighting.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/RoslynClassificationHighlighting.cs
index 15c2b91a0a..6c3b47eb9d 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/RoslynClassificationHighlighting.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/RoslynClassificationHighlighting.cs
@@ -58,56 +58,79 @@ namespace MonoDevelop.Ide.Editor.Highlighting
this.defaultScope = new ScopeStack (defaultScope);
this.userScope = this.defaultScope.Push (EditorThemeColors.UserTypes);
- classificationMap = new Dictionary<string, ScopeStack> {
- [ClassificationTypeNames.Comment] = MakeScope ("comment." + defaultScope),
- [ClassificationTypeNames.ExcludedCode] = MakeScope ("comment.excluded." + defaultScope),
- [ClassificationTypeNames.Identifier] = MakeScope (defaultScope),
- [ClassificationTypeNames.Keyword] = MakeScope ("keyword." + defaultScope),
- [ClassificationTypeNames.NumericLiteral] = MakeScope ("constant.numeric." + defaultScope),
- [ClassificationTypeNames.Operator] = MakeScope (defaultScope),
- [ClassificationTypeNames.PreprocessorKeyword] = MakeScope ("meta.preprocessor." + defaultScope),
- [ClassificationTypeNames.StringLiteral] = MakeScope ("string." + defaultScope),
- [ClassificationTypeNames.WhiteSpace] = MakeScope ("text." + defaultScope),
- [ClassificationTypeNames.Text] = MakeScope ("text." + defaultScope),
-
- [ClassificationTypeNames.PreprocessorText] = MakeScope ("meta.preprocessor.region.name." + defaultScope),
- [ClassificationTypeNames.Punctuation] = MakeScope ("punctuation." + defaultScope),
- [ClassificationTypeNames.VerbatimStringLiteral] = MakeScope ("string.verbatim." + defaultScope),
-
- [ClassificationTypeNames.ClassName] = MakeScope ("entity.name.class." + defaultScope),
- [ClassificationTypeNames.DelegateName] = MakeScope ("entity.name.delegate." + defaultScope),
- [ClassificationTypeNames.EnumName] = MakeScope ("entity.name.enum." + defaultScope),
- [ClassificationTypeNames.InterfaceName] = MakeScope ("entity.name.interface." + defaultScope),
- [ClassificationTypeNames.ModuleName] = MakeScope ("entity.name.module." + defaultScope),
- [ClassificationTypeNames.StructName] = MakeScope ("entity.name.struct." + defaultScope),
- [ClassificationTypeNames.TypeParameterName] = MakeScope ("entity.name.typeparameter." + defaultScope),
-
- [ClassificationTypeNames.XmlDocCommentAttributeName] = MakeScope ("comment.line.documentation." + defaultScope),
- [ClassificationTypeNames.XmlDocCommentAttributeQuotes] = MakeScope ("comment.line.documentation." + defaultScope),
- [ClassificationTypeNames.XmlDocCommentAttributeValue] = MakeScope ("comment.line.documentation." + defaultScope),
- [ClassificationTypeNames.XmlDocCommentCDataSection] = MakeScope ("comment.line.documentation." + defaultScope),
- [ClassificationTypeNames.XmlDocCommentComment] = MakeScope ("comment.line.documentation." + defaultScope),
- [ClassificationTypeNames.XmlDocCommentDelimiter] = MakeScope ("comment.line.documentation." + defaultScope),
- [ClassificationTypeNames.XmlDocCommentEntityReference] = MakeScope ("comment.line.documentation." + defaultScope),
- [ClassificationTypeNames.XmlDocCommentName] = MakeScope ("comment.line.documentation." + defaultScope),
- [ClassificationTypeNames.XmlDocCommentProcessingInstruction] = MakeScope ("comment.line.documentation." + defaultScope),
- [ClassificationTypeNames.XmlDocCommentText] = MakeScope ("comment.line.documentation." + defaultScope),
-
- [ClassificationTypeNames.XmlLiteralAttributeName] = MakeScope ("entity.other.attribute-name." + defaultScope),
- [ClassificationTypeNames.XmlLiteralAttributeQuotes] = MakeScope ("punctuation.definition.string." + defaultScope),
- [ClassificationTypeNames.XmlLiteralAttributeValue] = MakeScope ("string.quoted." + defaultScope),
- [ClassificationTypeNames.XmlLiteralCDataSection] = MakeScope ("text." + defaultScope),
- [ClassificationTypeNames.XmlLiteralComment] = MakeScope ("comment.block." + defaultScope),
- [ClassificationTypeNames.XmlLiteralDelimiter] = MakeScope (defaultScope),
- [ClassificationTypeNames.XmlLiteralEmbeddedExpression] = MakeScope (defaultScope),
- [ClassificationTypeNames.XmlLiteralEntityReference] = MakeScope (defaultScope),
- [ClassificationTypeNames.XmlLiteralName] = MakeScope ("entity.name.tag.localname." + defaultScope),
- [ClassificationTypeNames.XmlLiteralProcessingInstruction] = MakeScope (defaultScope),
- [ClassificationTypeNames.XmlLiteralText] = MakeScope ("text." + defaultScope),
+ classificationMap = GetClassificationMap (defaultScope);
+ }
+ static ImmutableDictionary<string, Dictionary<string, ScopeStack>> classificationMapCache = ImmutableDictionary<string, Dictionary<string, ScopeStack>>.Empty;
+
+ public static Dictionary<string, ScopeStack> GetClassificationMap (string scope)
+ {
+ Dictionary<string, ScopeStack> result;
+ if (classificationMapCache.TryGetValue (scope, out result))
+ return result;
+ var defaultScopeStack = new ScopeStack (scope);
+ result = new Dictionary<string, ScopeStack> {
+ [ClassificationTypeNames.Comment] = MakeScope (defaultScopeStack, "comment." + scope),
+ [ClassificationTypeNames.ExcludedCode] = MakeScope (defaultScopeStack, "comment.excluded." + scope),
+ [ClassificationTypeNames.Identifier] = MakeScope (defaultScopeStack, scope),
+ [ClassificationTypeNames.Keyword] = MakeScope (defaultScopeStack, "keyword." + scope),
+ [ClassificationTypeNames.NumericLiteral] = MakeScope (defaultScopeStack, "constant.numeric." + scope),
+ [ClassificationTypeNames.Operator] = MakeScope (defaultScopeStack, scope),
+ [ClassificationTypeNames.PreprocessorKeyword] = MakeScope (defaultScopeStack, "meta.preprocessor." + scope),
+ [ClassificationTypeNames.StringLiteral] = MakeScope (defaultScopeStack, "string." + scope),
+ [ClassificationTypeNames.WhiteSpace] = MakeScope (defaultScopeStack, "text." + scope),
+ [ClassificationTypeNames.Text] = MakeScope (defaultScopeStack, "text." + scope),
+
+ [ClassificationTypeNames.PreprocessorText] = MakeScope (defaultScopeStack, "meta.preprocessor.region.name." + scope),
+ [ClassificationTypeNames.Punctuation] = MakeScope (defaultScopeStack, "punctuation." + scope),
+ [ClassificationTypeNames.VerbatimStringLiteral] = MakeScope (defaultScopeStack, "string.verbatim." + scope),
+
+ [ClassificationTypeNames.ClassName] = MakeScope (defaultScopeStack, "entity.name.class." + scope),
+ [ClassificationTypeNames.DelegateName] = MakeScope (defaultScopeStack, "entity.name.delegate." + scope),
+ [ClassificationTypeNames.EnumName] = MakeScope (defaultScopeStack, "entity.name.enum." + scope),
+ [ClassificationTypeNames.InterfaceName] = MakeScope (defaultScopeStack, "entity.name.interface." + scope),
+ [ClassificationTypeNames.ModuleName] = MakeScope (defaultScopeStack, "entity.name.module." + scope),
+ [ClassificationTypeNames.StructName] = MakeScope (defaultScopeStack, "entity.name.struct." + scope),
+ [ClassificationTypeNames.TypeParameterName] = MakeScope (defaultScopeStack, "entity.name.typeparameter." + scope),
+
+ [ClassificationTypeNames.FieldName] = MakeScope (defaultScopeStack, "entity.name.field." + scope),
+ [ClassificationTypeNames.EnumMemberName] = MakeScope (defaultScopeStack, "entity.name.enummember." + scope),
+ [ClassificationTypeNames.ConstantName] = MakeScope (defaultScopeStack, "entity.name.constant." + scope),
+ [ClassificationTypeNames.LocalName] = MakeScope (defaultScopeStack, "entity.name.local." + scope),
+ [ClassificationTypeNames.ParameterName] = MakeScope (defaultScopeStack, "entity.name.parameter." + scope),
+ [ClassificationTypeNames.ExtensionMethodName] = MakeScope (defaultScopeStack, "entity.name.extensionmethod." + scope),
+ [ClassificationTypeNames.MethodName] = MakeScope (defaultScopeStack, "entity.name.function." + scope),
+ [ClassificationTypeNames.PropertyName] = MakeScope (defaultScopeStack, "entity.name.property." + scope),
+ [ClassificationTypeNames.EventName] = MakeScope (defaultScopeStack, "entity.name.event." + scope),
+
+ [ClassificationTypeNames.XmlDocCommentAttributeName] = MakeScope (defaultScopeStack, "comment.line.documentation." + scope),
+ [ClassificationTypeNames.XmlDocCommentAttributeQuotes] = MakeScope (defaultScopeStack, "comment.line.documentation." + scope),
+ [ClassificationTypeNames.XmlDocCommentAttributeValue] = MakeScope (defaultScopeStack, "comment.line.documentation." + scope),
+ [ClassificationTypeNames.XmlDocCommentCDataSection] = MakeScope (defaultScopeStack, "comment.line.documentation." + scope),
+ [ClassificationTypeNames.XmlDocCommentComment] = MakeScope (defaultScopeStack, "comment.line.documentation." + scope),
+ [ClassificationTypeNames.XmlDocCommentDelimiter] = MakeScope (defaultScopeStack, "comment.line.documentation." + scope),
+ [ClassificationTypeNames.XmlDocCommentEntityReference] = MakeScope (defaultScopeStack, "comment.line.documentation." + scope),
+ [ClassificationTypeNames.XmlDocCommentName] = MakeScope (defaultScopeStack, "comment.line.documentation." + scope),
+ [ClassificationTypeNames.XmlDocCommentProcessingInstruction] = MakeScope (defaultScopeStack, "comment.line.documentation." + scope),
+ [ClassificationTypeNames.XmlDocCommentText] = MakeScope (defaultScopeStack, "comment.line.documentation." + scope),
+
+ [ClassificationTypeNames.XmlLiteralAttributeName] = MakeScope (defaultScopeStack, "entity.other.attribute-name." + scope),
+ [ClassificationTypeNames.XmlLiteralAttributeQuotes] = MakeScope (defaultScopeStack, "punctuation.definition.string." + scope),
+ [ClassificationTypeNames.XmlLiteralAttributeValue] = MakeScope (defaultScopeStack, "string.quoted." + scope),
+ [ClassificationTypeNames.XmlLiteralCDataSection] = MakeScope (defaultScopeStack, "text." + scope),
+ [ClassificationTypeNames.XmlLiteralComment] = MakeScope (defaultScopeStack, "comment.block." + scope),
+ [ClassificationTypeNames.XmlLiteralDelimiter] = MakeScope (defaultScopeStack, scope),
+ [ClassificationTypeNames.XmlLiteralEmbeddedExpression] = MakeScope (defaultScopeStack, scope),
+ [ClassificationTypeNames.XmlLiteralEntityReference] = MakeScope (defaultScopeStack, scope),
+ [ClassificationTypeNames.XmlLiteralName] = MakeScope (defaultScopeStack, "entity.name.tag.localname." + scope),
+ [ClassificationTypeNames.XmlLiteralProcessingInstruction] = MakeScope (defaultScopeStack, scope),
+ [ClassificationTypeNames.XmlLiteralText] = MakeScope (defaultScopeStack, "text." + scope),
};
+ classificationMapCache = classificationMapCache.SetItem (scope, result);
+
+ return result;
}
- ScopeStack MakeScope (string scope)
+ static ScopeStack MakeScope (ScopeStack defaultScope, string scope)
{
return defaultScope.Push (scope);
}
@@ -140,14 +163,18 @@ namespace MonoDevelop.Ide.Editor.Highlighting
ScopeStack scopeStack;
foreach (var curSpan in classifications) {
- if (curSpan.TextSpan.Start > lastClassifiedOffsetEnd) {
+ var start = Math.Max (offset, curSpan.TextSpan.Start);
+ if (start < lastClassifiedOffsetEnd) { // Work around for : https://github.com/dotnet/roslyn/issues/25648
+ continue;
+ }
+ if (start > lastClassifiedOffsetEnd) {
scopeStack = userScope;
- ColoredSegment whitespaceSegment = new ColoredSegment (lastClassifiedOffsetEnd - offset, curSpan.TextSpan.Start - lastClassifiedOffsetEnd, scopeStack);
+ ColoredSegment whitespaceSegment = new ColoredSegment (lastClassifiedOffsetEnd - offset, start - lastClassifiedOffsetEnd, scopeStack);
coloredSegments.Add (whitespaceSegment);
}
scopeStack = GetStyleScopeStackFromClassificationType (curSpan.ClassificationType);
- ColoredSegment curColoredSegment = new ColoredSegment (curSpan.TextSpan.Start - offset, curSpan.TextSpan.Length, scopeStack);
+ ColoredSegment curColoredSegment = new ColoredSegment (start - offset, curSpan.TextSpan.Length, scopeStack);
coloredSegments.Add (curColoredSegment);
lastClassifiedOffsetEnd = curSpan.TextSpan.End;
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/StackMatchExpression.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/StackMatchExpression.cs
index 1e5ce98dfc..6113e45a1d 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/StackMatchExpression.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/StackMatchExpression.cs
@@ -29,6 +29,7 @@ using System.Collections.Generic;
using System.Collections.Immutable;
using System.Text;
using Roslyn.Utilities;
+using MonoDevelop.Core;
namespace MonoDevelop.Ide.Editor.Highlighting
{
@@ -38,7 +39,7 @@ namespace MonoDevelop.Ide.Editor.Highlighting
public static StackMatchExpression Parse (string expression)
{
- var sb = new StringBuilder ();
+ var sb = StringBuilderCache.Allocate ();
var stackStack = new Stack<Stack<StackMatchExpression>> ();
var exprStack = new Stack<StackMatchExpression> ();
@@ -88,6 +89,7 @@ namespace MonoDevelop.Ide.Editor.Highlighting
}
if (sb.Length > 0)
exprStack.Push (CreateMatchExpression (sb));
+ StringBuilderCache.Free (sb);
ShrinkStack (exprStack);
if (exprStack.IsEmpty ())
return new StringMatchExpression ("");
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/SyntaxHighlighting.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/SyntaxHighlighting.cs
index c8340e77e8..183d0e01a8 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/SyntaxHighlighting.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/SyntaxHighlighting.cs
@@ -10,6 +10,7 @@ using System.IO.Compression;
using System.Threading.Tasks;
using System.Threading;
using MonoDevelop.Core.Text;
+using Microsoft.CodeAnalysis.Execution;
namespace MonoDevelop.Ide.Editor.Highlighting
{
@@ -188,7 +189,7 @@ namespace MonoDevelop.Ide.Editor.Highlighting
int lastMatch = -1;
var highlightedSegment = new TextSegment (startOffset, length);
string lineText = text.GetTextAt (startOffset, length);
-
+ var initialState = state.Clone ();
int timeoutOccursAt;
unchecked {
timeoutOccursAt = Environment.TickCount + (int)matchTimeout.TotalMilliseconds;
@@ -205,8 +206,6 @@ namespace MonoDevelop.Ide.Editor.Highlighting
lastContexts.Clear ();
lastContexts.Add (currentContext);
}
- if (length <= 0)
- goto end;
lastMatch = offset;
currentContext = ContextStack.Peek ();
match = null;
@@ -218,7 +217,12 @@ namespace MonoDevelop.Ide.Editor.Highlighting
if (r == null)
continue;
try {
- var possibleMatch = r.Match (lineText, offset, length, matchTimeout);
+ Match possibleMatch;
+ if (r.pattern == "(?<=\\})" && offset > 0) { // HACK to fix typescript highlighting.
+ possibleMatch = r.Match (lineText, offset - 1, length, matchTimeout);
+ } else {
+ possibleMatch = r.Match (lineText, offset, length, matchTimeout);
+ }
if (possibleMatch.Success) {
if (match == null || possibleMatch.Index < match.Index) {
match = possibleMatch;
@@ -236,6 +240,9 @@ namespace MonoDevelop.Ide.Editor.Highlighting
continue;
}
}
+ if (length <= 0 && curMatch == null)
+ goto end;
+
if (Environment.TickCount >= timeoutOccursAt) {
curMatch.GotTimeout = true;
goto end;
@@ -330,7 +337,9 @@ namespace MonoDevelop.Ide.Editor.Highlighting
segments.Add (new ColoredSegment (curSegmentOffset, endOffset - curSegmentOffset, ScopeStack));
}
- return Task.FromResult (new HighlightedLine (highlightedSegment, segments));
+ return Task.FromResult (new HighlightedLine (highlightedSegment, segments) {
+ IsContinuedBeyondLineEnd = !initialState.Equals (state)
+ });
}
void PushStack (SyntaxMatch curMatch, IEnumerable<SyntaxContext> nextContexts)
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/themes/FallbackStyle.json b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/themes/FallbackStyle.json
index e53bff7df6..8a779a0171 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/themes/FallbackStyle.json
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/themes/FallbackStyle.json
@@ -29,7 +29,7 @@
"colors": [
{ "name": "Background(Read Only)", "color": "white" },
- { "name": "Search result background", "color": "#fffeb7" },
+ { "name": "Search result background", "color": "#fcff54" },
{ "name": "Search result background (highlighted)", "color": "#fffc38" },
{ "name": "Column Ruler", "color": "#eeeeee" },
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/themes/LightStyle.json b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/themes/LightStyle.json
index fbbbb86040..5e6891a78d 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/themes/LightStyle.json
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Highlighting/themes/LightStyle.json
@@ -29,7 +29,7 @@
"colors": [
{ "name": "Background(Read Only)", "color": "white" },
- { "name": "Search result background", "color": "#fffeb7" },
+ { "name": "Search result background", "color": "#fcff54" },
{ "name": "Search result background (highlighted)", "color": "#fffc38" },
{ "name": "Column Ruler", "color": "#eeeeee" },
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.TextMate/TextMateCompletionTextEditorExtension.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.TextMate/TextMateCompletionTextEditorExtension.cs
index fb5cca77ca..cd7c7da16d 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.TextMate/TextMateCompletionTextEditorExtension.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.TextMate/TextMateCompletionTextEditorExtension.cs
@@ -33,6 +33,7 @@ using System.Collections.Generic;
using System.Text;
using MonoDevelop.Core.Text;
using MonoDevelop.Ide.TypeSystem;
+using MonoDevelop.Core;
namespace MonoDevelop.Ide.Editor.TextMate
{
@@ -85,7 +86,7 @@ namespace MonoDevelop.Ide.Editor.TextMate
{
return Task.Run (delegate {
var result = new HashSet<string> ();
- var sb = new StringBuilder ();
+ var sb = StringBuilderCache.Allocate ();
int i = 0;
while (i < source.Length) {
char ch = source[i];
@@ -110,6 +111,7 @@ namespace MonoDevelop.Ide.Editor.TextMate
i++;
}
+ StringBuilderCache.Free (sb);
return (IEnumerable<string>)result;
});
}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/AutoSave.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/AutoSave.cs
index ca8fba7763..5d5adc3915 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/AutoSave.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/AutoSave.cs
@@ -70,11 +70,11 @@ namespace MonoDevelop.Ide.Editor
static MD5 md5 = MD5.Create ();
static string GetMD5 (string data)
{
- var result = new StringBuilder();
+ var result = StringBuilderCache.Allocate();
foreach (var b in md5.ComputeHash (Encoding.ASCII.GetBytes (data))) {
result.Append(b.ToString("X2"));
}
- return result.ToString();
+ return StringBuilderCache.ReturnAndFree (result);
}
/// <summary>
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/DefaultSourceEditorOptions.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/DefaultSourceEditorOptions.cs
index 3d691ea7d4..5ad1830664 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/DefaultSourceEditorOptions.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/DefaultSourceEditorOptions.cs
@@ -28,6 +28,8 @@ using MonoDevelop.Core;
using MonoDevelop.Ide.Gui.Content;
using MonoDevelop.Ide.Fonts;
using MonoDevelop.Ide.Editor.Extension;
+using Microsoft.VisualStudio.CodingConventions;
+using System.Threading.Tasks;
namespace MonoDevelop.Ide.Editor
{
@@ -52,6 +54,7 @@ namespace MonoDevelop.Ide.Editor
static DefaultSourceEditorOptions instance;
//static TextStylePolicy defaultPolicy;
static bool inited;
+ ICodingConventionContext context;
public static DefaultSourceEditorOptions Instance {
get { return instance; }
@@ -278,7 +281,7 @@ namespace MonoDevelop.Ide.Editor
removeTrailingWhitespaces = currentPolicy.RemoveTrailingWhitespace; //PropertyService.Get ("RemoveTrailingWhitespaces", true);
}
- public ITextEditorOptions WithTextStyle (MonoDevelop.Ide.Gui.Content.TextStylePolicy policy)
+ public DefaultSourceEditorOptions WithTextStyle (MonoDevelop.Ide.Gui.Content.TextStylePolicy policy)
{
if (policy == null)
throw new ArgumentNullException ("policy");
@@ -288,6 +291,52 @@ namespace MonoDevelop.Ide.Editor
return result;
}
+ internal void SetContext (ICodingConventionContext context)
+ {
+ this.context = context;
+ context.CodingConventionsChangedAsync += UpdateContextOptions;
+ UpdateContextOptions (null, null);
+ }
+
+ private Task UpdateContextOptions (object sender, CodingConventionsChangedEventArgs arg)
+ {
+ if (context == null)
+ return Task.FromResult (false);
+
+ defaultEolMarkerFromContext = null;
+ if (context.CurrentConventions.UniversalConventions.TryGetLineEnding (out string eolMarker))
+ defaultEolMarkerFromContext = eolMarker;
+
+ tabsToSpacesFromContext = null;
+ if (context.CurrentConventions.UniversalConventions.TryGetIndentStyle (out Microsoft.VisualStudio.CodingConventions.IndentStyle result))
+ tabsToSpacesFromContext = result == Microsoft.VisualStudio.CodingConventions.IndentStyle.Spaces;
+
+ indentationSizeFromContext = null;
+ if (context.CurrentConventions.UniversalConventions.TryGetIndentSize (out int indentSize))
+ indentationSizeFromContext = indentSize;
+
+ removeTrailingWhitespacesFromContext = null;
+ if (context.CurrentConventions.UniversalConventions.TryGetAllowTrailingWhitespace (out bool allowTrailing))
+ removeTrailingWhitespacesFromContext = !allowTrailing;
+
+ tabSizeFromContext = null;
+ if (context.CurrentConventions.UniversalConventions.TryGetTabWidth (out int tSize))
+ tabSizeFromContext = tSize;
+
+ rulerColumnFromContext = null;
+ showRulerFromContext = null;
+ if (context.CurrentConventions.TryGetConventionValue<string> (EditorConfigService.MaxLineLengthConvention, out string maxLineLength)) {
+ if (maxLineLength != "off" && int.TryParse (maxLineLength, out int i)) {
+ rulerColumnFromContext = i;
+ showRulerFromContext = true;
+ } else {
+ showRulerFromContext = false;
+ }
+ }
+
+ return Task.FromResult (true);
+ }
+
#region new options
public bool EnableAutoCodeCompletion {
@@ -420,9 +469,11 @@ namespace MonoDevelop.Ide.Editor
#region ITextEditorOptions
string defaultEolMarker = Environment.NewLine;
+ string defaultEolMarkerFromContext = null;
+
public string DefaultEolMarker {
get {
- return defaultEolMarker;
+ return defaultEolMarkerFromContext ?? defaultEolMarker;
}
set {
if (defaultEolMarker != value) {
@@ -472,9 +523,10 @@ namespace MonoDevelop.Ide.Editor
}
bool tabsToSpaces = true;
+ bool? tabsToSpacesFromContext;
public bool TabsToSpaces {
get {
- return tabsToSpaces;
+ return tabsToSpacesFromContext ?? tabsToSpaces;
}
set {
if (tabsToSpaces != value) {
@@ -486,9 +538,10 @@ namespace MonoDevelop.Ide.Editor
}
int indentationSize = 4;
+ int? indentationSizeFromContext;
public int IndentationSize {
get {
- return indentationSize;
+ return indentationSizeFromContext ?? indentationSize;
}
set {
if (indentationSize != value) {
@@ -505,21 +558,23 @@ namespace MonoDevelop.Ide.Editor
return TabsToSpaces ? new string (' ', this.TabSize) : "\t";
}
}
-
+
+ int? tabSizeFromContext;
public int TabSize {
get {
- return IndentationSize;
+ return tabSizeFromContext ?? IndentationSize;
}
set {
IndentationSize = value;
}
}
-
bool removeTrailingWhitespaces = true;
+ bool? removeTrailingWhitespacesFromContext;
+
public bool RemoveTrailingWhitespaces {
get {
- return removeTrailingWhitespaces;
+ return removeTrailingWhitespacesFromContext ?? removeTrailingWhitespaces;
}
set {
if (removeTrailingWhitespaces != value) {
@@ -600,10 +655,12 @@ namespace MonoDevelop.Ide.Editor
}
int rulerColumn = 120;
+ int? rulerColumnFromContext;
+
public int RulerColumn {
get {
- return rulerColumn;
+ return rulerColumnFromContext ?? rulerColumn;
}
set {
if (rulerColumn != value) {
@@ -615,9 +672,10 @@ namespace MonoDevelop.Ide.Editor
}
ConfigurationProperty<bool> showRuler = ConfigurationProperty.Create ("ShowRuler", true);
+ bool? showRulerFromContext;
public bool ShowRuler {
get {
- return showRuler;
+ return showRulerFromContext ?? showRuler;
}
set {
if (showRuler.Set (value))
@@ -763,6 +821,7 @@ namespace MonoDevelop.Ide.Editor
public bool SmartBackspace{
get {
return smartBackspace;
+
}
set {
if (smartBackspace.Set (value))
@@ -775,6 +834,8 @@ namespace MonoDevelop.Ide.Editor
{
FontService.RemoveCallback (UpdateFont);
IdeApp.Preferences.ColorScheme.Changed -= OnColorSchemeChanged;
+ if (context != null)
+ context.CodingConventionsChangedAsync -= UpdateContextOptions;
}
protected void OnChanged (EventArgs args)
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/EditActions.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/EditActions.cs
index 9fdeca3319..ea6fe11b15 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/EditActions.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/EditActions.cs
@@ -37,129 +37,129 @@ namespace MonoDevelop.Ide.Editor
{
public static void MoveCaretDown (TextEditor editor)
{
- editor.EditorActionHost.MoveCaretDown ();
+ editor.EditorOperations.MoveLineDown (false);
}
public static void MoveCaretUp (TextEditor editor)
{
- editor.EditorActionHost.MoveCaretUp ();
+ editor.EditorOperations.MoveLineUp (false);
}
public static void MoveCaretRight (TextEditor editor)
{
- editor.EditorActionHost.MoveCaretRight ();
+ editor.EditorOperations.MoveToPreviousCharacter (false);
}
public static void MoveCaretLeft (TextEditor editor)
{
- editor.EditorActionHost.MoveCaretLeft ();
+ editor.EditorOperations.MoveToNextCharacter (false);
}
public static void MoveCaretToLineEnd (TextEditor editor)
{
- editor.EditorActionHost.MoveCaretToLineEnd ();
+ editor.EditorOperations.MoveToEndOfLine (false);
}
public static void MoveCaretToLineStart (TextEditor editor)
{
- editor.EditorActionHost.MoveCaretToLineStart ();
+ editor.EditorOperations.MoveToStartOfLine (false);
}
public static void MoveCaretToDocumentStart (TextEditor editor)
{
- editor.EditorActionHost.MoveCaretToDocumentStart ();
+ editor.EditorOperations.MoveToStartOfDocument (false);
}
public static void MoveCaretToDocumentEnd (TextEditor editor)
{
- editor.EditorActionHost.MoveCaretToDocumentEnd ();
+ editor.EditorOperations.MoveToEndOfDocument (false);
}
public static void Backspace (TextEditor editor)
{
- editor.EditorActionHost.Backspace ();
+ editor.EditorOperations.Backspace ();
}
public static void Delete (TextEditor editor)
{
- editor.EditorActionHost.Delete ();
+ editor.EditorOperations.Delete ();
}
public static void ClipboardCopy (TextEditor editor)
{
- editor.EditorActionHost.ClipboardCopy ();
+ editor.EditorOperations.CopySelection ();
}
public static void ClipboardCut (TextEditor editor)
{
- editor.EditorActionHost.ClipboardCut ();
+ editor.EditorOperations.CutSelection ();
}
public static void ClipboardPaste (TextEditor editor)
{
- editor.EditorActionHost.ClipboardPaste ();
+ editor.EditorOperations.Paste ();
}
public static void SelectAll (TextEditor editor)
{
- editor.EditorActionHost.SelectAll ();
+ editor.EditorOperations.SelectAll ();
}
public static void NewLine (TextEditor editor)
{
- editor.EditorActionHost.NewLine ();
+ editor.EditorOperations.InsertNewLine ();
}
public static void PageUp (TextEditor textEditor)
{
- textEditor.EditorActionHost.PageUp ();
+ textEditor.EditorOperations.PageUp (false);
}
public static void PageDown (TextEditor textEditor)
{
- textEditor.EditorActionHost.PageDown ();
+ textEditor.EditorOperations.PageDown (false);
}
public static void Undo (TextEditor editor)
{
- editor.EditorActionHost.Undo ();
+ ((IMonoDevelopEditorOperations)editor.EditorOperations).Undo ();
}
public static void Redo (TextEditor editor)
{
- editor.EditorActionHost.Redo ();
+ ((IMonoDevelopEditorOperations)editor.EditorOperations).Redo ();
}
public static void DeleteCurrentLine (TextEditor textEditor)
{
- textEditor.EditorActionHost.DeleteCurrentLine ();
+ textEditor.EditorOperations.DeleteFullLine ();
}
public static void DeleteCurrentLineToEnd (TextEditor textEditor)
{
- textEditor.EditorActionHost.DeleteCurrentLineToEnd ();
+ textEditor.EditorOperations.DeleteToEndOfLine ();
}
public static void ScrollLineUp (TextEditor textEditor)
{
- textEditor.EditorActionHost.ScrollLineUp ();
+ textEditor.EditorOperations.ScrollLineTop ();
}
public static void ScrollLineDown (TextEditor textEditor)
{
- textEditor.EditorActionHost.ScrollLineDown ();
+ textEditor.EditorOperations.ScrollLineBottom ();
}
public static void ScrollPageUp (TextEditor textEditor)
{
- textEditor.EditorActionHost.ScrollPageUp ();
+ textEditor.EditorOperations.ScrollPageUp ();
}
public static void ScrollPageDown (TextEditor textEditor)
{
- textEditor.EditorActionHost.ScrollPageDown ();
+ textEditor.EditorOperations.ScrollPageDown ();
}
public static void GotoMatchingBrace (TextEditor textEditor)
@@ -171,27 +171,27 @@ namespace MonoDevelop.Ide.Editor
public static void MovePrevWord (TextEditor textEditor)
{
- textEditor.EditorActionHost.MovePrevWord ();
+ textEditor.EditorOperations.MoveToPreviousWord (false);
}
public static void MoveNextWord (TextEditor textEditor)
{
- textEditor.EditorActionHost.MoveNextWord ();
+ textEditor.EditorOperations.MoveToNextWord (false);
}
public static void MovePrevSubWord (TextEditor textEditor)
{
- textEditor.EditorActionHost.MovePrevSubWord ();
+ ((IMonoDevelopEditorOperations)textEditor.EditorOperations).MoveToPrevSubWord ();
}
public static void MoveNextSubWord (TextEditor textEditor)
{
- textEditor.EditorActionHost.MoveNextSubWord ();
+ ((IMonoDevelopEditorOperations)textEditor.EditorOperations).MoveToNextSubWord ();
}
public static void ShowQuickInfo (TextEditor textEditor)
{
- textEditor.EditorActionHost.ShowQuickInfo ();
+ ((IMonoDevelopEditorOperations)textEditor.EditorOperations).ShowQuickInfo ();
}
@@ -268,37 +268,37 @@ namespace MonoDevelop.Ide.Editor
public static void JoinLines (TextEditor textEditor)
{
- textEditor.EditorActionHost.JoinLines ();
+ ((IMonoDevelopEditorOperations)textEditor.EditorOperations).JoinLines ();
}
public static void RecenterEditor (TextEditor textEditor)
{
- textEditor.EditorActionHost.RecenterEditor ();
+ textEditor.EditorOperations.ScrollLineCenter ();
}
public static void StartCaretPulseAnimation (TextEditor textEditor)
{
- textEditor.EditorActionHost.StartCaretPulseAnimation ();
+ ((IMonoDevelopEditorOperations)textEditor.EditorOperations).StartCaretPulseAnimation ();
}
public static void DeleteNextSubword (TextEditor textEditor)
{
- textEditor.EditorActionHost.DeleteNextSubword ();
+ ((IMonoDevelopEditorOperations)textEditor.EditorOperations).DeleteNextSubword ();
}
public static void DeletePreviousSubword (TextEditor textEditor)
{
- textEditor.EditorActionHost.DeletePreviousSubword ();
+ ((IMonoDevelopEditorOperations)textEditor.EditorOperations).DeletePreviousSubword ();
}
public static void DeleteNextWord (TextEditor textEditor)
{
- textEditor.EditorActionHost.DeleteNextWord ();
+ textEditor.EditorOperations.DeleteWordToRight ();
}
public static void DeletePreviousWord (TextEditor textEditor)
{
- textEditor.EditorActionHost.DeletePreviousWord ();
+ textEditor.EditorOperations.DeleteWordToLeft ();
}
public static void InsertNewLinePreserveCaretPosition (TextEditor textEditor)
@@ -324,47 +324,47 @@ namespace MonoDevelop.Ide.Editor
public static void InsertNewLine (TextEditor textEditor)
{
- textEditor.EditorActionHost.InsertNewLine ();
+ textEditor.EditorOperations.InsertNewLine ();
}
public static void RemoveTab (TextEditor textEditor)
{
- textEditor.EditorActionHost.RemoveTab ();
+ textEditor.EditorOperations.Untabify ();
}
public static void InsertTab (TextEditor textEditor)
{
- textEditor.EditorActionHost.InsertTab ();
+ textEditor.EditorOperations.Tabify ();
}
public static void SwitchCaretMode (TextEditor textEditor)
{
- textEditor.EditorActionHost.SwitchCaretMode ();
+ ((IMonoDevelopEditorOperations)textEditor.EditorOperations).SwitchCaretMode ();
}
public static void MoveBlockUp (TextEditor textEditor)
{
- textEditor.EditorActionHost.MoveBlockUp ();
+ ((IMonoDevelopEditorOperations)textEditor.EditorOperations).MoveBlockUp ();
}
public static void MoveBlockDown (TextEditor textEditor)
{
- textEditor.EditorActionHost.MoveBlockDown ();
+ ((IMonoDevelopEditorOperations)textEditor.EditorOperations).MoveBlockDown ();
}
public static void ToggleBlockSelectionMode (TextEditor textEditor)
{
- textEditor.EditorActionHost.ToggleBlockSelectionMode ();
+ ((IMonoDevelopEditorOperations)textEditor.EditorOperations).ToggleBlockSelectionMode ();
}
public static void IndentSelection (TextEditor editor)
{
- editor.EditorActionHost.IndentSelection ();
+ editor.EditorOperations.Indent ();
}
public static void UnIndentSelection (TextEditor editor)
{
- editor.EditorActionHost.UnIndentSelection ();
+ editor.EditorOperations.Unindent ();
}
#region SelectionActions
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/EditorConfigService.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/EditorConfigService.cs
new file mode 100644
index 0000000000..1f4ee97422
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/EditorConfigService.cs
@@ -0,0 +1,134 @@
+ο»Ώ//
+// EditorConfigService.cs
+//
+// Author:
+// Mike KrΓΌger <mikkrg@microsoft.com>
+//
+// Copyright (c) 2017 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.Immutable;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.VisualStudio.CodingConventions;
+using System.Collections.Generic;
+using MonoDevelop.Core;
+
+namespace MonoDevelop.Ide.Editor
+{
+ static class EditorConfigService
+ {
+ public readonly static string MaxLineLengthConvention = "max_line_length";
+ readonly static object contextCacheLock = new object ();
+ readonly static ICodingConventionsManager codingConventionsManager = CodingConventionsManagerFactory.CreateCodingConventionsManager (new ConventionsFileManager());
+ static ImmutableDictionary<string, ICodingConventionContext> contextCache = ImmutableDictionary<string, ICodingConventionContext>.Empty;
+
+ public async static Task<ICodingConventionContext> GetEditorConfigContext (string fileName, CancellationToken token = default (CancellationToken))
+ {
+ if (!File.Exists (fileName))
+ return null;
+ if (contextCache.TryGetValue (fileName, out ICodingConventionContext result))
+ return result;
+ try {
+ result = await codingConventionsManager.GetConventionContextAsync (fileName, token);
+ } catch (OperationCanceledException) {
+ } catch (Exception e) {
+ LoggingService.LogError ("Error while getting coding conventions,", e);
+ }
+ if (result == null)
+ return null;
+ lock (contextCacheLock) {
+ contextCache = contextCache.SetItem (fileName, result);
+ return result;
+ }
+ }
+
+ public static void RemoveEditConfigContext (string fileName)
+ {
+ lock (contextCacheLock) {
+ contextCache = contextCache.Remove (fileName);
+ }
+ }
+
+ class ConventionsFileManager : IFileWatcher
+ {
+ Dictionary<string, FileSystemWatcher> watchers = new Dictionary<string, FileSystemWatcher> ();
+
+ public event ConventionsFileChangedAsyncEventHandler ConventionFileChanged;
+ public event ContextFileMovedAsyncEventHandler ContextFileMoved;
+
+ public void Dispose ()
+ {
+ lock (watchers) {
+ foreach (var kv in watchers)
+ kv.Value.Dispose ();
+ watchers = null;
+ }
+ }
+
+ void OnChanged (object source, FileSystemEventArgs e)
+ {
+ var watcher = (FileSystemWatcher)source;
+ ConventionFileChanged?.Invoke (this, new ConventionsFileChangeEventArgs (watcher.Filter, watcher.Path, GetChangeType(e.ChangeType)));
+ }
+
+ static ChangeType GetChangeType(WatcherChangeTypes type)
+ {
+ switch (type) {
+ case WatcherChangeTypes.Changed:
+ return ChangeType.FileModified;
+ case WatcherChangeTypes.Deleted:
+ return ChangeType.FileDeleted;
+ }
+ return ChangeType.FileModified;
+ }
+
+ public void StartWatching (string fileName, string directoryPath)
+ {
+ lock (watchers) {
+ var key = directoryPath + Path.DirectorySeparatorChar.ToString () + fileName;
+
+ if (watchers.ContainsKey (key))
+ return;
+
+ var watcher = new FileSystemWatcher ();
+ watcher.Path = directoryPath;
+ watcher.Filter = fileName;
+ watcher.Changed += OnChanged;
+ watcher.Deleted += OnChanged;
+ watcher.EnableRaisingEvents = true;
+ watchers.Add (key, watcher);
+ }
+ }
+
+ public void StopWatching (string fileName, string directoryPath)
+ {
+ lock (watchers) {
+ var key = directoryPath + Path.DirectorySeparatorChar.ToString () + fileName;
+ if (watchers.TryGetValue (key, out FileSystemWatcher watcher)) {
+ watcher.Dispose ();
+ watchers.Remove (key);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/InternalExtensionAPI/IEditorActionHost.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/InternalExtensionAPI/IMonoDevelopEditorOperations.cs
index 81fccd8303..3819dc85ab 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/InternalExtensionAPI/IEditorActionHost.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/InternalExtensionAPI/IMonoDevelopEditorOperations.cs
@@ -28,98 +28,32 @@ using MonoDevelop.Core.Text;
namespace MonoDevelop.Ide.Editor
{
- interface IEditorActionHost
+ interface IMonoDevelopEditorOperations : Microsoft.VisualStudio.Text.Operations.IEditorOperations
{
void SwitchCaretMode ();
- void InsertTab ();
-
- void RemoveTab ();
-
- void InsertNewLine ();
-
- void DeletePreviousWord ();
-
- void DeleteNextWord ();
-
void DeletePreviousSubword ();
void DeleteNextSubword ();
void StartCaretPulseAnimation ();
- void RecenterEditor ();
-
void JoinLines ();
- void MoveNextSubWord ();
-
- void MovePrevSubWord ();
-
- void MoveNextWord ();
-
- void MovePrevWord ();
-
- void PageUp ();
-
- void PageDown ();
-
- void MoveCaretDown ();
-
- void MoveCaretUp ();
-
- void MoveCaretRight ();
-
- void MoveCaretLeft ();
-
- void MoveCaretToLineEnd ();
-
- void MoveCaretToLineStart ();
+ void MoveToNextSubWord ();
- void MoveCaretToDocumentStart ();
-
- void MoveCaretToDocumentEnd ();
-
- void Backspace ();
-
- void Delete ();
-
- void ClipboardCopy ();
-
- void ClipboardCut ();
-
- void ClipboardPaste ();
-
- void SelectAll ();
-
- void NewLine ();
+ void MoveToPrevSubWord ();
void Undo ();
void Redo ();
- void DeleteCurrentLine ();
-
- void DeleteCurrentLineToEnd ();
-
- void ScrollLineUp ();
-
- void ScrollLineDown ();
-
- void ScrollPageUp ();
-
- void ScrollPageDown ();
-
void MoveBlockUp ();
void MoveBlockDown ();
void ToggleBlockSelectionMode ();
- void IndentSelection ();
-
- void UnIndentSelection ();
-
void ShowQuickInfo ();
}
} \ No newline at end of file
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/InternalExtensionAPI/ITextEditorImpl.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/InternalExtensionAPI/ITextEditorImpl.cs
index e0d1a9d7b3..36eae1181f 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/InternalExtensionAPI/ITextEditorImpl.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/InternalExtensionAPI/ITextEditorImpl.cs
@@ -46,6 +46,8 @@ namespace MonoDevelop.Ide.Editor
interface ITextEditorImpl : IDisposable
{
+ Microsoft.VisualStudio.Text.Editor.ITextView TextView { get; set; }
+
ViewContent ViewContent { get; }
string ContentName { get; set; }
@@ -98,7 +100,7 @@ namespace MonoDevelop.Ide.Editor
void FixVirtualIndentation ();
- IEditorActionHost Actions { get; }
+ IMonoDevelopEditorOperations Actions { get; }
ITextMarkerFactory TextMarkerFactory { get; }
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/Projection/ProjectedDocumentContext.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/Projection/ProjectedDocumentContext.cs
index b2fa634440..441f46cedc 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/Projection/ProjectedDocumentContext.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/Projection/ProjectedDocumentContext.cs
@@ -30,6 +30,7 @@ using MonoDevelop.Core.Text;
using MonoDevelop.Ide.Gui;
using MonoDevelop.Ide.TypeSystem;
using System.Threading.Tasks;
+using MonoDevelop.Core;
namespace MonoDevelop.Ide.Editor.Projection
{
@@ -101,7 +102,7 @@ namespace MonoDevelop.Ide.Editor.Projection
ReparseDocumentInternal ();
}
- Task ReparseDocumentInternal ()
+ async Task ReparseDocumentInternal ()
{
var options = new ParseOptions {
FileName = projectedEditor.FileName,
@@ -110,8 +111,9 @@ namespace MonoDevelop.Ide.Editor.Projection
RoslynDocument = projectedDocument,
OldParsedDocument = parsedDocument
};
- return TypeSystemService.ParseFile (options, projectedEditor.MimeType).ContinueWith (t => {
- parsedDocument = t.Result;
+ var result = await TypeSystemService.ParseFile (options, projectedEditor.MimeType).ConfigureAwait (false);
+ await Runtime.RunInMainThread (delegate {
+ parsedDocument = result;
base.OnDocumentParsed (EventArgs.Empty);
});
}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/TextEditor.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/TextEditor.cs
index 3e67d61419..01df4804d9 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/TextEditor.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/TextEditor.cs
@@ -50,7 +50,7 @@ namespace MonoDevelop.Ide.Editor
public sealed class TextEditor : Control, ITextDocument, IDisposable
{
readonly ITextEditorImpl textEditorImpl;
- public Microsoft.VisualStudio.Text.Editor.ITextView TextView { get; }
+ public Microsoft.VisualStudio.Text.Editor.ITextView TextView { get => textEditorImpl.TextView; set => textEditorImpl.TextView = value; }
IReadonlyTextDocument ReadOnlyTextDocument { get { return textEditorImpl.Document; } }
@@ -970,6 +970,8 @@ namespace MonoDevelop.Ide.Editor
if (isDisposed)
return;
Runtime.AssertMainThread ();
+ this.TextView.Close ();
+
// Break fileTypeCondition circular event handling reference.
fileTypeCondition = null;
isDisposed = true;
@@ -980,8 +982,6 @@ namespace MonoDevelop.Ide.Editor
provider.Dispose ();
textEditorImpl.Dispose ();
- this.TextView.Close();
-
base.Dispose (disposing);
}
@@ -1002,7 +1002,7 @@ namespace MonoDevelop.Ide.Editor
}
}
- internal IEditorActionHost EditorActionHost {
+ internal Microsoft.VisualStudio.Text.Operations.IEditorOperations EditorOperations {
get {
return textEditorImpl.Actions;
}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/TextEditorDisplayBinding.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/TextEditorDisplayBinding.cs
index ba49053020..f3f90d19b6 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/TextEditorDisplayBinding.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/TextEditorDisplayBinding.cs
@@ -97,18 +97,12 @@ namespace MonoDevelop.Ide.Editor
{
TextEditor editor;
- // HACK: this is a very poor test for whether to load the document. Maybe add an IsPlaceholder property to FilePath.
- // Another alternative would be to add a parameter to CreateContent.
- if (File.Exists(fileName))
- {
- editor = TextEditorFactory.CreateNewEditor(fileName, mimeType);
- }
- else
- {
- editor = TextEditorFactory.CreateNewEditor();
- editor.FileName = fileName;
- editor.MimeType = mimeType;
- }
+ // HACK: CreateNewEditor really needs to know whether the document exists (& should be loaded)
+ // or we're creating an empty document with the given file name & mime type.
+ //
+ // That information could be added to FilePath but fileName is converted to a string below
+ // which means the information is lost.
+ editor = TextEditorFactory.CreateNewEditor(fileName, mimeType);
editor.GetViewContent ().Project = ownerProject;
return editor.GetViewContent ();
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 dab769f786..c720e8daf2 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/TextEditorViewContent.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/TextEditorViewContent.cs
@@ -48,6 +48,7 @@ using Microsoft.CodeAnalysis;
using Gdk;
using MonoDevelop.Ide.CodeFormatting;
using System.Collections.Immutable;
+using Microsoft.VisualStudio.CodingConventions;
namespace MonoDevelop.Ide.Editor
{
@@ -73,7 +74,7 @@ namespace MonoDevelop.Ide.Editor
this.textEditor.MimeTypeChanged += UpdateTextEditorOptions;
DefaultSourceEditorOptions.Instance.Changed += UpdateTextEditorOptions;
textEditorImpl.ViewContent.ContentNameChanged += ViewContent_ContentNameChanged;
- textEditorImpl.ViewContent.DirtyChanged += ViewContent_DirtyChanged; ;
+ textEditorImpl.ViewContent.DirtyChanged += ViewContent_DirtyChanged;
}
@@ -82,9 +83,12 @@ namespace MonoDevelop.Ide.Editor
base.OnContentNameChanged ();
if (ContentName != textEditorImpl.ContentName && !string.IsNullOrEmpty (textEditorImpl.ContentName))
AutoSave.RemoveAutoSaveFile (textEditorImpl.ContentName);
+ if (textEditorImpl.ContentName != null)
+ EditorConfigService.RemoveEditConfigContext (textEditorImpl.ContentName);
textEditorImpl.ContentName = this.ContentName;
if (this.WorkbenchWindow?.Document != null)
textEditor.InitializeExtensionChain (this.WorkbenchWindow.Document);
+ UpdateTextEditorOptions (null, null);
}
void ViewContent_ContentNameChanged (object sender, EventArgs e)
@@ -145,7 +149,7 @@ namespace MonoDevelop.Ide.Editor
policyContainer.PolicyChanged -= HandlePolicyChanged;
}
- void UpdateStyleParent (MonoDevelop.Projects.Project styleParent, string mimeType)
+ async Task UpdateStyleParent (MonoDevelop.Projects.Project styleParent, string mimeType)
{
RemovePolicyChangeHandler ();
@@ -161,7 +165,13 @@ namespace MonoDevelop.Ide.Editor
var currentPolicy = policyContainer.Get<TextStylePolicy> (mimeTypes);
policyContainer.PolicyChanged += HandlePolicyChanged;
- textEditor.Options = DefaultSourceEditorOptions.Instance.WithTextStyle (currentPolicy);
+
+ var context = await EditorConfigService.GetEditorConfigContext (textEditor.FileName, default (CancellationToken));
+ if (context == null)
+ return;
+ var options = DefaultSourceEditorOptions.Instance.WithTextStyle (currentPolicy);
+ options.SetContext (context);
+ textEditor.Options = options;
}
void HandlePolicyChanged (object sender, MonoDevelop.Projects.Policies.PolicyChangedEventArgs args)
@@ -336,6 +346,7 @@ namespace MonoDevelop.Ide.Editor
base.Dispose ();
isDisposed = true;
+ EditorConfigService.RemoveEditConfigContext (textEditor.FileName);
CancelDocumentParsedUpdate ();
textEditorImpl.ViewContent.DirtyChanged -= HandleDirtyChanged;
textEditor.MimeTypeChanged -= UpdateTextEditorOptions;
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Execution/MonoExecutionParametersPreview.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Execution/MonoExecutionParametersPreview.cs
index ba33b9cea5..cc7ef21975 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Execution/MonoExecutionParametersPreview.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Execution/MonoExecutionParametersPreview.cs
@@ -44,7 +44,7 @@ namespace MonoDevelop.Ide.Execution
Dictionary<string,string> vars = new Dictionary<string, string> ();
options.GenerateOptions (vars, out cmd);
- StringBuilder sb = new StringBuilder ();
+ StringBuilder sb = StringBuilderCache.Allocate ();
if (cmd.Length == 0 && vars.Count == 0) {
sb.AppendLine (GLib.Markup.EscapeText (GettextCatalog.GetString ("No options have been specified.")));
@@ -68,7 +68,7 @@ namespace MonoDevelop.Ide.Execution
sb.AppendLine (svar);
}
- labelOps.Markup = sb.ToString ();
+ labelOps.Markup = StringBuilderCache.ReturnAndFree (sb);
}
}
}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Extensions/MimeTypeNode.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Extensions/MimeTypeNode.cs
index 441ddf81d6..71b486b1eb 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Extensions/MimeTypeNode.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Extensions/MimeTypeNode.cs
@@ -103,7 +103,7 @@ namespace MonoDevelop.Ide.Extensions
Regex CreateRegex (MimeTypeNode node)
{
- var globalPattern = new StringBuilder ();
+ var globalPattern = StringBuilderCache.Allocate ();
foreach (MimeTypeFileNode file in node.ChildNodes) {
string pattern = Regex.Escape (file.Pattern);
@@ -115,7 +115,7 @@ namespace MonoDevelop.Ide.Extensions
globalPattern.Append ('|');
globalPattern.Append (pattern);
}
- return new Regex (globalPattern.ToString (), RegexOptions.IgnoreCase);
+ return new Regex (StringBuilderCache.ReturnAndFree (globalPattern), RegexOptions.IgnoreCase);
}
public bool SupportsFile (string fileName)
{
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.FindInFiles/FindInFilesDialog.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.FindInFiles/FindInFilesDialog.cs
index 3b2d881171..58f710ad14 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.FindInFiles/FindInFilesDialog.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.FindInFiles/FindInFilesDialog.cs
@@ -500,20 +500,7 @@ namespace MonoDevelop.Ide.FindInFiles
Visible = true,
Ready = true,
};
-
- var checkMenuItem = searchentryFileMask.AddFilterOption (0, GettextCatalog.GetString ("Include binary files"));
- checkMenuItem.DrawAsRadio = false;
- checkMenuItem.Active = properties.Get ("IncludeBinaryFiles", false);
- checkMenuItem.Toggled += delegate {
- properties.Set ("IncludeBinaryFiles", checkMenuItem.Active);
- };
-
- var checkMenuItem1 = searchentryFileMask.AddFilterOption (1, GettextCatalog.GetString ("Include hidden files and directories"));
- checkMenuItem1.DrawAsRadio = false;
- checkMenuItem1.Active = properties.Get ("IncludeHiddenFiles", false);
- checkMenuItem1.Toggled += delegate {
- properties.Set ("IncludeHiddenFiles", checkMenuItem1.Active);
- };
+
searchentryFileMask.Query = properties.Get ("MonoDevelop.FindReplaceDialogs.FileMask", "");
@@ -793,15 +780,12 @@ namespace MonoDevelop.Ide.FindInFiles
return null;
}
- scope = new DirectoryScope (comboboxentryPath.Entry.Text, checkbuttonRecursively.Active) {
- IncludeHiddenFiles = properties.Get ("IncludeHiddenFiles", false)
- };
+ scope = new DirectoryScope (comboboxentryPath.Entry.Text, checkbuttonRecursively.Active);
break;
default:
throw new ApplicationException ("Unknown scope:" + comboboxScope.Active);
}
- scope.IncludeBinaryFiles = properties.Get ("IncludeBinaryFiles", false);
return scope;
}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.FindInFiles/Scope.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.FindInFiles/Scope.cs
index 9da97c4c0b..19a08d442f 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.FindInFiles/Scope.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.FindInFiles/Scope.cs
@@ -39,6 +39,7 @@ namespace MonoDevelop.Ide.FindInFiles
{
public abstract class Scope
{
+ [Obsolete ("Unused - will be removed")]
public bool IncludeBinaryFiles {
get;
set;
@@ -145,7 +146,7 @@ namespace MonoDevelop.Ide.FindInFiles
() => new List<FileProvider> (),
(folder, loop, providers) => {
foreach (var file in folder.Files.Where (f => filterOptions.NameMatches (f.FileName) && File.Exists (f.FullPath))) {
- if (!IncludeBinaryFiles && !DesktopService.GetFileIsText (file.FullPath))
+ if (!DesktopService.GetFileIsText (file.FullPath))
continue;
lock (alreadyVisited) {
if (alreadyVisited.Contains (file.FullPath))
@@ -171,7 +172,7 @@ namespace MonoDevelop.Ide.FindInFiles
foreach (ProjectFile file in project.GetSourceFilesAsync (conf).Result.Where (f => filterOptions.NameMatches (f.Name) && File.Exists (f.Name))) {
if ((file.Flags & ProjectItemFlags.Hidden) == ProjectItemFlags.Hidden)
continue;
- if (!IncludeBinaryFiles && !DesktopService.GetFileIsText (file.FilePath))
+ if (!DesktopService.GetFileIsText (file.FilePath))
continue;
lock (alreadyVisited) {
@@ -227,7 +228,7 @@ namespace MonoDevelop.Ide.FindInFiles
foreach (ProjectFile file in project.GetSourceFilesAsync (conf).Result.Where (f => filterOptions.NameMatches (f.Name) && File.Exists (f.Name))) {
if ((file.Flags & ProjectItemFlags.Hidden) == ProjectItemFlags.Hidden)
continue;
- if (!IncludeBinaryFiles && !DesktopService.GetFileIsText (file.Name))
+ if (!DesktopService.GetFileIsText (file.Name))
continue;
if (alreadyVisited.Contains (file.FilePath.FullPath))
continue;
@@ -280,6 +281,7 @@ namespace MonoDevelop.Ide.FindInFiles
get { return PathMode.Absolute; }
}
+ [Obsolete ("Unused - will be removed")]
public bool IncludeHiddenFiles {
get;
set;
@@ -315,33 +317,29 @@ namespace MonoDevelop.Ide.FindInFiles
}
foreach (string fileName in Directory.EnumerateFiles (curPath, "*")) {
- if (!IncludeHiddenFiles) {
- if (Platform.IsWindows) {
- var attr = File.GetAttributes (fileName);
- if (attr.HasFlag (FileAttributes.Hidden))
- continue;
- }
- if (Path.GetFileName (fileName).StartsWith (".", StringComparison.Ordinal))
+ if (Platform.IsWindows) {
+ var attr = File.GetAttributes (fileName);
+ if (attr.HasFlag (FileAttributes.Hidden))
continue;
}
+ if (Path.GetFileName (fileName).StartsWith (".", StringComparison.Ordinal))
+ continue;
if (!filterOptions.NameMatches (fileName))
continue;
- if (!IncludeBinaryFiles && !DesktopService.GetFileIsText (fileName))
+ if (!DesktopService.GetFileIsText (fileName))
continue;
yield return fileName;
}
if (recurse) {
foreach (string directoryName in Directory.EnumerateDirectories (curPath)) {
- if (!IncludeHiddenFiles) {
- if (Platform.IsWindows) {
- var attr = File.GetAttributes (directoryName);
- if (attr.HasFlag (FileAttributes.Hidden))
- continue;
- }
- if (Path.GetFileName (directoryName).StartsWith (".", StringComparison.Ordinal))
+ if (Platform.IsWindows) {
+ var attr = File.GetAttributes (directoryName);
+ if (attr.HasFlag (FileAttributes.Hidden))
continue;
}
+ if (Path.GetFileName (directoryName).StartsWith (".", StringComparison.Ordinal))
+ continue;
directoryStack.Push (directoryName);
}
}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Components/LogView.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Components/LogView.cs
index f3c7aefd5a..4ec206f18c 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Components/LogView.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Components/LogView.cs
@@ -804,6 +804,8 @@ namespace MonoDevelop.Ide.Gui.Components
}
internal class IndentTracker {
+ static int trackerID = 0;
+
List<TextTag> tags = new List<TextTag> ();
public TextTag IndentTag;
@@ -814,7 +816,12 @@ namespace MonoDevelop.Ide.Gui.Components
indent++;
if (indent >= tags.Count) {
- tag = new TextTag (indent.ToString ());
+ // create a unique tagname
+ // Fixes VSTS 584931
+ tag = new TextTag ($"{trackerID}-{indent}");
+ System.Console.WriteLine ($"{tag.Name}");
+ trackerID++;
+
tag.LeftMargin = 10 + 15 * (indent - 1);
tags.Add (tag);
} else {
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Content/TextStylePolicy.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Content/TextStylePolicy.cs
index 71b51040d2..e94cb3b05f 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Content/TextStylePolicy.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Content/TextStylePolicy.cs
@@ -100,15 +100,24 @@ namespace MonoDevelop.Ide.Gui.Content
};
}
- public TextStylePolicy WithTabWidth(int tabWidth)
+ public TextStylePolicy WithTabWidth (int tabWidth)
{
if (tabWidth == TabWidth)
return this;
- return new TextStylePolicy(this) {
+ return new TextStylePolicy (this) {
TabWidth = tabWidth
};
}
+ public TextStylePolicy WithEolMarker (EolMarker eolMarker)
+ {
+ if (eolMarker == EolMarker)
+ return this;
+ return new TextStylePolicy (this) {
+ EolMarker = eolMarker
+ };
+ }
+
public static string GetEolMarker (EolMarker eolMarker)
{
switch (eolMarker) {
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Pads.ProjectPad/ProjectFileNodeBuilder.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Pads.ProjectPad/ProjectFileNodeBuilder.cs
index d8f55c4c31..6e7c406db5 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Pads.ProjectPad/ProjectFileNodeBuilder.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Pads.ProjectPad/ProjectFileNodeBuilder.cs
@@ -155,7 +155,6 @@ namespace MonoDevelop.Ide.Gui.Pads.ProjectPad
public async override void RenameItem (string newName)
{
- ProjectFile newProjectFile = null;
var file = (ProjectFile) CurrentNode.DataItem;
string oldFileName = file.FilePath;
@@ -163,26 +162,24 @@ namespace MonoDevelop.Ide.Gui.Pads.ProjectPad
if (oldFileName == newFileName)
return;
- FilePath newPath, newLink = FilePath.Null;
- if (file.IsLink) {
- var oldLink = file.ProjectVirtualPath;
- newLink = oldLink.ParentDirectory.Combine (newName);
- newPath = file.Project.BaseDirectory.Combine (newLink);
- } else {
- newPath = file.FilePath.ParentDirectory.Combine (newName);
- }
-
+ var dependentFilesToRename = GetDependentFilesToRename (file, newName);
+
try {
- if (file.Project != null)
- newProjectFile = file.Project.Files.GetFileWithVirtualPath (newPath.ToRelative (file.Project.BaseDirectory));
-
- if (!FileService.IsValidPath (newPath) || ProjectFolderCommandHandler.ContainsDirectorySeparator (newName)) {
- MessageService.ShowWarning (GettextCatalog.GetString ("The name you have chosen contains illegal characters. Please choose a different name."));
- } else if ((newProjectFile != null && newProjectFile != file) || FileExistsCaseSensitive (file.FilePath.ParentDirectory, newName)) {
- // If there is already a file under the newPath which is *different*, then throw an exception
- MessageService.ShowWarning (GettextCatalog.GetString ("File or directory name is already in use. Please choose a different one."));
- } else {
+ if (CanRenameFile (file, newName)) {
+ if (dependentFilesToRename != null) {
+ if (dependentFilesToRename.Any (f => !CanRenameFile (f.File, f.NewName))) {
+ return;
+ }
+ }
+
FileService.RenameFile (file.FilePath, newName);
+
+ if (dependentFilesToRename != null) {
+ foreach (var dependentFile in dependentFilesToRename) {
+ FileService.RenameFile (dependentFile.File.FilePath, dependentFile.NewName);
+ }
+ }
+
if (file.Project != null)
await IdeApp.ProjectOperations.SaveAsync (file.Project);
}
@@ -193,6 +190,60 @@ namespace MonoDevelop.Ide.Gui.Pads.ProjectPad
}
}
+ static FilePath GetRenamedFilePath (ProjectFile file, string newName)
+ {
+ if (file.IsLink) {
+ var oldLink = file.ProjectVirtualPath;
+ var newLink = oldLink.ParentDirectory.Combine (newName);
+ return file.Project.BaseDirectory.Combine (newLink);
+ }
+ return file.FilePath.ParentDirectory.Combine (newName);
+ }
+
+ /// <summary>
+ /// Returns all dependent files that have names that start with the old name of the file.
+ /// </summary>
+ static List<(ProjectFile File, string NewName)> GetDependentFilesToRename (ProjectFile file, string newName)
+ {
+ if (!file.HasChildren)
+ return null;
+
+ List<(ProjectFile File, string NewName)> files = null;
+
+ string oldName = file.FilePath.FileName;
+ foreach (ProjectFile child in file.DependentChildren) {
+ string oldChildName = child.FilePath.FileName;
+ if (oldChildName.StartsWith (oldName, StringComparison.CurrentCultureIgnoreCase)) {
+ string childNewName = newName + oldChildName.Substring (oldName.Length);
+
+ if (files == null)
+ files = new List<(ProjectFile projectFile, string name)> ();
+ files.Add ((child, childNewName));
+ }
+ }
+ return files;
+ }
+
+ static bool CanRenameFile (ProjectFile file, string newName)
+ {
+ ProjectFile newProjectFile = null;
+ FilePath newPath = GetRenamedFilePath (file, newName);
+
+ if (file.Project != null)
+ newProjectFile = file.Project.Files.GetFileWithVirtualPath (newPath.ToRelative (file.Project.BaseDirectory));
+
+ if (!FileService.IsValidPath (newPath) || ProjectFolderCommandHandler.ContainsDirectorySeparator (newName)) {
+ MessageService.ShowWarning (GettextCatalog.GetString ("The name you have chosen contains illegal characters. Please choose a different name."));
+ return false;
+ } else if ((newProjectFile != null && newProjectFile != file) || FileExistsCaseSensitive (file.FilePath.ParentDirectory, newName)) {
+ // If there is already a file under the newPath which is *different*, then throw an exception
+ MessageService.ShowWarning (GettextCatalog.GetString ("File or directory name is already in use. Please choose a different one."));
+ return false;
+ }
+
+ return true;
+ }
+
static bool FileExistsCaseSensitive (FilePath parentDirectory, string fileName)
{
if (!Directory.Exists (parentDirectory))
@@ -393,9 +444,10 @@ namespace MonoDevelop.Ide.Gui.Pads.ProjectPad
{
var toggledActions = new Set<string> ();
Project proj = null;
+ ProjectFile finfo = null;
foreach (var node in CurrentNodes) {
- var finfo = (ProjectFile) node.DataItem;
+ finfo = (ProjectFile) node.DataItem;
//disallow multi-slect on more than one project, since available build actions may differ
if (proj == null && finfo.Project != null) {
@@ -410,7 +462,7 @@ namespace MonoDevelop.Ide.Gui.Pads.ProjectPad
if (proj == null)
return;
- foreach (string action in proj.GetBuildActions ()) {
+ foreach (string action in proj.GetBuildActions (finfo.FilePath)) {
if (action == "--") {
info.AddSeparator ();
} else {
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/Document.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/Document.cs
index 6abe1511a5..7d1f8c923a 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/Document.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/Document.cs
@@ -235,7 +235,6 @@ namespace MonoDevelop.Ide.Gui
get { return adhocProject != null; }
}
-
public override bool IsCompileableInProject {
get {
var project = Project;
@@ -431,6 +430,7 @@ namespace MonoDevelop.Ide.Gui
await Window.ViewContent.Save (fileName + "~");
FileService.NotifyFileChanged (fileName + "~");
}
+ DocumentRegistry.SkipNextChange (fileName);
await Window.ViewContent.Save (fileName);
FileService.NotifyFileChanged (fileName);
OnSaved(EventArgs.Empty);
@@ -838,6 +838,11 @@ namespace MonoDevelop.Ide.Gui
analysisDocumentSrc = new CancellationTokenSource ();
}
+ /// <summary>
+ /// During that process ad hoc projects shouldn't be created.
+ /// </summary>
+ internal static bool IsInProjectSettingLoadingProcess { get; set; }
+
Task EnsureAnalysisDocumentIsOpen ()
{
if (analysisDocument != null) {
@@ -862,16 +867,16 @@ namespace MonoDevelop.Ide.Gui
return Task.CompletedTask;
SubscribeRoslynWorkspace ();
analysisDocument = FileName != null ? TypeSystemService.GetDocumentId (this.Project, this.FileName) : null;
- if (analysisDocument != null) {
+ if (analysisDocument != null && !RoslynWorkspace.IsDocumentOpen(analysisDocument)) {
TypeSystemService.InformDocumentOpen (analysisDocument, Editor);
OnAnalysisDocumentChanged (EventArgs.Empty);
- return Task.CompletedTask;
}
+ return Task.CompletedTask;
}
}
lock (adhocProjectLock) {
var token = analysisDocumentSrc.Token;
- if (adhocProject != null) {
+ if (adhocProject != null || IsInProjectSettingLoadingProcess) {
return Task.CompletedTask;
}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/ViewCommandHandlers.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/ViewCommandHandlers.cs
index fd2177cd6f..864ca29f0e 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/ViewCommandHandlers.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/ViewCommandHandlers.cs
@@ -359,61 +359,61 @@ namespace MonoDevelop.Ide.Gui
[CommandHandler (TextEditorCommands.LineEnd)]
protected void OnLineEnd ()
{
- doc.Editor.EditorActionHost.MoveCaretToLineEnd ();
+ doc.Editor.EditorOperations.MoveToEndOfLine (false);
}
[CommandHandler (TextEditorCommands.LineStart)]
protected void OnLineStart ()
{
- doc.Editor.EditorActionHost.MoveCaretToLineStart ();
+ doc.Editor.EditorOperations.MoveToStartOfLine (false);
}
[CommandHandler (TextEditorCommands.DeleteLeftChar)]
protected void OnDeleteLeftChar ()
{
- doc.Editor.EditorActionHost.Backspace ();
+ doc.Editor.EditorOperations.Backspace ();
}
[CommandHandler (TextEditorCommands.DeleteRightChar)]
protected void OnDeleteRightChar ()
{
- doc.Editor.EditorActionHost.Delete ();
+ doc.Editor.EditorOperations.Delete ();
}
[CommandHandler (TextEditorCommands.CharLeft)]
protected void OnCharLeft ()
{
- doc.Editor.EditorActionHost.MoveCaretLeft ();
+ doc.Editor.EditorOperations.MoveToPreviousCharacter (false);
}
[CommandHandler (TextEditorCommands.CharRight)]
protected void OnCharRight ()
{
- doc.Editor.EditorActionHost.MoveCaretRight ();
+ doc.Editor.EditorOperations.MoveToNextCharacter (false);
}
[CommandHandler (TextEditorCommands.LineUp)]
protected void OnLineUp ()
{
- doc.Editor.EditorActionHost.MoveCaretUp ();
+ doc.Editor.EditorOperations.MoveLineUp (false);
}
[CommandHandler (TextEditorCommands.LineDown)]
protected void OnLineDown ()
{
- doc.Editor.EditorActionHost.MoveCaretDown ();
+ doc.Editor.EditorOperations.MoveLineDown (false);
}
[CommandHandler (TextEditorCommands.DocumentStart)]
protected void OnDocumentStart ()
{
- doc.Editor.EditorActionHost.MoveCaretToDocumentStart ();
+ doc.Editor.EditorOperations.MoveToStartOfDocument (false);
}
[CommandHandler (TextEditorCommands.DocumentEnd)]
protected void OnDocumentEnd ()
{
- doc.Editor.EditorActionHost.MoveCaretToDocumentEnd ();
+ doc.Editor.EditorOperations.MoveToEndOfDocument (false);
}
[CommandHandler (TextEditorCommands.DeleteLine)]
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Projects.OptionPanels/BaseDirectoryPanelWidget.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Projects.OptionPanels/BaseDirectoryPanelWidget.cs
index 7f0ed03eca..87763fbec2 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Projects.OptionPanels/BaseDirectoryPanelWidget.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Projects.OptionPanels/BaseDirectoryPanelWidget.cs
@@ -41,6 +41,8 @@ namespace MonoDevelop.Ide.Projects.OptionPanels
public BaseDirectoryPanelWidget()
{
this.Build();
+
+ label2.Accessible.SetShouldIgnore (true);
var a = folderentry.EntryAccessible;
a.SetTitleUIElement (label3.Accessible);
label3.Accessible.SetTitleFor (a);
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 876fd4dc31..c301f2cbbf 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Projects/ApplyPolicyDialog.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Projects/ApplyPolicyDialog.cs
@@ -146,7 +146,7 @@ namespace MonoDevelop.Ide.Projects
var sorted = content.ToList ();
sorted.Sort ((x, y) => x.Key.CompareTo(y.Key));
- StringBuilder sb = new StringBuilder ();
+ StringBuilder sb = StringBuilderCache.Allocate ();
foreach (var pol in sorted) {
if (sb.Length > 0)
@@ -168,7 +168,7 @@ namespace MonoDevelop.Ide.Projects
sb.Append (")");
}
}
- return sb.ToString ();
+ return StringBuilderCache.ReturnAndFree (sb);
}
protected void OnCombPoliciesChanged (object sender, System.EventArgs e)
@@ -256,7 +256,7 @@ namespace MonoDevelop.Ide.Projects
store.Clear ();
- var sb = new StringBuilder ();
+ var sb = StringBuilderCache.Allocate ();
foreach (var pol in sorted) {
sb.Append (pol.Key);
if (pol.Value.Count != 1 || pol.Value[0].Length != 0) {
@@ -277,7 +277,7 @@ namespace MonoDevelop.Ide.Projects
store.AppendValues (sb.ToString ());
sb.Length = 0;
}
-
+ StringBuilderCache.Free (sb);
HasPolicies = sorted.Count > 0;
}
}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Projects/AssemblyReferencePanel.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Projects/AssemblyReferencePanel.cs
index a87031db12..a1b91bf4ca 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Projects/AssemblyReferencePanel.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Projects/AssemblyReferencePanel.cs
@@ -285,7 +285,7 @@ namespace MonoDevelop.Ide.Projects
internal static string GetMatchMarkup (Gtk.Widget widget, string text, int[] matches, int startIndex)
{
- StringBuilder result = new StringBuilder ();
+ StringBuilder result = StringBuilderCache.Allocate ();
int lastPos = 0;
var color = HslColor.GenerateHighlightColors (widget.Style.Base (StateType.Normal),
widget.Style.Text (StateType.Normal), 3)[2];
@@ -304,7 +304,7 @@ namespace MonoDevelop.Ide.Projects
}
if (lastPos < text.Length)
result.Append (GLib.Markup.EscapeText (text.Substring (lastPos, text.Length - lastPos)));
- return result.ToString ();
+ return StringBuilderCache.ReturnAndFree (result);
}
public void AddReference (object sender, Gtk.ToggledArgs e)
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Projects/IdeFileSystemExtensionExtension.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Projects/IdeFileSystemExtensionExtension.cs
index 1472f82945..52ef22a80f 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Projects/IdeFileSystemExtensionExtension.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Projects/IdeFileSystemExtensionExtension.cs
@@ -63,8 +63,7 @@ namespace MonoDevelop.Ide.Projects
string error = GettextCatalog.GetString ("File {0} is read-only", file.FileName);
- var btn = new AlertButton (GettextCatalog.GetString ("Make Writable"));
- var res = MessageService.AskQuestion (error, GettextCatalog.GetString ("Would you like {0} to attempt to make the file writable and try again?", BrandingService.ApplicationName), btn, AlertButton.Cancel);
+ var res = MessageService.AskQuestion (error, GettextCatalog.GetString ("Would you like {0} to attempt to make the file writable and try again?", BrandingService.ApplicationName), AlertButton.MakeWriteable, AlertButton.Cancel);
if (res == AlertButton.Cancel)
throw new UserException (error) { AlreadyReportedToUser = true };
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Projects/NewFileDialog.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Projects/NewFileDialog.cs
index 4165abbf21..6f46230c8b 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Projects/NewFileDialog.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Projects/NewFileDialog.cs
@@ -507,7 +507,7 @@ namespace MonoDevelop.Ide.Projects
public event EventHandler OnOked;
- void OpenEvent (object sender, EventArgs e)
+ async void OpenEvent (object sender, EventArgs e)
{
if (!okButton.Sensitive)
return;
@@ -531,7 +531,7 @@ namespace MonoDevelop.Ide.Projects
}
try {
- if (!item.Create (project, project, path, titem.Language, filename))
+ if (!await item.Create (project, project, path, titem.Language, filename))
return;
} catch (Exception ex) {
LoggingService.LogError ("Error creating file", ex);
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.StandardHeader/StandardHeaderService.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.StandardHeader/StandardHeaderService.cs
index f3692a002d..4f78ec6d34 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.StandardHeader/StandardHeaderService.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.StandardHeader/StandardHeaderService.cs
@@ -70,7 +70,7 @@ namespace MonoDevelop.Ide.StandardHeader
if (!char.IsWhiteSpace (cmt[cmt.Length - 1]))
cmt = cmt + " ";
- StringBuilder sb = new StringBuilder (policy.Text.Length);
+ StringBuilder sb = StringBuilderCache.Allocate ();
string[] lines = policy.Text.Split ('\n');
foreach (string line in lines) {
if (string.IsNullOrWhiteSpace (line)) {
@@ -82,7 +82,7 @@ namespace MonoDevelop.Ide.StandardHeader
sb.Append (line);
sb.Append (eolMarker);
}
- result = sb.ToString ();
+ result = StringBuilderCache.ReturnAndFree (sb);
} else {
//multiline comment
result = String.Concat (comment[0], "\n", policy.Text, "\n", comment[1], "\n");
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/DirectoryTemplate.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/DirectoryTemplate.cs
index be481a9ca5..7e6aa7d606 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/DirectoryTemplate.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/DirectoryTemplate.cs
@@ -30,6 +30,7 @@ using System.Xml;
using System.IO;
using MonoDevelop.Core;
using MonoDevelop.Projects;
+using System.Threading.Tasks;
namespace MonoDevelop.Ide.Templates
{
@@ -85,7 +86,7 @@ namespace MonoDevelop.Ide.Templates
t.Show ();
}
- public override bool AddToProject (SolutionFolderItem policyParent, Project project,
+ public override async Task<bool> AddToProjectAsync (SolutionFolderItem policyParent, Project project,
string language, string directory, string name)
{
bool addedSomething = false;
@@ -97,6 +98,26 @@ namespace MonoDevelop.Ide.Templates
}
foreach (FileDescriptionTemplate t in templates) {
+ if (t.EvaluateCreateCondition ()) {
+ addedSomething |= await t.AddToProjectAsync (policyParent, project, language, directory, name);
+ }
+ }
+ return addedSomething;
+ }
+
+ [Obsolete ("Use public Task<bool> AddToProjectAsync (SolutionFolderItem policyParent, Project project, string language, string directory, string entryName).")]
+ public override bool AddToProject (SolutionFolderItem policyParent, Project project,
+ string language, string directory, string name)
+ {
+ bool addedSomething = false;
+ directory = Path.Combine (directory, dirName);
+ if (templates.Count == 0) {
+ string relPath = FileService.AbsoluteToRelativePath (project.BaseDirectory, directory);
+ if (project.AddDirectory (relPath) != null)
+ addedSomething = true;
+ }
+
+ foreach (FileDescriptionTemplate t in templates) {
if (t.EvaluateCreateCondition ())
addedSomething |= t.AddToProject (policyParent, project, language, directory, name);
}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/FileDescriptionTemplate.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/FileDescriptionTemplate.cs
index 4d6b1fe1ba..2164ddc98a 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/FileDescriptionTemplate.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/FileDescriptionTemplate.cs
@@ -37,6 +37,7 @@ using Mono.Addins;
using MonoDevelop.Projects;
using MonoDevelop.Ide.Codons;
using MonoDevelop.Core.StringParsing;
+using System.Threading.Tasks;
namespace MonoDevelop.Ide.Templates
{
@@ -73,7 +74,17 @@ namespace MonoDevelop.Ide.Templates
public abstract string Name { get; }
public abstract void Load (XmlElement filenode, FilePath baseDirectory);
- public abstract bool AddToProject (SolutionFolderItem policyParent, Project project, string language, string directory, string name);
+
+ [Obsolete("Use public abstract Task<bool> AddToProjectAsync (SolutionFolderItem policyParent, Project project, string language, string directory, string name)")]
+ public virtual bool AddToProject (SolutionFolderItem policyParent, Project project, string language, string directory, string name)
+ {
+ return false;
+ }
+
+ public virtual Task<bool> AddToProjectAsync (SolutionFolderItem policyParent, Project project, string language, string directory, string name)
+ {
+ return Task.FromResult(AddToProject (policyParent, project, language, directory, name));
+ }
public abstract void Show ();
internal string CreateCondition { get; private set; }
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/FileTemplate.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/FileTemplate.cs
index b183a357c2..8777fe313a 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/FileTemplate.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/FileTemplate.cs
@@ -34,6 +34,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using System.Threading.Tasks;
using System.Xml;
using Gtk;
using Mono.Addins;
@@ -244,13 +245,13 @@ namespace MonoDevelop.Ide.Templates
return node == null ? null : LoadTemplate (node);
}
- public virtual bool Create (SolutionFolderItem policyParent, Project project, string directory, string language, string name)
+ public virtual async Task<bool> Create (SolutionFolderItem policyParent, Project project, string directory, string language, string name)
{
if (!String.IsNullOrEmpty (WizardPath)) {
return false;
} else {
foreach (FileDescriptionTemplate newfile in Files)
- if (!CreateFile (newfile, policyParent, project, directory, language, name))
+ if (!await CreateFile (newfile, policyParent, project, directory, language, name))
return false;
return true;
}
@@ -303,13 +304,13 @@ namespace MonoDevelop.Ide.Templates
}
}
- protected virtual bool CreateFile (FileDescriptionTemplate newfile, SolutionFolderItem policyParent, Project project, string directory, string language, string name)
+ protected virtual async Task<bool> CreateFile (FileDescriptionTemplate newfile, SolutionFolderItem policyParent, Project project, string directory, string language, string name)
{
if (project != null) {
var model = project.GetStringTagModel (new DefaultConfigurationSelector ());
newfile.SetProjectTagModel (model);
try {
- if (newfile.AddToProject (policyParent, project, language, directory, name)) {
+ if (await newfile.AddToProjectAsync (policyParent, project, language, directory, name)) {
newfile.Show ();
return true;
}
@@ -322,14 +323,14 @@ namespace MonoDevelop.Ide.Templates
throw new InvalidOperationException ("Single file template expected");
if (directory != null) {
- string fileName = singleFile.SaveFile (policyParent, project, language, directory, name);
+ string fileName = await singleFile.SaveFileAsync (policyParent, project, language, directory, name);
if (fileName != null) {
IdeApp.Workbench.OpenDocument (fileName, project);
return true;
}
} else {
string fileName = singleFile.GetFileName (policyParent, project, language, directory, name);
- Stream stream = singleFile.CreateFileContent (policyParent, project, language, fileName, name);
+ Stream stream = singleFile.CreateFileContent (policyParent, project, language, fileName, name) ?? await singleFile.CreateFileContentAsync (policyParent, project, language, fileName, name);
string mimeType = GuessMimeType (fileName);
IdeApp.Workbench.NewDocument (fileName, mimeType, stream);
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/FileTemplateReference.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/FileTemplateReference.cs
index f815ec1c8c..9a6e891791 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/FileTemplateReference.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/FileTemplateReference.cs
@@ -34,6 +34,7 @@ using System.Xml;
using MonoDevelop.Projects;
using MonoDevelop.Core;
using MonoDevelop.Core.StringParsing;
+using System.Threading.Tasks;
namespace MonoDevelop.Ide.Templates
{
@@ -67,7 +68,7 @@ namespace MonoDevelop.Ide.Templates
get { return name;}
}
- public override bool AddToProject (SolutionFolderItem policyParent, Project project, string language, string directory, string entryName)
+ public override async Task<bool> AddToProjectAsync (SolutionFolderItem policyParent, Project project, string language, string directory, string entryName)
{
string[,] customTags = new string[,] {
{"ProjectName", project.Name},
@@ -79,6 +80,26 @@ namespace MonoDevelop.Ide.Templates
foreach (FileDescriptionTemplate fdt in innerTemplate.Files) {
if (fdt.EvaluateCreateCondition ()) {
+ if (!await fdt.AddToProjectAsync (policyParent, project, language, directory, substName))
+ return false;
+ }
+ }
+ return true;
+ }
+
+ [Obsolete ("Use public Task<bool> AddToProjectAsync (SolutionFolderItem policyParent, Project project, string language, string directory, string entryName).")]
+ public override bool AddToProject (SolutionFolderItem policyParent, Project project, string language, string directory, string entryName)
+ {
+ string[,] customTags = new string[,] {
+ {"ProjectName", project.Name},
+ {"EntryName", entryName},
+ {"EscapedProjectName", GetDotNetIdentifier (project.Name) }
+ };
+
+ string substName = StringParserService.Parse (this.name, customTags);
+
+ foreach (FileDescriptionTemplate fdt in innerTemplate.Files) {
+ if (fdt.EvaluateCreateCondition ()) {
if (!fdt.AddToProject (policyParent, project, language, directory, substName))
return false;
}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/ItemTemplate.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/ItemTemplate.cs
new file mode 100644
index 0000000000..ab18ac9ef6
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/ItemTemplate.cs
@@ -0,0 +1,49 @@
+ο»Ώ//
+// ItemTemplate.cs
+//
+// Author:
+// Matt Ward <matt.ward@xamarin.com>
+//
+// Copyright (c) 2017 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
+// 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;
+
+namespace MonoDevelop.Ide.Templates
+{
+ public class ItemTemplate
+ {
+ internal ItemTemplate (string id, string name)
+ {
+ Id = id;
+ Name = name;
+ }
+
+ public string Id { get; private set; }
+ public string Name { get; private set; }
+ public string Language { get; set; }
+
+ public virtual Stream GetStream (string path)
+ {
+ return null;
+ }
+ }
+}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/ItemTemplatePackageInstaller.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/ItemTemplatePackageInstaller.cs
new file mode 100644
index 0000000000..141bf9698d
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/ItemTemplatePackageInstaller.cs
@@ -0,0 +1,37 @@
+ο»Ώ//
+// ItemTemplatePackageInstaller.cs
+//
+// Author:
+// Matt Ward <matt.ward@xamarin.com>
+//
+// Copyright (c) 2017 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
+// 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.Collections.Generic;
+using System.Threading.Tasks;
+using MonoDevelop.Projects;
+
+namespace MonoDevelop.Ide.Templates
+{
+ public abstract class ItemTemplatePackageInstaller
+ {
+ public abstract Task Run (Project project, IEnumerable<TemplatePackageReference> packageReferences);
+ }
+}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/MicrosoftTemplateEngine.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/MicrosoftTemplateEngine.cs
new file mode 100644
index 0000000000..156114a3fd
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/MicrosoftTemplateEngine.cs
@@ -0,0 +1,349 @@
+//
+// MicrosoftTemplateEngine.cs
+//
+// Author:
+// David KarlaΕ‘ <david.karlas@xamarin.com>
+//
+// Copyright (c) 2017 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
+// 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.Linq;
+using System.Threading.Tasks;
+using Microsoft.TemplateEngine.Abstractions;
+using Microsoft.TemplateEngine.Abstractions.Mount;
+using Microsoft.TemplateEngine.Edge;
+using Microsoft.TemplateEngine.Edge.Settings;
+using Microsoft.TemplateEngine.Edge.Template;
+using Microsoft.TemplateEngine.Orchestrator.RunnableProjects;
+using Microsoft.TemplateEngine.Orchestrator.RunnableProjects.Config;
+using Microsoft.TemplateEngine.Orchestrator.RunnableProjects.Macros;
+using Microsoft.TemplateEngine.Utils;
+using Mono.Addins;
+using MonoDevelop.Core;
+using MonoDevelop.Core.Text;
+using MonoDevelop.Ide.CodeFormatting;
+using MonoDevelop.Ide.Codons;
+using MonoDevelop.Ide.Projects;
+using MonoDevelop.Projects.Policies;
+
+namespace MonoDevelop.Ide.Templates
+{
+ class MicrosoftTemplateEngine
+ {
+ static EngineEnvironmentSettings environmentSettings = new EngineEnvironmentSettings (new MyTemplateEngineHost (), (env) => new SettingsLoader (env));
+ static TemplateCreator templateCreator = new TemplateCreator (environmentSettings);
+
+ static bool dontUpdateCache = true;
+
+ static MicrosoftTemplateEngine ()
+ {
+ AddinManager.AddExtensionNodeHandler ("/MonoDevelop/Ide/Templates", OnProjectTemplateExtensionChanged);
+ AddinManager.AddExtensionNodeHandler ("/MonoDevelop/Ide/ItemTemplates", OnItemTemplateExtensionChanged);
+ dontUpdateCache = false;
+ UpdateCache ();
+ }
+
+ static List<TemplateExtensionNode> projectTemplateNodes = new List<TemplateExtensionNode> ();
+ static List<MicrosoftTemplateEngineSolutionTemplate> projectTemplates = new List<MicrosoftTemplateEngineSolutionTemplate> ();
+ static List<ItemTemplateExtensionNode> itemTemplateNodes = new List<ItemTemplateExtensionNode> ();
+ static List<MicrosoftTemplateEngineItemTemplate> itemTemplates = new List<MicrosoftTemplateEngineItemTemplate> ();
+
+ static void UpdateCache ()
+ {
+ if (dontUpdateCache)//Avoid updating cache while scan paths are added during registration
+ return;
+
+ // Prevent a TypeInitializationException in when calling SettingsLoader.Save when no templates
+ // are available, which throws an exception, by returning here. This prevents the MonoDevelop.Ide addin
+ // from loading. In practice this should not happen unless the .NET Core addin is disabled.
+ if (!projectTemplateNodes.Any () && !itemTemplateNodes.Any ())
+ return;
+
+ var paths = new Paths (environmentSettings);
+
+ //TODO: Uncomment this IF, but also add logic to invalidate/check if new templates were added from newly installed AddOns...
+ //if (!paths.Exists (paths.User.BaseDir) || !paths.Exists (paths.User.FirstRunCookie)) {
+ paths.DeleteDirectory (paths.User.BaseDir);//Delete cache
+ var settingsLoader = (SettingsLoader)environmentSettings.SettingsLoader;
+
+ foreach (var scanPath in projectTemplateNodes.Select (t => t.ScanPath).Distinct ()) {
+ settingsLoader.UserTemplateCache.Scan (scanPath);
+ }
+
+ foreach (var scanPath in itemTemplateNodes.Select (t => t.ScanPath).Distinct ()) {
+ settingsLoader.UserTemplateCache.Scan (scanPath);
+ }
+
+ settingsLoader.Save ();
+ paths.WriteAllText (paths.User.FirstRunCookie, "");
+ //}
+ var templateInfos = settingsLoader.UserTemplateCache.List (false, t => new MatchInfo ()).ToDictionary (m => m.Info.Identity, m => m.Info);
+ var newProjectTemplates = new List<MicrosoftTemplateEngineSolutionTemplate> ();
+ foreach (var template in projectTemplateNodes) {
+ ITemplateInfo templateInfo;
+ if (!templateInfos.TryGetValue (template.TemplateId, out templateInfo)) {
+ LoggingService.LogWarning ("Template {0} not found.", template.TemplateId);
+ continue;
+ }
+ newProjectTemplates.Add (new MicrosoftTemplateEngineSolutionTemplate (template, templateInfo));
+ }
+ projectTemplates = newProjectTemplates;
+
+ var newItemTemplates = new List<MicrosoftTemplateEngineItemTemplate> ();
+ foreach (var template in itemTemplateNodes) {
+ ITemplateInfo templateInfo;
+ if (!templateInfos.TryGetValue (template.TemplateId, out templateInfo)) {
+ LoggingService.LogWarning ("Template {0} not found.", template.TemplateId);
+ continue;
+ }
+ newItemTemplates.Add (new MicrosoftTemplateEngineItemTemplate (template, templateInfo));
+ }
+ itemTemplates = newItemTemplates;
+ }
+
+ static void OnProjectTemplateExtensionChanged (object sender, ExtensionNodeEventArgs args)
+ {
+ var node = (TemplateExtensionNode)args.ExtensionNode;
+
+ OnExtensionChanged (projectTemplateNodes, node, args.Change);
+ }
+
+ static void OnItemTemplateExtensionChanged (object sender, ExtensionNodeEventArgs args)
+ {
+ var node = (ItemTemplateExtensionNode)args.ExtensionNode;
+
+ OnExtensionChanged (itemTemplateNodes, node, args.Change);
+ }
+
+ static void OnExtensionChanged<T> (List<T> extensionNodes, T node, ExtensionChange change)
+ where T : ExtensionNode
+ {
+ if (change == ExtensionChange.Add) {
+ try {
+ extensionNodes.Add (node);
+ } catch (Exception ex) {
+ LogExtensionChangedError (ex, node);
+ }
+ } else {
+ foreach (var existingNode in extensionNodes) {
+ if (existingNode.Id == node.Id) {
+ extensionNodes.Remove (existingNode);
+ break;
+ }
+ }
+ }
+
+ UpdateCache ();
+ }
+
+ static void LogExtensionChangedError (Exception ex, ExtensionNode node)
+ {
+ string extId = null;
+ string addinId = null;
+
+ if (node != null) {
+ if (node.HasId)
+ extId = node.Id;
+ if (node.Addin != null)
+ addinId = node.Addin.Id;
+ }
+
+ LoggingService.LogError ("Error loading template id {0} in addin {1}:\n{2}",
+ extId ?? "(null)", addinId ?? "(null)", ex.ToString ());
+ }
+
+ public static IEnumerable<SolutionTemplate> GetProjectTemplates ()
+ {
+ return projectTemplates;
+ }
+
+ public static IEnumerable<ItemTemplate> GetItemTemplates ()
+ {
+ return itemTemplates;
+ }
+
+ /// <summary>
+ /// Used by unit tests to create a new solution template without having to use an addin.
+ /// </summary>
+ static internal SolutionTemplate CreateProjectTemplate (string templateId, string scanPath)
+ {
+ var settingsLoader = (SettingsLoader)environmentSettings.SettingsLoader;
+ settingsLoader.UserTemplateCache.Scan (scanPath);
+ settingsLoader.Save ();
+
+ var templateInfo = settingsLoader.UserTemplateCache.TemplateInfo
+ .FirstOrDefault (t => t.Identity == templateId);
+
+ return new MicrosoftTemplateEngineSolutionTemplate (templateId, templateId, null, templateInfo);
+ }
+
+ public static Task<TemplateCreationResult> InstantiateAsync (
+ ITemplateInfo templateInfo,
+ NewProjectConfiguration config,
+ IReadOnlyDictionary<string, string> parameters)
+ {
+ return templateCreator.InstantiateAsync (
+ templateInfo,
+ config.ProjectName,
+ config.GetValidProjectName (),
+ config.ProjectLocation,
+ parameters,
+ true,
+ false,
+ null
+ );
+ }
+
+ public static Task<TemplateCreationResult> InstantiateAsync (
+ ITemplateInfo templateInfo,
+ NewItemConfiguration config,
+ IReadOnlyDictionary<string, string> parameters)
+ {
+ return templateCreator.InstantiateAsync (
+ templateInfo,
+ config.NameWithoutExtension,
+ config.NameWithoutExtension,
+ config.Directory,
+ parameters,
+ true,
+ false,
+ null
+ );
+ }
+
+ public static string GetPath (ICreationPath path)
+ {
+ return NormalizePath (path.Path);
+ }
+
+ static string NormalizePath (string path)
+ {
+ if (Path.DirectorySeparatorChar != '\\')
+ return path.Replace ('\\', Path.DirectorySeparatorChar);
+
+ return path;
+ }
+
+ public static async Task FormatFile (PolicyContainer policies, FilePath file)
+ {
+ string mime = DesktopService.GetMimeTypeForUri (file);
+ if (mime == null)
+ return;
+
+ var formatter = CodeFormatterService.GetFormatter (mime);
+ if (formatter != null) {
+ try {
+ var content = await TextFileUtility.ReadAllTextAsync (file);
+ var formatted = formatter.FormatText (policies, content.Text);
+ if (formatted != null)
+ TextFileUtility.WriteText (file, formatted, content.Encoding);
+ } catch (Exception ex) {
+ LoggingService.LogError ("File formatting failed", ex);
+ }
+ }
+ }
+
+ public static string MergeDefaultParameters (string defaultParameters, ITemplateInfo templateInfo)
+ {
+ List<TemplateParameter> priorityParameters = null;
+ var parameters = new List<string> ();
+ var cacheParameters = templateInfo.CacheParameters.Where (m => !string.IsNullOrEmpty (m.Value.DefaultValue));
+
+ if (!cacheParameters.Any ())
+ return defaultParameters;
+
+ if (!string.IsNullOrEmpty (defaultParameters)) {
+ priorityParameters = TemplateParameter.CreateParameters (defaultParameters).ToList ();
+ defaultParameters += ",";
+ }
+
+ foreach (var p in cacheParameters) {
+ if (priorityParameters == null || !priorityParameters.Exists (t => t.Name == p.Key))
+ parameters.Add ($"{p.Key}={p.Value.DefaultValue}");
+ }
+
+ return defaultParameters += string.Join (",", parameters);
+ }
+
+ public static string GetLanguage (ITemplateInfo templateInfo)
+ {
+ ICacheTag languageTag;
+ if (templateInfo.Tags.TryGetValue ("language", out languageTag)) {
+ return languageTag.DefaultValue;
+ }
+
+ return string.Empty;
+ }
+
+ /// <summary>
+ /// Use '${TemplateConfigDirectory}/template.json' to get the template.json file
+ /// without having to specify the full path.
+ /// </summary>
+ public static Stream GetStream (ITemplateInfo template, string path)
+ {
+ path = NormalizePath (template, path);
+
+ var settingsLoader = (SettingsLoader)environmentSettings.SettingsLoader;
+
+ IMountPoint mountPoint;
+ IFile file;
+ if (settingsLoader.TryGetFileFromIdAndPath (template.ConfigMountPointId, path, out file, out mountPoint)) {
+ return file.OpenRead ();
+ }
+
+ return null;
+ }
+
+ static string NormalizePath (ITemplateInfo template, string path)
+ {
+ path = NormalizePath (path);
+
+ var tags = new string[,] {
+ {"TemplateConfigDirectory", Path.GetDirectoryName (template.ConfigPlace) }
+ };
+
+ return StringParserService.Parse (path, tags);
+ }
+
+ class MyTemplateEngineHost : DefaultTemplateEngineHost
+ {
+ static readonly AssemblyComponentCatalog builtIns = new AssemblyComponentCatalog (new[] {
+ typeof (RunnableProjectGenerator).Assembly,
+ });
+
+ public MyTemplateEngineHost () : base (BrandingService.ApplicationName, BuildInfo.CompatVersion, "en-US", new Dictionary<string, string> { { "dotnet-cli-version", "0" } }, builtIns)
+ {
+ }
+
+ public override bool TryGetHostParamDefault (string paramName, out string value)
+ {
+ if (paramName == "HostIdentifier") {
+ value = this.HostIdentifier;
+ return true;
+ }
+ value = null;
+ return false;
+ }
+ }
+ }
+}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/MicrosoftTemplateEngineItemTemplate.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/MicrosoftTemplateEngineItemTemplate.cs
new file mode 100644
index 0000000000..1dc550c4ee
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/MicrosoftTemplateEngineItemTemplate.cs
@@ -0,0 +1,50 @@
+ο»Ώ//
+// MicrosoftTemplateEngineItemTemplate.cs
+//
+// Author:
+// Matt Ward <matt.ward@xamarin.com>
+//
+// Copyright (c) 2017 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
+// 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.IO;
+using Microsoft.TemplateEngine.Abstractions;
+using MonoDevelop.Ide.Codons;
+
+namespace MonoDevelop.Ide.Templates
+{
+ class MicrosoftTemplateEngineItemTemplate : ItemTemplate
+ {
+ public MicrosoftTemplateEngineItemTemplate (ItemTemplateExtensionNode template, ITemplateInfo templateInfo)
+ : base (template.TemplateId, template.OverrideName ?? templateInfo.Name)
+ {
+ TemplateInfo = templateInfo;
+
+ Language = MicrosoftTemplateEngine.GetLanguage (templateInfo);
+ }
+
+ internal ITemplateInfo TemplateInfo { get; private set; }
+
+ public override Stream GetStream (string path)
+ {
+ return MicrosoftTemplateEngine.GetStream (TemplateInfo, path);
+ }
+ }
+}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/MicrosoftTemplateEngineItemTemplatingProvider.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/MicrosoftTemplateEngineItemTemplatingProvider.cs
new file mode 100644
index 0000000000..647cbd7c48
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/MicrosoftTemplateEngineItemTemplatingProvider.cs
@@ -0,0 +1,166 @@
+ο»Ώ//
+// MicrosoftTemplateEngineItemTemplatingProvider.cs
+//
+// Author:
+// Matt Ward <matt.ward@xamarin.com>
+//
+// Copyright (c) 2017 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
+// 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.Threading.Tasks;
+using Microsoft.TemplateEngine.Abstractions;
+using Microsoft.TemplateEngine.Edge.Template;
+using Mono.Addins;
+using MonoDevelop.Core.StringParsing;
+using MonoDevelop.Ide.Codons;
+using MonoDevelop.Projects;
+using System.Linq;
+using MonoDevelop.Core;
+using MonoDevelop.Projects.Policies;
+using MonoDevelop.Ide.CodeFormatting;
+using MonoDevelop.Core.Text;
+
+namespace MonoDevelop.Ide.Templates
+{
+ class MicrosoftTemplateEngineItemTemplatingProvider
+ {
+ public IEnumerable<ItemTemplate> GetTemplates ()
+ {
+ return MicrosoftTemplateEngine.GetItemTemplates ();
+ }
+
+ public async Task ProcessTemplate (ItemTemplate template, Project project, NewItemConfiguration config)
+ {
+ var itemTemplate = (MicrosoftTemplateEngineItemTemplate)template;
+ var parameters = GetParameters (project, itemTemplate, config);
+ var result = await MicrosoftTemplateEngine.InstantiateAsync (itemTemplate.TemplateInfo, config, parameters);
+
+ if (result.Status != CreationResultStatus.Success) {
+ string message = string.Format ("Could not create template. Id='{0}' {1} {2}", template.Id, result.Status, result.Message);
+ throw new InvalidOperationException (message);
+ }
+
+ foreach (var path in result.ResultInfo.PrimaryOutputs) {
+ string fullPath = Path.Combine (config.Directory, GetPath (path));
+
+ await MicrosoftTemplateEngine.FormatFile (project?.Policies, fullPath);
+
+ if (project != null) {
+ AddFileToProject (project, fullPath);
+ }
+
+ IdeApp.Workbench.OpenDocument (fullPath, project).Ignore ();
+
+ if (project != null) {
+ await InstallNuGetPackages (project, result.ResultInfo);
+ }
+ }
+ }
+
+ static Dictionary<string, string> GetParameters (Project project, MicrosoftTemplateEngineItemTemplate template, NewItemConfiguration config)
+ {
+ var parameters = new Dictionary<string, string> ();
+
+ var model = (IStringTagModel)config;
+ foreach (ITemplateParameter parameter in template.TemplateInfo.Parameters) {
+ string parameterValue = (string)model.GetValue (parameter.Name);
+ if (parameterValue != null)
+ parameters [parameter.Name] = parameterValue;
+ }
+
+ var dotNetProject = project as DotNetProject;
+ if (dotNetProject != null) {
+ string fileName = GetFullPathIncludingFileExtension (template, config);
+ parameters ["namespace"] = dotNetProject.GetDefaultNamespace (fileName);
+ }
+
+ return parameters;
+ }
+
+ static string GetFullPathIncludingFileExtension (MicrosoftTemplateEngineItemTemplate template, NewItemConfiguration config)
+ {
+ string fileName = config.Name;
+ if (StringComparer.OrdinalIgnoreCase.Equals (template.Language, "C#")) {
+ fileName = Path.ChangeExtension (config.Name, ".cs");
+ }
+ return Path.Combine (config.Directory, fileName);
+ }
+
+ void AddFileToProject (Project project, string fileName)
+ {
+ string buildAction = project.GetDefaultBuildAction (fileName);
+ ProjectFile projectFile = project.AddFile (fileName, buildAction);
+ }
+
+ static string GetPath (ICreationPath path)
+ {
+ return MicrosoftTemplateEngine.GetPath (path);
+ }
+
+ async Task InstallNuGetPackages (Project project, ICreationResult result)
+ {
+ var packageReferences = GetPackageReferences (result).ToList ();
+
+ if (!packageReferences.Any ())
+ return;
+
+ foreach (ItemTemplatePackageInstaller installer in AddinManager.GetExtensionObjects ("/MonoDevelop/Ide/ItemTemplatePackageInstallers")) {
+ await installer.Run (project, packageReferences);
+ }
+ }
+
+ IEnumerable<TemplatePackageReference> GetPackageReferences (ICreationResult result)
+ {
+ foreach (var postAction in result.PostActions) {
+ var packageReference = CreatePackageReference (postAction);
+ if (packageReference != null) {
+ yield return packageReference;
+ }
+ }
+ }
+
+ TemplatePackageReference CreatePackageReference (IPostAction action)
+ {
+ if (!IsInstallPackagePostAction (action))
+ return null;
+
+ if (!action.Args.TryGetValue ("reference", out string packageId))
+ return null;
+
+ if (!action.Args.TryGetValue ("version", out string packageVersion))
+ return null;
+
+ return new TemplatePackageReference (packageId, packageVersion);
+ }
+
+ static readonly Guid addReferencePostActionId = new Guid ("B17581D1-C5C9-4489-8F0A-004BE667B814");
+
+ static bool IsInstallPackagePostAction (IPostAction action)
+ {
+ return action.ActionId == addReferencePostActionId &&
+ action.Args != null &&
+ action.Args.TryGetValue ("referenceType", out string referenceType) &&
+ StringComparer.OrdinalIgnoreCase.Equals (referenceType, "package");
+ }
+ }
+}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/MicrosoftTemplateEngineProjectTemplatingProvider.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/MicrosoftTemplateEngineProjectTemplatingProvider.cs
index 4fa481ba91..6724b41f39 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/MicrosoftTemplateEngineProjectTemplatingProvider.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/MicrosoftTemplateEngineProjectTemplatingProvider.cs
@@ -1,4 +1,4 @@
-ο»Ώ//
+//
// MicrosoftTemplateEngineProjectTemplatingProvider.cs
//
// Author:
@@ -55,89 +55,9 @@ namespace MonoDevelop.Ide.Templates
return template is MicrosoftTemplateEngineSolutionTemplate;
}
- static EngineEnvironmentSettings environmentSettings = new EngineEnvironmentSettings (new MyTemplateEngineHost (), (env) => new SettingsLoader (env));
- static TemplateCreator templateCreator = new TemplateCreator (environmentSettings);
-
- static bool dontUpdateCache = true;
-
- static MicrosoftTemplateEngineProjectTemplatingProvider ()
- {
- AddinManager.AddExtensionNodeHandler ("/MonoDevelop/Ide/Templates", OnExtensionChanged);
- dontUpdateCache = false;
- UpdateCache ();
- }
-
- static List<TemplateExtensionNode> TemplatesNodes = new List<TemplateExtensionNode> ();
- static List<MicrosoftTemplateEngineSolutionTemplate> templates = new List<MicrosoftTemplateEngineSolutionTemplate> ();
-
- static void UpdateCache ()
- {
- if (dontUpdateCache)//Avoid updating cache while scan paths are added during registration
- return;
-
- // Prevent a TypeInitializationException in when calling SettingsLoader.Save when no templates
- // are available, which throws an exception, by returning here. This prevents the MonoDevelop.Ide addin
- // from loading. In practice this should not happen unless the .NET Core addin is disabled.
- if (!TemplatesNodes.Any ())
- return;
-
- var paths = new Paths (environmentSettings);
-
- //TODO: Uncomment this IF, but also add logic to invalidate/check if new templates were added from newly installed AddOns...
- //if (!paths.Exists (paths.User.BaseDir) || !paths.Exists (paths.User.FirstRunCookie)) {
- paths.DeleteDirectory (paths.User.BaseDir);//Delete cache
- var settingsLoader = (SettingsLoader)environmentSettings.SettingsLoader;
- foreach (var scanPath in TemplatesNodes.Select (t => t.ScanPath).Distinct ()) {
- settingsLoader.UserTemplateCache.Scan (scanPath);
- }
- settingsLoader.Save ();
- paths.WriteAllText (paths.User.FirstRunCookie, "");
- //}
- var templateInfos = settingsLoader.UserTemplateCache.List (false, t => new MatchInfo ()).ToDictionary (m => m.Info.Identity, m => m.Info);
- var newTemplates = new List<MicrosoftTemplateEngineSolutionTemplate> ();
- foreach (var template in TemplatesNodes) {
- ITemplateInfo templateInfo;
- if (!templateInfos.TryGetValue (template.TemplateId, out templateInfo)) {
- LoggingService.LogWarning ("Template {0} not found.", template.TemplateId);
- continue;
- }
- newTemplates.Add (new MicrosoftTemplateEngineSolutionTemplate (template, templateInfo));
- }
- templates = newTemplates;
- }
-
- static void OnExtensionChanged (object s, ExtensionNodeEventArgs args)
- {
- if (args.Change == ExtensionChange.Add) {
- var codon = (TemplateExtensionNode)args.ExtensionNode;
- try {
- TemplatesNodes.Add (codon);
- } catch (Exception e) {
- string extId = null, addinId = null;
- if (codon != null) {
- if (codon.HasId)
- extId = codon.Id;
- if (codon.Addin != null)
- addinId = codon.Addin.Id;
- }
- LoggingService.LogError ("Error loading template id {0} in addin {1}:\n{2}",
- extId ?? "(null)", addinId ?? "(null)", e.ToString ());
- }
- } else {
- foreach (var pt in TemplatesNodes) {
- var codon = (TemplateExtensionNode)args.ExtensionNode;
- if (pt.Id == codon.Id) {
- TemplatesNodes.Remove (pt);
- break;
- }
- }
- }
- UpdateCache ();
- }
-
public IEnumerable<SolutionTemplate> GetTemplates ()
{
- return templates;
+ return MicrosoftTemplateEngine.GetProjectTemplates ();
}
/// <summary>
@@ -145,14 +65,7 @@ namespace MonoDevelop.Ide.Templates
/// </summary>
static internal SolutionTemplate CreateTemplate (string templateId, string scanPath)
{
- var settingsLoader = (SettingsLoader)environmentSettings.SettingsLoader;
- settingsLoader.UserTemplateCache.Scan (scanPath);
- settingsLoader.Save ();
-
- var templateInfo = settingsLoader.UserTemplateCache.TemplateInfo
- .FirstOrDefault (t => t.Identity == templateId);
-
- return new MicrosoftTemplateEngineSolutionTemplate (templateId, templateId, null, templateInfo);
+ return MicrosoftTemplateEngine.CreateProjectTemplate (templateId, scanPath);
}
static MonoDevelop.Core.Instrumentation.Counter TemplateCounter = MonoDevelop.Core.Instrumentation.InstrumentationService.CreateCounter ("Template Instantiated", "Project Model", id: "Core.Template.Instantiated");
@@ -166,16 +79,12 @@ namespace MonoDevelop.Ide.Templates
var filesBeforeCreation = Directory.GetFiles (config.ProjectLocation, "*", SearchOption.AllDirectories);
- var result = await templateCreator.InstantiateAsync (
- templateInfo,
- config.ProjectName,
- config.GetValidProjectName (),
- config.ProjectLocation,
- parameters,
- true,
- false,
- null
- );
+ var result = await MicrosoftTemplateEngine.InstantiateAsync (templateInfo, config, parameters);
+
+ if (result.Status != CreationResultStatus.Success) {
+ string message = string.Format ("Could not create template. Id='{0}' {1} {2}", template.Id, result.Status, result.Message);
+ throw new InvalidOperationException (message);
+ }
var filesToOpen = new List<string> ();
foreach (var postAction in result.ResultInfo.PostActions) {
@@ -236,7 +145,7 @@ namespace MonoDevelop.Ide.Templates
foreach (var file in p.Files) {
if (!filesBeforeCreation.Contains ((string)file.FilePath, FilePath.PathComparer)) { //Format only newly created files
if (solutionTemplate.ShouldFormatFile (file.FilePath)) {
- await FormatFile (parentFolder?.Policies ?? p.Policies, file.FilePath);
+ await MicrosoftTemplateEngine.FormatFile (parentFolder?.Policies ?? p.Policies, file.FilePath);
}
}
}
@@ -245,12 +154,9 @@ namespace MonoDevelop.Ide.Templates
return processResult;
}
- string GetPath (ICreationPath path)
+ static string GetPath (ICreationPath path)
{
- if (Path.DirectorySeparatorChar != '\\')
- return path.Path.Replace ('\\', Path.DirectorySeparatorChar);
-
- return path.Path;
+ return MicrosoftTemplateEngine.GetPath (path);
}
Dictionary<string, string> GetParameters (MicrosoftTemplateEngineSolutionTemplate template, NewProjectConfiguration config)
@@ -280,45 +186,5 @@ namespace MonoDevelop.Ide.Templates
return TemplateParameter.CreateParameters (parameters)
.Where (parameter => parameter.IsValid);
}
-
- async Task FormatFile (PolicyContainer policies, FilePath file)
- {
- string mime = DesktopService.GetMimeTypeForUri (file);
- if (mime == null)
- return;
-
- var formatter = CodeFormatterService.GetFormatter (mime);
- if (formatter != null) {
- try {
- var content = await TextFileUtility.ReadAllTextAsync (file);
- var formatted = formatter.FormatText (policies, content.Text);
- if (formatted != null)
- TextFileUtility.WriteText (file, formatted, content.Encoding);
- } catch (Exception ex) {
- LoggingService.LogError ("File formatting failed", ex);
- }
- }
- }
-
- class MyTemplateEngineHost : DefaultTemplateEngineHost
- {
- static readonly AssemblyComponentCatalog builtIns = new AssemblyComponentCatalog (new[] {
- typeof (RunnableProjectGenerator).Assembly,
- });
-
- public MyTemplateEngineHost () : base (BrandingService.ApplicationName, BuildInfo.CompatVersion, "en-US", new Dictionary<string, string> { { "dotnet-cli-version", "0" } }, builtIns)
- {
- }
-
- public override bool TryGetHostParamDefault (string paramName, out string value)
- {
- if (paramName == "HostIdentifier") {
- value = this.HostIdentifier;
- return true;
- }
- value = null;
- return false;
- }
- }
}
}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/MicrosoftTemplateEngineSolutionTemplate.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/MicrosoftTemplateEngineSolutionTemplate.cs
index b0d0426f3f..c4194bdf1b 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/MicrosoftTemplateEngineSolutionTemplate.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/MicrosoftTemplateEngineSolutionTemplate.cs
@@ -43,18 +43,14 @@ namespace MonoDevelop.Ide.Templates
this.templateInfo = templateInfo;
Description = ParseDescription (template.OverrideDescription) ?? templateInfo.Description;
Category = template.Category;
- ICacheTag languageTag;
- if (templateInfo.Tags.TryGetValue ("language", out languageTag))
- Language = languageTag.DefaultValue;
- else
- Language = string.Empty;
+ Language = MicrosoftTemplateEngine.GetLanguage (templateInfo);
GroupId = template.GroupId ?? templateInfo.GroupIdentity;
//TODO: Support all this params
Condition = template.Condition;
//ProjectFileExtension = template.FileExtension;
Wizard = template.Wizard;
SupportedParameters = template.SupportedParameters;
- DefaultParameters = MergeDefaultParameters (template.DefaultParameters);
+ DefaultParameters = MicrosoftTemplateEngine.MergeDefaultParameters (template.DefaultParameters, templateInfo);
ImageId = template.ImageId;
FileFormattingExclude = template.FileFormatExclude;
//ImageFile = template.ImageFile;
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/NewItemConfiguration.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/NewItemConfiguration.cs
new file mode 100644
index 0000000000..cdfcd5320b
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/NewItemConfiguration.cs
@@ -0,0 +1,77 @@
+ο»Ώ//
+// NewItemConfiguration.cs
+//
+// Author:
+// Matt Ward <matt.ward@xamarin.com>
+//
+// Copyright (c) 2017 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
+// 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 MonoDevelop.Core.StringParsing;
+using MonoDevelop.Projects;
+
+namespace MonoDevelop.Ide.Templates
+{
+ public class NewItemConfiguration : IStringTagModel
+ {
+ Dictionary<string, string> parameters;
+
+ public NewItemConfiguration ()
+ {
+ parameters = new Dictionary<string, string> (StringComparer.OrdinalIgnoreCase);
+ }
+
+ public string Directory { get; set; }
+ public string Name { get; set; }
+
+ public string NameWithoutExtension {
+ get {
+ if (!string.IsNullOrEmpty (Name)) {
+ return Path.GetFileNameWithoutExtension (Name);
+ }
+ return string.Empty;
+ }
+ }
+
+ public string this [string name] {
+ get {
+ string result;
+ if (parameters.TryGetValue (name, out result)) {
+ return result;
+ }
+ return string.Empty;
+ }
+ set {
+ parameters [name] = value;
+ }
+ }
+
+ object IStringTagModel.GetValue (string name)
+ {
+ string result;
+ if (parameters.TryGetValue (name, out result))
+ return result;
+ return null;
+ }
+ }
+}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/ProjectDescriptor.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/ProjectDescriptor.cs
index b22295fcd5..a33e14a0c0 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/ProjectDescriptor.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/ProjectDescriptor.cs
@@ -141,7 +141,7 @@ namespace MonoDevelop.Ide.Templates
return project;
}
- public void InitializeItem (SolutionFolderItem policyParent, ProjectCreateInformation projectCreateInformation, string defaultLanguage, SolutionItem item)
+ public async void InitializeItem (SolutionFolderItem policyParent, ProjectCreateInformation projectCreateInformation, string defaultLanguage, SolutionItem item)
{
MonoDevelop.Projects.Project project = item as MonoDevelop.Projects.Project;
@@ -177,7 +177,7 @@ namespace MonoDevelop.Ide.Templates
try {
if (!projectCreateInformation.ShouldCreate (resourceTemplate.CreateCondition))
continue;
- var projectFile = new ProjectFile (resourceTemplate.SaveFile (policyParent, project, defaultLanguage, project.BaseDirectory, null));
+ var projectFile = new ProjectFile (await resourceTemplate.SaveFileAsync (policyParent, project, defaultLanguage, project.BaseDirectory, null));
projectFile.BuildAction = BuildAction.EmbeddedResource;
project.Files.Add (projectFile);
} catch (Exception ex) {
@@ -192,7 +192,7 @@ namespace MonoDevelop.Ide.Templates
if (!projectCreateInformation.ShouldCreate (fileTemplate.CreateCondition))
continue;
fileTemplate.SetProjectTagModel (projectCreateInformation.Parameters);
- fileTemplate.AddToProject (policyParent, project, defaultLanguage, project.BaseDirectory, null);
+ await fileTemplate.AddToProjectAsync (policyParent, project, defaultLanguage, project.BaseDirectory, null);
} catch (Exception ex) {
if (!IdeApp.IsInitialized)
throw;
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/PropertyDescriptionTemplate.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/PropertyDescriptionTemplate.cs
index 75aa833cb9..9b63af22a1 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/PropertyDescriptionTemplate.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/PropertyDescriptionTemplate.cs
@@ -24,6 +24,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
+using System.Threading.Tasks;
using System.Xml;
using MonoDevelop.Core;
using MonoDevelop.Ide.Templates;
@@ -68,6 +69,12 @@ namespace MonoDevelop.Ide.Templates
throw new InvalidOperationException ("Property is empty");
}
+ public override Task<bool> AddToProjectAsync (SolutionFolderItem policyParent, Project project, string language, string directory, string name)
+ {
+ AddToProject (policyParent, project, language, directory, name);
+ return Task.FromResult(true);
+ }
+
public override bool AddToProject (SolutionFolderItem policyParent, Project project, string language, string directory, string name)
{
var model = CombinedTagModel.GetTagModel (ProjectTagModel, policyParent, project, language, name, null);
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/ResourceFileDescriptionTemplate.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/ResourceFileDescriptionTemplate.cs
index b52003c6ca..eb05572766 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/ResourceFileDescriptionTemplate.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/ResourceFileDescriptionTemplate.cs
@@ -30,6 +30,7 @@ using System;
using System.Xml;
using MonoDevelop.Projects;
using MonoDevelop.Core;
+using System.Threading.Tasks;
namespace MonoDevelop.Ide.Templates
{
@@ -53,6 +54,7 @@ namespace MonoDevelop.Ide.Templates
}
}
+ [Obsolete("Use public Task<ProjectFile> AddFileToProjectAsync (SolutionFolderItem policyParent, Project project, string language, string directory, string name).")]
public override bool AddToProject (SolutionFolderItem policyParent, Project project, string language, string directory, string name)
{
ProjectFile file = template.AddFileToProject (policyParent, project, language, directory, name);
@@ -63,6 +65,17 @@ namespace MonoDevelop.Ide.Templates
else
return false;
}
+
+ public override async Task<bool> AddToProjectAsync (SolutionFolderItem policyParent, Project project, string language, string directory, string name)
+ {
+ ProjectFile file = await template.AddFileToProjectAsync (policyParent, project, language, directory, name);
+ if (file != null) {
+ file.BuildAction = BuildAction.EmbeddedResource;
+ return true;
+ }
+ else
+ return false;
+ }
public override void Show ()
{
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/SingleFileDescriptionTemplate.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/SingleFileDescriptionTemplate.cs
index 250c2b496f..48f4c46c32 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/SingleFileDescriptionTemplate.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/SingleFileDescriptionTemplate.cs
@@ -43,6 +43,7 @@ using MonoDevelop.Ide.CodeFormatting;
using MonoDevelop.Ide.Editor;
using MonoDevelop.Projects.SharedAssetsProjects;
using MonoDevelop.Core.StringParsing;
+using System.Threading.Tasks;
namespace MonoDevelop.Ide.Templates
{
@@ -112,14 +113,14 @@ namespace MonoDevelop.Ide.Templates
set { addStandardHeader = value; }
}
- public sealed override bool AddToProject (SolutionFolderItem policyParent, Project project, string language, string directory, string name)
+ public sealed override async Task<bool> AddToProjectAsync (SolutionFolderItem policyParent, Project project, string language, string directory, string name)
{
- return AddFileToProject (policyParent, project, language, directory, name) != null;
+ return await AddFileToProjectAsync (policyParent, project, language, directory, name) != null;
}
- public ProjectFile AddFileToProject (SolutionFolderItem policyParent, Project project, string language, string directory, string name)
+ public async Task<ProjectFile> AddFileToProjectAsync (SolutionFolderItem policyParent, Project project, string language, string directory, string name)
{
- generatedFile = SaveFile (policyParent, project, language, directory, name);
+ generatedFile = await SaveFileAsync (policyParent, project, language, directory, name);
if (generatedFile != null) {
string buildAction = this.buildAction ?? project.GetDefaultBuildAction (generatedFile);
ProjectFile projectFile = project.AddFile (generatedFile, buildAction);
@@ -157,6 +158,54 @@ namespace MonoDevelop.Ide.Templates
} else
return null;
}
+
+ [Obsolete ("Use public sealed Task<bool> AddToProjectAsync (SolutionFolderItem policyParent, Project project, string language, string directory, string name).")]
+ public sealed override bool AddToProject (SolutionFolderItem policyParent, Project project, string language, string directory, string name)
+ {
+ return AddFileToProject (policyParent, project, language, directory, name) != null;
+ }
+
+ [Obsolete ("Use public Task<ProjectFile> AddFileToProjectAsync (SolutionFolderItem policyParent, Project project, string language, string directory, string name).")]
+ public ProjectFile AddFileToProject (SolutionFolderItem policyParent, Project project, string language, string directory, string name)
+ {
+ generatedFile = SaveFile (policyParent, project, language, directory, name);
+ if (generatedFile != null) {
+ string buildAction = this.buildAction ?? project.GetDefaultBuildAction (generatedFile);
+ ProjectFile projectFile = project.AddFile (generatedFile, buildAction);
+
+ if (!string.IsNullOrEmpty (dependsOn)) {
+ var model = CombinedTagModel.GetTagModel (ProjectTagModel, policyParent, project, language, name, generatedFile);
+ string parsedDepName = StringParserService.Parse (dependsOn, model);
+ if (projectFile.DependsOn != parsedDepName)
+ projectFile.DependsOn = parsedDepName;
+ }
+
+ if (!string.IsNullOrEmpty (customTool))
+ projectFile.Generator = customTool;
+
+ if (!string.IsNullOrEmpty (customToolNamespace)) {
+ var model = CombinedTagModel.GetTagModel (ProjectTagModel, policyParent, project, language, name, generatedFile);
+ projectFile.CustomToolNamespace = StringParserService.Parse (customToolNamespace, model);
+ }
+
+ if (!string.IsNullOrEmpty (subType))
+ projectFile.ContentType = subType;
+
+ DotNetProject netProject = project as DotNetProject;
+ if (netProject != null) {
+ // Add required references
+ foreach (string aref in references) {
+ string res = netProject.AssemblyContext.GetAssemblyFullName (aref, netProject.TargetFramework);
+ res = netProject.AssemblyContext.GetAssemblyNameForVersion (res, netProject.TargetFramework);
+ if (!ContainsReference (netProject, res))
+ netProject.References.Add (ProjectReference.CreateAssemblyReference (aref));
+ }
+ }
+
+ return projectFile;
+ } else
+ return null;
+ }
public override bool SupportsProject (Project project, string projectPath)
{
@@ -202,7 +251,7 @@ namespace MonoDevelop.Ide.Templates
// Creates a file and saves it to disk. Returns the path to the new file
// All parameters are optional (can be null)
- public string SaveFile (SolutionFolderItem policyParent, Project project, string language, string baseDirectory, string entryName)
+ public async Task<string> SaveFileAsync (SolutionFolderItem policyParent, Project project, string language, string baseDirectory, string entryName)
{
string file = GetFileName (policyParent, project, language, baseDirectory, entryName);
AlertButton questionResult = null;
@@ -221,6 +270,63 @@ namespace MonoDevelop.Ide.Templates
Directory.CreateDirectory (Path.GetDirectoryName (file));
if (questionResult == null || questionResult == AlertButton.OverwriteFile) {
+ Stream stream = CreateFileContentFromDerivedClass (policyParent, project, language, file, entryName) ?? await CreateFileContentAsync (policyParent, project, language, file, entryName);
+
+ byte [] buffer = new byte [2048];
+ int nr;
+ FileStream fs = null;
+ try {
+ fs = File.Create (file);
+ while ((nr = stream.Read (buffer, 0, 2048)) > 0)
+ fs.Write (buffer, 0, nr);
+ } finally {
+ stream.Close ();
+ if (fs != null)
+ fs.Close ();
+ }
+ }
+ return file;
+ }
+
+ bool createFileContentFromDerivedClass;
+
+ /// <summary>
+ /// Allows a derived class's CreateFileContent to be called. Need to ensure that if the derived
+ /// class does not implement CreateFileContent then the SingleFileDescriptionTemplate's
+ /// CreateFileContentAsync is used instead of CreateFileContent.
+ /// </summary>
+ Stream CreateFileContentFromDerivedClass (SolutionFolderItem policyParent, Project project, string language, string fileName, string identifier)
+ {
+ createFileContentFromDerivedClass = true;
+ try {
+ return CreateFileContent (policyParent, project, language, fileName, identifier);
+ } finally {
+ createFileContentFromDerivedClass = false;
+ }
+ }
+
+ // Creates a file and saves it to disk. Returns the path to the new file
+ // All parameters are optional (can be null)
+ [Obsolete ("Use public Task<string> SaveFileAsync (SolutionFolderItem policyParent, Project project, string language, string baseDirectory, string entryName).")]
+ public string SaveFile (SolutionFolderItem policyParent, Project project, string language, string baseDirectory, string entryName)
+ {
+ string file = GetFileName (policyParent, project, language, baseDirectory, entryName);
+ AlertButton questionResult = null;
+
+ if (File.Exists (file)) {
+ questionResult = MessageService.AskQuestion (GettextCatalog.GetString ("File already exists"),
+ GettextCatalog.GetString ("File {0} already exists.\nDo you want to overwrite the existing file or add it to the project?", file),
+ AlertButton.Cancel,
+ AlertButton.AddExistingFile,
+ AlertButton.OverwriteFile);
+ if (questionResult == AlertButton.Cancel)
+ return null;
+ }
+
+ if (!Directory.Exists (Path.GetDirectoryName (file)))
+ Directory.CreateDirectory (Path.GetDirectoryName (file));
+
+ if (questionResult == null || questionResult == AlertButton.OverwriteFile) {
Stream stream = CreateFileContent (policyParent, project, language, file, entryName);
byte [] buffer = new byte [2048];
@@ -281,8 +387,12 @@ namespace MonoDevelop.Ide.Templates
// Returns a stream with the content of the file.
// project and language parameters are optional
+ [Obsolete ("Use public virtual async Task<Stream> CreateFileContentAsync (SolutionFolderItem policyParent, Project project, string language, string fileName, string identifier).")]
public virtual Stream CreateFileContent (SolutionFolderItem policyParent, Project project, string language, string fileName, string identifier)
{
+ if (createFileContentFromDerivedClass)
+ return null;
+
var model = CombinedTagModel.GetTagModel (ProjectTagModel, policyParent, project, language, identifier, fileName);
//HACK: for API compat, CreateContent just gets the override, not the base model
@@ -293,13 +403,13 @@ namespace MonoDevelop.Ide.Templates
string mime = DesktopService.GetMimeTypeForUri (fileName);
var formatter = !string.IsNullOrEmpty (mime) ? CodeFormatterService.GetFormatter (mime) : null;
-
+
if (formatter != null) {
var formatted = formatter.FormatText (policyParent != null ? policyParent.Policies : null, content);
if (formatted != null)
content = formatted;
}
-
+
var ms = new MemoryStream ();
var bom = Encoding.UTF8.GetPreamble ();
@@ -311,17 +421,17 @@ namespace MonoDevelop.Ide.Templates
data = System.Text.Encoding.UTF8.GetBytes (header);
ms.Write (data, 0, data.Length);
}
-
+
var doc = TextEditorFactory.CreateNewDocument ();
doc.Text = content;
-
+
TextStylePolicy textPolicy = policyParent != null ? policyParent.Policies.Get<TextStylePolicy> (mime ?? "text/plain")
: MonoDevelop.Projects.Policies.PolicyService.GetDefaultPolicy<TextStylePolicy> (mime ?? "text/plain");
string eolMarker = TextStylePolicy.GetEolMarker (textPolicy.EolMarker);
byte[] eolMarkerBytes = System.Text.Encoding.UTF8.GetBytes (eolMarker);
-
+
var tabToSpaces = textPolicy.TabsToSpaces? new string (' ', textPolicy.TabWidth) : null;
-
+
foreach (var line in doc.GetLines ()) {
var lineText = doc.GetTextAt (line.Offset, line.Length);
if (tabToSpaces != null)
@@ -332,7 +442,83 @@ namespace MonoDevelop.Ide.Templates
ms.Write (eolMarkerBytes, 0, eolMarkerBytes.Length);
}
}
+
+ ms.Position = 0;
+ return ms;
+ }
+
+ // Returns a stream with the content of the file.
+ // project and language parameters are optional
+ public virtual async Task<Stream> CreateFileContentAsync (SolutionFolderItem policyParent, Project project, string language, string fileName, string identifier)
+ {
+ var model = CombinedTagModel.GetTagModel (ProjectTagModel, policyParent, project, language, identifier, fileName);
+
+ //HACK: for API compat, CreateContent just gets the override, not the base model
+ // but ProcessContent gets the entire model
+ string content = CreateContent (project, model.OverrideTags, language);
+
+ content = ProcessContent (content, model);
+
+ string mime = DesktopService.GetMimeTypeForUri (fileName);
+ var formatter = !string.IsNullOrEmpty (mime) ? CodeFormatterService.GetFormatter (mime) : null;
+
+ if (formatter != null) {
+ var formatted = formatter.FormatText (policyParent != null ? policyParent.Policies : null, content);
+ if (formatted != null)
+ content = formatted;
+ }
+
+ var ms = new MemoryStream ();
+ Encoding encoding = null;
+ TextStylePolicy textPolicy = policyParent != null ? policyParent.Policies.Get<TextStylePolicy> (mime ?? "text/plain")
+ : MonoDevelop.Projects.Policies.PolicyService.GetDefaultPolicy<TextStylePolicy> (mime ?? "text/plain");
+ string eolMarker = TextStylePolicy.GetEolMarker (textPolicy.EolMarker);
+
+ var ctx = await EditorConfigService.GetEditorConfigContext (fileName);
+ if (ctx != null) {
+ ctx.CurrentConventions.UniversalConventions.TryGetEncoding (out encoding);
+ if (ctx.CurrentConventions.UniversalConventions.TryGetLineEnding (out string lineEnding))
+ eolMarker = lineEnding;
+ }
+ if (encoding == null)
+ encoding = System.Text.Encoding.UTF8;
+ var bom = encoding.GetPreamble ();
+ if (bom != null && bom.Length > 0)
+ ms.Write (bom, 0, bom.Length);
+
+ byte[] data;
+ if (AddStandardHeader) {
+ string header = StandardHeaderService.GetHeader (policyParent, fileName, true);
+ data = encoding.GetBytes (header);
+ ms.Write (data, 0, data.Length);
+ }
+
+ var doc = TextEditorFactory.CreateNewDocument ();
+ doc.Text = content;
+
+ byte[] eolMarkerBytes = encoding.GetBytes (eolMarker);
+
+ var tabToSpaces = textPolicy.TabsToSpaces? new string (' ', textPolicy.TabWidth) : null;
+ IDocumentLine lastLine = null;
+ foreach (var line in doc.GetLines ()) {
+ var lineText = doc.GetTextAt (line.Offset, line.Length);
+ if (tabToSpaces != null)
+ lineText = lineText.Replace ("\t", tabToSpaces);
+ if (line.LengthIncludingDelimiter > 0) {
+ data = encoding.GetBytes (lineText);
+ ms.Write (data, 0, data.Length);
+ ms.Write (eolMarkerBytes, 0, eolMarkerBytes.Length);
+ }
+ lastLine = line;
+ }
+ if (ctx != null && lastLine != null && lastLine.Length > 0) {
+ if (ctx.CurrentConventions.UniversalConventions.TryGetRequireFinalNewline (out bool requireNewLine)) {
+ if (requireNewLine)
+ ms.Write (eolMarkerBytes, 0, eolMarkerBytes.Length);
+ }
+ }
+
ms.Position = 0;
return ms;
}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/TemplatePackageReference.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/TemplatePackageReference.cs
new file mode 100644
index 0000000000..ba1f28bcee
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/TemplatePackageReference.cs
@@ -0,0 +1,40 @@
+ο»Ώ//
+// TemplatePackageReference.cs
+//
+// Author:
+// Matt Ward <matt.ward@xamarin.com>
+//
+// Copyright (c) 2017 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
+// 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.
+
+namespace MonoDevelop.Ide.Templates
+{
+ public class TemplatePackageReference
+ {
+ public TemplatePackageReference (string id, string version)
+ {
+ Id = id;
+ Version = version;
+ }
+
+ public string Id { get; private set; }
+ public string Version { get; private set; }
+ }
+}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/TemplatingService.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/TemplatingService.cs
index 5edc53bf20..695a3cb04e 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/TemplatingService.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/TemplatingService.cs
@@ -46,9 +46,12 @@ namespace MonoDevelop.Ide.Templates
List<TemplateWizard> projectTemplateWizards = new List<TemplateWizard> ();
List<ImageCodon> projectTemplateImages = new List<ImageCodon> ();
+ MicrosoftTemplateEngineItemTemplatingProvider itemTemplatingProvider;
+
public TemplatingService ()
{
RecentTemplates = new RecentTemplates ();
+ itemTemplatingProvider = new MicrosoftTemplateEngineItemTemplatingProvider ();
AddinManager.AddExtensionNodeHandler ("/MonoDevelop/Ide/ProjectTemplateCategories", OnTemplateCategoriesChanged);
AddinManager.AddExtensionNodeHandler ("/MonoDevelop/Ide/ProjectTemplatingProviders", OnTemplatingProvidersChanged);
AddinManager.AddExtensionNodeHandler ("/MonoDevelop/Ide/ProjectTemplateWizards", OnProjectTemplateWizardsChanged);
@@ -175,6 +178,21 @@ namespace MonoDevelop.Ide.Templates
return null;
}
+ public IEnumerable<ItemTemplate> GetItemTemplates ()
+ {
+ return itemTemplatingProvider.GetTemplates ();
+ }
+
+ public IEnumerable<ItemTemplate> GetItemTemplates (Predicate<ItemTemplate> match)
+ {
+ return GetItemTemplates ().Where (template => match (template));
+ }
+
+ public Task ProcessTemplate (ItemTemplate template, Project project, NewItemConfiguration config)
+ {
+ return itemTemplatingProvider.ProcessTemplate (template, project, config);
+ }
+
public RecentTemplates RecentTemplates { get; private set; }
}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/TextFileDescriptionTemplate.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/TextFileDescriptionTemplate.cs
index eaf02e1b4a..6d8f22a755 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/TextFileDescriptionTemplate.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Templates/TextFileDescriptionTemplate.cs
@@ -29,6 +29,7 @@
using System;
using System.Collections.Generic;
using System.IO;
+using System.Threading.Tasks;
using System.Xml;
using MonoDevelop.Core;
using MonoDevelop.Core.StringParsing;
@@ -103,6 +104,13 @@ namespace MonoDevelop.Ide.Templates
contentSrcFile = contentSrcFile.ToAbsolute (baseDirectory);
}
+ public override Task<Stream> CreateFileContentAsync (SolutionFolderItem policyParent, Project project, string language,
+ string fileName, string identifier)
+ {
+ return Task.FromResult<Stream>(File.OpenRead (contentSrcFile));
+ }
+
+ [Obsolete ("Use public Task<Stream> CreateFileContentAsync (SolutionFolderItem policyParent, Project project, string language, string fileName, string identifier).")]
public override Stream CreateFileContent (SolutionFolderItem policyParent, Project project, string language,
string fileName, string identifier)
{
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/Ambience.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/Ambience.cs
index 9b25d238c1..808edbab28 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/Ambience.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/Ambience.cs
@@ -106,9 +106,9 @@ namespace MonoDevelop.Ide.TypeSystem
if (String.IsNullOrEmpty (str))
return string.Empty;
- StringBuilder sb = new StringBuilder (str.Length);
+ var sb = StringBuilderCache.Allocate ();
MarkupUtilities.AppendEscapedString (sb, str, 0, str.Length);
- return sb.ToString ();
+ return StringBuilderCache.ReturnAndFree(sb);
}
#region Documentation
@@ -266,7 +266,7 @@ namespace MonoDevelop.Ide.TypeSystem
{
if (maxLineLength <= 0)
return text;
- StringBuilder result = new StringBuilder ();
+ StringBuilder result = StringBuilderCache.Allocate ();
int lineLength = 0;
bool inTag = false;
bool inAmp = false;
@@ -300,14 +300,14 @@ namespace MonoDevelop.Ide.TypeSystem
lineLength = 0;
}
}
- return result.ToString ();
+ return StringBuilderCache.ReturnAndFree(result);
}
public static string EscapeText (string text)
{
if (text == null)
return null;
- StringBuilder result = new StringBuilder (text.Length);
+ StringBuilder result = StringBuilderCache.Allocate ();
foreach (char ch in text) {
switch (ch) {
case '<':
@@ -335,12 +335,12 @@ namespace MonoDevelop.Ide.TypeSystem
break;
}
}
- return result.ToString ();
+ return StringBuilderCache.ReturnAndFree (result);
}
public static string UnescapeText (string text)
{
- var sb = new StringBuilder (text.Length);
+ var sb = StringBuilderCache.Allocate ();
for (int i = 0; i < text.Length; i++) {
char ch = text[i];
if (ch == '&') {
@@ -370,7 +370,7 @@ namespace MonoDevelop.Ide.TypeSystem
sb.Append (ch);
}
}
- return sb.ToString ();
+ return StringBuilderCache.ReturnAndFree (sb);
}
@@ -381,7 +381,7 @@ namespace MonoDevelop.Ide.TypeSystem
static string ParseBody (ISymbol member, XmlTextReader xml, string endTagName, DocumentationFormatOptions options)
{
- StringBuilder result = new StringBuilder ();
+ StringBuilder result = StringBuilderCache.Allocate ();
bool wasWhiteSpace = true;
bool appendSpace = false;
string listType = "bullet";
@@ -498,7 +498,7 @@ namespace MonoDevelop.Ide.TypeSystem
}
}
end:
- return result.ToString ().Trim ();
+ return StringBuilderCache.ReturnAndFree (result).Trim ();
}
static string FormatCref (string cref)
@@ -514,9 +514,9 @@ namespace MonoDevelop.Ide.TypeSystem
return null;
System.IO.StringReader reader = new System.IO.StringReader ("<docroot>" + doc + "</docroot>");
XmlTextReader xml = new XmlTextReader (reader);
- StringBuilder ret = new StringBuilder (70);
- StringBuilder parameterBuilder = new StringBuilder ();
- StringBuilder exceptions = new StringBuilder ();
+ StringBuilder ret = StringBuilderCache.Allocate ();
+ StringBuilder parameterBuilder = StringBuilderCache.Allocate ();
+ StringBuilder exceptions = StringBuilderCache.Allocate ();
exceptions.AppendLine (options.FormatHeading (GettextCatalog.GetString ("Exceptions:")));
// ret.Append ("<small>");
int paramCount = 0, exceptionCount = 0, summaryEnd = -1;
@@ -565,7 +565,7 @@ namespace MonoDevelop.Ide.TypeSystem
exceptions.Append ("</b>");
if (options.SmallText)
exceptions.Append ("</small>");
-
+
exceptions.AppendLine (options.FormatBody (ParseBody (member, xml, xml.Name, options)));
break;
case "returns":
@@ -578,7 +578,7 @@ namespace MonoDevelop.Ide.TypeSystem
break;
case "param":
string paramName = xml.GetAttribute ("name") != null ? xml ["name"].Trim () : "";
-
+
var body = options.FormatBody (ParseBody (member, xml, xml.Name, options));
if (!IsEmptyDocumentation (body)) {
paramCount++;
@@ -613,34 +613,37 @@ namespace MonoDevelop.Ide.TypeSystem
}
}
} while (xml.Read ());
-
- } catch (Exception ex) {
- MonoDevelop.Core.LoggingService.LogError (ex.ToString ());
- return EscapeText (doc);
- }
- if (IsEmptyDocumentation (ret.ToString ()) && IsEmptyDocumentation (parameterBuilder.ToString ()))
- return EscapeText (doc);
- if (string.IsNullOrEmpty (options.HighlightParameter) && exceptionCount > 0)
- ret.Append (exceptions.ToString ());
-
- string result = ret.ToString ();
- if (summaryEnd < 0)
- summaryEnd = result.Length;
- if (paramCount > 0) {
- var paramSb = new StringBuilder ();
- if (result.Length > 0)
- paramSb.AppendLine ();/*
+ if (IsEmptyDocumentation (ret.ToString ()) && IsEmptyDocumentation (parameterBuilder.ToString ()))
+ return EscapeText (doc);
+ if (string.IsNullOrEmpty (options.HighlightParameter) && exceptionCount > 0)
+ ret.Append (exceptions.ToString ());
+
+ string result = ret.ToString ();
+ if (summaryEnd < 0)
+ summaryEnd = result.Length;
+ if (paramCount > 0) {
+ var paramSb = StringBuilderCache.Allocate ();
+ if (result.Length > 0)
+ paramSb.AppendLine ();/*
paramSb.Append ("<small>");
paramSb.AppendLine (options.FormatHeading (GettextCatalog.GetPluralString ("Parameter:", "Parameters:", paramCount)));
paramSb.Append ("</small>");*/
- paramSb.Append (parameterBuilder.ToString ());
- result = result.Insert (summaryEnd, paramSb.ToString ());
+ paramSb.Append (parameterBuilder.ToString ());
+ result = result.Insert (summaryEnd, StringBuilderCache.ReturnAndFree(paramSb));
+ }
+ result = result.Trim ();
+ if (result.EndsWith (Environment.NewLine + "</small>"))
+ result = result.Substring (0, result.Length - (Environment.NewLine + "</small>").Length) + "</small>";
+ return result;
+ } catch (Exception ex) {
+ MonoDevelop.Core.LoggingService.LogError (ex.ToString ());
+ return EscapeText (doc);
+ } finally {
+ StringBuilderCache.Free (ret);
+ StringBuilderCache.Free (parameterBuilder);
+ StringBuilderCache.Free (exceptions);
}
- result = result.Trim ();
- if (result.EndsWith (Environment.NewLine + "</small>"))
- result = result.Substring (0, result.Length - (Environment.NewLine + "</small>").Length) + "</small>";
- return result;
}
#endregion
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/IMonoDevelopHostDocument.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/IMonoDevelopHostDocument.cs
new file mode 100644
index 0000000000..45ee2c8167
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/IMonoDevelopHostDocument.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Text;
+using Microsoft.VisualStudio.Text;
+
+namespace MonoDevelop.Ide.TypeSystem
+{
+ interface IMonoDevelopHostDocument
+ {
+ /// <summary>
+ /// Updates the text of the document.
+ /// </summary>
+ void UpdateText (SourceText newText);
+ }
+
+ static class MonoDevelopHostDocumentRegistration
+ {
+ internal static void Register (ITextBuffer textBuffer, IMonoDevelopHostDocument hostDocument)
+ {
+ textBuffer?.Properties.AddProperty (typeof (IMonoDevelopHostDocument), hostDocument);
+ }
+
+ internal static void UnRegister(ITextBuffer textBuffer)
+ {
+ textBuffer?.Properties.RemoveProperty (typeof (IMonoDevelopHostDocument));
+ }
+
+ internal static IMonoDevelopHostDocument FromDocument(Document document)
+ {
+ IMonoDevelopHostDocument containedDocument = null;
+ if (document.TryGetText (out SourceText sourceText)) {
+ ITextBuffer textBuffer = sourceText.Container.TryGetTextBuffer ();
+
+ containedDocument = textBuffer?.Properties.GetProperty<IMonoDevelopHostDocument> (typeof (IMonoDevelopHostDocument));
+ }
+
+ return containedDocument;
+ }
+ }
+}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MarkupUtilities.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MarkupUtilities.cs
index 00fee4d6f3..2cc64ee033 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MarkupUtilities.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MarkupUtilities.cs
@@ -28,6 +28,7 @@
using System;
using System.Text;
+using MonoDevelop.Core;
namespace MonoDevelop.Ide.TypeSystem
{
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 ea90521a02..f5cc57498c 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopPersistentStorageLocationService.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopPersistentStorageLocationService.cs
@@ -51,10 +51,26 @@ namespace MonoDevelop.Ide.TypeSystem
// 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 GetStorageLocation (Solution solution)
+ public event EventHandler<PersistentStorageLocationChangingEventArgs> StorageLocationChanging;
+
+ internal void NotifyStorageLocationChanging (SolutionId sol, string path)
+ {
+ lock (storageMap) {
+ if (storageMap.TryGetValue (sol, out string cached) && path == cached)
+ return;
+
+ StorageLocationChanging?.Invoke (this, new PersistentStorageLocationChangingEventArgs (sol, path, true));
+ storageMap.Remove (sol);
+ storageMap.Add (sol, path);
+ }
+ }
+
+ public string TryGetStorageLocation (SolutionId solutionId)
{
- storageMap.TryGetValue (solution.Id, out var path);
- return path;
+ lock (storageMap) {
+ storageMap.TryGetValue (solutionId, out var path);
+ return path;
+ }
}
}
}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopSourceTextContainer.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopSourceTextContainer.cs
index 2aae5a01ee..6d5e3993c6 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopSourceTextContainer.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopSourceTextContainer.cs
@@ -73,32 +73,34 @@ namespace MonoDevelop.Ide.TypeSystem
{
var handler = TextChanged;
if (handler != null) {
- lock (replaceLock) {
- var oldText = CurrentText;
- var changes = new Microsoft.CodeAnalysis.Text.TextChange[e.TextChanges.Count];
- var changeRanges = new TextChangeRange[e.TextChanges.Count];
- for (int i = 0; i < e.TextChanges.Count; ++i) {
- var c = e.TextChanges[i];
- var span = new TextSpan (c.Offset, c.RemovalLength);
- changes[i] = new Microsoft.CodeAnalysis.Text.TextChange (span, c.InsertedText.Text);
- changeRanges[i] = new TextChangeRange (span, c.InsertionLength);
- }
- var newText = oldText.WithChanges (changes);
- currentText = newText;
- try {
- handler (this, new Microsoft.CodeAnalysis.Text.TextChangeEventArgs (oldText, newText, changeRanges));
- } catch (ArgumentException ae) {
- if (!workspace.TryGetTarget (out var ws))
- return;
- if (!editor.TryGetTarget (out var ed))
- return;
- LoggingService.LogWarning (ae.Message + " re opening " + ed.FileName + " as roslyn source text.");
- ws.InformDocumentClose (Id, ed.FileName);
- Dispose (); // 100% ensure that this object is disposed
- if (ws.GetDocument (Id) != null)
- TypeSystemService.InformDocumentOpen (Id, ed);
- } catch (Exception ex) {
- LoggingService.LogError ("Error while text replacing", ex);
+ if (e.TextChanges.Count > 0) {
+ lock (replaceLock) {
+ var oldText = CurrentText;
+ var changes = new Microsoft.CodeAnalysis.Text.TextChange[e.TextChanges.Count];
+ var changeRanges = new TextChangeRange[e.TextChanges.Count];
+ for (int i = 0; i < e.TextChanges.Count; ++i) {
+ var c = e.TextChanges[i];
+ var span = new TextSpan (c.Offset, c.RemovalLength);
+ changes[i] = new Microsoft.CodeAnalysis.Text.TextChange (span, c.InsertedText.Text);
+ changeRanges[i] = new TextChangeRange (span, c.InsertionLength);
+ }
+ var newText = oldText.WithChanges (changes);
+ currentText = newText;
+ try {
+ handler (this, new Microsoft.CodeAnalysis.Text.TextChangeEventArgs (oldText, newText, changeRanges));
+ } catch (ArgumentException ae) {
+ if (!workspace.TryGetTarget (out var ws))
+ return;
+ if (!editor.TryGetTarget (out var ed))
+ return;
+ LoggingService.LogWarning (ae.Message + " re opening " + ed.FileName + " as roslyn source text.");
+ ws.InformDocumentClose (Id, ed.FileName);
+ Dispose (); // 100% ensure that this object is disposed
+ if (ws.GetDocument (Id) != null)
+ TypeSystemService.InformDocumentOpen (Id, ed);
+ } catch (Exception ex) {
+ LoggingService.LogError ("Error while text replacing", ex);
+ }
}
}
}
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 7dacb46048..1378da5b17 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.cs
@@ -103,14 +103,23 @@ namespace MonoDevelop.Ide.TypeSystem
IdeApp.Workspace.ActiveConfigurationChanged += HandleActiveConfigurationChanged;
}
ISolutionCrawlerRegistrationService solutionCrawler = Services.GetService<ISolutionCrawlerRegistrationService> ();
- //Options = Options.WithChangedOption (Microsoft.CodeAnalysis.Diagnostics.InternalRuntimeDiagnosticOptions.Syntax, true)
- // .WithChangedOption (Microsoft.CodeAnalysis.Diagnostics.InternalRuntimeDiagnosticOptions.Semantic, true);
+
+ // Trigger running compiler syntax and semantic errors via the diagnostic analyzer engine
+ Options = Options.WithChangedOption (Microsoft.CodeAnalysis.Diagnostics.InternalRuntimeDiagnosticOptions.Syntax, true)
+ .WithChangedOption (Microsoft.CodeAnalysis.Diagnostics.InternalRuntimeDiagnosticOptions.Semantic, true)
+ // Always use persistent storage regardless of solution size, at least until a consensus is reached
+ // https://github.com/mono/monodevelop/issues/4149 https://github.com/dotnet/roslyn/issues/25453
+ .WithChangedOption (Microsoft.CodeAnalysis.Storage.StorageOptions.SolutionSizeThreshold, 0);
if (IdeApp.Preferences.EnableSourceAnalysis) {
solutionCrawler.Register (this);
}
IdeApp.Preferences.EnableSourceAnalysis.Changed += OnEnableSourceAnalysisChanged;
+
+ foreach (var factory in AddinManager.GetExtensionObjects<Microsoft.CodeAnalysis.Options.IDocumentOptionsProviderFactory>("/MonoDevelop/Ide/TypeService/OptionProviders"))
+ Services.GetRequiredService<Microsoft.CodeAnalysis.Options.IOptionService> ().RegisterDocumentOptionsProvider (factory.Create (this));
+
}
void OnEnableSourceAnalysisChanged(object sender, EventArgs args)
@@ -206,15 +215,12 @@ namespace MonoDevelop.Ide.TypeSystem
var mdProjects = solution.GetAllProjects ();
ImmutableList<ProjectionEntry> toDispose;
lock (projectionListUpdateLock) {
- toDispose = projectionList;
+ toDispose = projectionList;
projectionList = projectionList.Clear ();
}
foreach (var p in toDispose)
p.Dispose ();
- projectIdMap.Clear ();
- projectIdToMdProjectMap = projectIdToMdProjectMap.Clear ();
- projectDataMap.Clear ();
solutionData = new SolutionData ();
List<Task> allTasks = new List<Task> ();
foreach (var proj in mdProjects) {
@@ -223,7 +229,7 @@ namespace MonoDevelop.Ide.TypeSystem
var netProj = proj as MonoDevelop.Projects.DotNetProject;
if (netProj != null && !netProj.SupportsRoslyn)
continue;
- var tp = LoadProject (proj, token).ContinueWith (t => {
+ var tp = LoadProject (proj, token, null).ContinueWith (t => {
if (!t.IsCanceled)
projects.Add (t.Result);
});
@@ -245,39 +251,39 @@ namespace MonoDevelop.Ide.TypeSystem
lock (addLock) {
if (!added) {
added = true;
- // HACK: https://github.com/dotnet/roslyn/issues/20581
- RegisterPrimarySolutionForPersistentStorage (solutionId, solution);
+ solution.Modified += OnSolutionModified;
+ NotifySolutionModified (solution, solutionId, this);
OnSolutionAdded (solutionInfo);
+ lock (generatedFiles) {
+ foreach (var generatedFile in generatedFiles) {
+ if (!this.IsDocumentOpen (generatedFile.Key.Id))
+ OnDocumentOpened (generatedFile.Key.Id, generatedFile.Value);
+ }
+ }
}
}
return solutionInfo;
});
}
- void RegisterPrimarySolutionForPersistentStorage (SolutionId solutionId, MonoDevelop.Projects.Solution solution)
- {
- var locService = (MonoDevelopPersistentStorageLocationService)Services.GetService<IPersistentStorageLocationService> ();
- locService.storageMap.Add (solutionId, solution.GetPreferencesDirectory ());
-
- var service = Services.GetService<IPersistentStorageService> () as Microsoft.CodeAnalysis.Storage.AbstractPersistentStorageService;
- if (service == null) {
- return;
- }
-
- service.RegisterPrimarySolution (solutionId);
- }
-
- void UnregisterPrimarySolutionForPersistentStorage (SolutionId solutionId, bool synchronousShutdown)
- {
- var locService = (MonoDevelopPersistentStorageLocationService)Services.GetService<IPersistentStorageLocationService> ();
- locService.storageMap.Remove (solutionId);
-
- var service = Services.GetService<IPersistentStorageService> () as Microsoft.CodeAnalysis.Storage.AbstractPersistentStorageService;
- if (service == null) {
- return;
- }
-
- service.UnregisterPrimarySolution (solutionId, synchronousShutdown);
+ 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.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 ());
}
internal Task<SolutionInfo> TryLoadSolution (CancellationToken cancellationToken = default(CancellationToken))
@@ -288,7 +294,6 @@ namespace MonoDevelop.Ide.TypeSystem
internal void UnloadSolution ()
{
OnSolutionRemoved ();
- UnregisterPrimarySolutionForPersistentStorage (CurrentSolution.Id, synchronousShutdown: false);
}
Dictionary<MonoDevelop.Projects.Solution, SolutionId> solutionIdMap = new Dictionary<MonoDevelop.Projects.Solution, SolutionId> ();
@@ -448,12 +453,21 @@ namespace MonoDevelop.Ide.TypeSystem
project.Modified -= OnProjectModified;
}
- async Task<ProjectInfo> LoadProject (MonoDevelop.Projects.Project p, CancellationToken token)
+ internal async Task<ProjectInfo> LoadProject (MonoDevelop.Projects.Project p, CancellationToken token, MonoDevelop.Projects.Project oldProject)
{
if (!projectIdMap.ContainsKey (p)) {
p.Modified += OnProjectModified;
}
+ if (oldProject != null) {
+ lock (projectIdMap) {
+ oldProject.Modified -= OnProjectModified;
+ projectIdMap.TryRemove (oldProject, out var id);
+ projectIdMap[p] = id;
+ projectIdToMdProjectMap = projectIdToMdProjectMap.SetItem (id, p);
+ }
+ }
+
var projectId = GetOrCreateProjectId (p);
//when reloading e.g. after a save, preserve document IDs
@@ -600,6 +614,13 @@ namespace MonoDevelop.Ide.TypeSystem
}
}
}
+ var projectId = GetProjectId (p);
+ lock (generatedFiles) {
+ foreach (var generatedFile in generatedFiles) {
+ if (generatedFile.Key.Id.ProjectId == projectId)
+ documents.Add (generatedFile.Key);
+ }
+ }
return Tuple.Create (documents, additionalDocuments);
}
@@ -755,6 +776,27 @@ namespace MonoDevelop.Ide.TypeSystem
IdeApp.Workbench.OpenDocument (doc.FilePath, mdProject, activate);
}
}
+ }
+
+ readonly Dictionary<DocumentInfo, SourceTextContainer> generatedFiles = new Dictionary<DocumentInfo, SourceTextContainer> ();
+ internal void AddAndOpenDocumentInternal (DocumentInfo documentInfo, SourceTextContainer textContainer)
+ {
+ lock (generatedFiles) {
+ generatedFiles[documentInfo] = textContainer;
+ OnDocumentAdded (documentInfo);
+ OnDocumentOpened (documentInfo.Id, textContainer);
+ }
+ }
+
+ internal void CloseAndRemoveDocumentInternal (DocumentId documentId, TextLoader reloader)
+ {
+ lock (generatedFiles) {
+ var documentInfo = generatedFiles.FirstOrDefault (kvp => kvp.Key.Id == documentId).Key;
+ if (documentInfo != null && generatedFiles.Remove(documentInfo) && CurrentSolution.ContainsDocument(documentId)) {
+ OnDocumentClosed (documentId, reloader);
+ OnDocumentRemoved (documentId);
+ }
+ }
}
List<MonoDevelopSourceTextContainer> openDocuments = new List<MonoDevelopSourceTextContainer>();
@@ -822,6 +864,10 @@ namespace MonoDevelop.Ide.TypeSystem
if (openDoc != null) {
openDoc.Dispose ();
openDocuments.Remove (openDoc);
+ } else {
+ //Apparently something else opened this file via AddAndOpenDocumentInternal(e.g. .cshtml)
+ //it's job of whatever opened to also call CloseAndRemoveDocumentInternal
+ return;
}
}
if (!CurrentSolution.ContainsDocument (analysisDocument))
@@ -865,6 +911,13 @@ namespace MonoDevelop.Ide.TypeSystem
var document = GetDocument (id);
if (document == null)
return;
+
+ var hostDocument = MonoDevelopHostDocumentRegistration.FromDocument (document);
+ if (hostDocument != null) {
+ hostDocument.UpdateText (text);
+ return;
+ }
+
bool isOpen;
var filePath = document.FilePath;
Projection projection = null;
@@ -1204,6 +1257,11 @@ namespace MonoDevelop.Ide.TypeSystem
}
var path = DetermineFilePath (info.Id, info.Name, info.FilePath, info.Folders, mdProject?.FileName.ParentDirectory, true);
+ // If file is already part of project don't re-add it, example of this is .cshtml
+ if (mdProject?.IsFileInProject (path) == true) {
+ this.OnDocumentAdded (info);
+ return;
+ }
info = info.WithFilePath (path).WithTextLoader (new MonoDevelopTextLoader (path));
string formattedText;
@@ -1297,6 +1355,22 @@ namespace MonoDevelop.Ide.TypeSystem
var path = GetMetadataPath (metadataReference);
if (mdProject == null || path == null)
return;
+ foreach (var r in mdProject.References) {
+ if (r.ReferenceType == MonoDevelop.Projects.ReferenceType.Assembly && r.Reference == path) {
+ LoggingService.LogWarning ("Warning duplicate reference is added " + path);
+ return;
+ }
+
+ if (r.ReferenceType == MonoDevelop.Projects.ReferenceType.Project) {
+ foreach (var fn in r.GetReferencedFileNames (MonoDevelop.Projects.ConfigurationSelector.Default)) {
+ if (fn == path) {
+ LoggingService.LogWarning ("Warning duplicate reference is added " + path + " for project " + r.Reference);
+ return;
+ }
+ }
+ }
+ }
+
mdProject.AddReference (path);
tryApplyState_changedProjects.Add (mdProject);
this.OnMetadataReferenceAdded (projectId, metadataReference);
@@ -1435,7 +1509,13 @@ namespace MonoDevelop.Ide.TypeSystem
return;
var projectId = GetProjectId (project);
if (CurrentSolution.ContainsProject (projectId)) {
- HandleActiveConfigurationChanged (this, EventArgs.Empty);
+ var projectInfo = LoadProject (project, CancellationToken.None, null).ContinueWith (t => {
+ if (t.IsFaulted) {
+ LoggingService.LogError ("Failed to reload project", t.Exception);
+ return;
+ }
+ OnProjectReloaded (t.Result);
+ });
} else {
modifiedProjects.Add (project);
}
@@ -1467,7 +1547,6 @@ namespace MonoDevelop.Ide.TypeSystem
originalOffset = offset;
return false;
}
-
}
// static class MonoDevelopWorkspaceFeatures
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/NR5CompatibiltyExtensions.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/NR5CompatibiltyExtensions.cs
index de720d862a..e0d7f7f003 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/NR5CompatibiltyExtensions.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/NR5CompatibiltyExtensions.cs
@@ -60,7 +60,7 @@ namespace MonoDevelop.Ide.TypeSystem
/// <param name="symbol">Symbol.</param>
public static string GetFullMetadataName (this INamedTypeSymbol symbol)
{
- var fullName = new StringBuilder (symbol.MetadataName);
+ var fullName = StringBuilderCache.Allocate (symbol.MetadataName);
var parentType = symbol.ContainingType;
while (parentType != null) {
fullName.Insert (0, '+');
@@ -73,7 +73,7 @@ namespace MonoDevelop.Ide.TypeSystem
fullName.Insert (0, ns.MetadataName);
ns = ns.ContainingNamespace;
}
- return fullName.ToString ();
+ return StringBuilderCache.ReturnAndFree (fullName);
}
/// <summary>
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 e337d273b1..378afdf996 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/TypeSystemService.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/TypeSystemService.cs
@@ -314,7 +314,7 @@ namespace MonoDevelop.Ide.TypeSystem
{
var derivedDataPath = UserProfile.Current.CacheDir.Combine ("DerivedData");
- var name = new StringBuilder ();
+ var name = StringBuilderCache.Allocate ();
foreach (var ch in framework.Name) {
if (char.IsLetterOrDigit (ch)) {
name.Append (ch);
@@ -323,7 +323,7 @@ namespace MonoDevelop.Ide.TypeSystem
}
}
- string result = derivedDataPath.Combine (name.ToString ());
+ string result = derivedDataPath.Combine (StringBuilderCache.ReturnAndFree (name));
try {
if (!Directory.Exists (result))
Directory.CreateDirectory (result);
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/TypeSystemService_WorkspaceHandling.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/TypeSystemService_WorkspaceHandling.cs
index ec571ac1af..43468257e5 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/TypeSystemService_WorkspaceHandling.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/TypeSystemService_WorkspaceHandling.cs
@@ -41,7 +41,8 @@ namespace MonoDevelop.Ide.TypeSystem
{
public static partial class TypeSystemService
{
- static readonly MonoDevelopWorkspace emptyWorkspace;
+ //Internal for unit test
+ internal static readonly MonoDevelopWorkspace emptyWorkspace;
static object workspaceLock = new object();
static ImmutableList<MonoDevelopWorkspace> workspaces = ImmutableList<MonoDevelopWorkspace>.Empty;
@@ -63,8 +64,8 @@ namespace MonoDevelop.Ide.TypeSystem
return ws;
}
return emptyWorkspace;
- }
-
+ }
+
public static async Task<MonoDevelopWorkspace> GetWorkspaceAsync (MonoDevelop.Projects.Solution solution, CancellationToken cancellationToken = default (CancellationToken))
{
var workspace = GetWorkspace (solution);
@@ -116,42 +117,47 @@ namespace MonoDevelop.Ide.TypeSystem
internal static async Task<List<MonoDevelopWorkspace>> Load (WorkspaceItem item, ProgressMonitor progressMonitor, CancellationToken cancellationToken = default (CancellationToken), bool showStatusIcon = true)
{
using (Counters.ParserService.WorkspaceItemLoaded.BeginTiming ()) {
- var wsList = new List<MonoDevelopWorkspace> ();
+ var wsList = CreateWorkspaces (item).ToList();
//If we want BeginTiming to work correctly we need to `await`
- return await InternalLoad (wsList, item, progressMonitor, cancellationToken, showStatusIcon).ContinueWith (t => { t.Wait (); return wsList; });
+ await InternalLoad (wsList, progressMonitor, cancellationToken, showStatusIcon).ConfigureAwait (false);
+ return wsList.ToList ();
}
}
- static Task InternalLoad (List<MonoDevelopWorkspace> list, MonoDevelop.Projects.WorkspaceItem item, ProgressMonitor progressMonitor, CancellationToken cancellationToken = default(CancellationToken), bool showStatusIcon = true)
+ static IEnumerable<MonoDevelopWorkspace> CreateWorkspaces (WorkspaceItem item)
{
- return Task.Run (async () => {
- var ws = item as MonoDevelop.Projects.Workspace;
- if (ws != null) {
- foreach (var it in ws.Items) {
- await InternalLoad (list, it, progressMonitor, cancellationToken).ConfigureAwait (false);
- }
- ws.ItemAdded += OnWorkspaceItemAdded;
- ws.ItemRemoved += OnWorkspaceItemRemoved;
- } else {
- var solution = item as MonoDevelop.Projects.Solution;
- if (solution != null) {
- var workspace = new MonoDevelopWorkspace (solution);
- lock (workspaceLock)
- workspaces = workspaces.Add (workspace);
- list.Add (workspace);
- if (showStatusIcon)
- workspace.ShowStatusIcon ();
- await workspace.TryLoadSolution (cancellationToken).ConfigureAwait (false);
- solution.SolutionItemAdded += OnSolutionItemAdded;
- solution.SolutionItemRemoved += OnSolutionItemRemoved;
- TaskCompletionSource<MonoDevelopWorkspace> request;
- if (workspaceRequests.TryGetValue (solution, out request))
- request.TrySetResult (workspace);
- if (showStatusIcon)
- workspace.HideStatusIcon ();
+ if (item is MonoDevelop.Projects.Workspace ws) {
+ foreach (var wsItem in ws.Items) {
+ foreach (var mdWorkspace in CreateWorkspaces (wsItem)) {
+ yield return mdWorkspace;
}
}
- });
+ ws.ItemAdded += OnWorkspaceItemAdded;
+ ws.ItemRemoved += OnWorkspaceItemRemoved;
+ } else if (item is MonoDevelop.Projects.Solution solution) {
+ var workspace = new MonoDevelopWorkspace (solution);
+ lock (workspaceLock)
+ workspaces = workspaces.Add (workspace);
+ solution.SolutionItemAdded += OnSolutionItemAdded;
+ solution.SolutionItemRemoved += OnSolutionItemRemoved;
+ yield return workspace;
+ }
+ }
+
+ static async Task InternalLoad (List<MonoDevelopWorkspace> mdWorkspaces, ProgressMonitor progressMonitor, CancellationToken cancellationToken = default (CancellationToken), bool showStatusIcon = true)
+ {
+ foreach (var workspace in mdWorkspaces) {
+ if (showStatusIcon)
+ workspace.ShowStatusIcon ();
+
+ await workspace.TryLoadSolution (cancellationToken).ConfigureAwait (false);
+ TaskCompletionSource<MonoDevelopWorkspace> request;
+ if (workspaceRequests.TryGetValue (workspace.MonoDevelopSolution, out request))
+ request.TrySetResult (workspace);
+ if (showStatusIcon)
+ workspace.HideStatusIcon ();
+
+ }
}
internal static void Unload (MonoDevelop.Projects.WorkspaceItem item)
@@ -244,7 +250,7 @@ namespace MonoDevelop.Ide.TypeSystem
if (project == null)
throw new ArgumentNullException (nameof(project));
foreach (var w in workspaces) {
- var projectId = w.GetProjectId (project);
+ var projectId = w.GetProjectId (project);
if (projectId != null)
return w.CurrentSolution.GetProject (projectId);
}
@@ -256,7 +262,29 @@ namespace MonoDevelop.Ide.TypeSystem
var parentSolution = project.ParentSolution;
var workspace = await GetWorkspaceAsync (parentSolution, cancellationToken);
var projectId = workspace.GetProjectId (project);
- return projectId == null ? null : workspace.CurrentSolution.GetProject (projectId);
+ if (projectId == null)
+ return null;
+ var proj = workspace.CurrentSolution.GetProject (projectId);
+ if (proj != null)
+ return proj;
+ //We assume that since we have projectId and project is not found in solution
+ //project is being loaded(waiting MSBuild to return list of source files)
+ var taskSource = new TaskCompletionSource<Microsoft.CodeAnalysis.Project> ();
+ EventHandler<WorkspaceChangeEventArgs> del = (s, e) => {
+ if (e.Kind == WorkspaceChangeKind.SolutionAdded || e.Kind == WorkspaceChangeKind.SolutionReloaded) {
+ proj = workspace.CurrentSolution.GetProject (projectId);
+ if (proj != null)
+ taskSource.SetResult (proj);
+ }
+ };
+ cancellationToken.Register (taskSource.SetCanceled);
+ workspace.WorkspaceChanged += del;
+ try {
+ proj = await taskSource.Task;
+ } finally {
+ workspace.WorkspaceChanged -= del;
+ }
+ return proj;
}
public static Task<Compilation> GetCompilationAsync (MonoDevelop.Projects.Project project, CancellationToken cancellationToken = default(CancellationToken))
@@ -264,7 +292,7 @@ namespace MonoDevelop.Ide.TypeSystem
if (project == null)
throw new ArgumentNullException (nameof(project));
foreach (var w in workspaces) {
- var projectId = w.GetProjectId (project);
+ var projectId = w.GetProjectId (project);
if (projectId == null)
continue;
var roslynProject = w.CurrentSolution.GetProject (projectId);
@@ -277,7 +305,7 @@ namespace MonoDevelop.Ide.TypeSystem
static void OnWorkspaceItemAdded (object s, MonoDevelop.Projects.WorkspaceItemEventArgs args)
{
- Task.Run (() => TypeSystemService.Load (args.Item, null));
+ TypeSystemService.Load (args.Item, null).Ignore ();
}
static void OnWorkspaceItemRemoved (object s, MonoDevelop.Projects.WorkspaceItemEventArgs args)
@@ -287,15 +315,29 @@ namespace MonoDevelop.Ide.TypeSystem
static async void OnSolutionItemAdded (object sender, MonoDevelop.Projects.SolutionItemChangeEventArgs args)
{
- var project = args.SolutionItem as MonoDevelop.Projects.Project;
- if (project != null) {
- Unload (project.ParentSolution);
- await Load (project.ParentSolution, new ProgressMonitor());
+ try {
+ var project = args.SolutionItem as MonoDevelop.Projects.Project;
+ if (project != null) {
+ var ws = GetWorkspace (args.Solution);
+ var projectInfo = await ws.LoadProject (project, CancellationToken.None, args.ReplacedItem as MonoDevelop.Projects.Project);
+ if (args.Reloading) {
+ ws.OnProjectReloaded (projectInfo);
+ }
+ else {
+ ws.OnProjectAdded (projectInfo);
+ }
+ }
+ } catch (Exception ex) {
+ LoggingService.LogError ("OnSolutionItemAdded failed", ex);
}
}
static void OnSolutionItemRemoved (object sender, MonoDevelop.Projects.SolutionItemChangeEventArgs args)
{
+ if (args.Reloading) {
+ return;
+ }
+
var project = args.SolutionItem as MonoDevelop.Projects.Project;
var solution = sender as MonoDevelop.Projects.Solution;
if (project != null) {
@@ -358,7 +400,7 @@ namespace MonoDevelop.Ide.TypeSystem
{
if (project == null)
throw new ArgumentNullException (nameof(project));
- return outputTrackedProjects.Any (otp => string.Equals (otp.LanguageName, project.LanguageName, StringComparison.OrdinalIgnoreCase)) ||
+ return outputTrackedProjects.Any (otp => string.Equals (otp.LanguageName, project.LanguageName, StringComparison.OrdinalIgnoreCase)) ||
project.GetTypeTags().Any (tag => outputTrackedProjects.Any (otp => string.Equals (otp.ProjectType, tag, StringComparison.OrdinalIgnoreCase)));
}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/WorkspaceExtensions.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/WorkspaceExtensions.cs
new file mode 100644
index 0000000000..580af7969a
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/WorkspaceExtensions.cs
@@ -0,0 +1,46 @@
+//
+// WorkspaceExtensions.cs
+//
+// Author:
+// Kirill Osenkov <https://github.com/KirillOsenkov>
+//
+// Copyright (c) 2018 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 Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.SolutionCrawler;
+
+namespace MonoDevelop.Ide.TypeSystem
+{
+ static class WorkspaceExtensions
+ {
+ internal static void RegisterSolutionCrawler (Workspace workspace)
+ {
+ var solutionCrawlerRegistrationService = workspace.Services.GetService<ISolutionCrawlerRegistrationService> ();
+ solutionCrawlerRegistrationService.Register (workspace);
+ }
+
+ internal static void UnregisterSolutionCrawler (Workspace workspace)
+ {
+ var solutionCrawlerRegistrationService = workspace.Services.GetService<ISolutionCrawlerRegistrationService> ();
+ solutionCrawlerRegistrationService.Unregister (workspace);
+ }
+ }
+} \ No newline at end of file
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.csproj b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.csproj
index 37e3d30145..120048f39d 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.csproj
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.csproj
@@ -135,14 +135,14 @@
<Reference Include="Microsoft.TemplateEngine.Utils">
<HintPath>..\..\..\packages\Microsoft.TemplateEngine.Utils.1.0.0-beta3-20171117-314\lib\net45\Microsoft.TemplateEngine.Utils.dll</HintPath>
</Reference>
- <Reference Include="Microsoft.VisualStudio.Composition, Version=15.3.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
- <HintPath>..\..\..\packages\Microsoft.VisualStudio.Composition.15.3.38\lib\net45\Microsoft.VisualStudio.Composition.dll</HintPath>
+ <Reference Include="Microsoft.VisualStudio.Composition, Version=15.6.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+ <HintPath>..\..\..\packages\Microsoft.VisualStudio.Composition.15.6.36\lib\net45\Microsoft.VisualStudio.Composition.dll</HintPath>
</Reference>
- <Reference Include="Microsoft.VisualStudio.Threading, Version=15.3.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
- <HintPath>..\..\..\packages\Microsoft.VisualStudio.Threading.15.4.4\lib\net45\Microsoft.VisualStudio.Threading.dll</HintPath>
+ <Reference Include="Microsoft.VisualStudio.Threading, Version=15.6.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+ <HintPath>..\..\..\packages\Microsoft.VisualStudio.Threading.15.6.46\lib\net45\Microsoft.VisualStudio.Threading.dll</HintPath>
</Reference>
<Reference Include="Microsoft.VisualStudio.Validation, Version=15.3.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
- <HintPath>..\..\..\packages\Microsoft.VisualStudio.Validation.15.3.15\lib\net45\Microsoft.VisualStudio.Validation.dll</HintPath>
+ <HintPath>..\..\..\packages\Microsoft.VisualStudio.Validation.15.3.32\lib\net45\Microsoft.VisualStudio.Validation.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Mono.Cairo" />
@@ -211,6 +211,10 @@
<HintPath>..\..\..\packages\System.ValueTuple.4.4.0\lib\netstandard1.0\System.ValueTuple.dll</HintPath>
<Private>False</Private>
</Reference>
+ <Reference Include="Microsoft.VisualStudio.CodingConventions">
+ <HintPath>..\..\..\build\bin\Microsoft.VisualStudio.CodingConventions.dll</HintPath>
+ <Private>False</Private>
+ </Reference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MonoDevelop.Core\MonoDevelop.Core.csproj">
@@ -8561,10 +8565,16 @@
<Compile Include="MonoDevelop.Ide.Commands\ToolsCommands.cs" />
<Compile Include="MonoDevelop.Ide.Commands\ViewCommands.cs" />
<Compile Include="MonoDevelop.Ide.Commands\WindowCommands.cs" />
+ <Compile Include="MonoDevelop.Ide.Composition\CommonEditorAssetServiceFactory.cs" />
<Compile Include="MonoDevelop.Ide.Composition\CompositionManager.cs" />
+ <Compile Include="MonoDevelop.Ide.Composition\InlineRenameService.cs" />
<Compile Include="MonoDevelop.Ide.Composition\JoinableTaskContextHost.cs" />
<Compile Include="MonoDevelop.Ide.Composition\PlatformCatalog.cs" />
<Compile Include="MonoDevelop.Ide.Composition\PlatformExtensions.cs" />
+ <Compile Include="MonoDevelop.Ide.Composition\PreviewFactoryService.cs" />
+ <Compile Include="MonoDevelop.Ide.Composition\RoslynWaitIndicator.cs" />
+ <Compile Include="MonoDevelop.Ide.Composition\StreamingFindUsagesPresenter.cs" />
+ <Compile Include="MonoDevelop.Ide.Composition\SuggestedActionCategoryRegistryService.cs" />
<Compile Include="MonoDevelop.Ide.Editor\ITextEditorFactoryService.cs" />
<Compile Include="MonoDevelop.Ide.Gui\DisplayBindingService.cs" />
<Compile Include="MonoDevelop.Ide.Gui\BackgroundProgressMonitor.cs" />
@@ -8643,6 +8653,7 @@
<Compile Include="MonoDevelop.Ide.Gui\Workbench.cs" />
<Compile Include="MonoDevelop.Ide.Gui\StartupInfo.cs" />
<Compile Include="MonoDevelop.Ide.Gui\ProgressMonitors.cs" />
+ <Compile Include="MonoDevelop.Ide.TypeSystem\IMonoDevelopHostDocument.cs" />
<Compile Include="MonoDevelop.Ide.TypeSystem\MonoDevelopPersistentStorageLocationService.cs" />
<Compile Include="MonoDevelop.Ide\RoslynLogger.cs" />
<Compile Include="MonoDevelop.Ide\Services.cs" />
@@ -9274,6 +9285,7 @@
<Compile Include="MonoDevelop.Components\ImageLoader.cs" />
<Compile Include="MonoDevelop.Ide.CodeCompletion\ParameterHintingData.cs" />
<Compile Include="MonoDevelop.Ide.TypeSystem\MonoDevelopWorkspace.cs" />
+ <Compile Include="MonoDevelop.Ide.TypeSystem\WorkspaceExtensions.cs" />
<Compile Include="MonoDevelop.Ide.Editor\IDocumentLine.cs" />
<Compile Include="MonoDevelop.Ide.CodeTemplates\IListDataProvider.cs" />
<Compile Include="MonoDevelop.Ide.Editor\ITextEditorOptions.cs" />
@@ -9343,7 +9355,7 @@
<Compile Include="MonoDevelop.Ide.Editor\TextMarkerFactory.cs" />
<Compile Include="MonoDevelop.Ide.Editor\InternalExtensionAPI\ITextEditorImpl.cs" />
<Compile Include="MonoDevelop.Ide.Editor\InternalExtensionAPI\ITextMarkerFactory.cs" />
- <Compile Include="MonoDevelop.Ide.Editor\InternalExtensionAPI\IEditorActionHost.cs" />
+ <Compile Include="MonoDevelop.Ide.Editor\InternalExtensionAPI\IMonoDevelopEditorOperations.cs" />
<Compile Include="MonoDevelop.Ide.Editor\EditActions.cs" />
<Compile Include="MonoDevelop.Ide.Editor\DocumentContext.cs" />
<Compile Include="MonoDevelop.Ide.Editor\InternalExtensionAPI\ITextEditorFactory.cs" />
@@ -9615,7 +9627,6 @@
<Compile Include="MonoDevelop.Ide.Projects\LanguageCellRenderer.cs" />
<Compile Include="MonoDevelop.Components\RestartPanel.cs" />
<Compile Include="MonoDevelop.Ide.TypeSystem\MonoDevelopSourceText.cs" />
- <Compile Include="MonoDevelop.Ide.CodeCompletion\CompletionPresenterSession.cs" />
<Compile Include="MonoDevelop.Ide.CodeCompletion\TaggedTextUtil.cs" />
<Compile Include="MonoDevelop.Ide.CodeCompletion\SignatureHelpParameterHintingData.cs" />
<Compile Include="MonoDevelop.Ide.CodeCompletion\RoslynCompletionData.cs" />
@@ -9631,8 +9642,17 @@
<Compile Include="MonoDevelop.Ide.CodeCompletion\KeyActions.cs" />
<Compile Include="MonoDevelop.Ide.CodeCompletion\IListDataProvider.cs" />
<Compile Include="MonoDevelop.Ide.Gui.OptionPanels\D152AccessibilityPanel.cs" />
+ <Compile Include="MonoDevelop.Ide.Editor\EditorConfigService.cs" />
<Compile Include="MonoDevelop.Ide.Gui\StartupAssetType.cs" />
<Compile Include="MonoDevelop.Ide.Gui\DocumentRegistry.cs" />
+ <Compile Include="MonoDevelop.Ide.Codons\ItemTemplateExtensionNode.cs" />
+ <Compile Include="MonoDevelop.Ide.Templates\MicrosoftTemplateEngineItemTemplatingProvider.cs" />
+ <Compile Include="MonoDevelop.Ide.Templates\ItemTemplate.cs" />
+ <Compile Include="MonoDevelop.Ide.Templates\MicrosoftTemplateEngineItemTemplate.cs" />
+ <Compile Include="MonoDevelop.Ide.Templates\MicrosoftTemplateEngine.cs" />
+ <Compile Include="MonoDevelop.Ide.Templates\NewItemConfiguration.cs" />
+ <Compile Include="MonoDevelop.Ide.Templates\ItemTemplatePackageInstaller.cs" />
+ <Compile Include="MonoDevelop.Ide.Templates\TemplatePackageReference.cs" />
</ItemGroup>
<ItemGroup>
<None Include="Makefile.am" />
@@ -9678,6 +9698,7 @@
<Folder Include="MonoDevelop.Components\Xwt\" />
<Folder Include="MonoDevelop.Components.AtkCocoaHelper\" />
<Folder Include="MonoDevelop.Ide.Editor.Highlighting\syntaxes\Markdown\" />
+ <Folder Include="MonoDevelop.Ide.EditorConfig\" />
</ItemGroup>
<ItemGroup>
<Content Include="gtkrc">
@@ -9728,9 +9749,14 @@
<InternalsVisibleTo Include="MonoDevelop.Refactoring.Tests" />
<InternalsVisibleTo Include="Xamarin.Forms.Addin" />
<InternalsVisibleTo Include="MonoDevelop.TextEditor.Tests" />
+ <InternalsVisibleTo Include="WebToolingAddin" />
+ <InternalsVisibleTo Include="Xamarin.Designer.MonoDevelop" />
+ <InternalsVisibleTo Include="Xamarin.AndroidDesigner.MonoDevelop" />
+ <InternalsVisibleTo Include="Xamarin.iOSDesigner.MonoDevelop" />
+ <InternalsVisibleTo Include="Xamarin.FormsPreviewer.MonoDevelop" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<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.Ide/MonoDevelop.Ide/DesktopService.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/DesktopService.cs
index 0c6a410f2d..6d3da0c058 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/DesktopService.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/DesktopService.cs
@@ -400,5 +400,7 @@ namespace MonoDevelop.Ide
return PlatformService.AccessibilityInUse;
}
}
+
+ internal static string GetNativeRuntimeDescription () => PlatformService.GetNativeRuntimeDescription ();
}
}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/DispatchService.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/DispatchService.cs
index 7db2f6b7fd..564c6ad3bc 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/DispatchService.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/DispatchService.cs
@@ -52,7 +52,7 @@ namespace MonoDevelop.Ide
internal class TimeoutProxy
{
- SendOrPostCallback d;
+ internal SendOrPostCallback d;
object state;
ManualResetEventSlim resetEvent;
@@ -89,8 +89,34 @@ namespace MonoDevelop.Ide
[DllImport ("libglib-2.0-0.dll", CallingConvention = CallingConvention.Cdecl)]
static extern uint g_timeout_add_full (int priority, uint interval, GSourceFuncInternal d, IntPtr data, GLib.DestroyNotify notify);
+ class ExceptionWithStackTraceWithoutThrowing : Exception
+ {
+ readonly string stacktrace;
+
+ public ExceptionWithStackTraceWithoutThrowing (string message) : base (message)
+ {
+ stacktrace = Environment.StackTrace;
+ }
+
+ public override string StackTrace => stacktrace;
+ }
+
static void AddTimeout (TimeoutProxy proxy)
{
+ if (proxy.d == null) {
+ // Create an exception without throwing it, as throwing is expensive and these exceptions can be
+ // hit a lot of times.
+
+ const string exceptionMessage = "Unexpected null delegate sent to synchronization context";
+ LoggingService.LogInternalError (exceptionMessage,
+ new ExceptionWithStackTraceWithoutThrowing (exceptionMessage));
+
+ // Return here without queueing the UI operation. Async calls which await on the given callback
+ // will continue immediately, but at least we won't crash.
+ // Having a null continuation won't do anything anyway.
+ return;
+ }
+
var gch = GCHandle.Alloc (proxy);
g_timeout_add_full (defaultPriority, 0, TimeoutProxy.SourceHandler, (IntPtr)gch, GLib.DestroyHelper.NotifyHandler);
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/Ide.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/Ide.cs
index ab8adb3045..505890829c 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/Ide.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/Ide.cs
@@ -534,13 +534,22 @@ namespace MonoDevelop.Ide
DispatchIdleActions (500);
}
-
+
internal static bool OnExit ()
{
- if (Exiting != null) {
- ExitEventArgs args = new ExitEventArgs ();
- Exiting (null, args);
- return !args.Cancel;
+ var exiting = Exiting;
+ if (exiting != null) {
+ bool haveAnyCancelled = false;
+ var args = new ExitEventArgs ();
+ foreach (ExitEventHandler handler in exiting.GetInvocationList ()) {
+ try {
+ handler (null, args);
+ haveAnyCancelled |= args.Cancel;
+ } catch (Exception ex) {
+ LoggingService.LogError ("Exception processing IdeApp.Exiting handler.", ex);
+ }
+ }
+ return !haveAnyCancelled;
}
return true;
}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/IdeStartup.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/IdeStartup.cs
index 87c2f014e9..b3e22ab854 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/IdeStartup.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/IdeStartup.cs
@@ -96,6 +96,9 @@ namespace MonoDevelop.Ide
return 1;
SetupExceptionManager ();
+ // explicit GLib type system initialization for GLib < 2.36 before any other type system access
+ GLib.GType.Init ();
+
IdeApp.Customizer = options.IdeCustomizer ?? new IdeCustomizer ();
try {
IdeApp.Customizer.Initialize ();
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/IdeVersionInfo.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/IdeVersionInfo.cs
index 27c5b8e337..7125638f14 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/IdeVersionInfo.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/IdeVersionInfo.cs
@@ -131,6 +131,13 @@ namespace MonoDevelop.Ide
sb.Append (" (").Append (gtkTheme).AppendLine (" theme)");
else
sb.AppendLine ();
+
+ var nativeRuntime = DesktopService.GetNativeRuntimeDescription ();
+ if (!string.IsNullOrEmpty (nativeRuntime)) {
+ sb.Append ('\t');
+ sb.AppendLine (nativeRuntime);
+ }
+
if (Platform.IsWindows && !IsMono ()) {
using (var key = Microsoft.Win32.Registry.LocalMachine.OpenSubKey (@"SOFTWARE\Xamarin\GtkSharp\Version")) {
Version ver;
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/ImageService.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/ImageService.cs
index 2b7a3da97f..82c899249e 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/ImageService.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/ImageService.cs
@@ -822,10 +822,10 @@ namespace MonoDevelop.Ide
{
var md5 = System.Security.Cryptography.MD5.Create ();
byte[] hash = md5.ComputeHash (Encoding.UTF8.GetBytes (email.Trim ().ToLower ()));
- StringBuilder sb = new StringBuilder ();
+ StringBuilder sb = StringBuilderCache.Allocate ();
foreach (byte b in hash)
sb.Append (b.ToString ("x2"));
- return sb.ToString ();
+ return StringBuilderCache.ReturnAndFree (sb);
}
public static void LoadUserIcon (this Gtk.Image image, string email, int size)
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/MessageService.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/MessageService.cs
index 0dedbf9f98..1dba998a37 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/MessageService.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/MessageService.cs
@@ -91,7 +91,8 @@ namespace MonoDevelop.Ide
public static AlertButton OverwriteFile = new AlertButton (GettextCatalog.GetString ("_Overwrite file"));
public static AlertButton AddExistingFile = new AlertButton (GettextCatalog.GetString ("Add existing file"));
-
+ public static AlertButton MakeWriteable = new AlertButton (GettextCatalog.GetString ("Make Writeable"));
+
public string Label { get; set; }
public string Icon { get; set; }
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/RootWorkspace.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/RootWorkspace.cs
index 3a88bf0b3e..c7d84187ea 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/RootWorkspace.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/RootWorkspace.cs
@@ -426,15 +426,21 @@ namespace MonoDevelop.Ide
item.Dispose ();
}
}
-
+
public bool RequestItemUnload (WorkspaceObject item)
{
- if (ItemUnloading != null) {
+ var itemUnloading = ItemUnloading;
+ if (itemUnloading != null) {
try {
+ bool haveAnyCancelled = false;
ItemUnloadingEventArgs args = new ItemUnloadingEventArgs (item);
- ItemUnloading (this, args);
- return !args.Cancel;
- } catch (Exception ex) {
+ foreach (EventHandler<ItemUnloadingEventArgs> handler in itemUnloading.GetInvocationList ()) {
+ handler (this, args);
+ haveAnyCancelled |= args.Cancel;
+ }
+ return !haveAnyCancelled;
+ }
+ catch (Exception ex) {
LoggingService.LogError ("Exception in ItemUnloading.", ex);
}
}
@@ -619,19 +625,24 @@ namespace MonoDevelop.Ide
}
if (IdeApp.ProjectOperations.CurrentSelectedWorkspaceItem == null)
IdeApp.ProjectOperations.CurrentSelectedWorkspaceItem = GetAllSolutions ().FirstOrDefault ();
- if (Items.Count == 1 && loadPreferences) {
- timer.Trace ("Restoring workspace preferences");
- await RestoreWorkspacePreferences (item);
- }
+ Document.IsInProjectSettingLoadingProcess = true;
+ try {
+ if (Items.Count == 1 && loadPreferences) {
+ timer.Trace ("Restoring workspace preferences");
+ await RestoreWorkspacePreferences (item);
+ }
- if (Items.Count == 1 && !reloading)
- FirstWorkspaceItemRestored?.Invoke (this, new WorkspaceItemEventArgs (item));
+ if (Items.Count == 1 && !reloading)
+ FirstWorkspaceItemRestored?.Invoke (this, new WorkspaceItemEventArgs (item));
- timer.Trace ("Reattaching documents");
- ReattachDocumentProjects (null);
- monitor.ReportSuccess (GettextCatalog.GetString ("Solution loaded."));
+ timer.Trace ("Reattaching documents");
+ ReattachDocumentProjects (null);
+ monitor.ReportSuccess (GettextCatalog.GetString ("Solution loaded."));
- UpdateOpenWorkspaceItemMetadata (metadata, item);
+ UpdateOpenWorkspaceItemMetadata (metadata, item);
+ } finally {
+ Document.IsInProjectSettingLoadingProcess = false;
+ }
}
return true;
}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/RoslynLogger.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/RoslynLogger.cs
index f33ca6475b..ed5f08c122 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/RoslynLogger.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/RoslynLogger.cs
@@ -5,12 +5,20 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Internal.Log;
+using Microsoft.CodeAnalysis.ErrorReporting;
using MonoDevelop.Core;
namespace MonoDevelop.Ide
{
class RoslynLogger : ILogger
{
+ static RoslynLogger ()
+ {
+ // Maybe we should crash here?
+ FatalError.Handler = exception => LoggingService.LogInternalError ("Roslyn fatal exception", exception);
+ FatalError.NonFatalHandler = exception => LoggingService.LogInternalError ("Roslyn non-fatal exception", exception);
+ }
+
public bool IsEnabled (FunctionId functionId)
{
// ? Maybe log more than these exceptions? http://source.roslyn.io/#Microsoft.CodeAnalysis.Workspaces/Log/FunctionId.cs,8
diff --git a/main/src/core/MonoDevelop.Ide/packages.config b/main/src/core/MonoDevelop.Ide/packages.config
index 1c45ae2656..0d86112706 100644
--- a/main/src/core/MonoDevelop.Ide/packages.config
+++ b/main/src/core/MonoDevelop.Ide/packages.config
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+ο»Ώ<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.TemplateEngine.Abstractions" version="1.0.0-beta3-20171117-314" targetFramework="net461" />
<package id="Microsoft.TemplateEngine.Core" version="1.0.0-beta3-20171117-314" targetFramework="net461" />
diff --git a/main/src/core/MonoDevelop.Startup/app.config b/main/src/core/MonoDevelop.Startup/app.config
index 1a0b277854..11cef824bd 100644
--- a/main/src/core/MonoDevelop.Startup/app.config
+++ b/main/src/core/MonoDevelop.Startup/app.config
@@ -108,43 +108,43 @@
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.CodeAnalysis" publicKeyToken="31bf3856ad364e35" culture="neutral" />
- <bindingRedirect oldVersion="0.0.0.0-2.7.0.0" newVersion="2.7.0.0" />
+ <bindingRedirect oldVersion="0.0.0.0-2.8.0.0" newVersion="2.8.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.CodeAnalysis.CSharp" publicKeyToken="31bf3856ad364e35" culture="neutral" />
- <bindingRedirect oldVersion="0.0.0.0-2.7.0.0" newVersion="2.7.0.0" />
+ <bindingRedirect oldVersion="0.0.0.0-2.8.0.0" newVersion="2.8.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.CodeAnalysis.CSharp.Workspaces" publicKeyToken="31bf3856ad364e35" culture="neutral" />
- <bindingRedirect oldVersion="0.0.0.0-2.7.0.0" newVersion="2.7.0.0" />
+ <bindingRedirect oldVersion="0.0.0.0-2.8.0.0" newVersion="2.8.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.CodeAnalysis.Features" publicKeyToken="31bf3856ad364e35" culture="neutral" />
- <bindingRedirect oldVersion="0.0.0.0-2.7.0.0" newVersion="2.7.0.0" />
+ <bindingRedirect oldVersion="0.0.0.0-2.8.0.0" newVersion="2.8.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.CodeAnalysis.EditorFeatures.Text" publicKeyToken="31bf3856ad364e35" culture="neutral" />
- <bindingRedirect oldVersion="0.0.0.0-2.7.0.0" newVersion="2.7.0.0" />
+ <bindingRedirect oldVersion="0.0.0.0-2.8.0.0" newVersion="2.8.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.CodeAnalysis.Workspaces" publicKeyToken="31bf3856ad364e35" culture="neutral" />
- <bindingRedirect oldVersion="0.0.0.0-2.7.0.0" newVersion="2.7.0.0" />
+ <bindingRedirect oldVersion="0.0.0.0-2.8.0.0" newVersion="2.8.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.CodeAnalysis.Workspaces.Desktop" publicKeyToken="31bf3856ad364e35" culture="neutral" />
- <bindingRedirect oldVersion="0.0.0.0-2.7.0.0" newVersion="2.7.0.0" />
+ <bindingRedirect oldVersion="0.0.0.0-2.8.0.0" newVersion="2.8.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.CodeAnalysis.VisualBasic" publicKeyToken="31bf3856ad364e35" culture="neutral" />
- <bindingRedirect oldVersion="0.0.0.0-2.7.0.0" newVersion="2.7.0.0" />
+ <bindingRedirect oldVersion="0.0.0.0-2.8.0.0" newVersion="2.8.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.CodeAnalysis.VisualBasic.Features" publicKeyToken="31bf3856ad364e35" culture="neutral" />
- <bindingRedirect oldVersion="0.0.0.0-2.7.0.0" newVersion="2.7.0.0" />
+ <bindingRedirect oldVersion="0.0.0.0-2.8.0.0" newVersion="2.8.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.CodeAnalysis.VisualBasic.Workspaces" publicKeyToken="31bf3856ad364e35" culture="neutral" />
- <bindingRedirect oldVersion="0.0.0.0-2.7.0.0" newVersion="2.7.0.0" />
+ <bindingRedirect oldVersion="0.0.0.0-2.8.0.0" newVersion="2.8.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.VisualStudio.CoreUtility" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
@@ -163,6 +163,10 @@
<bindingRedirect oldVersion="0.0.0.0-15.0.0.0" newVersion="15.0.0.0" />
</dependentAssembly>
<dependentAssembly>
+ <assemblyIdentity name="Microsoft.VisualStudio.Threading" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-15.6.0.0" newVersion="15.6.0.0" />
+ </dependentAssembly>
+ <dependentAssembly>
<assemblyIdentity name="Microsoft.VisualStudio.Validation" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-15.3.0.0" newVersion="15.3.0.0" />
</dependentAssembly>
diff --git a/main/src/core/MonoDevelop.TextEditor.Tests/Mono.TextEditor.Tests.DefaultEditActions/CaretMoveActionTests.cs b/main/src/core/MonoDevelop.TextEditor.Tests/Mono.TextEditor.Tests.DefaultEditActions/CaretMoveActionTests.cs
index a060504f0c..b5d3108a1f 100644
--- a/main/src/core/MonoDevelop.TextEditor.Tests/Mono.TextEditor.Tests.DefaultEditActions/CaretMoveActionTests.cs
+++ b/main/src/core/MonoDevelop.TextEditor.Tests/Mono.TextEditor.Tests.DefaultEditActions/CaretMoveActionTests.cs
@@ -461,6 +461,44 @@ IEnumerable<string> GetFileExtensions (string filename)
");
}
+ [Test]
+ public void TestUTF32Chars_Right ()
+ {
+ var data = Create (@"$πŸš€");
+ CaretMoveActions.Right (data);
+ Check (data, @"πŸš€$");
+ }
+
+ [Test]
+ public void TestUTF32Chars_Left ()
+ {
+ var data = Create (@"πŸš€$");
+ CaretMoveActions.Left (data);
+ Check (data, @"$πŸš€");
+ }
+ [Test]
+ public void TestUTF32Chars_Up ()
+ {
+ var data = Create (@"12
+πŸš€
+1$2");
+ CaretMoveActions.Up (data);
+ Check (data, @"12
+πŸš€$
+12");
+ }
+
+ [Test]
+ public void TestUTF32Chars_Down ()
+ {
+ var data = Create (@"1$2
+πŸš€
+12");
+ CaretMoveActions.Down (data);
+ Check (data, @"12
+πŸš€$
+12");
+ }
}
}
diff --git a/main/src/core/MonoDevelop.TextEditor.Tests/Mono.TextEditor.Tests.DefaultEditActions/DeleteActionTests.cs b/main/src/core/MonoDevelop.TextEditor.Tests/Mono.TextEditor.Tests.DefaultEditActions/DeleteActionTests.cs
index 3989286a5d..e97d1c14a6 100644
--- a/main/src/core/MonoDevelop.TextEditor.Tests/Mono.TextEditor.Tests.DefaultEditActions/DeleteActionTests.cs
+++ b/main/src/core/MonoDevelop.TextEditor.Tests/Mono.TextEditor.Tests.DefaultEditActions/DeleteActionTests.cs
@@ -242,5 +242,21 @@ namespace Mono.TextEditor.Tests.Actions
MonoDevelop.SourceEditor.EditActions.AdvancedBackspace (data);
Check (data, @""" $)");
}
+
+ [Test]
+ public void TestBackspaceUTF32 ()
+ {
+ var data = Create (@"12πŸš€$34");
+ DeleteActions.Backspace (data);
+ Check (data, @"12$34");
+ }
+
+ [Test]
+ public void TestDeleteUTF32 ()
+ {
+ var data = Create (@"12$πŸš€34");
+ DeleteActions.Delete (data);
+ Check (data, @"12$34");
+ }
}
}
diff --git a/main/src/core/MonoDevelop.TextEditor.Tests/Mono.TextEditor.Tests.DefaultEditActions/MiscActionsTest.cs b/main/src/core/MonoDevelop.TextEditor.Tests/Mono.TextEditor.Tests.DefaultEditActions/MiscActionsTest.cs
index 67f9e3c83d..0069fe500b 100644
--- a/main/src/core/MonoDevelop.TextEditor.Tests/Mono.TextEditor.Tests.DefaultEditActions/MiscActionsTest.cs
+++ b/main/src/core/MonoDevelop.TextEditor.Tests/Mono.TextEditor.Tests.DefaultEditActions/MiscActionsTest.cs
@@ -281,6 +281,17 @@ dddddd$dddd
eeeeeeeeee
ffffffffff");
}
+
+ /// <summary>
+ /// Bug 586125: Alt+Up at beginning of the document results in an exception
+ /// </summary>
+ [Test ()]
+ public void TestBug586125 ()
+ {
+ TextEditorData data = Create (@"$1234567890
+1234567890");
+ MiscActions.MoveBlockUp (data);
+ }
}
}
diff --git a/main/src/core/MonoDevelop.TextEditor.Tests/Mono.TextEditor.Tests/DiffTrackerTests.cs b/main/src/core/MonoDevelop.TextEditor.Tests/Mono.TextEditor.Tests/DiffTrackerTests.cs
new file mode 100644
index 0000000000..4cc2648f66
--- /dev/null
+++ b/main/src/core/MonoDevelop.TextEditor.Tests/Mono.TextEditor.Tests/DiffTrackerTests.cs
@@ -0,0 +1,112 @@
+//
+// DiffTrackerTests.cs
+//
+// Author:
+// Mike KrΓΌger <mikkrg@microsoft.com>
+//
+// Copyright (c) 2018 Microsoft Corporation. All rights reserved.
+//
+// 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 NUnit.Framework;
+using System.Linq;
+using Mono.TextEditor.Utils;
+using System.Text;
+
+namespace Mono.TextEditor.Tests
+{
+ [TestFixture]
+ public class DiffTrackerTests
+ {
+ static TextDocument GetDocument ()
+ {
+ TextDocument doc = new TextDocument ();
+ StringBuilder sb = new StringBuilder ();
+ for (int i = 0; i < 10; i++)
+ sb.AppendLine ("1234567890");
+ doc.Text = sb.ToString ();
+ doc.DiffTracker.SetBaseDocument (doc.CreateDocumentSnapshot ());
+
+ return doc;
+ }
+
+ [Test]
+ public void TestInsertChanged ()
+ {
+ var doc = GetDocument ();
+ Assert.AreEqual (TextDocument.LineState.Unchanged, doc.DiffTracker.GetLineState (doc.GetLine (5)));
+ doc.InsertText (doc.GetLine (5).Offset, "Hello");
+ Assert.AreEqual (TextDocument.LineState.Dirty, doc.DiffTracker.GetLineState (doc.GetLine (5)));
+ }
+
+ [Test]
+ public void TestRemoveChanged ()
+ {
+ var doc = GetDocument ();
+ Assert.AreEqual (TextDocument.LineState.Unchanged, doc.DiffTracker.GetLineState (doc.GetLine (5)));
+ doc.RemoveText (doc.GetLine (5).Offset, 1);
+ Assert.AreEqual (TextDocument.LineState.Dirty, doc.DiffTracker.GetLineState (doc.GetLine (5)));
+ }
+
+ [Test]
+ public void TestInsertLine ()
+ {
+ var doc = GetDocument ();
+ Assert.AreEqual (TextDocument.LineState.Unchanged, doc.DiffTracker.GetLineState (doc.GetLine (5)));
+ doc.InsertText (doc.GetLine (5).Offset, "Hello\n");
+ Assert.AreEqual (TextDocument.LineState.Dirty, doc.DiffTracker.GetLineState (doc.GetLine (5)));
+ }
+
+ [Test]
+ public void TestRemoveLine ()
+ {
+ var doc = GetDocument ();
+ Assert.AreEqual (TextDocument.LineState.Unchanged, doc.DiffTracker.GetLineState (doc.GetLine (5)));
+ doc.RemoveText (doc.GetLine (5).Offset, doc.GetLine (5).LengthIncludingDelimiter);
+ Assert.AreEqual (TextDocument.LineState.Dirty, doc.DiffTracker.GetLineState (doc.GetLine (5)));
+ }
+
+ [Test]
+ public void TestLowerLineChangeOnInsert ()
+ {
+ var doc = GetDocument ();
+ Assert.AreEqual (TextDocument.LineState.Unchanged, doc.DiffTracker.GetLineState (doc.GetLine (5)));
+ doc.InsertText (doc.GetLine (7).Offset, "Hello\n");
+ doc.InsertText (doc.GetLine (5).Offset, "Hello\n");
+ Assert.AreEqual (TextDocument.LineState.Dirty, doc.DiffTracker.GetLineState (doc.GetLine (5)));
+ Assert.AreEqual (TextDocument.LineState.Unchanged, doc.DiffTracker.GetLineState (doc.GetLine (7)));
+ Assert.AreEqual (TextDocument.LineState.Dirty, doc.DiffTracker.GetLineState (doc.GetLine (8)));
+ }
+
+
+ [Test]
+ public void TestLowerLineChangeOnRemove ()
+ {
+ var doc = GetDocument ();
+ Assert.AreEqual (TextDocument.LineState.Unchanged, doc.DiffTracker.GetLineState (doc.GetLine (5)));
+ doc.InsertText (doc.GetLine (7).Offset, "Hello\n");
+ doc.RemoveText (doc.GetLine (5).Offset, doc.GetLine (5).LengthIncludingDelimiter);
+ Assert.AreEqual (TextDocument.LineState.Dirty, doc.DiffTracker.GetLineState (doc.GetLine (5)));
+ Assert.AreEqual (TextDocument.LineState.Unchanged, doc.DiffTracker.GetLineState (doc.GetLine (7)));
+ Assert.AreEqual (TextDocument.LineState.Dirty, doc.DiffTracker.GetLineState (doc.GetLine (6)));
+ }
+
+ }
+}
diff --git a/main/src/core/MonoDevelop.TextEditor.Tests/MonoDevelop.TextEditor.Tests.csproj b/main/src/core/MonoDevelop.TextEditor.Tests/MonoDevelop.TextEditor.Tests.csproj
index ed0861d6bf..2e81e3c00d 100644
--- a/main/src/core/MonoDevelop.TextEditor.Tests/MonoDevelop.TextEditor.Tests.csproj
+++ b/main/src/core/MonoDevelop.TextEditor.Tests/MonoDevelop.TextEditor.Tests.csproj
@@ -80,6 +80,7 @@
<Compile Include="Mono.TextEditor.Tests\SemanticRuleTests.cs" />
<Compile Include="Mono.TextEditor.Tests\TextEditorDataTests.cs" />
<Compile Include="MonoDevelop.TextEditor.Extension\NavigationExtensionTests.cs" />
+ <Compile Include="Mono.TextEditor.Tests\DiffTrackerTests.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>