From 6f90bfc3810c175f119cc315bb3d0f5bf43ba65f Mon Sep 17 00:00:00 2001 From: Rival Abdrakhmanov Date: Mon, 20 Nov 2023 10:50:28 +0100 Subject: [PATCH 1/5] Add settings page for function file templates --- .../RiderAzureCSharpFileTemplatesOptionPage.kt | 13 +++++++++++++ .../RiderAzureFSharpFileTemplatesOptionPage.kt | 13 +++++++++++++ .../azure-intellij-plugin-appservice-dotnet.xml | 10 ++++++++++ 3 files changed, 36 insertions(+) create mode 100644 PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/settings/templates/RiderAzureCSharpFileTemplatesOptionPage.kt create mode 100644 PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/settings/templates/RiderAzureFSharpFileTemplatesOptionPage.kt diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/settings/templates/RiderAzureCSharpFileTemplatesOptionPage.kt b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/settings/templates/RiderAzureCSharpFileTemplatesOptionPage.kt new file mode 100644 index 0000000000..0041a3c694 --- /dev/null +++ b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/settings/templates/RiderAzureCSharpFileTemplatesOptionPage.kt @@ -0,0 +1,13 @@ +/* + * Copyright 2018-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the MIT license. + */ + +package com.microsoft.azure.toolkit.intellij.legacy.function.settings.templates + +import com.intellij.openapi.options.Configurable +import com.jetbrains.rider.settings.simple.SimpleOptionsPage + +class RiderAzureCSharpFileTemplatesOptionPage : + SimpleOptionsPage("Azure (C#)", "RiderAzureCSharpFileTemplatesSettings"), Configurable.NoScroll { + override fun getId() = pageId + "Id" +} \ No newline at end of file diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/settings/templates/RiderAzureFSharpFileTemplatesOptionPage.kt b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/settings/templates/RiderAzureFSharpFileTemplatesOptionPage.kt new file mode 100644 index 0000000000..b6428361ae --- /dev/null +++ b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/settings/templates/RiderAzureFSharpFileTemplatesOptionPage.kt @@ -0,0 +1,13 @@ +/* + * Copyright 2018-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the MIT license. + */ + +package com.microsoft.azure.toolkit.intellij.legacy.function.settings.templates + +import com.intellij.openapi.options.Configurable +import com.jetbrains.rider.settings.simple.SimpleOptionsPage + +class RiderAzureFSharpFileTemplatesOptionPage : + SimpleOptionsPage("Azure (F#)", "RiderAzureFSharpFileTemplatesSettings"), Configurable.NoScroll { + override fun getId() = pageId + "Id" +} \ No newline at end of file diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/resources/META-INF/azure-intellij-plugin-appservice-dotnet.xml b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/resources/META-INF/azure-intellij-plugin-appservice-dotnet.xml index a538513611..eabe1e27ad 100644 --- a/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/resources/META-INF/azure-intellij-plugin-appservice-dotnet.xml +++ b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/resources/META-INF/azure-intellij-plugin-appservice-dotnet.xml @@ -23,6 +23,16 @@ id="com.microsoft.azure.toolkit.intellij.legacy.function.settings.AzureFunctionConfigurable" instance="com.microsoft.azure.toolkit.intellij.legacy.function.settings.AzureFunctionConfigurable"/> + + + + From 233069bc3f1b594ffc5f6a8896c950f49f91b211 Mon Sep 17 00:00:00 2001 From: Rival Abdrakhmanov Date: Mon, 20 Nov 2023 11:38:23 +0100 Subject: [PATCH 2/5] Add timer completion --- .../ReSharper.Azure.sln | 8 ++ .../TimerTriggerCompletionContributor.kt | 17 +++ ...zure-intellij-plugin-appservice-dotnet.xml | 3 + .../azure-toolkit-for-rider/build.gradle.kts | 2 + .../Azure.Intellisense.csproj | 1 + ...CSharpTimerTriggerCronArgumentsProvider.cs | 112 +++++++++++++++++ .../Azure.Psi/Azure.Psi.csproj | 17 +++ .../FunctionApp/FunctionAppFinder.cs | 117 ++++++++++++++++++ .../ReSharper.Azure/Azure.Psi/ZoneMarker.cs | 31 +++++ 9 files changed, 308 insertions(+) create mode 100644 PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/completion/csharp/TimerTriggerCompletionContributor.kt create mode 100644 PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Intellisense/FunctionApp/CodeCompletion/CSharp/Rules/CSharpTimerTriggerCronArgumentsProvider.cs create mode 100644 PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Psi/Azure.Psi.csproj create mode 100644 PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Psi/FunctionApp/FunctionAppFinder.cs create mode 100644 PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Psi/ZoneMarker.cs diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/ReSharper.Azure.sln b/PluginsAndFeatures/azure-toolkit-for-rider/ReSharper.Azure.sln index 97bb7d11af..37b5b12a4c 100644 --- a/PluginsAndFeatures/azure-toolkit-for-rider/ReSharper.Azure.sln +++ b/PluginsAndFeatures/azure-toolkit-for-rider/ReSharper.Azure.sln @@ -7,8 +7,12 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{D7AED5E7-CF45-4740-A0D8-DA638A964069}" ProjectSection(SolutionItems) = preProject src\dotnet\Directory.Build.props = src\dotnet\Directory.Build.props + CHANGELOG.md = CHANGELOG.md + README.md = README.md EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azure.Psi", "src\dotnet\ReSharper.Azure\Azure.Psi\Azure.Psi.csproj", "{90893DE8-F9A4-4970-BE08-0A5E3EB97E1E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -23,5 +27,9 @@ Global {89B4800D-245A-49F5-94C6-E45D239EFA84}.Debug|Any CPU.Build.0 = Debug|Any CPU {89B4800D-245A-49F5-94C6-E45D239EFA84}.Release|Any CPU.ActiveCfg = Release|Any CPU {89B4800D-245A-49F5-94C6-E45D239EFA84}.Release|Any CPU.Build.0 = Release|Any CPU + {90893DE8-F9A4-4970-BE08-0A5E3EB97E1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {90893DE8-F9A4-4970-BE08-0A5E3EB97E1E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {90893DE8-F9A4-4970-BE08-0A5E3EB97E1E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {90893DE8-F9A4-4970-BE08-0A5E3EB97E1E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/completion/csharp/TimerTriggerCompletionContributor.kt b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/completion/csharp/TimerTriggerCompletionContributor.kt new file mode 100644 index 0000000000..6075f69c29 --- /dev/null +++ b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/completion/csharp/TimerTriggerCompletionContributor.kt @@ -0,0 +1,17 @@ +/* + * Copyright 2018-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the MIT license. + */ + +package com.microsoft.azure.toolkit.intellij.legacy.function.completion.csharp + +import com.jetbrains.rider.completion.ProtocolCompletionContributor + +class TimerTriggerCompletionContributor : ProtocolCompletionContributor() { + /** + * Override default Rider behavior to terminate on first digit prefix. + * + * Please note, this is a global behavior. There is no option for now to handle this for a particular completion case. + * Please consider switching back if cause any issues in future. + */ + override fun shouldStopOnPrefix(prefix: String, isAutoPopup: Boolean): Boolean = false +} \ No newline at end of file diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/resources/META-INF/azure-intellij-plugin-appservice-dotnet.xml b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/resources/META-INF/azure-intellij-plugin-appservice-dotnet.xml index eabe1e27ad..1967c97d49 100644 --- a/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/resources/META-INF/azure-intellij-plugin-appservice-dotnet.xml +++ b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/resources/META-INF/azure-intellij-plugin-appservice-dotnet.xml @@ -41,6 +41,9 @@ description="Azure Functions Core Tools releases feed URL." /> + + diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/build.gradle.kts b/PluginsAndFeatures/azure-toolkit-for-rider/build.gradle.kts index a830ba95d0..6415cbd260 100644 --- a/PluginsAndFeatures/azure-toolkit-for-rider/build.gradle.kts +++ b/PluginsAndFeatures/azure-toolkit-for-rider/build.gradle.kts @@ -235,6 +235,8 @@ tasks { val dllFiles = listOf( "$outputFolder/Azure.Project/bin/$dotnetBuildConfiguration/JetBrains.ReSharper.Azure.Project.dll", "$outputFolder/Azure.Project/bin/$dotnetBuildConfiguration/JetBrains.ReSharper.Azure.Project.pdb", + "$outputFolder/Azure.Psi/bin/$dotnetBuildConfiguration/JetBrains.ReSharper.Azure.Psi.dll", + "$outputFolder/Azure.Psi/bin/$dotnetBuildConfiguration/JetBrains.ReSharper.Azure.Psi.pdb", "$outputFolder/Azure.Intellisense/bin/$dotnetBuildConfiguration/JetBrains.ReSharper.Azure.Intellisense.dll", "$outputFolder/Azure.Intellisense/bin/$dotnetBuildConfiguration/JetBrains.ReSharper.Azure.Intellisense.pdb" ) diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Intellisense/Azure.Intellisense.csproj b/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Intellisense/Azure.Intellisense.csproj index f60e092f98..ebcfe0ca12 100644 --- a/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Intellisense/Azure.Intellisense.csproj +++ b/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Intellisense/Azure.Intellisense.csproj @@ -30,6 +30,7 @@ + diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Intellisense/FunctionApp/CodeCompletion/CSharp/Rules/CSharpTimerTriggerCronArgumentsProvider.cs b/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Intellisense/FunctionApp/CodeCompletion/CSharp/Rules/CSharpTimerTriggerCronArgumentsProvider.cs new file mode 100644 index 0000000000..52088d732a --- /dev/null +++ b/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Intellisense/FunctionApp/CodeCompletion/CSharp/Rules/CSharpTimerTriggerCronArgumentsProvider.cs @@ -0,0 +1,112 @@ +// Copyright 2018-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the MIT license. + +using JetBrains.DocumentModel; +using JetBrains.ReSharper.Azure.Psi.FunctionApp; +using JetBrains.ReSharper.Feature.Services.CodeCompletion; +using JetBrains.ReSharper.Feature.Services.CodeCompletion.Infrastructure; +using JetBrains.ReSharper.Feature.Services.CodeCompletion.Infrastructure.AspectLookupItems.BaseInfrastructure; +using JetBrains.ReSharper.Feature.Services.CodeCompletion.Infrastructure.AspectLookupItems.Info; +using JetBrains.ReSharper.Feature.Services.CodeCompletion.Infrastructure.AspectLookupItems.Matchers; +using JetBrains.ReSharper.Feature.Services.CodeCompletion.Infrastructure.LookupItems; +using JetBrains.ReSharper.Feature.Services.CSharp.CodeCompletion.Infrastructure; +using JetBrains.ReSharper.Features.Intellisense.CodeCompletion.CSharp; +using JetBrains.ReSharper.Features.Intellisense.CodeCompletion.CSharp.Rules; +using JetBrains.ReSharper.Psi; +using JetBrains.ReSharper.Psi.CSharp; +using JetBrains.ReSharper.Psi.CSharp.Tree; +using JetBrains.ReSharper.Psi.CSharp.Util; +using JetBrains.ReSharper.Psi.Tree; + +namespace JetBrains.ReSharper.Azure.Intellisense.FunctionApp.CodeCompletion.CSharp.Rules; + +[Language(typeof(CSharpLanguage))] +public class CSharpTimerTriggerCronArgumentsProvider : CSharpItemsProviderBase +{ + private readonly struct CronSuggestion(string expression, string description) + { + public readonly string Expression = expression; + public readonly string Description = description; + } + + private readonly CronSuggestion[] _cronSuggestions = + { + new("* * * * * *", "Every second"), + new("0 * * * * *", "Every minute"), + new("0 */5 * * * *", "Every 5 minutes"), + new("0 0 * * * *", "Every hour"), + new("0 0 */6 * * *", "Every 6 hours at minute 0"), + new("0 0 8-18 * * *", "Every hour between 08:00 AM and 06:59 PM"), + new("0 0 0 * * *", "At 12:00 AM"), + new("0 0 10 * * *", "At 10:00 AM"), + new("0 0 * * * 1-5", "Every hour, Monday through Friday"), + new("0 0 0 * * 0", "At 12:00 AM, only on Sunday"), + new("0 0 9 * * Mon", "At 09:00 AM, only on Monday"), + new("0 0 0 1 * *", "At 12:00 AM, on day 1 of the month"), + new("0 0 0 1 1 *", "At 12:00 AM, on day 1 of the month, only in January"), + new("0 0 * * * Sun", "Every hour, only on Sunday"), + new("0 0 0 * * Sat,Sun", "At 12:00 AM, only on Saturday and Sunday"), + new("0 0 0 * * 6,0", "At 12:00 AM, only on Saturday and Sunday"), + new("0 0 0 1-7 * Sun", "At 12:00 AM, between day 1 and 7 of the month, only on Sunday"), + new("11 5 23 * * *", "At 11:05:11 PM"), + new("*/15 * * * * *", "Every 15 seconds"), + new("0 30 9 * Jan Mon", "At 09:30 AM, only on Monday, only in January") + }; + + protected override bool IsAvailable(CSharpCodeCompletionContext context) + { + return IsStringLiteral(context) && + IsTimerTriggerAnnotation(context) && + context.BasicContext.CodeCompletionType == CodeCompletionType.BasicCompletion; + } + + protected override bool AddLookupItems(CSharpCodeCompletionContext context, IItemsCollector collector) + { + foreach (var cronSuggestion in _cronSuggestions) + { + if (context.NodeInFile.Parent is not ICSharpLiteralExpression literalExpression) return false; + var ranges = GetRangeWithinQuotes(literalExpression); + + var lookupItem = + CSharpLookupItemFactory.Instance.CreateTextLookupItem(new TextLookupRanges(ranges, ranges), + cronSuggestion.Expression); + + lookupItem.Presentation.DisplayTypeName.Text = cronSuggestion.Description; + + lookupItem.WithMatcher(static item => + new TextualMatcher(item.Info.Text.Replace(" ", "·"), item.Info)); + + collector.Add(lookupItem); + } + + return true; + } + + private static DocumentRange GetRangeWithinQuotes(ICSharpLiteralExpression expression) + { + var literalAlterer = CSharpStringLiteralAlterer.CreateByLiteralExpression(expression); + var underQuotesRange = literalAlterer.UnderQuotesRange; + var containingFile = expression.GetContainingFile(); + return containingFile?.GetDocumentRange(underQuotesRange) ?? DocumentRange.InvalidRange; + } + + private static bool IsStringLiteral(CSharpCodeCompletionContext context) => + context.UnterminatedContext.TreeNode is ITokenNode token && + token.GetTokenType().IsStringLiteral; + + private static bool IsTimerTriggerAnnotation(CSharpCodeCompletionContext context) + { + var token = context.UnterminatedContext.TreeNode as ITokenNode; + if (token == null) return false; + + var literal = token.Parent as ICSharpLiteralExpression; + var argument = CSharpArgumentNavigator.GetByValue(literal); + var attribute = AttributeNavigator.GetByArgument(argument); + + if (attribute == null) return false; + if (attribute.Arguments.Count != 1) return false; + + var resolveResult = attribute.TypeReference?.Resolve(); + return resolveResult?.DeclaredElement is ITypeElement typeElement && + FunctionAppFinder.IsTimerTriggerAttribute(typeElement); + } +} \ No newline at end of file diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Psi/Azure.Psi.csproj b/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Psi/Azure.Psi.csproj new file mode 100644 index 0000000000..710c8c535d --- /dev/null +++ b/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Psi/Azure.Psi.csproj @@ -0,0 +1,17 @@ + + + + net472 + JetBrains.ReSharper.Azure.Psi + JetBrains.ReSharper.Azure.Psi + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Psi/FunctionApp/FunctionAppFinder.cs b/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Psi/FunctionApp/FunctionAppFinder.cs new file mode 100644 index 0000000000..08421e56d6 --- /dev/null +++ b/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Psi/FunctionApp/FunctionAppFinder.cs @@ -0,0 +1,117 @@ +// Copyright 2018-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the MIT license. + +using System.Linq; +using JetBrains.Metadata.Reader.API; +using JetBrains.Metadata.Reader.Impl; +using JetBrains.Rd.Base; +using JetBrains.ReSharper.Psi; +using JetBrains.Util; +using JetBrains.Util.Logging; + +namespace JetBrains.ReSharper.Azure.Psi.FunctionApp; + +public static class FunctionAppFinder +{ + private static readonly ILogger OurLogger = Logger.GetLogger(typeof(FunctionAppFinder)); + + private static class DefaultWorker + { + public static readonly IClrTypeName FunctionNameAttributeTypeName = + new ClrTypeName("Microsoft.Azure.WebJobs.FunctionNameAttribute"); + + public static readonly IClrTypeName TimerTriggerAttributeTypeName = + new ClrTypeName("Microsoft.Azure.WebJobs.TimerTriggerAttribute"); + } + + private static class IsolatedWorker + { + public static readonly IClrTypeName FunctionAttributeTypeName = + new ClrTypeName("Microsoft.Azure.Functions.Worker.FunctionAttribute"); + + public static readonly IClrTypeName TimerTriggerAttributeTypeName = + new ClrTypeName("Microsoft.Azure.Functions.Worker.TimerTriggerAttribute"); + } + + /// + /// Get Function Name from Attribute for a provided method or null if attribute is missing + /// + /// A Method instance to check. + /// Function App name string value. + public static string? GetFunctionNameFromMethod(IMethod? method) + { + if (method == null) return null; + + var functionAttribute = GetFunctionNameAttribute(method); + if (functionAttribute == null) return null; + + var functionParameters = functionAttribute.PositionParameters().ToArray(); + if (functionParameters.Length < 1) + { + OurLogger.Warn($"Insufficient number of parameters in '{functionAttribute.GetAttributeShortName()}' attribute to get a Function name."); + return null; + } + + var functionNameParameter = functionParameters.First(); + + if (functionNameParameter == null || !functionNameParameter.ConstantValue.IsString()) + { + OurLogger.Error( + $"Unable to get a Function name from '{method.ShortName}' method attribute parameter: '{functionNameParameter.PrintToString()}'."); + return null; + } + + return functionNameParameter.ConstantValue.StringValue; + } + + /// + /// Check whether a method define a Function App that can be run. + /// Reference links: + /// - https://docs.microsoft.com/en-us/azure/azure-functions/functions-dotnet-class-library#methods-recognized-as-functions + /// - https://docs.microsoft.com/en-us/azure/azure-functions/functions-dotnet-dependency-injection + /// + /// A Method instance to check. + /// Flag whether provided method can be considered as a method to start a Function App of any type. + public static bool IsSuitableFunctionAppMethod(IMethod? method) + { + return method != null && + method.GetAccessRights() == AccessRights.PUBLIC && + GetFunctionNameAttribute(method) != null; + } + + /// + /// Check whether declared type is a Function App Timer Trigger type. + /// + /// A type element to check. + /// Flag whether type element match Function App Timer Trigger attribute type. + public static bool IsTimerTriggerAttribute(ITypeElement typeElement) + { + return typeElement.GetClrName().Equals(DefaultWorker.TimerTriggerAttributeTypeName) || + typeElement.GetClrName().Equals(IsolatedWorker.TimerTriggerAttributeTypeName); + } + + private static IAttributeInstance? GetFunctionNameAttribute(IMethod method) + { + var functionAttributes = method.GetAttributeInstances(DefaultWorker.FunctionNameAttributeTypeName, false) + .Union(method.GetAttributeInstances(IsolatedWorker.FunctionAttributeTypeName, false)) + .ToList(); + + if (functionAttributes.IsEmpty()) + { + if (OurLogger.IsTraceEnabled()) + { + OurLogger.Trace( + $"Unable to get a proper function name from a method '{method.ShortName}' that has more then one [Function] attribute."); + } + + return null; + } + + if (functionAttributes.Count > 1) + { + OurLogger.Info( + $"Found more then one FunctionName attribute from a method '{method.ShortName}'. Return the first match."); + } + + return functionAttributes.First(); + } +} \ No newline at end of file diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Psi/ZoneMarker.cs b/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Psi/ZoneMarker.cs new file mode 100644 index 0000000000..06a2b5ae45 --- /dev/null +++ b/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Psi/ZoneMarker.cs @@ -0,0 +1,31 @@ +// Copyright (c) 2020 JetBrains s.r.o. +// +// All rights reserved. +// +// MIT License +// +// 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 JetBrains.Application.BuildScript.Application.Zones; +using JetBrains.ReSharper.Psi.CSharp; +using JetBrains.ReSharper.Resources.Shell; + +namespace JetBrains.ReSharper.Azure.Psi +{ + [ZoneMarker] + public class ZoneMarker : IRequire, IRequire + { + } +} From ea94140f51bc40ebc6a2bbac7d96af13edc6377b Mon Sep 17 00:00:00 2001 From: Rival Abdrakhmanov Date: Mon, 20 Nov 2023 13:25:58 +0100 Subject: [PATCH 3/5] Add function version inspection --- .../intellij/legacy/function/FunctionUtils.kt | 6 ++ .../AzureFunctionsVersionInspection.kt | 71 +++++++++++++++++++ .../coreTools/FunctionsCoreToolsMsBuild.kt | 7 ++ .../templates/FunctionTemplateManager.kt | 7 +- .../templates/InstallFunctionToolComponent.kt | 3 +- ...zure-intellij-plugin-appservice-dotnet.xml | 8 +++ .../AzureFunctionsTimerTriggerCron.html | 5 ++ .../AzureFunctionsVersionNotSpecified.html | 5 ++ 8 files changed, 105 insertions(+), 7 deletions(-) create mode 100644 PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/codeInspection/msbuild/AzureFunctionsVersionInspection.kt create mode 100644 PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/coreTools/FunctionsCoreToolsMsBuild.kt create mode 100644 PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/resources/inspectionDescriptions/AzureFunctionsTimerTriggerCron.html create mode 100644 PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/resources/inspectionDescriptions/AzureFunctionsVersionNotSpecified.html diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/FunctionUtils.kt b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/FunctionUtils.kt index 1b65b475b1..98a69750f5 100644 --- a/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/FunctionUtils.kt +++ b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/FunctionUtils.kt @@ -9,6 +9,12 @@ import com.microsoft.azure.toolkit.lib.common.utils.JsonUtils private const val AZURE_FUNCTIONS_APP_SETTINGS = "Azure Functions App Settings" +// Known and supported list of tags from https://github.com/Azure/azure-functions-tooling-feed/blob/main/cli-feed-v4.json +val FUNCTIONS_CORE_TOOLS_KNOWN_SUPPORTED_VERSIONS = listOf("v2", "v3", "v4") + +// Latest supported version by the Azure Toolkit for Rider +const val FUNCTIONS_CORE_TOOLS_LATEST_SUPPORTED_VERSION = "v4" + fun saveAppSettingsToSecurityStorage(key: String?, appSettings: Map) { if (key.isNullOrEmpty()) { return diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/codeInspection/msbuild/AzureFunctionsVersionInspection.kt b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/codeInspection/msbuild/AzureFunctionsVersionInspection.kt new file mode 100644 index 0000000000..7af0a4584c --- /dev/null +++ b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/codeInspection/msbuild/AzureFunctionsVersionInspection.kt @@ -0,0 +1,71 @@ +/* + * Copyright 2018-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the MIT license. + */ + +package com.microsoft.azure.toolkit.intellij.legacy.function.codeInspection.msbuild + +import com.intellij.codeInspection.* +import com.intellij.openapi.project.Project +import com.intellij.psi.XmlElementFactory +import com.intellij.psi.XmlElementVisitor +import com.intellij.psi.impl.source.tree.CompositeElement +import com.intellij.psi.xml.XmlChildRole +import com.intellij.psi.xml.XmlElementType +import com.intellij.psi.xml.XmlTag +import com.intellij.xml.util.XmlUtil +import com.microsoft.azure.toolkit.intellij.legacy.function.FUNCTIONS_CORE_TOOLS_KNOWN_SUPPORTED_VERSIONS +import com.microsoft.azure.toolkit.intellij.legacy.function.coreTools.PROPERTY_AZURE_FUNCTIONS_VERSION + +class AzureFunctionsVersionInspection : XmlSuppressableInspectionTool() { + override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean) = object : XmlElementVisitor() { + override fun visitXmlTag(tag: XmlTag) { + val tagName = tag.name.lowercase() + if (tagName.equals(PROPERTY_AZURE_FUNCTIONS_VERSION, ignoreCase = true)) { + val child = XmlChildRole.START_TAG_END_FINDER.findChild(tag.node) + ?: XmlChildRole.EMPTY_TAG_END_FINDER.findChild(tag.node) + if (child != null) { + val node = child.treeNext + + val isVersionNotSpecified = node == null || node.elementType !== XmlElementType.XML_TEXT + val isVersionUnsupported = node != null && + node.elementType === XmlElementType.XML_TEXT && + FUNCTIONS_CORE_TOOLS_KNOWN_SUPPORTED_VERSIONS.none { + it.equals(node.text, ignoreCase = true) + } + + if (isVersionNotSpecified || isVersionUnsupported) { + val versionQuickFixes = FUNCTIONS_CORE_TOOLS_KNOWN_SUPPORTED_VERSIONS.reversed() + .filterNot { it.contains('-') } // only show release versions + .map { SetVersionQuickFix(it) } + .toTypedArray() + + holder.registerProblem(tag, + if (isVersionNotSpecified) + "Azure Functions version not specified" + else + "Unsupported Azure Functions version", + ProblemHighlightType.WARNING, + *versionQuickFixes) + } + } + } + } + } + + private class SetVersionQuickFix(val version: String) : LocalQuickFix { + override fun getFamilyName() = "Set Azure Functions version '$version'" + + override fun applyFix(project: Project, descriptor: ProblemDescriptor) { + val tag = descriptor.psiElement as XmlTag + + XmlUtil.expandTag(tag) + + val newTag = XmlElementFactory.getInstance(tag.project) + .createTagFromText("<${tag.name}>$version") + + val node = tag.node as? CompositeElement ?: return + + node.replaceAllChildrenToChildrenOf(newTag.node) + } + } +} \ No newline at end of file diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/coreTools/FunctionsCoreToolsMsBuild.kt b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/coreTools/FunctionsCoreToolsMsBuild.kt new file mode 100644 index 0000000000..d9dd03a613 --- /dev/null +++ b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/coreTools/FunctionsCoreToolsMsBuild.kt @@ -0,0 +1,7 @@ +/* + * Copyright 2018-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the MIT license. + */ + +package com.microsoft.azure.toolkit.intellij.legacy.function.coreTools + +const val PROPERTY_AZURE_FUNCTIONS_VERSION = "AzureFunctionsVersion" \ No newline at end of file diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/templates/FunctionTemplateManager.kt b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/templates/FunctionTemplateManager.kt index 0237682c63..f1c5c241f4 100644 --- a/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/templates/FunctionTemplateManager.kt +++ b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/templates/FunctionTemplateManager.kt @@ -11,6 +11,7 @@ import com.intellij.openapi.components.service import com.intellij.openapi.diagnostic.logger import com.intellij.util.application import com.jetbrains.rider.projectView.actions.projectTemplating.backend.ReSharperProjectTemplateProvider +import com.microsoft.azure.toolkit.intellij.legacy.function.FUNCTIONS_CORE_TOOLS_LATEST_SUPPORTED_VERSION import com.microsoft.azure.toolkit.intellij.legacy.function.coreTools.FunctionsCoreToolsInfoProvider import java.io.File @@ -19,12 +20,6 @@ class FunctionTemplateManager { companion object { fun getInstance(): FunctionTemplateManager = service() - // Known and supported list of tags from https://github.com/Azure/azure-functions-tooling-feed/blob/main/cli-feed-v4.json - val FUNCTIONS_CORE_TOOLS_KNOWN_SUPPORTED_VERSIONS = listOf("v2", "v3", "v4") - - // Latest supported version by the Azure Toolkit for Rider - const val FUNCTIONS_CORE_TOOLS_LATEST_SUPPORTED_VERSION = "v4" - private val LOG = logger() private fun isFunctionsProjectTemplate(file: File?) = diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/templates/InstallFunctionToolComponent.kt b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/templates/InstallFunctionToolComponent.kt index 8e6ab8b3bd..37b79fd0b6 100644 --- a/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/templates/InstallFunctionToolComponent.kt +++ b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/templates/InstallFunctionToolComponent.kt @@ -14,6 +14,7 @@ import com.intellij.platform.ide.progress.runWithModalProgressBlocking import com.intellij.ui.dsl.builder.panel import com.jetbrains.rd.util.reactive.IProperty import com.jetbrains.rider.ui.components.base.Viewable +import com.microsoft.azure.toolkit.intellij.legacy.function.FUNCTIONS_CORE_TOOLS_LATEST_SUPPORTED_VERSION import com.microsoft.azure.toolkit.intellij.legacy.function.coreTools.FunctionsCoreToolsInfoProvider import javax.swing.JComponent import javax.swing.JPanel @@ -39,7 +40,7 @@ class InstallFunctionToolComponent(private val validationError: IProperty + + diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/resources/inspectionDescriptions/AzureFunctionsTimerTriggerCron.html b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/resources/inspectionDescriptions/AzureFunctionsTimerTriggerCron.html new file mode 100644 index 0000000000..4266bdea79 --- /dev/null +++ b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/resources/inspectionDescriptions/AzureFunctionsTimerTriggerCron.html @@ -0,0 +1,5 @@ + + +This inspection checks that the Azure Functions timer trigger schedule expression is valid, as per documentation. + + \ No newline at end of file diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/resources/inspectionDescriptions/AzureFunctionsVersionNotSpecified.html b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/resources/inspectionDescriptions/AzureFunctionsVersionNotSpecified.html new file mode 100644 index 0000000000..adbb625c0a --- /dev/null +++ b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/resources/inspectionDescriptions/AzureFunctionsVersionNotSpecified.html @@ -0,0 +1,5 @@ + + +This inspection checks that the project file contains a valid AzureFunctionsVersion value, as per documentation. + + \ No newline at end of file From 7b1733edfe35346fb4164bb8249e197e2a1778d3 Mon Sep 17 00:00:00 2001 From: Rival Abdrakhmanov Date: Mon, 20 Nov 2023 15:08:25 +0100 Subject: [PATCH 4/5] Add timer trigger highlighter --- .../ReSharper.Azure.sln | 6 + ...zure-intellij-plugin-appservice-dotnet.xml | 2 + ...nctions.Worker.Extensions.Abstractions.xml | 5 + .../annotations/Microsoft.Azure.WebJobs.xml | 5 + .../azure-toolkit-for-rider/build.gradle.kts | 5 +- .../Azure.Daemon/Azure.Daemon.csproj | 31 +++++ .../Azure.Daemon/Errors/FunctionAppErrors.xml | 82 +++++++++++ .../TimerTriggerCronProblemAnalyzer.cs | 128 ++++++++++++++++++ .../Highlighters/AzureHighlightingGroupIds.cs | 12 ++ .../Azure.Daemon/ZoneMarker.cs | 10 ++ .../Azure.Intellisense/ZoneMarker.cs | 9 +- .../Azure.Project/ZoneMarker.cs | 29 +--- .../ReSharper.Azure/Azure.Psi/ZoneMarker.cs | 31 +---- 13 files changed, 299 insertions(+), 56 deletions(-) create mode 100644 PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/resources/dotnet/Extensions/com.intellij.resharper.azure/annotations/Microsoft.Azure.Functions.Worker.Extensions.Abstractions.xml create mode 100644 PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/resources/dotnet/Extensions/com.intellij.resharper.azure/annotations/Microsoft.Azure.WebJobs.xml create mode 100644 PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Daemon/Azure.Daemon.csproj create mode 100644 PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Daemon/Errors/FunctionAppErrors.xml create mode 100644 PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Daemon/FunctionApp/Stages/Analysis/TimerTriggerCronProblemAnalyzer.cs create mode 100644 PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Daemon/Highlighters/AzureHighlightingGroupIds.cs create mode 100644 PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Daemon/ZoneMarker.cs diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/ReSharper.Azure.sln b/PluginsAndFeatures/azure-toolkit-for-rider/ReSharper.Azure.sln index 37b5b12a4c..48d43279cf 100644 --- a/PluginsAndFeatures/azure-toolkit-for-rider/ReSharper.Azure.sln +++ b/PluginsAndFeatures/azure-toolkit-for-rider/ReSharper.Azure.sln @@ -13,6 +13,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azure.Psi", "src\dotnet\ReSharper.Azure\Azure.Psi\Azure.Psi.csproj", "{90893DE8-F9A4-4970-BE08-0A5E3EB97E1E}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azure.Daemon", "src\dotnet\ReSharper.Azure\Azure.Daemon\Azure.Daemon.csproj", "{1E66ACB9-DE07-4961-AAD6-B87DB5B419E0}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -31,5 +33,9 @@ Global {90893DE8-F9A4-4970-BE08-0A5E3EB97E1E}.Debug|Any CPU.Build.0 = Debug|Any CPU {90893DE8-F9A4-4970-BE08-0A5E3EB97E1E}.Release|Any CPU.ActiveCfg = Release|Any CPU {90893DE8-F9A4-4970-BE08-0A5E3EB97E1E}.Release|Any CPU.Build.0 = Release|Any CPU + {1E66ACB9-DE07-4961-AAD6-B87DB5B419E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1E66ACB9-DE07-4961-AAD6-B87DB5B419E0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1E66ACB9-DE07-4961-AAD6-B87DB5B419E0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1E66ACB9-DE07-4961-AAD6-B87DB5B419E0}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/resources/META-INF/azure-intellij-plugin-appservice-dotnet.xml b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/resources/META-INF/azure-intellij-plugin-appservice-dotnet.xml index 9ab04dddb1..8c6df13817 100644 --- a/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/resources/META-INF/azure-intellij-plugin-appservice-dotnet.xml +++ b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/resources/META-INF/azure-intellij-plugin-appservice-dotnet.xml @@ -40,6 +40,8 @@ defaultValue="https://functionscdn.azureedge.net/public/cli-feed-v4.json" description="Azure Functions Core Tools releases feed URL." /> + + + + + + diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/resources/dotnet/Extensions/com.intellij.resharper.azure/annotations/Microsoft.Azure.WebJobs.xml b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/resources/dotnet/Extensions/com.intellij.resharper.azure/annotations/Microsoft.Azure.WebJobs.xml new file mode 100644 index 0000000000..0a89e24337 --- /dev/null +++ b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/resources/dotnet/Extensions/com.intellij.resharper.azure/annotations/Microsoft.Azure.WebJobs.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/build.gradle.kts b/PluginsAndFeatures/azure-toolkit-for-rider/build.gradle.kts index 6415cbd260..5529fc3d7a 100644 --- a/PluginsAndFeatures/azure-toolkit-for-rider/build.gradle.kts +++ b/PluginsAndFeatures/azure-toolkit-for-rider/build.gradle.kts @@ -238,7 +238,10 @@ tasks { "$outputFolder/Azure.Psi/bin/$dotnetBuildConfiguration/JetBrains.ReSharper.Azure.Psi.dll", "$outputFolder/Azure.Psi/bin/$dotnetBuildConfiguration/JetBrains.ReSharper.Azure.Psi.pdb", "$outputFolder/Azure.Intellisense/bin/$dotnetBuildConfiguration/JetBrains.ReSharper.Azure.Intellisense.dll", - "$outputFolder/Azure.Intellisense/bin/$dotnetBuildConfiguration/JetBrains.ReSharper.Azure.Intellisense.pdb" + "$outputFolder/Azure.Intellisense/bin/$dotnetBuildConfiguration/JetBrains.ReSharper.Azure.Intellisense.pdb", + "$outputFolder/Azure.Daemon/bin/$dotnetBuildConfiguration/JetBrains.ReSharper.Azure.Daemon.dll", + "$outputFolder/Azure.Daemon/bin/$dotnetBuildConfiguration/JetBrains.ReSharper.Azure.Daemon.pdb", + "$outputFolder/Azure.Daemon/bin/$dotnetBuildConfiguration/NCrontab.Signed.dll" ) for (f in dllFiles) { diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Daemon/Azure.Daemon.csproj b/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Daemon/Azure.Daemon.csproj new file mode 100644 index 0000000000..d0a6c06100 --- /dev/null +++ b/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Daemon/Azure.Daemon.csproj @@ -0,0 +1,31 @@ + + + + net472 + JetBrains.ReSharper.Azure.Daemon + JetBrains.ReSharper.Azure.Daemon + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + JetBrains.ReSharper.Azure.Daemon.Errors.FunctionAppErrors + Errors\FunctionAppErrors.Generated.cs + ERRORS + + + + diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Daemon/Errors/FunctionAppErrors.xml b/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Daemon/Errors/FunctionAppErrors.xml new file mode 100644 index 0000000000..2d289bbca6 --- /dev/null +++ b/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Daemon/Errors/FunctionAppErrors.xml @@ -0,0 +1,82 @@ + + + + + JetBrains.ReSharper.Azure.Daemon.Errors; + JetBrains.ReSharper.Azure.Daemon.FunctionApp.Stages.Analysis; + JetBrains.ReSharper.Azure.Daemon.Highlighters; + JetBrains.ReSharper.Psi.CSharp; + JetBrains.ReSharper.Psi.CSharp.Tree; + + + + + + + + + + + + + + + Invalid Function App Timer Trigger Cron expression + Function App Timer Trigger Cron expression is not valid and can not be used. + + + + + + + + + + + + cronErrorMessage + + Expression.GetHighlightingRange() + + + + diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Daemon/FunctionApp/Stages/Analysis/TimerTriggerCronProblemAnalyzer.cs b/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Daemon/FunctionApp/Stages/Analysis/TimerTriggerCronProblemAnalyzer.cs new file mode 100644 index 0000000000..b38fdf6758 --- /dev/null +++ b/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Daemon/FunctionApp/Stages/Analysis/TimerTriggerCronProblemAnalyzer.cs @@ -0,0 +1,128 @@ +// Copyright 2018-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the MIT license. + +using System; +using JetBrains.ReSharper.Azure.Daemon.Errors.FunctionAppErrors; +using JetBrains.ReSharper.Azure.Psi.FunctionApp; +using JetBrains.ReSharper.Feature.Services.Daemon; +using JetBrains.ReSharper.Psi; +using JetBrains.ReSharper.Psi.CSharp.Tree; +using JetBrains.Util; +using NCrontab; + +namespace JetBrains.ReSharper.Azure.Daemon.FunctionApp.Stages.Analysis; + +/// +/// Analyzer for Cron expressions in Function App Timer Trigger +/// matching NCRONTAB specification, or System.TimeSpan. +/// +/// NCRONTAB specification. https://github.com/atifaziz/NCrontab +/// +/// In general, NCRONTAB expressions are as follows: +/// +/// * * * * * * +/// - - - - - - +/// | | | | | | +/// | | | | | +--- day of week (0 - 6) (Sunday=0) +/// | | | | +----- month (1 - 12) +/// | | | +------- day of month (1 - 31) +/// | | +--------- hour (0 - 23) +/// | +----------- min (0 - 59) +/// +------------- sec (0 - 59) +/// +/// Note that NCRONTAB uses 6 fields, but Azure Functions also supports 5 fields. +/// https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-timer?tabs=csharp#ncrontab-expressions +/// +[ElementProblemAnalyzer(typeof(IAttribute), HighlightingTypes = new[] +{ + typeof(TimerTriggerCronExpressionError) +})] +public class TimerTriggerCronProblemAnalyzer : ElementProblemAnalyzer +{ + protected override void Run(IAttribute element, ElementProblemAnalyzerData data, IHighlightingConsumer consumer) + { + if (element.Arguments.Count != 1) return; + + var resolveResult = element.TypeReference?.Resolve(); + var typeElement = resolveResult?.DeclaredElement as ITypeElement; + if (typeElement == null) return; + + if (!FunctionAppFinder.IsTimerTriggerAttribute(typeElement)) return; + + var expressionArgument = element.Arguments.First().Value; + if (expressionArgument is null || !expressionArgument.Type().IsString()) return; + + var literal = (expressionArgument as ICSharpLiteralExpression)?.ConstantValue.StringValue; + if (literal.IsEmpty()) return; + + if (literal.StartsWith("%") && literal.EndsWith("%") && literal.Length > 2) return; + + var mayBeTimeSpanSchedule = literal.Contains(":"); + if (mayBeTimeSpanSchedule) + { + if (!IsValidTimeSpanSchedule(literal, out var errorMessage)) + { + consumer.AddHighlighting(new TimerTriggerCronExpressionError(expressionArgument, errorMessage)); + } + } + else if (!IsValidCrontabSchedule(literal, out var errorMessage)) + { + consumer.AddHighlighting(new TimerTriggerCronExpressionError(expressionArgument, errorMessage)); + } + } + + private static bool IsValidCrontabSchedule(string literal, out string? errorMessage) + { + try + { + var normalizedLiteral = NormalizeCronSchedule(literal); + CrontabSchedule.Parse(normalizedLiteral, new CrontabSchedule.ParseOptions {IncludingSeconds = true}); + errorMessage = null; + return true; + } + catch (CrontabException e) + { + errorMessage = e.Message; + return false; + } + } + + private static bool IsValidTimeSpanSchedule(string literal, out string? errorMessage) + { + // See https://github.com/Azure/azure-webjobs-sdk-extensions/blob/dev/src/WebJobs.Extensions/Extensions/Timers/Scheduling/TimerSchedule.cs#L77 + try + { + // ReSharper disable once ReturnValueOfPureMethodIsNotUsed + TimeSpan.Parse(literal); + errorMessage = null; + return true; + } + catch (FormatException e) + { + errorMessage = e.Message; + return false; + } + } + + /// + /// NCRONTAB expression supports both five field and six field format. + /// The sixth field position is a value for seconds which is placed at the beginning of the expression. + /// + /// This method converts a five field format to a six field format by prepending "0 " when needed. + /// + /// + /// + private static string NormalizeCronSchedule(string cronSchedule) + { + var numberOfFields = cronSchedule.Trim() + .Replace(@"\t", " ") + .Split(new [] { ' ' }, StringSplitOptions.RemoveEmptyEntries) + .Length; + + if (numberOfFields == 5) + { + return "0 " + cronSchedule; + } + + return cronSchedule; + } +} \ No newline at end of file diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Daemon/Highlighters/AzureHighlightingGroupIds.cs b/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Daemon/Highlighters/AzureHighlightingGroupIds.cs new file mode 100644 index 0000000000..a04b02d161 --- /dev/null +++ b/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Daemon/Highlighters/AzureHighlightingGroupIds.cs @@ -0,0 +1,12 @@ +// Copyright 2018-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the MIT license. + +using JetBrains.ReSharper.Feature.Services.Daemon; + +namespace JetBrains.ReSharper.Azure.Daemon.Highlighters; + +// RegisterConfigurableHighlightingsGroup registers a group in Inspection Severity +[RegisterConfigurableHighlightingsGroup(FunctionApp, "Function App inspections")] +public static class AzureHighlightingGroupIds +{ + public const string FunctionApp = "FUNCTION_APP"; +} \ No newline at end of file diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Daemon/ZoneMarker.cs b/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Daemon/ZoneMarker.cs new file mode 100644 index 0000000000..392c3fe229 --- /dev/null +++ b/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Daemon/ZoneMarker.cs @@ -0,0 +1,10 @@ +// Copyright 2018-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the MIT license. + +using JetBrains.Application.BuildScript.Application.Zones; +using JetBrains.ReSharper.Feature.Services; +using JetBrains.ReSharper.Psi.CSharp; + +namespace JetBrains.ReSharper.Azure.Daemon; + +[ZoneMarker] +public class ZoneMarker : IRequire, IRequire; \ No newline at end of file diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Intellisense/ZoneMarker.cs b/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Intellisense/ZoneMarker.cs index 8e6446b566..80ea91775c 100644 --- a/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Intellisense/ZoneMarker.cs +++ b/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Intellisense/ZoneMarker.cs @@ -4,8 +4,7 @@ using JetBrains.ReSharper.Feature.Services; using JetBrains.ReSharper.Psi.CSharp; -namespace JetBrains.ReSharper.Azure.Intellisense -{ - [ZoneMarker] - public class ZoneMarker : IRequire, IRequire; -} +namespace JetBrains.ReSharper.Azure.Intellisense; + +[ZoneMarker] +public class ZoneMarker : IRequire, IRequire; \ No newline at end of file diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Project/ZoneMarker.cs b/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Project/ZoneMarker.cs index 814746dcb8..0f77913ac5 100644 --- a/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Project/ZoneMarker.cs +++ b/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Project/ZoneMarker.cs @@ -1,29 +1,10 @@ -// Copyright (c) 2020 JetBrains s.r.o. -// -// All rights reserved. -// -// MIT License -// -// 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. +// Copyright 2018-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the MIT license. using JetBrains.Application.BuildScript.Application.Zones; using JetBrains.ProjectModel; using JetBrains.ReSharper.Psi.CSharp; -namespace JetBrains.ReSharper.Azure.Project -{ - [ZoneMarker] - public class ZoneMarker : IRequire, IRequire; -} +namespace JetBrains.ReSharper.Azure.Project; + +[ZoneMarker] +public class ZoneMarker : IRequire, IRequire; \ No newline at end of file diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Psi/ZoneMarker.cs b/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Psi/ZoneMarker.cs index 06a2b5ae45..d6d605f7e7 100644 --- a/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Psi/ZoneMarker.cs +++ b/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Psi/ZoneMarker.cs @@ -1,31 +1,10 @@ -// Copyright (c) 2020 JetBrains s.r.o. -// -// All rights reserved. -// -// MIT License -// -// 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. +// Copyright 2018-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the MIT license. using JetBrains.Application.BuildScript.Application.Zones; using JetBrains.ReSharper.Psi.CSharp; using JetBrains.ReSharper.Resources.Shell; -namespace JetBrains.ReSharper.Azure.Psi -{ - [ZoneMarker] - public class ZoneMarker : IRequire, IRequire - { - } -} +namespace JetBrains.ReSharper.Azure.Psi; + +[ZoneMarker] +public class ZoneMarker : IRequire, IRequire; \ No newline at end of file From 072c9b25a309fcbb13317ce75662bcf3190af73c Mon Sep 17 00:00:00 2001 From: Rival Abdrakhmanov Date: Mon, 20 Nov 2023 16:57:02 +0100 Subject: [PATCH 5/5] Add protocol --- .../azure-toolkit-for-rider/.gitignore | 6 - .../azure-toolkit-for-rider/.idea/gradle.xml | 1 + .../build.gradle.kts | 2 + .../AzureFunctionsVersionInspection.kt | 5 +- ...olsMsBuild.kt => FunctionCoreToolsInfo.kt} | 2 +- ...er.kt => FunctionCoreToolsInfoProvider.kt} | 18 +- ...Manager.kt => FunctionCoreToolsManager.kt} | 6 +- .../FunctionCoreToolsMsBuildService.kt | 23 ++ .../coreTools/FunctionsCoreToolsInfo.kt | 7 - .../daemon/AzureRunnableProjectKinds.kt | 11 + .../daemon/FunctionAppSolutionExtListener.kt | 83 +++++ .../templates/FunctionTemplateManager.kt | 4 +- .../templates/InstallFunctionToolComponent.kt | 4 +- ...zure-intellij-plugin-appservice-dotnet.xml | 3 + .../internal/Trigger Azure Function.http.ft | 21 ++ .../build.gradle.kts | 3 + .../FunctionAppDaemonModel.Generated.kt | 241 +++++++++++++ .../azure-toolkit-for-rider/build.gradle.kts | 17 +- .../model/daemon/FunctionAppDaemonModel.kt | 29 +- .../settings.gradle.kts | 1 + .../Errors/FunctionAppErrors.Generated.cs | 74 ++++ .../FunctionApp/FunctionAppDaemonHost.cs | 77 ++++ .../FunctionAppDaemonModel.Generated.cs | 341 ++++++++++++++++++ .../FunctionAppRunMarkerAttributeIds.cs | 16 + .../FunctionAppRunMarkerGutterMark.cs | 94 +++++ .../FunctionAppRunMarkerProvider.cs | 47 +++ .../FunctionAppRunMarkersThemedIcons.cs | 134 +++++++ 27 files changed, 1207 insertions(+), 63 deletions(-) rename PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/coreTools/{FunctionsCoreToolsMsBuild.kt => FunctionCoreToolsInfo.kt} (67%) rename PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/coreTools/{FunctionsCoreToolsInfoProvider.kt => FunctionCoreToolsInfoProvider.kt} (91%) rename PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/coreTools/{FunctionsCoreToolsManager.kt => FunctionCoreToolsManager.kt} (98%) create mode 100644 PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/coreTools/FunctionCoreToolsMsBuildService.kt delete mode 100644 PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/coreTools/FunctionsCoreToolsInfo.kt create mode 100644 PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/daemon/AzureRunnableProjectKinds.kt create mode 100644 PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/daemon/FunctionAppSolutionExtListener.kt create mode 100644 PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/resources/fileTemplates/internal/Trigger Azure Function.http.ft create mode 100644 PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-resharper-host/build.gradle.kts create mode 100644 PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-resharper-host/src/main/kotlin/org/jetbrains/protocol/FunctionAppDaemonModel.Generated.kt create mode 100644 PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Daemon/Errors/FunctionAppErrors.Generated.cs create mode 100644 PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Daemon/FunctionApp/FunctionAppDaemonHost.cs create mode 100644 PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Daemon/Protocol/FunctionAppDaemonModel.Generated.cs create mode 100644 PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Daemon/RunMarkers/FunctionAppRunMarkerAttributeIds.cs create mode 100644 PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Daemon/RunMarkers/FunctionAppRunMarkerGutterMark.cs create mode 100644 PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Daemon/RunMarkers/FunctionAppRunMarkerProvider.cs create mode 100644 PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Daemon/RunMarkers/FunctionAppRunMarkersThemedIcons.cs diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/.gitignore b/PluginsAndFeatures/azure-toolkit-for-rider/.gitignore index aee25c300d..7328419566 100644 --- a/PluginsAndFeatures/azure-toolkit-for-rider/.gitignore +++ b/PluginsAndFeatures/azure-toolkit-for-rider/.gitignore @@ -40,12 +40,6 @@ bin/ # Jar dependencies generated in build **/resources/spark/spark-tools-*.jar -# Rider Protocol generated files -*Generated.kt - -# Rider Protocol and Inspections generated files -*Generated.cs - # Build results [Dd]ebug/ [Rr]elease/ diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/.idea/gradle.xml b/PluginsAndFeatures/azure-toolkit-for-rider/.idea/gradle.xml index 280e7efc6c..a8940e320f 100644 --- a/PluginsAndFeatures/azure-toolkit-for-rider/.idea/gradle.xml +++ b/PluginsAndFeatures/azure-toolkit-for-rider/.idea/gradle.xml @@ -20,6 +20,7 @@ diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/build.gradle.kts b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/build.gradle.kts index 0176a7ee1a..e1cf2975b6 100644 --- a/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/build.gradle.kts +++ b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/build.gradle.kts @@ -13,6 +13,8 @@ dependencies { runtimeOnly(project(path = ":azure-intellij-plugin-appservice", configuration = "instrumentedJar")) compileOnly(project(path = ":azure-intellij-resource-connector-lib")) runtimeOnly(project(path = ":azure-intellij-resource-connector-lib", configuration = "instrumentedJar")) + compileOnly(project(path = ":azure-intellij-plugin-resharper-host")) + runtimeOnly(project(path = ":azure-intellij-plugin-resharper-host", configuration = "instrumentedJar")) implementation("com.microsoft.azure:azure-toolkit-appservice-lib") implementation("com.microsoft.azure:azure-toolkit-ide-appservice-lib") implementation("com.microsoft.azure:azure-toolkit-ide-containerregistry-lib") diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/codeInspection/msbuild/AzureFunctionsVersionInspection.kt b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/codeInspection/msbuild/AzureFunctionsVersionInspection.kt index 7af0a4584c..cc3e6eaeec 100644 --- a/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/codeInspection/msbuild/AzureFunctionsVersionInspection.kt +++ b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/codeInspection/msbuild/AzureFunctionsVersionInspection.kt @@ -14,9 +14,12 @@ import com.intellij.psi.xml.XmlElementType import com.intellij.psi.xml.XmlTag import com.intellij.xml.util.XmlUtil import com.microsoft.azure.toolkit.intellij.legacy.function.FUNCTIONS_CORE_TOOLS_KNOWN_SUPPORTED_VERSIONS -import com.microsoft.azure.toolkit.intellij.legacy.function.coreTools.PROPERTY_AZURE_FUNCTIONS_VERSION class AzureFunctionsVersionInspection : XmlSuppressableInspectionTool() { + companion object { + const val PROPERTY_AZURE_FUNCTIONS_VERSION = "AzureFunctionsVersion" + } + override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean) = object : XmlElementVisitor() { override fun visitXmlTag(tag: XmlTag) { val tagName = tag.name.lowercase() diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/coreTools/FunctionsCoreToolsMsBuild.kt b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/coreTools/FunctionCoreToolsInfo.kt similarity index 67% rename from PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/coreTools/FunctionsCoreToolsMsBuild.kt rename to PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/coreTools/FunctionCoreToolsInfo.kt index d9dd03a613..d4800c6f4f 100644 --- a/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/coreTools/FunctionsCoreToolsMsBuild.kt +++ b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/coreTools/FunctionCoreToolsInfo.kt @@ -4,4 +4,4 @@ package com.microsoft.azure.toolkit.intellij.legacy.function.coreTools -const val PROPERTY_AZURE_FUNCTIONS_VERSION = "AzureFunctionsVersion" \ No newline at end of file +data class FunctionCoreToolsInfo(val coreToolsPath: String, val coreToolsExecutable: String) diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/coreTools/FunctionsCoreToolsInfoProvider.kt b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/coreTools/FunctionCoreToolsInfoProvider.kt similarity index 91% rename from PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/coreTools/FunctionsCoreToolsInfoProvider.kt rename to PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/coreTools/FunctionCoreToolsInfoProvider.kt index 2e298ef34b..f418f897fe 100644 --- a/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/coreTools/FunctionsCoreToolsInfoProvider.kt +++ b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/coreTools/FunctionCoreToolsInfoProvider.kt @@ -17,17 +17,17 @@ import com.microsoft.azure.toolkit.lib.appservice.utils.FunctionCliResolver import java.io.File @Service -class FunctionsCoreToolsInfoProvider { +class FunctionCoreToolsInfoProvider { companion object { - fun getInstance(): FunctionsCoreToolsInfoProvider = service() + fun getInstance(): FunctionCoreToolsInfoProvider = service() - private val LOG = logger() + private val LOG = logger() } suspend fun retrieveForVersion( azureFunctionsVersion: String, allowDownload: Boolean - ): FunctionsCoreToolsInfo? { + ): FunctionCoreToolsInfo? { application.assertIsNonDispatchThread() val coreToolsFromConfiguration = retrieveFromConfiguration(azureFunctionsVersion) @@ -43,7 +43,7 @@ class FunctionsCoreToolsInfoProvider { return null } - private fun retrieveFromConfiguration(azureFunctionsVersion: String): FunctionsCoreToolsInfo? { + private fun retrieveFromConfiguration(azureFunctionsVersion: String): FunctionCoreToolsInfo? { val settings = AzureFunctionSettings.getInstance() val toolsPathEntries = settings.azureCoreToolsPathEntries LOG.debug("Azure Core Tools path entries: ${toolsPathEntries.joinToString { "${it.functionsVersion}: ${it.coreToolsPath}" }}") @@ -73,8 +73,8 @@ class FunctionsCoreToolsInfoProvider { private suspend fun retrieveFromFeed( azureFunctionsVersion: String, allowDownload: Boolean - ): FunctionsCoreToolsInfo? { - val coreToolsPathFromFeed = FunctionsCoreToolsManager.getInstance().demandCoreToolsPathForVersion( + ): FunctionCoreToolsInfo? { + val coreToolsPathFromFeed = FunctionCoreToolsManager.getInstance().demandCoreToolsPathForVersion( azureFunctionsVersion, Registry.get("azure.function_app.core_tools.feed.url").asString(), allowDownload @@ -86,7 +86,7 @@ class FunctionsCoreToolsInfoProvider { return null } - private fun resolveFromPath(funcCoreToolsPath: File): FunctionsCoreToolsInfo? { + private fun resolveFromPath(funcCoreToolsPath: File): FunctionCoreToolsInfo? { val patchedPath = patchCoreToolsPath(funcCoreToolsPath) val executablePath = if (SystemInfo.isWindows) { @@ -108,7 +108,7 @@ class FunctionsCoreToolsInfoProvider { } } - return FunctionsCoreToolsInfo(patchedPath.path, executablePath.path) + return FunctionCoreToolsInfo(patchedPath.path, executablePath.path) } private fun patchCoreToolsPath(funcCoreToolsPath: File): File { diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/coreTools/FunctionsCoreToolsManager.kt b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/coreTools/FunctionCoreToolsManager.kt similarity index 98% rename from PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/coreTools/FunctionsCoreToolsManager.kt rename to PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/coreTools/FunctionCoreToolsManager.kt index e9a44f5c3b..c011ea8119 100644 --- a/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/coreTools/FunctionsCoreToolsManager.kt +++ b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/coreTools/FunctionCoreToolsManager.kt @@ -23,11 +23,11 @@ import java.io.IOException import java.net.UnknownHostException @Service -class FunctionsCoreToolsManager { +class FunctionCoreToolsManager { companion object { - fun getInstance(): FunctionsCoreToolsManager = service() + fun getInstance(): FunctionCoreToolsManager = service() - private val LOG = logger() + private val LOG = logger() } private val releaseCache = concurrentMapOf() diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/coreTools/FunctionCoreToolsMsBuildService.kt b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/coreTools/FunctionCoreToolsMsBuildService.kt new file mode 100644 index 0000000000..3853a92857 --- /dev/null +++ b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/coreTools/FunctionCoreToolsMsBuildService.kt @@ -0,0 +1,23 @@ +/* + * Copyright 2018-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the MIT license. + */ + +package com.microsoft.azure.toolkit.intellij.legacy.function.coreTools + +import com.intellij.openapi.components.Service +import com.intellij.openapi.components.service +import com.intellij.openapi.project.Project +import com.jetbrains.rider.azure.model.AzureFunctionsVersionRequest +import com.jetbrains.rider.azure.model.functionAppDaemonModel +import com.jetbrains.rider.projectView.solution + +@Service +class FunctionCoreToolsMsBuildService { + companion object { + fun getInstance(): FunctionCoreToolsMsBuildService = service() + } + + suspend fun requestAzureFunctionsVersion(project: Project, projectFilePath: String) = + project.solution.functionAppDaemonModel.getAzureFunctionsVersion + .startSuspending(AzureFunctionsVersionRequest(projectFilePath)) +} \ No newline at end of file diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/coreTools/FunctionsCoreToolsInfo.kt b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/coreTools/FunctionsCoreToolsInfo.kt deleted file mode 100644 index 3c6c916308..0000000000 --- a/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/coreTools/FunctionsCoreToolsInfo.kt +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Copyright 2018-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the MIT license. - */ - -package com.microsoft.azure.toolkit.intellij.legacy.function.coreTools - -data class FunctionsCoreToolsInfo(val coreToolsPath: String, val coreToolsExecutable: String) diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/daemon/AzureRunnableProjectKinds.kt b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/daemon/AzureRunnableProjectKinds.kt new file mode 100644 index 0000000000..fedb0731af --- /dev/null +++ b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/daemon/AzureRunnableProjectKinds.kt @@ -0,0 +1,11 @@ +/* + * Copyright 2018-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the MIT license. + */ + +package com.microsoft.azure.toolkit.intellij.legacy.function.daemon + +import com.jetbrains.rider.model.RunnableProjectKind + +object AzureRunnableProjectKinds { + val AzureFunctions = RunnableProjectKind("AzureFunctions") +} \ No newline at end of file diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/daemon/FunctionAppSolutionExtListener.kt b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/daemon/FunctionAppSolutionExtListener.kt new file mode 100644 index 0000000000..dea1ec936a --- /dev/null +++ b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/daemon/FunctionAppSolutionExtListener.kt @@ -0,0 +1,83 @@ +/* + * Copyright 2018-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the MIT license. + */ + +@file:Suppress("UnstableApiUsage") + +package com.microsoft.azure.toolkit.intellij.legacy.function.daemon + +import com.intellij.execution.Executor +import com.intellij.execution.RunManager +import com.intellij.execution.RunnerAndConfigurationSettings +import com.intellij.execution.executors.DefaultDebugExecutor +import com.intellij.execution.executors.DefaultRunExecutor +import com.intellij.openapi.client.ClientProjectSession +import com.intellij.openapi.project.Project +import com.jetbrains.rd.protocol.SolutionExtListener +import com.jetbrains.rd.ui.bedsl.extensions.valueOrEmpty +import com.jetbrains.rd.util.lifetime.Lifetime +import com.jetbrains.rider.azure.model.FunctionAppDaemonModel +import com.jetbrains.rider.model.RunnableProject +import com.jetbrains.rider.model.runnableProjectsModel +import com.jetbrains.rider.projectView.solution + +class FunctionAppSolutionExtListener : SolutionExtListener { + override fun extensionCreated(lifetime: Lifetime, session: ClientProjectSession, model: FunctionAppDaemonModel) { + model.runFunctionApp.advise(lifetime) { + runConfiguration( + functionName = it.functionName, + runnableProject = getRunnableProject(session.project, it.projectFilePath), + executor = DefaultRunExecutor.getRunExecutorInstance(), + project = session.project + ) + } + model.debugFunctionApp.advise(lifetime) { + runConfiguration( + functionName = it.functionName, + runnableProject = getRunnableProject(session.project, it.projectFilePath), + executor = DefaultDebugExecutor.getDebugExecutorInstance(), + project = session.project + ) + } + model.triggerFunctionApp.advise(lifetime) { +// val triggerAction = TriggerAzureFunctionAction(functionName = triggerFunctionRequest.functionName) +// +// ActionUtil.invokeAction( +// triggerAction, +// SimpleDataContext.getProjectContext(project), +// ActionPlaces.EDITOR_GUTTER_POPUP, +// null, +// null +// ) + } + } + + private fun getRunnableProject(project: Project, expectedProjectPath: String): RunnableProject { + val runnableProjects = project.solution.runnableProjectsModel.projects.valueOrEmpty() + return runnableProjects.find { runnableProject -> + runnableProject.projectFilePath == expectedProjectPath && runnableProject.kind == AzureRunnableProjectKinds.AzureFunctions + } + ?: throw IllegalStateException( + "Unable to find a project to run with path: '$expectedProjectPath', available project paths: " + + runnableProjects.joinToString(", ", "'", "'") { it.projectFilePath } + ) + } + + private fun runConfiguration( + functionName: String?, + runnableProject: RunnableProject, + executor: Executor, + project: Project + ) { + val runManager = RunManager.getInstance(project) + val existingSettings = findExistingConfigurationSettings(functionName, runnableProject.projectFilePath) + + } + + private fun findExistingConfigurationSettings( + functionName: String?, + projectFilePath: String + ): RunnerAndConfigurationSettings? { + return null + } +} \ No newline at end of file diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/templates/FunctionTemplateManager.kt b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/templates/FunctionTemplateManager.kt index f1c5c241f4..f6f9abb00b 100644 --- a/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/templates/FunctionTemplateManager.kt +++ b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/templates/FunctionTemplateManager.kt @@ -12,7 +12,7 @@ import com.intellij.openapi.diagnostic.logger import com.intellij.util.application import com.jetbrains.rider.projectView.actions.projectTemplating.backend.ReSharperProjectTemplateProvider import com.microsoft.azure.toolkit.intellij.legacy.function.FUNCTIONS_CORE_TOOLS_LATEST_SUPPORTED_VERSION -import com.microsoft.azure.toolkit.intellij.legacy.function.coreTools.FunctionsCoreToolsInfoProvider +import com.microsoft.azure.toolkit.intellij.legacy.function.coreTools.FunctionCoreToolsInfoProvider import java.io.File @Service @@ -33,7 +33,7 @@ class FunctionTemplateManager { application.assertIsNonDispatchThread() // Determine core tools info for the latest supported Azure Functions version - val toolsInfoProvider = FunctionsCoreToolsInfoProvider.getInstance() + val toolsInfoProvider = FunctionCoreToolsInfoProvider.getInstance() val coreToolsInfo = toolsInfoProvider.retrieveForVersion( FUNCTIONS_CORE_TOOLS_LATEST_SUPPORTED_VERSION, false diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/templates/InstallFunctionToolComponent.kt b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/templates/InstallFunctionToolComponent.kt index 37b79fd0b6..e800a83d73 100644 --- a/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/templates/InstallFunctionToolComponent.kt +++ b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/templates/InstallFunctionToolComponent.kt @@ -15,7 +15,7 @@ import com.intellij.ui.dsl.builder.panel import com.jetbrains.rd.util.reactive.IProperty import com.jetbrains.rider.ui.components.base.Viewable import com.microsoft.azure.toolkit.intellij.legacy.function.FUNCTIONS_CORE_TOOLS_LATEST_SUPPORTED_VERSION -import com.microsoft.azure.toolkit.intellij.legacy.function.coreTools.FunctionsCoreToolsInfoProvider +import com.microsoft.azure.toolkit.intellij.legacy.function.coreTools.FunctionCoreToolsInfoProvider import javax.swing.JComponent import javax.swing.JPanel @@ -38,7 +38,7 @@ class InstallFunctionToolComponent(private val validationError: IProperty + + diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/resources/fileTemplates/internal/Trigger Azure Function.http.ft b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/resources/fileTemplates/internal/Trigger Azure Function.http.ft new file mode 100644 index 0000000000..dca6434e13 --- /dev/null +++ b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/resources/fileTemplates/internal/Trigger Azure Function.http.ft @@ -0,0 +1,21 @@ +#set($comment = '#') +${comment} Trigger Azure Function - ${functionName} +${comment} +${comment} More information can be found in the Azure Functions documentation, +${comment} as well as examples on how to pass test data to a function: +${comment} https://docs.microsoft.com/en-us/azure/azure-functions/functions-run-local#passing-test-data-to-a-function +${comment} +${comment} Make sure to update the below calls to suit your function host and port. +${comment} +${comment} Call the following endpoint to locally run HTTP and webhook-triggered functions: + +GET http://localhost:7071/api/${functionName} + +${comment}${comment}${comment} + +${comment} Call the following administrative endpoint to trigger non-HTTP functions: + +POST http://localhost:7071/admin/functions/${functionName} +Content-Type: application/json + +{} \ No newline at end of file diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-resharper-host/build.gradle.kts b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-resharper-host/build.gradle.kts new file mode 100644 index 0000000000..3d0beb76b1 --- /dev/null +++ b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-resharper-host/build.gradle.kts @@ -0,0 +1,3 @@ +plugins { + id("org.jetbrains.kotlin.jvm") +} \ No newline at end of file diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-resharper-host/src/main/kotlin/org/jetbrains/protocol/FunctionAppDaemonModel.Generated.kt b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-resharper-host/src/main/kotlin/org/jetbrains/protocol/FunctionAppDaemonModel.Generated.kt new file mode 100644 index 0000000000..10238458a3 --- /dev/null +++ b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-resharper-host/src/main/kotlin/org/jetbrains/protocol/FunctionAppDaemonModel.Generated.kt @@ -0,0 +1,241 @@ +@file:Suppress("EXPERIMENTAL_API_USAGE","EXPERIMENTAL_UNSIGNED_LITERALS","PackageDirectoryMismatch","UnusedImport","unused","LocalVariableName","CanBeVal","PropertyName","EnumEntryName","ClassName","ObjectPropertyName","UnnecessaryVariable","SpellCheckingInspection") +package com.jetbrains.rider.azure.model + +import com.jetbrains.rd.framework.* +import com.jetbrains.rd.framework.base.* +import com.jetbrains.rd.framework.impl.* + +import com.jetbrains.rd.util.lifetime.* +import com.jetbrains.rd.util.reactive.* +import com.jetbrains.rd.util.string.* +import com.jetbrains.rd.util.* +import kotlin.time.Duration +import kotlin.reflect.KClass +import kotlin.jvm.JvmStatic + + + +/** + * #### Generated from [FunctionAppDaemonModel.kt:14] + */ +class FunctionAppDaemonModel private constructor( + private val _runFunctionApp: RdSignal, + private val _debugFunctionApp: RdSignal, + private val _triggerFunctionApp: RdSignal, + private val _getAzureFunctionsVersion: RdCall +) : RdExtBase() { + //companion + + companion object : ISerializersOwner { + + override fun registerSerializersCore(serializers: ISerializers) { + serializers.register(FunctionAppRequest) + serializers.register(AzureFunctionsVersionRequest) + } + + + + + private val __StringNullableSerializer = FrameworkMarshallers.String.nullable() + + const val serializationHash = 8720132529663507412L + + } + override val serializersOwner: ISerializersOwner get() = FunctionAppDaemonModel + override val serializationHash: Long get() = FunctionAppDaemonModel.serializationHash + + //fields + + /** + * Signal from backend to run a Function App locally. + */ + val runFunctionApp: ISource get() = _runFunctionApp + + /** + * Signal from backend to debug a Function App locally. + */ + val debugFunctionApp: ISource get() = _debugFunctionApp + + /** + * Signal from backend to trigger a Function App. + */ + val triggerFunctionApp: ISource get() = _triggerFunctionApp + + /** + * Request from frontend to read the AzureFunctionsVersion MSBuild property. + */ + val getAzureFunctionsVersion: IRdCall get() = _getAzureFunctionsVersion + //methods + //initializer + init { + bindableChildren.add("runFunctionApp" to _runFunctionApp) + bindableChildren.add("debugFunctionApp" to _debugFunctionApp) + bindableChildren.add("triggerFunctionApp" to _triggerFunctionApp) + bindableChildren.add("getAzureFunctionsVersion" to _getAzureFunctionsVersion) + } + + //secondary constructor + internal constructor( + ) : this( + RdSignal(FunctionAppRequest), + RdSignal(FunctionAppRequest), + RdSignal(FunctionAppRequest), + RdCall(AzureFunctionsVersionRequest, __StringNullableSerializer) + ) + + //equals trait + //hash code trait + //pretty print + override fun print(printer: PrettyPrinter) { + printer.println("FunctionAppDaemonModel (") + printer.indent { + print("runFunctionApp = "); _runFunctionApp.print(printer); println() + print("debugFunctionApp = "); _debugFunctionApp.print(printer); println() + print("triggerFunctionApp = "); _triggerFunctionApp.print(printer); println() + print("getAzureFunctionsVersion = "); _getAzureFunctionsVersion.print(printer); println() + } + printer.print(")") + } + //deepClone + override fun deepClone(): FunctionAppDaemonModel { + return FunctionAppDaemonModel( + _runFunctionApp.deepClonePolymorphic(), + _debugFunctionApp.deepClonePolymorphic(), + _triggerFunctionApp.deepClonePolymorphic(), + _getAzureFunctionsVersion.deepClonePolymorphic() + ) + } + //contexts + //threading + override val extThreading: ExtThreadingKind get() = ExtThreadingKind.Default +} +val com.jetbrains.rd.ide.model.Solution.functionAppDaemonModel get() = getOrCreateExtension("functionAppDaemonModel", ::FunctionAppDaemonModel) + + + +/** + * #### Generated from [FunctionAppDaemonModel.kt:21] + */ +data class AzureFunctionsVersionRequest ( + val projectFilePath: String +) : IPrintable { + //companion + + companion object : IMarshaller { + override val _type: KClass = AzureFunctionsVersionRequest::class + + @Suppress("UNCHECKED_CAST") + override fun read(ctx: SerializationCtx, buffer: AbstractBuffer): AzureFunctionsVersionRequest { + val projectFilePath = buffer.readString() + return AzureFunctionsVersionRequest(projectFilePath) + } + + override fun write(ctx: SerializationCtx, buffer: AbstractBuffer, value: AzureFunctionsVersionRequest) { + buffer.writeString(value.projectFilePath) + } + + + } + //fields + //methods + //initializer + //secondary constructor + //equals trait + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other == null || other::class != this::class) return false + + other as AzureFunctionsVersionRequest + + if (projectFilePath != other.projectFilePath) return false + + return true + } + //hash code trait + override fun hashCode(): Int { + var __r = 0 + __r = __r*31 + projectFilePath.hashCode() + return __r + } + //pretty print + override fun print(printer: PrettyPrinter) { + printer.println("AzureFunctionsVersionRequest (") + printer.indent { + print("projectFilePath = "); projectFilePath.print(printer); println() + } + printer.print(")") + } + //deepClone + //contexts + //threading +} + + +/** + * #### Generated from [FunctionAppDaemonModel.kt:15] + */ +data class FunctionAppRequest ( + val methodName: String?, + val functionName: String?, + val projectFilePath: String +) : IPrintable { + //companion + + companion object : IMarshaller { + override val _type: KClass = FunctionAppRequest::class + + @Suppress("UNCHECKED_CAST") + override fun read(ctx: SerializationCtx, buffer: AbstractBuffer): FunctionAppRequest { + val methodName = buffer.readNullable { buffer.readString() } + val functionName = buffer.readNullable { buffer.readString() } + val projectFilePath = buffer.readString() + return FunctionAppRequest(methodName, functionName, projectFilePath) + } + + override fun write(ctx: SerializationCtx, buffer: AbstractBuffer, value: FunctionAppRequest) { + buffer.writeNullable(value.methodName) { buffer.writeString(it) } + buffer.writeNullable(value.functionName) { buffer.writeString(it) } + buffer.writeString(value.projectFilePath) + } + + + } + //fields + //methods + //initializer + //secondary constructor + //equals trait + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other == null || other::class != this::class) return false + + other as FunctionAppRequest + + if (methodName != other.methodName) return false + if (functionName != other.functionName) return false + if (projectFilePath != other.projectFilePath) return false + + return true + } + //hash code trait + override fun hashCode(): Int { + var __r = 0 + __r = __r*31 + if (methodName != null) methodName.hashCode() else 0 + __r = __r*31 + if (functionName != null) functionName.hashCode() else 0 + __r = __r*31 + projectFilePath.hashCode() + return __r + } + //pretty print + override fun print(printer: PrettyPrinter) { + printer.println("FunctionAppRequest (") + printer.indent { + print("methodName = "); methodName.print(printer); println() + print("functionName = "); functionName.print(printer); println() + print("projectFilePath = "); projectFilePath.print(printer); println() + } + printer.print(")") + } + //deepClone + //contexts + //threading +} diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/build.gradle.kts b/PluginsAndFeatures/azure-toolkit-for-rider/build.gradle.kts index 5529fc3d7a..e3af027f90 100644 --- a/PluginsAndFeatures/azure-toolkit-for-rider/build.gradle.kts +++ b/PluginsAndFeatures/azure-toolkit-for-rider/build.gradle.kts @@ -171,7 +171,10 @@ tasks { val copyIcons by registering(Copy::class) { description = "Copies the icons directory of the base plugin." - from(projectDir.resolve("..").resolve("azure-toolkit-for-intellij").resolve("src").resolve("main").resolve("resources").resolve("icons")) + from( + projectDir.resolve("..").resolve("azure-toolkit-for-intellij").resolve("src").resolve("main") + .resolve("resources").resolve("icons") + ) into(projectDir.resolve("src").resolve("main").resolve("resources").resolve("icons")) } @@ -185,7 +188,7 @@ tasks { } } - buildPlugin { + buildPlugin { dependsOn(copyIcons) dependsOn(compileDotNet) } @@ -196,11 +199,11 @@ tasks { configure { val modelDir = projectDir.resolve("protocol").resolve("src").resolve("main") - .resolve("kotlin") - val csDaemonGeneratedOutput = projectDir.resolve("ReSharper.Azure").resolve("src") + .resolve("kotlin").resolve("model").resolve("daemon") + val csGeneratedOutput = projectDir.resolve("src").resolve("dotnet").resolve("ReSharper.Azure") .resolve("Azure.Daemon").resolve("Protocol") - val ktGeneratedOutput = projectDir.resolve("src").resolve("main").resolve("kotlin") - .resolve("org").resolve("jetbrains").resolve("protocol") + val ktGeneratedOutput = projectDir.resolve("azure-intellij-plugin-resharper-host").resolve("src") + .resolve("main").resolve("kotlin").resolve("org").resolve("jetbrains").resolve("protocol") verbose = true hashFolder = "build/rdgen" @@ -224,7 +227,7 @@ tasks { transform = "reversed" root = "com.jetbrains.rider.model.nova.ide.IdeRoot" namespace = "JetBrains.Rider.Azure.Model" - directory = csDaemonGeneratedOutput.canonicalPath + directory = csGeneratedOutput.canonicalPath } } prepareSandbox { diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/protocol/src/main/kotlin/model/daemon/FunctionAppDaemonModel.kt b/PluginsAndFeatures/azure-toolkit-for-rider/protocol/src/main/kotlin/model/daemon/FunctionAppDaemonModel.kt index fc1bca5ff0..7188ae806f 100644 --- a/PluginsAndFeatures/azure-toolkit-for-rider/protocol/src/main/kotlin/model/daemon/FunctionAppDaemonModel.kt +++ b/PluginsAndFeatures/azure-toolkit-for-rider/protocol/src/main/kotlin/model/daemon/FunctionAppDaemonModel.kt @@ -1,23 +1,5 @@ -/** - * Copyright (c) 2020 JetBrains s.r.o. - * - * All rights reserved. - * - * MIT License - * - * 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. +/* + * Copyright 2018-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the MIT license. */ package model.daemon @@ -26,16 +8,13 @@ import com.jetbrains.rd.generator.nova.* import com.jetbrains.rd.generator.nova.PredefinedType.string import com.jetbrains.rd.generator.nova.csharp.CSharp50Generator import com.jetbrains.rd.generator.nova.kotlin.Kotlin11Generator -import com.jetbrains.rd.generator.nova.util.syspropertyOrInvalid -import com.jetbrains.rider.model.nova.ide.IdeRoot import com.jetbrains.rider.model.nova.ide.SolutionModel -import java.io.File @Suppress("unused") object FunctionAppDaemonModel : Ext(SolutionModel.Solution) { private val FunctionAppRequest = structdef { - field("methodName", string) - field("functionName", string) + field("methodName", string.nullable) + field("functionName", string.nullable) field("projectFilePath", string) } diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/settings.gradle.kts b/PluginsAndFeatures/azure-toolkit-for-rider/settings.gradle.kts index 31ac5ae350..1883b95d68 100644 --- a/PluginsAndFeatures/azure-toolkit-for-rider/settings.gradle.kts +++ b/PluginsAndFeatures/azure-toolkit-for-rider/settings.gradle.kts @@ -20,6 +20,7 @@ pluginManagement { } include("protocol") +include("azure-intellij-plugin-resharper-host") include(":azure-intellij-plugin-lib") project(":azure-intellij-plugin-lib").projectDir = file("../azure-toolkit-for-intellij/azure-intellij-plugin-lib") include(":azure-intellij-plugin-lib-dotnet") diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Daemon/Errors/FunctionAppErrors.Generated.cs b/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Daemon/Errors/FunctionAppErrors.Generated.cs new file mode 100644 index 0000000000..b015c577a4 --- /dev/null +++ b/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Daemon/Errors/FunctionAppErrors.Generated.cs @@ -0,0 +1,74 @@ +//------------------------------------------------------------------------------ +// +// Generated by JetBrains ErrorDescriptionGenerator +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ +using System; +using System.Collections.Generic; +using System.Linq; +using JetBrains.Application; +using JetBrains.Application.Settings; +using JetBrains.DataFlow; +using JetBrains.Lifetimes; +using JetBrains.Core; +using JetBrains.ReSharper.Psi; +using JetBrains.ReSharper.Daemon; +using JetBrains.ReSharper.Feature.Services.Daemon; +using JetBrains.ReSharper.Feature.Services.Daemon.Attributes; +using JetBrains.DocumentModel; +using JetBrains.ReSharper.Psi.Resolve; +using JetBrains.ReSharper.Psi.Tree; +using JetBrains.Util; +using JetBrains.Application.I18n; +using JetBrains.ReSharper.Azure.Daemon.Errors; +using JetBrains.ReSharper.Azure.Daemon.FunctionApp.Stages.Analysis; +using JetBrains.ReSharper.Azure.Daemon.Highlighters; +using JetBrains.ReSharper.Psi.CSharp; +using JetBrains.ReSharper.Psi.CSharp.Tree; + + +namespace JetBrains.ReSharper.Azure.Daemon.Errors.FunctionAppErrors +{ + #region TimerTriggerCronExpressionError + + [ConfigurableSeverityHighlighting(HIGHLIGHTING_ID, "CSHARP", Languages = "CSHARP", OverlapResolve = OverlapResolveKind.NONE, ToolTipFormatString = MESSAGE)] + public partial class TimerTriggerCronExpressionError : IHighlighting + { + protected const string MESSAGE = "{0}"; + public const string HIGHLIGHTING_ID = "Azure.FunctionApp.TimerTriggerCronExpression"; + + public TimerTriggerCronExpressionError(ICSharpExpression expression, string cronErrorMessage) + { + Expression = expression; + CronErrorMessage = cronErrorMessage; + ToolTip = string.Format(MESSAGE, cronErrorMessage).NON_LOCALIZABLE(); + } + + public ICSharpExpression Expression { get; } + public string CronErrorMessage { get; } + + public /*Localized*/ string ToolTip { get; } + public /*Localized*/ string ErrorStripeToolTip => ToolTip; + + public DocumentRange CalculateRange() + { + return Expression.GetHighlightingRange(); + } + + public bool IsValid() + { + return (Expression == null || Expression.IsValid()); + } + } + + #endregion + +#region Configurable Severity Registrar + [RegisterConfigurableSeverity(TimerTriggerCronExpressionError.HIGHLIGHTING_ID, null, null, null, AzureHighlightingGroupIds.FunctionApp, "Invalid Function App Timer Trigger Cron expression", null, null, "Function App Timer Trigger Cron expression is not valid and can not be used.", null, null, Severity.ERROR)] + public class RegisterSeverityComponentCAC4631F674C122DAC43AAECF236F252D2734D93052808AE491FDDD72FB80E4C + { + } +#endregion +} diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Daemon/FunctionApp/FunctionAppDaemonHost.cs b/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Daemon/FunctionApp/FunctionAppDaemonHost.cs new file mode 100644 index 0000000000..2bceabbe2a --- /dev/null +++ b/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Daemon/FunctionApp/FunctionAppDaemonHost.cs @@ -0,0 +1,77 @@ +// Copyright 2018-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the MIT license. + +using JetBrains.Lifetimes; +using JetBrains.ProjectModel; +using JetBrains.ProjectModel.MSBuild; +using JetBrains.ProjectModel.Properties; +using JetBrains.Rd.Tasks; +using JetBrains.ReSharper.Feature.Services.Protocol; +using JetBrains.ReSharper.Resources.Shell; +using JetBrains.Rider.Azure.Model; +using JetBrains.Util; + +namespace JetBrains.ReSharper.Azure.Daemon.FunctionApp; + +[SolutionComponent] +public class FunctionAppDaemonHost +{ + private readonly ISolution _solution; + private readonly FunctionAppDaemonModel _model; + + public FunctionAppDaemonHost(ISolution solution) + { + _solution = solution; + + _model = solution.GetProtocolSolution().GetFunctionAppDaemonModel(); + _model.GetAzureFunctionsVersion.SetSync(GetAzureFunctionsVersionHandler); + } + + public void RunFunctionApp(string projectFilePath) => _model.RunFunctionApp( + new FunctionAppRequest( + projectFilePath: projectFilePath, + methodName: null, + functionName: null)); + + public void DebugFunctionApp(string projectFilePath) => _model.DebugFunctionApp( + new FunctionAppRequest( + projectFilePath: projectFilePath, + methodName: null, + functionName: null)); + + public void RunFunctionApp(string projectFilePath, string methodName, string functionName) => _model.RunFunctionApp( + new FunctionAppRequest( + projectFilePath: projectFilePath, + methodName: methodName, + functionName: functionName)); + + public void DebugFunctionApp(string projectFilePath, string methodName, string functionName) => + _model.DebugFunctionApp( + new FunctionAppRequest( + projectFilePath: projectFilePath, + methodName: methodName, + functionName: functionName)); + + public void TriggerFunctionApp(string projectFilePath, string methodName, string functionName) => + _model.TriggerFunctionApp( + new FunctionAppRequest( + projectFilePath: projectFilePath, + methodName: methodName, + functionName: functionName)); + + + private string? GetAzureFunctionsVersionHandler(Lifetime lifetime, AzureFunctionsVersionRequest request) + { + var projectFilePath = VirtualFileSystemPath.Parse(request.ProjectFilePath, InteractionContext.SolutionContext); + IProject? project; + using (ReadLockCookie.Create()) + { + project = _solution.FindProjectByProjectFilePath(projectFilePath); + } + + if (project is null) return null; + + var version = project.GetUniqueRequestedProjectProperty(MSBuildProjectUtil.AzureFunctionsVersionProperty); + + return version; + } +} \ No newline at end of file diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Daemon/Protocol/FunctionAppDaemonModel.Generated.cs b/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Daemon/Protocol/FunctionAppDaemonModel.Generated.cs new file mode 100644 index 0000000000..99c38c51b7 --- /dev/null +++ b/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Daemon/Protocol/FunctionAppDaemonModel.Generated.cs @@ -0,0 +1,341 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a RdGen v1.11. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ +using System; +using System.Linq; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using JetBrains.Annotations; + +using JetBrains.Core; +using JetBrains.Diagnostics; +using JetBrains.Collections; +using JetBrains.Collections.Viewable; +using JetBrains.Lifetimes; +using JetBrains.Serialization; +using JetBrains.Rd; +using JetBrains.Rd.Base; +using JetBrains.Rd.Impl; +using JetBrains.Rd.Tasks; +using JetBrains.Rd.Util; +using JetBrains.Rd.Text; + + +// ReSharper disable RedundantEmptyObjectCreationArgumentList +// ReSharper disable InconsistentNaming +// ReSharper disable RedundantOverflowCheckingContext + + +namespace JetBrains.Rider.Azure.Model +{ + + + /// + ///

