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:
authorJeffrey Stedfast <jestedfa@microsoft.com>2019-08-07 19:32:26 +0300
committerJeffrey Stedfast <jestedfa@microsoft.com>2019-08-07 19:32:26 +0300
commit87513d0fc80db7df76feeeda996bb69c7c85fa3b (patch)
tree8756c5d507f3797f011080116642ab533a8e6f9f /main/src/core
parentdd19d5a12437cf88d0d9d136dd76ad7edaf61089 (diff)
parentb6e403e5402c9696e27fb23a494c5e4596281696 (diff)
Merge branch 'master' into vsts-866545-objectvaluetreeview
Diffstat (limited to 'main/src/core')
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/TargetFrameworkMoniker.cs4
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Core/FilePath.cs31
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/ProjectTypeNode.cs6
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/SolutionItemTypeNode.cs2
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/DefaultMSBuildEngine.cs6
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildEvaluationContext.cs293
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildFileFormat.cs4
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildProjectInstance.cs2
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildProjectService.cs32
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/ProjectEvaluationException.cs8
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/SlnFileFormat.cs40
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/CompiledAssemblyProject.cs8
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/MSBuildSerializationExtension.cs28
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs4
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectService.cs6
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SdkProjectExtension.cs70
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SdkProjectReader.cs12
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItem.cs6
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/WorkspaceItem.cs2
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/WorkspaceObjectReader.cs4
-rw-r--r--main/src/core/MonoDevelop.Core/MonoDevelop.Projects/WorkspaceSerializationExtension.cs10
-rw-r--r--main/src/core/MonoDevelop.Ide/ExtensionModel/Commands.addin.xml19
-rw-r--r--main/src/core/MonoDevelop.Ide/ExtensionModel/MainMenu.addin.xml2
-rw-r--r--main/src/core/MonoDevelop.Ide/ExtensionModel/MonoDevelop.Ide.addin.xml2
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Commands/ActionCommand.cs7
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Commands/CommandManager.cs14
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.DockNotebook/DockNotebook.cs33
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.DockNotebook/DockNotebookTab.cs18
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.DockNotebook/TabStrip.cs83
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockBarItem.cs21
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.MainToolbar/CommandSearchCategory.cs26
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components/GtkWorkarounds.cs29
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Mac/NSViewExtensions.cs5
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Shared/GtkWorkarounds.cs65
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Commands/FileCommands.cs1
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Commands/FileTabCommands.cs102
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.CustomTools/CustomToolService.cs9
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/DefaultSourceEditorOptions.cs2
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/Workbench.cs21
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/WorkbenchMemento.cs3
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.csproj12
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/Ide.cs4
-rw-r--r--main/src/core/MonoDevelop.Ide/icons/tab-pinned-9.pngbin0 -> 138 bytes
-rw-r--r--main/src/core/MonoDevelop.Ide/icons/tab-pinned-9@2x.pngbin0 -> 209 bytes
-rw-r--r--main/src/core/MonoDevelop.Ide/icons/tab-pinned-9~dark.pngbin0 -> 137 bytes
-rw-r--r--main/src/core/MonoDevelop.Ide/icons/tab-pinned-9~dark@2x.pngbin0 -> 201 bytes
-rw-r--r--main/src/core/MonoDevelop.Ide/icons/tab-unpinned-9.pngbin0 -> 143 bytes
-rw-r--r--main/src/core/MonoDevelop.Ide/icons/tab-unpinned-9@2x.pngbin0 -> 188 bytes
-rw-r--r--main/src/core/MonoDevelop.Ide/icons/tab-unpinned-9~dark.pngbin0 -> 140 bytes
-rw-r--r--main/src/core/MonoDevelop.Ide/icons/tab-unpinned-9~dark@2x.pngbin0 -> 178 bytes
50 files changed, 723 insertions, 333 deletions
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/TargetFrameworkMoniker.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/TargetFrameworkMoniker.cs
index 7b49c3be82..e6d4a4b32d 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/TargetFrameworkMoniker.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core.Assemblies/TargetFrameworkMoniker.cs
@@ -333,6 +333,10 @@ namespace MonoDevelop.Core.Assemblies
get { return new TargetFrameworkMoniker ("4.7.1"); }
}
+ public static TargetFrameworkMoniker NET_4_7_2 {
+ get { return new TargetFrameworkMoniker ("4.7.2"); }
+ }
+
public static TargetFrameworkMoniker PORTABLE_4_0 {
get { return new TargetFrameworkMoniker (ID_PORTABLE, "4.0", "Profile1"); }
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Core/FilePath.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Core/FilePath.cs
index c0e4238cb8..d48d076f05 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Core/FilePath.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Core/FilePath.cs
@@ -143,6 +143,14 @@ namespace MonoDevelop.Core
}
}
+ [Pure]
+ internal bool HasFileName (string name)
+ {
+ return fileName.Length > name.Length
+ && fileName.EndsWith (name, PathComparison)
+ && fileName [fileName.Length - name.Length - 1] == Path.DirectorySeparatorChar;
+ }
+
public string Extension {
get {
return Path.GetExtension (fileName);
@@ -153,8 +161,27 @@ namespace MonoDevelop.Core
public bool HasExtension (string extension)
{
return fileName.Length > extension.Length
- && fileName.EndsWith (extension, PathComparison)
- && fileName[fileName.Length - extension.Length - 1] != Path.PathSeparator;
+ && (extension == string.Empty
+ ? HasNoExtension (fileName)
+ : fileName.EndsWith (extension, PathComparison) && fileName [fileName.Length - extension.Length] == '.');
+
+ static bool HasNoExtension (string path)
+ {
+ // Look for the last dot that's after the last path separator
+ for (int i = path.Length - 1; i >= 0; --i) {
+ var ch = path [i];
+ if (ch == '.') {
+ // Check if it's the dot is the last character
+ // if it is, then we have no extension
+ return i == path.Length - 1;
+ }
+
+ if (ch == Path.DirectorySeparatorChar)
+ return true;
+ }
+
+ return true;
+ }
}
public string FileNameWithoutExtension {
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/ProjectTypeNode.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/ProjectTypeNode.cs
index 18d9d0e167..13d5beeaae 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/ProjectTypeNode.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/ProjectTypeNode.cs
@@ -45,7 +45,7 @@ namespace MonoDevelop.Projects.Extensions
Project project = null;
if (!string.IsNullOrEmpty (fileName)) {
- p = await MSBuildProject.LoadAsync (fileName);
+ p = await MSBuildProject.LoadAsync (fileName).ConfigureAwait (false);
if (ctx != null && ctx.Solution != null) {
p.EngineManager = ctx.Solution.MSBuildEngineManager;
p.SolutionDirectory = ctx.Solution.ItemDirectory;
@@ -53,7 +53,7 @@ namespace MonoDevelop.Projects.Extensions
var migrators = MSBuildProjectService.GetMigrableFlavors (p.ProjectTypeGuids);
if (migrators.Count > 0)
- await MSBuildProjectService.MigrateFlavors (monitor, fileName, Guid, p, migrators);
+ await MSBuildProjectService.MigrateFlavors (monitor, fileName, Guid, p, migrators).ConfigureAwait (false);
var unsupporedFlavor = p.ProjectTypeGuids.FirstOrDefault (fid => !MSBuildProjectService.IsKnownFlavorGuid (fid) && !MSBuildProjectService.IsKnownTypeGuid (fid));
if (unsupporedFlavor != null) {
@@ -72,7 +72,7 @@ namespace MonoDevelop.Projects.Extensions
}
if (project == null)
- project = await base.CreateSolutionItem (monitor, ctx, fileName) as Project;
+ project = await base.CreateSolutionItem (monitor, ctx, fileName).ConfigureAwait(false) as Project;
if (project == null)
throw new InvalidOperationException ("Project node type is not a subclass of MonoDevelop.Projects.Project");
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/SolutionItemTypeNode.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/SolutionItemTypeNode.cs
index 46fa87c880..3cd16adde0 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/SolutionItemTypeNode.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Extensions/SolutionItemTypeNode.cs
@@ -99,7 +99,7 @@ namespace MonoDevelop.Projects.Extensions
if (typeof(SolutionItemFactory).IsAssignableFrom (ItemType)) {
if (factory == null)
factory = (SolutionItemFactory)Activator.CreateInstance (ItemType);
- item = await factory.CreateItem (fileName, Guid);
+ item = await factory.CreateItem (fileName, Guid).ConfigureAwait (false);
} else
item = MSBuildProjectService.CreateUninitializedInstance (ItemType);
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 e821b48bf6..a22fc426c5 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/DefaultMSBuildEngine.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/DefaultMSBuildEngine.cs
@@ -850,7 +850,7 @@ namespace MonoDevelop.Projects.MSBuild
static bool IsWildcardInclude (string include)
{
- return include.IndexOf ('*') != -1;
+ return include.IndexOfAny (wildcards) != -1;
}
IEnumerable<MSBuildItemEvaluated> ExpandWildcardFilePath (ProjectInfo pinfo, MSBuildEvaluationContext context, MSBuildItem sourceItem, string path, Regex directoryExcludeRegex)
@@ -1018,7 +1018,7 @@ namespace MonoDevelop.Projects.MSBuild
return it;
}
- static char[] wildcards = { '*', '%' };
+ static char[] wildcards = { '*', '?' };
void Evaluate (ProjectInfo project, MSBuildEvaluationContext context, MSBuildProperty prop)
{
@@ -1174,7 +1174,7 @@ namespace MonoDevelop.Projects.MSBuild
var fileName = Path.GetFileName (path);
- if (fileName.IndexOfAny (new [] { '*', '?' }) == -1) {
+ if (fileName.IndexOfAny (wildcards) == -1) {
// Not a wildcard. Keep searching if the file doesn't exist.
var result = File.Exists (path) ? new [] { path } : null;
keepSearching = result == null;
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 94ea9abfa3..e7626bece3 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildEvaluationContext.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildEvaluationContext.cs
@@ -614,10 +614,6 @@ namespace MonoDevelop.Projects.MSBuild
if (memberName.Length == 0)
return false;
- var member = ResolveMember (type, memberName.ToString (), instance == null);
- if (member == null || member.Length == 0)
- return false;
-
if (j < str.Length && str[j] == '(') {
// It is a method invocation
object [] parameterValues;
@@ -625,6 +621,10 @@ namespace MonoDevelop.Projects.MSBuild
if (!EvaluateParameters (str, ref j, out parameterValues))
return false;
+ var member = ResolveMember (type, memberName.ToString (), instance == null, MemberTypes.Method);
+ if (member == null || member.Length == 0)
+ return false;
+
if (!EvaluateMethod (str, member, instance, parameterValues, out val))
return false;
@@ -634,6 +634,10 @@ namespace MonoDevelop.Projects.MSBuild
} else {
// It has to be a property or field
try {
+ var member = ResolveMember (type, memberName.ToString (), instance == null, MemberTypes.Property | MemberTypes.Field);
+ if (member == null || member.Length == 0)
+ return false;
+
if (member[0] is PropertyInfo)
val = ((PropertyInfo)member[0]).GetValue (instance);
else if (member[0] is FieldInfo)
@@ -683,7 +687,7 @@ namespace MonoDevelop.Projects.MSBuild
internal bool EvaluateMember (ReadOnlySpan<char> str, Type type, string memberName, object instance, object [] parameterValues, out object val)
{
val = null;
- var member = ResolveMember (type, memberName, instance == null);
+ var member = ResolveMember (type, memberName, instance == null, MemberTypes.Method);
if (member == null || member.Length == 0)
return false;
return EvaluateMethod (str, member, instance, parameterValues, out val);
@@ -694,22 +698,17 @@ namespace MonoDevelop.Projects.MSBuild
val = null;
// Find a method with a matching number of parameters
- var method = FindBestOverload (member.OfType<MethodBase> (), parameterValues);
+ var (method, methodParams) = FindBestOverload (member, parameterValues, out var paramsArgType);
if (method == null)
return false;
try {
// Convert the given parameters to the types specified in the method signature
- var methodParams = method.GetParameters ();
-
var convertedArgs = (methodParams.Length == parameterValues.Length) ? parameterValues : new object [methodParams.Length];
int numArgs = methodParams.Length;
- Type paramsArgType = null;
- if (methodParams.Length > 0 && methodParams [methodParams.Length - 1].ParameterType.IsArray && methodParams [methodParams.Length - 1].IsDefined (typeof (ParamArrayAttribute))) {
- paramsArgType = methodParams [methodParams.Length - 1].ParameterType.GetElementType ();
+ if (paramsArgType != null)
numArgs--;
- }
if (method.DeclaringType == typeof (IntrinsicFunctions) && method.Name == nameof (IntrinsicFunctions.GetPathOfFileAbove) && parameterValues.Length == methodParams.Length - 1) {
string startingDirectory = String.IsNullOrWhiteSpace (FullFileName) ? String.Empty : Path.GetDirectoryName (FullFileName);
@@ -792,58 +791,158 @@ namespace MonoDevelop.Projects.MSBuild
return false;
}
- MethodBase FindBestOverload (IEnumerable<MethodBase> methods, object [] args)
+ (MethodBase method, ParameterInfo[] parameters) FindBestOverload (IEnumerable<MemberInfo> members, object [] args, out Type paramsArgType)
{
- MethodBase methodWithParams = null;
+ (MethodBase, ParameterInfo[]) methodWithParams = default;
+ (MethodBase, ParameterInfo[]) validMatch = default;
- foreach (var m in methods) {
- var argInfo = m.GetParameters ();
+ paramsArgType = null;
- // Exclude methods which take a complex object as argument
- if (argInfo.Any (a => a.ParameterType != typeof(object) && Type.GetTypeCode (a.ParameterType) == TypeCode.Object && !IsParamsArg(a)))
+ foreach (var member in members) {
+ if (!(member is MethodBase m))
continue;
- if (args.Length >= argInfo.Length - 1 && argInfo.Length > 0 && IsParamsArg (argInfo [argInfo.Length - 1])) {
- methodWithParams = m;
- continue;
- }
- if (args.Length != argInfo.Length) {
- if (args.Length == argInfo.Length - 1 && m.DeclaringType != typeof (IntrinsicFunctions) || m.Name != nameof(IntrinsicFunctions.GetPathOfFileAbove)) {
+ var argInfo = m.GetParameters ();
+
+ if (args.Length == argInfo.Length - 1) {
+ if (m.DeclaringType == typeof (IntrinsicFunctions) && m.Name == nameof (IntrinsicFunctions.GetPathOfFileAbove)) {
+ validMatch = (m, argInfo);
continue;
}
}
- bool isValid = true;
- for (int n = 0; n < args.Length; n++) {
- if (!CanConvertArg (m, n, args [n], argInfo [n].ParameterType)) {
- isValid = false;
- break;
- }
+ // Unable to match in this case.
+ if (args.Length < argInfo.Length - 1)
+ continue;
+
+ var kind = MatchArgs (args, argInfo);
+ if (kind == MatchKind.Exact)
+ return (m, argInfo);
+
+ if (kind == MatchKind.CanConvert)
+ validMatch = (m, argInfo);
+ else if (kind == MatchKind.Params) {
+ methodWithParams = (m, argInfo);
+ paramsArgType = argInfo [argInfo.Length - 1].ParameterType.GetElementType ();
}
- if (isValid)
- return m;
}
- return methodWithParams;
+
+ return validMatch != default ? validMatch : methodWithParams;
}
- bool IsParamsArg (ParameterInfo pi)
+ enum MatchKind
+ {
+ None,
+ Params,
+ CanConvert,
+ Exact,
+ }
+
+ static MatchKind MatchArgs (object[] args, ParameterInfo[] parameters)
+ {
+ bool isParams = parameters.Length > 0 && IsParamsArg (parameters [parameters.Length - 1]);
+
+ int last = parameters.Length;
+ if (isParams)
+ last--;
+ else if (args.Length != parameters.Length)
+ return MatchKind.None;
+
+ var kind = MatchKind.Exact;
+ for (int n = 0; n < last; n++) {
+ var parameterType = parameters [n].ParameterType;
+
+ var other = Match (parameterType, args [n]);
+ if (other == MatchKind.None)
+ return MatchKind.None;
+
+ if (other == MatchKind.CanConvert)
+ kind = MatchKind.CanConvert;
+ }
+
+ if (!isParams)
+ return kind;
+
+ // Check implicit argument
+ if (args.Length == last)
+ return MatchKind.Params;
+
+ var elementType = parameters[last].ParameterType.GetElementType ();
+ if (IsComplexType (elementType))
+ return MatchKind.None;
+
+ int argsRemaining = args.Length - last;
+ if (argsRemaining == 1 && elementType == typeof(char)) {
+ if (Match (parameters [last].ParameterType, args [last], checkComplexType: false) != MatchKind.None)
+ return MatchKind.Params;
+ }
+
+ for (int n_arg = last; n_arg < args.Length; ++n_arg) {
+ if (Match (elementType, args [n_arg]) == MatchKind.None)
+ return MatchKind.None;
+ }
+
+ return MatchKind.Params;
+
+ static bool IsComplexType (Type type)
+ {
+ return Type.GetTypeCode (type) == TypeCode.Object && type != typeof (object);
+ }
+
+ static MatchKind Match (Type parameterType, object argument, bool checkComplexType = true)
+ {
+ if (parameterType.IsInstanceOfType (argument))
+ return MatchKind.Exact;
+
+ if (checkComplexType && IsComplexType (parameterType))
+ return MatchKind.None;
+
+ if (CanConvertArg (argument, parameterType))
+ return MatchKind.CanConvert;
+
+
+ return MatchKind.None;
+ }
+ }
+
+ static bool IsParamsArg (ParameterInfo pi)
{
return pi.ParameterType.IsArray && pi.IsDefined (typeof (ParamArrayAttribute));
}
- bool CanConvertArg (MethodBase method, int argNum, object value, Type parameterType)
+ static bool CanConvertArg (object value, Type parameterType)
{
var sval = value as string;
if (sval == "null" || value == null)
- return !parameterType.IsValueType || typeof(Nullable).IsInstanceOfType (parameterType);
+ return !parameterType.IsValueType || Nullable.GetUnderlyingType (parameterType) != null;
if (sval != null && parameterType == typeof (char []))
return true;
- if (parameterType == typeof (char) && sval != null && sval.Length != 1)
+ if (sval != null && sval.Length != 1 && parameterType == typeof (char)) {
return false;
+ }
- return true;
+ if (sval != null && parameterType.IsEnum) {
+ // Enum.Parse expects comma separated values.
+ var enumValue = sval.Replace ('|', ',')
+ .Replace (parameterType.FullName + ".", "")
+ .Replace (parameterType.Name + ".", "");
+
+ try {
+ _ = Enum.Parse (parameterType, enumValue, ignoreCase: true);
+ return true;
+ } catch {
+ return false;
+ }
+ }
+
+ try {
+ _ = Convert.ChangeType (value, parameterType, CultureInfo.InvariantCulture);
+ return true;
+ } catch {
+ return false;
+ }
}
object ConvertArg (MethodBase method, int argNum, object value, Type parameterType)
@@ -856,11 +955,11 @@ namespace MonoDevelop.Projects.MSBuild
return sval.ToCharArray ();
if (sval != null && parameterType.IsEnum) {
- var enumValue = sval;
- if (enumValue.StartsWith (parameterType.Name, StringComparison.Ordinal))
- enumValue = enumValue.Substring (parameterType.Name.Length + 1);
- if (enumValue.StartsWith (parameterType.FullName, StringComparison.Ordinal))
- enumValue = enumValue.Substring (parameterType.FullName.Length + 1);
+ // Enum.Parse expects comma separated values.
+ var enumValue = sval.Replace ('|', ',')
+ .Replace (parameterType.FullName + ".", "")
+ .Replace (parameterType.Name + ".", "");
+
return Enum.Parse(parameterType, enumValue, ignoreCase: true);
}
@@ -907,15 +1006,15 @@ namespace MonoDevelop.Projects.MSBuild
{
if (typeName == "MSBuild")
return typeof (Microsoft.Build.Evaluation.IntrinsicFunctions);
- else {
- var t = supportedTypeMembers.FirstOrDefault (st => st.Item1.FullName == typeName);
- if (t == null)
- return null;
- return t.Item1;
+
+ foreach (var kvp in supportedTypeMembers) {
+ if (kvp.Key.FullName == typeName)
+ return kvp.Key;
}
+ return null;
}
- MemberInfo[] ResolveMember (Type type, string memberName, bool isStatic)
+ MemberInfo[] ResolveMember (Type type, string memberName, bool isStatic, MemberTypes memberTypes)
{
if (type == typeof (string) && memberName == "new")
memberName = "Copy";
@@ -923,52 +1022,68 @@ namespace MonoDevelop.Projects.MSBuild
type = typeof (Array);
var flags = isStatic ? BindingFlags.Static : BindingFlags.Instance;
if (type != typeof (Microsoft.Build.Evaluation.IntrinsicFunctions)) {
- var t = supportedTypeMembers.FirstOrDefault (st => st.Item1 == type);
- if (t == null)
+ if (!supportedTypeMembers.TryGetValue (type, out var list))
return null;
- if (t.Item2 != null && !t.Item2.Contains (memberName))
+
+ if (list != null && !list.Contains (memberName))
return null;
} else
flags |= BindingFlags.NonPublic;
-
- return type.GetMember (memberName, flags | BindingFlags.Public | BindingFlags.IgnoreCase);
+
+ return type.GetMember (memberName, memberTypes, flags | BindingFlags.Public | BindingFlags.IgnoreCase);
}
- static Tuple<Type, string []> [] supportedTypeMembers = {
- Tuple.Create (typeof(System.Array), (string[]) null),
- Tuple.Create (typeof(System.Byte), (string[]) null),
- Tuple.Create (typeof(System.Char), (string[]) null),
- Tuple.Create (typeof(System.Convert), (string[]) null),
- Tuple.Create (typeof(System.DateTime), (string[]) null),
- Tuple.Create (typeof(System.Decimal), (string[]) null),
- Tuple.Create (typeof(System.Double), (string[]) null),
- Tuple.Create (typeof(System.Enum), (string[]) null),
- Tuple.Create (typeof(System.Guid), (string[]) null),
- Tuple.Create (typeof(System.Int16), (string[]) null),
- Tuple.Create (typeof(System.Int32), (string[]) null),
- Tuple.Create (typeof(System.Int64), (string[]) null),
- Tuple.Create (typeof(System.IO.Path), (string[]) null),
- Tuple.Create (typeof(System.Math), (string[]) null),
- Tuple.Create (typeof(System.UInt16), (string[]) null),
- Tuple.Create (typeof(System.UInt32), (string[]) null),
- Tuple.Create (typeof(System.UInt64), (string[]) null),
- Tuple.Create (typeof(System.SByte), (string[]) null),
- Tuple.Create (typeof(System.Single), (string[]) null),
- Tuple.Create (typeof(System.String), (string[]) null),
- Tuple.Create (typeof(System.StringComparer), (string[]) null),
- Tuple.Create (typeof(System.TimeSpan), (string[]) null),
- Tuple.Create (typeof(System.Text.RegularExpressions.Regex), (string[]) null),
- Tuple.Create (typeof(Microsoft.Build.Utilities.ToolLocationHelper), (string[]) null),
- Tuple.Create (typeof(System.Globalization.CultureInfo), (string[]) null),
- Tuple.Create (typeof(System.Environment), new string [] {
- "CommandLine", "ExpandEnvironmentVariables", "GetEnvironmentVariable", "GetEnvironmentVariables", "GetFolderPath", "GetLogicalDrives"
- }),
- Tuple.Create (typeof(System.IO.Directory), new string [] {
- "GetDirectories", "GetFiles", "GetLastAccessTime", "GetLastWriteTime", "GetParent"
- }),
- Tuple.Create (typeof(System.IO.File), new string [] {
- "Exists", "GetCreationTime", "GetAttributes", "GetLastAccessTime", "GetLastWriteTime", "ReadAllText"
- }),
+ sealed class TypeEqualityComparer : IEqualityComparer<Type>
+ {
+ public bool Equals (Type x, Type y) => x == y;
+
+ public int GetHashCode (Type obj) => obj?.GetHashCode () ?? 0;
+ }
+
+ static readonly Dictionary<Type, string []> supportedTypeMembers = new Dictionary<Type, string []> (new TypeEqualityComparer()) {
+ { typeof(System.Array), null },
+ { typeof(System.Byte), null },
+ { typeof(System.Char), null },
+ { typeof(System.Convert), null },
+ { typeof(System.DateTime), null },
+ { typeof(System.Decimal), null },
+ { typeof(System.Double), null },
+ { typeof(System.Enum), null },
+ { typeof(System.Guid), null },
+ { typeof(System.Int16), null },
+ { typeof(System.Int32), null },
+ { typeof(System.Int64), null },
+ { typeof(System.IO.Path), null },
+ { typeof(System.Math), null },
+ { typeof(System.UInt16), null },
+ { typeof(System.UInt32), null },
+ { typeof(System.UInt64), null },
+ { typeof(System.SByte), null },
+ { typeof(System.Single), null },
+ { typeof(System.String), null },
+ { typeof(System.StringComparer), null },
+ { typeof(System.TimeSpan), null },
+ { typeof(System.Text.RegularExpressions.Regex), null },
+ { typeof(Microsoft.Build.Utilities.ToolLocationHelper), null },
+ { typeof(System.Globalization.CultureInfo), null },
+ {
+ typeof (System.Environment),
+ new string [] {
+ "CommandLine", "ExpandEnvironmentVariables", "GetEnvironmentVariable", "GetEnvironmentVariables", "GetFolderPath", "GetLogicalDrives"
+ }
+ },
+ {
+ typeof (System.IO.Directory),
+ new string [] {
+ "GetDirectories", "GetFiles", "GetLastAccessTime", "GetLastWriteTime", "GetParent"
+ }
+ },
+ {
+ typeof (System.IO.File),
+ new string [] {
+ "Exists", "GetCreationTime", "GetAttributes", "GetLastAccessTime", "GetLastWriteTime", "ReadAllText"
+ }
+ },
};
int FindNextTag (string str, int i)
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildFileFormat.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildFileFormat.cs
index e7c8945f90..fe0e089335 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildFileFormat.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildFileFormat.cs
@@ -168,7 +168,7 @@ namespace MonoDevelop.Projects.MSBuild
internal async Task WriteFile (FilePath file, object obj, ProgressMonitor monitor)
{
if (slnFileFormat.CanWriteFile (obj, this)) {
- await slnFileFormat.WriteFile (file, obj, true, monitor);
+ await slnFileFormat.WriteFile (file, obj, true, monitor).ConfigureAwait (false);
} else {
throw new NotSupportedException ();
}
@@ -177,7 +177,7 @@ namespace MonoDevelop.Projects.MSBuild
internal async Task<object> ReadFile (FilePath file, Type expectedType, MonoDevelop.Core.ProgressMonitor monitor)
{
if (slnFileFormat.CanReadFile (file, this))
- return await slnFileFormat.ReadFile (file, monitor);
+ return await slnFileFormat.ReadFile (file, monitor).ConfigureAwait(false);
else
throw new NotSupportedException ();
}
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 a23254c86c..4b21073b76 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildProjectInstance.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildProjectInstance.cs
@@ -115,7 +115,7 @@ namespace MonoDevelop.Projects.MSBuild
} catch (Exception ex) {
// If the project can't be evaluated don't crash
LoggingService.LogError ("MSBuild project could not be evaluated", ex);
- throw new ProjectEvaluationException (msproject, ex.Message);
+ throw new ProjectEvaluationException (msproject, ex.Message, ex);
} finally {
if (oldProjectInstance != null)
engine.DisposeProjectInstance (oldProjectInstance);
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildProjectService.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildProjectService.cs
index 703bbcf97d..398aa31187 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildProjectService.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/MSBuildProjectService.cs
@@ -784,26 +784,24 @@ namespace MonoDevelop.Projects.MSBuild
return Task.FromResult<SolutionItem> (new GenericProject ());
// Unknown project types are already displayed in the solution view, we don't need to tell the user with a modal dialog as well
- return Task<SolutionItem>.Factory.StartNew (delegate {
- var t = ReadGenericProjectType (file);
- if (t == null)
- throw new UnknownSolutionItemTypeException (GettextCatalog.GetString ("Unknown project type"));
+ var t = ReadGenericProjectType (file);
+ if (t == null)
+ return Task.FromException<SolutionItem> (new UnknownSolutionItemTypeException (GettextCatalog.GetString ("Unknown project type")));
- var dt = Services.ProjectService.DataContext.GetConfigurationDataType (t);
- if (dt != null) {
- if (!typeof (Project).IsAssignableFrom (dt.ValueType))
- throw new UnknownSolutionItemTypeException (GettextCatalog.GetString ("Unknown project type: {0}", t));
+ var dt = Services.ProjectService.DataContext.GetConfigurationDataType (t);
+ if (dt != null) {
+ if (!typeof (Project).IsAssignableFrom (dt.ValueType))
+ return Task.FromException<SolutionItem> (new UnknownSolutionItemTypeException (GettextCatalog.GetString ("Unknown project type: {0}", t)));
- return (SolutionItem)Activator.CreateInstance (dt.ValueType);
- }
+ return Task.FromResult ((SolutionItem)Activator.CreateInstance (dt.ValueType));
+ }
- Type type;
- lock (genericProjectTypes) {
- if (!genericProjectTypes.TryGetValue (t, out type))
- throw new UnknownSolutionItemTypeException (GettextCatalog.GetString ("Unknown project type: {0}", t));
- }
- return (SolutionItem)Activator.CreateInstance (type);
- });
+ Type type;
+ lock (genericProjectTypes) {
+ if (!genericProjectTypes.TryGetValue (t, out type))
+ return Task.FromException<SolutionItem> (new UnknownSolutionItemTypeException (GettextCatalog.GetString ("Unknown project type: {0}", t)));
+ }
+ return Task.FromResult ((SolutionItem)Activator.CreateInstance (type));
}
static string ReadGenericProjectType (string file)
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/ProjectEvaluationException.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/ProjectEvaluationException.cs
index 000fcea525..88775b3e5d 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/ProjectEvaluationException.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/ProjectEvaluationException.cs
@@ -29,12 +29,16 @@ namespace MonoDevelop.Projects.MSBuild
{
public class ProjectEvaluationException: ApplicationException
{
- public ProjectEvaluationException (MSBuildProject project, string message): base (message)
+ internal ProjectEvaluationException (MSBuildProject project, string message, Exception innerException) : base (message, innerException)
{
Project = project;
}
- public MSBuildProject Project { get; private set; }
+ public ProjectEvaluationException (MSBuildProject project, string message): this (project, message, null)
+ {
+ }
+
+ public MSBuildProject Project { get; }
}
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/SlnFileFormat.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/SlnFileFormat.cs
index 742edb3d99..581fef41d4 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/SlnFileFormat.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects.MSBuild/SlnFileFormat.cs
@@ -64,22 +64,20 @@ namespace MonoDevelop.Projects.MSBuild
return obj is Solution;
}
- public Task WriteFile (string file, object obj, bool saveProjects, ProgressMonitor monitor)
+ public async Task WriteFile (string file, object obj, bool saveProjects, ProgressMonitor monitor)
{
- return Task.Run (async delegate {
- Solution sol = (Solution)obj;
+ Solution sol = (Solution)obj;
- try {
- monitor.BeginTask (GettextCatalog.GetString ("Saving solution: {0}", file), 1);
- await WriteFileInternal (file, file, sol, saveProjects, monitor).ConfigureAwait (false);
- } catch (Exception ex) {
- monitor.ReportError (GettextCatalog.GetString ("Could not save solution: {0}", file), ex);
- LoggingService.LogError (GettextCatalog.GetString ("Could not save solution: {0}", file), ex);
- throw;
- } finally {
- monitor.EndTask ();
- }
- });
+ try {
+ monitor.BeginTask (GettextCatalog.GetString ("Saving solution: {0}", file), 1);
+ await WriteFileInternal (file, file, sol, saveProjects, monitor).ConfigureAwait (false);
+ } catch (Exception ex) {
+ monitor.ReportError (GettextCatalog.GetString ("Could not save solution: {0}", file), ex);
+ LoggingService.LogError (GettextCatalog.GetString ("Could not save solution: {0}", file), ex);
+ throw;
+ } finally {
+ monitor.EndTask ();
+ }
}
async Task WriteFileInternal (string file, string sourceFile, Solution solution, bool saveProjects, ProgressMonitor monitor)
@@ -91,7 +89,7 @@ namespace MonoDevelop.Projects.MSBuild
try {
monitor.BeginStep ();
item.SavingSolution = true;
- await item.SaveAsync (monitor);
+ await item.SaveAsync (monitor).ConfigureAwait (false);
} finally {
item.SavingSolution = false;
}
@@ -377,21 +375,19 @@ namespace MonoDevelop.Projects.MSBuild
try {
monitor.BeginTask (string.Format (GettextCatalog.GetString ("Loading solution: {0}"), fileName), 1);
monitor.BeginStep ();
- await sol.OnBeginLoad ();
+ await sol.OnBeginLoad ().ConfigureAwait (false);
var projectLoadMonitor = monitor as ProjectLoadProgressMonitor;
if (projectLoadMonitor != null)
projectLoadMonitor.CurrentSolution = sol;
- await Task.Run (() => {
- sol.ReadSolution (monitor);
- });
+ sol.ReadSolution (monitor);
} catch (Exception ex) {
monitor.ReportError (GettextCatalog.GetString ("Could not load solution: {0}", fileName), ex);
- await sol.OnEndLoad ();
+ await sol.OnEndLoad ().ConfigureAwait (false);
sol.NotifyItemReady ();
monitor.EndTask ();
throw;
}
- await sol.OnEndLoad ();
+ await sol.OnEndLoad ().ConfigureAwait (false);
sol.NotifyItemReady ();
monitor.EndTask ();
return sol;
@@ -533,7 +529,7 @@ namespace MonoDevelop.Projects.MSBuild
}
}
monitor.Step (1);
- });
+ }, TaskScheduler.Default);
loadTasks.Add (ft);
// Limit the number of concurrent tasks. Por solutions with many projects, spawning one thread per
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/CompiledAssemblyProject.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/CompiledAssemblyProject.cs
index ffaaef930f..4bb348eddc 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/CompiledAssemblyProject.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/CompiledAssemblyProject.cs
@@ -215,11 +215,9 @@ namespace MonoDevelop.Projects
public override Task<SolutionItem> LoadSolutionItem (ProgressMonitor monitor, SolutionLoadContext ctx, string fileName, MSBuildFileFormat expectedFormat, string typeGuid, string itemGuid)
{
- return Task<SolutionItem>.Factory.StartNew (delegate {
- CompiledAssemblyProject p = new CompiledAssemblyProject ();
- p.LoadFrom (fileName);
- return p;
- });
+ CompiledAssemblyProject p = new CompiledAssemblyProject ();
+ p.LoadFrom (fileName);
+ return Task.FromResult<SolutionItem> (p);
}
}
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/MSBuildSerializationExtension.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/MSBuildSerializationExtension.cs
index f5b1f1922c..8172ed8212 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/MSBuildSerializationExtension.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/MSBuildSerializationExtension.cs
@@ -41,26 +41,22 @@ namespace MonoDevelop.Projects
return false;
}
- public override Task<SolutionItem> LoadSolutionItem (ProgressMonitor monitor, SolutionLoadContext ctx, string fileName, MSBuildFileFormat expectedFormat, string typeGuid, string itemGuid)
+ public override async Task<SolutionItem> LoadSolutionItem (ProgressMonitor monitor, SolutionLoadContext ctx, string fileName, MSBuildFileFormat expectedFormat, string typeGuid, string itemGuid)
{
- return Task.Run (() => {
- foreach (var f in MSBuildFileFormat.GetSupportedFormats ()) {
- if (f.CanReadFile (fileName, typeof(SolutionItem)))
- return MSBuildProjectService.LoadItem (monitor, fileName, f, typeGuid, itemGuid, ctx);
- }
- throw new NotSupportedException ();
- });
+ foreach (var f in MSBuildFileFormat.GetSupportedFormats ()) {
+ if (f.CanReadFile (fileName, typeof(SolutionItem)))
+ return await MSBuildProjectService.LoadItem (monitor, fileName, f, typeGuid, itemGuid, ctx).ConfigureAwait (false);
+ }
+ throw new NotSupportedException ();
}
- public override Task<WorkspaceItem> LoadWorkspaceItem (ProgressMonitor monitor, string fileName)
+ public override async Task<WorkspaceItem> LoadWorkspaceItem (ProgressMonitor monitor, string fileName)
{
- return Task.Run (async () => {
- foreach (var f in MSBuildFileFormat.GetSupportedFormats ()) {
- if (f.CanReadFile (fileName, typeof (WorkspaceItem)))
- return (WorkspaceItem)await f.ReadFile (fileName, typeof (WorkspaceItem), monitor).ConfigureAwait (false);
- }
- throw new NotSupportedException ();
- });
+ foreach (var f in MSBuildFileFormat.GetSupportedFormats ()) {
+ if (f.CanReadFile (fileName, typeof (WorkspaceItem)))
+ return (WorkspaceItem)await f.ReadFile (fileName, typeof (WorkspaceItem), monitor).ConfigureAwait (false);
+ }
+ throw new NotSupportedException ();
}
}
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs
index 3df66730cc..a8a7c72dd0 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs
@@ -415,9 +415,7 @@ namespace MonoDevelop.Projects
protected override Task OnLoad (ProgressMonitor monitor)
{
- return Task.Run (async delegate {
- await LoadAsync (monitor);
- });
+ return LoadAsync (monitor);
}
async Task LoadAsync (ProgressMonitor monitor)
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectService.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectService.cs
index 7997a72146..4b57332e0d 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectService.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/ProjectService.cs
@@ -54,7 +54,7 @@ namespace MonoDevelop.Projects
TargetFramework defaultTargetFramework;
string defaultPlatformTarget = "anycpu";
- static readonly TargetFrameworkMoniker DefaultTargetFrameworkId = TargetFrameworkMoniker.NET_4_7;
+ static readonly TargetFrameworkMoniker DefaultTargetFrameworkId = TargetFrameworkMoniker.NET_4_7_2;
public const string BuildTarget = "Build";
public const string CleanTarget = "Clean";
@@ -123,7 +123,7 @@ namespace MonoDevelop.Projects
var r = GetObjectReaderForFile (file, typeof(SolutionItem));
if (r == null)
throw new UnknownSolutionItemTypeException ();
- SolutionItem loadedItem = await r.LoadSolutionItem (monitor, ctx, file, format, typeGuid, itemGuid);
+ SolutionItem loadedItem = await Task.Run (() => r.LoadSolutionItem (monitor, ctx, file, format, typeGuid, itemGuid));
if (loadedItem != null) {
loadedItem.NeedsReload = false;
UpdateReadSolutionItemMetadata (metadata, loadedItem);
@@ -216,7 +216,7 @@ namespace MonoDevelop.Projects
var r = GetObjectReaderForFile (file, typeof(WorkspaceItem));
if (r == null)
throw new InvalidOperationException ("Invalid file format: " + file);
- WorkspaceItem item = await r.LoadWorkspaceItem (monitor, fullpath);
+ WorkspaceItem item = await Task.Run (() => r.LoadWorkspaceItem (monitor, fullpath));
if (item != null)
item.NeedsReload = false;
else
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SdkProjectExtension.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SdkProjectExtension.cs
index e7514fe8f1..195b692af1 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SdkProjectExtension.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SdkProjectExtension.cs
@@ -38,6 +38,8 @@ namespace MonoDevelop.Projects
[ExportProjectModelExtension]
public class SdkProjectExtension : DotNetProjectExtension
{
+ HashSet<(string Name, string Include)> evaluatedItems;
+
MSBuildSdkProject msbuildSdkProject = new MSBuildSdkProject ();
string[] cachedBuildActions;
@@ -53,8 +55,7 @@ namespace MonoDevelop.Projects
/// </summary>
internal static bool FileShouldBeHidden (FilePath file)
{
- return file.HasExtension (".userprefs") ||
- file.FileName == ".DS_Store";
+ return file.HasExtension (".userprefs") || file.HasFileName (".DS_Store");
}
public IEnumerable<string> TargetFrameworks {
@@ -109,6 +110,7 @@ namespace MonoDevelop.Projects
Project.UseFileWatcher = true;
cachedBuildActions = null;
+ evaluatedItems = null;
}
internal protected override void OnWriteProject (ProgressMonitor monitor, MSBuildProject msproject)
@@ -129,36 +131,15 @@ namespace MonoDevelop.Projects
{
var sourceFiles = await base.OnGetSourceFiles (monitor, configuration);
- return AddMissingProjectFiles (sourceFiles, configuration);
- }
-
- ImmutableArray<ProjectFile> AddMissingProjectFiles (ImmutableArray<ProjectFile> files, ConfigurationSelector configuration)
- {
- ImmutableArray<ProjectFile>.Builder missingFiles = null;
- foreach (ProjectFile existingFile in Project.Files.Where (file => file.BuildAction == BuildAction.Compile)) {
- if (!files.Any (file => file.FilePath == existingFile.FilePath)) {
- if (missingFiles == null)
- missingFiles = ImmutableArray.CreateBuilder<ProjectFile> ();
- missingFiles.Add (existingFile);
- }
- }
-
// Ensure generated assembly info file is available to type system. It is created in the obj
// directory and is excluded from the project with a wildcard exclude but the type system needs it to
// ensure the project's assembly information is correct to prevent diagnostic errors.
var generatedAssemblyInfoFile = GetGeneratedAssemblyInfoFile (configuration);
if (generatedAssemblyInfoFile != null) {
- if (missingFiles == null)
- missingFiles = ImmutableArray.CreateBuilder<ProjectFile> ();
- missingFiles.Add (generatedAssemblyInfoFile);
+ return sourceFiles.Add (generatedAssemblyInfoFile);
}
- if (missingFiles == null)
- return files;
-
- missingFiles.Capacity = missingFiles.Count + files.Length;
- missingFiles.AddRange (files);
- return missingFiles.MoveToImmutable ();
+ return sourceFiles;
}
ProjectFile GetGeneratedAssemblyInfoFile (ConfigurationSelector configuration)
@@ -185,14 +166,23 @@ namespace MonoDevelop.Projects
// project file is being saved.
}
- bool IsFSharpSdkProject ()
+ bool? isFSharpSdkProject;
+ bool IsLegacyFSharpSdkProject ()
{
- var sdks = Project.MSBuildProject.GetReferencedSDKs ();
- for (var i = 0; i < sdks.Length; i++) {
- if (sdks [i].Contains ("FSharp"))
- return true;
+ if (isFSharpSdkProject is null) {
+ isFSharpSdkProject = ContainsFSharpSdk (Project.MSBuildProject.GetReferencedSDKs ());
+ }
+
+ return isFSharpSdkProject.Value;
+
+ static bool ContainsFSharpSdk (string[] sdks)
+ {
+ for (var i = 0; i < sdks.Length; i++) {
+ if (sdks [i].Contains ("FSharp"))
+ return true;
+ }
+ return false;
}
- return false;
}
internal protected override bool OnGetSupportsImportedItem (IMSBuildItemEvaluated buildItem)
@@ -200,7 +190,7 @@ namespace MonoDevelop.Projects
if (!IsBuildActionSupported (buildItem.Name))
return false;
- if (IsFSharpSdkProject ()) {
+ if (IsLegacyFSharpSdkProject ()) {
// Ignore imported F# files. F# files are defined in the main project.
// This prevents duplicate F# files when a new project is first created.
if (buildItem.Include.EndsWith (".fs", StringComparison.OrdinalIgnoreCase))
@@ -210,11 +200,15 @@ namespace MonoDevelop.Projects
if (IsFromSharedProject (buildItem))
return false;
- // HACK: Remove any imported items that are not in the EvaluatedItems
- // This may happen if a condition excludes the item. All items passed to the
- // OnGetSupportsImportedItem are from the EvaluatedItemsIgnoringCondition
- return Project.MSBuildProject.EvaluatedItems
- .Any (item => item.IsImported && item.Name == buildItem.Name && item.Include == buildItem.Include);
+ evaluatedItems ??= CreateEvaluatedItemsCache (Project.MSBuildProject);
+ return evaluatedItems.Contains ((buildItem.Name, buildItem.Include));
+
+ static HashSet<(string, string)> CreateEvaluatedItemsCache (MSBuildProject project)
+ => new HashSet<(string Name, string Include)> (
+ project.EvaluatedItems
+ .Where (x => x.IsImported)
+ .Select (x => (x.Name, x.Include))
+ );
}
/// <summary>
@@ -262,6 +256,8 @@ namespace MonoDevelop.Projects
internal protected override async Task OnReevaluateProject (ProgressMonitor monitor)
{
await base.OnReevaluateProject (monitor);
+
+ isFSharpSdkProject = null;
UpdateHiddenFiles (Project.Files);
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SdkProjectReader.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SdkProjectReader.cs
index 6765edf762..2d42a1576f 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SdkProjectReader.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SdkProjectReader.cs
@@ -96,15 +96,13 @@ namespace MonoDevelop.Projects
return null;
}
- public override Task<SolutionItem> LoadSolutionItem (ProgressMonitor monitor, SolutionLoadContext ctx, string fileName, MSBuildFileFormat expectedFormat, string typeGuid, string itemGuid)
+ public override async Task<SolutionItem> LoadSolutionItem (ProgressMonitor monitor, SolutionLoadContext ctx, string fileName, MSBuildFileFormat expectedFormat, string typeGuid, string itemGuid)
{
- return Task.Run (() => {
- if (CanRead (fileName, typeof (SolutionItem))) {
- return MSBuildProjectService.LoadItem (monitor, fileName, MSBuildFileFormat.VS2012, typeGuid, itemGuid, ctx);
- }
+ if (CanRead (fileName, typeof (SolutionItem))) {
+ return await MSBuildProjectService.LoadItem (monitor, fileName, MSBuildFileFormat.VS2012, typeGuid, itemGuid, ctx);
+ }
- throw new NotSupportedException ();
- });
+ throw new NotSupportedException ();
}
}
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItem.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItem.cs
index 8dce5f1327..2a9c0c96e3 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItem.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/SolutionItem.cs
@@ -460,7 +460,7 @@ namespace MonoDevelop.Projects
if (ItemExtension.OnCheckHasSolutionData () && !SavingSolution && ParentSolution != null) {
// The project has data that has to be saved in the solution, but the solution is not being saved. Do it now.
- await SolutionFormat.SlnFileFormat.WriteFile (ParentSolution.FileName, ParentSolution, false, monitor);
+ await Task.Run (() => SolutionFormat.SlnFileFormat.WriteFile (ParentSolution.FileName, ParentSolution, false, monitor));
ParentSolution.NeedsReload = false;
}
}
@@ -1232,12 +1232,12 @@ namespace MonoDevelop.Projects
protected virtual Task OnLoad (ProgressMonitor monitor)
{
- return Task.FromResult (0);
+ return Task.CompletedTask;
}
protected internal virtual Task OnSave (ProgressMonitor monitor)
{
- return Task.FromResult (0);
+ return Task.CompletedTask;
}
public FilePath GetAbsoluteChildPath (FilePath relPath)
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/WorkspaceItem.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/WorkspaceItem.cs
index 639c96b249..7b4dec5b75 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/WorkspaceItem.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/WorkspaceItem.cs
@@ -276,7 +276,7 @@ namespace MonoDevelop.Projects
FileService.RequestFileEdit (f);
try {
fileStatusTracker.BeginSave ();
- await ItemExtension.Save (monitor);
+ await Task.Run (() => ItemExtension.Save (monitor));
await OnSaveUserProperties (); // Call the virtual to avoid the lock
OnSaved (new WorkspaceItemEventArgs (this));
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/WorkspaceObjectReader.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/WorkspaceObjectReader.cs
index 9c0a453544..b205558a76 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/WorkspaceObjectReader.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/WorkspaceObjectReader.cs
@@ -41,12 +41,12 @@ namespace MonoDevelop.Projects
public virtual Task<SolutionItem> LoadSolutionItem (ProgressMonitor monitor, SolutionLoadContext ctx, string fileName, MSBuildFileFormat expectedFormat, string typeGuid, string itemGuid)
{
- throw new NotSupportedException ();
+ return Task.FromException<SolutionItem> (new NotSupportedException ());
}
public virtual Task<WorkspaceItem> LoadWorkspaceItem (ProgressMonitor monitor, string fileName)
{
- throw new NotSupportedException ();
+ return Task.FromException<WorkspaceItem> (new NotSupportedException ());
}
}
diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/WorkspaceSerializationExtension.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/WorkspaceSerializationExtension.cs
index f96243af37..7e4c748ab5 100644
--- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/WorkspaceSerializationExtension.cs
+++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/WorkspaceSerializationExtension.cs
@@ -45,13 +45,11 @@ namespace MonoDevelop.Projects
return false;
}
- public override Task<WorkspaceItem> LoadWorkspaceItem (ProgressMonitor monitor, string fileName)
+ public override async Task<WorkspaceItem> LoadWorkspaceItem (ProgressMonitor monitor, string fileName)
{
- return Task.Run (async () => {
- var workspaceItem = ReadWorkspaceItemFile (fileName, monitor);
- await workspaceItem.LoadUserProperties ().ConfigureAwait (false);
- return workspaceItem;
- });
+ var workspaceItem = ReadWorkspaceItemFile (fileName, monitor);
+ await workspaceItem.LoadUserProperties ().ConfigureAwait (false);
+ return workspaceItem;
}
WorkspaceItem ReadWorkspaceItemFile (FilePath fileName, ProgressMonitor monitor)
diff --git a/main/src/core/MonoDevelop.Ide/ExtensionModel/Commands.addin.xml b/main/src/core/MonoDevelop.Ide/ExtensionModel/Commands.addin.xml
index 70c27e8047..a08baa0058 100644
--- a/main/src/core/MonoDevelop.Ide/ExtensionModel/Commands.addin.xml
+++ b/main/src/core/MonoDevelop.Ide/ExtensionModel/Commands.addin.xml
@@ -543,6 +543,16 @@
defaultHandler = "MonoDevelop.Ide.Commands.ReopenClosedTabHandler"
_label = "Reopen Closed Tab"
_description = "Opens the last tab that has been closed"/>
+ <Command id = "MonoDevelop.Ide.Commands.FileTabCommands.CloseAllExceptPinned"
+ defaultHandler = "MonoDevelop.Ide.Commands.CloseAllExceptPinnedHandler"
+ _label = "Close All Except _Pinned"
+ _description = "Close all files except pinned"
+ macShortcut = "Meta|Shift|P" />
+ <Command id = "MonoDevelop.Ide.Commands.FileTabCommands.PinTab"
+ defaultHandler = "MonoDevelop.Ide.Commands.PinTabHandler"
+ _label = "_Pin Tab"
+ _description = "Pin/Unpin current Tab selected"
+ macShortcut = "Meta|Alt|P" />
</Category>
<!-- ViewCommands -->
@@ -935,7 +945,7 @@
_label = "Find Next Like Selection"
_description = "Search forwards for the selected text"
shortcut = "Control|F3"
- macShortcut = "Meta|E Meta|F3" />
+ macShortcut = "Meta|F3" />
<Command id = "MonoDevelop.Ide.Commands.SearchCommands.FindPreviousSelection"
_label = "Find Previous Like Selection"
_description = "Search backwards for the selected text"
@@ -1012,10 +1022,11 @@
shortcut = "Control|I"
macShortcut = "Meta|L" />
<Command id = "MonoDevelop.Ide.Commands.SearchCommands.UseSelectionForFind"
- _label = "Find Like Selection"
- _description = "Uses the current selection as find string"/>
+ _label = "Use Selection for Find"
+ _description = "Uses the current selection as find string"
+ macShortcut = "Meta|E" />
<Command id = "MonoDevelop.Ide.Commands.SearchCommands.UseSelectionForReplace"
- _label = "Replace Like Selection"
+ _label = "Use Selection for Replace"
_description = "Uses the current selection as replace string"/>
</Category>
diff --git a/main/src/core/MonoDevelop.Ide/ExtensionModel/MainMenu.addin.xml b/main/src/core/MonoDevelop.Ide/ExtensionModel/MainMenu.addin.xml
index feb4dea335..e9d314c67c 100644
--- a/main/src/core/MonoDevelop.Ide/ExtensionModel/MainMenu.addin.xml
+++ b/main/src/core/MonoDevelop.Ide/ExtensionModel/MainMenu.addin.xml
@@ -157,7 +157,7 @@
<CommandItem id = "MonoDevelop.Ide.Commands.SearchCommands.FindPrevious" />
<CommandItem id = "MonoDevelop.Ide.Commands.SearchCommands.FindNext" />
<CommandItem id = "MonoDevelop.Ide.Commands.SearchCommands.FindNextSelection" />
-
+ <CommandItem id = "MonoDevelop.Ide.Commands.SearchCommands.UseSelectionForFind" />
<SeparatorItem id = "SearchSeparator2" />
<CommandItem id = "MonoDevelop.Ide.Commands.SearchCommands.FindInFiles" />
<CommandItem id = "MonoDevelop.Ide.Commands.SearchCommands.ReplaceInFiles" />
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 70690194fb..c25b4e1b7c 100644
--- a/main/src/core/MonoDevelop.Ide/ExtensionModel/MonoDevelop.Ide.addin.xml
+++ b/main/src/core/MonoDevelop.Ide/ExtensionModel/MonoDevelop.Ide.addin.xml
@@ -348,8 +348,10 @@
<Extension path = "/MonoDevelop/Ide/ContextMenu/DocumentTab">
<CommandItem id = "MonoDevelop.Ide.Commands.FileCommands.CloseFile" />
<CommandItem id = "MonoDevelop.Ide.Commands.FileTabCommands.CloseAll" />
+ <CommandItem id = "MonoDevelop.Ide.Commands.FileTabCommands.CloseAllExceptPinned" />
<CommandItem id = "MonoDevelop.Ide.Commands.FileTabCommands.CloseAllButThis" />
<CommandItem id = "MonoDevelop.Ide.Commands.FileTabCommands.CloseAllToTheRight" />
+ <CommandItem id = "MonoDevelop.Ide.Commands.FileTabCommands.PinTab" />
<CommandItem id = "MonoDevelop.Ide.Commands.FileTabCommands.ReopenClosedTab" />
<SeparatorItem id = "CloseSeparator" />
<CommandItem id = "MonoDevelop.Ide.Commands.FileCommands.Save" />
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Commands/ActionCommand.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Commands/ActionCommand.cs
index fd92edcc49..4f7753ace4 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Commands/ActionCommand.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Commands/ActionCommand.cs
@@ -109,15 +109,16 @@ namespace MonoDevelop.Components.Commands
info.Visible = false;
return;
}
- defaultHandler = (CommandHandler) Activator.CreateInstance (DefaultHandlerType);
+ defaultHandler = (CommandHandler)Activator.CreateInstance (DefaultHandlerType);
}
if (commandArray) {
info.ArrayInfo = new CommandArrayInfo (info);
defaultHandler.InternalUpdate (info.ArrayInfo);
- }
- else
+ } else
defaultHandler.InternalUpdate (info);
}
+
+ internal RuntimeAddin RuntimeAddin => defaultHandlerAddin;
}
}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Commands/CommandManager.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Commands/CommandManager.cs
index 326e5a8299..67aea3f5a5 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Commands/CommandManager.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Commands/CommandManager.cs
@@ -478,8 +478,14 @@ namespace MonoDevelop.Components.Commands
}
#endif
// Handle the GDK key via MD commanding
- if (ProcessKeyEventCore (ev))
- return true;
+ try {
+ if (ProcessKeyEventCore (ev)) {
+ return true;
+ }
+ } catch (Exception ex) {
+ LoggingService.LogInternalError ("Exception while parsing command", ex);
+ return false;
+ }
#if MAC
// Otherwise if we have a native first responder that is not the GdkQuartzView
@@ -547,6 +553,10 @@ namespace MonoDevelop.Components.Commands
return false;
}
+ if (commands == null) {
+ return false;
+ }
+
var toplevelFocus = IdeApp.Workbench.HasToplevelFocus;
var conflict = new List<Command> ();
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.DockNotebook/DockNotebook.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.DockNotebook/DockNotebook.cs
index b12ecad3fb..1697cba57a 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.DockNotebook/DockNotebook.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.DockNotebook/DockNotebook.cs
@@ -36,6 +36,7 @@ using MonoDevelop.Ide;
using MonoDevelop.Components.AtkCocoaHelper;
using MonoDevelop.Core;
using MonoDevelop.Ide.Gui.Shell;
+using System.Linq;
namespace MonoDevelop.Components.DockNotebook
{
@@ -136,6 +137,7 @@ namespace MonoDevelop.Components.DockNotebook
public event TabsReorderedHandler TabsReordered;
public event EventHandler<TabEventArgs> TabClosed;
+ public event EventHandler<TabEventArgs> TabPinned;
public event EventHandler<TabEventArgs> TabActivated;
public event EventHandler<TabEventArgs> PageAdded;
@@ -349,6 +351,8 @@ namespace MonoDevelop.Components.DockNotebook
PageAdded?.Invoke (this, new TabEventArgs { Tab = tab, });
+ tab.OnChangingPinned = OnTabPinned;
+
NotebookChanged?.Invoke (this, EventArgs.Empty);
return tab;
@@ -360,6 +364,24 @@ namespace MonoDevelop.Components.DockNotebook
((DockNotebookTab)pages [n]).Index = n;
}
+ void OnTabPinned (DockNotebookTab sender, bool value)
+ {
+ if (pages.Count == 1)
+ return;
+
+ var stickedPages = pages.Where (p => p.IsPinned);
+ var normalPages = pages.Where (p => !p.IsPinned);
+
+ if (value) {
+ if (stickedPages.Any ())
+ ReorderTab (sender, normalPages.MinValueOrDefault (s => s.Index) ?? stickedPages.MaxValueOrDefault (s => s.Index), false);
+ else
+ ReorderTab (sender, pages.FirstOrDefault (), false);
+ } else {
+ ReorderTab (sender, stickedPages.MaxValueOrDefault (s => s.Index) ?? normalPages.MinValueOrDefault (s => s.Index), false);
+ }
+ }
+
public DockNotebookTab GetTab (int n)
{
if (n < 0 || n >= pages.Count)
@@ -388,8 +410,11 @@ namespace MonoDevelop.Components.DockNotebook
NotebookChanged?.Invoke (this, EventArgs.Empty);
}
- internal void ReorderTab (DockNotebookTab tab, DockNotebookTab targetTab)
+ internal void ReorderTab (DockNotebookTab tab, DockNotebookTab targetTab, bool pinCheck = true)
{
+ if (pinCheck && tab.IsPinned != targetTab.IsPinned)
+ return;
+
if (tab == targetTab)
return;
int targetPos = targetTab.Index;
@@ -412,6 +437,12 @@ namespace MonoDevelop.Components.DockNotebook
TabClosed (this, new TabEventArgs () { Tab = tab });
}
+ internal void OnPinTab (DockNotebookTab tab)
+ {
+ if (TabPinned != null)
+ TabPinned (this, new TabEventArgs () { Tab = tab });
+ }
+
internal void OnActivateTab (DockNotebookTab tab)
{
if (TabActivated != 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 fbd6a1ed22..53c1b62205 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.DockNotebook/DockNotebookTab.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.DockNotebook/DockNotebookTab.cs
@@ -35,6 +35,9 @@ namespace MonoDevelop.Components.DockNotebook
{
class DockNotebookTab: IAnimatable, IDisposable
{
+ public System.Action<DockNotebookTab, bool> OnChangingPinned;
+ public System.Action<DockNotebookTab, bool> OnChangedPinned;
+
DockNotebook notebook;
readonly TabStrip strip;
@@ -47,6 +50,8 @@ namespace MonoDevelop.Components.DockNotebook
Xwt.Drawing.Image icon;
Widget content;
+ internal Cairo.Rectangle PinButtonActiveArea;
+
Gdk.Rectangle allocation;
internal Gdk.Rectangle Allocation {
get {
@@ -113,6 +118,19 @@ namespace MonoDevelop.Components.DockNotebook
public double DirtyStrength { get; set; }
+ bool isPinned;
+ public bool IsPinned {
+ get { return isPinned; }
+ set {
+ if (isPinned == value)
+ return;
+ OnChangingPinned?.Invoke (this, value);
+ isPinned = value;
+ strip.Update ();
+ OnChangedPinned?.Invoke (this, value);
+ }
+ }
+
void IAnimatable.BatchBegin () { }
void IAnimatable.BatchCommit () { QueueDraw (); }
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 7f7743b443..6f32941ec4 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.DockNotebook/TabStrip.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.DockNotebook/TabStrip.cs
@@ -37,6 +37,7 @@ using MonoDevelop.Components.Docking;
using MonoDevelop.Ide.Gui;
using MonoDevelop.Ide;
using System.Runtime.InteropServices;
+using MonoDevelop.Ide.Editor;
namespace MonoDevelop.Components.DockNotebook
{
@@ -49,6 +50,8 @@ namespace MonoDevelop.Components.DockNotebook
static Xwt.Drawing.Image tabbarBackImage = Xwt.Drawing.Image.FromResource ("tabbar-back.9.png");
static Xwt.Drawing.Image tabCloseImage = Xwt.Drawing.Image.FromResource ("tab-close-9.png");
static Xwt.Drawing.Image tabDirtyImage = Xwt.Drawing.Image.FromResource ("tab-dirty-9.png");
+ static Xwt.Drawing.Image tabPinnedImage = Xwt.Drawing.Image.FromResource ("tab-pinned-9.png");
+ static Xwt.Drawing.Image tabUnPinnedImage = Xwt.Drawing.Image.FromResource ("tab-unpinned-9.png");
HBox innerBox;
@@ -84,8 +87,11 @@ namespace MonoDevelop.Components.DockNotebook
static readonly int VerticalTextSize = 11;
const int TabSpacing = 0;
const int LeanWidth = 12;
+ const int ButtonSize = 14;
const double CloseButtonMarginRight = 0;
const double CloseButtonMarginBottom = -1.0;
+ const double PinButtonMarginRight = 0;
+ const double PinButtonMarginBottom = -1.0;
const int TextOffset = 1;
@@ -235,7 +241,7 @@ namespace MonoDevelop.Components.DockNotebook
tab.AccessibilityPressCloseButton += OnAccessibilityPressCloseButton;
tab.AccessibilityShowMenu += OnAccessibilityShowMenu;
}
- }
+ }
UpdateAccessibilityTabs ();
notebook.PageAdded += PageAddedHandler;
notebook.PageRemoved += PageRemovedHandler;
@@ -254,14 +260,14 @@ namespace MonoDevelop.Components.DockNotebook
void PageAddedHandler (object sender, TabEventArgs args)
{
- var tab = args.Tab;
+ var tab = args.Tab;
- if (tab.Accessible != null) {
+ if (tab.Accessible != null) {
Accessible.AddAccessibleElement (tab.Accessible);
- Accessible.AddAccessibleElement (tab.CloseButtonAccessible);
-
- tab.AccessibilityPressTab += OnAccessibilityPressTab;
- tab.AccessibilityPressCloseButton += OnAccessibilityPressCloseButton;
+ Accessible.AddAccessibleElement (tab.CloseButtonAccessible);
+
+ tab.AccessibilityPressTab += OnAccessibilityPressTab;
+ tab.AccessibilityPressCloseButton += OnAccessibilityPressCloseButton;
tab.AccessibilityShowMenu += OnAccessibilityShowMenu;
}
@@ -272,13 +278,13 @@ namespace MonoDevelop.Components.DockNotebook
void PageRemovedHandler (object sender, TabEventArgs args)
{
- var tab = args.Tab;
+ var tab = args.Tab;
+
+ if (tab.Accessible != null) {
+ tab.AccessibilityPressTab -= OnAccessibilityPressTab;
+ tab.AccessibilityPressCloseButton -= OnAccessibilityPressCloseButton;
+ tab.AccessibilityShowMenu -= OnAccessibilityShowMenu;
- if (tab.Accessible != null) {
- tab.AccessibilityPressTab -= OnAccessibilityPressTab;
- tab.AccessibilityPressCloseButton -= OnAccessibilityPressCloseButton;
- tab.AccessibilityShowMenu -= OnAccessibilityShowMenu;
-
Accessible.RemoveAccessibleElement (tab.Accessible);
Accessible.RemoveAccessibleElement (tab.CloseButtonAccessible);
}
@@ -290,11 +296,11 @@ namespace MonoDevelop.Components.DockNotebook
UpdateAccessibilityTabs ();
}
- void PageReorderedHandler (DockNotebookTab tab, int oldPlacement, int newPlacement)
+ void PageReorderedHandler (DockNotebookTab tab, int oldPlacement, int newPlacement)
{
QueueResize ();
- UpdateAccessibilityTabs ();
+ UpdateAccessibilityTabs ();
}
void UpdateAccessibilityTabs ()
@@ -553,6 +559,7 @@ namespace MonoDevelop.Components.DockNotebook
return base.OnMotionNotifyEvent (evnt);
}
+ bool overPinOnPress;
bool overCloseOnPress;
bool allowDoubleClick;
@@ -573,6 +580,13 @@ namespace MonoDevelop.Components.DockNotebook
}
overCloseOnPress = false;
+ // Don't select the tab if we are clicking the pin button
+ if (IsOverPinButton (t, (int)evnt.X, (int)evnt.Y)) {
+ overPinOnPress = true;
+ return true;
+ }
+ overPinOnPress = false;
+
if (evnt.Type == EventType.TwoButtonPress) {
if (allowDoubleClick) {
notebook.OnActivateTab (t);
@@ -604,15 +618,22 @@ namespace MonoDevelop.Components.DockNotebook
return base.OnButtonReleaseEvent (evnt);
}
- if (!draggingTab && overCloseOnPress) {
+ if (!draggingTab) {
var t = FindTab ((int)evnt.X, (int)evnt.Y);
- if (t != null && IsOverCloseButton (t, (int)evnt.X, (int)evnt.Y)) {
+ if (t != null && overCloseOnPress && IsOverCloseButton (t, (int)evnt.X, (int)evnt.Y)) {
notebook.OnCloseTab (t);
allowDoubleClick = false;
return true;
+ } else if (t != null && overPinOnPress && IsOverPinButton (t, (int)evnt.X, (int)evnt.Y)) {
+ t.IsPinned = !t.IsPinned;
+ notebook.OnPinTab (t);
+ allowDoubleClick = false;
+ QueueDraw ();
+ return true;
}
}
overCloseOnPress = false;
+ overPinOnPress = false;
allowDoubleClick = true;
if (dragX != 0)
this.Animate ("EndDrag",
@@ -935,6 +956,7 @@ namespace MonoDevelop.Components.DockNotebook
// Cancel drag operations and animations
buttonPressedOnTab = false;
overCloseOnPress = false;
+ overPinOnPress = false;
allowDoubleClick = true;
draggingTab = false;
dragX = 0;
@@ -966,6 +988,11 @@ namespace MonoDevelop.Components.DockNotebook
return tab != null && tab.CloseButtonActiveArea.Contains (x, y);
}
+ static bool IsOverPinButton (DockNotebookTab tab, int x, int y)
+ {
+ return tab != null && tab.PinButtonActiveArea.Contains (x, y);
+ }
+
public void Update ()
{
if (!tracker.Hovered) {
@@ -1145,7 +1172,7 @@ namespace MonoDevelop.Components.DockNotebook
leftPadding = (leftPadding * Math.Min (1.0, Math.Max (0.5, (tabBounds.Width - 30) / 70.0)));
double bottomPadding = active ? TabActivePadding.Bottom : TabPadding.Bottom;
- DrawTabBackground (this, ctx, allocation, tabBounds.Width, tabBounds.X, active);
+ DrawTabBackground (this, ctx, allocation, tabBounds.Width, tabBounds.X, active, tab.IsPinned);
ctx.LineWidth = 1;
ctx.NewPath ();
@@ -1158,9 +1185,17 @@ namespace MonoDevelop.Components.DockNotebook
tab.CloseButtonActiveArea = closeButtonAlloation.Inflate (2, 2);
+ var spinButtonAllocation = new Cairo.Rectangle (closeButtonAlloation.X - rightPadding - PinButtonMarginRight,
+ closeButtonAlloation.Y,
+ tabPinnedImage.Width, tabPinnedImage.Height);
+
+ tab.PinButtonActiveArea = spinButtonAllocation.Inflate (2, 2);
+
bool closeButtonHovered = tracker.Hovered && tab.CloseButtonActiveArea.Contains (tracker.MousePosition);
+ bool pinButtonHovered = tracker.Hovered && tab.PinButtonActiveArea.Contains (tracker.MousePosition);
bool tabHovered = tracker.Hovered && tab.Allocation.Contains (tracker.MousePosition);
- bool drawCloseButton = active || tabHovered || focused;
+ bool drawCloseButton = tab.IsPinned || (active || tabHovered || focused);
+ bool drawPinButton = tab.IsPinned || tabHovered;
if (!closeButtonHovered && tab.DirtyStrength > 0.5) {
ctx.DrawImage (this, tabDirtyImage, closeButtonAlloation.X, closeButtonAlloation.Y);
@@ -1170,11 +1205,17 @@ namespace MonoDevelop.Components.DockNotebook
if (drawCloseButton)
ctx.DrawImage (this, tabCloseImage.WithAlpha ((closeButtonHovered ? 1.0 : 0.5) * tab.Opacity), closeButtonAlloation.X, closeButtonAlloation.Y);
+ if (drawPinButton)
+ ctx.DrawImage (this, (tab.IsPinned ? tabPinnedImage : tabUnPinnedImage).WithAlpha ((pinButtonHovered ? 1.0 : 0.5) * tab.Opacity), spinButtonAllocation.X, spinButtonAllocation.Y);
+
// Render Text
double tw = tabBounds.Width - (leftPadding + rightPadding);
if (drawCloseButton || tab.DirtyStrength > 0.5)
tw -= closeButtonAlloation.Width / 2;
+ if (drawPinButton || tab.DirtyStrength > 0.5)
+ tw -= spinButtonAllocation.Width / 2 + rightPadding;
+
double tx = tabBounds.X + leftPadding;
var baseline = la.GetLine (0).Layout.GetPixelBaseline ();
double ty = tabBounds.Height - bottomPadding - baseline;
@@ -1199,11 +1240,11 @@ namespace MonoDevelop.Components.DockNotebook
ctx.SetSource (lg);
Pango.CairoHelper.ShowLayout (ctx, la.GetLine (0).Layout);
}
- }
+ }
la.Dispose ();
}
- static void DrawTabBackground (Widget widget, Context ctx, Gdk.Rectangle allocation, int contentWidth, int px, bool active = true)
+ static void DrawTabBackground (Widget widget, Context ctx, Gdk.Rectangle allocation, int contentWidth, int px, bool active = true, bool isPinned = false)
{
int lean = Math.Min (LeanWidth, contentWidth / 2);
int halfLean = lean / 2;
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockBarItem.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockBarItem.cs
index 1a54f5e800..9556f15db2 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockBarItem.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockBarItem.cs
@@ -39,6 +39,7 @@ using Animations = Xwt.Motion.AnimationExtensions;
using MonoDevelop.Core;
using MonoDevelop.Ide.Fonts;
using MonoDevelop.Ide;
+using Gdk;
namespace MonoDevelop.Components.Docking
{
@@ -369,6 +370,12 @@ namespace MonoDevelop.Components.Docking
if (autoShowTimeout == uint.MaxValue) {
autoShowTimeout = GLib.Timeout.Add (bar.Frame.AutoShowDelay, delegate {
autoShowTimeout = uint.MaxValue;
+
+ // Check is mouse over - it may be that the LeaveEvent wasn't fired becaues of a gtk bug. So we double check as a work around.
+ GetPointer (out int x, out int y);
+ bool isMouseOver = x >= 0 && y >= 0 && x <= Allocation.Width && y <= Allocation.Height;
+ if (!isMouseOver)
+ return false;
AutoShow ();
return false;
});
@@ -430,11 +437,23 @@ namespace MonoDevelop.Components.Docking
protected override bool OnEnterNotifyEvent (Gdk.EventCrossing evnt)
{
+ ScheduleAutoShowOnHover();
+ return base.OnEnterNotifyEvent (evnt);
+ }
+
+ protected override bool OnMotionNotifyEvent (EventMotion evnt)
+ {
+ ScheduleAutoHide (true);
+ ScheduleAutoShowOnHover ();
+ return base.OnMotionNotifyEvent (evnt);
+ }
+
+ void ScheduleAutoShowOnHover ()
+ {
if (bar.HoverActivationEnabled && autoShowFrame == null) {
ScheduleAutoShow ();
QueueDraw ();
}
- return base.OnEnterNotifyEvent (evnt);
}
void OnPerformPress (object sender, EventArgs args)
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.MainToolbar/CommandSearchCategory.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.MainToolbar/CommandSearchCategory.cs
index 9084175639..ab8d215712 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.MainToolbar/CommandSearchCategory.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.MainToolbar/CommandSearchCategory.cs
@@ -26,27 +26,27 @@
using System;
using System.Threading;
using System.Threading.Tasks;
-using MonoDevelop.Core;
+using System.Linq;
using System.Collections.Generic;
-using MonoDevelop.Core.Instrumentation;
-using MonoDevelop.Projects;
-using MonoDevelop.Ide.Gui;
-using MonoDevelop.Ide;
-using ICSharpCode.NRefactory.TypeSystem;
-using MonoDevelop.Ide.TypeSystem;
+using MonoDevelop.Core;
using MonoDevelop.Core.Text;
-using Gtk;
-using System.Linq;
using MonoDevelop.Components.Commands;
+using MonoDevelop.Ide;
namespace MonoDevelop.Components.MainToolbar
{
class CommandSearchCategory : SearchCategory
{
static readonly List<Tuple<Command, string>> allCommands;
+ static readonly Mono.Addins.RuntimeAddin currentRuntimeAddin;
static CommandSearchCategory ()
{
+ // The AddinManager is not thread safe, so we need to make sure we're
+ // calling from the main thread.
+ Runtime.AssertMainThread ();
+ currentRuntimeAddin = Mono.Addins.AddinManager.CurrentAddin;
+
var hiddenCategory = GettextCatalog.GetString ("Hidden");
allCommands = IdeApp.CommandService.GetCommands ()
.Where (cmd => (cmd as ActionCommand)?.CommandArray != true && cmd.Category != hiddenCategory)
@@ -58,7 +58,7 @@ namespace MonoDevelop.Components.MainToolbar
{
}
- string[] validTags = new [] { "cmd", "command", "c" };
+ readonly string[] validTags = { "cmd", "command", "c" };
public override string [] Tags {
get {
@@ -86,10 +86,12 @@ namespace MonoDevelop.Components.MainToolbar
break;
var cmd = cmdTuple.Item1;
var matchString = cmdTuple.Item2;
- int rank;
- if (matcher.CalcMatchRank (matchString, out rank))
+ if (matcher.CalcMatchRank (matchString, out var rank)) {
+ if ((cmd as ActionCommand)?.RuntimeAddin == currentRuntimeAddin)
+ rank += 1; // we prefer commands comming from the addin
searchResultCallback.ReportResult (new CommandResult (cmd, null, route, pattern.Pattern, matchString, rank));
+ }
}
} catch (OperationCanceledException) {
}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/GtkWorkarounds.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/GtkWorkarounds.cs
index 0a25ce6227..0312ddd9bf 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/GtkWorkarounds.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/GtkWorkarounds.cs
@@ -45,20 +45,10 @@ using System.Windows.Input;
namespace MonoDevelop.Components
{
- public static class GtkWorkarounds
+ public static partial class GtkWorkarounds
{
- const string LIBOBJC ="/usr/lib/libobjc.dylib";
const string USER32DLL = "User32.dll";
- [DllImport (LIBOBJC, EntryPoint = "sel_registerName")]
- static extern IntPtr sel_registerName (string selector);
-
- [DllImport (LIBOBJC, EntryPoint = "objc_getClass")]
- static extern IntPtr objc_getClass (string klass);
-
- [DllImport (LIBOBJC, EntryPoint = "objc_msgSend")]
- static extern IntPtr objc_msgSend_IntPtr (IntPtr klass, IntPtr selector);
-
[DllImport (LIBOBJC, EntryPoint = "objc_msgSend")]
static extern void objc_msgSend_void_bool (IntPtr klass, IntPtr selector, bool arg);
@@ -83,9 +73,6 @@ namespace MonoDevelop.Components
[DllImport (LIBOBJC, EntryPoint = "objc_msgSend_stret")]
static extern void objc_msgSend_CGRect64 (out CGRect64 rect, IntPtr klass, IntPtr selector);
- [DllImport (LIBOBJC, EntryPoint = "objc_msgSend")]
- static extern void objc_msgSend_NSInt64_NSInt32 (IntPtr klass, IntPtr selector, int arg);
-
[DllImport (PangoUtil.LIBQUARTZ)]
static extern IntPtr gdk_quartz_window_get_nswindow (IntPtr window);
@@ -109,7 +96,7 @@ namespace MonoDevelop.Components
static IntPtr cls_NSScreen;
static IntPtr sel_screens, sel_objectEnumerator, sel_nextObject, sel_frame, sel_visibleFrame,
- sel_requestUserAttention, sel_setHasShadow, sel_invalidateShadow, sel_terminate;
+ sel_requestUserAttention, sel_setHasShadow, sel_invalidateShadow;
static IntPtr sharedApp;
static IntPtr cls_NSEvent;
static IntPtr sel_modifierFlags;
@@ -174,21 +161,9 @@ namespace MonoDevelop.Components
sel_modifierFlags = sel_registerName ("modifierFlags");
sel_setHasShadow = sel_registerName ("setHasShadow:");
sel_invalidateShadow = sel_registerName ("invalidateShadow");
- sel_terminate = sel_registerName ("terminate:");
sharedApp = objc_msgSend_IntPtr (objc_getClass ("NSApplication"), sel_registerName ("sharedApplication"));
}
- static void MacTerminate ()
- {
- objc_msgSend_NSInt64_NSInt32 (sharedApp, sel_terminate, 0);
- }
-
- public static void Terminate ()
- {
- if (Platform.IsMac)
- MacTerminate ();
- }
-
static Gdk.Rectangle MacGetUsableMonitorGeometry (Gdk.Screen screen, int monitor)
{
IntPtr array = objc_msgSend_IntPtr (cls_NSScreen, sel_screens);
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Mac/NSViewExtensions.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Mac/NSViewExtensions.cs
index 9d7e89b4cc..be3192f786 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Mac/NSViewExtensions.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Mac/NSViewExtensions.cs
@@ -22,6 +22,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+#if MAC
using System;
using System.Runtime.InteropServices;
using Foundation;
@@ -71,10 +72,12 @@ namespace AppKit
}
}
- static readonly IntPtr sel_sortSubviewsUsingFunction_context_ = Selector.GetHandle ("sortSubviewsUsingFunction:context:");
+ static readonly IntPtr sel_sortSubviewsUsingFunction_context_ =
+ Selector.GetHandle ("sortSubviewsUsingFunction:context:");
static void SortSubviews (NSView view, IntPtr function_pointer, IntPtr context)
{
MonoDevelop.Components.Mac.Messaging.void_objc_msgSend_IntPtr_IntPtr (view.Handle, sel_sortSubviewsUsingFunction_context_, function_pointer, context);
}
}
}
+#endif
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Shared/GtkWorkarounds.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Shared/GtkWorkarounds.cs
new file mode 100644
index 0000000000..9ae2811d82
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Shared/GtkWorkarounds.cs
@@ -0,0 +1,65 @@
+//
+// GtkWorkarounds.cs
+//
+// Author:
+// iain <iaholmes@microsoft.com>
+//
+// Copyright (c) 2019
+//
+// 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.Runtime.InteropServices;
+
+using MonoDevelop.Core;
+
+// This partial of the GtkWorkarounds class is shared between MonoDevelop.Ide.dll and md-tool.exe
+// Anything that only needs to be in MonoDevelop.Ide should go into the other part.
+namespace MonoDevelop.Components
+{
+ public static partial class GtkWorkarounds
+ {
+ const string LIBOBJC = "/usr/lib/libobjc.dylib";
+
+ [DllImport (LIBOBJC, EntryPoint = "objc_msgSend")]
+ static extern IntPtr objc_msgSend_IntPtr (IntPtr klass, IntPtr selector);
+
+ [DllImport (LIBOBJC, EntryPoint = "sel_registerName")]
+ static extern IntPtr sel_registerName (string selector);
+
+ [DllImport (LIBOBJC, EntryPoint = "objc_getClass")]
+ static extern IntPtr objc_getClass (string klass);
+
+ [DllImport (LIBOBJC, EntryPoint = "objc_msgSend")]
+ static extern void objc_msgSend_NSInt64_NSInt32 (IntPtr klass, IntPtr selector, int arg);
+
+ static void MacTerminate ()
+ {
+ var sel_terminate = sel_registerName ("terminate:");
+ var app = objc_msgSend_IntPtr (objc_getClass ("NSApplication"), sel_registerName ("sharedApplication"));
+
+ objc_msgSend_NSInt64_NSInt32 (app, sel_terminate, 0);
+ }
+
+ public static void Terminate ()
+ {
+ if (Platform.IsMac)
+ MacTerminate ();
+ }
+ }
+}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Commands/FileCommands.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Commands/FileCommands.cs
index c2b43f1433..bc209f4124 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Commands/FileCommands.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Commands/FileCommands.cs
@@ -444,4 +444,5 @@ namespace MonoDevelop.Ide.Commands
// MonoDevelop.Ide.Commands.CopyPathNameHandler Implemented in FileTabCommands.cs
// MonoDevelop.Ide.Commands.FileTabCommands.ToggleMaximize Implemented in FileTabCommands.cs
// MonoDevelop.Ide.Commands.FileTabCommands.ReopenClosedTab Implemented in FileTabCommands.cs
+ // MonoDevelop.Ide.Commands.FileTabCommands.CloseAllExceptPinned Implemented in FileTabCommands.cs
}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Commands/FileTabCommands.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Commands/FileTabCommands.cs
index 65ade3f49b..295000ea11 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Commands/FileTabCommands.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Commands/FileTabCommands.cs
@@ -39,6 +39,10 @@ using MonoDevelop.Ide.Gui.Dialogs;
using MonoDevelop.Ide.Gui.Documents;
using MonoDevelop.Ide.Gui.Shell;
+using MonoDevelop.Components.DockNotebook;
+using System.Collections.Immutable;
+using MonoDevelop.Core;
+
namespace MonoDevelop.Ide.Commands
{
public enum FileTabCommands
@@ -48,14 +52,26 @@ namespace MonoDevelop.Ide.Commands
CopyPathName,
ToggleMaximize,
ReopenClosedTab,
- CloseAllToTheRight
+ CloseAllToTheRight,
+ CloseAllExceptPinned,
+ PinTab,
}
- class CloseAllHandler : CommandHandler
+ class CloseAllHandler : TabCommandHandler
{
- protected virtual Document GetDocumentException ()
+ protected virtual ImmutableArray<Document> GetDocumentExceptions ()
+ {
+ return ImmutableArray<Document>.Empty;
+ }
+
+ bool HasDistinctViewContent (ImmutableArray<Document> viewContents, Document document)
{
- return null;
+ for (int i = 0; i < viewContents.Length; i++) {
+ if (document.Window.Document == viewContents[i]) {
+ return false;
+ }
+ }
+ return true;
}
protected virtual bool StartAfterException => false;
@@ -67,15 +83,15 @@ namespace MonoDevelop.Ide.Commands
return;
var activeNotebook = ((SdiWorkspaceWindow)active.Window).TabControl;
- var except = GetDocumentException ();
+ var except = GetDocumentExceptions ();
var docs = new List<Document> ();
var dirtyDialogShown = false;
- var startRemoving = except == null || !StartAfterException;
+ var startRemoving = !except.Any () || !StartAfterException;
foreach (var doc in IdeApp.Workbench.Documents) {
if (((SdiWorkspaceWindow)doc.Window).TabControl == activeNotebook) {
- if (except != null && doc == except) {
+ if (except.Any () && !HasDistinctViewContent (except, doc)) {
startRemoving = true;
continue;
}
@@ -102,34 +118,72 @@ namespace MonoDevelop.Ide.Commands
}
}
- class CloseAllButThisHandler : CloseAllHandler
+ abstract class TabCommandHandler : CommandHandler
{
- protected override Document GetDocumentException ()
- {
- return IdeApp.Workbench.ActiveDocument;
+ protected DockNotebookTab GetTabFromActiveDocument () {
+ var document = IdeApp.Workbench.ActiveDocument;
+ if (document == null)
+ return null;
+ return ((SdiWorkspaceWindow)document.Window).DockNotebookTab;
}
+ }
+ class CloseAllExceptPinnedHandler : CloseAllHandler
+ {
protected override void Update (CommandInfo info)
{
- var documents = IdeApp.Workbench.Documents;
- var activeDoc = IdeApp.Workbench.ActiveDocument;
+ info.Visible = info.Enabled = IdeApp.Workbench.Documents.Count != 0;
+ }
- if (activeDoc == null) {
- info.Enabled = false;
+ protected override ImmutableArray<Document> GetDocumentExceptions ()
+ {
+ var active = IdeApp.Workbench.ActiveDocument;
+ if (active == null)
+ return ImmutableArray<Document>.Empty;
+
+ var activeNotebook = ((SdiWorkspaceWindow)active.Window).TabControl;
+
+ var contents = Microsoft.CodeAnalysis
+ .ImmutableArrayExtensions
+ .WhereAsArray (
+ IdeApp.Workbench.Documents.ToImmutableArray (),
+ doc => ((SdiWorkspaceWindow)doc.Window).TabControl == activeNotebook && (((SdiWorkspaceWindow)doc.Window).DockNotebookTab?.IsPinned ?? false)
+ );
+ return contents;
+ }
+ }
+
+ class PinTabHandler : TabCommandHandler
+ {
+ protected override void Update (CommandInfo info)
+ {
+ info.Visible = info.Enabled = IdeApp.Workbench.ActiveDocument != null;
+ if (!info.Visible)
return;
+
+ var selectedTab = GetTabFromActiveDocument ();
+ if (selectedTab != null) {
+ info.Text = (selectedTab.IsPinned) ? GettextCatalog.GetString ("Un_pin Tab") : GettextCatalog.GetString ("_Pin Tab");
}
+ }
- var activeNotebook = ((SdiWorkspaceWindow)activeDoc.Window).TabControl;
+ protected override void Run ()
+ {
+ var selectedTab = GetTabFromActiveDocument ();
+ if (selectedTab != null)
+ selectedTab.IsPinned = !selectedTab.IsPinned;
+ }
+ }
- // Disable if only document in tab strip
- foreach (var doc in documents) {
- if (doc != activeDoc && ((SdiWorkspaceWindow)doc.Window).TabControl == activeNotebook) {
- info.Enabled = true;
- return;
- }
+ class CloseAllButThisHandler : CloseAllHandler
+ {
+ protected override ImmutableArray<Document> GetDocumentExceptions ()
+ {
+ var active = IdeApp.Workbench.ActiveDocument;
+ if (active == null) {
+ return ImmutableArray<Document>.Empty;
}
-
- info.Enabled = false;
+ return ImmutableArray.Create (active.Window.Document);
}
}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.CustomTools/CustomToolService.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.CustomTools/CustomToolService.cs
index ef32d1a4ad..1721889cd2 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.CustomTools/CustomToolService.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.CustomTools/CustomToolService.cs
@@ -310,8 +310,6 @@ namespace MonoDevelop.Ide.CustomTools
// Execute the generator
- Exception error = null;
-
// Share the one pad for all Tool output.
Pad pad = null;
@@ -337,7 +335,6 @@ namespace MonoDevelop.Ide.CustomTools
try {
await tool.Generate (monitor, project, file, result);
} catch (Exception ex) {
- error = ex;
result.UnhandledException = ex;
}
@@ -360,11 +357,7 @@ namespace MonoDevelop.Ide.CustomTools
UpdateCompleted (monitor, file, genFile, result, false);
} finally {
FileService.ThawEvents ();
- if (error == null)
- newTask.SetResult (true);
- else {
- newTask.SetException (error);
- }
+ newTask.TrySetResult (true);
}
}
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 3d812dfa67..9a47f7e362 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/DefaultSourceEditorOptions.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/DefaultSourceEditorOptions.cs
@@ -367,7 +367,7 @@ namespace MonoDevelop.Ide.Editor
showRulerFromContext = false;
}
}
-
+ this.FireChange ();
return Task.FromResult (true);
}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/Workbench.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/Workbench.cs
index 74bdc40b31..eef174104a 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/Workbench.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/Workbench.cs
@@ -850,6 +850,7 @@ namespace MonoDevelop.Ide.Gui
if (!String.IsNullOrEmpty (document.FileName)) {
var dp = CreateDocumentPrefs (args, document);
dp.NotebookId = notebookId;
+ dp.IsPinned = tab.IsPinned;
files.Add (dp);
}
}
@@ -867,6 +868,16 @@ namespace MonoDevelop.Ide.Gui
dp.Line = line.LineNumber + 1;
dp.Column = pos.Position - line.Start + 1;
}
+
+ try {
+ var tab = ((SdiWorkspaceWindow)document.Window).DockNotebookTab;
+ if (tab != null) {
+ dp.IsPinned = tab.IsPinned;
+ }
+ } catch (Exception ex) {
+ LoggingService.LogInternalError (ex);
+ }
+
return dp;
}
@@ -953,6 +964,16 @@ namespace MonoDevelop.Ide.Gui
var document = await documentManager.BatchOpenDocument (pm, fileName, null, doc.Line, doc.Column, nb);
if (document != null) {
+
+ try {
+ var tab = ((SdiWorkspaceWindow)document.Window).DockNotebookTab;
+ if (tab != null) {
+ tab.IsPinned = doc.IsPinned;
+ }
+ } catch (Exception ex) {
+ LoggingService.LogInternalError (ex);
+ }
+
var t = new Tuple<Document,string> (document, fileName);
docViews.Add (t);
}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/WorkbenchMemento.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/WorkbenchMemento.cs
index d70c432c54..a8a35f8d5c 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/WorkbenchMemento.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/WorkbenchMemento.cs
@@ -127,6 +127,9 @@ namespace MonoDevelop.Ide.Gui
[ItemProperty (DefaultValue = 0)]
public int NotebookId;
+
+ [ItemProperty (DefaultValue = false)]
+ public bool IsPinned;
}
[DataItem ("Pad")]
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.csproj b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.csproj
index 4b27c74d7a..6879aa96f6 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.csproj
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.csproj
@@ -142,6 +142,14 @@
<EmbeddedResource Include="templates\EmptyStruct.xft.xml" />
<EmbeddedResource Include="templates\EmptyTextFile.xft.xml" />
<EmbeddedResource Include="templates\EmptyXMLFile.xft.xml" />
+ <EmbeddedResource Include="icons\tab-pinned-9.png" />
+ <EmbeddedResource Include="icons\tab-pinned-9%402x.png" />
+ <EmbeddedResource Include="icons\tab-pinned-9~dark.png" />
+ <EmbeddedResource Include="icons\tab-pinned-9~dark%402x.png" />
+ <EmbeddedResource Include="icons\tab-unpinned-9.png" />
+ <EmbeddedResource Include="icons\tab-unpinned-9%402x.png" />
+ <EmbeddedResource Include="icons\tab-unpinned-9~dark.png" />
+ <EmbeddedResource Include="icons\tab-unpinned-9~dark%402x.png" />
<EmbeddedResource Include="icons\reference-assembly-16.png" />
<EmbeddedResource Include="icons\reference-assembly-16%402x.png" />
<EmbeddedResource Include="icons\reference-assembly-16~dark.png" />
@@ -4252,6 +4260,7 @@
<Compile Include="MonoDevelop.Components\Mac\DragEventTrapView.cs" />
<Compile Include="MonoDevelop.Components\Mac\NativeToolkitHelper.cs" />
<Compile Include="MonoDevelop.Components\Mac\NSViewExtensions.cs" />
+ <Compile Include="MonoDevelop.Components\Shared\GtkWorkarounds.cs" />
</ItemGroup>
<ItemGroup Condition="'$(Configuration)' == 'DebugMac' OR '$(Configuration)' == 'ReleaseMac'">
<Compile Include="MonoDevelop.Components\Mac\KeyCodes.cs" />
@@ -4353,6 +4362,9 @@
<InternalsVisibleTo Include="Xamarin.OSXEditor" />
<InternalsVisibleTo Include="Xamarin.Sketches" />
</ItemGroup>
+ <ItemGroup>
+ <Folder Include="MonoDevelop.Components\Shared\" />
+ </ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Target Name="AfterBuild">
<Copy SourceFiles="@(Data)" DestinationFolder="..\..\..\build\data\%(Data.RelativeDir)" SkipUnchangedFiles="true" />
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/Ide.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/Ide.cs
index da8982d467..1776fbeb3b 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/Ide.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/Ide.cs
@@ -541,9 +541,9 @@ namespace MonoDevelop.Ide
// If the user interacted with the IDE just a moment ago, wait a bit more time before
// running the action
- var interactionSpan = (int)(DateTime.Now - commandService.LastUserInteraction).TotalMilliseconds;
+ var interactionSpan = Math.Max (0, (DateTime.Now - commandService.LastUserInteraction).TotalMilliseconds);
if (interactionSpan < 500) {
- DispatchIdleActions (500 - interactionSpan);
+ DispatchIdleActions (500 - (int) interactionSpan);
return;
}
diff --git a/main/src/core/MonoDevelop.Ide/icons/tab-pinned-9.png b/main/src/core/MonoDevelop.Ide/icons/tab-pinned-9.png
new file mode 100644
index 0000000000..edc1f09dd6
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/icons/tab-pinned-9.png
Binary files differ
diff --git a/main/src/core/MonoDevelop.Ide/icons/tab-pinned-9@2x.png b/main/src/core/MonoDevelop.Ide/icons/tab-pinned-9@2x.png
new file mode 100644
index 0000000000..86acbbbc16
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/icons/tab-pinned-9@2x.png
Binary files differ
diff --git a/main/src/core/MonoDevelop.Ide/icons/tab-pinned-9~dark.png b/main/src/core/MonoDevelop.Ide/icons/tab-pinned-9~dark.png
new file mode 100644
index 0000000000..9fa86cb595
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/icons/tab-pinned-9~dark.png
Binary files differ
diff --git a/main/src/core/MonoDevelop.Ide/icons/tab-pinned-9~dark@2x.png b/main/src/core/MonoDevelop.Ide/icons/tab-pinned-9~dark@2x.png
new file mode 100644
index 0000000000..ee2e2262ff
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/icons/tab-pinned-9~dark@2x.png
Binary files differ
diff --git a/main/src/core/MonoDevelop.Ide/icons/tab-unpinned-9.png b/main/src/core/MonoDevelop.Ide/icons/tab-unpinned-9.png
new file mode 100644
index 0000000000..24f9f94650
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/icons/tab-unpinned-9.png
Binary files differ
diff --git a/main/src/core/MonoDevelop.Ide/icons/tab-unpinned-9@2x.png b/main/src/core/MonoDevelop.Ide/icons/tab-unpinned-9@2x.png
new file mode 100644
index 0000000000..cab628cf34
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/icons/tab-unpinned-9@2x.png
Binary files differ
diff --git a/main/src/core/MonoDevelop.Ide/icons/tab-unpinned-9~dark.png b/main/src/core/MonoDevelop.Ide/icons/tab-unpinned-9~dark.png
new file mode 100644
index 0000000000..e240b6cc83
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/icons/tab-unpinned-9~dark.png
Binary files differ
diff --git a/main/src/core/MonoDevelop.Ide/icons/tab-unpinned-9~dark@2x.png b/main/src/core/MonoDevelop.Ide/icons/tab-unpinned-9~dark@2x.png
new file mode 100644
index 0000000000..23838c89b2
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/icons/tab-unpinned-9~dark@2x.png
Binary files differ