Generated from: FunctionAppDaemonModel.kt:14

+ ///
+ public class FunctionAppDaemonModel : RdExtBase + { + //fields + //public fields + + /// + /// Signal from backend to run a Function App locally. + /// + [NotNull] public void RunFunctionApp(FunctionAppRequest value) => _RunFunctionApp.Fire(value); + + /// + /// Signal from backend to debug a Function App locally. + /// + [NotNull] public void DebugFunctionApp(FunctionAppRequest value) => _DebugFunctionApp.Fire(value); + + /// + /// Signal from backend to trigger a Function App. + /// + [NotNull] public void TriggerFunctionApp(FunctionAppRequest value) => _TriggerFunctionApp.Fire(value); + + /// + /// Request from frontend to read the AzureFunctionsVersion MSBuild property. + /// + [NotNull] public IRdEndpoint GetAzureFunctionsVersion => _GetAzureFunctionsVersion; + + //private fields + [NotNull] private readonly RdSignal _RunFunctionApp; + [NotNull] private readonly RdSignal _DebugFunctionApp; + [NotNull] private readonly RdSignal _TriggerFunctionApp; + [NotNull] private readonly RdCall _GetAzureFunctionsVersion; + + //primary constructor + private FunctionAppDaemonModel( + [NotNull] RdSignal runFunctionApp, + [NotNull] RdSignal debugFunctionApp, + [NotNull] RdSignal triggerFunctionApp, + [NotNull] RdCall getAzureFunctionsVersion + ) + { + if (runFunctionApp == null) throw new ArgumentNullException("runFunctionApp"); + if (debugFunctionApp == null) throw new ArgumentNullException("debugFunctionApp"); + if (triggerFunctionApp == null) throw new ArgumentNullException("triggerFunctionApp"); + if (getAzureFunctionsVersion == null) throw new ArgumentNullException("getAzureFunctionsVersion"); + + _RunFunctionApp = runFunctionApp; + _DebugFunctionApp = debugFunctionApp; + _TriggerFunctionApp = triggerFunctionApp; + _GetAzureFunctionsVersion = getAzureFunctionsVersion; + _GetAzureFunctionsVersion.ValueCanBeNull = true; + BindableChildren.Add(new KeyValuePair("runFunctionApp", _RunFunctionApp)); + BindableChildren.Add(new KeyValuePair("debugFunctionApp", _DebugFunctionApp)); + BindableChildren.Add(new KeyValuePair("triggerFunctionApp", _TriggerFunctionApp)); + BindableChildren.Add(new KeyValuePair("getAzureFunctionsVersion", _GetAzureFunctionsVersion)); + } + //secondary constructor + internal FunctionAppDaemonModel ( + ) : this ( + new RdSignal(FunctionAppRequest.Read, FunctionAppRequest.Write), + new RdSignal(FunctionAppRequest.Read, FunctionAppRequest.Write), + new RdSignal(FunctionAppRequest.Read, FunctionAppRequest.Write), + new RdCall(AzureFunctionsVersionRequest.Read, AzureFunctionsVersionRequest.Write, ReadStringNullable, WriteStringNullable) + ) {} + //deconstruct trait + //statics + + public static CtxReadDelegate ReadStringNullable = JetBrains.Rd.Impl.Serializers.ReadString.NullableClass(); + + public static CtxWriteDelegate WriteStringNullable = JetBrains.Rd.Impl.Serializers.WriteString.NullableClass(); + + protected override long SerializationHash => 8720132529663507412L; + + protected override Action Register => RegisterDeclaredTypesSerializers; + public static void RegisterDeclaredTypesSerializers(ISerializers serializers) + { + + serializers.RegisterToplevelOnce(typeof(JetBrains.Rider.Model.IdeRoot), JetBrains.Rider.Model.IdeRoot.RegisterDeclaredTypesSerializers); + } + + + //constants + + //custom body + //methods + //equals trait + //hash code trait + //pretty print + public override void Print(PrettyPrinter printer) + { + printer.Println("FunctionAppDaemonModel ("); + using (printer.IndentCookie()) { + printer.Print("runFunctionApp = "); _RunFunctionApp.PrintEx(printer); printer.Println(); + printer.Print("debugFunctionApp = "); _DebugFunctionApp.PrintEx(printer); printer.Println(); + printer.Print("triggerFunctionApp = "); _TriggerFunctionApp.PrintEx(printer); printer.Println(); + printer.Print("getAzureFunctionsVersion = "); _GetAzureFunctionsVersion.PrintEx(printer); printer.Println(); + } + printer.Print(")"); + } + //toString + public override string ToString() + { + var printer = new SingleLinePrettyPrinter(); + Print(printer); + return printer.ToString(); + } + } + public static class SolutionFunctionAppDaemonModelEx + { + public static FunctionAppDaemonModel GetFunctionAppDaemonModel(this JetBrains.Rider.Model.Solution solution) + { + return solution.GetOrCreateExtension("functionAppDaemonModel", () => new FunctionAppDaemonModel()); + } + } + + + /// + ///

Generated from: FunctionAppDaemonModel.kt:21

+ ///
+ public sealed class AzureFunctionsVersionRequest : IPrintable, IEquatable + { + //fields + //public fields + [NotNull] public string ProjectFilePath {get; private set;} + + //private fields + //primary constructor + public AzureFunctionsVersionRequest( + [NotNull] string projectFilePath + ) + { + if (projectFilePath == null) throw new ArgumentNullException("projectFilePath"); + + ProjectFilePath = projectFilePath; + } + //secondary constructor + //deconstruct trait + public void Deconstruct([NotNull] out string projectFilePath) + { + projectFilePath = ProjectFilePath; + } + //statics + + public static CtxReadDelegate Read = (ctx, reader) => + { + var projectFilePath = reader.ReadString(); + var _result = new AzureFunctionsVersionRequest(projectFilePath); + return _result; + }; + + public static CtxWriteDelegate Write = (ctx, writer, value) => + { + writer.Write(value.ProjectFilePath); + }; + + //constants + + //custom body + //methods + //equals trait + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != GetType()) return false; + return Equals((AzureFunctionsVersionRequest) obj); + } + public bool Equals(AzureFunctionsVersionRequest other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + return ProjectFilePath == other.ProjectFilePath; + } + //hash code trait + public override int GetHashCode() + { + unchecked { + var hash = 0; + hash = hash * 31 + ProjectFilePath.GetHashCode(); + return hash; + } + } + //pretty print + public void Print(PrettyPrinter printer) + { + printer.Println("AzureFunctionsVersionRequest ("); + using (printer.IndentCookie()) { + printer.Print("projectFilePath = "); ProjectFilePath.PrintEx(printer); printer.Println(); + } + printer.Print(")"); + } + //toString + public override string ToString() + { + var printer = new SingleLinePrettyPrinter(); + Print(printer); + return printer.ToString(); + } + } + + + /// + ///

Generated from: FunctionAppDaemonModel.kt:15

+ ///
+ public sealed class FunctionAppRequest : IPrintable, IEquatable + { + //fields + //public fields + [CanBeNull] public string MethodName {get; private set;} + [CanBeNull] public string FunctionName {get; private set;} + [NotNull] public string ProjectFilePath {get; private set;} + + //private fields + //primary constructor + public FunctionAppRequest( + [CanBeNull] string methodName, + [CanBeNull] string functionName, + [NotNull] string projectFilePath + ) + { + if (projectFilePath == null) throw new ArgumentNullException("projectFilePath"); + + MethodName = methodName; + FunctionName = functionName; + ProjectFilePath = projectFilePath; + } + //secondary constructor + //deconstruct trait + public void Deconstruct([CanBeNull] out string methodName, [CanBeNull] out string functionName, [NotNull] out string projectFilePath) + { + methodName = MethodName; + functionName = FunctionName; + projectFilePath = ProjectFilePath; + } + //statics + + public static CtxReadDelegate Read = (ctx, reader) => + { + var methodName = ReadStringNullable(ctx, reader); + var functionName = ReadStringNullable(ctx, reader); + var projectFilePath = reader.ReadString(); + var _result = new FunctionAppRequest(methodName, functionName, projectFilePath); + return _result; + }; + public static CtxReadDelegate ReadStringNullable = JetBrains.Rd.Impl.Serializers.ReadString.NullableClass(); + + public static CtxWriteDelegate Write = (ctx, writer, value) => + { + WriteStringNullable(ctx, writer, value.MethodName); + WriteStringNullable(ctx, writer, value.FunctionName); + writer.Write(value.ProjectFilePath); + }; + public static CtxWriteDelegate WriteStringNullable = JetBrains.Rd.Impl.Serializers.WriteString.NullableClass(); + + //constants + + //custom body + //methods + //equals trait + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != GetType()) return false; + return Equals((FunctionAppRequest) obj); + } + public bool Equals(FunctionAppRequest other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + return Equals(MethodName, other.MethodName) && Equals(FunctionName, other.FunctionName) && ProjectFilePath == other.ProjectFilePath; + } + //hash code trait + public override int GetHashCode() + { + unchecked { + var hash = 0; + hash = hash * 31 + (MethodName != null ? MethodName.GetHashCode() : 0); + hash = hash * 31 + (FunctionName != null ? FunctionName.GetHashCode() : 0); + hash = hash * 31 + ProjectFilePath.GetHashCode(); + return hash; + } + } + //pretty print + public void Print(PrettyPrinter printer) + { + printer.Println("FunctionAppRequest ("); + using (printer.IndentCookie()) { + printer.Print("methodName = "); MethodName.PrintEx(printer); printer.Println(); + printer.Print("functionName = "); FunctionName.PrintEx(printer); printer.Println(); + printer.Print("projectFilePath = "); ProjectFilePath.PrintEx(printer); printer.Println(); + } + printer.Print(")"); + } + //toString + public override string ToString() + { + var printer = new SingleLinePrettyPrinter(); + Print(printer); + return printer.ToString(); + } + } +} diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Daemon/RunMarkers/FunctionAppRunMarkerAttributeIds.cs b/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Daemon/RunMarkers/FunctionAppRunMarkerAttributeIds.cs new file mode 100644 index 0000000000..017c6b3c52 --- /dev/null +++ b/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Daemon/RunMarkers/FunctionAppRunMarkerAttributeIds.cs @@ -0,0 +1,16 @@ +// Copyright 2018-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the MIT license. + +using JetBrains.TextControl.DocumentMarkup; + +namespace JetBrains.ReSharper.Azure.Daemon.RunMarkers; + +[RegisterHighlighter( + FunctionAppRunMethodMarkerId, + GutterMarkType = typeof(FunctionAppMethodRunMarkerGutterMark), + EffectType = EffectType.GUTTER_MARK, + Layer = HighlighterLayer.SYNTAX + 1) +] +public static class FunctionAppRunMarkerAttributeIds +{ + public const string FunctionAppRunMethodMarkerId = "Azure Function App Run Method Gutter Mark"; +} \ No newline at end of file diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Daemon/RunMarkers/FunctionAppRunMarkerGutterMark.cs b/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Daemon/RunMarkers/FunctionAppRunMarkerGutterMark.cs new file mode 100644 index 0000000000..84fc87593f --- /dev/null +++ b/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Daemon/RunMarkers/FunctionAppRunMarkerGutterMark.cs @@ -0,0 +1,94 @@ +// Copyright 2018-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the MIT license. + +using System.Collections.Generic; +using JetBrains.Application.UI.Controls.BulbMenu.Anchors; +using JetBrains.Application.UI.Controls.BulbMenu.Items; +using JetBrains.ProjectModel; +using JetBrains.ReSharper.Azure.Daemon.FunctionApp; +using JetBrains.ReSharper.Azure.Psi.FunctionApp; +using JetBrains.ReSharper.Resources.Shell; +using JetBrains.Rider.Backend.Features.RunMarkers; +using JetBrains.TextControl.DocumentMarkup; +using JetBrains.UI.Icons; +using JetBrains.UI.RichText; +using JetBrains.UI.ThemedIcons; +using JetBrains.Util; + +namespace JetBrains.ReSharper.Azure.Daemon.RunMarkers; + +public abstract class FunctionAppRunMarkerGutterMark(IconId iconId) : RunMarkerGutterMark(iconId) +{ + public override IAnchor Priority => BulbMenuAnchors.PermanentBackgroundItems; + + public override IEnumerable GetBulbMenuItems(IHighlighter highlighter) + { + if (!(highlighter.UserData is RunMarkerHighlighting runMarker)) yield break; + + var solution = Shell.Instance.GetComponent().Solution; + if (solution == null) yield break; + + if (runMarker.AttributeId != FunctionAppRunMarkerAttributeIds.FunctionAppRunMethodMarkerId) + yield break; + + foreach (var item in GetRunMethodItems(solution, runMarker)) + { + yield return item; + } + } + + private IEnumerable GetRunMethodItems(ISolution solution, RunMarkerHighlighting runMarker) + { + var functionAppDaemonHost = solution.GetComponent(); + + var methodName = runMarker.Method.ShortName; + var functionName = FunctionAppFinder.GetFunctionNameFromMethod(runMarker.Method) ?? + runMarker.Method.ShortName; + + var projectFilePath = + runMarker.Project.ProjectFileLocation.NormalizeSeparators(FileSystemPathEx.SeparatorStyle.Unix); + + var subAnchor = BulbMenuAnchors.PermanentItem.CreateNext(separate: true); + + yield return new BulbMenuItem( + new ExecutableItem(() => { functionAppDaemonHost.RunFunctionApp(projectFilePath); }), + new RichText("Run all functions..."), + RunMarkersThemedIcons.RunThis.Id, + BulbMenuAnchors.PermanentItem); + + yield return new BulbMenuItem( + new ExecutableItem(() => { functionAppDaemonHost.DebugFunctionApp(projectFilePath); }), + new RichText("Debug all functions..."), + RunMarkersThemedIcons.DebugThis.Id, + BulbMenuAnchors.PermanentItem); + + yield return new BulbMenuItem( + new ExecutableItem(() => + { + functionAppDaemonHost.RunFunctionApp(projectFilePath, methodName, functionName); + }), + new RichText($"Run '{functionName}'..."), + RunMarkersThemedIcons.RunThis.Id, + subAnchor); + + yield return new BulbMenuItem( + new ExecutableItem(() => + { + functionAppDaemonHost.DebugFunctionApp(projectFilePath, methodName, functionName); + }), + new RichText($"Debug '{functionName}'..."), + RunMarkersThemedIcons.DebugThis.Id, + subAnchor); + + yield return new BulbMenuItem( + new ExecutableItem(() => + { + functionAppDaemonHost.TriggerFunctionApp(projectFilePath, methodName, functionName); + }), + new RichText($"Trigger '{functionName}'..."), + FunctionAppRunMarkersThemedIcons.Trigger.Id, + subAnchor); + } +} + +public class FunctionAppMethodRunMarkerGutterMark() + : FunctionAppRunMarkerGutterMark(FunctionAppRunMarkersThemedIcons.RunFunctionApp.Id); \ No newline at end of file diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Daemon/RunMarkers/FunctionAppRunMarkerProvider.cs b/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Daemon/RunMarkers/FunctionAppRunMarkerProvider.cs new file mode 100644 index 0000000000..15becc9cc9 --- /dev/null +++ b/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Daemon/RunMarkers/FunctionAppRunMarkerProvider.cs @@ -0,0 +1,47 @@ +// Copyright 2018-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the MIT license. + +using JetBrains.Application.Settings; +using JetBrains.ReSharper.Azure.Project.FunctionApp; +using JetBrains.ReSharper.Azure.Psi.FunctionApp; +using JetBrains.ReSharper.Feature.Services.Daemon; +using JetBrains.ReSharper.Psi; +using JetBrains.ReSharper.Psi.Caches.SymbolCache; +using JetBrains.ReSharper.Psi.CSharp; +using JetBrains.ReSharper.Psi.CSharp.Tree; +using JetBrains.ReSharper.Psi.Tree; +using JetBrains.Rider.Backend.Features.RunMarkers; +using IMethodDeclaration = JetBrains.ReSharper.Psi.CSharp.Tree.IMethodDeclaration; + +namespace JetBrains.ReSharper.Azure.Daemon.RunMarkers; + +[Language(typeof(CSharpLanguage))] +public class FunctionAppRunMarkerProvider : IRunMarkerProvider +{ + public double Priority => RunMarkerProviderPriority.DEFAULT; + + public void CollectRunMarkers(IFile file, IContextBoundSettingsStore settings, IHighlightingConsumer consumer) + { + if (file is not ICSharpFile csharpFile) return; + + var project = file.GetProject(); + if (project == null || !project.IsValid()) return; + if (!FunctionAppProjectDetector.IsAzureFunctionsProject(project)) return; + + foreach (var declaration in CachedDeclarationsCollector.Run(csharpFile)) + { + if (declaration.DeclaredElement is not { } method) continue; + if (!FunctionAppFinder.IsSuitableFunctionAppMethod(method)) continue; + + var range = declaration.GetNameDocumentRange(); + + var highlighting = new RunMarkerHighlighting( + method: declaration.DeclaredElement, + declaration: declaration, + attributeId: FunctionAppRunMarkerAttributeIds.FunctionAppRunMethodMarkerId, + range: range, + targetFrameworkId: file.GetPsiModule().TargetFrameworkId); + + consumer.AddHighlighting(highlighting, range); + } + } +} \ No newline at end of file diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Daemon/RunMarkers/FunctionAppRunMarkersThemedIcons.cs b/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Daemon/RunMarkers/FunctionAppRunMarkersThemedIcons.cs new file mode 100644 index 0000000000..76ac79e4a0 --- /dev/null +++ b/PluginsAndFeatures/azure-toolkit-for-rider/src/dotnet/ReSharper.Azure/Azure.Daemon/RunMarkers/FunctionAppRunMarkersThemedIcons.cs @@ -0,0 +1,134 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace JetBrains.UI.ThemedIcons +{ + /// + /// + /// Autogenerated identifier classes and identifier objects to Themed Icons registered with . + /// Identifier classes should be used in attributes, XAML, or generic parameters. Where an value is expected, use the identifier object in the Id field of the identifier class. + /// + /// + /// + /// This code was compile-time generated to support Themed Icons in the JetBrains application. + /// It has two primary goals: load the icons of this assembly to be registered with so that they were WPF-accessible and theme-sensitive; and emit early-bound accessors for referencing icons in codebehind in a compile-time-validated manner. + ///

XAML

+ /// For performance reasons, the icons are not individually exposed with application resources. There is a custom markup extension to bind an image source in markup. + /// To use an icon from XAML, set an property to the markup extension, which takes an icon identifier class (nested in class) as a parameter. + /// Example: + /// <Image Source="{icons:ThemedIcon myres:DodofuxThemedIconsThemedIcons+Trinity}" /> + ///

Attributes

+ /// Sometimes you have to reference an icon from a type attriute when you're defining objects in code. Typical examples are Options pages and Tool Windows. + /// To avoid the use of string IDs which are not validated very well, we've emitted identifier classes to be used with typeof() expression, one per each icon. Use the attribute overload which takes a for an image, and choose your icon class from nested classes in the class. + /// Example: + /// [Item(Name="Sample", Icon=typeof(DodofuxThemedIconsThemedIcons.Trinity))] + ///

CodeBehind

+ /// In codebehind, we have two distinct tasks: (a) specify some icon in the APIs and (b) render icon images onscreen. + /// On the APIs stage you should only manipulate icon identifier objects (of type , statically defined in in Id fields). Icon identifier classes (nested in ) should be turned into icon identifier objects as early as possible. Rendering is about getting an to assign to WPF, or to use with GDI+ / Windows Forms. + /// You should turn an identifier object into a rendered image as late as possible. The identifier is static and lightweight and does not depend on the current theme, while the image is themed and has to be loaded or generated/rasterized. You need an instance to get the image out of an icon identifier object. Once you got the image, you should take care to change it with theme changes — either by using a live image property, or by listening to the theme change event. See and its extensions for the related facilities. + /// Example: + /// // Getting IconId identifier object to use with APIs + ///IconId iconid = DodofuxThemedIconsThemedIcons.Trinity.Id; + /// // Getting IconId out of an Icon Identifier Class type + ///IconId iconid = new JetBrains.Application.Icons.CompiledIconsCs.CompiledIconCsId(typeof(DodofuxThemedIconsThemedIcons.Trinity)); + /// // Getting image for screen rendering by IconId + ///themediconmanager.Icons[icnoid] + /// // Getting image for screen rendering by Icon Identifier Class + ///themediconmanager.GetIcon<DodofuxThemedIconsThemedIcons.Trinity>() + ///

Icons Origin

+ /// This code was generated by a pre-compile build task from a set of input files which are XAML files adhering to a certain convention, as convenient for exporting them from the Illustrator workspace, plus separate PNG files with raster icons. In the projects, these files are designated with ThemedIconsXamlV3 and ThemedIconPng build actions and do not themselves get into the output assembly. All of such files are processed, vector images for different themes of the same icon are split and combined into the single list of icons in this assembly. This list is then written into the genearted XAML file (compiled into BAML within assembly), and serves as the source for this generated code. + ///
+ public sealed class FunctionAppRunMarkersThemedIcons + { + #region RunFunctionApp + + [global::JetBrains.Application.Icons.CompiledIconsCs.CompiledIconCsAttribute()] + public sealed class RunFunctionApp : global::JetBrains.Application.Icons.CompiledIconsCs.CompiledIconCsClass + { + + /// identifier class + public static global::JetBrains.UI.Icons.IconId Id = new global::JetBrains.Application.Icons.CompiledIconsCs.CompiledIconCsId(typeof(RunFunctionApp)); + + /// Loads the image for Themed Icon RunFunctionApp theme aspect Color. + public global::JetBrains.Util.Icons.TiImage Load_Color() + { + return global::JetBrains.Util.Icons.TiImageConverter.FromTiSvg( + ""); + } + + /// Loads the image for Themed Icon RunFunctionApp theme aspect Gray. + public global::JetBrains.Util.Icons.TiImage Load_Gray() + { + return global::JetBrains.Util.Icons.TiImageConverter.FromTiSvg( + ""); + } + + /// Loads the image for Themed Icon RunFunctionApp theme aspect GrayDark. + public global::JetBrains.Util.Icons.TiImage Load_GrayDark() + { + return global::JetBrains.Util.Icons.TiImageConverter.FromTiSvg( + ""); + } + + /// Returns the set of theme images for Themed Icon RunFunctionApp. + public override global::JetBrains.Application.Icons.CompiledIconsCs.CompiledIconCsIdOwner.ThemedIconThemeImage[] GetThemeImages() + { + return new global::JetBrains.Application.Icons.CompiledIconsCs.CompiledIconCsIdOwner.ThemedIconThemeImage[] { + new global::JetBrains.Application.Icons.CompiledIconsCs.CompiledIconCsIdOwner.ThemedIconThemeImage("Color", new global::JetBrains.Application.Icons.CompiledIconsCs.CompiledIconCsIdOwner.LoadImageDelegate(this.Load_Color)), + new global::JetBrains.Application.Icons.CompiledIconsCs.CompiledIconCsIdOwner.ThemedIconThemeImage("Gray", new global::JetBrains.Application.Icons.CompiledIconsCs.CompiledIconCsIdOwner.LoadImageDelegate(this.Load_Gray)), + new global::JetBrains.Application.Icons.CompiledIconsCs.CompiledIconCsIdOwner.ThemedIconThemeImage("GrayDark", new global::JetBrains.Application.Icons.CompiledIconsCs.CompiledIconCsIdOwner.LoadImageDelegate(this.Load_GrayDark))}; + } + } + + #endregion + + #region Trigger + + [global::JetBrains.Application.Icons.CompiledIconsCs.CompiledIconCsAttribute()] + public sealed class Trigger : global::JetBrains.Application.Icons.CompiledIconsCs.CompiledIconCsClass + { + + /// identifier class + public static global::JetBrains.UI.Icons.IconId Id = new global::JetBrains.Application.Icons.CompiledIconsCs.CompiledIconCsId(typeof(Trigger)); + + /// Loads the image for Themed Icon Trigger theme aspect Color. + public global::JetBrains.Util.Icons.TiImage Load_Color() + { + return global::JetBrains.Util.Icons.TiImageConverter.FromTiSvg( + ""); + } + + /// Loads the image for Themed Icon Trigger theme aspect Gray. + public global::JetBrains.Util.Icons.TiImage Load_Gray() + { + return global::JetBrains.Util.Icons.TiImageConverter.FromTiSvg( + ""); + } + + /// Loads the image for Themed Icon Trigger theme aspect GrayDark. + public global::JetBrains.Util.Icons.TiImage Load_GrayDark() + { + return global::JetBrains.Util.Icons.TiImageConverter.FromTiSvg( + ""); + } + + /// Returns the set of theme images for Themed Icon Trigger. + public override global::JetBrains.Application.Icons.CompiledIconsCs.CompiledIconCsIdOwner.ThemedIconThemeImage[] GetThemeImages() + { + return new global::JetBrains.Application.Icons.CompiledIconsCs.CompiledIconCsIdOwner.ThemedIconThemeImage[] { + new global::JetBrains.Application.Icons.CompiledIconsCs.CompiledIconCsIdOwner.ThemedIconThemeImage("Color", new global::JetBrains.Application.Icons.CompiledIconsCs.CompiledIconCsIdOwner.LoadImageDelegate(this.Load_Color)), + new global::JetBrains.Application.Icons.CompiledIconsCs.CompiledIconCsIdOwner.ThemedIconThemeImage("Gray", new global::JetBrains.Application.Icons.CompiledIconsCs.CompiledIconCsIdOwner.LoadImageDelegate(this.Load_Gray)), + new global::JetBrains.Application.Icons.CompiledIconsCs.CompiledIconCsIdOwner.ThemedIconThemeImage("GrayDark", new global::JetBrains.Application.Icons.CompiledIconsCs.CompiledIconCsIdOwner.LoadImageDelegate(this.Load_GrayDark))}; + } + } + + #endregion + } +}